diff --git a/app/views/account/_password_login_form.html.erb b/app/views/account/_password_login_form.html.erb index ae6ffcfcfa..9882655d9e 100644 --- a/app/views/account/_password_login_form.html.erb +++ b/app/views/account/_password_login_form.html.erb @@ -67,14 +67,14 @@ See docs/COPYRIGHT.rdoc for more details. <%= link_to t(:label_register), '', title: t(:label_register), - class: 'modal-wrapper--activation-link', - id: 'registration-modal--activation-link--login-form' %> + class: 'modal-wrapper--activation-link' %> <% end %> <% end %> - +
<% @user ||= User.new %> <%= render partial: '/account/register' %> - +
diff --git a/app/views/account/register.html.erb b/app/views/account/register.html.erb index a17f70cfee..48ca2557ee 100644 --- a/app/views/account/register.html.erb +++ b/app/views/account/register.html.erb @@ -28,8 +28,10 @@ See docs/COPYRIGHT.rdoc for more details. ++#%> <%= activate_angular_js do %> - +
<% @user ||= User.new %> <%= render partial: '/account/register' %> - +
<% end %> diff --git a/app/views/layouts/base.html.erb b/app/views/layouts/base.html.erb index 5344adb816..738108ebe9 100644 --- a/app/views/layouts/base.html.erb +++ b/app/views/layouts/base.html.erb @@ -146,11 +146,12 @@ See docs/COPYRIGHT.rdoc for more details. <%= render_flash_messages %> <% if show_onboarding_modal? %> - +
<%= render partial: '/onboarding/starting_video_modal' %> - +
<% end %>

<%= l(:label_content) %>

diff --git a/app/views/onboarding/_menu_item.html.erb b/app/views/onboarding/_menu_item.html.erb index bf6b137774..45540204f8 100644 --- a/app/views/onboarding/_menu_item.html.erb +++ b/app/views/onboarding/_menu_item.html.erb @@ -26,8 +26,9 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. See docs/COPYRIGHT.rdoc for more details. ++#%> - +
  • <%= link_to l(:label_introduction_video), '', @@ -35,4 +36,4 @@ See docs/COPYRIGHT.rdoc for more details. class: 'modal-wrapper--activation-link' %>
  • <%= render partial: '/onboarding/starting_video_modal' %> - +
    diff --git a/frontend/legacy/app/components/modals/modal-wrapper/modal-wrapper.directive.ts b/frontend/legacy/app/components/modals/modal-wrapper/modal-wrapper.directive.ts deleted file mode 100644 index 384963e944..0000000000 --- a/frontend/legacy/app/components/modals/modal-wrapper/modal-wrapper.directive.ts +++ /dev/null @@ -1,110 +0,0 @@ -// -- copyright -// OpenProject is a project management system. -// Copyright (C) 2012-2015 the OpenProject Foundation (OPF) -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License version 3. -// -// OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows: -// Copyright (C) 2006-2013 Jean-Philippe Lang -// Copyright (C) 2010-2013 the ChiliProject Team -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -// -// See doc/COPYRIGHT.rdoc for more details. -// ++ - -import {openprojectLegacyModule} from "../../../openproject-legacy-app"; - -export class ModalWrapperController { - public activationLinkId:string; - public iframeSelector = '.iframe-target-wrapper'; - - private modalBody:string; - public modalClassName = 'ngdialog-theme-openproject'; - - protected opModalService:any; - protected dynamicContentModal:any; - - constructor(protected $element:ng.IAugmentedJQuery, - protected $attrs:ng.IAttributes) { - - window.OpenProject.pluginContext.valuesPromise().then((context) => { - this.opModalService = context.services.opModalService; - this.dynamicContentModal = context.classes.modals.dynamicContent; - - // Find activation link - var activationLink = $element.find('.modal-wrapper--activation-link'); - if (this.activationLinkId) { - activationLink = jQuery(this.activationLinkId); - } - - // Set modal class name - if ($attrs['modalClassName']) { - this.modalClassName = $attrs['modalClassName']; - } - - // Set template from wrapped element - const wrappedElement = $element.find('.modal-wrapper--content'); - this.modalBody = wrappedElement.html(); - - if ($attrs['iframeUrl']) { - this.appendIframe($attrs['iframeUrl']); - } - - if (!!$attrs['initialize']) { - this.initialize(); - } - else { - activationLink.click(() => this.initialize()); - } - - }); - } - - public initialize() { - let modal = this.opModalService.show(this.dynamicContentModal, { modalBody: this.modalBody, modalClassName: this.modalClassName }); - modal.openingEvent.subscribe((modal:any) => { - //HACK: need to trigger an angular digest in order to have the - //modal template be evaluated. Without it, the onInit will not be run. - jQuery('.op-modal--modal-container').click(); - }); - } - - private appendIframe(url:string) { - let subdom = angular.element(this.modalBody); - let iframe = angular.element(''); - iframe.attr('src', url); - - subdom.find(this.iframeSelector).append(iframe); - - this.modalBody = subdom.html(); - } -} - -function modalWrapper():any { - return { - restrict: 'E', - scope: { - modalParams: '=', - activationLinkId: '=?' - }, - controller: ModalWrapperController, - controllerAs: '$ctrl', - bindToController: true, - }; -} - -openprojectLegacyModule.directive('modalWrapper', modalWrapper); diff --git a/frontend/src/app/angular4-modules.ts b/frontend/src/app/angular4-modules.ts index 8f2d2f1860..f950168d22 100644 --- a/frontend/src/app/angular4-modules.ts +++ b/frontend/src/app/angular4-modules.ts @@ -207,6 +207,7 @@ import {OpenProjectFileUploadService} from "core-components/api/op-file-upload/o import {AttributeHelpTextModal} from "./modules/common/help-texts/attribute-help-text.modal"; import {CopyToClipboardDirective} from 'core-app/modules/common/copy-to-clipboard/copy-to-clipboard.directive'; import {WorkPackageEmbeddedTableEntryComponent} from "core-components/wp-table/embedded/wp-embedded-table-entry.component"; +import {ModalWrapperAugmentService} from "core-app/globals/augmenting/modal-wrapper.augment.service"; @NgModule({ imports: [ @@ -306,6 +307,10 @@ import {WorkPackageEmbeddedTableEntryComponent} from "core-components/wp-table/e // External query configuration ExternalQueryConfigurationService, + + // Augmenting Rails + ModalWrapperAugmentService, + ], declarations: [ ConfirmFormSubmitController, @@ -566,8 +571,11 @@ export function bootstrapOptional(appRef:ApplicationRef, ...elements:{ tagName:s export function initializeServices(injector:Injector) { return () => { - const ExternalQueryConfiguration:ExternalQueryConfigurationService = injector.get(ExternalQueryConfigurationService); - const global = (window as any); + const ExternalQueryConfiguration = injector.get(ExternalQueryConfigurationService); + const ModalWrapper = injector.get(ModalWrapperAugmentService); + + // Setup modal wrapping + ModalWrapper.setupListener(); // Setup query configuration listener ExternalQueryConfiguration.setupListener(); diff --git a/frontend/src/app/globals/augmenting/modal-wrapper.augment.service.ts b/frontend/src/app/globals/augmenting/modal-wrapper.augment.service.ts new file mode 100644 index 0000000000..1695382846 --- /dev/null +++ b/frontend/src/app/globals/augmenting/modal-wrapper.augment.service.ts @@ -0,0 +1,104 @@ +// -- copyright +// OpenProject is a project management system. +// Copyright (C) 2012-2015 the OpenProject Foundation (OPF) +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License version 3. +// +// OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows: +// Copyright (C) 2006-2013 Jean-Philippe Lang +// Copyright (C) 2010-2013 the ChiliProject Team +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +// See doc/COPYRIGHT.rdoc for more details. +// ++ + + +import {Inject, Injectable} from "@angular/core"; +import {DOCUMENT} from "@angular/common"; +import {DynamicContentModal} from "core-components/modals/modal-wrapper/dynamic-content.modal"; +import {OpModalService} from "core-components/op-modals/op-modal.service"; + +const iframeSelector = '.iframe-target-wrapper'; + +@Injectable() +export class ModalWrapperAugmentService { + + constructor(@Inject(DOCUMENT) protected documentElement:Document, + protected opModalService:OpModalService) { + } + + /** + * Create initial listeners for Rails-rendered modals + */ + public setupListener() { + const matches = this.documentElement.querySelectorAll('section[data-augmented-model-wrapper]'); + for (let i = 0; i < matches.length; ++i) { + this.wrapElement(jQuery(matches[i])); + } + } + + /** + * Wrap a section[data-augmented-modal-wrapper] element + */ + public wrapElement(element:JQuery) { + // Find activation link + const activationLink = element.find('.modal-wrapper--activation-link'); + const initializeNow = element.data('modalInitializeNow'); + + if (initializeNow) { + this.show(element); + } else { + activationLink.click((evt:JQueryEventObject) => { + this.show(element); + evt.preventDefault(); + }); + } + } + + private show(element:JQuery) { + // Set modal class name + const modalClassName = element.data('modalClassName'); + // Append CSP-whitelisted IFrame for onboarding + const iframeUrl = element.data('modalIframeUrl'); + + // Set template from wrapped element + const wrappedElement = element.find('.modal-wrapper--content'); + let modalBody = wrappedElement.html(); + + if (iframeUrl) { + modalBody = this.appendIframe(modalBody, iframeUrl); + } + + this.opModalService.show( + DynamicContentModal, + { + modalBody: modalBody, + modalClassName: modalClassName + } + ); + } + + private appendIframe(body:string, url:string) { + let subdom = jQuery(body); + let iframe = jQuery(''); + iframe.attr('src', url); + + subdom.find(iframeSelector).append(iframe); + + return subdom.html(); + } +}