Added main stream code

Showing with 1995 additions and 0 deletions
/**
* Main application luncher
*
*/
Ext.application({
name: 'MyMA',
controllers: ['Viewport', 'ProgramMenu', 'Taskpanel', 'Program', 'Users', 'User', 'Aliases', 'Alias', 'Transports'],
enableQuickTips: true
});
/**
* Contains Common overrides and extentions
*
*/
/**
* Adds functions with predefined configs
*/
Ext.override(Ext.Msg, {
onShow: function() {
this.callParent(arguments);
this.center();
// This will fix trace information block
if(!Ext.isEmpty(Ext.query('div.x-msg-trace')) && !Ext.isEmpty(Ext.query('div.x-msg-error'))) {
var error = Ext.get(Ext.query('div.x-msg-error')),
trace = Ext.get(Ext.query('div.x-msg-trace'));
if(trace.first().getHeight() + error.first().getHeight() > this.body.getHeight()) {
trace.first().setHeight(this.body.getHeight() - error.first().getHeight());
}
}
},
showInfo: function(config) {
Ext.Msg.show(Ext.apply({
autoScroll: true,
title: 'Info',
msg: '',
icon: Ext.Msg.INFO,
buttons: Ext.Msg.OK
}, config || {}))
},
showError: function(cfg) {
if(Ext.isObject(cfg.msg)) {
if(cfg.msg.tpl) {
if(Ext.isArray(cfg.msg.tpl) || Ext.isString(cfg.msg.tpl)) {
cfg.msg = new Ext.XTemplate(Ext.isArray(cfg.msg.tpl) ? cfg.msg.tpl.join('') : cfg.msg.tpl).apply(cfg.msg.data || {});
}
else if(cfg.msg.tpl.isTemplate) {
cfg.msg = cfg.msg.tpl.apply(cfg.msg.data || {});
}
}
else if(cfg.msg.error) {
cfg.msg = new Ext.XTemplate(
'<div class="x-msg-error">',
'<tpl if="code">Error code: {code}<br/></tpl>',
'<tpl if="type">Error type: {type}<br/></tpl>',
'Message: <tpl if="message">{message}</tpl><tpl if="!values.message">Unknown error</tpl><br>',
'<tpl if="file">File: {file}<br/></tpl>',
'<tpl if="line">Line: {line}<br/></tpl>',
'</div>',
'<tpl if="traces">',
'<div class="x-msg-trace"><tpl for="traces">',
'({line}) {file}: <div class="x-msg-trace-detail">',
'<tpl if="type == \'-&gt;\'">{class}-&gt;{function}()</tpl>',
'<tpl if="args && args.length &gt; 0"><div><b>Arguments:</b> {[ Ext.encode(values.args) ]}</div></tpl>',
'</div>',
'</tpl></div>',
'</tpl>'
).apply(cfg.msg.error);
}
}
Ext.Msg.show(Ext.apply({
autoScroll: true,
title: 'Error',
msg: '',
icon: Ext.Msg.ERROR,
buttons: Ext.Msg.OK
}, cfg || {}))
}
});
/**
* Adds default settings to the Ext.data.Connection
* The main goal is to change onComplete function to handle common server exceptions
*/
Ext.override(Ext.data.Connection, {
// Default request path
url: '.',
// Default timeoute
timeout: 380000,
/**
* Set guest state to the authorization controller
*/
setGuest: Ext.emptyFn,
/**
* Return isGuest current value
* @return {Boolean}
*/
getGuest: Ext.emptyFn,
/**
* Finds meta tag in the document to set application base url
* @return {string}
*/
getBaseUrl: function() {
if(!Ext.isDefined(this.baseUrl)) {
this.baseUrl = (Ext.query('meta[name=application-url]')[0] || { content: '.' }).content;
this.baseUrl.replace(/[\/\\]+$/, "");
this.url = this.baseUrl;
}
return this.url;
},
/**
* Returns RESTful url using base url and passed route
* @return {string}
*/
getRestUrl: function() {
var route = [];
Ext.iterate(arguments, function(value) {
this.push(value);
}, route);
route = route.join('/');
route.replace(/^[\/\\]+/, "");
return [this.getBaseUrl(), '/index.php/', route].join('');
},
/**
* To be called when the request has come back from the server
* This override needs to catch specific server exceptions and stop callback execution
* @private
* @param {Object} request
* @return {Object} The response
*/
onComplete : function(request) {
var me = this,
options = request.options,
result,
success,
response;
try {
result = me.parseStatus(request.xhr.status);
} catch (e) {
// in some browsers we can't access the status if the readyState is not 4, so the request has failed
result = {
success : false,
isException : false
};
}
success = result.success;
// Run success
if (success) {
response = me.createResponse(request);
me.fireEvent('requestcomplete', me, response, options);
Ext.callback(options.success, options.scope, [response, options]);
} else {
if (result.isException || request.aborted || request.timedout) {
response = me.createException(request);
} else {
response = me.createResponse(request);
}
// Keep unauthorized statuses
if(Ext.isEmpty(me.getGuest()) && (response.status != 404 || response.status != 500)) {
me.setGuest(true);
}
else {
if(options.proxy && options.proxy.isProxy) {
var data = response.responseText ? Ext.decode(response.responseText) : {};
Ext.Msg.showError({
title: data.error.title || 'Error',
msg: {
error: data.error
},
buttons: Ext.Msg.OK
});
}
else {
me.fireEvent('requestexception', me, response, options);
}
Ext.callback(options.failure, options.scope, [response, options]);
}
}
if (!Ext.isDefined(me.isGuest)) {
Ext.callback(options.callback, options.scope, [options, success, response]);
}
delete me.requests[request.id];
return response;
}
});
/**
* Changes for the toolbar element
*/
Ext.override(Ext.Toolbar, {
// Adds function to the toolbar to return input element's values
getValues: function() {
var params = {},
items = this.query('searchfield,textfield,numberfield,checkbox,radio,combo');
Ext.each(items, function(item){
this[item.name || item.itemId || item.getId()] = item.getValue();
}, params);
return params;
}
});
/**
* Additional component to initiate query request on enter key event
*/
Ext.define('Ext.form.SearchField', {
extend: 'Ext.form.field.Text',
alias: 'widget.searchfield',
enableKeyEvents: true,
// If field is in the toolbar than this option may points to button
// or put here function
handler: null,
// Add specialkey listener
initComponent: function() {
this.callParent();
if(!Ext.isEmpty(this.handler)) {
this.on('specialkey', this.checkEnterKey, this);
}
},
// Handle enter key presses, execute the search if the field has a value
checkEnterKey: function(field, e) {
var value = this.getValue();
if (e.getKey() === e.ENTER) {
if(Ext.isFunction(this.handler)) {
this.handler();
}
else if(Ext.isString(this.handler)) {
var point = this.up('toolbar').query('#' + this.handler);
if(point.length > 0 && point[0].getXType() == 'button') {
point[0].fireEvent('click',point[0]);
}
}
}
}
});
\ No newline at end of file
/**
* Conroller: Alias
*
*/
Ext.define('MyMA.controller.Alias', {
extend: 'Ext.app.Controller',
views: ['Alias'],
refs: [{
selector: 'alias',
ref: 'aliasWindow'
}],
init: function() {
this.control({
'alias > toolbar > #savedata': {
click: this.saveData
}
});
},
saveData: function(Button) {
var form = this.getAliasWindow().down('form').getForm(),
id = form.getValues().id || null;
if(!form.isValid()) {
return false;
}
form.submit({
url: Ext.Ajax.getRestUrl('api','alias', id),
clientValidation: true,
method: id > 0 ? 'PUT' : 'POST',
scope: {
controller: this,
win: this.getAliasWindow()
},
success: this.onSuccessSubmit,
failure: this.onFailSubmit
});
},
/**
*
*/
onSuccessSubmit: function(form, action) {
this.win.close();
this.controller.getController('Aliases').getStore('Aliases').reload({
params: {
start: 0
}
});
Ext.Msg.showInfo({
msg: 'Data saved'
})
},
/**
*
*/
onFailSubmit: function(form, action) {
try {
var data = Ext.decode(action.response.responseText);
throw(data);
}
catch(e) {
Ext.Msg.showError({
msg: e
});
}
}
});
Ext.define('MyMA.controller.Aliases', {
extend: 'Ext.app.Controller',
stores: ['Aliases'],
views: ['Aliases','Alias'],
refs: [{
selector: 'aliases > grid',
ref: 'aliasesList'
}],
init: function() {
this.control({
'aliases > grid > toolbar > #addrecord': {
click: this.showForm
},
'aliases > grid > toolbar > #search': {
click: this.onSearch
},
'aliases actioncolumn': {
click: this.onActionColumn
}
});
},
/**
* Handles action columns click
* @param {Object} grid view
* @param {HTMLElement} Element
* @param {Integer} row index
* @param {Integer} column index
* @param {Object} Event object
* @param {Object} Scope object
* @param {Object}
*/
onActionColumn: function(gridview, el, rowIndex, colIndex, e, scope, rowEl) {
if(e.getTarget('.x-ibtn-edit')) {
var record = scope.store.getAt(rowIndex);
var widget = this.getController('Taskpanel').addProgram({
name: 'alias'
});
widget.setTitle('Alias: ' + record.get('alias'));
widget.down('form').getForm().loadRecord(record);
}
if(e.getTarget('.x-ibtn-delete')) {
var record = scope.store.getAt(rowIndex);
Ext.Msg.confirm('Info', 'Press Yes to confirm remove action', function(button) {
if (button === 'yes') {
this.record.destroy({
scope: this,
success: function() {
this.store.remove(this.record)
}
});
}
}, {
store: scope.store,
record: record
});
}
},
/**
* Show form to add new record or edit existing data
* @param {Object} Button
*/
showForm: function(Button) {
this.getController('Taskpanel').addProgram({
name: 'alias',
title: 'New Alias'
});
},
/**
* Search action
*/
onSearch: function(Button) {
this.getAliasesList().getStore().reload({ params: Button.up('toolbar').getValues() });
}
});
Ext.define('MyMA.controller.Program', {
extend: 'Ext.app.Controller',
stores: ['Programs'],
refs: [{
selector: 'taskpanel',
ref: 'taskPanel'
}],
init: function() {
var control = {};
Ext.each(this.refs, function(item){
this.control[item.selector] = {
beforeclose: this.me.programStop,
hide: this.me.programState,
show: this.me.programState,
minimize: this.me.programMinimize
}
}, {
control: control,
me: this
});
this.control(control);
},
/**
* Register controll for the created "Program"
* @param String, selector name
*/
registerControl: function(selector) {
var selector = selector || null,
ctrl = {};
if(!selector) {
return;
}
ctrl[selector] = {
beforeclose: this.programStop,
hide: this.programState,
show: this.programState,
minimize: this.programMinimize
};
this.control(ctrl);
}, // end registerControl()
/**
* Hides widget and sets status to the Store object
* @param {Object} item
*/
programMinimize: function(item) {
var record;
if(!(record = this.getStore('Programs').getProccess({
property: 'item',
value: item.getId()
})))
{
return false;
}
this.getTaskPanel().items.get(record.get('control')).toggle(false);
item.hide();
this.programState(item);
}, // end programMinimize()
/**
* Writes program state to the Store object
* @param {Object} item
* @param {Object} opt
*/
programState: function(item, opt) {
var record;
if(!(record = this.getStore('Programs').getProccess({
property: 'item',
value: item.getId()
})))
{
return false;
}
record.set('state', item.isHidden() ? 'hide' : 'show');
}, // end programState()
/**
* Destroyes wiget and removes program information from the Store
* @param {Object} item
* @param {Object} record
*/
programStop: function(item, record) {
var record = record || Ext.undefined;
if (!record['data']) {
(record = this.getStore('Programs').getProccess({
property: 'item',
value: item.getId()
}));
}
if(item.animateTarget) {
item.animateTarget = null;
}
if(record && record['data']) {
this.getTaskPanel().items.get(record.get('control')).destroy();
this.getStore('Programs').remove(record);
}
} // end programStop()
});
Ext.define('MyMA.controller.ProgramMenu', {
extend: 'Ext.app.Controller',
init: function() {
this.control({
'programmenu > menu': {
click: this.LaunchProgram
}
});
},
LaunchProgram: function(menu, item) {
if (item.itemId == 'logout') {
this.getController('Viewport').Logout();
}
else {
this.getController('Taskpanel').addProgram({
name: item.widgetName,
title: item.text
});
}
}
});
Ext.define('MyMA.controller.Taskpanel', {
extend: 'Ext.app.Controller',
stores: ['Programs'],
refs: [{
selector: 'taskpanel',
ref: 'taskPanel'
}],
init: function() {
this.control({
'taskpanel > button': {
toggle: this.programState
}
});
},
/**
* Add program to the task panel
* @param data
*/
addProgram: function(data) {
var data = data || {
name: null
},
store = this.getStore('Programs'),
record, widget;
if(!(record = store.getProccess({
property: 'name',
value: data.name
})))
{
try {
var widget = Ext.widget(data.name),
progId = (store.max('id') || 0) + 1;
}
catch(e) {
return false;
}
var Button = this.getTaskPanel().add({
xtype: 'button',
ui: 'program-button',
height: 28,
text: data.title || widget.title,
enableToggle: true,
pressed: true,
programId: progId
});
record = store.add({
id: progId,
title: data.title || widget.title,
name: data.name,
state: 'show',
item: widget.getId(),
control: Button.getId()
})[0];
this.getController('Program').registerControl(data.name);
widget.animateTarget = Button.getId();
widget.setTitle(data.title);
widget.show();
}
else {
this.getTaskPanel().items.get(record.get('control')).toggle(true);
if((widget = Ext.getCmp(record.get('item')))) {
widget.show();
}
}
return widget ? widget : null;
},
/**
* Get reference function
* @param {Object} Button
*/
callRef: function(selector) {
var me = this;
try {
for (var i = 0, ln = this.refs.length; i < ln; i++) {
if (this.refs[i]['selector'] == selector) {
return me['get' + Ext.String.capitalize(this.refs[i]['ref'])]();
}
}
}
catch(e) { }
return null;
},
programState: function(Button) {
var store = this.getStore('Programs'),
record, widget;
if(!(record = store.getProccess({
property: 'id',
value: Button.programId
})))
{
return false;
}
if ((widget = Ext.getCmp(record.get('item')))) {
widget[record.get('state') == 'show' ? 'hide' : 'show']();
}
},
/**
* Close all process those are registed in the Programs storage
*/
closeAll: function() {
this.getStore('Programs').each(function(record){
if ((widget = Ext.getCmp(record.get('item')))) {
widget.hide();
this.getTaskPanel().items.get(record.get('control')).destroy();
}
}, this);
}
});
Ext.define('MyMA.controller.Transports', {
extend: 'Ext.app.Controller',
stores: ['Transports'],
views: ['Transports'],
refs: [{
selector: 'transports > grid',
ref: 'transportsList'
}],
init: function() {
this.control({
'transports > grid > toolbar > #addrecord': {
click: this.addRecord
},
'transports > grid > toolbar > #search': {
click: this.onSearch
},
'transports actioncolumn': {
click: this.onActionColumn
},
'transports > grid': {
edit: this.onEditAction
}
});
},
/**
* Handles action columns click
* @param {Object} grid view
* @param {HTMLElement} Element
* @param {Integer} row index
* @param {Integer} column index
* @param {Object} Event object
* @param {Object} Scope object
* @param {Object}
*/
onActionColumn: function(gridview, el, rowIndex, colIndex, e, scope, rowEl) {
if(e.getTarget('.x-ibtn-delete')) {
var record = scope.store.getAt(rowIndex);
Ext.Msg.confirm('Info', 'Press Yes to confirm remove action', function(button) {
if (button === 'yes') {
if(!this.record.get('id')) {
this.store.remove(this.record);
}
else {
this.record.destroy({
scope: this,
success: function() {
this.store.remove(this.record)
}
});
}
}
}, {
store: scope.store,
record: record
});
}
},
/**
* Add record to the store and start editing
*/
addRecord: function(Button) {
this.getTransportsList().getStore().insert(0, this.getTransportsList().getStore().model.create({
id: 0,
domain: null,
transport: 'virtual'
}));
},
/**
* Search action
*/
onSearch: function(Button) {
this.getTransportsList().getStore().reload({ params: Button.up('toolbar').getValues() });
},
/**
* Fires when edit complete and record was updated
* @param {object}, Ext.grid.plugin.Editing
* @param {object}, An edit event
*/
onEditAction: function(editor, e) {
e.record.save({
scope: e,
success: function(record) {
this.store.reload();
}
});
}
});
Ext.define('MyMA.controller.User', {
extend: 'Ext.app.Controller',
views: ['User'],
refs: [{
selector: 'user',
ref: 'userWindow'
}],
init: function() {
this.control({
'user > toolbar > #savedata': {
click: this.saveData
}
});
},
saveData: function(Button) {
var form = this.getUserWindow().down('form').getForm(),
id = form.getValues().id || null;
if(!form.isValid()) {
return false;
}
form.submit({
url: Ext.Ajax.getRestUrl('api','user', id),
clientValidation: true,
method: id > 0 ? 'PUT' : 'POST',
params: Ext.applyIf(Ext.copyTo({}, form.getValues(), 'smtp,imap,manager'), {
smtp: 0,
imap: 0,
manager: 0
}),
scope: {
controller: this,
win: this.getUserWindow()
},
success: this.onSuccessSubmit,
failure: this.onFailSubmit
});
},
/**
*
*/
onSuccessSubmit: function(form, action) {
this.win.close();
this.controller.getController('Users').getStore('Users').reload({
params: {
start: 0
}
});
Ext.Msg.showInfo({
msg: 'Data saved'
})
},
/**
*
*/
onFailSubmit: function(form, action) {
try {
var data = Ext.decode(action.response.responseText);
throw(data);
}
catch(e) {
Ext.Msg.showError({
msg: e
});
}
}
});
Ext.define('MyMA.controller.Users', {
extend: 'Ext.app.Controller',
stores: ['Users', 'Choice'],
views: ['Users', 'User'],
refs: [{
selector: 'users > grid',
ref: 'usersList'
}, {
selector: 'users',
ref: 'usersWindow'
}],
init: function() {
this.control({
'users > grid > toolbar > #addrecord': {
click: this.showForm
},
'users > grid > toolbar > #search': {
click: this.onSearch
},
'users actioncolumn': {
click: this.onActionColumn
}
});
},
/**
* Handles action columns click
* @param {Object} grid view
* @param {HTMLElement} Element
* @param {Integer} row index
* @param {Integer} column index
* @param {Object} Event object
* @param {Object} Scope object
* @param {Object}
*/
onActionColumn: function(gridview, el, rowIndex, colIndex, e, scope, rowEl) {
if(e.getTarget('.x-ibtn-edit')) {
var record = scope.store.getAt(rowIndex);
var widget = this.getController('Taskpanel').addProgram({
name: 'user'
});
widget.setTitle('User: ' + record.get('name'));
widget.down('form').getForm().loadRecord(record);
}
if(e.getTarget('.x-ibtn-delete')) {
var record = scope.store.getAt(rowIndex);
Ext.Msg.confirm('Info', 'Press Yes to conform remove action', function(button) {
if (button === 'yes') {
this.record.destroy({
scope: this,
success: function() {
this.store.remove(this.record)
}
});
}
}, {
store: scope.store,
record: record
});
}
},
/**
* Show form to add new record or edit existing data
* @param {Object} Button
*/
showForm: function(Button) {
this.getController('Taskpanel').addProgram({
name: 'user',
title: 'New User'
});
},
/**
* Search action
*/
onSearch: function(Button) {
this.getUsersList().getStore().reload({ params: Button.up('toolbar').getValues() });
}
});
/**
* Controller: Viewport
*
*/
Ext.define('MyMA.controller.Viewport', {
extend: 'Ext.app.Controller',
views: ['Viewport', 'Authorize'],
refs: [{
selector: 'viewport',
ref: 'appView'
}, {
selector: 'authorize',
ref: 'authPanel'
}, {
selector: 'authorize > form',
ref: 'authForm'
}],
/**
*
*/
isGuest: Ext.undefined,
/**
* A template method that is called when your application boots.
* It is called before the Application's launch function is executed so gives a hook
* point to run any code before your Viewport is created.
*/
init: function(app) {
// Bind Guest to the Ext.data.Connection
Ext.override(Ext.data.Connection, {
/**
* Set guest state to the authorization controller
*/
setGuest: Ext.Function.bind(this.setGuest, this),
/**
* Return isGuest current value
* @return {Boolean}
*/
getGuest: Ext.Function.bind(this.getGuest, this)
});
this.control({
'authorize > form > toolbar > button': {
click: this.Authorize
}
});
this.Authorize();
},
/**
* Authorize
* if passed main application view, the first step need to query
* @param object, main application view
*/
Authorize: function() {
if (this.getAuthPanel()) {
var form = this.getAuthPanel().down('form').getForm();
if(form.isValid()) {
form.submit({
url: Ext.Ajax.getRestUrl('api','login', 'authorize', 0),
method: 'PUT',
clientValidation: true,
scope: this,
success: this.successLogin
})
}
}
else {
Ext.Ajax.request({
url: Ext.Ajax.getRestUrl('api', 'login'),
scope: this,
callback: function(){
if (!this.isGuest && !this.getAppView()) {
this.setGuest(false);
this.getView('Viewport').create();
}
}
});
}
},
/**
* Return isGuest value
* @param state
*/
getGuest: function() {
return this.isGuest;
},
/**
* Set isGuest flag value
* @param object, this controller
* @param boolean, state to set
*/
setGuest: function(state) {
this.isGuest = Ext.isBoolean(state) ? state : true;
if(this.isGuest && !this.getAuthPanel()) {
this.getView('Authorize').create();
}
},
/**
* private
*/
successLogin: function(form, action) {
this.getAuthPanel().close();
if(!this.getAppView()) {
this.getView('Viewport').create();
}
},
/**
* Logout
* public
*/
Logout: function() {
Ext.Ajax.request({
url: Ext.Ajax.getRestUrl('api','login', 'logout', 0),
method: 'PUT',
scope: this,
callback: function() {
if(this.getAppView()) {
this.getController('Taskpanel').closeAll();
this.getAppView().destroy();
}
this.setGuest(this, true);
}
});
}
});
Ext.define('MyMA.model.Aliases', {
extend: 'Ext.data.Model',
fields: [{
name: 'id',
type: 'int'
}, {
name: 'alias',
type: 'string'
}, {
name: 'recipient',
type: 'string'
}, {
name: 'comment',
type: 'string'
}],
proxy: {
type: 'rest',
url: Ext.Ajax.getRestUrl('api', 'alias'),
reader: {
type: 'json',
root: 'results',
totalProperty: 'total'
},
writer: {
type: 'json',
allowSingle: true
}
}
});
Ext.define('MyMA.model.Brief', {
extend: 'Ext.data.Model',
fields: ['id', 'name'],
proxy: {
type: 'memory',
reader: {
type: 'json',
root: 'results'
}
}
});
Ext.define('MyMA.model.Transports', {
extend: 'Ext.data.Model',
fields: [{
name: 'id',
type: 'int'
}, {
name: 'domain',
type: 'string'
}, {
name: 'transport',
type: 'string'
}],
proxy: {
type: 'rest',
url: Ext.Ajax.getRestUrl('api', 'transport'),
reader: {
type: 'json',
root: 'results',
totalProperty: 'total'
},
writer: {
type: 'json',
allowSingle: true
}
}
});
Ext.define('MyMA.model.Users', {
extend: 'Ext.data.Model',
fields: [{
name: 'id',
type: 'int'
}, {
name: 'name',
type: 'string'
}, {
name: 'login',
type: 'string'
}, {
name: 'passwd',
type: 'string'
}, {
name: 'uid',
type: 'int',
defaultValue: 8
}, {
name: 'gid',
type: 'int',
defaultValue: 12
}, {
name: 'maildir',
type: 'string'
}, {
name: 'smtp',
type: 'int'
}, {
name: 'imap',
type: 'int'
}, {
name: 'quota',
type: 'int',
defaultValue: 10000000
}, {
name: 'manager',
type: 'int'
}],
validations: [{
type: 'format',
field: 'maildir',
matcher: /^\/[a-z]\.ru\/[a-z_0-9]\/Maildir\/$/
}],
proxy: {
type: 'rest',
url: Ext.Ajax.getRestUrl('api/user'),
reader: {
type: 'json',
root: 'results'
},
writer: {
type: 'json',
allowSingle: true
}
}
});
Ext.define('MyMA.model.Users', {
extend: 'Ext.data.Model',
fields: [{
name: 'id',
type: 'int'
}, {
name: 'name',
type: 'string'
}, {
name: 'login',
type: 'string'
}, {
name: 'passwd',
type: 'string'
}, {
name: 'uid',
type: 'int',
defaultValue: 8
}, {
name: 'gid',
type: 'int',
defaultValue: 12
}, {
name: 'maildir',
type: 'string'
}, {
name: 'smtp',
type: 'int'
}, {
name: 'imap',
type: 'int'
}, {
name: 'quota',
type: 'int',
defaultValue: 10000000
}, {
name: 'manager',
type: 'int'
}],
validations: [{
type: 'format',
field: 'maildir',
matcher: /^\/[a-z]\.ru\/[a-z_0-9]\/Maildir\/$/
}],
proxy: {
type: 'rest',
url: Ext.Ajax.getRestUrl('api/user'),
reader: {
type: 'json',
root: 'results'
},
writer: {
type: 'json',
allowSingle: true
}
}
});
Ext.define('MyMA.model.Brief', {
extend: 'Ext.data.Model',
fields: ['id', 'name'],
proxy: {
type: 'memory',
reader: {
type: 'json',
root: 'results'
}
}
});
Ext.define('MyMA.model.Aliases', {
extend: 'Ext.data.Model',
fields: [{
name: 'id',
type: 'int'
}, {
name: 'alias',
type: 'string'
}, {
name: 'recipient',
type: 'string'
}, {
name: 'comment',
type: 'string'
}],
proxy: {
type: 'rest',
url: Ext.Ajax.getRestUrl('api', 'alias'),
reader: {
type: 'json',
root: 'results',
totalProperty: 'total'
},
writer: {
type: 'json',
allowSingle: true
}
}
});
Ext.define('MyMA.model.Transports', {
extend: 'Ext.data.Model',
fields: [{
name: 'id',
type: 'int'
}, {
name: 'domain',
type: 'string'
}, {
name: 'transport',
type: 'string'
}],
proxy: {
type: 'rest',
url: Ext.Ajax.getRestUrl('api', 'transport'),
reader: {
type: 'json',
root: 'results',
totalProperty: 'total'
},
writer: {
type: 'json',
allowSingle: true
}
}
});
Ext.define('MyMA.store.Aliases', {
extend: 'Ext.data.Store',
requires: 'MyMA.model.Aliases',
model: 'MyMA.model.Aliases',
groupField: 'alias',
remoteSort: true,
pageSize: 100
});
Ext.define('MyMA.store.Choice', {
extend: 'Ext.data.Store',
requires: 'MyMA.model.Brief',
model: 'MyMA.model.Brief',
data: [{
id: 0,
name: 'No'
}, {
id: 1,
name: 'Yes'
}]
});
Ext.define('MyMA.store.Programs', {
extend: 'Ext.data.ArrayStore',
fields: ['id', 'name', 'state', 'item', 'title', 'control'],
data: [],
/**
* Get item record from process storage
* @param object
*/
getProccess: function(data) {
var data = data || {
property: 'id',
value: null
},
idx = -1;
if((idx = this.find(data.property, data.value, 0, false, true, true)) > -1) {
return this.getAt(idx);
}
return null;
}
});
Ext.define('MyMA.store.Transports', {
extend: 'Ext.data.Store',
requires: 'MyMA.model.Transports',
model: 'MyMA.model.Transports',
remoteSort: true,
pageSize: 100
});
Ext.define('MyMA.store.Users', {
extend: 'Ext.data.Store',
requires: 'MyMA.model.Users',
model: 'MyMA.model.Users',
remoteSort: true,
pageSize: 100
});
Ext.define('MyMA.view.Alias', {
extend: 'Ext.window.Window',
alias: 'widget.alias',
layout: 'fit',
title: 'Alias',
width: 400,
constrainHeader: true,
closeAction: 'destroy',
buttons: [{
xtype: 'button',
itemId: 'savedata',
text: 'Save',
scope: this
}],
items: [{
xtype: 'form',
frame: true,
monitorValid: true,
defaults: {
xtype: 'textfield',
anchor: '100%',
allowBlank: false
},
items: [{
xtype: 'hidden',
name: 'id'
}, {
fieldLabel: 'Alias',
name: 'alias',
vtype: 'email'
}, {
fieldLabel: 'Recipient',
name: 'recipient',
vtype: 'email'
}, {
fieldLabel: 'Comment',
xtype: 'textarea',
name: 'comment'
}]
}]
});
Ext.define('MyMA.view.Aliases', {
extend: 'Ext.window.Window',
alias: 'widget.aliases',
layout: 'fit',
minimizable: true,
constrainHeader: true,
closeAction: 'destroy',
width: 900,
listeners: {
render: function(win) {
if(Ext.getBody().getHeight() > 500) {
win.setHeight(Ext.getBody().getHeight() - 150);
}
}
},
items: [{
xtype: 'grid',
border: false,
viewConfig: {
plugins: {
ptype: 'gridviewdragdrop'
},
listeners: {
/**
* This event is fired through the GridView.
* Add listeners to the GridView object Fired when a drop operation has been completed and the data has been moved or copied
* @param {} node
* @param {} data
* @param {} overModel
* @param {} dropPosition
* @param {} eOpts
*/
beforedrop: function(node, data, overModel, dropPosition, eOpts) {
Ext.each(data.records, function(record) {
if(record.get('alias') != this.groupName) {
record.set('alias', this.groupName);
record.save({
action: 'update',
scope: this,
failure: function(record) {
record.store.reload();
}
});
}
}, {
data: data,
groupName: this.getFeature('alias-groups').getGroupName(node),
model: overModel
});
}
}
},
tbar: [{
xtype: 'button',
itemId: 'addrecord',
iconCls: 'x-ibtn-add',
text: 'New Item'
}, {
xtype: 'tbseparator',
width: 5
}, {
xtype: 'searchfield',
handler: 'search',
name: 'query'
}, {
xtype: 'tbspacer',
width: 5
}, {
xtype: 'button',
itemId: 'search',
text: 'Search'
}],
bbar: {
xtype: 'pagingtoolbar',
displayInfo: true,
store: 'Aliases'
},
features: [{
ftype: 'grouping',
id: 'alias-groups',
groupHeaderTpl: 'Group: {name} ({rows.length})',
startCollapsed: false
}],
selModel: {
selType: 'rowmodel'
},
columns: [{
xtype: 'actioncolumn',
width: 30,
items: [{
getClass: function() {
return 'x-ibtn-edit x-ibtn-def';
}
}]
}, {
header: 'ID',
dataIndex: 'id',
width: 40
}, {
header: 'Recipient',
dataIndex: 'recipient',
flex: 1
}, {
header: 'Alias',
hidden: true,
dataIndex: 'alias'
}, {
header: 'Comment',
dataIndex: 'comment',
flex: 1
}, {
xtype: 'actioncolumn',
width: 30,
items: [{
getClass: function() {
return 'x-ibtn-delete x-ibtn-def';
}
}]
}],
selType: 'rowmodel',
multiSelect: true,
store: 'Aliases'
}]
});
Ext.define('MyMA.view.Authorize', {
extend: 'Ext.Window',
alias: 'widget.authorize',
layout: 'fit',
autoShow: true,
layout: 'fit',
width: 350,
closable: false,
constrain: true,
draggable: false,
resizable: false,
modal: true,
cls: 'x-window-authbaner',
dockedItems: [{
dock: 'top',
xtype: 'toolbar',
ui: 'authform-baner',
height: 43,
html: '{LOGIN @ MAIL . PANEL }'
}],
items: [{
xtype: 'form',
url: 'index.php',
monitorValid: true,
frame: false,
border: false,
defaults: {
anchor: '100%'
},
buttons: [{
text: 'Login'
}],
items: [{
fieldLabel: 'Login',
xtype: 'textfield',
allowBlank: false,
name: 'login'
}, {
fieldLabel: 'Password',
xtype: 'textfield',
name: 'pass',
inputType: 'password'
}]
}]
});
Ext.define('MyMA.view.ProgramMenu', {
extend: 'Ext.Button',
alias: 'widget.programmenu',
text: 'Menu',
height: 30,
ui: 'program-menu',
menu: [{
text: 'Users',
widgetName: 'users'
}, {
text: 'Aliases',
widgetName: 'aliases'
}, {
text: 'Transports',
widgetName: 'transports'
}, '-', {
text: 'Logout',
itemId: 'logout'
}]
});
Ext.define('MyMA.view.Taskpanel', {
extend: 'Ext.Toolbar',
alias: 'widget.taskpanel',
ui: 'programbar',
height: 28,
style: {
border: 0,
padding: 0
},
autoScroll: true,
items: []
});
Ext.define('MyMA.view.Transports', {
extend: 'Ext.window.Window',
alias: 'widget.transports',
layout: 'fit',
minimizable: true,
constrainHeader: true,
closeAction: 'destroy',
width: 900,
listeners: {
render: function(win) {
if(Ext.getBody().getHeight() > 500) {
win.setHeight(Ext.getBody().getHeight() - 150);
}
}
},
items: [{
xtype: 'grid',
border: false,
tbar: [{
xtype: 'button',
itemId: 'addrecord',
iconCls: 'x-ibtn-add',
text: 'New Item'
}, {
xtype: 'tbseparator',
width: 5
}, {
xtype: 'searchfield',
handler: 'search',
name: 'query'
}, {
xtype: 'tbspacer',
width: 5
}, {
xtype: 'button',
itemId: 'search',
text: 'Search'
}],
bbar: {
xtype: 'pagingtoolbar',
displayInfo: true,
store: 'Transports'
},
columns: [{
header: 'ID',
dataIndex: 'id',
width: 40
}, {
header: 'Domain',
dataIndex: 'domain',
editor: {
xtype: 'textfield',
allowBlank: false
},
flex: 1
}, {
header: 'Transport',
dataIndex: 'transport'
}, {
xtype: 'actioncolumn',
width: 30,
items: [{
getClass: function() {
return 'x-ibtn-delete x-ibtn-def';
}
}]
}],
selType: 'rowmodel',
plugins: [
Ext.create('Ext.grid.plugin.RowEditing', {
clicksToEdit: 1
})
],
store: 'Transports'
}]
});
Ext.define('MyMA.view.User', {
extend: 'Ext.window.Window',
alias: 'widget.user',
layout: 'fit',
title: 'User',
width: 400,
constrainHeader: true,
closeAction: 'destroy',
buttons: [{
xtype: 'button',
itemId: 'savedata',
text: 'Save',
scope: this
}],
items: [{
xtype: 'form',
frame: true,
monitorValid: true,
defaults: {
xtype: 'textfield',
anchor: '100%',
allowBlank: false
},
items: [{
xtype: 'hidden',
name: 'id'
}, {
xtype: 'checkbox',
fieldLabel: 'Manager',
name: 'manager',
inputValue: 1
}, {
xtype: 'checkbox',
fieldLabel: 'SMTP',
name: 'smtp',
inputValue: 1
}, {
xtype: 'checkbox',
fieldLabel: 'IMAP',
name: 'imap',
inputValue: 1
}, {
fieldLabel: 'Name',
name: 'name'
}, {
fieldLabel: 'Login',
name: 'login',
vtype: 'email'
}, {
fieldLabel: 'Password',
name: 'passwd'
}, {
xtype: 'numberfield',
allowDecimal: false,
fieldLabel: 'UID',
name: 'uid',
anchor: '50%',
value: 8
}, {
xtype: 'numberfield',
allowDecimal: false,
fieldLabel: 'GID',
name: 'gid',
anchor: '50%',
value: 12
}, {
fieldLabel: 'Mail directory',
name: 'maildir'
}, {
xtype: 'numberfield',
name: 'quota',
allowDecimal: false,
fieldLabel: 'Quota',
anchor: '60%',
value: 100000000
}]
}]
});
Ext.define('MyMA.view.Users', {
extend: 'Ext.window.Window',
alias: 'widget.users',
layout: 'fit',
minimizable: true,
constrainHeader: true,
closeAction: 'destroy',
width: 900,
listeners: {
render: function(win) {
if(Ext.getBody().getHeight() > 500) {
win.setHeight(Ext.getBody().getHeight() - 150);
}
}
},
items: [{
xtype: 'grid',
border: false,
listeners: {
/**
* Initiate data save through proxy
* @param editor : Ext.grid.plugin.Editing
* @param object
* grid - The grid
* record - The record that was edited
* field - The field name that was edited
* value - The value being set
* row - The grid table row
* column - The grid Column defining the column that was edited.
* rowIdx - The row index that was edited
* colIdx - The column index that was edited
* originalValue - The original value for the field, before the edit (only when using CellEditing)
* originalValues - The original values for the field, before the edit (only when using RowEditing)
* newValues - The new values being set (only when using RowEditing)
* view - The grid view (only when using RowEditing)
* store - The grid store (only when using RowEditing)
*/
edit: function(editor, data) {
if(data.originalValue == data.value) {
return;
}
data.record.save({
action: 'update',
scope: data,
success: function() {
this.record.commit();
//this.view.refresh();
}
});
}
},
tbar: [{
xtype: 'button',
iconCls: 'x-ibtn-add',
itemId: 'addrecord',
text: 'New Item'
}, {
xtype: 'tbseparator',
width: 5
}, {
xtype: 'searchfield',
handler: 'search',
name: 'query'
}, {
xtype: 'tbspacer',
width: 5
}, {
xtype: 'button',
itemId: 'search',
text: 'Search'
}],
bbar: {
xtype: 'pagingtoolbar',
displayInfo: true,
store: 'Users'
},
plugins: [
Ext.create('Ext.grid.plugin.CellEditing', {
clicksToEdit: 1
})
],
selModel: {
selType: 'cellmodel'
},
columns: [{
xtype: 'actioncolumn',
width: 30,
items: [{
getClass: function() {
return 'x-ibtn-edit x-ibtn-def';
}
}]
}, {
header: 'ID',
dataIndex: 'id',
width: 40
}, {
header: 'Name',
dataIndex: 'name',
editor: {
xtype: 'textfield'
},
flex: 1
}, {
header: 'Login',
dataIndex: 'login',
width: 120
}, {
header: 'Password',
hidden: true,
dataIndex: 'passwd'
}, {
header: 'uid',
dataIndex: 'uid',
width: 40
}, {
header: 'gid',
dataIndex: 'gid',
width: 40
}, {
header: 'Mail directory',
dataIndex: 'maildir'
}, {
header: 'SMTP',
dataIndex: 'smtp',
editor: {
xtype: 'combo',
valueField: 'id',
displayField: 'name',
triggerAction: 'all',
editable: false,
store: 'Choice'
},
renderer: function(value) {
if(value==1) {
return 'Yes';
}
return 'No';
}
}, {
header: 'IMAP',
dataIndex: 'imap',
editor: {
xtype: 'combo',
valueField: 'id',
displayField: 'name',
triggerAction: 'all',
editable: false,
store: 'Choice'
},
renderer: function(value) {
if(value==1) {
return 'Yes';
}
return 'No';
}
}, {
header: 'Quota',
dataIndex: 'quota',
editor: {
xtype: 'numberfield',
allowDecimal: false
}
}, {
xtype: 'actioncolumn',
width: 30,
items: [{
getClass: function() {
return 'x-ibtn-delete x-ibtn-def';
}
}]
}],
store: 'Users'
}]
});
Ext.define('MyMA.view.Viewport', {
extend: 'Ext.container.Viewport',
requires: [
'MyMA.view.ProgramMenu',
'MyMA.view.Taskpanel',
'MyMA.view.Users',
'MyMA.view.Aliases'
],
layout: 'fit',
statics: {
ready: false
},
items: {
xtype: 'panel',
layout: 'fit',
border: false,
dockedItems: [{
dock: 'top',
xtype: 'toolbar',
height: 30,
ui: 'programbar-panel',
items: [{
xtype: 'programmenu',
width: 100
}, '-', {
xtype: 'taskpanel',
flex: 1
}]
}],
items: [{
xtype: 'panel',
border: false,
ui: 'desk-panel',
bodyCls: 'x-desk-panel-bg',
layout: {
type: 'fit'
}
}]
}
});
This diff could not be displayed because it is too large.
This diff could not be displayed because it is too large.
public/images/box/corners-blue.gif

1010 Bytes

public/images/box/corners.gif

1005 Bytes

public/images/box/l-blue.gif

810 Bytes

public/images/box/l.gif

810 Bytes

public/images/box/r-blue.gif

810 Bytes

public/images/box/r.gif

810 Bytes

public/images/box/tb-blue.gif

851 Bytes

public/images/box/tb.gif

839 Bytes

public/images/button/arrow.gif

828 Bytes

public/images/button/btn.gif

4.2 KB

public/images/button/group-lr.gif

861 Bytes

public/images/button/group-tb.gif

846 Bytes

public/images/button/s-arrow-b.gif

937 Bytes

public/images/button/s-arrow-o.gif

937 Bytes

public/images/button/s-arrow.gif

937 Bytes

public/images/dd/drop-add.gif

1001 Bytes

public/images/dd/drop-no.gif

949 Bytes

public/images/dd/drop-yes.gif

1016 Bytes

public/images/form/checkbox.gif

2.01 KB

public/images/form/exclamation.gif

996 Bytes

public/images/form/radio.gif

1.71 KB

public/images/form/spinner.gif

1.93 KB

public/images/form/text-bg.gif

819 Bytes

public/images/form/trigger.gif

1.77 KB

public/images/grid/checked.gif

959 Bytes

public/images/grid/columns.gif

962 Bytes

public/images/grid/dirty.gif

832 Bytes

public/images/grid/done.gif

133 Bytes

public/images/grid/drop-no.gif

947 Bytes

public/images/grid/drop-yes.gif

860 Bytes

public/images/grid/footer-bg.gif

834 Bytes

public/images/grid/grid-hrow.gif

855 Bytes

public/images/grid/grid-split.gif

817 Bytes

public/images/grid/grid3-hrow.gif

836 Bytes

public/images/grid/group-by.gif

917 Bytes

public/images/grid/hd-pop.gif

839 Bytes

public/images/grid/hmenu-asc.gif

931 Bytes

public/images/grid/hmenu-desc.gif

930 Bytes

public/images/grid/hmenu-lock.gif

955 Bytes

public/images/grid/hmenu-lock.png

648 Bytes

public/images/grid/loading.gif

771 Bytes

public/images/grid/mso-hd.gif

875 Bytes

public/images/grid/nowait.gif

884 Bytes

public/images/grid/page-first.gif

925 Bytes

public/images/grid/page-last.gif

923 Bytes

public/images/grid/page-next.gif

875 Bytes

public/images/grid/page-prev.gif

879 Bytes

public/images/grid/refresh.gif

977 Bytes

public/images/grid/row-over.gif

823 Bytes

public/images/grid/row-sel.gif

823 Bytes

public/images/grid/sort-hd.gif

1.44 KB

public/images/grid/sort_asc.gif

830 Bytes

public/images/grid/sort_desc.gif

833 Bytes

public/images/grid/unchecked.gif

941 Bytes

public/images/grid/wait.gif

1.07 KB

public/images/layout/mini-left.gif

871 Bytes

public/images/layout/mini-top.gif

856 Bytes

public/images/menu/checked.gif

959 Bytes

public/images/menu/item-over.gif

47 Bytes

public/images/menu/menu-parent.gif

854 Bytes

public/images/menu/menu.gif

834 Bytes

public/images/menu/unchecked.gif

941 Bytes

public/images/shared/calendar.gif

979 Bytes

public/images/shared/glass-bg.gif

873 Bytes

public/images/shared/left-btn.gif

870 Bytes

public/images/shared/right-btn.gif

871 Bytes

public/images/shared/shadow-c.png

118 Bytes

public/images/shared/shadow-lr.png

135 Bytes

public/images/shared/shadow.png

311 Bytes

public/images/shared/warning.gif

960 Bytes

public/images/sizer/ne-handle.gif

854 Bytes

public/images/sizer/nw-handle.gif

853 Bytes

public/images/sizer/se-handle.gif

853 Bytes

public/images/sizer/square.gif

864 Bytes

public/images/sizer/sw-handle.gif

855 Bytes

public/images/slider/slider-bg.gif

145 Bytes

public/images/tip/tip-sides.gif

1.58 KB

public/images/toolbar/more.gif

845 Bytes

public/images/tree/arrows.gif

617 Bytes

public/images/tree/drop-above.gif

911 Bytes

public/images/tree/drop-add.gif

1001 Bytes

public/images/tree/drop-append.gif

1001 Bytes

public/images/tree/drop-below.gif

911 Bytes

public/images/tree/drop-no.gif

949 Bytes

public/images/tree/drop-over.gif

911 Bytes

public/images/tree/drop-under.gif

911 Bytes

public/images/tree/drop-yes.gif

1016 Bytes

public/images/tree/elbow-end.gif

70 Bytes

public/images/tree/elbow-line.gif

72 Bytes

public/images/tree/elbow-minus.gif

159 Bytes

public/images/tree/elbow-plus.gif

160 Bytes

public/images/tree/elbow.gif

73 Bytes

public/images/tree/folder-open.gif

356 Bytes

public/images/tree/folder.gif

351 Bytes

public/images/tree/leaf.gif

945 Bytes

public/images/tree/loading.gif

771 Bytes

public/images/tree/s.gif

43 Bytes

public/images/ui/panel/._AT.png

66.9 KB

public/images/ui/panel/AT.png

13.2 KB

public/images/ui/toolbar/navbg.jpg

436 Bytes

No preview for this file type
This diff could not be displayed because it is too large.
This diff could not be displayed because it is too large.
This diff could not be displayed because it is too large.
This diff could not be displayed because it is too large.
This diff could not be displayed because it is too large.
This diff could not be displayed because it is too large.
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!