forked from rauchg/slackin
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit c75f8ce
Showing
23 changed files
with
2,821 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
node | ||
node_modules |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
.gitignore |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
|
||
6TO5 = ./node_modules/.bin/6to5 | ||
|
||
all: node | ||
|
||
node: lib | ||
@mkdir -p node/assets/ | ||
@rm -rf node/assets/* | ||
@cp -r lib/assets node/ | ||
@for path in lib/*.js; do \ | ||
file=`basename $$path`; \ | ||
$(6TO5) "lib/$$file" > "node/$$file"; \ | ||
done |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
|
||
# slackin | ||
|
||
A little server that enables public access | ||
to a Slack server. Like Freenode, but on Slack. | ||
|
||
It prompts users to join by emailing them an | ||
invite to your organization (all of it or just | ||
one guest channel) through the Slack API. | ||
|
||
You get: | ||
|
||
- A landing page you can point users to | ||
(`http://slack.yourdomain.com`) | ||
- An `<iframe>` badge to embed on any website | ||
that shows connected users in *realtime* with socket.io. | ||
- A SVG badge that works well from static mediums | ||
(like GitHub README pages) | ||
|
||
## How to use | ||
|
||
### Server | ||
|
||
`deploy to heroku button here` | ||
|
||
To launch it: | ||
|
||
```bash | ||
$ npm install -g slackin | ||
$ slackin --token "token" --org socketio | ||
``` | ||
|
||
The available options are: | ||
|
||
- `--port [port]` – What port to bind to (defaults to `3000`) | ||
- `--token [token]` (required) – API token for your org. Get it | ||
[here](https://api.slack.com/web). | ||
- `--org [org]` (required) – Organization subdomain (//**this**.slack.com) | ||
- `--channel [chan]` – If you want users to join *just one guest channel* | ||
within your organization, provide it. | ||
- `--silent` - If provided, no errors or warnings are printed out. | ||
|
||
### Realtime Badge | ||
|
||
[![](https://cldup.com/IaiPnDEAA6.gif)](http://slack.socket.io) | ||
|
||
```html | ||
<script async defer src="http://slackin.yourhost.com/slackin.js"></script> | ||
``` | ||
|
||
or for the large version, append `?large`: | ||
|
||
```html | ||
<script async defer src="http://slackin.yourhost.com/slackin.js?large"></script> | ||
``` | ||
|
||
### SVG | ||
|
||
[![](https://cldup.com/jWUT4QFLnq.png)](http://slack.socket.io) | ||
|
||
```html | ||
<img src="http://slackin.yourhost.com/badge.svg"> | ||
``` | ||
|
||
### Landing page | ||
|
||
[![](https://cldup.com/WIbawiqp0Q.png)](http://slack.socket.io) | ||
|
||
Point to `http://slackin.yourhost.com`. | ||
|
||
**Note:** the image for the logo of the landing page | ||
is retrieved from the Slack API. If your organization | ||
doesn't have one configured, it won't be shown. | ||
|
||
## API | ||
|
||
Requiring `slackin` as a module will return | ||
a `Function` that creates a `HTTP.Server` instance | ||
that you can manipulate. | ||
|
||
```js | ||
require('slackin')({ | ||
token: 'yourtoken', // required | ||
interval: 1000, | ||
org: 'your-slack-subdomain', // required | ||
channel: 'channel' // for single channel mode, | ||
silent: false // suppresses warnings | ||
}).listen(3000); | ||
``` | ||
|
||
This will show response times from Slack and how many | ||
online users you have on the console. | ||
|
||
By default logging is enabled. | ||
|
||
## Credits | ||
|
||
- The SVG badge generation was taken from the | ||
excellent [shields](https://github.com/badges/shields) project. | ||
- The button CSS is based on | ||
[github-buttons](https://github.com/mdo/github-buttons). | ||
|
||
## License | ||
|
||
MIT |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
#!/usr/bin/env node | ||
|
||
// es6 polyfills | ||
require('6to5/register'); | ||
|
||
var pkg = require('../package'); | ||
var program = require('commander'); | ||
var slackin = require('../node'); | ||
|
||
program | ||
.version(pkg.version) | ||
.option('-p, --port [port]', 'Port to listen on', 3000) | ||
.option('-t, --token [token]', 'Token (https://api.slack.com/web)') | ||
.option('-o, --org [org]', 'Organization subdomain ({xxx}.slack.com)') | ||
.option('-c, --channel [chan]', 'Invite users only to this channel') | ||
.option('-i, --interval [int]', 'How frequently we poll Slack', 1000) | ||
.option('-s, --silent', 'Do not print out warns or errors') | ||
.parse(process.argv); | ||
|
||
var port = program.port; | ||
slackin(program).listen(port, function(err){ | ||
if (err) throw err; | ||
if (!program.silent) console.log('%s – listening on *:%d', new Date, port); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,226 @@ | ||
(function(){ | ||
|
||
// give up and resort to `target=_blank` | ||
// if we're not modern enough | ||
if (!document.body.getBoundingClientRect | ||
|| !document.body.querySelectorAll | ||
|| !window.postMessage) { | ||
return; | ||
} | ||
|
||
// search for a script tag pointing to slackin.js | ||
function search(){ | ||
var replaced = 0; | ||
var scripts = document.querySelectorAll('script'); | ||
var script; | ||
for (var i = 0; i < scripts.length; i++) { | ||
script = scripts[i]; | ||
if (!script.src) continue; | ||
if (/\/slackin\.js(\?.*)?$/.test(script.src)) { | ||
// replace script with iframe | ||
replace(script); | ||
|
||
// we abort the search for subsequent | ||
// slackin.js executions to exhaust | ||
// the queue | ||
return true; | ||
} | ||
} | ||
} | ||
|
||
// replace the script tag with an iframe | ||
function replace(script){ | ||
var parent = script.parentNode; | ||
if (!parent) return; | ||
|
||
var large = /\?large/.test(script.src); | ||
var iframe = document.createElement('iframe'); | ||
var iframePath = '/iframe' + (large ? '?large' : ''); | ||
iframe.src = script.src.replace(/\/slackin\.js.*/, iframePath); | ||
iframe.style.borderWidth = 0; | ||
iframe.className = '__slackin'; | ||
|
||
// a decent aproximation that we adjust later | ||
// once we have the knowledge of the actual | ||
// numbers of users, based on a user count | ||
// of 3 digits by 3 digits | ||
iframe.style.width = (large ? 171 : 114) + 'px'; | ||
|
||
// height depends on target size | ||
iframe.style.height = (large ? 30 : 20) + 'px'; | ||
|
||
// hidden by default to avoid flicker | ||
iframe.style.visibility = 'hidden'; | ||
|
||
parent.insertBefore(iframe, script); | ||
parent.removeChild(script); | ||
|
||
// setup iframe RPC | ||
iframe.onload = function(){ | ||
setup(iframe); | ||
}; | ||
} | ||
|
||
// setup an "RPC" channel between iframe and us | ||
function setup(iframe){ | ||
var id = Math.random() * (1 << 24) | 0; | ||
iframe.contentWindow.postMessage('slackin:' + id, '*'); | ||
window.addEventListener('message', function(e){ | ||
// show dialog upon click | ||
if ('slackin-click:' + id == e.data) { | ||
showDialog(iframe); | ||
} | ||
|
||
// update width | ||
var wp = 'slackin-width:' + id + ':'; | ||
if (wp == e.data.substr(0, wp.length)) { | ||
var width = e.data.substr(wp.length); | ||
iframe.style.width = width + 'px'; | ||
|
||
// ensure it's shown (since first time hidden) | ||
iframe.style.visibility = 'visible'; | ||
} | ||
}); | ||
} | ||
|
||
// show the dialog around the iframe | ||
// by, yes, creating a new iframe | ||
var showing = false; | ||
function showDialog(iframe){ | ||
if (showing) return; | ||
showing = true; | ||
|
||
// container div | ||
var div = document.createElement('div'); | ||
div.className = '__slackin'; | ||
div.style.border = '1px solid #D6D6D6'; | ||
div.style.padding = '0'; | ||
div.style.margin = '0'; | ||
div.style.lineHeight = '0'; | ||
div.style.backgroundColor = '#FAFAFA'; | ||
div.style.width = '250px'; | ||
div.style.height = '124px'; | ||
div.style.position = 'absolute'; | ||
div.style.left = '-10000px'; | ||
div.style.borderRadius = '4px'; | ||
div.style.padding = '4px'; | ||
|
||
// new iframe | ||
var ni = document.createElement('iframe'); | ||
ni.className = '__slackin'; | ||
ni.style.width = '250px'; | ||
ni.style.height = '124px'; | ||
ni.style.borderWidth = 0; | ||
ni.src = iframe.src.replace(/\?.*/, '') + '/dialog'; | ||
ni.onload = function(){ | ||
window.addEventListener('scroll', dposition); | ||
window.addEventListener('resize', dposition); | ||
position(); | ||
}; | ||
|
||
// arrows | ||
var a1 = document.createElement('div'); | ||
var a2 = document.createElement('div'); | ||
[a1, a2].forEach(function(a){ | ||
a.style.border = 'solid transparent'; | ||
a.style.pointerEvents = 'none'; | ||
a.style.width = '0'; | ||
a.style.height = '0'; | ||
a.style.margin = '0'; | ||
a.style.padding = '0'; | ||
a.style.position = 'absolute'; | ||
a.style.display = 'inline'; | ||
}); | ||
|
||
a1.style.borderColor = 'rgba(214, 214, 214, 0)'; | ||
a2.style.borderColor = 'rgba(250, 250, 250, 0)'; | ||
|
||
a1.style.borderWidth = '7px'; | ||
a1.style.marginLeft = '-7px'; | ||
a2.style.borderWidth = '6px'; | ||
a2.style.marginLeft = '-6px'; | ||
|
||
// append | ||
div.appendChild(a1); | ||
div.appendChild(a2); | ||
div.appendChild(ni); | ||
document.body.appendChild(div); | ||
|
||
function position(){ | ||
[div, a1, a2].forEach(function(el){ | ||
el.style.left = ''; | ||
el.style.right = ''; | ||
el.style.bottom = ''; | ||
el.style.top = ''; | ||
}); | ||
|
||
var divPos = div.getBoundingClientRect(); | ||
var iframePos = iframe.getBoundingClientRect(); | ||
var divHeight = divPos.height + 9; // arrow height | ||
|
||
var st = document.body.scrollTop; | ||
var sl = document.body.scrollLeft; | ||
var iw = window.innerWidth; | ||
var ih = window.innerHeight; | ||
|
||
// position vertically / arrows | ||
if (iframePos.bottom + divHeight > st + ih) { | ||
div.style.top = (iframePos.top - divHeight) + 'px'; | ||
a1.style.top = a2.style.top = '100%'; | ||
|
||
a1.style.borderBottomColor = 'rgba(214, 214, 214, 0)'; | ||
a2.style.borderBottomColor = 'rgba(250, 250, 250, 0)'; | ||
a1.style.borderTopColor = '#d6d6d6'; | ||
a2.style.borderTopColor = '#fafafa'; | ||
} else { | ||
div.style.top = (iframePos.top + iframePos.height + 9) + 'px'; | ||
a1.style.bottom = a2.style.bottom = '100%'; | ||
|
||
a1.style.borderTopColor = 'rgba(214, 214, 214, 0)'; | ||
a2.style.borderTopColor = 'rgba(250, 250, 250, 0)'; | ||
a1.style.borderBottomColor = '#d6d6d6'; | ||
a2.style.borderBottomColor = '#fafafa'; | ||
} | ||
|
||
// position horizontally | ||
var left = iframePos.left | ||
+ Math.round(iframePos.width / 2) | ||
- Math.round(divPos.width / 2); | ||
if (left < sl) left = sl; | ||
if (left + divPos.width > sl + iw) { | ||
left = sl + iw - divPos.width; | ||
} | ||
div.style.left = left + 'px'; | ||
|
||
a1.style.left = | ||
a2.style.left = (iframePos.left - left + Math.round(iframePos.width / 2)) + 'px'; | ||
} | ||
|
||
// debounced positionining | ||
var timer; | ||
function dposition(){ | ||
clearTimeout(timer); | ||
timer = setTimeout(position, 100); | ||
} | ||
|
||
function hide(){ | ||
showing = false; | ||
window.removeEventListener('scroll', dposition); | ||
window.removeEventListener('resize', dposition); | ||
document.body.removeChild(div); | ||
document.documentElement.removeEventListener('click', click, true); | ||
} | ||
|
||
function click(ev){ | ||
if ('__slackin' != ev.target.className) { | ||
hide(); | ||
} | ||
} | ||
|
||
document.documentElement.addEventListener('click', click, true); | ||
} | ||
|
||
var found = search(); | ||
if (!found) setTimeout(search, 5000); | ||
|
||
})(); |
Oops, something went wrong.