Skip to content

Commit

Permalink
Merge pull request #89 from OneSignal/http-modal-prompt
Browse files Browse the repository at this point in the history
Http modal prompt
  • Loading branch information
Jason Pang committed Jul 8, 2016
2 parents 12618fd + 43abe3a commit dc32b3e
Show file tree
Hide file tree
Showing 16 changed files with 737 additions and 111 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "onesignal-web-sdk",
"version": "1.2.0",
"sdkVersion": "109550",
"sdkVersion": "109600",
"description": "Web push notifications from OneSignal.",
"main": "src/entry.js",
"dependencies": {
Expand Down
176 changes: 140 additions & 36 deletions src/OneSignal.js

Large diffs are not rendered by default.

File renamed without changes
6 changes: 2 additions & 4 deletions src/bell/ActiveAnimatedElement.js
Original file line number Diff line number Diff line change
Expand Up @@ -120,9 +120,8 @@ export default class ActiveAnimatedElement extends AnimatedElement {
if (this.active)
return Promise.resolve(this);
else return new Promise((resolve) => {
once(window, ActiveAnimatedElement.EVENTS.ACTIVE, (event, destroyListenerFn) => {
OneSignal.once(ActiveAnimatedElement.EVENTS.ACTIVE, (event) => {
if (event === this) {
destroyListenerFn();
return resolve(this);
}
}, true);
Expand All @@ -137,9 +136,8 @@ export default class ActiveAnimatedElement extends AnimatedElement {
if (this.inactive)
return Promise.resolve(this);
else return new Promise((resolve) => {
once(window, ActiveAnimatedElement.EVENTS.INACTIVE, (event, destroyListenerFn) => {
OneSignal.once(ActiveAnimatedElement.EVENTS.INACTIVE, (event) => {
if (event === this) {
destroyListenerFn();
return resolve(this);
}
}, true);
Expand Down
6 changes: 2 additions & 4 deletions src/bell/AnimatedElement.js
Original file line number Diff line number Diff line change
Expand Up @@ -105,10 +105,9 @@ export default class AnimatedElement {
if (this.state === 'shown')
return Promise.resolve(this);
else return new Promise((resolve) => {
once(window, AnimatedElement.EVENTS.SHOWN, (event, destroyListenerFn) => {
OneSignal.once(AnimatedElement.EVENTS.SHOWN, (event) => {
var self = this;
if (event === this) {
destroyListenerFn();
return resolve(this);
}
}, true);
Expand All @@ -123,9 +122,8 @@ export default class AnimatedElement {
if (this.state === 'hidden')
return Promise.resolve(this);
else return new Promise((resolve) => {
once(window, AnimatedElement.EVENTS.HIDDEN, (event, destroyListenerFn) => {
OneSignal.once(AnimatedElement.EVENTS.HIDDEN, (event) => {
if (event === this) {
destroyListenerFn();
return resolve(this);
}
}, true);
Expand Down
28 changes: 1 addition & 27 deletions src/bell/Dialog.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import Event from '../events.js';
import AnimatedElement from './AnimatedElement.js';
import * as Browser from 'bowser';
import Bell from './bell.js';
import Helpers from '../helpers';
import { HOST_URL } from '../vars.js';


Expand All @@ -25,33 +26,6 @@ export default class Dialog extends AnimatedElement {
});
}

getNotificationIcons() {
return OneSignal.getAppId()
.then(appId => {
if (!appId) {
return Promise.reject(null);
} else {
let url = `${OneSignal._API_URL}apps/${appId}/icon`;
return url;
}
}, () => {
log.debug('No app ID, not getting notification icon for notify button.');
return;
})
.then(url => fetch(url))
.then(response => response.json())
.then(data => {
if (data.errors) {
log.error(`API call %c${url}`, getConsoleStyle('code'), 'failed with:', data.errors);
reject(null);
}
return data;
})
.catch(function (ex) {
log.error('Call %cgetNotificationIcons()', getConsoleStyle('code'), 'failed with:', ex);
})
}

getPlatformNotificationIcon() {
if (this.notificationIcons) {
if (Browser.chrome || Browser.firefox) {
Expand Down
1 change: 0 additions & 1 deletion src/bell/Launcher.js
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,6 @@ export default class Launcher extends ActiveAnimatedElement {
if (this.bell.badge.content.length > 0) {
return this.bell.badge.hide()
.then(() => Promise.all([super.activate(), this.resize(this.bell.options.size)]))
.then(() => this.bell.badge.show())
.catch((e) => log.error(e))
}
else {
Expand Down
29 changes: 19 additions & 10 deletions src/bell/bell.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,15 @@ import * as Browser from 'bowser';
import { HOST_URL } from '../vars.js';
import AnimatedElement from './AnimatedElement.js';
import ActiveAnimatedElement from './ActiveAnimatedElement.js';
import Helpers from '../helpers';
import Launcher from './Launcher.js';
import Badge from './Badge.js';
import Button from './Button.js';
import Dialog from './Dialog.js';
import Message from './Message.js';

import "./bell.scss";
var logoSvg = require('raw!./bell.svg');
var logoSvg = require('raw!./../assets/bell.svg');


export default class Bell {
Expand Down Expand Up @@ -286,7 +287,7 @@ export default class Bell {
this.badge.hide();
}
if (this.dialog.notificationIcons === null) {
this.dialog.getNotificationIcons().then((icons) => {
Helpers.getNotificationIcons().then((icons) => {
this.dialog.notificationIcons = icons;
});
}
Expand Down Expand Up @@ -354,7 +355,7 @@ export default class Bell {

// Remove any existing bell
if (this.container) {
removeDomElement('onesignal-bell-container');
removeDomElement('#onesignal-bell-container');
}

window.addDomElement = addDomElement;
Expand All @@ -378,12 +379,11 @@ export default class Bell {
// Add visual elements
addDomElement(this.button.selector, 'beforeEnd', logoSvg);

new Promise(resolve => {
OneSignal.isPushNotificationsEnabled((isPushEnabled) => {
resolve(isPushEnabled)
});
})
.then(isPushEnabled => {
Promise.all([
OneSignal.isPushNotificationsEnabled(),
OneSignal.getSubscription()
])
.then(([isPushEnabled, notOptedOut]) => {
// Resize to small instead of specified size if enabled, otherwise there's a jerking motion where the bell, at a different size than small, jerks sideways to go from large -> small or medium -> small
let resizeTo = (isPushEnabled ? 'small' : this.options.size);
// Add default classes
Expand Down Expand Up @@ -419,7 +419,16 @@ export default class Bell {
(isPushEnabled ? this.launcher.inactivate() : nothing())
.then(() => delay(this.options.showLauncherAfter))
.then(() => {
return this.launcher.show();
if (OneSignal.isUsingSubscriptionWorkaround() &&
notOptedOut &&
!isPushEnabled &&
(OneSignal.config.autoRegister === true) &&
!Helpers.isHttpPromptAlreadyShown()) {
log.debug('Not showing notify button because popover will be shown.');
return nothing();
} else {
return this.launcher.show();
}
})
.then(() => {
return delay(this.options.showBadgeAfter);
Expand Down
7 changes: 5 additions & 2 deletions src/environment.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,16 @@ export default class Environment {
else {
// If the window is the root top-most level
if (window === window.top) {
if (contains(location.href, "initOneSignal"))
if (contains(location.href, "initOneSignal") ||
(location.pathname === '/subscribe' && location.search === ''))
return Environment.POPUP;
else
return Environment.HOST;
}
else
else if (location.pathname === '/webPushIframe' ||
location.pathname === '/webPushModal') {
return Environment.IFRAME;
}
}
}

Expand Down
3 changes: 2 additions & 1 deletion src/events.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@ const RETRIGGER_REMOTE_EVENTS = [
'dbSet',
'register',
'notificationDisplay',
'notificationDismiss'
'notificationDismiss',
'permissionPromptDisplayed'
];

const LEGACY_EVENT_MAP = {
Expand Down
129 changes: 107 additions & 22 deletions src/helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,21 @@ export default class Helpers {
}
}

/**
* Stores a flag in sessionStorage that we've already shown the HTTP popover to this user and that we should not
* show it again until they open a new window or tab to the site.
*/
static markHttpPopoverShown() {
sessionStorage.setItem("ONESIGNAL_HTTP_PROMPT_SHOWN", true);
}

/**
* Returns true if the HTTP popover was already shown inside the same session.
*/
static isHttpPromptAlreadyShown() {
return sessionStorage.getItem("ONESIGNAL_HTTP_PROMPT_SHOWN") == "true";
}

/**
* Returns true if this current window session is continuing and not a newly opened tab or window.
*/
Expand Down Expand Up @@ -143,7 +158,7 @@ export default class Helpers {
}

if (OneSignal._thisIsThePopup) {
// 12/16/2015 -- At this point, the user has just clicked Allow on the HTTP prompt!!
// 12/16/2015 -- At this point, the user has just clicked Allow on the HTTP popup!!
OneSignal.getNotificationPermission()
.then((permission) => {
log.debug("Sending player Id and registrationId back to host page");
Expand Down Expand Up @@ -223,6 +238,33 @@ export default class Helpers {
});
}

static getNotificationIcons() {
return OneSignal.getAppId()
.then(appId => {
if (!appId) {
return Promise.reject(null);
} else {
let url = `${OneSignal._API_URL}apps/${appId}/icon`;
return url;
}
}, () => {
log.debug('No app ID, not getting notification icon for notify button.');
return;
})
.then(url => fetch(url))
.then(response => response.json())
.then(data => {
if (data.errors) {
log.error(`API call %c${url}`, getConsoleStyle('code'), 'failed with:', data.errors);
reject(null);
}
return data;
})
.catch(function (ex) {
log.error('Call %cgetNotificationIcons()', getConsoleStyle('code'), 'failed with:', ex);
})
}

static establishServiceWorkerChannel(serviceWorkerRegistration) {
if (OneSignal._channel) {
OneSignal._channel.off('data');
Expand Down Expand Up @@ -256,30 +298,53 @@ export default class Helpers {
}

static getPromptOptionsQueryString() {
var message_localization_opts = OneSignal.config['promptOptions'];
var message_localization_opts_str = '';
if (message_localization_opts) {
var message_localization_params = [
let promptOptions = OneSignal.config['promptOptions'];
let promptOptionsStr = '';
if (promptOptions) {
let hash = Helpers.getPromptOptionsPostHash();
for (let key of Object.keys(hash)) {
var value = hash[key];
promptOptionsStr += '&' + key + '=' + value;
}
}
return promptOptionsStr;
}

static getPromptOptionsPostHash() {
let promptOptions = OneSignal.config['promptOptions'];
if (promptOptions) {
var legacyParams = {
'exampleNotificationTitleDesktop': 'exampleNotificationTitle',
'exampleNotificationMessageDesktop': 'exampleNotificationMessage',
'exampleNotificationTitleMobile': 'exampleNotificationTitle',
'exampleNotificationMessageMobile': 'exampleNotificationMessage',
};
for (let legacyParamKey of Object.keys(legacyParams)) {
let legacyParamValue = legacyParams[legacyParamKey];
if (promptOptions[legacyParamKey]) {
promptOptions[legacyParamValue] = promptOptions[legacyParamKey];
}
}
var allowedPromptOptions = [
'siteName',
'actionMessage',
'exampleNotificationTitleDesktop',
'exampleNotificationMessageDesktop',
'exampleNotificationTitleMobile',
'exampleNotificationMessageMobile',
'exampleNotificationTitle',
'exampleNotificationMessage',
'exampleNotificationCaption',
'acceptButtonText',
'cancelButtonText',
'showCredit'];
for (var i = 0; i < message_localization_params.length; i++) {
var key = message_localization_params[i];
var value = message_localization_opts[key];
'cancelButtonText'
];
var hash = {};
for (var i = 0; i < allowedPromptOptions.length; i++) {
var key = allowedPromptOptions[i];
var value = promptOptions[key];
var encoded_value = encodeURIComponent(value);
if (value || value === false || value === '') {
message_localization_opts_str += '&' + key + '=' + encoded_value;
hash[key] = encoded_value;
}
}
}
return message_localization_opts_str;
return hash;
}

static triggerCustomPromptClicked(clickResult) {
Expand All @@ -288,10 +353,6 @@ export default class Helpers {
});
}

static saveAppId() {

}

static autoCorrectSubdomain(inputSubdomain) {
let normalizedSubdomain = Helpers.getNormalizedSubdomain(inputSubdomain);
if (normalizedSubdomain !== inputSubdomain) {
Expand Down Expand Up @@ -330,7 +391,15 @@ export default class Helpers {
return iframe;
}

static openSubdomainPopup(url) {
// Arguments :
// verb : 'GET'|'POST'
// target : an optional opening target (a name, or "_blank"), defaults to "_self"
static openWindowViaPost(url, data) {
var form = document.createElement("form");
form.action = url;
form.method = 'POST';
form.target = "onesignal-http-popup";

var dualScreenLeft = window.screenLeft != undefined ? window.screenLeft : screen.left;
var dualScreenTop = window.screenTop != undefined ? window.screenTop : screen.top;
var thisWidth = window.innerWidth ? window.innerWidth : document.documentElement.clientWidth ? document.documentElement.clientWidth : screen.width;
Expand All @@ -339,6 +408,22 @@ export default class Helpers {
var childHeight = OneSignal._windowHeight;
var left = ((thisWidth / 2) - (childWidth / 2)) + dualScreenLeft;
var top = ((thisHeight / 2) - (childHeight / 2)) + dualScreenTop;
return window.open(url, "_blank", `'scrollbars=yes, width=${childWidth}, height=${childHeight}, top=${top}, left=${left}`);
window.open('about:blank', "onesignal-http-popup", `'scrollbars=yes, width=${childWidth}, height=${childHeight}, top=${top}, left=${left}`);

if (data) {
for (var key in data) {
var input = document.createElement("textarea");
input.name = key;
input.value = typeof data[key] === "object" ? JSON.stringify(data[key]) : data[key];
form.appendChild(input);
}
}
form.style.display = 'none';
document.body.appendChild(form);
form.submit();
};

static openSubdomainPopup(url, data) {
Helpers.openWindowViaPost(url, data);
}
}

0 comments on commit dc32b3e

Please sign in to comment.