@atlassian/atlassian-connect-js 5.3.190
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.depcheckrc.json +16 -0
- package/.editorconfig +9 -0
- package/.envrc +5 -0
- package/.eslintignore +12 -0
- package/.eslintrc +31 -0
- package/.husky/pre-commit +11 -0
- package/.lintstagedrc.js +6 -0
- package/.netrc +1 -0
- package/.npmrc-public +4 -0
- package/.nvmrc +1 -0
- package/LICENSE +3 -0
- package/README.md +281 -0
- package/bitbucket-pipelines.yml +33 -0
- package/build/bin/bin-helper.js +29 -0
- package/build/bin/npm-postinstall.js +9 -0
- package/build/configs/append-sourcemapping.js +13 -0
- package/build/configs/availabletasks.js +15 -0
- package/build/configs/clean.js +12 -0
- package/build/configs/concat.js +44 -0
- package/build/configs/copy.js +32 -0
- package/build/configs/index.js +19 -0
- package/build/configs/jshint.js +9 -0
- package/build/configs/karma.js +11 -0
- package/build/configs/replace.js +10 -0
- package/build/configs/requirejs.js +187 -0
- package/build/configs/saucelabs-launchers.js +30 -0
- package/build/configs/shell.js +24 -0
- package/build/configs/uglify.js +15 -0
- package/build/configs/watch.js +45 -0
- package/build/end.frag +13 -0
- package/build/start.frag +18 -0
- package/bundlesize.config.json +14 -0
- package/dist/connect-host.css +225 -0
- package/dist/connect-host.js +13908 -0
- package/dist/connect-host.min.css +1 -0
- package/dist/iframe-fedramp.js +13663 -0
- package/dist/iframe.js +13663 -0
- package/dist/legacy-text-colors.css +245 -0
- package/dist/surfaces.css +11 -0
- package/dist/themes/atlaskit-tokens_dark-future.css +6 -0
- package/dist/themes/atlaskit-tokens_dark.css +394 -0
- package/dist/themes/atlaskit-tokens_legacy-dark.css +394 -0
- package/dist/themes/atlaskit-tokens_legacy-light.css +394 -0
- package/dist/themes/atlaskit-tokens_light-future.css +6 -0
- package/dist/themes/atlaskit-tokens_light.css +394 -0
- package/dist/themes/atlaskit-tokens_shape.css +14 -0
- package/dist/themes/atlaskit-tokens_spacing.css +26 -0
- package/dist/themes/atlaskit-tokens_typography-adg3.css +25 -0
- package/dist/themes/atlaskit-tokens_typography-modernized.css +25 -0
- package/dist/themes/atlaskit-tokens_typography-refreshed.css +25 -0
- package/gulpfile.js +204 -0
- package/memleak-check/app.html +10 -0
- package/memleak-check/index.html +31 -0
- package/memleak-check/index.js +33 -0
- package/package.json +102 -0
- package/renovate.json +11 -0
- package/security-assistant.yml +2 -0
- package/spec/.eslintrc +10 -0
- package/spec/config/karma.base.conf.js +200 -0
- package/spec/config/karma.conf.js +20 -0
- package/spec/fixtures/base_dialog_component_tests.js +180 -0
- package/spec/mocks/mock_feature_flag.js +23 -0
- package/spec/tests/amd_spec.js +122 -0
- package/spec/tests/analytics_dispatcher_spec.js +429 -0
- package/spec/tests/analytics_performance_spec.js +41 -0
- package/spec/tests/button_spec.js +143 -0
- package/spec/tests/dialog_extension_spec.js +59 -0
- package/spec/tests/dialog_module_provider_spec.js +499 -0
- package/spec/tests/dialog_module_spec.js +395 -0
- package/spec/tests/dialog_spec.js +296 -0
- package/spec/tests/dialog_webitem_spec.js +183 -0
- package/spec/tests/dropdown_module_spec.js +77 -0
- package/spec/tests/env_module_spec.js +153 -0
- package/spec/tests/events_spec.js +77 -0
- package/spec/tests/extension_configuration_options_store_spec.js +25 -0
- package/spec/tests/flag_module_provider_spec.js +79 -0
- package/spec/tests/flag_module_spec.js +118 -0
- package/spec/tests/flag_spec.js +243 -0
- package/spec/tests/host-api_spec.js +220 -0
- package/spec/tests/iframe-create_spec.js +43 -0
- package/spec/tests/iframe_container_spec.js +19 -0
- package/spec/tests/iframe_spec.js +265 -0
- package/spec/tests/inline_dialog_spec.js +41 -0
- package/spec/tests/inline_dialog_webitem_spec.js +331 -0
- package/spec/tests/loading_indicator_spec.js +48 -0
- package/spec/tests/messages_module_spec.js +108 -0
- package/spec/tests/meta_spec.js +71 -0
- package/spec/tests/module_args_spec.js +52 -0
- package/spec/tests/observe_spec.js +73 -0
- package/spec/tests/public_events.spec.js +102 -0
- package/spec/tests/scroll_position_spec.js +109 -0
- package/spec/tests/theming_spec.js +594 -0
- package/spec/tests/util_spec.js +55 -0
- package/spec/tests/utils/base64_spec.js +20 -0
- package/spec/tests/utils/button_spec.js +11 -0
- package/spec/tests/utils/cookie_spec.js +19 -0
- package/spec/tests/utils/deprecate_spec.js +22 -0
- package/spec/tests/utils/dialog_spec.js +297 -0
- package/spec/tests/utils/host_util_spec.js +45 -0
- package/spec/tests/utils/iframe_spec.js +41 -0
- package/spec/tests/utils/jwt_spec.js +135 -0
- package/spec/tests/utils/url_spec.js +37 -0
- package/spec/tests/utils/waitUntilReadyNextTick.js +5 -0
- package/spec/tests/utils/webitem.js +219 -0
- package/spec/tests/webitem_spec.js +131 -0
- package/src/css/host/dialog.css +144 -0
- package/src/css/host/flags.css +5 -0
- package/src/css/host/host.css +64 -0
- package/src/css/host/messages.css +12 -0
- package/src/css/plugin/legacy-text-colors.less +55 -0
- package/src/css/plugin/surfaces.css +11 -0
- package/src/host/ACJSFrameworkAdaptor.js +44 -0
- package/src/host/actions/analytics_action.js +35 -0
- package/src/host/actions/button_actions.js +21 -0
- package/src/host/actions/dialog_actions.js +27 -0
- package/src/host/actions/dialog_extension_actions.js +25 -0
- package/src/host/actions/dom_event_actions.js +32 -0
- package/src/host/actions/dropdown_actions.js +12 -0
- package/src/host/actions/env_actions.js +57 -0
- package/src/host/actions/event_actions.js +33 -0
- package/src/host/actions/flag_actions.js +22 -0
- package/src/host/actions/iframe_actions.js +27 -0
- package/src/host/actions/inline_dialog_actions.js +26 -0
- package/src/host/actions/inline_dialog_webitem_actions.js +10 -0
- package/src/host/actions/jwt_actions.js +51 -0
- package/src/host/actions/loading_indicator_actions.js +10 -0
- package/src/host/actions/module_actions.js +14 -0
- package/src/host/actions/webitem_actions.js +29 -0
- package/src/host/components/button.js +112 -0
- package/src/host/components/dialog.js +447 -0
- package/src/host/components/dialog_extension.js +106 -0
- package/src/host/components/dialog_webitem.js +69 -0
- package/src/host/components/flag.js +102 -0
- package/src/host/components/iframe.js +130 -0
- package/src/host/components/iframe_container.js +38 -0
- package/src/host/components/inline_dialog.js +108 -0
- package/src/host/components/inline_dialog_webitem.js +157 -0
- package/src/host/components/loading_indicator.js +110 -0
- package/src/host/components/webitem.js +227 -0
- package/src/host/deprecate.js +20 -0
- package/src/host/dispatchers/analytics_dispatcher.js +512 -0
- package/src/host/dispatchers/event_dispatcher.js +46 -0
- package/src/host/dollar.js +8 -0
- package/src/host/host-api.js +325 -0
- package/src/host/iframe-create.js +7 -0
- package/src/host/index.js +108 -0
- package/src/host/module-providers.js +13 -0
- package/src/host/modules/_featureFlag.js +42 -0
- package/src/host/modules/_performance.js +54 -0
- package/src/host/modules/analytics.js +17 -0
- package/src/host/modules/dialog.js +496 -0
- package/src/host/modules/dropdown.js +255 -0
- package/src/host/modules/env.js +156 -0
- package/src/host/modules/events.js +28 -0
- package/src/host/modules/flag.js +170 -0
- package/src/host/modules/host.js +19 -0
- package/src/host/modules/inline-dialog.js +33 -0
- package/src/host/modules/messages.js +309 -0
- package/src/host/modules/page.js +29 -0
- package/src/host/modules/scroll-position.js +102 -0
- package/src/host/modules/theming.js +114 -0
- package/src/host/stores/extension_configuration_options_store.js +24 -0
- package/src/host/util.js +98 -0
- package/src/host/utils/access-narrowing-context.js +18 -0
- package/src/host/utils/base64.js +22 -0
- package/src/host/utils/button.js +10 -0
- package/src/host/utils/cookie.js +14 -0
- package/src/host/utils/dialog.js +239 -0
- package/src/host/utils/feature-flag.js +27 -0
- package/src/host/utils/iframe.js +23 -0
- package/src/host/utils/jwt.js +60 -0
- package/src/host/utils/observe.js +34 -0
- package/src/host/utils/removal-observer.js +30 -0
- package/src/host/utils/simplexdm.js +58 -0
- package/src/host/utils/url.js +23 -0
- package/src/host/utils/webitem.js +214 -0
- package/src/plugin/amd.js +115 -0
- package/src/plugin/analytics.js +84 -0
- package/src/plugin/deprecate.js +16 -0
- package/src/plugin/dialog.js +197 -0
- package/src/plugin/dollar.js +77 -0
- package/src/plugin/events-instance.js +2 -0
- package/src/plugin/events.js +246 -0
- package/src/plugin/extension_configuration_options_store.js +27 -0
- package/src/plugin/featureFlag.js +8 -0
- package/src/plugin/index.js +118 -0
- package/src/plugin/meta.js +14 -0
- package/src/plugin/public-events.js +73 -0
- package/src/plugin/theming.js +211 -0
- package/src/plugin/util.js +104 -0
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import $ from '../dollar';
|
|
2
|
+
import FlagActions from '../actions/flag_actions';
|
|
3
|
+
import EventDispatcher from '../dispatchers/event_dispatcher';
|
|
4
|
+
const FLAGID_PREFIX = 'ap-flag-';
|
|
5
|
+
const FLAG_CLASS = 'ac-aui-flag';
|
|
6
|
+
const FLAG_ACTION_CLASS = 'ac-flag-actions';
|
|
7
|
+
|
|
8
|
+
class Flag {
|
|
9
|
+
|
|
10
|
+
cleanKey(dirtyKey) {
|
|
11
|
+
var cleanFlagKeyRegExp = new RegExp('^' + FLAGID_PREFIX + '(.+)$');
|
|
12
|
+
var matches = dirtyKey.match(cleanFlagKeyRegExp);
|
|
13
|
+
if(matches && matches[1]) {
|
|
14
|
+
return matches[1];
|
|
15
|
+
}
|
|
16
|
+
return null;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
_toHtmlString(str) {
|
|
20
|
+
if($.type(str) === 'string'){
|
|
21
|
+
return str;
|
|
22
|
+
} else if($.type(str) === 'object' && (str instanceof $) ){
|
|
23
|
+
return str.html();
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
_renderBody(body){
|
|
28
|
+
var body = this._toHtmlString(body);
|
|
29
|
+
var $body = $('<div />').html(body);
|
|
30
|
+
$('<p />').addClass(FLAG_ACTION_CLASS).appendTo($body);
|
|
31
|
+
return $body.html();
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
_renderActions($flag, flagId, actions) {
|
|
35
|
+
var $actionContainer = $flag.find('.' + FLAG_ACTION_CLASS);
|
|
36
|
+
actions = actions || {};
|
|
37
|
+
var $action;
|
|
38
|
+
|
|
39
|
+
Object.getOwnPropertyNames(actions).forEach((key) => {
|
|
40
|
+
$action = $('<a />')
|
|
41
|
+
.attr('href', '#')
|
|
42
|
+
.data({
|
|
43
|
+
'key': key,
|
|
44
|
+
'flag_id': flagId
|
|
45
|
+
})
|
|
46
|
+
.text(actions[key]);
|
|
47
|
+
$actionContainer.append($action);
|
|
48
|
+
}, this);
|
|
49
|
+
return $flag;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
render (options) {
|
|
53
|
+
bindFlagDomEvents();
|
|
54
|
+
var _id = FLAGID_PREFIX + options.id;
|
|
55
|
+
var auiFlag = AJS.flag({
|
|
56
|
+
type: options.type,
|
|
57
|
+
title: options.title,
|
|
58
|
+
body: this._renderBody(options.body),
|
|
59
|
+
close: options.close
|
|
60
|
+
});
|
|
61
|
+
auiFlag.setAttribute('id', _id);
|
|
62
|
+
var $auiFlag = $(auiFlag);
|
|
63
|
+
this._renderActions($auiFlag, options.id, options.actions);
|
|
64
|
+
$auiFlag.addClass(FLAG_CLASS);
|
|
65
|
+
$auiFlag.close = auiFlag.close;
|
|
66
|
+
return $auiFlag;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
close (id) {
|
|
70
|
+
var f = document.getElementById(id);
|
|
71
|
+
f.close();
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
var FlagComponent = new Flag();
|
|
77
|
+
var flagDomEventsBound = false;
|
|
78
|
+
function bindFlagDomEvents(){
|
|
79
|
+
if(flagDomEventsBound) {
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
$(document).on('aui-flag-close', (e) => {
|
|
83
|
+
const _id = e.target.id;
|
|
84
|
+
var cleanFlagId = FlagComponent.cleanKey(_id);
|
|
85
|
+
FlagActions.closed(cleanFlagId);
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
$(document).on('click', '.' + FLAG_ACTION_CLASS, (e) => {
|
|
89
|
+
var $target = $(e.target);
|
|
90
|
+
var actionKey = $target.data('key');
|
|
91
|
+
var flagId = $target.data('flag_id');
|
|
92
|
+
FlagActions.actionInvoked(actionKey, flagId);
|
|
93
|
+
});
|
|
94
|
+
flagDomEventsBound = true;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
EventDispatcher.register('flag-close', (data) => {
|
|
99
|
+
FlagComponent.close(data.id);
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
export default FlagComponent;
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import EventDispatcher from '../dispatchers/event_dispatcher';
|
|
2
|
+
import IframeActions from '../actions/iframe_actions';
|
|
3
|
+
import $ from '../dollar';
|
|
4
|
+
import util from '../util';
|
|
5
|
+
import simpleXDM from 'simple-xdm/host';
|
|
6
|
+
import urlUtil from '../utils/url';
|
|
7
|
+
import JwtActions from '../actions/jwt_actions';
|
|
8
|
+
import iframeUtils from '../utils/iframe';
|
|
9
|
+
import simpleXdmUtils from '../utils/simplexdm';
|
|
10
|
+
import { Flags } from '../utils/feature-flag';
|
|
11
|
+
|
|
12
|
+
const CONTAINER_CLASSES = ['ap-container'];
|
|
13
|
+
|
|
14
|
+
class Iframe {
|
|
15
|
+
|
|
16
|
+
constructor () {
|
|
17
|
+
this._contentResolver = false;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
setContentResolver(callback) {
|
|
21
|
+
this._contentResolver = callback;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
resize(width, height, $el){
|
|
25
|
+
width = util.stringToDimension(width);
|
|
26
|
+
height = util.stringToDimension(height);
|
|
27
|
+
$el.css({
|
|
28
|
+
width: width,
|
|
29
|
+
height: height
|
|
30
|
+
});
|
|
31
|
+
$el.trigger('resized', {width: width, height: height});
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
simpleXdmExtension(extension, $container) {
|
|
35
|
+
if(!extension.url || (urlUtil.hasJwt(extension.url) && urlUtil.isJwtExpired(extension.url))){
|
|
36
|
+
if(this._contentResolver){
|
|
37
|
+
JwtActions.requestRefreshUrl({
|
|
38
|
+
extension: extension,
|
|
39
|
+
resolver: this._contentResolver,
|
|
40
|
+
$container: $container
|
|
41
|
+
});
|
|
42
|
+
} else {
|
|
43
|
+
console.error('JWT is expired and no content resolver was specified');
|
|
44
|
+
}
|
|
45
|
+
} else {
|
|
46
|
+
this._appendExtension($container, this._simpleXdmCreate(extension));
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
_simpleXdmCreate(extension){
|
|
51
|
+
var simpleXdmAttributes = simpleXdmUtils.createSimpleXdmExtension(extension);
|
|
52
|
+
extension.id = simpleXdmAttributes.iframeAttributes.id;
|
|
53
|
+
extension.$el = this.render(simpleXdmAttributes.iframeAttributes);
|
|
54
|
+
return extension;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
_appendExtension($container, extension){
|
|
58
|
+
var existingFrame = $container.find('iframe');
|
|
59
|
+
if(existingFrame.length > 0) {
|
|
60
|
+
existingFrame.destroy();
|
|
61
|
+
}
|
|
62
|
+
if (extension.options.hideIframeUntilLoad) {
|
|
63
|
+
extension.$el
|
|
64
|
+
.css({visibility: 'hidden'})
|
|
65
|
+
.load(() => {
|
|
66
|
+
extension.$el
|
|
67
|
+
.css({visibility: ''});
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
$container.prepend(extension.$el);
|
|
71
|
+
IframeActions.notifyIframeCreated(extension.$el, extension);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
_appendExtensionError($container, text, traceId) {
|
|
75
|
+
var $error = $('<div class="connect-resolve-error"></div>');
|
|
76
|
+
var $additionalText = $('<p />').text(text);
|
|
77
|
+
$error.append('<p class="error">Error: The content resolver threw the following error:</p>');
|
|
78
|
+
$error.append($additionalText);
|
|
79
|
+
|
|
80
|
+
if (Flags.getBooleanFeatureFlag('display_trace_for_confluence_top_errors') && traceId) {
|
|
81
|
+
$error.append(`<br><p class="error-trace-id">Trace: ${traceId}</p>`);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
$container.prepend($error);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
resolverResponse(data) {
|
|
88
|
+
var simpleExtension = this._simpleXdmCreate(data.extension);
|
|
89
|
+
this._appendExtension(data.$container, simpleExtension);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
resolverFailResponse(data) {
|
|
93
|
+
this._appendExtensionError(data.$container, data.errorText, data.errorTraceId);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
render(attributes){
|
|
97
|
+
attributes = attributes || {};
|
|
98
|
+
attributes.referrerpolicy = 'no-referrer';
|
|
99
|
+
return $('<iframe />').attr(attributes).addClass('ap-iframe');
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
var IframeComponent = new Iframe();
|
|
104
|
+
|
|
105
|
+
EventDispatcher.register('iframe-resize', function(data){
|
|
106
|
+
IframeComponent.resize(data.width, data.height, data.$el);
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
EventDispatcher.register('content-resolver-register-by-extension', function(data){
|
|
110
|
+
IframeComponent.setContentResolver(data.callback);
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
EventDispatcher.register('jwt-url-refreshed', function(data) {
|
|
114
|
+
IframeComponent.resolverResponse(data);
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
EventDispatcher.register('jwt-url-refreshed-failed', function(data) {
|
|
118
|
+
IframeComponent.resolverFailResponse(data);
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
EventDispatcher.register('after:iframe-bridge-established', function(data) {
|
|
123
|
+
if(!data.extension.options.noDom){
|
|
124
|
+
data.$el[0].bridgeEstablished = true;
|
|
125
|
+
} else {
|
|
126
|
+
data.extension.options.bridgeEstablished = true;
|
|
127
|
+
}
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
export default IframeComponent;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import $ from '../dollar';
|
|
2
|
+
import IframeComponent from './iframe';
|
|
3
|
+
import LoadingIndicatorComponent from './loading_indicator';
|
|
4
|
+
import EventDispatcher from '../dispatchers/event_dispatcher';
|
|
5
|
+
|
|
6
|
+
const CONTAINER_CLASSES = ['ap-iframe-container'];
|
|
7
|
+
|
|
8
|
+
class IframeContainer {
|
|
9
|
+
|
|
10
|
+
createExtension(extension, options) {
|
|
11
|
+
var $container = this._renderContainer();
|
|
12
|
+
if(!options || options.loadingIndicator !== false){
|
|
13
|
+
$container.append(this._renderLoadingIndicator());
|
|
14
|
+
}
|
|
15
|
+
IframeComponent.simpleXdmExtension(extension, $container);
|
|
16
|
+
return $container;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
_renderContainer(attributes){
|
|
20
|
+
var container = $('<div />').attr(attributes || {});
|
|
21
|
+
container.addClass(CONTAINER_CLASSES.join(' '));
|
|
22
|
+
return container;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
_renderLoadingIndicator(){
|
|
26
|
+
return LoadingIndicatorComponent.render();
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
var IframeContainerComponent = new IframeContainer();
|
|
32
|
+
|
|
33
|
+
EventDispatcher.register('iframe-create', (data) => {
|
|
34
|
+
var id = 'embedded-' + data.extension.id;
|
|
35
|
+
data.extension.$el.parents('.ap-iframe-container').attr('id', id);
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
export default IframeContainerComponent;
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import EventDispatcher from '../dispatchers/event_dispatcher';
|
|
2
|
+
import InlineDialogActions from '../actions/inline_dialog_actions';
|
|
3
|
+
import $ from '../dollar';
|
|
4
|
+
import util from '../util';
|
|
5
|
+
|
|
6
|
+
class InlineDialog {
|
|
7
|
+
|
|
8
|
+
resize(data){
|
|
9
|
+
var width = util.stringToDimension(data.width);
|
|
10
|
+
var height = util.stringToDimension(data.height);
|
|
11
|
+
var $content = data.$el.find('.contents');
|
|
12
|
+
if($content.length === 1){
|
|
13
|
+
$content.css({
|
|
14
|
+
width: width,
|
|
15
|
+
height: height
|
|
16
|
+
});
|
|
17
|
+
InlineDialogActions.refresh(data.$el);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
refresh($el){
|
|
22
|
+
if (!$el.is(':visible')) {
|
|
23
|
+
return
|
|
24
|
+
}
|
|
25
|
+
$el[0].popup.reset();
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
_getInlineDialog($el){
|
|
29
|
+
return AJS.InlineDialog($el);
|
|
30
|
+
}
|
|
31
|
+
_renderContainer(){
|
|
32
|
+
return $('<div />').addClass('aui-inline-dialog-contents');
|
|
33
|
+
}
|
|
34
|
+
_displayInlineDialog(data){
|
|
35
|
+
InlineDialogActions.created({
|
|
36
|
+
$el: data.$el,
|
|
37
|
+
trigger: data.trigger,
|
|
38
|
+
extension: data.extension
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
hideInlineDialog($el){
|
|
42
|
+
$el.hide();
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
closeInlineDialog(){
|
|
46
|
+
$('.aui-inline-dialog').filter(function(){
|
|
47
|
+
return $(this).find('.ap-iframe-container').length > 0;
|
|
48
|
+
}).hide();
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
render(data){
|
|
52
|
+
var $inlineDialog = $(document.getElementById('inline-dialog-' + data.id));
|
|
53
|
+
|
|
54
|
+
if ($inlineDialog.length !== 0) {
|
|
55
|
+
$inlineDialog.remove();
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
var $el = AJS.InlineDialog(
|
|
59
|
+
data.bindTo,
|
|
60
|
+
//assign unique id to inline Dialog
|
|
61
|
+
data.id,
|
|
62
|
+
($placeholder, trigger, showInlineDialog) => {
|
|
63
|
+
$placeholder.append(data.$content);
|
|
64
|
+
this._displayInlineDialog({
|
|
65
|
+
extension: data.extension,
|
|
66
|
+
$el: $placeholder,
|
|
67
|
+
trigger: trigger
|
|
68
|
+
});
|
|
69
|
+
showInlineDialog();
|
|
70
|
+
},
|
|
71
|
+
data.inlineDialogOptions
|
|
72
|
+
);
|
|
73
|
+
|
|
74
|
+
// Increase z-index so it shows above the Jira project sidebar
|
|
75
|
+
$el.css('z-index', 1000);
|
|
76
|
+
|
|
77
|
+
return $el;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
var InlineDialogComponent = new InlineDialog();
|
|
83
|
+
|
|
84
|
+
EventDispatcher.register('iframe-resize', function(data) {
|
|
85
|
+
var container = data.$el.parents('.aui-inline-dialog');
|
|
86
|
+
if(container.length === 1) {
|
|
87
|
+
InlineDialogComponent.resize({
|
|
88
|
+
width: data.width,
|
|
89
|
+
height: data.height,
|
|
90
|
+
$el: container
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
EventDispatcher.register('inline-dialog-refresh', function(data){
|
|
96
|
+
InlineDialogComponent.refresh(data.$el);
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
EventDispatcher.register('inline-dialog-hide', function(data) {
|
|
100
|
+
InlineDialogComponent.hideInlineDialog(data.$el);
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
EventDispatcher.register('inline-dialog-close', function(data) {
|
|
104
|
+
InlineDialogComponent.closeInlineDialog();
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
export default InlineDialogComponent;
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import WebItemActions from '../actions/webitem_actions';
|
|
2
|
+
import InlineDialogWebItemActions from '../actions/inline_dialog_webitem_actions';
|
|
3
|
+
import EventDispatcher from '../dispatchers/event_dispatcher';
|
|
4
|
+
import InlineDialogComponent from './inline_dialog';
|
|
5
|
+
import WebitemComponent from './webitem';
|
|
6
|
+
import WebItemUtils from '../utils/webitem';
|
|
7
|
+
import IframeContainer from './iframe_container';
|
|
8
|
+
import $ from '../dollar';
|
|
9
|
+
import IframeCreate from '../iframe-create';
|
|
10
|
+
import Util from '../util';
|
|
11
|
+
import urlUtils from '../utils/url';
|
|
12
|
+
import { getAccessNarrowingSpaceContext } from '../utils/access-narrowing-context';
|
|
13
|
+
|
|
14
|
+
const ITEM_NAME = 'inline-dialog';
|
|
15
|
+
const SELECTOR = '.ap-inline-dialog';
|
|
16
|
+
const WEBITEM_UID_KEY = 'inline-dialog-target-uid';
|
|
17
|
+
|
|
18
|
+
export class InlineDialogWebItem {
|
|
19
|
+
constructor(){
|
|
20
|
+
this._inlineDialogWebItemSpec = {
|
|
21
|
+
name: ITEM_NAME,
|
|
22
|
+
selector: SELECTOR,
|
|
23
|
+
triggers: ['mouseenter', 'click']
|
|
24
|
+
};
|
|
25
|
+
this._inlineDialogWebItems = {};
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
getWebItem(){
|
|
29
|
+
return this._inlineDialogWebItemSpec;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
_createInlineDialog(data){
|
|
33
|
+
var $inlineDialog = InlineDialogComponent.render({
|
|
34
|
+
extension: data.extension,
|
|
35
|
+
id: data.id,
|
|
36
|
+
bindTo: data.$target,
|
|
37
|
+
$content: $('<div />'),
|
|
38
|
+
inlineDialogOptions: data.extension.options
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
return $inlineDialog;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* @param {WebItemInvokedEventData} data
|
|
46
|
+
*/
|
|
47
|
+
triggered(data) {
|
|
48
|
+
// don't trigger on hover, when hover is not specified.
|
|
49
|
+
const eventType = data.eventType;
|
|
50
|
+
const onHover = data.extension.options.onHover;
|
|
51
|
+
if (eventType !== 'click' && !onHover) {
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
const $target = data.$target;
|
|
55
|
+
var webitemId = $target.data(WEBITEM_UID_KEY);
|
|
56
|
+
|
|
57
|
+
EventDispatcher.dispatch('analytics-inline-dialog-opened', {
|
|
58
|
+
extension: data.extension,
|
|
59
|
+
eventType: eventType,
|
|
60
|
+
onHover: onHover
|
|
61
|
+
})
|
|
62
|
+
|
|
63
|
+
if (eventType === 'click' && !onHover) {
|
|
64
|
+
if ($target.attr('data-inline-created') === 'true') {
|
|
65
|
+
// Let AUI handle the click event, otherwise we would destroy and recreate the dialog
|
|
66
|
+
// This will lead to the dialog being hidden immediately after it was opened
|
|
67
|
+
return;
|
|
68
|
+
} else {
|
|
69
|
+
// We have to handle the first click event to set up the dialog
|
|
70
|
+
// We set this property to ignore subsequent clicks and let AUI handle them
|
|
71
|
+
$target.attr('data-inline-created', 'true');
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
var $inlineDialog = this._createInlineDialog({
|
|
76
|
+
id: webitemId,
|
|
77
|
+
extension: data.extension,
|
|
78
|
+
$target: $target,
|
|
79
|
+
options: data.extension.options || {}
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
$inlineDialog.show();
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
opened(data){
|
|
86
|
+
var $existingFrame = data.$el.find('iframe');
|
|
87
|
+
var isExistingFrame = ($existingFrame && $existingFrame.length === 1);
|
|
88
|
+
// existing iframe is already present and src is still valid (either no jwt or jwt has not expired).
|
|
89
|
+
if(isExistingFrame){
|
|
90
|
+
const src = $existingFrame.attr('src');
|
|
91
|
+
const srcPresent = (src.length > 0);
|
|
92
|
+
if(srcPresent) {
|
|
93
|
+
const srcHasJWT = urlUtils.hasJwt(src);
|
|
94
|
+
const srcHasValidJWT = srcHasJWT && !urlUtils.isJwtExpired(src);
|
|
95
|
+
if(srcHasValidJWT || !srcHasJWT) {
|
|
96
|
+
return false;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
const dialogExtension = getAccessNarrowingSpaceContext(data.extension);
|
|
101
|
+
const contentRequest = WebitemComponent.requestContent(dialogExtension);
|
|
102
|
+
if(!contentRequest){
|
|
103
|
+
console.warn('no content resolver found');
|
|
104
|
+
return false;
|
|
105
|
+
}
|
|
106
|
+
contentRequest.then(function(content){
|
|
107
|
+
content.options = content.options || {};
|
|
108
|
+
Util.extend(content.options, {
|
|
109
|
+
autoresize: true,
|
|
110
|
+
widthinpx: true
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
InlineDialogWebItemActions.addExtension({
|
|
114
|
+
$el: data.$el,
|
|
115
|
+
extension: content
|
|
116
|
+
});
|
|
117
|
+
});
|
|
118
|
+
return true;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
addExtension(data){
|
|
122
|
+
var addon = IframeCreate(data.extension);
|
|
123
|
+
data.$el.empty().append(addon);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* @param {WebItemInvokedEventData} data
|
|
128
|
+
*/
|
|
129
|
+
createIfNotExists(data) {
|
|
130
|
+
const $target = data.$target;
|
|
131
|
+
var uid = $target.data(WEBITEM_UID_KEY);
|
|
132
|
+
|
|
133
|
+
if(!uid) {
|
|
134
|
+
uid = WebItemUtils.uniqueId();
|
|
135
|
+
$target.data(WEBITEM_UID_KEY, uid);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
let inlineDialogInstance = new InlineDialogWebItem();
|
|
142
|
+
let webitem = inlineDialogInstance.getWebItem();
|
|
143
|
+
EventDispatcher.register('before:webitem-invoked:' + webitem.name, function(data){
|
|
144
|
+
inlineDialogInstance.createIfNotExists(data);
|
|
145
|
+
});
|
|
146
|
+
EventDispatcher.register('webitem-invoked:' + webitem.name, function(data){
|
|
147
|
+
inlineDialogInstance.triggered(data);
|
|
148
|
+
});
|
|
149
|
+
EventDispatcher.register('inline-dialog-opened', function(data){
|
|
150
|
+
inlineDialogInstance.opened(data);
|
|
151
|
+
});
|
|
152
|
+
EventDispatcher.register('inline-dialog-extension', function(data){
|
|
153
|
+
inlineDialogInstance.addExtension(data);
|
|
154
|
+
});
|
|
155
|
+
WebItemActions.addWebItem(webitem);
|
|
156
|
+
|
|
157
|
+
export default inlineDialogInstance;
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import EventDispatcher from '../dispatchers/event_dispatcher';
|
|
2
|
+
import LoadingIndicatorActions from '../actions/loading_indicator_actions';
|
|
3
|
+
import $ from '../dollar';
|
|
4
|
+
|
|
5
|
+
const LOADING_INDICATOR_CLASS = 'ap-status-indicator';
|
|
6
|
+
|
|
7
|
+
const LOADING_STATUSES = {
|
|
8
|
+
loading: '<div class="ap-loading"><div class="small-spinner"></div>Loading app...</div>',
|
|
9
|
+
'load-timeout': '<div class="ap-load-timeout"><div class="small-spinner"></div>App is not responding. Wait or <a href="#" class="ap-btn-cancel">cancel</a>?</div>',
|
|
10
|
+
'load-error': 'App failed to load.'
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
const LOADING_TIMEOUT = 12000;
|
|
14
|
+
|
|
15
|
+
class LoadingIndicator {
|
|
16
|
+
constructor () {
|
|
17
|
+
this._stateRegistry = {};
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
_loadingContainer($iframeContainer){
|
|
21
|
+
return $iframeContainer.find('.' + LOADING_INDICATOR_CLASS);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
render() {
|
|
25
|
+
var container = document.createElement('div');
|
|
26
|
+
container.classList.add(LOADING_INDICATOR_CLASS);
|
|
27
|
+
container.innerHTML = LOADING_STATUSES.loading;
|
|
28
|
+
var $container = $(container);
|
|
29
|
+
this._startSpinner($container);
|
|
30
|
+
return $container;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
_startSpinner($container) {
|
|
34
|
+
// TODO: AUI or spin.js broke something. This is bad but ironically matches v3's implementation.
|
|
35
|
+
setTimeout(() => {
|
|
36
|
+
var spinner = $container.find('.small-spinner');
|
|
37
|
+
if (spinner.length && spinner.spin) {
|
|
38
|
+
spinner.spin({lines: 12, length: 3, width: 2, radius: 3, trail: 60, speed: 1.5, zIndex: 1});
|
|
39
|
+
}
|
|
40
|
+
}, 10);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
hide($iframeContainer, extensionId){
|
|
44
|
+
this._clearTimeout(extensionId);
|
|
45
|
+
this._loadingContainer($iframeContainer)[0].style.display = 'none';
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
cancelled($iframeContainer, extensionId){
|
|
49
|
+
var status = LOADING_STATUSES['load-error'];
|
|
50
|
+
this._loadingContainer($iframeContainer).empty().text(status);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
_setupTimeout($container, extension){
|
|
54
|
+
this._stateRegistry[extension.id] = setTimeout(() => {
|
|
55
|
+
LoadingIndicatorActions.timeout($container, extension);
|
|
56
|
+
}, LOADING_TIMEOUT);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
_clearTimeout(extensionId) {
|
|
60
|
+
if(this._stateRegistry[extensionId]) {
|
|
61
|
+
clearTimeout(this._stateRegistry[extensionId]);
|
|
62
|
+
delete this._stateRegistry[extensionId];
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
timeout($iframeContainer, extensionId){
|
|
67
|
+
var status = $(LOADING_STATUSES['load-timeout']);
|
|
68
|
+
var container = this._loadingContainer($iframeContainer);
|
|
69
|
+
container.empty().append(status);
|
|
70
|
+
this._startSpinner(container);
|
|
71
|
+
$('a.ap-btn-cancel', container).click(function () {
|
|
72
|
+
LoadingIndicatorActions.cancelled($iframeContainer, extensionId);
|
|
73
|
+
});
|
|
74
|
+
this._clearTimeout(extensionId);
|
|
75
|
+
return container;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
var LoadingComponent = new LoadingIndicator();
|
|
80
|
+
|
|
81
|
+
EventDispatcher.register('iframe-create', (data) => {
|
|
82
|
+
if(!data.extension.options.noDom) {
|
|
83
|
+
LoadingComponent._setupTimeout(data.$el.parents('.ap-iframe-container'), data.extension);
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
EventDispatcher.register('iframe-bridge-established', (data) => {
|
|
88
|
+
if(!data.extension.options.noDom) {
|
|
89
|
+
LoadingComponent.hide(data.$el.parents('.ap-iframe-container'), data.extension.id);
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
EventDispatcher.register('iframe-bridge-timeout', (data) => {
|
|
94
|
+
if(!data.extension.options.noDom) {
|
|
95
|
+
LoadingComponent.timeout(data.$el, data.extension.id);
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
EventDispatcher.register('iframe-bridge-cancelled', (data) => {
|
|
100
|
+
if(!data.extension.options.noDom) {
|
|
101
|
+
LoadingComponent.cancelled(data.$el, data.extension.id);
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
EventDispatcher.register('iframe-destroyed', function (data) {
|
|
106
|
+
LoadingComponent._clearTimeout(data.extension.extension_id);
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
export default LoadingComponent;
|