diff --git a/web/package.json b/web/package.json index bb756dc2..b5c643ce 100644 --- a/web/package.json +++ b/web/package.json @@ -33,6 +33,7 @@ "karma-webpack": "~2.0.13", "node-sass": "^4.5.3", "optimize-css-assets-webpack-plugin": "^2.0.0", + "popper.js": "^1.14.4", "raw-loader": "^0.5.1", "sass-loader": "^7.1.0", "sass-resources-loader": "^1.3.3", @@ -56,7 +57,7 @@ "backgrid-select-all": "^0.3.5", "backgrid-sizeable-columns": "^0.1.1", "bignumber.js": "^6.0.0", - "bootstrap": "^3.3.7", + "bootstrap": "^4.1.3", "bootstrap-datepicker": "^1.7.0", "bootstrap-switch": "3.3.4", "bowser": "1.6.1", diff --git a/web/pgadmin/about/templates/about/index.html b/web/pgadmin/about/templates/about/index.html index 61576cc7..f2c338f2 100644 --- a/web/pgadmin/about/templates/about/index.html +++ b/web/pgadmin/about/templates/about/index.html @@ -24,7 +24,7 @@
{{ info.current_user }}
-
{{ config.APP_NAME }} {{ _('logo') }}
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/fts_configurations/static/js/fts_configuration.js b/web/pgadmin/browser/server_groups/servers/databases/schemas/fts_configurations/static/js/fts_configuration.js index 935cc84c..9f43b34e 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/schemas/fts_configurations/static/js/fts_configuration.js +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/fts_configurations/static/js/fts_configuration.js @@ -197,12 +197,12 @@ define('pgadmin.node.fts_configuration', [ '
', '
', '
', - '
', + '
', ' ', '
', - '
', - '
', - ' ', + '
', + '
', + ' ', '
', '
', '
', @@ -257,7 +257,7 @@ define('pgadmin.node.fts_configuration', [ var self = this, titleTmpl = _.template('
'), $gridBody = $('
', { - class:'pgadmin-control-group backgrid form-group col-xs-12 object subnode', + class:'pgadmin-control-group backgrid form-group col-12 object subnode', }).append( titleTmpl({label: data.label}) ); diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/static/js/schema.js b/web/pgadmin/browser/server_groups/servers/databases/schemas/static/js/schema.js index 43f9cfda..d616f0cc 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/schemas/static/js/schema.js +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/static/js/schema.js @@ -64,7 +64,7 @@ define('pgadmin.node.schema', [ '
', ' ', '
'].join('\n')), - gridBody = $('
').append( + gridBody = $('
').append( gridHeader(attributes) ); diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/exclusion_constraint/static/js/exclusion_constraint.js b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/exclusion_constraint/static/js/exclusion_constraint.js index 1befc999..b8b46a63 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/exclusion_constraint/static/js/exclusion_constraint.js +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/exclusion_constraint/static/js/exclusion_constraint.js @@ -391,12 +391,12 @@ define('pgadmin.node.exclusion_constraint', [ '
', '
', '
', - '
', + '
', ' ', '
', - '
', - '
', - ' ', + '
', + '
', + ' ', '
', '
', '
', @@ -443,7 +443,7 @@ define('pgadmin.node.exclusion_constraint', [ var self = this, titleTmpl = _.template('
'), $gridBody = - $('
').append( + $('
').append( // Append titleTmpl only if create/edit mode data.mode !== 'properties' ? titleTmpl({label: data.label}) : '' ); diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/foreign_key/static/js/foreign_key.js b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/foreign_key/static/js/foreign_key.js index e3dd9dcb..efbabc22 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/foreign_key/static/js/foreign_key.js +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/foreign_key/static/js/foreign_key.js @@ -309,7 +309,7 @@ define('pgadmin.node.foreign_key', [ '
', '
', '
', - ' ', + ' ', '
', '
', '
', @@ -374,7 +374,7 @@ define('pgadmin.node.foreign_key', [ '', '
'].join('\n')), $gridBody = - $('
').append( + $('
').append( // Append titleTmpl only if create/edit mode data.mode !== 'properties' ? titleTmpl({label: data.label}) : '' ); diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/triggers/static/js/trigger.js b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/triggers/static/js/trigger.js index 95dcc968..bf0bb8dd 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/triggers/static/js/trigger.js +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/triggers/static/js/trigger.js @@ -25,7 +25,7 @@ define('pgadmin.node.trigger', [ ' <%=helpMessage%>', '<% } %>', ].join('\n')), - className: 'pgadmin-control-group form-group col-xs-6', + className: 'pgadmin-control-group form-group col-6', }); if (!pgBrowser.Nodes['coll-trigger']) { diff --git a/web/pgadmin/browser/server_groups/servers/pgagent/schedules/static/js/pga_schedule.js b/web/pgadmin/browser/server_groups/servers/pgagent/schedules/static/js/pga_schedule.js index 1cfa38c9..a8884edc 100644 --- a/web/pgadmin/browser/server_groups/servers/pgagent/schedules/static/js/pga_schedule.js +++ b/web/pgadmin/browser/server_groups/servers/pgagent/schedules/static/js/pga_schedule.js @@ -343,7 +343,7 @@ define('pgadmin.node.pga_schedule', [ ); this.$el.prepend( - '
' + gettext('Schedules are specified using a cron-style format.
  • For each selected time or date element, the schedule will execute.
    e.g. To execute at 5 minutes past every hour, simply select ‘05’ in the Minutes list box.
  • Values from more than one field may be specified in order to further control the schedule.
    e.g. To execute at 12:05 and 14:05 every Monday and Thursday, you would click minute 05, hours 12 and 14, and weekdays Monday and Thursday.
  • For additional flexibility, the Month Days check list includes an extra Last Day option. This matches the last day of the month, whether it happens to be the 28th, 29th, 30th or 31st.
') + '
' diff --git a/web/pgadmin/browser/server_groups/servers/pgagent/templates/pga_job/css/pga_job.css b/web/pgadmin/browser/server_groups/servers/pgagent/templates/pga_job/css/pga_job.css index d26e218b..ef46fc42 100644 --- a/web/pgadmin/browser/server_groups/servers/pgagent/templates/pga_job/css/pga_job.css +++ b/web/pgadmin/browser/server_groups/servers/pgagent/templates/pga_job/css/pga_job.css @@ -25,6 +25,6 @@ margin: 5px; } -div[role=tabpanel] > .pgadmin-control-group.form-group.pg-el-xs-12.jscexceptions { +div[role=tabpanel] > .pgadmin-control-group.form-group.c.jscexceptions { min-height: 400px; } diff --git a/web/pgadmin/browser/server_groups/servers/roles/static/js/role.js b/web/pgadmin/browser/server_groups/servers/roles/static/js/role.js index 55fd4fe1..09f0f4e2 100644 --- a/web/pgadmin/browser/server_groups/servers/roles/static/js/role.js +++ b/web/pgadmin/browser/server_groups/servers/roles/static/js/role.js @@ -66,8 +66,8 @@ define('pgadmin.node.role', [ var RoleCustomSwitchControl = Backform.SwitchControl.extend({ template: _.template([ - '', - '
', + '', + '
', '
', '
\ -
\ +
\
' + unescape(message) + '
\
\
'; diff --git a/web/pgadmin/browser/static/js/keyboard.js b/web/pgadmin/browser/static/js/keyboard.js index 371faa5d..dc12659d 100644 --- a/web/pgadmin/browser/static/js/keyboard.js +++ b/web/pgadmin/browser/static/js/keyboard.js @@ -4,6 +4,7 @@ import $ from 'jquery'; import Mousetrap from 'mousetrap'; import * as commonUtils from '../../../static/js/utils'; import dialogTabNavigator from '../../../static/js/dialog_tab_navigator'; +import {default as keyboardFunc} from 'sources/keyboard_shortcuts'; const pgBrowser = pgAdmin.Browser = pgAdmin.Browser || {}; @@ -37,9 +38,7 @@ _.extend(pgBrowser.keyboardNavigation, { this.keyboardShortcut.help_shortcut], }, // Main menu 'bindRightPanel': {'shortcuts': [this.keyboardShortcut.tabbed_panel_backward, this.keyboardShortcut.tabbed_panel_forward]}, // Main window panels - 'bindMainMenuLeft': {'shortcuts': 'left', 'bindElem': '.pg-navbar'}, // Main menu - 'bindMainMenuRight': {'shortcuts': 'right', 'bindElem': '.pg-navbar'}, // Main menu - 'bindMainMenuUpDown': {'shortcuts': ['up', 'down']}, // Main menu + 'bindSubMenuClose': {'shortcuts': ['esc','enter']}, 'bindLeftTree': {'shortcuts': this.keyboardShortcut.left_tree_shortcut}, // Main menu, 'bindSubMenuQueryTool': {'shortcuts': this.keyboardShortcut.sub_menu_query_tool}, // Sub menu - Open Query Tool, 'bindSubMenuViewData': {'shortcuts': this.keyboardShortcut.sub_menu_view_data}, // Sub menu - Open View Data, @@ -58,9 +57,37 @@ _.extend(pgBrowser.keyboardNavigation, { _.each(self.shortcutMethods, (keyCombo, callback) => { self._bindWithMousetrap(keyCombo.shortcuts, self[callback], keyCombo.bindElem); }); + + + /* Dropdown submenu was not working properly for up/down arrow keys. + * So up/down/right/left events for dropdown were removed from Mousetrap and were + * handled manually. + */ + const LEFT_KEY = 37, + UP_KEY = 38, + RIGHT_KEY = 39, + DOWN_KEY = 40; + + $('.pg-navbar').on('keydown', (event)=> { + switch(event.keyCode) { + case LEFT_KEY: + self.bindMainMenuLeft(event); + break; + case UP_KEY: + self.bindMainMenuUpDown(event, 'up'); + break; + case RIGHT_KEY: + self.bindMainMenuRight(event); + break; + case DOWN_KEY: + self.bindMainMenuUpDown(event, 'down'); + break; + } + }); }, _bindWithMousetrap: function(shortcuts, callback, bindElem) { const self = this; + Mousetrap.unbind(shortcuts); if (bindElem) { const elem = document.querySelector(bindElem); Mousetrap(elem).bind(shortcuts, function() { @@ -72,6 +99,15 @@ _.extend(pgBrowser.keyboardNavigation, { }); } }, + unbindShortcuts: function() { + // Reset previous events on each instance + const self = this; + _.each(self.mousetrapInstances, (obj) => { + obj['instance'].reset(); + }); + // Clear already processed events + self.mousetrapInstances = []; + }, bindMainMenu: function(event, combo) { const shortcut_obj = this.keyboardShortcut; if (combo === shortcut_obj.file_shortcut) $('#mnu_file a.dropdown-toggle').dropdown('toggle'); @@ -106,48 +142,85 @@ _.extend(pgBrowser.keyboardNavigation, { }, 1000); }, bindMainMenuLeft: function(event) { - let prevMenu; - if ($(event.target).hasClass('menu-link')) { // Menu items - prevMenu = $(event.target).parent().parent().parent().prev('.dropdown'); - } - else if ($(event.target).parent().hasClass('dropdown-submenu')) { // Sub menu - $(event.target).parent().toggleClass('open'); - return; - } - else { //Menu headers - prevMenu = $(event.target).parent().prev('.dropdown'); - } + if ($(event.target).hasClass('nav-link')) { // Menu items + let currNavMenu = $(event.target).closest('.nav-item'); + keyboardFunc._stopEventPropagation(event); - if (prevMenu.hasClass('hide')) prevMenu = prevMenu.prev('.dropdown'); // Skip hidden menus + currNavMenu = currNavMenu.prev('.nav-item'); + // Skip hidden menus + while(currNavMenu.hasClass('d-none')) { + currNavMenu = currNavMenu.prev('.nav-item'); + } + + currNavMenu.find('.dropdown-toggle').first().dropdown('toggle'); - prevMenu.find('a:first').dropdown('toggle'); + } else if($(event.target).closest('.dropdown-menu').length > 0) { + let currLi = $(event.target).closest('li'); + keyboardFunc._stopEventPropagation(event); + /*close submenu*/ + let currMenu = currLi.closest('.dropdown-menu'); + if(currMenu.closest('.dropdown-submenu').length > 0) { + currMenu.removeClass('show'); + currLi = currMenu.closest('.dropdown-submenu'); + currLi.find('.dropdown-item').trigger('focus'); + } + } }, bindMainMenuRight: function(event) { - let nextMenu; - if ($(event.target).hasClass('menu-link')) { // Menu items - nextMenu = $(event.target).parent().parent().parent().next('.dropdown'); - } - else if ($(event.target).parent().hasClass('dropdown-submenu')) { // Sub menu - $(event.target).parent().toggleClass('open'); - return; - } - else { //Menu headers - nextMenu = $(event.target).parent().next('.dropdown'); - } + if ($(event.target).hasClass('nav-link')) { // Menu items + let currNavMenu = $(event.target).closest('.nav-item'); + keyboardFunc._stopEventPropagation(event); - if (nextMenu.hasClass('hide')) nextMenu = nextMenu.next('.dropdown'); // Skip hidden menus + currNavMenu = currNavMenu.next('.nav-item'); + // Skip hidden menus + while(currNavMenu.hasClass('d-none')) { + currNavMenu = currNavMenu.next('.nav-item'); + } + + currNavMenu.find('.dropdown-toggle').first().dropdown('toggle'); + } else if($(event.target).closest('.dropdown-menu').length > 0) { + let currLi = $(event.target).closest('li'); + keyboardFunc._stopEventPropagation(event); - nextMenu.find('a:first').dropdown('toggle'); + /*open submenu if any*/ + if(currLi.hasClass('dropdown-submenu')){ + currLi.find('.dropdown-menu').addClass('show'); + currLi = currLi.find('.dropdown-menu .dropdown-item').first().trigger('focus'); + } + } }, bindMainMenuUpDown: function(event, combo) { // Handle Sub-menus - if (combo === 'up' && $(event.target).parent().prev().prev('.dropdown-submenu').length > 0) { - $(event.target).parent().prev().prev('.dropdown-submenu').find('a:first').trigger('focus'); - } else { - if ($(event.target).parent().hasClass('dropdown-submenu')) { - $(event.target).parent().parent().parent().find('a:first').dropdown('toggle'); - $(event.target).parent().parent().children().eq(2).find('a:first').trigger('focus'); + if($(event.target).closest('.dropdown-menu').length > 0) { + keyboardFunc._stopEventPropagation(event); + let currLi = $(event.target).closest('li'); + /*close all the submenus on movement*/ + $(event.target).closest('.dropdown-menu').find('.show').removeClass('show'); + + if(combo === 'up') { + currLi = currLi.prev(); } + else if(combo === 'down'){ + currLi = currLi.next(); + } + + /*do not focus on divider and disabled */ + while(currLi.hasClass('dropdown-divider') + || currLi.find('.dropdown-item').first().hasClass('disabled')) { + if(combo === 'up') { + currLi = currLi.prev(); + } + else if(combo === 'down'){ + currLi = currLi.next(); + } + } + currLi.find('.dropdown-item').trigger('focus'); + } + }, + bindSubMenuClose: function() { + if($(event.target).hasClass('dropdown-item') + && $(event.target).closest('.dropdown-submenu').length > 0) { + $(event.target).closest('.dropdown').find('.dropdown-submenu .dropdown-menu').removeClass('show'); } }, bindLeftTree: function() { diff --git a/web/pgadmin/browser/static/js/menu.js b/web/pgadmin/browser/static/js/menu.js index 45520c65..df56305f 100644 --- a/web/pgadmin/browser/static/js/menu.js +++ b/web/pgadmin/browser/static/js/menu.js @@ -55,7 +55,7 @@ define([ module: this.module || pgAdmin.Browser, cb: this.callback, data: this.data, - }).addClass('menu-link'); + }).addClass('dropdown-item'); this.is_disabled = this.disabled(node, item); if (this.icon) { @@ -64,53 +64,14 @@ define([ })); } + url.addClass((this.is_disabled ? ' disabled' : '')); + var textSpan = $('').text(' ' + this.label); url.append(textSpan); - this.$el = $('
  • ') - .addClass('menu-item' + (this.is_disabled ? ' disabled' : '')) - .append(url); - - this.applyStyle(); - }, - - applyDisabledStyle: function() { - var span = this.$el.find('span'); - var icon = this.$el.find('i'); - - - span.addClass('text-gray'); - span.removeClass('text-fg-inverse'); - icon.addClass('text-gray'); - icon.removeClass('text-fg-inverse'); + this.$el = $('
  • ').append(url); }, - - applyEnabledStyle: function() { - var element = this.$el; - var span = this.$el.find('span'); - - span.addClass('text-fg-inverse'); - span.removeClass('text-gray'); - element.find('i').addClass('text-fg-inverse'); - element.find('i').removeClass('text-gray'); - - span.on('mouseover',() => { - element.addClass('bg-gray-dark'); - }); - span.on('mouseout',() => { - element.removeClass('bg-gray-dark'); - }); - }, - - applyStyle: function() { - if (this.is_disabled) { - this.applyDisabledStyle(); - } else { - this.applyEnabledStyle(); - } - }, - /* * Updates the enable/disable state of the menu-item based on the current * selection using the disabled function. This also creates a object @@ -118,17 +79,13 @@ define([ */ update: function(node, item) { - if (this.$el && !this.$el.hasClass('disabled')) { - this.$el.addClass('disabled'); + if (this.$el && !this.$el.find('.dropdown-item').hasClass('disabled')) { + this.$el.find('.dropdown-item').addClass('disabled'); } this.is_disabled = this.disabled(node, item); if (this.$el && !this.is_disabled) { - this.$el.removeClass('disabled'); - } - - if (this.$el) { - this.applyStyle(); + this.$el.find('.dropdown-item').removeClass('disabled'); } this.context = { @@ -208,16 +165,16 @@ define([ pgAdmin.Browser.MenuGroup = function(opts, items, prev, ctx) { var template = _.template([ - '<% if (above) { %>
    <% } %>', - '
  • <% } %>', + '
    ' + diff --git a/web/pgadmin/browser/static/scss/_browser.scss b/web/pgadmin/browser/static/scss/_browser.scss index b15c5fd5..894112aa 100644 --- a/web/pgadmin/browser/static/scss/_browser.scss +++ b/web/pgadmin/browser/static/scss/_browser.scss @@ -45,8 +45,8 @@ samp, } .pg-toolbar-btn:hover { - border: 1px solid $color-gray-light !important; - background-color: $color-gray-lighter !important; + border: none; + background-color: $color-bg !important; } .pg-toolbar-btn { @@ -55,5 +55,5 @@ samp, background-color: $color-bg !important; font-size: 14px !important; color: $color-gray-darker !important; - border: 1px solid $color-gray-light !important; + border: none; } diff --git a/web/pgadmin/browser/templates/browser/index.html b/web/pgadmin/browser/templates/browser/index.html index b1280422..f8c2af96 100644 --- a/web/pgadmin/browser/templates/browser/index.html +++ b/web/pgadmin/browser/templates/browser/index.html @@ -34,7 +34,7 @@ require.onResourceLoad = function (context, map, depMaps) { if (loadingStatusEl) { if (!context) { // we will call onResourceLoad(false) by ourselves when requirejs - // is not loading anything hide the indicator and exit + // is not loading anything d-none the indicator and exit setTimeout(function() { if (panel != null) { try{ @@ -93,85 +93,76 @@ window.onload = function(e){ {% block body %}
    -
    -
    {{ _('Loading {0} v{1}...').format(config.APP_NAME, config.APP_VERSION) }}
    +
    +
    {{ _('Loading {0} v{1}...').format(config.APP_NAME, config.APP_VERSION) }}
    -