From f79185dff7482410b73c16c8ba3bcd984bb9ccf7 Mon Sep 17 00:00:00 2001 From: Luke Bennett Date: Tue, 26 Jul 2016 04:52:39 +0100 Subject: Added a new idea for a dispatcher Initial version of dispatcher is functioning, now need to add glob patterns and swap out everything in the old dispatcher Added support for wildcard page queries Tidied up names and method order. Started adding code docs Started converting old dispatcher implementations to new dispatcher --- app/assets/javascripts/application.js | 1 + app/assets/javascripts/diff.js | 8 + app/assets/javascripts/dispatcher.js | 282 --------------------- app/assets/javascripts/dispatcher.js.es6 | 91 +++++++ app/assets/javascripts/due_date_select.js | 5 + app/assets/javascripts/gl_form.js | 21 ++ app/assets/javascripts/issuable.js.es6 | 5 + app/assets/javascripts/issuable_form.js | 10 + app/assets/javascripts/issue.js | 2 + app/assets/javascripts/issues-bulk-assignment.js | 5 + app/assets/javascripts/merged_buttons.js | 7 + app/assets/javascripts/milestone.js | 6 + app/assets/javascripts/old-dispatcher.js | 179 +++++++++++++ app/assets/javascripts/shortcuts_issuable.js | 3 + app/assets/javascripts/shortcuts_navigation.js | 29 +++ .../templates/issuable_template_selectors.js.es6 | 10 +- app/assets/javascripts/todos.js | 2 + app/assets/javascripts/zen_mode.js | 14 + 18 files changed, 396 insertions(+), 284 deletions(-) delete mode 100644 app/assets/javascripts/dispatcher.js create mode 100644 app/assets/javascripts/dispatcher.js.es6 create mode 100644 app/assets/javascripts/old-dispatcher.js diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js index 31fa508d6c1..5f317f674ff 100644 --- a/app/assets/javascripts/application.js +++ b/app/assets/javascripts/application.js @@ -33,6 +33,7 @@ /*= require bootstrap/popover */ /*= require select2 */ /*= require underscore */ +/*= require dispatcher */ /*= require dropzone */ /*= require mousetrap */ /*= require mousetrap/pause */ diff --git a/app/assets/javascripts/diff.js b/app/assets/javascripts/diff.js index c8634b78f2b..9654552f487 100644 --- a/app/assets/javascripts/diff.js +++ b/app/assets/javascripts/diff.js @@ -66,4 +66,12 @@ })(); + window.gl.Dispatcher.register([ + 'projects:merge_requests:edit', + 'projects:merge_requests:show', + 'projects:merge_requests:diffs', + 'projects:commit:show', + 'projects:compare:show' + ], this.Diff); + }).call(this); diff --git a/app/assets/javascripts/dispatcher.js b/app/assets/javascripts/dispatcher.js deleted file mode 100644 index 99b16f7d59b..00000000000 --- a/app/assets/javascripts/dispatcher.js +++ /dev/null @@ -1,282 +0,0 @@ -(function() { - var Dispatcher; - - $(function() { - return new Dispatcher(); - }); - - Dispatcher = (function() { - function Dispatcher() { - this.initSearch(); - this.initPageScripts(); - } - - Dispatcher.prototype.initPageScripts = function() { - var page, path, shortcut_handler; - page = $('body').attr('data-page'); - if (!page) { - return false; - } - path = page.split(':'); - shortcut_handler = null; - switch (page) { - case 'projects:boards:show': - shortcut_handler = new ShortcutsNavigation(); - break; - case 'projects:merge_requests:index': - case 'projects:issues:index': - Issuable.init(); - new IssuableBulkActions(); - shortcut_handler = new ShortcutsNavigation(); - break; - case 'projects:issues:show': - new Issue(); - shortcut_handler = new ShortcutsIssuable(); - new ZenMode(); - break; - case 'projects:milestones:show': - case 'groups:milestones:show': - case 'dashboard:milestones:show': - new Milestone(); - break; - case 'dashboard:todos:index': - new Todos(); - break; - case 'projects:milestones:new': - case 'projects:milestones:edit': - new ZenMode(); - new DueDateSelect(); - new GLForm($('.milestone-form')); - break; - case 'groups:milestones:new': - new ZenMode(); - break; - case 'projects:compare:show': - new Diff(); - break; - case 'projects:issues:new': - case 'projects:issues:edit': - shortcut_handler = new ShortcutsNavigation(); - new GLForm($('.issue-form')); - new IssuableForm($('.issue-form')); - new IssuableTemplateSelectors(); - break; - case 'projects:merge_requests:new': - case 'projects:merge_requests:edit': - new Diff(); - shortcut_handler = new ShortcutsNavigation(); - new GLForm($('.merge-request-form')); - new IssuableForm($('.merge-request-form')); - new IssuableTemplateSelectors(); - break; - case 'projects:tags:new': - new ZenMode(); - new GLForm($('.tag-form')); - break; - case 'projects:releases:edit': - new ZenMode(); - new GLForm($('.release-form')); - break; - case 'projects:merge_requests:show': - new Diff(); - shortcut_handler = new ShortcutsIssuable(true); - new ZenMode(); - new MergedButtons(); - break; - case 'projects:merge_requests:commits': - case 'projects:merge_requests:builds': - new MergedButtons(); - break; - case "projects:merge_requests:diffs": - new Diff(); - new ZenMode(); - new MergedButtons(); - break; - case "projects:merge_requests:conflicts": - window.mcui = new MergeConflictResolver() - case 'dashboard:activity': - new Activities(); - break; - case 'dashboard:projects:starred': - new Activities(); - break; - case 'projects:commit:show': - new Commit(); - new Diff(); - new ZenMode(); - shortcut_handler = new ShortcutsNavigation(); - break; - case 'projects:commits:show': - case 'projects:activity': - shortcut_handler = new ShortcutsNavigation(); - break; - case 'projects:show': - shortcut_handler = new ShortcutsNavigation(); - new NotificationsForm(); - if ($('#tree-slider').length) { - new TreeView(); - } - break; - case 'groups:activity': - new Activities(); - break; - case 'groups:show': - shortcut_handler = new ShortcutsNavigation(); - new NotificationsForm(); - new NotificationsDropdown(); - break; - case 'groups:group_members:index': - new gl.MemberExpirationDate(); - new GroupMembers(); - new UsersSelect(); - break; - case 'projects:project_members:index': - new gl.MemberExpirationDate(); - new ProjectMembers(); - new UsersSelect(); - break; - case 'groups:new': - case 'groups:edit': - case 'admin:groups:edit': - case 'admin:groups:new': - new GroupAvatar(); - break; - case 'projects:tree:show': - shortcut_handler = new ShortcutsNavigation(); - new TreeView(); - break; - case 'projects:find_file:show': - shortcut_handler = true; - break; - case 'projects:blob:show': - case 'projects:blame:show': - new LineHighlighter(); - shortcut_handler = new ShortcutsNavigation(); - new ShortcutsBlob(true); - break; - case 'projects:labels:new': - case 'projects:labels:edit': - new Labels(); - break; - case 'projects:labels:index': - if ($('.prioritized-labels').length) { - new LabelManager(); - } - break; - case 'projects:network:show': - // Ensure we don't create a particular shortcut handler here. This is - // already created, where the network graph is created. - shortcut_handler = true; - break; - case 'projects:forks:new': - new ProjectFork(); - break; - case 'projects:artifacts:browse': - new BuildArtifacts(); - break; - case 'projects:group_links:index': - new gl.MemberExpirationDate(); - new GroupsSelect(); - break; - case 'search:show': - new Search(); - break; - case 'projects:protected_branches:index': - new gl.ProtectedBranchCreate(); - new gl.ProtectedBranchEditList(); - break; - } - switch (path.first()) { - case 'admin': - new Admin(); - switch (path[1]) { - case 'groups': - new UsersSelect(); - break; - case 'projects': - new NamespaceSelects(); - break; - case 'labels': - switch (path[2]) { - case 'new': - case 'edit': - new Labels(); - } - case 'abuse_reports': - new gl.AbuseReports(); - break; - } - break; - case 'dashboard': - case 'root': - shortcut_handler = new ShortcutsDashboardNavigation(); - break; - case 'profiles': - new NotificationsForm(); - new NotificationsDropdown(); - break; - case 'projects': - new Project(); - new ProjectAvatar(); - switch (path[1]) { - case 'compare': - new CompareAutocomplete(); - break; - case 'edit': - shortcut_handler = new ShortcutsNavigation(); - new ProjectNew(); - break; - case 'new': - new ProjectNew(); - break; - case 'show': - new Star(); - new ProjectNew(); - new ProjectShow(); - new NotificationsDropdown(); - break; - case 'wikis': - new Wikis(); - shortcut_handler = new ShortcutsNavigation(); - new ZenMode(); - new GLForm($('.wiki-form')); - break; - case 'snippets': - shortcut_handler = new ShortcutsNavigation(); - if (path[2] === 'show') { - new ZenMode(); - } - break; - case 'labels': - case 'graphs': - case 'compare': - case 'pipelines': - case 'forks': - case 'milestones': - case 'project_members': - case 'deploy_keys': - case 'builds': - case 'hooks': - case 'services': - case 'protected_branches': - shortcut_handler = new ShortcutsNavigation(); - } - } - // If we haven't installed a custom shortcut handler, install the default one - if (!shortcut_handler) { - return new Shortcuts(); - } - }; - - Dispatcher.prototype.initSearch = function() { - // Only when search form is present - if ($('.search').length) { - return new SearchAutocomplete(); - } - }; - - return Dispatcher; - - })(); - -}).call(this); diff --git a/app/assets/javascripts/dispatcher.js.es6 b/app/assets/javascripts/dispatcher.js.es6 new file mode 100644 index 00000000000..bce23e5b257 --- /dev/null +++ b/app/assets/javascripts/dispatcher.js.es6 @@ -0,0 +1,91 @@ +((global) => { + class Dispatcher { + constructor() { + this.registeredModules = []; + this.executedModules = []; + document.addEventListener('page:change', this.processModules.bind(this)); + document.addEventListener('page:before-unload', this.processModules.bind(this)); + } + + /** + * Registers a module to a page query, or an array of page queries. + * Module page queries are matched against the `body` `date-page` attribute + * in order to + * @param {String} pageQuery - A page query, often taken from the body + * `data-page` attribute. + * e.g. `primary:secondary:tertiary`. + * It can also accept wildcards. + * e.g. `primary:*:tertiary`. + * @param {Function} module - A function to be invoked when a module's + * page query matches the current page identifier. + * @return {Undefined} + */ + register(pageQuery, module) { + if (_.isArray(pageQuery)) { + for (pageQuery of pageQuery) { + this.registerModule(pageQuery, module); + } + } else { + this.registerModule(pageQuery, module); + } + } + + processModules(e) { + const shouldDestroy = (e.type === 'page:before-unload'); + for (let i = 0; i < this.registeredModules.length; i++) { + const module = this.registeredModules[i]; + if (shouldDestroy) { + this.destroyModule(module); + } else { + this.executeModule(module); + }; + } + if (shouldDestroy) this.executedModules = []; + } + + registerModule(pageQuery, module) { + this.registeredModules.push({ + pageQuery, + module, + }); + } + + destroyModule(module) { + if (!module.destroyableInstance) return; + if (module.destroyableInstance.destroy) module.destroyableInstance.destroy(); + delete module.destroyableInstance; + delete global[module.module.name]; + } + + executeModule(module) { + if (!this.isExecutable(module)) return; + try { + module.destroyableInstance = new module.module(); + } catch (e) { + module.destroyableInstance = module.module(); + } + global[module.module.name] = module.module; + this.executedModules.push(module.module.name); + } + + isExecutable(module) { + for (let i = 0; i < this.executedModules.length; i++) { + const executedModuleName = this.executedModules[i]; + if (module.module.name === executedModuleName) { + return false; + } + } + return this.matchesPageIdentifier(module) + } + + matchesPageIdentifier(module) { + const currentPageIdentifier = document.body.attributes['data-page'].value; + const pageQueryRegexString = module.pageQuery.replace(/\*/g, '.*'); + const pageQueryRegex = new RegExp(pageQueryRegexString, 'gi'); + return pageQueryRegex.test(currentPageIdentifier); + } + } + + global.Dispatcher = new Dispatcher(); + +})(window.gl || (window.gl = {})); diff --git a/app/assets/javascripts/due_date_select.js b/app/assets/javascripts/due_date_select.js index bf68b7e3a9b..191b44bb1a3 100644 --- a/app/assets/javascripts/due_date_select.js +++ b/app/assets/javascripts/due_date_select.js @@ -104,4 +104,9 @@ })(); + window.gl.Dispatcher.register([ + 'projects:milestones:new', + 'projects:milestones:edit' + ], this.DueDateSelect); + }).call(this); diff --git a/app/assets/javascripts/gl_form.js b/app/assets/javascripts/gl_form.js index 2703adc0705..2532af2e85c 100644 --- a/app/assets/javascripts/gl_form.js +++ b/app/assets/javascripts/gl_form.js @@ -56,4 +56,25 @@ })(); + window.gl.Dispatcher.register([ + 'projects:milestones:edit', + 'projects:milestones:new' + ], () => new GLForm($('.milestone-form'))); + + window.gl.Dispatcher.register([ + 'projects:issues:new', + 'projects:issues:edit' + ], () => new GLForm($('.issue-form'))); + + window.gl.Dispatcher.register([ + 'projects:merge_requests:new', + 'projects:merge_requests:edit' + ], () => new GLForm($('.merge-request-form'))); + + window.gl.Dispatcher.register('projects:tags:new', () => new GLForm($('.tag-form'))); + + window.gl.Dispatcher.register('projects:releases:edit', () => new GLForm($('.release-form'))); + + window.gl.Dispatcher.register('projects:wikis:*', () => new GLForm($('.wiki-form'))); + }).call(this); diff --git a/app/assets/javascripts/issuable.js.es6 b/app/assets/javascripts/issuable.js.es6 index 53faaa38a0c..f15a85e1f29 100644 --- a/app/assets/javascripts/issuable.js.es6 +++ b/app/assets/javascripts/issuable.js.es6 @@ -100,4 +100,9 @@ } }; + window.gl.Dispatcher.register([ + 'projects:issues:index', + 'projects:merge_requests:index' + ], this.Issuable.init); + }).call(this); diff --git a/app/assets/javascripts/issuable_form.js b/app/assets/javascripts/issuable_form.js index b7f92ae9883..c7538c8f650 100644 --- a/app/assets/javascripts/issuable_form.js +++ b/app/assets/javascripts/issuable_form.js @@ -147,4 +147,14 @@ })(); + window.gl.Dispatcher.register([ + 'projects:issues:new', + 'projects:issues:edit' + ], () => new this.IssuableForm($('.issue-form'))); + + window.gl.Dispatcher.register([ + 'projects:merge_requests:new', + 'projects:merge_requests:edit' + ], () => new this.IssuableForm($('.merge-request-form'))); + }).call(this); diff --git a/app/assets/javascripts/issue.js b/app/assets/javascripts/issue.js index 261bf6137c2..1c81864bd9c 100644 --- a/app/assets/javascripts/issue.js +++ b/app/assets/javascripts/issue.js @@ -151,4 +151,6 @@ })(); + window.gl.Dispatcher.register('projects:issues:show', this.Issue); + }).call(this); diff --git a/app/assets/javascripts/issues-bulk-assignment.js b/app/assets/javascripts/issues-bulk-assignment.js index 62a7fc9a06c..31bba58557f 100644 --- a/app/assets/javascripts/issues-bulk-assignment.js +++ b/app/assets/javascripts/issues-bulk-assignment.js @@ -164,4 +164,9 @@ })(); + window.gl.Dispatcher.register([ + 'projects:issues:index', + 'projects:merge_requests:index' + ], this.IssuableBulkActions); + }).call(this); diff --git a/app/assets/javascripts/merged_buttons.js b/app/assets/javascripts/merged_buttons.js index 1fed38661a2..b4c79845205 100644 --- a/app/assets/javascripts/merged_buttons.js +++ b/app/assets/javascripts/merged_buttons.js @@ -42,4 +42,11 @@ })(); + window.gl.Dispatcher.register([ + 'projects:merge_requests:show', + 'projects:merge_requests:commits', + 'projects:merge_requests:builds', + 'projects:merge_requests:diffs' + ], this.MergedButtons); + }).call(this); diff --git a/app/assets/javascripts/milestone.js b/app/assets/javascripts/milestone.js index bc1a99057d9..79400fc1b40 100644 --- a/app/assets/javascripts/milestone.js +++ b/app/assets/javascripts/milestone.js @@ -193,4 +193,10 @@ })(); + window.gl.Dispatcher.register([ + 'projects:milestones:show', + 'groups:milestones:show', + 'dashboard:milestones:show' + ], this.Milestone); + }).call(this); diff --git a/app/assets/javascripts/old-dispatcher.js b/app/assets/javascripts/old-dispatcher.js new file mode 100644 index 00000000000..ee8dc90c54c --- /dev/null +++ b/app/assets/javascripts/old-dispatcher.js @@ -0,0 +1,179 @@ +(function() { + var Dispatcher; + + $(function() { + return new Dispatcher(); + }); + + Dispatcher = (function() { + function Dispatcher() { + this.initSearch(); + this.initPageScripts(); + } + + Dispatcher.prototype.initPageScripts = function() { + var page, path, shortcut_handler; + page = $('body').attr('data-page'); + if (!page) { + return false; + } + path = page.split(':'); + shortcut_handler = null; + switch (page) { + case "projects:merge_requests:conflicts": + window.mcui = new MergeConflictResolver() + case 'dashboard:activity': + new Activities(); + break; + case 'dashboard:projects:starred': + new Activities(); + break; + case 'projects:commit:show': + new Commit(); + break; + case 'projects:commits:show': + case 'projects:activity': + break; + case 'projects:show': + new NotificationsForm(); + if ($('#tree-slider').length) { + new TreeView(); + } + break; + case 'groups:activity': + new Activities(); + break; + case 'groups:show': + new NotificationsForm(); + new NotificationsDropdown(); + break; + case 'groups:group_members:index': + new gl.MemberExpirationDate(); + new GroupMembers(); + new UsersSelect(); + break; + case 'projects:project_members:index': + new gl.MemberExpirationDate(); + new ProjectMembers(); + new UsersSelect(); + break; + case 'groups:new': + case 'groups:edit': + case 'admin:groups:edit': + case 'admin:groups:new': + new GroupAvatar(); + break; + case 'projects:tree:show': + new TreeView(); + break; + case 'projects:find_file:show': + shortcut_handler = true; + break; + case 'projects:blob:show': + case 'projects:blame:show': + new LineHighlighter(); + new ShortcutsBlob(true); + break; + case 'projects:labels:new': + case 'projects:labels:edit': + new Labels(); + break; + case 'projects:labels:index': + if ($('.prioritized-labels').length) { + new LabelManager(); + } + break; + case 'projects:network:show': + // Ensure we don't create a particular shortcut handler here. This is + // already created, where the network graph is created. + shortcut_handler = true; + break; + case 'projects:forks:new': + new ProjectFork(); + break; + case 'projects:artifacts:browse': + new BuildArtifacts(); + break; + case 'projects:group_links:index': + new gl.MemberExpirationDate(); + new GroupsSelect(); + break; + case 'search:show': + new Search(); + break; + case 'projects:protected_branches:index': + new gl.ProtectedBranchCreate(); + new gl.ProtectedBranchEditList(); + break; + } + switch (path.first()) { + case 'admin': + new Admin(); + switch (path[1]) { + case 'groups': + new UsersSelect(); + break; + case 'projects': + new NamespaceSelects(); + break; + case 'labels': + switch (path[2]) { + case 'new': + case 'edit': + new Labels(); + } + case 'abuse_reports': + new gl.AbuseReports(); + break; + } + break; + case 'dashboard': + case 'root': + shortcut_handler = new ShortcutsDashboardNavigation(); + break; + case 'profiles': + new NotificationsForm(); + new NotificationsDropdown(); + break; + case 'projects': + new Project(); + new ProjectAvatar(); + switch (path[1]) { + case 'compare': + new CompareAutocomplete(); + break; + case 'edit': + new ProjectNew(); + break; + case 'new': + new ProjectNew(); + break; + case 'show': + new Star(); + new ProjectNew(); + new ProjectShow(); + new NotificationsDropdown(); + break; + case 'wikis': + new Wikis(); + break; + } + } + // If we haven't installed a custom shortcut handler, install the default one + if (!shortcut_handler) { + return new Shortcuts(); + } + }; + + Dispatcher.prototype.initSearch = function() { + // Only when search form is present + if ($('.search').length) { + return new SearchAutocomplete(); + } + }; + + return Dispatcher; + + })(); + +}).call(this); diff --git a/app/assets/javascripts/shortcuts_issuable.js b/app/assets/javascripts/shortcuts_issuable.js index 235bf4f95ec..29ae01777a0 100644 --- a/app/assets/javascripts/shortcuts_issuable.js +++ b/app/assets/javascripts/shortcuts_issuable.js @@ -74,4 +74,7 @@ })(ShortcutsNavigation); + window.gl.Dispatcher.register('projects:issues:show', this.ShortcutsIssuable); + window.gl.Dispatcher.register('projects:merge_requests:show', () => new this.ShortcutsIssuable(true)); + }).call(this); diff --git a/app/assets/javascripts/shortcuts_navigation.js b/app/assets/javascripts/shortcuts_navigation.js index b04159420d1..e3a02992a74 100644 --- a/app/assets/javascripts/shortcuts_navigation.js +++ b/app/assets/javascripts/shortcuts_navigation.js @@ -64,4 +64,33 @@ })(Shortcuts); + window.gl.Dispatcher.register([ + 'projects:boards:show', + 'projects:issues:index', + 'projects:issues:edit', + 'projects:merge_requests:edit', + 'projects:merge_requests:index', + 'projects:commit:show', + 'projects:activity', + 'projects:show', + 'groups:show', + 'projects:tree:show', + 'projects:blame:show', + 'projects:edit:*', + 'projects:wikis:*', + 'projects:snippets:*', + 'projects:labels:*', + 'projects:graphs:*', + 'projects:compare:*', + 'projects:pipelines:*', + 'projects:forks:*', + 'projects:milestones:*', + 'projects:project_members:*', + 'projects:deploy_keys:*', + 'projects:builds:*', + 'projects:hooks:*', + 'projects:services:*', + 'projects:protected_branches:*' + ], this.ShortcutsNavigation); + }).call(this); diff --git a/app/assets/javascripts/templates/issuable_template_selectors.js.es6 b/app/assets/javascripts/templates/issuable_template_selectors.js.es6 index bd8cdde033e..3b510fd510f 100644 --- a/app/assets/javascripts/templates/issuable_template_selectors.js.es6 +++ b/app/assets/javascripts/templates/issuable_template_selectors.js.es6 @@ -25,5 +25,11 @@ } } - global.IssuableTemplateSelectors = IssuableTemplateSelectors; -})(window); + global.Dispatcher.register([ + 'projects:issues:new', + 'projects:issues:edit', + 'projects:merge_requests:new', + 'projects:merge_requests:edit' + ], IssuableTemplateSelectors); + +})(window.gl || (window.gl = {})); diff --git a/app/assets/javascripts/todos.js b/app/assets/javascripts/todos.js index 93421649ac7..b05f7f499af 100644 --- a/app/assets/javascripts/todos.js +++ b/app/assets/javascripts/todos.js @@ -173,4 +173,6 @@ })(); + window.gl.Dispatcher.register('dashboard:todos:index', this.Todos); + }).call(this); diff --git a/app/assets/javascripts/zen_mode.js b/app/assets/javascripts/zen_mode.js index 777b32b41c9..c53caff2416 100644 --- a/app/assets/javascripts/zen_mode.js +++ b/app/assets/javascripts/zen_mode.js @@ -92,4 +92,18 @@ })(); + window.gl.Dispatcher.register([ + 'projects:issues:show', + 'projects:milestones:edit', + 'projects:milestones:new', + 'groups:milestones:new', + 'projects:tags:new', + 'projects:releases:edit', + 'projects:merge_requests:show', + 'projects:merge_requests:diffs', + 'projects:commit:show', + 'projects:wikis:*', + 'projects:snippets:show' + ], this.ZenMode); + }).call(this); -- cgit v1.2.1