Commit 91d3e54e authored by Eric Eastwood's avatar Eric Eastwood

Add events, Use `es6-promise` - v0.2.4

Thank you @malditogeek for `es6-promise` library suggestion:
https://github.com/gitterHQ/sidecar/tree/es6-promise - Thank you to
@suprememoocow for the feedback on the API.
parent 779948d7
# v0.2.4 - 2015-9-1
- Emit `gitter-sidecar-ready` event on `document` when the script has loaded: `document.addEventListener('gitter-sidecar-ready', function(e) { var Chat = e.detail.Chat; var chat = new Chat(/*opts*/); });`
- Emit `gitter-sidecar-instance-started` event on `document` after a Sidecar chat instance is initialized: `document.addEventListener('gitter-sidecar-instance-started', function(e) { var chat = e.detail.chat; chat.toggleChat(true); });`
- Emit `gitter-chat-started` event on container after a Sidecar chat instance is initialized: `document.querySelector('.gitter-chat-embed').addEventListener('gitter-chat-started', function(e) { var chat = e.detail.chat; chat.toggleChat(true); });`
- Use [`es6-promise`](https://www.npmjs.com/package/es6-promise) instead of [`bluebird`](https://github.com/petkaantonov/bluebird) for the sake of file size
- Stop using `bling.js` for DOM manipulation. Now using `dom-utility.js` which is fully encapsulated from the `window` world.
# v0.2.3 - 2015-8-31
- `options.preload` defaults to `false`. Instead, we load the iframe after the "Open Chat" button is clicked and the aside is slid into place. This is to avoid the unnecessary strain to the Gitter servers for people who never click the open chat button, etc.
- Add `.is-loading` state for when the iframe hasn't embedded yet but we are working on it. We don't add the iframe exactly on click because that causes jank in the slide in animation.
# v0.2.2 - 2015-8-27
- `options.room` defaults to `undefined` and will throw an error if no room is specified
- Using a custom PostCSS plugin and [`postcss-plugin-context`](https://github.com/postcss/postcss-plugin-context) to add `box-sizing: border-box;` to each rule: `@context border-box { /* ... */ }
- Use `<a>` element as the default generated activation element so that if the JS fails to execute, we still have it link through to the actual room.
# v0.2.1 - 2015-8-20
- Update basic example(cosmetic)
......
......@@ -2,7 +2,7 @@
Gitter embed widget
# Latest version: 0.2.3
# Latest version: 0.2.4
### [Changelog](https://github.com/gitterHQ/sidecar/blob/master/CHANGELOG.md)
......@@ -25,7 +25,7 @@ Set options with the global window option:
```html
<script>
((window.___gitter = {}).chat = {}).options = {
((window.gitter = {}).chat = {}).options = {
room: 'gitterHQ/gitter'
};
</script>
......@@ -60,9 +60,9 @@ You can also override these options individually on the container:
You can set any of the chat options above in this object as well
- `window.___gitter.chat.options.disableDefaultChat`: Stop the default chat from just loading on the page when including the Sidecar script. *So you can handle the Gitter chat creation yourself.*
- `window.gitter.chat.options.disableDefaultChat`: Stop the default chat from just loading on the page when including the Sidecar script. *So you can handle the Gitter chat creation yourself.*
The default chat is stored on `window.___gitter.chat.defaultChat`.
The default chat is stored on `window.gitter.chat.defaultChat`.
# API
......@@ -71,7 +71,7 @@ The default chat is stored on `window.___gitter.chat.defaultChat`.
```js
var chat = new window.___gitter.Chat(/* options */);`
var chat = new window.gitter.Chat(/* options */);`
```
- `toggleChat(isChatOpen)`: Function/method - Takes a boolean which toggles the visibility of the chat panel
......@@ -80,8 +80,19 @@ var chat = new window.___gitter.Chat(/* options */);`
## Events
Emitted on Document:
- `gitter-sidecar-ready`: Emitted when the sidecar script has loaded and is available via `window.gitter`
- `gitter-sidecar-instance-started`: Emitted after any Sidecar chat instance has initialized
- Data: `chat`: The sidecar chat instance that was initialized
Emitted on Container:
- `gitter-chat-toggle`: Emitted whenever the chat is opened or closed
- Data: `state`: Whether it was opened(true) or closed(false)
- `gitter-chat-started`: Emitted after the Sidecar chat instance has initialized
- Data: `chat`: The sidecar chat instance that was initialized
*example:*
......
This diff is collapsed.
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -70,7 +70,7 @@
<aside class="sidebar"></aside>
<script>
((window.___gitter = {}).chat = {}).options = {
((window.gitter = {}).chat = {}).options = {
container: '.sidebar',
showChatByDefault: false
};
......
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Sidecar Basic Example</title>
<meta charset="UTF-8">
<title>Sidecar Basic Example</title>
<style>
html,
body {
padding: 0;
margin: 0;
}
html {
width: 100%;
height: 100%;
box-sizing: border-box;
}
body {
width: 100%;
height: 100%;
min-width: 100%;
min-height: 100%;
}
*,
*:before,
*:after {
box-sizing: inherit;
}
body {
overflow: hidden;
font-family: Arial, sans-serif;
}
iframe {
width: 100%;
height: 100%;
border: 0;
}
</style>
<link href="../common.css" rel="stylesheet">
</head>
<body>
<iframe src="http://marionettejs.com/"></iframe>
<script>
((window.___gitter = {}).chat = {}).options = {
room: 'marionettejs/backbone.marionette'
};
</script>
<script src="../../dist/sidecar.js" async defer></script>
<iframe src="http://marionettejs.com/"></iframe>
<script>
((window.gitter = {}).chat = {}).options = {
room: 'marionettejs/backbone.marionette'
};
</script>
<script src="../../dist/sidecar.js" async defer></script>
</body>
</html>
......
html,
body {
padding: 0;
margin: 0;
}
html {
width: 100%;
height: 100%;
box-sizing: border-box;
}
body {
width: 100%;
height: 100%;
min-width: 100%;
min-height: 100%;
}
*,
*:before,
*:after {
box-sizing: inherit;
}
body {
overflow: hidden;
font-family: Arial, sans-serif;
}
iframe {
width: 100%;
height: 100%;
border: 0;
}
......@@ -70,7 +70,7 @@
<aside class="sidebar"></aside>
<script>
((window.___gitter = {}).chat = {}).options = {
((window.gitter = {}).chat = {}).options = {
container: '.sidebar'
};
</script>
......
{
"name": "gitter-sidecar",
"version": "0.2.3",
"version": "0.2.4",
"description": "",
"main": "index.js",
"scripts": {
"gulp": "babel-node gulpfile.js",
"build-standalone": "webpack",
"build-standalone": "webpack -p",
"build-standalone-dev": "webpack --watch --progress"
},
"author": "",
......@@ -26,7 +26,7 @@
"webpack": "^1.10.5"
},
"dependencies": {
"bluebird": "^2.9.34",
"es6-promise": "^3.0.2",
"object-assign": "^3.0.0"
}
}
@context border-box {
.gitter-hidden {
display: none;
}
.gitter-icon {
width: 24px;
height: 24px;
fill: currentColor;
}
/*
* States:
* `.is-collapsed`
* `.is-loading`
*/
.gitter-chat-embed {
--background-color: #ffffff;
z-index: 100;
position: fixed;
top: 0;
left: 60%;
bottom: 0;
right: 0;
display: flex;
flex-direction: row;
background-color: var(--background-color);
border-left: 1px solid #333;
box-shadow: -12px 0 18px 0 rgba(50, 50, 50, 0.3);
transition: transform 0.3s cubic-bezier(0.16, 0.22, 0.22, 1.7);
.gitter-hidden {
display: none;
}
.gitter-icon {
width: 24px;
height: 24px;
fill: currentColor;
}
/*
* States:
* `.is-collapsed`
* `.is-loading`
*/
.gitter-chat-embed {
--background-color: #ffffff;
z-index: 100;
position: fixed;
top: 0;
left: 60%;
bottom: 0;
right: 0;
display: flex;
flex-direction: row;
background-color: var(--background-color);
border-left: 1px solid #333;
box-shadow: -12px 0 18px 0 rgba(50, 50, 50, 0.3);
transition: transform 0.3s cubic-bezier(0.16, 0.22, 0.22, 1.7);
&.is-collapsed:not(.is-loading) {
transform: translateX(110%);
}
&.is-collapsed:not(.is-loading) {
transform: translateX(110%);
}
/* Add some "extension" so that there isn't a gap
* when we translate(via animation) more than 100% */
&:after {
content: '';
/* Add some "extension" so that there isn't a gap
* when we translate(via animation) more than 100% */
&:after {
content: '';
z-index: -1;
position: absolute;
top: 0;
left: 100%;
bottom: 0;
right: -100%;
z-index: -1;
position: absolute;
top: 0;
left: 100%;
bottom: 0;
right: -100%;
background-color: var(--background-color);
}
background-color: var(--background-color);
}
& > iframe {
flex: 1;
width: 100%;
height: 100%;
& > iframe {
flex: 1;
width: 100%;
height: 100%;
border: 0;
}
border: 0;
}
}
}
.gitter-chat-embed-loading-wrapper {
position: absolute;
top: 0;
left: 0;
bottom: 0;
right: 0;
display: none;
/* main axis */
justify-content: center;
/* cross axis */
align-items: center;
.is-loading & {
display: flex;
}
}
.gitter-chat-embed-loading-wrapper {
position: absolute;
top: 0;
left: 0;
bottom: 0;
right: 0;
display: none;
/* main axis */
justify-content: center;
/* cross axis */
align-items: center;
.is-loading & {
display: flex;
}
}
.gitter-chat-embed-loading-indicator {
color: rgba(0, 0, 0, 0.75);
animation: spin 2s infinite linear;
}
@keyframes spin {
from {
transform: rotate(0deg);
}
to {
transform: rotate(359.9deg);
}
}
.gitter-chat-embed-action-bar {
position: absolute;
top: 0;
right: 0;
.gitter-chat-embed-loading-indicator {
color: rgba(0, 0, 0, 0.75);
animation: spin 2s infinite linear;
}
@keyframes spin {
from {
transform: rotate(0deg);
}
to {
transform: rotate(359.9deg);
}
}
.gitter-chat-embed-action-bar {
position: absolute;
top: 0;
right: 0;
display: flex;
display: flex;
color: #3a3133;
color: rgba(58, 49, 51, 0.65);
&:hover {
color: rgba(58, 49, 51, 1);
}
}
color: #3a3133;
color: rgba(58, 49, 51, 0.65);
&:hover {
color: rgba(58, 49, 51, 1);
}
}
.gitter-chat-embed-action-bar-item {
flex: 1;
display: flex;
/* main axis */
justify-content: center;
/* cross axis */
align-items: center;
.gitter-chat-embed-action-bar-item {
flex: 1;
display: flex;
/* main axis */
justify-content: center;
/* cross axis */
align-items: center;
width: 100%;
width: 100%;
padding: 8px 16px;
padding: 8px 16px;
background: rgba(255, 255, 255, 0.5);
border: 0;
background: rgba(255, 255, 255, 0.5);
border: 0;
color: inherit;
font-size: 48px;
font-weight: bold;
color: inherit;
font-size: 48px;
font-weight: bold;
cursor: pointer;
cursor: hand;
cursor: pointer;
cursor: hand;
transition: all 0.2s ease;
transition: all 0.2s ease;
&:hover,
&:focus {
outline: none;
box-shadow: inset 0 32px 32px -32px rgba(0, 0, 0, 0.25);
}
&:hover,
&:focus {
outline: none;
box-shadow: inset 0 32px 32px -32px rgba(0, 0, 0, 0.25);
}
&:active {
box-shadow: inset 0 32px 72px -32px rgba(0, 0, 0, 0.25);
&:active {
box-shadow: inset 0 32px 72px -32px rgba(0, 0, 0, 0.25);
color: #f68d42;
}
color: #f68d42;
}
}
}
.gitter-open-chat-button {
z-index: 100;
position: fixed;
bottom: 0;
right: 10px;
padding: 1em 3em;
background-color: #36bc98;
border: 0;
border-top-left-radius: 0.5em;
border-top-right-radius: 0.5em;
color: #ffffff;
text-align: center;
text-decoration: none;
.gitter-open-chat-button {
z-index: 100;
position: fixed;
bottom: 0;
right: 10px;
padding: 1em 3em;
background-color: #36bc98;
border: 0;
border-top-left-radius: 0.5em;
border-top-right-radius: 0.5em;
color: #ffffff;
text-align: center;
text-decoration: none;
cursor: pointer;
cursor: hand;
transition:
transform 0.3s ease,
background-color 0.3s ease;
cursor: pointer;
cursor: hand;
transition:
transform 0.3s ease,
background-color 0.3s ease;
&:hover,
&:focus {
background-color: #3ea07f;
}
&:focus {
box-shadow: 0 0 8px rgba(62, 160, 127, 0.6);
&:hover,
&:focus {
background-color: #3ea07f;
}
&:focus {
box-shadow: 0 0 8px rgba(62, 160, 127, 0.6);
outline: none;
}
outline: none;
}
&.is-collapsed {
transform: translateY(120%);
}
&.is-collapsed {
transform: translateY(120%);
}
}
}
}
\ No newline at end of file
......@@ -3,28 +3,41 @@ import objectAssign from 'object-assign';
import Chat from './lib/chat.js';
let getOrDefaultKey = function(obj, key) {
return obj[key] || (function() {
obj[key] = {};
return obj[key];
})();
return obj[key] || (function() {
obj[key] = {};
return obj[key];
})();
};
let windowGitter = getOrDefaultKey(window, '___gitter');
if(!((windowGitter.chat || {}).options || {}).disableDefaultChat) {
let windowGitterChat = getOrDefaultKey(windowGitter, 'chat');
windowGitterChat.defaultChat = new Chat(windowGitterChat.options || {});
}
let windowGitter = getOrDefaultKey(window, 'gitter');
let sidecar = {
Chat
Chat
};
// Plop it on the window
// Plop it on the `window`
objectAssign(windowGitter, sidecar);
// Tell them that `sidecar` is loaded and ready
let event = new CustomEvent('gitter-sidecar-ready', {
detail: sidecar
});
document.dispatchEvent(event);
if(!((windowGitter.chat || {}).options || {}).disableDefaultChat) {
let windowGitterChat = getOrDefaultKey(windowGitter, 'chat');
windowGitterChat.defaultChat = new Chat(windowGitterChat.options || {});
}
export default sidecar;
let $ = document.querySelectorAll.bind(document);
Node.prototype.on = window.on = function(names, fn) {
names.split(/\s/).forEach(function(name) {
this.addEventListener(name, fn);
}.bind(this));
// Keep the chaining going
return this;
};
HTMLCollection.prototype.__proto__ = Array.prototype;
NodeList.prototype.__proto__ = Array.prototype;
NodeList.prototype.on = NodeList.prototype.addEventListener = function(name, fn) {
this.forEach(function(elem) {
elem.on(name, fn);
});
// Keep the chaining going
return this;
};
export default $;
import objectAssign from 'object-assign';
import Promise from 'bluebird';
import {Promise} from 'es6-promise';
import $ from './bling.js';
import ElementStore from './element-store.js';
import chatCss from '../css/chat.css';
import { default as $ } from './dom-utility.js';
import * as domUtility from './dom-utility.js';
// This will concat anything including array-like things(like NodeLists)
let concat = function(...args) {
return args.reduce(function(result, item) {
// If array-like
if(item && item.length && !Array.isArray(item)) {
item = Array.prototype.slice.call(item);
}
return result.concat(item);
}, []);
};
// Pass in a selector string, dom node, or array of dom nodes
let coerceIntoElementsArray = function(stuff) {
let elements = [];
if(typeof stuff === 'string') {
elements = $(stuff);
}
else {
elements = concat(stuff);
}
return elements;
};
const gitterUrl = 'https://gitter.im/';
// Pass in a shape object of options and the element
......@@ -60,8 +40,8 @@ let getDataOptionsFromElement = function(options, element) {
const spacebarKey = 32;
const enterKey = 13;
let elementOnActivate = function(elements, cb) {
elements = coerceIntoElementsArray(elements);
NodeList.prototype.on.call(elements, 'click keydown', function(e, ...args) {
elements = domUtility.coerceIntoElementsArray(elements);
domUtility.on(elements, 'click keydown', function(e, ...args) {
// If click or spacebar, or enter is pressed
if(e.type === 'click' || (e.type === 'keydown' && (e.keyCode === spacebarKey || e.keyCode === enterKey))) {
cb.call(this, e, ...args);
......@@ -102,7 +82,7 @@ let embedGitterSvgSprites = function() {
let tempContainer = document.createElement('div');
tempContainer.insertAdjacentHTML('beforeend', gitterSvgSprites);
let body = $('body')[0];
tempContainer.children.forEach(function(child) {
domUtility.forEach(tempContainer.children, function(child) {
body.appendChild(child);
elementStore