@tapni/auth 0.0.170 → 0.0.172
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/README.md +2 -0
- package/dist/.vite/manifest.json +18 -10
- package/dist/.well-known/assetlinks.json +10 -12
- package/dist/.well-known/microsoft-identity-association.json +5 -5
- package/dist/{Account-6F9eRo1R.js → Account-BVGvxZ85.js} +31 -32
- package/dist/{QR-2Izy5Dj4.js → QR-DwjajyG2.js} +3 -3
- package/dist/TapniAuth.es.js +1 -1
- package/dist/TapniAuth.umd.js +9 -9
- package/dist/blank.html +31 -0
- package/dist/{install-co2F1hxN.js → install-B8fBS6C4.js} +752 -996
- package/dist/site.webmanifest +11 -1
- package/dist/style.css +1 -1
- package/dist/{web-NrPZl3qD.js → web-XbruGdlD.js} +2 -5
- package/package.json +64 -55
- package/src/.prettierrc.json +16 -0
- package/src/App.vue +249 -265
- package/src/components/Language.vue +66 -143
- package/src/components/LinkIcon.vue +174 -225
- package/src/components/ModalOverlay.vue +47 -50
- package/src/components/OTP.vue +64 -94
- package/src/components/SSO.vue +80 -111
- package/src/components/SSOPick.vue +93 -148
- package/src/eslint.config.js +15 -0
- package/src/install.js +9 -10
- package/src/main.js +54 -57
- package/src/mixins/apple.mixin.js +56 -54
- package/src/mixins/auth.mixin.js +21 -74
- package/src/mixins/facebook.mixin.js +67 -66
- package/src/mixins/global.mixin.js +107 -109
- package/src/mixins/google.mixin.js +53 -54
- package/src/mixins/mfa-auth.mixin.js +68 -68
- package/src/mixins/microsoft.mixin.js +67 -75
- package/src/mixins/okta.mixin.js +50 -57
- package/src/mixins/qr-auth.mixin.js +111 -107
- package/src/mixins/saml.mixin.js +97 -48
- package/src/router/index.js +6 -6
- package/src/routes.js +60 -66
- package/src/services/Api.js +55 -57
- package/src/services/AuthService.js +75 -75
- package/src/services/CompanyService.js +10 -10
- package/src/services/DeviceService.js +3 -3
- package/src/services/UserService.js +45 -45
- package/src/services/UtilService.js +256 -218
- package/src/store/auth.js +471 -543
- package/src/store/constants.js +1 -1
- package/src/store/event-bus.js +22 -22
- package/src/store/locales/cn.js +442 -458
- package/src/store/locales/de.js +438 -517
- package/src/store/locales/en.js +449 -510
- package/src/store/locales/es.js +442 -524
- package/src/store/locales/fr.js +442 -516
- package/src/store/locales/it.js +442 -514
- package/src/store/locales/kr.js +442 -491
- package/src/store/locales/lang.js +43 -43
- package/src/store/locales/sr.js +439 -492
- package/src/store/locales/tr.js +436 -487
- package/src/store/store.js +6 -6
- package/src/views/Account.vue +169 -207
- package/src/views/Callback.vue +36 -33
- package/src/views/Login.vue +220 -392
- package/src/views/MFA.vue +89 -103
- package/src/views/QR.vue +25 -28
- package/src/views/Register.vue +201 -205
- package/src/views/Reset.vue +132 -135
- package/src/views/Verify.vue +153 -151
- package/src/views/Welcome.vue +61 -60
- /package/dist/{web-L3jORB19.js → web-AXRKjAOB.js} +0 -0
- /package/dist/{web-5VtGcKeU.js → web-IFGkBi0t.js} +0 -0
- /package/dist/{web-AImUTDQQ.js → web-LIfHmYL2.js} +0 -0
package/src/store/store.js
CHANGED
package/src/views/Account.vue
CHANGED
|
@@ -1,239 +1,201 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
<h4>{{ssoLang[appLanguage].change_language }}</h4>
|
|
110
|
-
</div>
|
|
111
|
-
<div class="right">
|
|
112
|
-
<img
|
|
113
|
-
src="https://cdn.tapni.co/icons/newArrowRight.svg"
|
|
114
|
-
/>
|
|
115
|
-
</div>
|
|
116
|
-
</div>
|
|
117
|
-
|
|
118
|
-
<div class="divider"></div>
|
|
119
|
-
|
|
120
|
-
<div class="device" @click="logoutAccount">
|
|
121
|
-
<div class="left">
|
|
122
|
-
<img
|
|
123
|
-
src="https://cdn.tapni.co/icons/newLogout.svg"
|
|
124
|
-
style="width: 50px; border-radius: 20px"
|
|
125
|
-
/>
|
|
126
|
-
</div>
|
|
127
|
-
<div class="middle">
|
|
128
|
-
<h4>{{ssoLang[appLanguage].logout }}</h4>
|
|
129
|
-
</div>
|
|
130
|
-
<div class="right">
|
|
131
|
-
<img
|
|
132
|
-
src="https://cdn.tapni.co/icons/newArrowRight.svg"
|
|
133
|
-
/>
|
|
134
|
-
</div>
|
|
135
|
-
</div>
|
|
136
|
-
|
|
137
|
-
<!-- Additional items can be added here in the future -->
|
|
138
|
-
<div v-if="false" class="moreFooter">
|
|
139
|
-
<p class="app-version" style="margin-top: 10px">
|
|
140
|
-
{{ssoLang[appLanguage].version }}: {{ appVersion }}
|
|
141
|
-
</p>
|
|
142
|
-
<h4 v-if="false">{{ssoLang[appLanguage].terms_and_privacy }}</h4>
|
|
143
|
-
</div>
|
|
144
|
-
</div>
|
|
145
|
-
</div>
|
|
146
|
-
</div>
|
|
2
|
+
<div class="page-login content-boxed content-boxed-padding center-text" style="margin-top: -1px; overflow: hidden; border: solid 0px #ffffff">
|
|
3
|
+
<br />
|
|
4
|
+
<h1 class="bold full-top no-bottom center-text">{{ ssoLang[appLanguage].welcome }}</h1>
|
|
5
|
+
<p class="full-bottom half-top center-text color-black font-16">{{ account.email }}</p>
|
|
6
|
+
|
|
7
|
+
<div v-if="display !== 'npm' && false" class="full-top full-bottom">
|
|
8
|
+
<a @click="continueTo('app')" class="button-center button button-90 google-button bg-tapni-grey pointer">
|
|
9
|
+
<span> {{ ssoLang[appLanguage].continue }} </span>
|
|
10
|
+
</a>
|
|
11
|
+
|
|
12
|
+
<div class="page-login-links center-text">
|
|
13
|
+
<a @click="continueTo('admin')"
|
|
14
|
+
>Looking for Admin Dashboard? <b>{{ ssoLang[appLanguage].click_here }}</b></a
|
|
15
|
+
>
|
|
16
|
+
<div class="clear"></div>
|
|
17
|
+
</div>
|
|
18
|
+
</div>
|
|
19
|
+
|
|
20
|
+
<div class="container">
|
|
21
|
+
<div v-if="false" class="accountCard pointer" @click="expanded = !expanded">
|
|
22
|
+
<div class="activeAccount">
|
|
23
|
+
<div class="left" v-if="$storex.username">
|
|
24
|
+
<img :src="loggedInAccounts[$storex.username]?.photo" :alt="loggedInAccounts[$storex.username]?.name" style="width: 50px; border-radius: 20px" />
|
|
25
|
+
</div>
|
|
26
|
+
<div class="middle" v-if="$storex.username">
|
|
27
|
+
<h4>{{ loggedInAccounts[$storex.username]?.name }}</h4>
|
|
28
|
+
<div>@{{ $storex.username }}</div>
|
|
29
|
+
</div>
|
|
30
|
+
<div class="right" v-show="addAccountReady">
|
|
31
|
+
<img src="https://cdn.tapni.co/icons/newArrowRight.svg" alt="Right arrow" :style="{ transform: expanded ? 'rotate(90deg)' : '' }" />
|
|
32
|
+
</div>
|
|
33
|
+
</div>
|
|
34
|
+
<div class="otherAccounts" v-if="expanded && loggedInAccounts">
|
|
35
|
+
<template v-for="(username, index) in Object.keys(loggedInAccounts)">
|
|
36
|
+
<div class="activeAccount" :key="index" v-if="username !== $storex.username" @click="switchAccount(username)">
|
|
37
|
+
<div class="left">
|
|
38
|
+
<img :src="loggedInAccounts[username].photo" :alt="loggedInAccounts[username].name" style="width: 50px; border-radius: 20px" />
|
|
39
|
+
</div>
|
|
40
|
+
<div class="middle">
|
|
41
|
+
<h4>{{ loggedInAccounts[username].name }}</h4>
|
|
42
|
+
<div>@ {{ username }}</div>
|
|
43
|
+
</div>
|
|
44
|
+
</div>
|
|
45
|
+
</template>
|
|
46
|
+
<div class="activeAccount newAccount" @click="addAccount">
|
|
47
|
+
<div class="left">
|
|
48
|
+
<img src="https://cdn.tapni.co/icons/Add.png" style="width: 50px; border-radius: 20px" />
|
|
49
|
+
</div>
|
|
50
|
+
<div class="middle">
|
|
51
|
+
<h4>{{ ssoLang[appLanguage].add_account }}</h4>
|
|
52
|
+
</div>
|
|
53
|
+
<div class="right">
|
|
54
|
+
<img src="https://cdn.tapni.co/icons/Plus.png" width="30px" />
|
|
55
|
+
</div>
|
|
56
|
+
</div>
|
|
57
|
+
</div>
|
|
58
|
+
</div>
|
|
59
|
+
|
|
60
|
+
<div class="settingsCard pointer left-text">
|
|
61
|
+
<div class="device" @click="toggleAccountSettingsModal">
|
|
62
|
+
<div class="left">
|
|
63
|
+
<img src="https://cdn.tapni.co/icons/newSettings.svg" style="width: 50px; border-radius: 20px" />
|
|
64
|
+
</div>
|
|
65
|
+
<div class="middle">
|
|
66
|
+
<h4>{{ ssoLang[appLanguage].mfa }}</h4>
|
|
67
|
+
</div>
|
|
68
|
+
<div class="right">
|
|
69
|
+
<img src="https://cdn.tapni.co/icons/newArrowRight.svg" />
|
|
70
|
+
</div>
|
|
71
|
+
</div>
|
|
72
|
+
|
|
73
|
+
<div class="divider"></div>
|
|
74
|
+
|
|
75
|
+
<div class="device" @click="toggleLanguageModal">
|
|
76
|
+
<div class="left">
|
|
77
|
+
<img src="https://cdn.tapni.co/icons/newPublicProfile.svg" style="width: 50px; border-radius: 20px" />
|
|
78
|
+
</div>
|
|
79
|
+
<div class="middle">
|
|
80
|
+
<h4>{{ ssoLang[appLanguage].change_language }}</h4>
|
|
81
|
+
</div>
|
|
82
|
+
<div class="right">
|
|
83
|
+
<img src="https://cdn.tapni.co/icons/newArrowRight.svg" />
|
|
84
|
+
</div>
|
|
85
|
+
</div>
|
|
86
|
+
|
|
87
|
+
<div class="divider"></div>
|
|
88
|
+
|
|
89
|
+
<div class="device" @click="logoutAccount">
|
|
90
|
+
<div class="left">
|
|
91
|
+
<img src="https://cdn.tapni.co/icons/newLogout.svg" style="width: 50px; border-radius: 20px" />
|
|
92
|
+
</div>
|
|
93
|
+
<div class="middle">
|
|
94
|
+
<h4>{{ ssoLang[appLanguage].logout }}</h4>
|
|
95
|
+
</div>
|
|
96
|
+
<div class="right">
|
|
97
|
+
<img src="https://cdn.tapni.co/icons/newArrowRight.svg" />
|
|
98
|
+
</div>
|
|
99
|
+
</div>
|
|
100
|
+
|
|
101
|
+
<!-- Additional items can be added here in the future -->
|
|
102
|
+
<div v-if="false" class="moreFooter">
|
|
103
|
+
<p class="app-version" style="margin-top: 10px">{{ ssoLang[appLanguage].version }}: {{ appVersion }}</p>
|
|
104
|
+
<h4 v-if="false">{{ ssoLang[appLanguage].terms_and_privacy }}</h4>
|
|
105
|
+
</div>
|
|
106
|
+
</div>
|
|
107
|
+
</div>
|
|
108
|
+
</div>
|
|
147
109
|
</template>
|
|
148
110
|
|
|
149
111
|
<script>
|
|
150
|
-
import AuthMixin from
|
|
151
|
-
import { EventBus } from
|
|
152
|
-
import AuthService from
|
|
112
|
+
import AuthMixin from '../mixins/auth.mixin';
|
|
113
|
+
import { EventBus } from '../store/event-bus.js';
|
|
114
|
+
import AuthService from '../services/AuthService.js';
|
|
153
115
|
export default {
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
116
|
+
mixins: [AuthMixin],
|
|
117
|
+
data() {
|
|
118
|
+
return {
|
|
119
|
+
expanded: false,
|
|
120
|
+
addAccountReady: false,
|
|
121
|
+
appVersion: import.meta.env.APP_VERSION
|
|
122
|
+
};
|
|
123
|
+
},
|
|
124
|
+
async mounted() {
|
|
125
|
+
if (!this.isLoggedIn) {
|
|
126
|
+
return this.$router.push('/');
|
|
127
|
+
}
|
|
128
|
+
this.getAccountSettings();
|
|
129
|
+
},
|
|
130
|
+
methods: {
|
|
131
|
+
continueTo(realm) {
|
|
132
|
+
console.log('continue to ' + realm);
|
|
133
|
+
},
|
|
134
|
+
addAccount() {
|
|
135
|
+
this.$router.push('/login');
|
|
136
|
+
},
|
|
137
|
+
switchAccount(username) {
|
|
138
|
+
console.log('switch', username);
|
|
139
|
+
},
|
|
140
|
+
toggleAccountSettingsModal() {
|
|
141
|
+
this.$router.push('/mfa');
|
|
142
|
+
// EventBus.$emit('toggleAccountSettingsModal')
|
|
143
|
+
},
|
|
144
|
+
toggleLanguageModal() {
|
|
145
|
+
EventBus.$emit('toggleSSOLanguageModal');
|
|
146
|
+
},
|
|
147
|
+
logoutAccount() {
|
|
148
|
+
this.logout({ refreshToken: this.refreshTokens[0], sendRequest: true });
|
|
149
|
+
}
|
|
150
|
+
}
|
|
189
151
|
};
|
|
190
152
|
</script>
|
|
191
153
|
|
|
192
154
|
<style scoped>
|
|
193
155
|
.container {
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
156
|
+
padding: 20px !important;
|
|
157
|
+
display: flex;
|
|
158
|
+
flex-direction: column;
|
|
159
|
+
gap: 20px;
|
|
160
|
+
padding-bottom: 100px !important;
|
|
199
161
|
}
|
|
200
162
|
.settingsCard {
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
163
|
+
background-color: white;
|
|
164
|
+
padding: 20px;
|
|
165
|
+
border-radius: 26px;
|
|
166
|
+
align-items: center;
|
|
205
167
|
}
|
|
206
168
|
|
|
207
169
|
.device {
|
|
208
|
-
|
|
209
|
-
|
|
170
|
+
display: flex;
|
|
171
|
+
align-items: center;
|
|
210
172
|
}
|
|
211
173
|
|
|
212
174
|
h4 {
|
|
213
|
-
|
|
214
|
-
|
|
175
|
+
margin-left: 20px;
|
|
176
|
+
font-weight: bold;
|
|
215
177
|
}
|
|
216
178
|
|
|
217
179
|
.middle {
|
|
218
|
-
|
|
180
|
+
flex: 1;
|
|
219
181
|
}
|
|
220
182
|
|
|
221
183
|
.left img {
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
184
|
+
background-color: #f7f8f9;
|
|
185
|
+
border-radius: 20px;
|
|
186
|
+
padding: 10px;
|
|
225
187
|
}
|
|
226
188
|
|
|
227
189
|
.divider {
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
190
|
+
height: 1px;
|
|
191
|
+
background-color: #f0f0f0;
|
|
192
|
+
margin: 20px 0;
|
|
231
193
|
}
|
|
232
194
|
|
|
233
195
|
.moreFooter {
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
196
|
+
display: flex;
|
|
197
|
+
align-items: center;
|
|
198
|
+
justify-content: space-between;
|
|
199
|
+
padding: 0 10px;
|
|
238
200
|
}
|
|
239
201
|
</style>
|
package/src/views/Callback.vue
CHANGED
|
@@ -1,46 +1,49 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
2
|
+
<div class="page-login content-boxed content-boxed-padding">
|
|
3
|
+
<h5 v-if="($route.query.platform === 'android' || $route.query.platform === 'ios') && !isNative" style="text-align: center; width: 80%; margin: 0 auto; margin-top: 260px">
|
|
4
|
+
{{ ssoLang[this.appLanguage].you_will_be_redirected }}<br />
|
|
5
|
+
{{ ssoLang[this.appLanguage].if_redirect_not_directly }}, <span @click="inAppRedirect" style="color: blue; cursor: pointer">{{ ssoLang[this.appLanguage].click_here }}</span
|
|
6
|
+
>.
|
|
7
|
+
</h5>
|
|
8
|
+
<h4 v-else style="text-align: center; width: 80%; margin: 0 auto; margin-top: 260px">{{ ssoLang[this.appLanguage].please_wait }}</h4>
|
|
9
|
+
</div>
|
|
8
10
|
</template>
|
|
9
11
|
|
|
10
12
|
<script>
|
|
11
13
|
/* eslint-disable */
|
|
12
|
-
import OktaMixin from
|
|
13
|
-
import SamlMixin from
|
|
14
|
-
import AuthMixin from
|
|
14
|
+
import OktaMixin from '../mixins/okta.mixin';
|
|
15
|
+
import SamlMixin from '../mixins/saml.mixin';
|
|
16
|
+
import AuthMixin from '../mixins/auth.mixin';
|
|
15
17
|
import { sanitizeUrl } from '@braintree/sanitize-url';
|
|
16
18
|
export default {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
+
name: 'AuthCallback',
|
|
20
|
+
mixins: [OktaMixin, SamlMixin, AuthMixin],
|
|
19
21
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
+
data() {
|
|
23
|
+
return {};
|
|
24
|
+
},
|
|
22
25
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
async mounted() {
|
|
27
|
-
if(this.$route.path === '/callback/auth') {
|
|
28
|
-
this.exchangeAuthCode({
|
|
29
|
-
code: this.$route.query.code
|
|
30
|
-
})
|
|
31
|
-
}
|
|
32
|
-
if(this.$route.path === '/callback/okta') return await this.handleOktaRedirect();
|
|
33
|
-
if(this.$route.path === '/callback/saml') return await this.handleSamlRedirect();
|
|
34
|
-
},
|
|
35
|
-
methods: {
|
|
36
|
-
inAppRedirect() {
|
|
37
|
-
let url = sanitizeUrl(location.href);
|
|
38
|
-
url = url.replace('http', 'tapni')
|
|
39
|
-
url = url.replace('https', 'tapni')
|
|
40
|
-
return window.open(url);
|
|
26
|
+
async mounted() {
|
|
27
|
+
if (this.$route.path === '/callback/redirect') {
|
|
28
|
+
return location.href = atob(this.$route.query.uri);
|
|
41
29
|
}
|
|
42
|
-
|
|
43
|
-
|
|
30
|
+
if (this.$route.path === '/callback/auth') {
|
|
31
|
+
this.exchangeAuthCode({
|
|
32
|
+
code: this.$route.query.code,
|
|
33
|
+
code_verifier: this.$route.query.code_verifier
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
if (this.$route.path === '/callback/okta') return await this.handleOktaRedirect();
|
|
37
|
+
if (this.$route.path === '/callback/saml') return await this.handleSamlRedirect();
|
|
38
|
+
},
|
|
39
|
+
methods: {
|
|
40
|
+
inAppRedirect() {
|
|
41
|
+
let url = sanitizeUrl(location.href);
|
|
42
|
+
url = url.replace('http', 'tapni');
|
|
43
|
+
url = url.replace('https', 'tapni');
|
|
44
|
+
return window.open(url);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
44
47
|
};
|
|
45
48
|
</script>
|
|
46
49
|
|