2017-07-18 09:13:16 -05:00
define (
'pgadmin.browser.node' , [
2017-08-08 22:02:16 -05:00
'sources/gettext' , 'jquery' , 'underscore' , 'underscore.string' , 'sources/pgadmin' ,
2017-07-31 08:29:44 -05:00
'pgadmin.browser.menu' , 'backbone' , 'pgadmin.alertifyjs' , 'pgadmin.browser.datamodel' ,
2017-08-17 11:13:07 -05:00
'backform' , 'sources/browser/generate_url' , 'pgadmin.browser.utils' , 'pgadmin.backform'
] , function ( gettext , $ , _ , S , pgAdmin , Menu , Backbone , Alertify , pgBrowser , Backform , generateUrl ) {
2015-06-30 00:51:55 -05:00
2017-06-12 10:43:29 -05:00
var wcDocker = window . wcDocker ,
keyCode = {
ENTER : 13 ,
ESCAPE : 27 ,
F1 : 112
} ;
2015-06-30 00:51:55 -05:00
// It has already been defined.
// Avoid running this script again.
if ( pgBrowser . Node )
return pgBrowser . Node ;
pgBrowser . Nodes = pgBrowser . Nodes || { } ;
// A helper (base) class for all the nodes, this has basic
// operations/callbacks defined for basic operation.
pgBrowser . Node = function ( ) { } ;
// Helper function to correctly set up the property chain, for subclasses.
// Uses a hash of class properties to be extended.
//
// It is unlikely - we will instantiate an object for this class.
// (Inspired by Backbone.extend function)
pgBrowser . Node . extend = function ( props ) {
var parent = this ;
var child ;
// The constructor function for the new subclass is defined to simply call
// the parent's constructor.
child = function ( ) { return parent . apply ( this , arguments ) ; } ;
// Add static properties to the constructor function, if supplied.
_ . extend ( child , parent , _ . omit ( props , 'callbacks' ) ) ;
// Make sure - a child have all the callbacks of the parent.
child . callbacks = _ . extend ( { } , parent . callbacks , props . callbacks ) ;
2016-08-29 01:22:50 -05:00
var bindToChild = function ( cb ) {
if ( typeof ( child . callbacks [ cb ] ) == 'function' ) {
child . callbacks [ cb ] = child . callbacks [ cb ] . bind ( child ) ;
}
} ,
callbacks = _ . keys ( child . callbacks ) ;
for ( var idx = 0 ; idx < callbacks . length ; idx ++ ) bindToChild ( callbacks [ idx ] ) ;
2015-06-30 00:51:55 -05:00
// Registering the node by calling child.Init(...) function
child . Init . apply ( child ) ;
// Initialize the parent
this . Init . apply ( child ) ;
return child ;
} ;
2015-11-19 12:11:58 -06:00
_ . extend ( pgAdmin . Browser . Node , Backbone . Events , {
2015-06-30 00:51:55 -05:00
// Node type
type : undefined ,
// Label
label : '' ,
2016-05-16 10:25:51 -05:00
// Help pages
2016-04-12 07:35:47 -05:00
sqlAlterHelp : '' ,
sqlCreateHelp : '' ,
2016-05-16 10:25:51 -05:00
dialogHelp : '' ,
2016-04-12 07:35:47 -05:00
2017-07-18 09:13:16 -05:00
title : function ( o , d ) {
2016-01-11 10:00:42 -06:00
return o . label + ( d ? ( ' - ' + d . label ) : '' ) ;
2015-06-30 00:51:55 -05:00
} ,
2015-11-19 11:45:48 -06:00
hasId : true ,
2015-06-30 00:51:55 -05:00
///////
// Initialization function
// Generally - used to register the menus for this type of node.
//
// Also, look at pgAdmin.Browser.add_menus(...) function.
//
// NOTE: Override this for each node for initialization purpose
Init : function ( ) {
2016-01-04 10:27:18 -06:00
var self = this ;
if ( self . node _initialized )
2015-06-30 00:51:55 -05:00
return ;
2016-01-04 10:27:18 -06:00
self . node _initialized = true ;
2015-06-30 00:51:55 -05:00
pgAdmin . Browser . add _menus ( [ {
2016-01-04 10:27:18 -06:00
name : 'refresh' , node : self . type , module : self ,
2015-12-04 04:19:08 -06:00
applies : [ 'object' , 'context' ] , callback : 'refresh' ,
2017-06-07 05:23:02 -05:00
priority : 1 , label : gettext ( 'Refresh...' ) ,
2015-10-20 02:03:18 -05:00
icon : 'fa fa-refresh'
2015-06-30 00:51:55 -05:00
} ] ) ;
2016-01-04 10:27:18 -06:00
2016-08-22 06:30:16 -05:00
if ( self . canEdit ) {
pgAdmin . Browser . add _menus ( [ {
name : 'show_obj_properties' , node : self . type , module : self ,
applies : [ 'object' , 'context' ] , callback : 'show_obj_properties' ,
2017-06-07 05:23:02 -05:00
priority : 999 , label : gettext ( 'Properties...' ) ,
2016-08-22 06:30:16 -05:00
data : { 'action' : 'edit' } , icon : 'fa fa-pencil-square-o'
} ] ) ;
}
2016-01-04 10:27:18 -06:00
if ( self . canDrop ) {
pgAdmin . Browser . add _menus ( [ {
name : 'delete_object' , node : self . type , module : self ,
applies : [ 'object' , 'context' ] , callback : 'delete_obj' ,
2017-06-07 05:23:02 -05:00
priority : 2 , label : gettext ( 'Delete/Drop' ) ,
2016-01-04 10:27:18 -06:00
data : { 'url' : 'drop' } , icon : 'fa fa-trash' ,
2016-05-13 14:39:59 -05:00
enable : _ . isFunction ( self . canDrop ) ?
function ( ) {
return ! ! ( self . canDrop . apply ( self , arguments ) ) ;
} : ( ! ! self . canDrop )
2016-01-04 10:27:18 -06:00
} ] ) ;
if ( self . canDropCascade ) {
pgAdmin . Browser . add _menus ( [ {
name : 'delete_object_cascade' , node : self . type , module : self ,
applies : [ 'object' , 'context' ] , callback : 'delete_obj' ,
2017-06-07 05:23:02 -05:00
priority : 3 , label : gettext ( 'Drop Cascade' ) ,
2016-01-04 10:27:18 -06:00
data : { 'url' : 'delete' } , icon : 'fa fa-trash' ,
2016-05-06 09:47:21 -05:00
enable : _ . isFunction ( self . canDropCascade ) ?
function ( ) { return self . canDropCascade . apply ( self , arguments ) ; } : ( ! ! self . canDropCascade )
2016-01-04 10:27:18 -06:00
} ] ) ;
}
}
2016-06-08 07:18:59 -05:00
2016-06-20 08:17:10 -05:00
// show query tool only in context menu of supported nodes.
2017-07-27 06:55:07 -05:00
if ( true ) {
if ( _ . indexOf ( pgAdmin . unsupported _nodes , self . type ) == - 1 ) {
pgAdmin . Browser . add _menus ( [ {
name : 'show_query_tool' , node : self . type , module : self ,
applies : [ 'context' ] , callback : 'show_query_tool' ,
priority : 998 , label : gettext ( 'Query Tool...' ) ,
icon : 'fa fa-bolt' ,
enable : function ( itemData , item , data ) {
if ( itemData . _type == 'database' && itemData . allowConn )
return true ;
else if ( itemData . _type != 'database' )
return true ;
else
return false ;
}
} ] ) ;
}
2016-06-08 07:18:59 -05:00
}
2016-05-15 13:55:31 -05:00
// This will add options of scripts eg:'CREATE Script'
if ( self . hasScriptTypes && _ . isArray ( self . hasScriptTypes )
&& self . hasScriptTypes . length > 0 ) {
// For each script type create menu
_ . each ( self . hasScriptTypes , function ( stype ) {
var type _label = S (
2017-07-18 09:13:16 -05:00
gettext ( "%s Script" )
2016-05-15 13:55:31 -05:00
) . sprintf ( stype . toUpperCase ( ) ) . value ( ) ,
stype = stype . toLowerCase ( ) ;
// Adding menu for each script type
pgAdmin . Browser . add _menus ( [ {
name : 'show_script_' + stype , node : self . type , module : self ,
applies : [ 'object' , 'context' ] , callback : 'show_script' ,
2016-06-08 07:18:59 -05:00
priority : 4 , label : type _label , category : 'Scripts' ,
2016-05-15 13:55:31 -05:00
data : { 'script' : stype } , icon : 'fa fa-pencil' ,
2016-09-23 04:06:50 -05:00
enable : self . check _user _permission
2016-05-15 13:55:31 -05:00
} ] ) ;
} ) ;
}
} ,
///////
// Checks if Script Type is allowed to user
// First check if role node & create role allowed
// Otherwise test rest of database objects
// if no permission matched then do not allow create script
///////
check _user _permission : function ( itemData , item , data ) {
2016-09-23 04:06:50 -05:00
// Do not display CREATE script on server group and server node
2017-07-27 06:55:07 -05:00
if ( itemData . _type == 'server_group' || itemData . _type == 'server' ) {
2016-09-23 04:06:50 -05:00
return false ;
}
2016-12-09 05:59:13 -06:00
// Do not display the menu if the database connection is not allowed
if ( itemData . _type == 'database' && ! itemData . allowConn )
return false ;
2016-05-15 13:55:31 -05:00
var node = pgBrowser . Nodes [ itemData . _type ] ,
parentData = node . getTreeNodeHierarchy ( item ) ;
if ( _ . indexOf ( [ 'create' , 'insert' , 'update' , 'delete' ] , data . script ) != - 1 ) {
if ( itemData . type == 'role' &&
parentData . server . user . can _create _role ) {
return true ;
2016-10-18 06:37:44 -05:00
} else if (
(
parentData . server && (
parentData . server . user . is _superuser ||
parentData . server . user . can _create _db )
) ||
(
parentData . schema && parentData . schema . can _create
)
) {
2016-05-15 13:55:31 -05:00
return true ;
} else {
return false ;
}
} else {
return true ;
}
2015-06-30 00:51:55 -05:00
} ,
///////
// Generate a Backform view using the node's model type
//
// Used to generate view for the particular node properties, edit,
// creation.
2016-08-29 01:22:50 -05:00
getView : function ( item , type , el , node , formType , callback , ctx , cancelFunc ) {
2016-01-04 02:04:45 -06:00
var that = this ;
2015-06-30 00:51:55 -05:00
2015-10-28 12:06:09 -05:00
if ( ! this . type || this . type == '' )
2015-06-30 00:51:55 -05:00
// We have no information, how to generate view for this type.
return null ;
if ( this . model ) {
// This will be the URL, used for object manipulation.
// i.e. Create, Update in these cases
2015-11-19 11:45:48 -06:00
var urlBase = this . generate _url ( item , type , node , false ) ;
2015-06-30 00:51:55 -05:00
if ( ! urlBase )
// Ashamed of myself, I don't know how to manipulate this
// node.
return null ;
2015-10-28 12:06:09 -05:00
var attrs = { } ;
2015-06-30 00:51:55 -05:00
// In order to get the object data from the server, we must set
// object-id in the model (except in the create mode).
if ( type !== 'create' ) {
2015-12-16 02:07:49 -06:00
attrs [ this . model . idAttribute || this . model . prototype . idAttribute ||
'id' ] = node . _id ;
2015-06-30 00:51:55 -05:00
}
// We know - which data model to be used for this object.
2016-01-15 07:40:29 -06:00
var info = this . getTreeNodeHierarchy . apply ( this , [ item ] ) ,
newModel = new ( this . model . extend ( { urlRoot : urlBase } ) ) (
attrs , { node _info : info }
) ,
2016-01-17 10:51:02 -06:00
fields = Backform . generateViewSchema (
2016-01-12 10:48:54 -06:00
info , newModel , type , this , node
) ;
2015-06-30 00:51:55 -05:00
2016-01-04 05:24:06 -06:00
if ( type == 'create' || type == 'edit' ) {
2016-01-12 10:48:54 -06:00
if ( callback && ctx ) {
callback = callback . bind ( ctx ) ;
} else {
callback = function ( ) {
console . log ( "Broke something!!! Why we don't have the callback or the context???" ) ;
} ;
}
Data management within the properties dialog in Create/Edit mode is not
done using the Backbone event management.
Emitting 'pgadmin-session:*' for different operations, when we
create/modify the data within the properties dialog.
We will keep track of each child node using the handler object within
the Model, and Collection objects, also - provides them the name of the
attribute, it represents. It will be used to identify the invalid nested
objects within the existing object.
Also, provide the array of modified variables, which were modified in
the validation function to avoid checking each, and every thing in the
validation function. We will need to validate that particular and the
dependent attributes only.
Also - avoid multiple validation operations from the parent object to
improve performance. And, depends on the event based operations for
validation, instead of integrate the data operation and view operation
within one operation. We do maintain the invalid objects, and validate
them only from the collection objects, which also helps improve the
performance during validation.
2016-01-15 04:29:20 -06:00
var onSessionInvalid = function ( msg ) {
2017-07-10 03:36:10 -05:00
var alertMessage = ' \
< div class = "media error-in-footer bg-red-1 border-red-2 font-red-3 text-14" > \
< div class = "media-body media-middle" > \
< div class = "alert-icon error-icon" > \
< i class = "fa fa-exclamation-triangle" aria - hidden = "true" > < / i > \
< / d i v > \
< div class = "alert-text" > ' + msg + ' < / d i v > \
2017-11-28 08:10:12 -06:00
< div class = "close-error-bar" > \
< a class = "close-error" > x < / a > \
< / d i v > \
2017-07-10 03:36:10 -05:00
< / d i v > \
< / d i v > ' ;
2016-01-04 05:24:06 -06:00
if ( ! _ . isUndefined ( that . statusBar ) ) {
2017-07-10 03:36:10 -05:00
that . statusBar . html ( alertMessage ) . css ( "visibility" , "visible" ) ;
2017-11-28 08:10:12 -06:00
that . statusBar . find ( "a.close-error" ) . bind ( "click" , function ( e ) {
this . empty ( ) . css ( "visibility" , "hidden" ) ;
} . bind ( that . statusBar ) ) ;
2016-01-04 05:24:06 -06:00
}
2016-01-12 10:48:54 -06:00
callback ( true ) ;
return true ;
Data management within the properties dialog in Create/Edit mode is not
done using the Backbone event management.
Emitting 'pgadmin-session:*' for different operations, when we
create/modify the data within the properties dialog.
We will keep track of each child node using the handler object within
the Model, and Collection objects, also - provides them the name of the
attribute, it represents. It will be used to identify the invalid nested
objects within the existing object.
Also, provide the array of modified variables, which were modified in
the validation function to avoid checking each, and every thing in the
validation function. We will need to validate that particular and the
dependent attributes only.
Also - avoid multiple validation operations from the parent object to
improve performance. And, depends on the event based operations for
validation, instead of integrate the data operation and view operation
within one operation. We do maintain the invalid objects, and validate
them only from the collection objects, which also helps improve the
performance during validation.
2016-01-15 04:29:20 -06:00
} ;
2016-01-12 10:48:54 -06:00
Data management within the properties dialog in Create/Edit mode is not
done using the Backbone event management.
Emitting 'pgadmin-session:*' for different operations, when we
create/modify the data within the properties dialog.
We will keep track of each child node using the handler object within
the Model, and Collection objects, also - provides them the name of the
attribute, it represents. It will be used to identify the invalid nested
objects within the existing object.
Also, provide the array of modified variables, which were modified in
the validation function to avoid checking each, and every thing in the
validation function. We will need to validate that particular and the
dependent attributes only.
Also - avoid multiple validation operations from the parent object to
improve performance. And, depends on the event based operations for
validation, instead of integrate the data operation and view operation
within one operation. We do maintain the invalid objects, and validate
them only from the collection objects, which also helps improve the
performance during validation.
2016-01-15 04:29:20 -06:00
var onSessionValidated = function ( sessHasChanged ) {
2016-01-12 10:48:54 -06:00
2016-01-04 05:24:06 -06:00
if ( ! _ . isUndefined ( that . statusBar ) ) {
2016-01-21 03:10:00 -06:00
that . statusBar . empty ( ) . css ( "visibility" , "hidden" ) ;
2016-01-04 05:24:06 -06:00
}
2016-01-12 10:48:54 -06:00
Data management within the properties dialog in Create/Edit mode is not
done using the Backbone event management.
Emitting 'pgadmin-session:*' for different operations, when we
create/modify the data within the properties dialog.
We will keep track of each child node using the handler object within
the Model, and Collection objects, also - provides them the name of the
attribute, it represents. It will be used to identify the invalid nested
objects within the existing object.
Also, provide the array of modified variables, which were modified in
the validation function to avoid checking each, and every thing in the
validation function. We will need to validate that particular and the
dependent attributes only.
Also - avoid multiple validation operations from the parent object to
improve performance. And, depends on the event based operations for
validation, instead of integrate the data operation and view operation
within one operation. We do maintain the invalid objects, and validate
them only from the collection objects, which also helps improve the
performance during validation.
2016-01-15 04:29:20 -06:00
callback ( false , sessHasChanged ) ;
} ;
2016-01-12 10:48:54 -06:00
Data management within the properties dialog in Create/Edit mode is not
done using the Backbone event management.
Emitting 'pgadmin-session:*' for different operations, when we
create/modify the data within the properties dialog.
We will keep track of each child node using the handler object within
the Model, and Collection objects, also - provides them the name of the
attribute, it represents. It will be used to identify the invalid nested
objects within the existing object.
Also, provide the array of modified variables, which were modified in
the validation function to avoid checking each, and every thing in the
validation function. We will need to validate that particular and the
dependent attributes only.
Also - avoid multiple validation operations from the parent object to
improve performance. And, depends on the event based operations for
validation, instead of integrate the data operation and view operation
within one operation. We do maintain the invalid objects, and validate
them only from the collection objects, which also helps improve the
performance during validation.
2016-01-15 04:29:20 -06:00
callback ( false , false ) ;
newModel . on ( 'pgadmin-session:valid' , onSessionValidated ) ;
newModel . on ( 'pgadmin-session:invalid' , onSessionInvalid ) ;
2016-01-04 02:04:45 -06:00
}
2015-06-30 00:51:55 -05:00
// 'schema' has the information about how to generate the form.
2016-01-17 10:51:02 -06:00
if ( _ . size ( fields ) ) {
2015-06-30 00:51:55 -05:00
// This will contain the actual view
var view ;
if ( formType == 'fieldset' ) {
// It is used to show, edit, create the object in the
// properties tab.
view = new Backform . Fieldset ( {
el : el , model : newModel , schema : fields
} ) ;
} else {
// This generates a view to be used by the node dialog
// (for create/edit operation).
view = new Backform . Dialog ( {
el : el , model : newModel , schema : fields
} ) ;
}
2017-06-08 08:37:31 -05:00
var setFocusOnEl = function ( ) {
setTimeout ( function ( ) {
$ ( el ) . find ( '.tab-pane.active:first' ) . find ( 'input:first' ) . focus ( ) ;
} , 500 ) ;
} ;
2015-06-30 00:51:55 -05:00
if ( ! newModel . isNew ( ) ) {
// This is definetely not in create mode
2016-09-26 09:10:38 -05:00
var msgDiv = '<div class="alert alert-info pg-panel-message pg-panel-properties-message">' +
2017-06-07 05:23:02 -05:00
gettext ( "Retrieving data from the server..." ) + '</div>' ,
2016-09-26 09:10:38 -05:00
$msgDiv = $ ( msgDiv ) ;
var timer = setTimeout ( function ( ctx ) {
// notify user if request is taking longer than 1 second
if ( ! _ . isUndefined ( ctx ) ) {
$msgDiv . appendTo ( ctx ) ;
}
} , 1000 , ctx ) ;
2017-06-08 08:37:31 -05:00
2017-07-18 09:13:16 -05:00
newModel . fetch ( {
success : function ( res , msg , xhr ) {
// clear timeout and remove message
clearTimeout ( timer ) ;
$msgDiv . addClass ( 'hidden' ) ;
// We got the latest attributes of the
// object. Render the view now.
view . render ( ) ;
setFocusOnEl ( ) ;
newModel . startNewSession ( ) ;
} ,
error : function ( xhr , error , message ) {
var _label = that && item ?
that . getTreeNodeHierarchy (
item
) [ that . type ] . label : '' ;
pgBrowser . Events . trigger (
'pgadmin:node:retrieval:error' , 'properties' ,
xhr , error , message , item
2016-08-29 01:22:50 -05:00
) ;
2017-07-18 09:13:16 -05:00
if (
! Alertify . pgHandleItemError (
xhr , error , message , { item : item , info : info }
)
) {
Alertify . pgNotifier (
error , xhr ,
S (
gettext ( "Error retrieving properties - %s" )
) . sprintf ( message || _label ) . value ( ) ,
function ( ) {
console . log ( arguments ) ;
}
) ;
}
// Close the panel (if could not fetch properties)
if ( cancelFunc ) {
cancelFunc ( ) ;
}
2016-08-29 01:22:50 -05:00
}
} ) ;
2015-06-30 00:51:55 -05:00
} else {
// Yay - render the view now!
2017-06-08 08:37:31 -05:00
// $(el).focus();
Data management within the properties dialog in Create/Edit mode is not
done using the Backbone event management.
Emitting 'pgadmin-session:*' for different operations, when we
create/modify the data within the properties dialog.
We will keep track of each child node using the handler object within
the Model, and Collection objects, also - provides them the name of the
attribute, it represents. It will be used to identify the invalid nested
objects within the existing object.
Also, provide the array of modified variables, which were modified in
the validation function to avoid checking each, and every thing in the
validation function. We will need to validate that particular and the
dependent attributes only.
Also - avoid multiple validation operations from the parent object to
improve performance. And, depends on the event based operations for
validation, instead of integrate the data operation and view operation
within one operation. We do maintain the invalid objects, and validate
them only from the collection objects, which also helps improve the
performance during validation.
2016-01-15 04:29:20 -06:00
view . render ( ) ;
2017-06-08 08:37:31 -05:00
setFocusOnEl ( ) ;
Data management within the properties dialog in Create/Edit mode is not
done using the Backbone event management.
Emitting 'pgadmin-session:*' for different operations, when we
create/modify the data within the properties dialog.
We will keep track of each child node using the handler object within
the Model, and Collection objects, also - provides them the name of the
attribute, it represents. It will be used to identify the invalid nested
objects within the existing object.
Also, provide the array of modified variables, which were modified in
the validation function to avoid checking each, and every thing in the
validation function. We will need to validate that particular and the
dependent attributes only.
Also - avoid multiple validation operations from the parent object to
improve performance. And, depends on the event based operations for
validation, instead of integrate the data operation and view operation
within one operation. We do maintain the invalid objects, and validate
them only from the collection objects, which also helps improve the
performance during validation.
2016-01-15 04:29:20 -06:00
newModel . startNewSession ( ) ;
2015-06-30 00:51:55 -05:00
}
}
return view ;
}
return null ;
} ,
register _node _panel : function ( ) {
var w = pgBrowser . docker ,
p = w . findPanels ( 'node_props' ) ;
if ( p && p . length == 1 )
return ;
2016-09-26 04:04:49 -05:00
var events = { } ;
events [ wcDocker . EVENT . RESIZE _ENDED ] = function ( ) {
var $container = this . $container . find ( '.obj_properties' ) . first ( ) ,
v = $container . data ( 'obj-view' ) ;
if ( v && v . model && v . model ) {
v . model . trigger (
'pg-browser-resized' , {
'view' : v , 'panel' : this , 'container' : $container
} ) ;
}
} ;
2015-06-30 00:51:55 -05:00
p = new pgBrowser . Panel ( {
name : 'node_props' ,
showTitle : true ,
2015-08-11 08:49:27 -05:00
isCloseable : true ,
isPrivate : true ,
2016-05-25 05:17:56 -05:00
elContainer : true ,
2017-11-01 10:18:07 -05:00
content : '<div class="obj_properties"><div class="alert alert-info pg-panel-message">' + gettext ( 'Please wait while we fetch information about the node from the server...' ) + '</div></div>' ,
2016-05-25 05:17:56 -05:00
onCreate : function ( myPanel , $container ) {
$container . addClass ( 'pg-no-overflow' ) ;
2016-09-26 04:04:49 -05:00
} ,
events : events
} ) ;
2015-06-30 00:51:55 -05:00
p . load ( pgBrowser . docker ) ;
} ,
2016-08-22 06:30:16 -05:00
/ *
* Default script type menu for node .
*
* Override this , to show more script type menus ( e . g hasScriptTypes : [ 'create' , 'select' , 'insert' , 'update' , 'delete' ] )
*
* Or set it to empty array to disable script type menu on node ( e . g hasScriptTypes : [ ] )
* /
hasScriptTypes : [ 'create' ] ,
/ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* This function determines the given item is editable or not .
*
* Override this , when a node is not editable .
* /
canEdit : true ,
2015-06-30 00:51:55 -05:00
/ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* This function determines the given item is deletable or not .
*
* Override this , when a node is not deletable .
* /
2016-01-04 10:27:18 -06:00
canDrop : false ,
/ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* This function determines the given item and children are deletable or
* not .
*
* Override this , when a node is not deletable .
* /
canDropCascade : false ,
2015-06-30 00:51:55 -05:00
// List of common callbacks - that can be used for different
// operations!
callbacks : {
/ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* This function allows to create / edit / show properties of any
* object depending on the arguments provided .
*
* args must be a object containing :
* action - create / edit / properties
2017-11-07 19:27:10 -06:00
* item - The properties of the item ( tree node item )
2015-06-30 00:51:55 -05:00
*
* NOTE :
* if item is not provided , the action will be done on the
* currently selected tree item node .
*
* * /
2016-01-06 21:07:14 -06:00
show _obj _properties : function ( args , item ) {
2015-06-30 00:51:55 -05:00
var t = pgBrowser . tree ,
2016-01-06 21:07:14 -06:00
i = args . item || item || t . selected ( ) ,
2017-07-18 09:13:16 -05:00
d = i && i . length == 1 ? t . itemData ( i ) : undefined ,
2015-06-30 00:51:55 -05:00
o = this ,
2016-01-11 10:00:42 -06:00
l = o . title . apply ( this , [ d ] ) ;
2015-06-30 00:51:55 -05:00
// Make sure - the properties dialog type registered
pgBrowser . Node . register _node _panel ( ) ;
// No node selected.
if ( ! d )
return ;
2016-01-04 06:22:30 -06:00
var self = this ,
isParent = ( _ . isArray ( this . parent _type ) ?
function ( d ) {
return ( _ . indexOf ( self . parent _type , d . _type ) != - 1 ) ;
} : function ( d ) {
return ( self . parent _type == d . _type ) ;
2016-05-21 03:48:24 -05:00
} ) ,
addPanel = function ( ) {
var d = window . document ,
b = d . body ,
el = d . createElement ( 'div' ) ;
d . body . insertBefore ( el , d . body . firstChild ) ;
2016-05-25 05:17:56 -05:00
var pW = screen . width < 800 ? '95%' : '500px' ,
2017-07-18 09:13:16 -05:00
pH = screen . height < 600 ? '95%' : '550px' ,
2016-05-21 03:48:24 -05:00
w = pgAdmin . toPx ( el , self . width || pW , 'width' , true ) ,
h = pgAdmin . toPx ( el , self . height || pH , 'height' , true ) ,
x = ( b . offsetWidth - w ) / 2 ,
y = ( b . offsetHeight - h ) / 2 ;
2017-07-18 09:13:16 -05:00
var p = pgBrowser . docker . addPanel (
2016-05-21 03:48:24 -05:00
'node_props' , wcDocker . DOCK . FLOAT , undefined ,
{ w : w + 'px' , h : h + 'px' , x : x + 'px' , y : y + 'px' }
) ;
b . removeChild ( el ) ;
2017-07-27 06:55:07 -05:00
// delete(el);
2016-05-21 03:48:24 -05:00
return p ;
} ;
2016-01-04 06:22:30 -06:00
2015-06-30 00:51:55 -05:00
if ( args . action == 'create' ) {
// If we've parent, we will get the information of it for
// proper object manipulation.
//
// You know - we're working with RDBMS, relation is everything
// for us.
2016-01-04 11:55:21 -06:00
if ( self . parent _type && ! isParent ( d ) ) {
2015-06-30 00:51:55 -05:00
// In browser tree, I can be under any node, But - that
// does not mean, it is my parent.
//
// We have some group nodes too.
//
// i.e.
// Tables, Views, etc. nodes under Schema node
//
// And, actual parent of a table is schema, not Tables.
while ( i && t . hasParent ( i ) ) {
i = t . parent ( i ) ;
2017-07-18 09:13:16 -05:00
var pd = t . itemData ( i ) ;
2015-06-30 00:51:55 -05:00
2016-01-04 11:55:21 -06:00
if ( isParent ( pd ) ) {
2015-06-30 00:51:55 -05:00
// Assign the data, this is my actual parent.
d = pd ;
break ;
}
}
}
// Seriously - I really don't have parent data present?
//
// The only node - which I know - who does not have parent
// node, is the Server Group (and, comes directly under root
// node - which has no parent.)
2016-01-04 11:55:21 -06:00
if ( ! d || ( this . parent _type != null && ! isParent ( d ) ) ) {
2015-06-30 00:51:55 -05:00
// It should never come here.
// If it is here, that means - we do have some bug in code.
return ;
}
if ( ! d )
return ;
2017-06-07 05:23:02 -05:00
l = S ( gettext ( 'Create - %s' ) ) . sprintf (
2015-06-30 00:51:55 -05:00
[ this . label ] ) . value ( ) ;
2016-05-21 03:48:24 -05:00
p = addPanel ( ) ;
2015-06-30 00:51:55 -05:00
setTimeout ( function ( ) {
o . showProperties ( i , d , p , args . action ) ;
} , 10 ) ;
} else {
if ( pgBrowser . Node . panels && pgBrowser . Node . panels [ d . id ] &&
pgBrowser . Node . panels [ d . id ] . $container ) {
2017-07-18 09:13:16 -05:00
var p = pgBrowser . Node . panels [ d . id ] ;
2015-06-30 00:51:55 -05:00
/ * * T O D O : :
* Run in edit mode ( if asked ) only when it is
* not already been running edit mode
* * /
var mode = p . $container . attr ( 'action-mode' ) ;
if ( mode ) {
2017-06-07 05:23:02 -05:00
var msg = gettext ( 'Are you sure want to stop editing the properties of %s "%s"?' ) ;
2015-06-30 00:51:55 -05:00
if ( args . action == 'edit' ) {
2017-06-07 05:23:02 -05:00
msg = gettext ( 'Are you sure want to reset the current changes and re-open the panel for %s "%s"?' ) ;
2015-06-30 00:51:55 -05:00
}
Alertify . confirm (
2017-06-07 05:23:02 -05:00
gettext ( 'Edit in progress?' ) ,
2016-07-25 11:23:10 -05:00
S ( msg ) . sprintf ( o . label . toLowerCase ( ) , d . label ) . value ( ) ,
2015-06-30 00:51:55 -05:00
function ( ) {
setTimeout ( function ( ) {
o . showProperties ( i , d , p , args . action ) ;
} , 10 ) ;
} ,
null ) . show ( ) ;
} else {
setTimeout ( function ( ) {
o . showProperties ( i , d , p , args . action ) ;
} , 10 ) ;
}
} else {
pgBrowser . Node . panels = pgBrowser . Node . panels || { } ;
2016-05-21 03:48:24 -05:00
p = pgBrowser . Node . panels [ d . id ] = addPanel ( ) ;
2015-06-30 00:51:55 -05:00
setTimeout ( function ( ) {
o . showProperties ( i , d , p , args . action ) ;
} , 10 ) ;
}
}
p . title ( l ) ;
p . icon ( 'icon-' + this . type ) ;
// Make sure the properties dialog is visible
p . focus ( ) ;
} ,
// Delete the selected object
2016-01-05 01:06:33 -06:00
delete _obj : function ( args , item ) {
2016-06-03 05:01:47 -05:00
var input = args || { 'url' : 'drop' } ,
obj = this ,
t = pgBrowser . tree ,
i = input . item || item || t . selected ( ) ,
d = i && i . length == 1 ? t . itemData ( i ) : undefined ;
2015-06-30 00:51:55 -05:00
if ( ! d )
return ;
2016-01-05 01:06:33 -06:00
/ *
* Make sure - we ' re using the correct version of node
* /
obj = pgBrowser . Nodes [ d . _type ] ;
var objName = d . label ;
2016-01-04 10:27:18 -06:00
var msg , title ;
if ( input . url == 'delete' ) {
2017-06-07 05:23:02 -05:00
msg = S ( gettext ( 'Are you sure you want to drop %s "%s" and all the objects that depend on it?' ) )
2016-07-25 11:23:10 -05:00
. sprintf ( obj . label . toLowerCase ( ) , d . label ) . value ( ) ;
2017-06-07 05:23:02 -05:00
title = S ( gettext ( 'DROP CASCADE %s?' ) ) . sprintf ( obj . label ) . value ( ) ;
2016-01-04 10:27:18 -06:00
2016-01-05 01:06:33 -06:00
if ( ! ( _ . isFunction ( obj . canDropCascade ) ?
obj . canDropCascade . apply ( obj , [ d , i ] ) : obj . canDropCascade ) ) {
2017-07-31 08:29:44 -05:00
Alertify . error (
2017-11-06 18:49:11 -06:00
S ( gettext ( 'The %s "%s" cannot be dropped.' ) )
2016-01-05 01:06:33 -06:00
. sprintf ( obj . label , d . label ) . value ( ) ,
10
) ;
2016-01-04 10:27:18 -06:00
return ;
}
} else {
2017-06-07 05:23:02 -05:00
msg = S ( gettext ( 'Are you sure you want to drop %s "%s"?' ) )
2016-07-25 11:23:10 -05:00
. sprintf ( obj . label . toLowerCase ( ) , d . label ) . value ( ) ;
2017-06-07 05:23:02 -05:00
title = S ( gettext ( 'DROP %s?' ) ) . sprintf ( obj . label ) . value ( ) ;
2015-06-30 00:51:55 -05:00
2016-01-05 01:06:33 -06:00
if ( ! ( _ . isFunction ( obj . canDrop ) ?
2017-06-30 04:21:05 -05:00
obj . canDrop . apply ( obj , [ d , i ] ) : obj . canDrop ) ) {
2017-07-31 08:29:44 -05:00
Alertify . error (
2017-11-06 18:49:11 -06:00
S ( gettext ( 'The %s "%s" cannot be dropped.' ) )
2017-06-30 04:21:05 -05:00
. sprintf ( obj . label , d . label ) . value ( ) ,
10
) ;
2016-01-04 10:27:18 -06:00
return ;
}
}
Alertify . confirm ( title , msg ,
function ( ) {
$ . ajax ( {
url : obj . generate _url ( i , input . url , d , true ) ,
type : 'DELETE' ,
success : function ( res ) {
if ( res . success == 0 ) {
pgBrowser . report _error ( res . errormsg , res . info ) ;
} else {
2017-07-07 01:25:55 -05:00
pgBrowser . removeTreeNode ( i , true ) ;
2015-06-30 00:51:55 -05:00
}
2016-01-04 10:27:18 -06:00
return true ;
} ,
error : function ( jqx ) {
var msg = jqx . responseText ;
/* Error from the server */
2016-05-16 12:25:19 -05:00
if ( jqx . status == 417 || jqx . status == 410 || jqx . status == 500 ) {
2016-01-04 10:27:18 -06:00
try {
2016-01-05 01:06:33 -06:00
var data = $ . parseJSON ( jqx . responseText ) ;
2016-01-04 10:27:18 -06:00
msg = data . errormsg ;
} catch ( e ) { }
}
pgBrowser . report _error (
2017-06-07 05:23:02 -05:00
S ( gettext ( 'Error dropping %s: "%s"' ) )
2016-01-05 01:06:33 -06:00
. sprintf ( obj . label , objName )
2016-01-04 10:27:18 -06:00
. value ( ) , msg ) ;
}
} ) ;
} ,
null ) . show ( )
2015-06-30 00:51:55 -05:00
} ,
2016-05-15 13:55:31 -05:00
// Callback for creating script(s) & opening them in Query editor
show _script : function ( args , item ) {
var scriptType = args . script ,
obj = this ,
t = pgBrowser . tree ,
i = item || t . selected ( ) ,
d = i && i . length == 1 ? t . itemData ( i ) : undefined ;
if ( ! d )
return ;
/ *
* Make sure - we ' re using the correct version of node
* /
obj = pgBrowser . Nodes [ d . _type ] ;
2017-07-18 09:13:16 -05:00
var objName = d . label ,
sql _url ;
2016-05-15 13:55:31 -05:00
// URL for script type
if ( scriptType == 'insert' ) {
sql _url = 'insert_sql' ;
} else if ( scriptType == 'update' ) {
sql _url = 'update_sql' ;
} else if ( scriptType == 'delete' ) {
sql _url = 'delete_sql' ;
} else if ( scriptType == 'select' ) {
sql _url = 'select_sql' ;
} else if ( scriptType == 'exec' ) {
sql _url = 'exec_sql' ;
} else {
// By Default get CREATE SQL
sql _url = 'sql' ;
}
// Open data grid & pass the URL for fetching
2017-06-15 06:19:47 -05:00
pgAdmin . DataGrid . show _query _tool (
obj . generate _url ( i , sql _url , d , true ) ,
i , scriptType
2016-05-15 13:55:31 -05:00
) ;
} ,
2016-06-08 07:18:59 -05:00
// Callback to render query editor
show _query _tool : function ( args , item ) {
var obj = this ,
t = pgBrowser . tree ,
i = item || t . selected ( ) ,
d = i && i . length == 1 ? t . itemData ( i ) : undefined ;
if ( ! d )
return ;
// Here call data grid method to render query tool
2017-06-13 05:34:13 -05:00
pgAdmin . DataGrid . show _query _tool ( '' , i ) ;
2016-06-08 07:18:59 -05:00
} ,
2017-11-21 10:28:01 -06:00
// Logic to change the server background colour
// There is no way of applying CSS to parent element so we have to
// do it via JS code only
change _server _background : function ( item , data ) {
if ( ! item || ! data )
return ;
// Go further only if node type is a Server
if ( data && data . _type && data . _type == 'server' ) {
var element = $ ( item ) . find ( 'span.aciTreeItem' ) . first ( ) || null ,
// First element will be icon and second will be colour code
bgcolor = data . icon . split ( " " ) [ 1 ] || null ,
fgcolor = data . icon . split ( " " ) [ 2 ] || '' ;
if ( bgcolor ) {
// li tag for the current branch
var first _level _element = element . parents ( ) [ 3 ] || null ,
dynamic _class = 'pga_server_' + data . _id + '_bgcolor' ,
style _tag ;
// Prepare dynamic style tag
style _tag = "<style id=" + dynamic _class + " type='text/css'> \n" ;
style _tag += "." + dynamic _class + ' .aciTreeItem {' ;
style _tag += " border-radius: 3px; margin-bottom: 2px;" ;
style _tag += " background: " + bgcolor + "} \n" ;
if ( fgcolor ) {
style _tag += "." + dynamic _class + ' .aciTreeText {' ;
style _tag += " color: " + fgcolor + ";} \n"
}
style _tag += "</style>" ;
// Prepare dynamic style tag using template
$ ( '#' + dynamic _class ) . remove ( ) ;
$ ( style _tag ) . appendTo ( "head" ) ;
if ( first _level _element )
$ ( first _level _element ) . addClass ( dynamic _class ) ;
}
}
} ,
2016-08-09 06:12:05 -05:00
added : function ( item , data , browser ) {
var b = browser || pgBrowser ,
t = b . tree ,
pItem = t . parent ( item ) ,
pData = pItem && t . itemData ( pItem ) ,
pNode = pData && pgBrowser . Nodes [ pData . _type ] ;
// Check node is a collection or not.
if ( pNode && pNode . is _collection ) {
/ * I f ' c o l l e c t i o n _ c o u n t ' i s n o t p r e s e n t i n d a t a
* it means tree node expanded first time , so we will
* kept collection count and label in data itself .
* /
if ( ! ( 'collection_count' in pData ) ) {
pData . collection _count = 0 ;
}
pData . collection _count ++ ;
2016-08-29 09:36:48 -05:00
t . setLabel (
pItem , {
label : (
2017-05-10 02:55:49 -05:00
_ . escape ( pData . _label ) + ' <span>(' + pData . collection _count + ')</span>'
2016-08-29 09:36:48 -05:00
)
}
) ;
2016-08-09 06:12:05 -05:00
}
2017-11-21 10:28:01 -06:00
pgBrowser . Node . callbacks . change _server _background ( item , data ) ;
2016-08-09 06:12:05 -05:00
} ,
2015-06-30 00:51:55 -05:00
// Callback called - when a node is selected in browser tree.
2015-10-30 02:37:09 -05:00
selected : function ( item , data , browser ) {
2015-10-20 02:03:18 -05:00
// Show the information about the selected node in the below panels,
// which are visible at this time:
2015-06-30 00:51:55 -05:00
// + Properties
2015-10-20 02:03:18 -05:00
// + Query (if applicable, otherwise empty)
2015-06-30 00:51:55 -05:00
// + Dependents
// + Dependencies
// + Statistics
2015-10-30 02:37:09 -05:00
var b = browser || pgBrowser ,
2015-10-28 12:06:09 -05:00
t = b . tree ,
2015-10-30 02:37:09 -05:00
d = data || t . itemData ( item ) ;
2015-06-30 00:51:55 -05:00
// Update the menu items
2015-10-28 12:06:09 -05:00
pgAdmin . Browser . enable _disable _menus . apply ( b , [ item ] ) ;
if ( d && b ) {
if ( 'properties' in b . panels &&
b . panels [ 'properties' ] &&
b . panels [ 'properties' ] . panel &&
b . panels [ 'properties' ] . panel . isVisible ( ) ) {
2015-06-30 00:51:55 -05:00
// Show object properties (only when the 'properties' tab
// is active).
2015-10-28 12:06:09 -05:00
this . showProperties ( item , d , b . panels [ 'properties' ] . panel ) ;
2015-10-20 02:03:18 -05:00
}
2015-10-28 12:06:09 -05:00
if ( 'sql' in b . panels &&
b . panels [ 'sql' ] &&
b . panels [ 'sql' ] . panel &&
b . panels [ 'sql' ] . panel . isVisible ( ) ) {
2015-10-20 02:03:18 -05:00
// TODO:: Show reverse engineered query for this object (when 'sql'
// tab is active.)
}
2015-10-28 12:06:09 -05:00
if ( 'statistics' in b . panels &&
b . panels [ 'statistics' ] &&
b . panels [ 'statistics' ] . panel &&
b . panels [ 'statistics' ] . panel . isVisible ( ) ) {
2015-10-20 02:03:18 -05:00
// TODO:: Show statistics for this object (when the 'statistics'
// tab is active.)
}
2015-10-28 12:06:09 -05:00
if ( 'dependencies' in b . panels &&
b . panels [ 'dependencies' ] &&
b . panels [ 'dependencies' ] . panel &&
b . panels [ 'dependencies' ] . panel . isVisible ( ) ) {
2015-10-20 02:03:18 -05:00
// TODO:: Show dependencies for this object (when the
2015-06-30 00:51:55 -05:00
// 'dependencies' tab is active.)
2015-10-20 02:03:18 -05:00
}
2015-10-28 12:06:09 -05:00
if ( 'dependents' in b . panels &&
b . panels [ 'dependents' ] &&
b . panels [ 'dependents' ] . panel &&
b . panels [ 'dependents' ] . panel . isVisible ( ) ) {
2015-10-20 02:03:18 -05:00
// TODO:: Show dependents for this object (when the 'dependents'
// tab is active.)
2015-06-30 00:51:55 -05:00
}
}
2016-01-19 06:31:14 -06:00
return true ;
2015-10-20 02:03:18 -05:00
} ,
2016-05-21 05:06:36 -05:00
removed : function ( item ) {
2016-08-09 06:12:05 -05:00
var self = this ,
t = pgBrowser . tree ,
pItem = t . parent ( item ) ,
pData = pItem && t . itemData ( pItem ) ,
pNode = pData && pgBrowser . Nodes [ pData . _type ] ;
// Check node is a collection or not.
2016-08-29 09:36:48 -05:00
if (
pNode && pNode . is _collection && 'collection_count' in pData
) {
2016-08-09 06:12:05 -05:00
pData . collection _count -- ;
2016-08-29 09:36:48 -05:00
t . setLabel (
pItem , {
label : (
2017-05-10 02:55:49 -05:00
_ . escape ( pData . _label ) + ' <span>(' + pData . collection _count + ')</span>'
2016-08-29 09:36:48 -05:00
)
}
) ;
2016-08-09 06:12:05 -05:00
}
2016-05-21 05:06:36 -05:00
setTimeout ( function ( ) { self . clear _cache . apply ( self , item ) ; } , 0 ) ;
} ,
2016-08-09 06:12:05 -05:00
unloaded : function ( item ) {
var self = this ,
t = pgBrowser . tree ,
data = item && t . itemData ( item ) ;
// In case of unload remove the collection counter
if ( self . is _collection && 'collection_count' in data )
{
delete data . collection _count ;
2017-05-10 02:55:49 -05:00
t . setLabel ( item , { label : _ . escape ( data . _label ) } ) ;
2016-08-09 06:12:05 -05:00
}
} ,
2016-08-29 09:36:48 -05:00
refresh : function ( cmd , i ) {
2015-12-04 04:19:08 -06:00
var self = this ,
t = pgBrowser . tree ,
2016-08-29 09:36:48 -05:00
item = i || t . selected ( ) ,
d = t . itemData ( item ) ;
2015-12-04 04:19:08 -06:00
2016-08-29 09:36:48 -05:00
pgBrowser . Events . trigger ( 'pgadmin:browser:tree:refresh' , item ) ;
2015-06-30 00:51:55 -05:00
}
} ,
/ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* A hook ( not a callback ) to show object properties in given HTML
* element .
*
* This has been used for the showing , editing properties of the node .
* This has also been used for creating a node .
* * /
showProperties : function ( item , data , panel , action ) {
var that = this ,
tree = pgAdmin . Browser . tree ,
j = panel . $container . find ( '.obj_properties' ) . first ( ) ,
view = j . data ( 'obj-view' ) ,
2015-10-28 12:06:09 -05:00
content = $ ( '<div tabindex="1"></div>' )
2017-06-12 10:43:29 -05:00
. addClass ( 'pg-prop-content col-xs-12' ) ;
// Handle key press events for Cancel, save and help button
var handleKeyDown = function ( event , context ) {
// If called on panel other than node_props, return
if ( panel && panel [ '_type' ] !== 'node_props' ) return ;
switch ( event . which ) {
case keyCode . ESCAPE :
closePanel ( ) ;
break ;
case keyCode . ENTER :
// Return if event is fired from child element
if ( event . target !== context ) return ;
if ( view && view . model && view . model . sessChanged ( ) ) {
onSave . call ( this , view ) ;
}
break ;
case keyCode . F1 :
onDialogHelp ( ) ;
break ;
default :
break ;
}
} . bind ( panel ) ;
setTimeout ( function ( ) {
// Register key press events with panel element
panel . $container . find ( '.backform-tab' ) . on ( "keydown" , function ( event ) {
handleKeyDown ( event , this ) ;
} ) ;
} , 200 ) ; // wait for panel tab to render
2016-01-04 02:04:45 -06:00
// Template function to create the status bar
2017-06-12 10:43:29 -05:00
var createStatusBar = function ( location ) {
2016-01-04 02:04:45 -06:00
var statusBar = $ ( '<div></div>' ) . addClass (
'pg-prop-status-bar'
) . appendTo ( j ) ;
2016-01-21 03:10:00 -06:00
statusBar . css ( "visibility" , "hidden" ) ;
2016-01-04 02:04:45 -06:00
if ( location == "header" ) {
statusBar . appendTo ( that . header ) ;
} else {
statusBar . prependTo ( that . footer ) ;
}
that . statusBar = statusBar ;
return statusBar ;
2016-04-14 02:20:15 -05:00
} . bind ( panel ) ,
2015-06-30 00:51:55 -05:00
// Template function to create the button-group
2016-01-04 02:04:45 -06:00
createButtons = function ( buttons , location , extraClasses ) {
2016-04-14 02:20:15 -05:00
var panel = this ;
2015-06-30 00:51:55 -05:00
// arguments must be non-zero length array of type
// object, which contains following attributes:
// label, type, extraClasses, register
if ( buttons && _ . isArray ( buttons ) && buttons . length > 0 ) {
// All buttons will be created within a single
// div area.
var btnGroup =
$ ( '<div></div>' ) . addClass (
2015-07-14 02:45:59 -05:00
'pg-prop-btn-group'
2016-01-04 02:04:45 -06:00
) ,
2015-07-14 02:45:59 -05:00
// Template used for creating a button
tmpl = _ . template ( [
2015-06-30 00:51:55 -05:00
'<button type="<%= type %>" ' ,
Data management within the properties dialog in Create/Edit mode is not
done using the Backbone event management.
Emitting 'pgadmin-session:*' for different operations, when we
create/modify the data within the properties dialog.
We will keep track of each child node using the handler object within
the Model, and Collection objects, also - provides them the name of the
attribute, it represents. It will be used to identify the invalid nested
objects within the existing object.
Also, provide the array of modified variables, which were modified in
the validation function to avoid checking each, and every thing in the
validation function. We will need to validate that particular and the
dependent attributes only.
Also - avoid multiple validation operations from the parent object to
improve performance. And, depends on the event based operations for
validation, instead of integrate the data operation and view operation
within one operation. We do maintain the invalid objects, and validate
them only from the collection objects, which also helps improve the
performance during validation.
2016-01-15 04:29:20 -06:00
'class="btn <%=extraClasses.join(\' \')%>"' ,
2016-04-08 05:58:47 -05:00
'<% if (disabled) { %> disabled="disabled"<% } %> title="<%-tooltip%>">' ,
'<span class="<%= icon %>"></span><% if (label != "") { %> <%-label%><% } %></button>'
2015-06-30 00:51:55 -05:00
] . join ( ' ' ) ) ;
2016-01-04 02:04:45 -06:00
if ( location == "header" ) {
btnGroup . appendTo ( that . header ) ;
} else {
btnGroup . appendTo ( that . footer ) ;
}
2015-07-14 02:45:59 -05:00
if ( extraClasses ) {
btnGroup . addClass ( extraClasses ) ;
}
2015-06-30 00:51:55 -05:00
_ . each ( buttons , function ( btn ) {
// Create the actual button, and append to
// the group div
// icon may not present for this button
if ( ! btn . icon ) {
btn . icon = "" ;
}
var b = $ ( tmpl ( btn ) ) ;
btnGroup . append ( b ) ;
// Register is a callback to set callback
2015-12-17 04:43:36 -06:00
// for certain operation for this button.
2015-06-30 00:51:55 -05:00
btn . register ( b ) ;
} ) ;
return btnGroup ;
}
return null ;
2016-04-14 02:20:15 -05:00
} . bind ( panel ) ,
2015-06-30 00:51:55 -05:00
// Callback to show object properties
properties = function ( ) {
2015-07-14 02:45:59 -05:00
2016-06-29 06:16:02 -05:00
// Avoid unnecessary reloads
var panel = this ,
i = tree . selected ( ) ,
d = i && tree . itemData ( i ) ,
n _type = d . _type ,
n _value = - 1 ,
n = i && d && pgBrowser . Nodes [ d . _type ] ,
treeHierarchy = n . getTreeNodeHierarchy ( i ) ;
2016-07-19 05:00:39 -05:00
if ( _ . isEqual ( $ ( panel ) . data ( 'node-prop' ) , treeHierarchy ) ) {
2016-06-29 06:16:02 -05:00
return ;
}
// Cache the current IDs for next time
2016-07-19 05:00:39 -05:00
$ ( panel ) . data ( 'node-prop' , treeHierarchy ) ;
2016-04-14 02:20:15 -05:00
2015-07-14 02:45:59 -05:00
if ( ! content . hasClass ( 'has-pg-prop-btn-group' ) )
content . addClass ( 'has-pg-prop-btn-group' ) ;
2015-06-30 00:51:55 -05:00
// We need to release any existing view, before
// creating new view.
if ( view ) {
// Release the view
2016-04-15 08:58:08 -05:00
view . remove ( { data : true , internal : true , silent : true } ) ;
2017-07-27 06:55:07 -05:00
// Deallocate the view
// delete view;
2015-06-30 00:51:55 -05:00
view = null ;
// Reset the data object
j . data ( 'obj-view' , null ) ;
}
// Make sure the HTML element is empty.
j . empty ( ) ;
2016-01-04 02:04:45 -06:00
that . header = $ ( '<div></div>' ) . addClass (
'pg-prop-header'
) . appendTo ( j ) ;
that . footer = $ ( '<div></div>' ) . addClass (
'pg-prop-footer'
) . appendTo ( j ) ;
2015-06-30 00:51:55 -05:00
// Create a view to show the properties in fieldsets
2016-09-26 09:10:38 -05:00
view = that . getView ( item , 'properties' , content , data , 'fieldset' , undefined , j ) ;
2015-06-30 00:51:55 -05:00
if ( view ) {
// Save it for release it later
j . data ( 'obj-view' , view ) ;
2016-01-04 02:04:45 -06:00
2015-06-30 00:51:55 -05:00
// Create proper buttons
2016-01-04 02:04:45 -06:00
2015-06-30 00:51:55 -05:00
var buttons = [ ] ;
2016-08-22 06:30:16 -05:00
2015-06-30 00:51:55 -05:00
buttons . push ( {
2016-04-08 05:58:47 -05:00
label : '' , type : 'edit' ,
2017-06-07 05:23:02 -05:00
tooltip : gettext ( 'Edit' ) ,
2016-04-08 05:58:47 -05:00
extraClasses : [ 'btn-default' ] ,
2015-06-30 00:51:55 -05:00
icon : 'fa fa-lg fa-pencil-square-o' ,
2016-08-22 06:30:16 -05:00
disabled : ! that . canEdit ,
2015-06-30 00:51:55 -05:00
register : function ( btn ) {
btn . click ( function ( ) {
onEdit ( ) ;
} ) ;
}
} ) ;
2016-08-22 06:30:16 -05:00
2016-04-12 07:35:47 -05:00
buttons . push ( {
label : '' , type : 'help' ,
2017-06-07 05:23:02 -05:00
tooltip : gettext ( 'SQL help for this object type.' ) ,
2016-05-16 10:25:51 -05:00
extraClasses : [ 'btn-default' , 'pull-right' ] ,
2016-04-15 07:29:57 -05:00
icon : 'fa fa-lg fa-info' ,
2016-04-12 07:35:47 -05:00
disabled : ( that . sqlAlterHelp == '' && that . sqlCreateHelp == '' ) ? true : false ,
register : function ( btn ) {
btn . click ( function ( ) {
onSqlHelp ( ) ;
} ) ;
}
} ) ;
2017-06-07 10:31:47 -05:00
createButtons ( buttons , 'header' , 'pg-prop-btn-group-above bg-gray-2 border-gray-3' ) ;
2015-06-30 00:51:55 -05:00
}
j . append ( content ) ;
2016-04-14 02:20:15 -05:00
} . bind ( panel ) ,
2016-04-12 07:35:47 -05:00
onSqlHelp = function ( ) {
2016-04-14 02:20:15 -05:00
var panel = this ;
2016-04-12 07:35:47 -05:00
// See if we can find an existing panel, if not, create one
2017-07-18 09:13:16 -05:00
var pnlSqlHelp = pgBrowser . docker . findPanels ( 'pnl_sql_help' ) [ 0 ] ;
2016-04-12 07:35:47 -05:00
if ( pnlSqlHelp == null ) {
2017-07-18 09:13:16 -05:00
var pnlProperties = pgBrowser . docker . findPanels ( 'properties' ) [ 0 ] ;
2016-04-12 07:35:47 -05:00
pgBrowser . docker . addPanel ( 'pnl_sql_help' , wcDocker . DOCK . STACKED , pnlProperties ) ;
pnlSqlHelp = pgBrowser . docker . findPanels ( 'pnl_sql_help' ) [ 0 ] ;
}
// Construct the URL
2017-07-18 09:13:16 -05:00
var server = that . getTreeNodeHierarchy ( item ) . server ;
2016-04-12 07:35:47 -05:00
2017-07-18 09:13:16 -05:00
var url = pgBrowser . utils . pg _help _path ;
2016-04-12 07:35:47 -05:00
if ( server . server _type == 'ppas' ) {
2017-07-18 09:13:16 -05:00
url = pgBrowser . utils . edbas _help _path ;
2016-04-12 07:35:47 -05:00
}
2017-07-18 09:13:16 -05:00
var major = Math . floor ( server . version / 10000 ) ,
minor = Math . floor ( server . version / 100 ) - ( major * 100 ) ;
2016-04-12 07:35:47 -05:00
2017-07-18 09:13:16 -05:00
url = url . replace ( '$VERSION$' , major + '.' + minor ) ;
2016-04-15 08:26:32 -05:00
if ( ! S ( url ) . endsWith ( '/' ) ) {
2016-04-12 07:35:47 -05:00
url = url + '/'
}
if ( that . sqlCreateHelp == '' && that . sqlAlterHelp != '' ) {
url = url + that . sqlAlterHelp
} else if ( that . sqlCreateHelp != '' && that . sqlAlterHelp == '' ) {
url = url + that . sqlCreateHelp
} else {
if ( view . model . isNew ( ) ) {
url = url + that . sqlCreateHelp
} else {
url = url + that . sqlAlterHelp
}
}
// Update the panel
2017-07-18 09:13:16 -05:00
var iframe = $ ( pnlSqlHelp ) . data ( 'embeddedFrame' ) ;
2016-04-12 07:35:47 -05:00
pnlSqlHelp . title ( 'SQL: ' + that . label ) ;
2016-04-15 07:29:57 -05:00
2016-04-12 07:35:47 -05:00
pnlSqlHelp . focus ( ) ;
iframe . openURL ( url ) ;
2016-04-14 02:20:15 -05:00
} . bind ( panel ) ,
2016-05-16 10:25:51 -05:00
onDialogHelp = function ( ) {
var panel = this ;
// See if we can find an existing panel, if not, create one
2017-07-18 09:13:16 -05:00
var pnlDialogHelp = pgBrowser . docker . findPanels ( 'pnl_online_help' ) [ 0 ] ;
2016-05-16 10:25:51 -05:00
if ( pnlDialogHelp == null ) {
2017-07-18 09:13:16 -05:00
var pnlProperties = pgBrowser . docker . findPanels ( 'properties' ) [ 0 ] ;
2016-05-16 10:25:51 -05:00
pgBrowser . docker . addPanel ( 'pnl_online_help' , wcDocker . DOCK . STACKED , pnlProperties ) ;
pnlDialogHelp = pgBrowser . docker . findPanels ( 'pnl_online_help' ) [ 0 ] ;
}
// Update the panel
2017-07-18 09:13:16 -05:00
var iframe = $ ( pnlDialogHelp ) . data ( 'embeddedFrame' ) ;
2016-05-16 10:25:51 -05:00
pnlDialogHelp . focus ( ) ;
iframe . openURL ( that . dialogHelp ) ;
} . bind ( panel ) ,
2017-06-12 10:43:29 -05:00
onSave = function ( view ) {
var m = view . model ,
d = m . toJSON ( true ) ,
// Generate a timer for the request
timer = setTimeout ( function ( ) {
$ ( '.obj_properties' ) . addClass ( 'show_progress' ) ;
} , 1000 ) ;
if ( d && ! _ . isEmpty ( d ) ) {
m . save ( { } , {
attrs : d ,
validate : false ,
cache : false ,
success : function ( ) {
onSaveFunc . call ( ) ;
// Hide progress cursor
$ ( '.obj_properties' ) . removeClass ( 'show_progress' ) ;
clearTimeout ( timer ) ;
// Removing the node-prop property of panel
// so that we show updated data on panel
var pnlProperties = pgBrowser . docker . findPanels ( 'properties' ) [ 0 ] ,
pnlSql = pgBrowser . docker . findPanels ( 'sql' ) [ 0 ] ,
pnlStats = pgBrowser . docker . findPanels ( 'statistics' ) [ 0 ] ,
pnlDependencies = pgBrowser . docker . findPanels ( 'dependencies' ) [ 0 ] ,
pnlDependents = pgBrowser . docker . findPanels ( 'dependents' ) [ 0 ] ;
if ( pnlProperties )
$ ( pnlProperties ) . removeData ( 'node-prop' ) ;
if ( pnlSql )
$ ( pnlSql ) . removeData ( 'node-prop' ) ;
if ( pnlStats )
$ ( pnlStats ) . removeData ( 'node-prop' ) ;
if ( pnlDependencies )
$ ( pnlDependencies ) . removeData ( 'node-prop' ) ;
if ( pnlDependents )
$ ( pnlDependents ) . removeData ( 'node-prop' ) ;
} ,
error : function ( m , jqxhr ) {
Alertify . pgNotifier (
"error" , jqxhr ,
2017-11-20 07:31:03 -06:00
gettext ( "Error saving properties" )
) ;
2017-06-12 10:43:29 -05:00
// Hide progress cursor
$ ( '.obj_properties' ) . removeClass ( 'show_progress' ) ;
clearTimeout ( timer ) ;
}
} ) ;
}
} . bind ( panel ) ,
2015-06-30 00:51:55 -05:00
editFunc = function ( ) {
2016-04-14 02:20:15 -05:00
var panel = this ;
2015-06-30 00:51:55 -05:00
if ( action && action == 'properties' ) {
action = 'edit' ;
}
panel . $container . attr ( 'action-mode' , action ) ;
// We need to release any existing view, before
// creating the new view.
if ( view ) {
// Release the view
2016-04-15 08:58:08 -05:00
view . remove ( { data : true , internal : true , silent : true } ) ;
2017-07-27 06:55:07 -05:00
// Deallocate the view
2015-06-30 00:51:55 -05:00
view = null ;
// Reset the data object
j . data ( 'obj-view' , null ) ;
}
// Make sure the HTML element is empty.
j . empty ( ) ;
2016-01-04 02:04:45 -06:00
that . header = $ ( '<div></div>' ) . addClass (
'pg-prop-header'
) . appendTo ( j )
that . footer = $ ( '<div></div>' ) . addClass (
'pg-prop-footer'
) . appendTo ( j ) ;
2016-01-12 10:48:54 -06:00
var updateButtons = function ( hasError , modified ) {
var btnGroup = this . find ( '.pg-prop-btn-group' ) ,
2016-05-06 09:29:32 -05:00
btnSave = btnGroup . find ( 'button.btn-primary' ) ,
btnReset = btnGroup . find ( 'button.btn-warning' ) ;
2015-10-28 12:06:09 -05:00
2016-01-12 10:48:54 -06:00
if ( hasError || ! modified ) {
2015-10-28 12:06:09 -05:00
btnSave . prop ( 'disabled' , true ) ;
btnSave . attr ( 'disabled' , 'disabled' ) ;
2016-01-12 10:48:54 -06:00
} else {
btnSave . prop ( 'disabled' , false ) ;
btnSave . removeAttr ( 'disabled' ) ;
}
if ( ! modified ) {
2015-10-28 12:06:09 -05:00
btnReset . prop ( 'disabled' , true ) ;
btnReset . attr ( 'disabled' , 'disabled' ) ;
2016-01-12 10:48:54 -06:00
} else {
btnReset . prop ( 'disabled' , false ) ;
btnReset . removeAttr ( 'disabled' ) ;
2015-10-28 12:06:09 -05:00
}
} ;
// Create a view to edit/create the properties in fieldsets
2016-08-29 01:22:50 -05:00
view = that . getView ( item , action , content , data , 'dialog' , updateButtons , j , onCancelFunc ) ;
2015-06-30 00:51:55 -05:00
if ( view ) {
// Save it to release it later
j . data ( 'obj-view' , view ) ;
2015-07-14 02:45:59 -05:00
2016-01-17 10:51:02 -06:00
panel . icon (
_ . isFunction ( that [ 'node_image' ] ) ?
( that [ 'node_image' ] ) . apply ( that , [ data , view . model ] ) :
( that [ 'node_image' ] || ( 'icon-' + that . type ) )
) ;
2015-06-30 00:51:55 -05:00
// Create proper buttons
createButtons ( [ {
2016-04-12 07:35:47 -05:00
label : '' , type : 'help' ,
2017-06-07 05:23:02 -05:00
tooltip : gettext ( 'SQL help for this object type.' ) ,
2016-05-16 10:25:51 -05:00
extraClasses : [ 'btn-default' , 'pull-left' ] ,
2016-04-15 07:29:57 -05:00
icon : 'fa fa-lg fa-info' ,
2016-05-16 10:25:51 -05:00
disabled : ( that . sqlAlterHelp == '' && that . sqlCreateHelp == '' ) ? true : false ,
2016-04-12 07:35:47 -05:00
register : function ( btn ) {
btn . click ( function ( ) {
onSqlHelp ( ) ;
} ) ;
}
2016-05-16 10:25:51 -05:00
} , {
label : '' , type : 'help' ,
2017-06-07 05:23:02 -05:00
tooltip : gettext ( 'Help for this dialog.' ) ,
2016-05-16 10:25:51 -05:00
extraClasses : [ 'btn-default' , 'pull-left' ] ,
icon : 'fa fa-lg fa-question' ,
disabled : ( that . dialogHelp == '' ) ? true : false ,
register : function ( btn ) {
btn . click ( function ( ) {
onDialogHelp ( ) ;
} ) ;
}
2016-04-12 07:35:47 -05:00
} , {
2017-06-07 05:23:02 -05:00
label : gettext ( 'Save' ) , type : 'save' ,
tooltip : gettext ( 'Save this object.' ) ,
2015-06-30 00:51:55 -05:00
extraClasses : [ 'btn-primary' ] ,
icon : 'fa fa-lg fa-save' ,
Data management within the properties dialog in Create/Edit mode is not
done using the Backbone event management.
Emitting 'pgadmin-session:*' for different operations, when we
create/modify the data within the properties dialog.
We will keep track of each child node using the handler object within
the Model, and Collection objects, also - provides them the name of the
attribute, it represents. It will be used to identify the invalid nested
objects within the existing object.
Also, provide the array of modified variables, which were modified in
the validation function to avoid checking each, and every thing in the
validation function. We will need to validate that particular and the
dependent attributes only.
Also - avoid multiple validation operations from the parent object to
improve performance. And, depends on the event based operations for
validation, instead of integrate the data operation and view operation
within one operation. We do maintain the invalid objects, and validate
them only from the collection objects, which also helps improve the
performance during validation.
2016-01-15 04:29:20 -06:00
disabled : true ,
2015-06-30 00:51:55 -05:00
register : function ( btn ) {
// Save the changes
btn . click ( function ( ) {
2017-06-12 10:43:29 -05:00
onSave . call ( this , view ) ;
2015-06-30 00:51:55 -05:00
} ) ;
}
} , {
2017-06-07 05:23:02 -05:00
label : gettext ( 'Cancel' ) , type : 'cancel' ,
tooltip : gettext ( 'Cancel changes to this object.' ) ,
2015-06-30 00:51:55 -05:00
extraClasses : [ 'btn-danger' ] ,
icon : 'fa fa-lg fa-close' ,
Data management within the properties dialog in Create/Edit mode is not
done using the Backbone event management.
Emitting 'pgadmin-session:*' for different operations, when we
create/modify the data within the properties dialog.
We will keep track of each child node using the handler object within
the Model, and Collection objects, also - provides them the name of the
attribute, it represents. It will be used to identify the invalid nested
objects within the existing object.
Also, provide the array of modified variables, which were modified in
the validation function to avoid checking each, and every thing in the
validation function. We will need to validate that particular and the
dependent attributes only.
Also - avoid multiple validation operations from the parent object to
improve performance. And, depends on the event based operations for
validation, instead of integrate the data operation and view operation
within one operation. We do maintain the invalid objects, and validate
them only from the collection objects, which also helps improve the
performance during validation.
2016-01-15 04:29:20 -06:00
disabled : false ,
2015-06-30 00:51:55 -05:00
register : function ( btn ) {
btn . click ( function ( ) {
// Removing the action-mode
panel . $container . removeAttr ( 'action-mode' ) ;
onCancelFunc . call ( arguments ) ;
} ) ;
}
} , {
2017-06-07 05:23:02 -05:00
label : gettext ( 'Reset' ) , type : 'reset' ,
tooltip : gettext ( 'Reset the fields on this dialog.' ) ,
2015-06-30 00:51:55 -05:00
extraClasses : [ 'btn-warning' ] ,
icon : 'fa fa-lg fa-recycle' ,
Data management within the properties dialog in Create/Edit mode is not
done using the Backbone event management.
Emitting 'pgadmin-session:*' for different operations, when we
create/modify the data within the properties dialog.
We will keep track of each child node using the handler object within
the Model, and Collection objects, also - provides them the name of the
attribute, it represents. It will be used to identify the invalid nested
objects within the existing object.
Also, provide the array of modified variables, which were modified in
the validation function to avoid checking each, and every thing in the
validation function. We will need to validate that particular and the
dependent attributes only.
Also - avoid multiple validation operations from the parent object to
improve performance. And, depends on the event based operations for
validation, instead of integrate the data operation and view operation
within one operation. We do maintain the invalid objects, and validate
them only from the collection objects, which also helps improve the
performance during validation.
2016-01-15 04:29:20 -06:00
disabled : true ,
2015-06-30 00:51:55 -05:00
register : function ( btn ) {
btn . click ( function ( ) {
setTimeout ( function ( ) { editFunc . call ( ) ; } , 0 ) ;
} ) ;
}
2017-06-07 10:31:47 -05:00
} ] , 'footer' , 'pg-prop-btn-group-below bg-gray-2 border-gray-3' ) ;
2015-06-30 00:51:55 -05:00
} ;
2015-07-14 02:45:59 -05:00
2016-01-04 02:04:45 -06:00
// Create status bar.
createStatusBar ( 'footer' ) ;
2015-07-14 02:45:59 -05:00
// Add some space, so that - button group does not override the
// space
content . addClass ( 'pg-prop-has-btn-group-below' ) ;
// Show contents before buttons
j . prepend ( content ) ;
2016-04-14 02:20:15 -05:00
} . bind ( panel ) ,
2015-06-30 00:51:55 -05:00
closePanel = function ( ) {
// Closing this panel
2016-04-15 08:02:21 -05:00
this . close ( ) ;
} . bind ( panel ) ,
2016-04-29 05:11:24 -05:00
updateTreeItem = function ( that ) {
2016-08-29 09:36:48 -05:00
var _old = data ,
_new = _ . clone ( view . model . tnode ) ,
info = _ . clone ( view . model . node _info ) ;
2016-04-14 02:20:15 -05:00
2016-04-29 05:11:24 -05:00
// Clear the cache for this node now.
setTimeout ( function ( ) { that . clear _cache . apply ( that , item ) ; } , 0 ) ;
pgBrowser . Events . trigger (
2016-08-29 09:36:48 -05:00
'pgadmin:browser:tree:update' ,
_old , _new , info , {
2017-07-07 01:25:55 -05:00
success : function ( _item , _newNodeData , _oldNodeData ) {
pgBrowser . Events . trigger (
'pgadmin:browser:node:updated' , _item , _newNodeData ,
_oldNodeData
) ;
2016-08-29 09:36:48 -05:00
pgBrowser . Events . trigger (
2017-07-07 01:25:55 -05:00
'pgadmin:browser:node:' + _newNodeData . _type + ':updated' ,
_item , _newNodeData , _oldNodeData
2016-08-29 09:36:48 -05:00
) ;
}
}
2016-04-29 05:11:24 -05:00
) ;
2016-08-29 09:36:48 -05:00
closePanel ( ) ;
2015-06-30 00:51:55 -05:00
} ,
2016-04-29 05:11:24 -05:00
saveNewNode = function ( that ) {
2016-08-29 09:36:48 -05:00
var panel = this ,
j = panel . $container . find ( '.obj_properties' ) . first ( ) ,
view = j . data ( 'obj-view' ) ;
2016-04-29 05:11:24 -05:00
// Clear the cache for this node now.
setTimeout ( function ( ) { that . clear _cache . apply ( that , item ) ; } , 0 ) ;
2016-08-29 09:36:48 -05:00
try {
pgBrowser . Events . trigger (
'pgadmin:browser:tree:add' , _ . clone ( view . model . tnode ) ,
_ . clone ( view . model . node _info )
) ;
} catch ( e ) {
console . log ( e ) ;
2015-06-30 00:51:55 -05:00
}
2016-08-29 09:36:48 -05:00
closePanel ( ) ;
2016-04-29 05:11:24 -05:00
} . bind ( panel , that ) ,
2015-06-30 00:51:55 -05:00
editInNewPanel = function ( ) {
// Open edit in separate panel
setTimeout ( function ( ) {
that . callbacks . show _obj _properties . apply ( that , [ {
'action' : 'edit' ,
'item' : item
} ] ) ;
} , 0 ) ;
} ,
2016-04-15 08:02:21 -05:00
onCancelFunc = closePanel ,
2016-04-29 05:11:24 -05:00
onSaveFunc = updateTreeItem . bind ( panel , that ) ,
2016-04-14 02:20:15 -05:00
onEdit = editFunc . bind ( panel ) ;
2015-06-30 00:51:55 -05:00
if ( action ) {
if ( action == 'create' ) {
2016-04-15 08:02:21 -05:00
onCancelFunc = closePanel ;
onSaveFunc = saveNewNode ;
2015-06-30 00:51:55 -05:00
}
if ( action != 'properties' ) {
// We need to keep track edit/create mode for this panel.
editFunc ( ) ;
} else {
properties ( ) ;
}
} else {
/* Show properties */
properties ( ) ;
2016-04-14 02:20:15 -05:00
onEdit = editInNewPanel . bind ( panel ) ;
2015-06-30 00:51:55 -05:00
}
2016-04-15 05:44:01 -05:00
if ( panel . closeable ( ) ) {
var onCloseFunc = function ( ) {
var j = this . $container . find ( '.obj_properties' ) . first ( ) ,
view = j && j . data ( 'obj-view' ) ;
if ( view ) {
2016-04-15 08:58:08 -05:00
view . remove ( { data : true , internal : true , silent : true } ) ;
2016-04-15 05:44:01 -05:00
}
} . bind ( panel ) ;
panel . on ( wcDocker . EVENT . CLOSED , onCloseFunc ) ;
}
2015-06-30 00:51:55 -05:00
} ,
2016-06-02 19:27:48 -05:00
_find _parent _node : function ( t , i , d ) {
if ( this . parent _type ) {
d = d || t . itemData ( i ) ;
if ( _ . isString ( this . parent _type ) ) {
if ( this . parent _type == d . _type ) {
return i ;
}
while ( t . hasParent ( i ) ) {
i = t . parent ( i ) ;
d = t . itemData ( i ) ;
if ( this . parent _type == d . _type )
return i ;
}
} else {
if ( _ . indexOf ( this . parent _type , d . _type ) >= 0 ) {
return i ;
}
while ( t . hasParent ( i ) ) {
i = t . parent ( i ) ;
d = t . itemData ( i ) ;
if ( _ . indexOf ( this . parent _type , d . _type ) >= 0 )
return i ;
}
}
}
return null ;
} ,
2015-06-30 00:51:55 -05:00
/ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Generate the URL for different operations
*
* arguments :
* type : Create / drop / edit / properties / sql / depends / statistics
* d : Provide the ItemData for the current item node
* with _id : Required id information at the end ?
*
* Supports url generation for create , drop , edit , properties , sql ,
* depends , statistics
* /
2015-12-26 02:52:19 -06:00
generate _url : function ( item , type , d , with _id , info ) {
2017-08-17 11:13:07 -05:00
var opURL = {
2015-06-30 00:51:55 -05:00
'create' : 'obj' , 'drop' : 'obj' , 'edit' : 'obj' ,
2015-11-23 01:55:37 -06:00
'properties' : 'obj' , 'statistics' : 'stats'
2017-08-17 11:13:07 -05:00
} , self = this ,
2016-01-09 08:24:50 -06:00
priority = - Infinity ;
2017-08-17 11:13:07 -05:00
var treeInfo = ( _ . isUndefined ( item ) || _ . isNull ( item ) ) ?
2016-01-09 08:24:50 -06:00
info || { } : this . getTreeNodeHierarchy ( item ) ;
2017-08-17 11:13:07 -05:00
var actionType = type in opURL ? opURL [ type ] : type ;
var itemID = with _id && d . _type == self . type ? encodeURIComponent ( d . _id ) : '' ;
2016-01-09 08:24:50 -06:00
if ( self . parent _type ) {
if ( _ . isString ( self . parent _type ) ) {
2017-08-17 11:13:07 -05:00
var p = treeInfo [ self . parent _type ] ;
2016-01-09 08:24:50 -06:00
if ( p ) {
priority = p . priority ;
}
} else {
_ . each ( self . parent _type , function ( o ) {
2017-08-17 11:13:07 -05:00
var p = treeInfo [ o ] ;
2016-01-09 08:24:50 -06:00
if ( p ) {
if ( priority < p . priority ) {
priority = p . priority ;
}
}
} ) ;
}
}
2017-08-17 11:13:07 -05:00
var nodePickFunction = function ( treeInfoValue ) {
return ( treeInfoValue . priority <= priority ) ;
2015-11-19 11:45:48 -06:00
} ;
2017-08-17 11:13:07 -05:00
return generateUrl . generate _url ( pgBrowser . URL , treeInfo , actionType , self . type , nodePickFunction , itemID ) ;
2015-06-30 00:51:55 -05:00
} ,
Data management within the properties dialog in Create/Edit mode is not
done using the Backbone event management.
Emitting 'pgadmin-session:*' for different operations, when we
create/modify the data within the properties dialog.
We will keep track of each child node using the handler object within
the Model, and Collection objects, also - provides them the name of the
attribute, it represents. It will be used to identify the invalid nested
objects within the existing object.
Also, provide the array of modified variables, which were modified in
the validation function to avoid checking each, and every thing in the
validation function. We will need to validate that particular and the
dependent attributes only.
Also - avoid multiple validation operations from the parent object to
improve performance. And, depends on the event based operations for
validation, instead of integrate the data operation and view operation
within one operation. We do maintain the invalid objects, and validate
them only from the collection objects, which also helps improve the
performance during validation.
2016-01-15 04:29:20 -06:00
// Base class for Node Data Collection
2016-01-18 22:45:04 -06:00
Collection : pgBrowser . DataCollection ,
Data management within the properties dialog in Create/Edit mode is not
done using the Backbone event management.
Emitting 'pgadmin-session:*' for different operations, when we
create/modify the data within the properties dialog.
We will keep track of each child node using the handler object within
the Model, and Collection objects, also - provides them the name of the
attribute, it represents. It will be used to identify the invalid nested
objects within the existing object.
Also, provide the array of modified variables, which were modified in
the validation function to avoid checking each, and every thing in the
validation function. We will need to validate that particular and the
dependent attributes only.
Also - avoid multiple validation operations from the parent object to
improve performance. And, depends on the event based operations for
validation, instead of integrate the data operation and view operation
within one operation. We do maintain the invalid objects, and validate
them only from the collection objects, which also helps improve the
performance during validation.
2016-01-15 04:29:20 -06:00
// Base class for Node Data Model
2016-01-18 22:45:04 -06:00
Model : pgBrowser . DataModel ,
2015-11-19 11:45:48 -06:00
getTreeNodeHierarchy : function ( i ) {
var idx = 0 ,
res = { } ,
2017-07-18 09:13:16 -05:00
t = pgBrowser . tree ,
d ;
2015-11-19 11:45:48 -06:00
do {
d = t . itemData ( i ) ;
if ( d . _type in pgBrowser . Nodes && pgBrowser . Nodes [ d . _type ] . hasId ) {
2015-12-26 02:52:19 -06:00
res [ d . _type ] = _ . extend ( { } , d , {
2015-11-19 11:45:48 -06:00
'priority' : idx
2015-12-26 02:52:19 -06:00
} ) ;
2015-11-23 01:55:37 -06:00
idx -= 1 ;
2015-11-19 11:45:48 -06:00
}
i = t . hasParent ( i ) ? t . parent ( i ) : null ;
} while ( i ) ;
return res ;
2015-12-26 02:52:19 -06:00
} ,
2016-01-05 03:06:30 -06:00
cache : function ( url , node _info , level , data ) {
var cached = this . cached = this . cached || { } ,
hash = url ,
min _priority = (
node _info && node _info [ level ] && node _info [ level ] . priority
) || 0 ;
if ( node _info ) {
_ . each (
_ . sortBy (
_ . values (
_ . pick (
node _info ,
function ( v , k , o ) {
return ( v . priority <= min _priority ) ;
} ) ) ,
function ( o ) { return o . priority ; } ) ,
function ( o ) {
hash = S ( '%s/%s' ) . sprintf ( hash , encodeURI ( o . _id ) ) . value ( ) ;
} ) ;
}
2015-12-26 02:52:19 -06:00
if ( _ . isUndefined ( data ) ) {
2016-04-29 05:11:24 -05:00
var res = cached [ hash ] ;
if ( ! _ . isUndefined ( res ) &&
( res . at - Date . now ( ) > 300000 ) ) {
res = undefined ;
}
return res ;
2015-12-26 02:52:19 -06:00
}
2016-04-29 05:11:24 -05:00
res = cached [ hash ] = { data : data , at : Date . now ( ) , level : level } ;
2015-12-26 02:52:19 -06:00
2016-01-05 03:06:30 -06:00
return res ;
2016-04-29 05:11:24 -05:00
} ,
clear _cache : function ( item ) {
/ *
* Reset the cache , when new node is created .
*
* FIXME :
* At the moment , we will clear all the cache for this node . But - we
* would like to clear the cache only this nodes parent , so that - it
* fetches the new data .
* /
this . cached = { } ;
2017-12-13 09:17:17 -06:00
// Trigger Notify event about node's cache
var self = this ;
pgBrowser . Events . trigger (
'pgadmin:browser:node:' + self . type + ':cache_cleared' ,
item , self
) ;
2016-04-29 05:11:24 -05:00
} ,
cache _level : function ( node _info , with _id ) {
if ( node _info ) {
if ( with _id && this . type in node _info ) {
return this . type ;
}
if ( _ . isArray ( this . parent _type ) ) {
for ( var parent in this . parent _type ) {
if ( parent in node _info ) {
return parent ;
}
}
return this . type ;
}
return this . parent _type ;
}
2015-11-19 11:45:48 -06:00
}
2015-06-30 00:51:55 -05:00
} ) ;
return pgAdmin . Browser . Node ;
} ) ;