Initial commit.

This commit is contained in:
zeekay
2015-07-20 00:17:36 -07:00
commit a407be410e
10 changed files with 592 additions and 0 deletions
+4
View File
@@ -0,0 +1,4 @@
node_modules
lib/
phantomjsdriver.log
selenium-server-standalone-2.45.0.jar
+1
View File
@@ -0,0 +1 @@
src
+22
View File
@@ -0,0 +1,22 @@
before-install:
- export TRAVIS_COMMIT_MSG="$(git log --format=%B --no-merges -n 1)"
env:
global:
- secure: nmJKkHXADOoPQfEjaGo+oN0aJ9ysJ9phVp4cW0RgceM+MnwXduUdaFIc3hrP2RhdJhxj1yji+8dm5Cr0vr4HvKZs21Ng4dHX+x2KTCFaxKX4qh+Xr7KA4dTToLMGit6liKJtO9OMk8O0co0NK7RVUMfaIH8+C5M6O1G1ysuy3gMchtFG2Lnmi0FKGeLKuenKLk1Wgb8EiYH4l9OanyV3NQ4Ea2/l3r0XgYjaWHvEu+Fr9q4IdS7a+c2AwztDJmvs3rAnaG2yTeyquOWyTCRVNi5yMm9/xnocOz7i1dqW7MSFU1NPUUPaYZGwPnVIjYoDTgtkR0S80Zpm4qqLtr/Qv9A0MfWi+3ftqZtAE9jjxhrMe4bEFVK1iBnE+xGpwrIrAQv4nevoM7OK6RJ/8rqvdfLD8sNOLsyXTlwILIXluMbZX93kpdVl9tcyUkOCeeoGzSY/i74Y+gnHtKozioeP6BX/O3Ov+V+NRqtaXxPCrEUk7QW1UTk5R1lNtJQHipr5Nze2QjEbbGaOYKU0kFkynlFvRvoXw2hZfdMAUIjKmqBA5UxARYWXve2UNRPcFHrfNiESpV0L4fHxqpHGPp0UGuirzwgKYJWIJId+7vd3e5rGS+JtBRiwfx4H/1H8tjKE4XLTIORXRJLWVrBDEbkf7Z5XYyyohLMd2XH+YlEw6kk=
- secure: CAMnRWopXQ8ews94NsseBgeV/x2nTVPa5IGCf4mgNAPd8F7ASrBGLegs9wzzX78fMMpZZqG10uA6B5x4X0lloId1qtBqbGn8fB6j038550EtJ39r79PmtUliVYqPKPO9EehjzyrC2RldiZhln16QRfuc0xBqYnyq6psVNWYDOO6Se3HrIAHwzc8BcQN8MbkncnB91vPBG/WF8ynBrQblw+GzQ7lbuvtrZT86ZGf1qk1mrGeUBXMRUG0P/XnMqonceSOnj4FETCJI6x2yslNfO93qvpAdsYbt+117m/ASkV9UaXWZr7kVbm7/5xknF3P/uKK+e4fOUSEUMcw7Tvg5mTTJGmCp4wkYiQYdN0bp6Gs6NqVbG1lYe9q5NVYA6vw28lQ2jQmYqIyP+09NnnP5Qilu7z4CuePWQGjxec+pHpsc/FyhD+VocnGmg4zJwWR50Bmxzg6rlMwzqFU6CHIMjz6kJxNMVVIJFGg4LcVSPzKP6+gKFGj346LJZ5vV3D1s9BkZ1pL0O0cvUXPOhUDkC7hPjJYNMFIO06XTmQhnHuM3YucgBTv6dIyIAHMFEW2k3rUfqIX3x1vC1QYHvTJfWIF16EmgSMbzUtNFjDM0vdoEykzIRmyHeVdBw922wviX9gkEWbBqcKeMPvmnY7ZdbHyn1NSotN8RFR2hazq72Oc=
addons:
sauce_connect: true
language: node_js
node_js:
- 0.12
script: |
./node_modules/.bin/shortcake test-ci
cache:
directories:
- node_modules
notifications:
email:
on_success: change
on_failure: always
slack:
secure: YMxrTGLhS9bCst3ItaDDJEwQLTxuRE8njyD/+Z4phNBNoYbmmKi0Y8mlfT4TfDvntIhQ0a2O2HrHSmS8J73lxrrDDc+UDiSQwDyiBiSfXyBed4ZUN9k5aAylGZS2DwLuBaq+tVDseJvQUgWhce3OeuW1q/3E7WgqxsO5N1nNabN8X6IVzjIvqpmweRosnrF26NMiFiglOI/M2Ux1M190lpNmL+x55kchAwl2FK8PA/7fFoMalduAOtcbCXIeKwXAJD2EdiY5hSUJQgdyc8UQCncJBusU5tPW0plKq9of5w5dn5Aqwi/MgfNFLGzULrLiRSjZGH1eOb4+MY04n9/kPf2wJfdvf5JPKMDRwBKRGht+QVwpmU8dlbQzPPTyaLbaIdJYxsBTLlR8Tz9xOgG3sYLki9i1ae+01MFzlf02Y6e+t3KYkzNd7yT5waE+ZVDRe9A/+3JQGw5T8G5UPAt4DfXdIAnI3yPCzxCPMghXXpSFxjAJKAk8MpHsW6TXYVkn6TGPVCUfMclwlM4CxkjvvYjdwKSW4Vg09TIyV04qZy97rFDwhH+nH4nv7cQNbawuZVgF4tMjvkyVma76EUMSg565/uBwsjuOfW/gj6F9Ggb/7wymnqvu3kUbxGLikW/pigJpnytbMnvlH9sFhfgljzB7n//MCr5762ltsYnnhp0=
+79
View File
@@ -0,0 +1,79 @@
exec = require('shortcake').exec
option '-b', '--browser [browserName]', 'browser to test with'
option '-g', '--grep [filter]', 'test filter'
option '-v', '--version [<newversion> | major | minor | patch | build]', 'new version'
task 'clean', 'clean project', (options) ->
exec 'rm -rf lib'
exec 'rm -rf .test'
task 'build', 'build project', (options) ->
exec 'node_modules/.bin/coffee -bcm -o lib/ src/'
exec 'node_modules/.bin/coffee -bcm -o .test/ test/'
task 'watch', 'watch for changes and recompile project', ->
exec 'node_modules/.bin/coffee -bcmw -o lib/ src/'
exec 'node_modules/.bin/coffee -bcmw -o .test test/'
task 'publish', 'publish project', (options) ->
newVersion = options.version ? 'patch'
exec """
git push
npm version #{newVersion}
npm publish
""".split '\n'
task 'static-server', 'Run static server for tests', ->
connect = require 'connect'
server = connect()
server.use (require 'serve-static') './test'
server.listen process.env.PORT ? 3333
task 'selenium-install', 'Install selenium standalone', ->
exec 'node_modules/.bin/selenium-standalone install'
task 'test', 'Run tests', (options) ->
browserName = options.browser ? 'phantomjs'
invoke 'static-server'
selenium = require 'selenium-standalone'
selenium.start (err, child) ->
throw err if err?
exec "NODE_ENV=test
BROWSER=#{browserName}
node_modules/.bin/mocha
--compilers coffee:coffee-script/register
--reporter spec
--colors
--timeout 60000
test/test.coffee", (err) ->
child.kill()
process.exit 1 if err?
process.exit 0
task 'test-ci', 'Run tests on CI server', ->
invoke 'static-server'
browsers = require './test/ci-config'
tests = for {browserName, platform, version, deviceName, deviceOrientation} in browsers
"NODE_ENV=test
BROWSER=\"#{browserName}\"
PLATFORM=\"#{platform}\"
VERSION=\"#{version}\"
DEVICE_NAME=\"#{deviceName ? ''}\"
DEVICE_ORIENTATION=\"#{deviceOrientation ? ''}\"
node_modules/.bin/mocha
--compilers coffee:coffee-script/register
--reporter spec
--colors
--timeout 60000
test/test.coffee"
exec tests, (err) ->
process.exit 1 if err?
process.exit 0
+2
View File
@@ -0,0 +1,2 @@
# inform
A contact/newsletter form library.
+41
View File
@@ -0,0 +1,41 @@
{
"name": "inform",
"version": "0.0.1",
"description": "A contact and newsletter form library.",
"main": "lib",
"devDependencies": {
"bebop": "^1.3.6",
"cake": "^0.1.1",
"chai": "^3.1.0",
"coffee-script": "^1.9.3",
"connect": "^3.4.0",
"executive": "^0.4.8",
"mocha": "^2.2.5",
"requisite": "^1.9.16",
"selenium-standalone": "^4.5.3",
"serve-static": "^1.10.0",
"shortcake": "^0.2.1",
"uglify-js": "^2.4.23",
"webdriverio": "^2.4.5"
},
"scripts": {
"test": "cake test"
},
"repository": {
"type": "git",
"url": "git+https://github.com/crowdstart/inform.git"
},
"keywords": [
"form",
"contact",
"email",
"signup",
"crowdstart"
],
"author": "\"author\": \"Zach Kelling <zk@crowdstart.com> (http://zeekay.io)",
"license": "MIT",
"bugs": {
"url": "https://github.com/crowdstart/inform/issues"
},
"homepage": "https://github.com/crowdstart/inform#readme"
}
+335
View File
@@ -0,0 +1,335 @@
do ->
`var endpoint = "%s", ml = %s`
called = false
errors = null
forms = null
handlers = null
parent = null
script = null
selectors = {}
validate = false
XHR = ->
xhr = null
if window.XMLHttpRequest
xhr = new XMLHttpRequest()
else if window.ActiveXObject
xhr = new ActiveXObject 'Microsoft.XMLHTTP'
setHeaders: (headers) ->
for k,v of headers
xhr.setRequestHeader k, v
return
post: (url, headers, payload, cb) ->
xhr.open 'POST', url, true
@setHeaders headers
xhr.send payload
xhr.onreadystatechange = ->
if xhr.readyState == 4
if xhr.status == 200 or xhr.status == 201
cb null, xhr.status, xhr
else
cb (new Error 'Subscription failed'), xhr.status, xhr
return
return
# get form container
getContainer = (script, selector = '')->
if selector != ''
document.querySelector selectors.container
else
parent = script.parentNode
inputs = parent.getElementsByTagName 'input'
if inputs.length < 1
document.body
else
parent
# get this script tag
getScript = ->
# find last script node
scripts = document.getElementsByTagName( 'script' )
# last element is this script tag
script = scripts[ scripts.length - 1 ]
script
# Get elements from inside a parent
getElements = (parent, selector) ->
console.log 'getElements', parent, selector
if selector? and selector != ''
parent.querySelectorAll selector
else
[parent]
# get value from a selector
getValue = (parent = document.body, selector) ->
el = parent.querySelector selector
el?.value?.trim()
# serialize a form
serializeForm = (el) ->
return {} unless el?
data =
metadata: {}
inputs = el.getElementsByTagName 'input'
# Loop over form elements
for input in inputs
# Clean up inputs
k = input.name.trim().toLowerCase()
v = input.value.trim()
# Skip inputs we don't care about
if k == '' or v == '' or (input.getAttribute 'type') == 'submit'
continue
# Detect emails
if /email/.test k
data.email = v
else
data.metadata[k] = v
# Use selectors if necessary
if selectors.email
data.email = getValue el, selectors.email
else
data.email ?= ''
for prop in ['firstname', 'lastname', 'name']
if (selector = selectors[prop])?
data.metadata[prop] = getValue el, selector
console.error 'Email is required' if data.email == ''
data
# get setting off script tag data attribute
attr = (name) ->
val = script.getAttribute 'data-' + name
return unless val?
switch val.trim().toLowerCase()
when 'false'
false
when 'true'
true
else
val
# Google event tracking code
google =
setup: ->
return if window.ga? or window._gaq?
((i, s, o, g, r, a, m) ->
i['GoogleAnalyticsObject'] = r
i[r] = i[r] or ->
(i[r].q = i[r].q or []).push arguments
return
i[r].l = 1 * new Date()
a = s.createElement(o)
m = s.getElementsByTagName(o)[0]
a.async = 1
a.src = g
m.parentNode.insertBefore a, m
return
) window, document, 'script', '//www.google-analytics.com/analytics.js', 'ga'
return
track: (opts) ->
return unless opts.category?
google.setup()
category = opts.category ? 'Subscription'
action = opts.action ? opts.name ? 'Signup'
label = opts.label ? 'Lead'
value = opts.value ? 1
if window._gaq?
window._gaq.push ['_trackEvent', category, action, label, value]
if window.ga?
window.ga 'send', 'event', category, action, label, value
return
# Facebook event tracking
facebook =
setup: ->
return if window._fbq?.loaded
_fbq = window._fbq or (window._fbq = [])
fbds = document.createElement('script')
fbds.async = true
fbds.src = '//connect.facebook.net/en_US/fbds.js'
s = document.getElementsByTagName('script')[0]
s.parentNode.insertBefore fbds, s
_fbq.loaded = true
return
track: (opts) ->
return unless opts.id?
facebook.setup()
value = opts.value ? '1.00'
currency = opts.currency ? 'USD'
window._fbq.push ['track', opts.id,
value: value,
currency: currency,
]
return
# Trigger event tracking
track = ->
facebook.track ml.facebook
google.track ml.google
return
# Wire up submit handler
addHandler = (el, errorEl) ->
unless errorEl?
errorEl = document.createElement 'div'
errorEl.className = 'crowdstart-mailinglist-error'
errorEl.style.display = 'none'
errorEl.style.width = 100 + '%%'[0] # Prevents interpolation from picking up % as a thing needing interpolatin'
el.appendChild errorEl
showError = (msg) ->
errorEl.style.display = 'inline'
errorEl.innerHTML = msg
false
hideError = ->
errorEl.style.display = 'none'
thankYou = ->
switch ml.thankyou.type
when 'redirect'
setTimeout ->
window.location = ml.thankyou.url
, 1000
when 'html'
el.innerHTML = ml.thankyou.html
if document.createEvent && document.dispatchEvent
event = document.createEvent 'Event'
event.initEvent 'thankyou', true, true
document.dispatchEvent event
else
console.log "Could not create or dispatch thankyou event"
submitHandler = (ev) ->
if ev.defaultPrevented
return
else
ev.preventDefault()
data = serializeForm el
console.log data
if ml.validate
unless data.email?
return showError 'Email is required'
if (data.email.indexOf '@') == -1
return showError 'Invalid email'
if data.email.length < 3
return showError 'Invalid email'
hideError()
payload = JSON.stringify data
headers =
'X-Requested-With': 'XMLHttpRequest',
'Content-type': 'application/json; charset=utf-8'
xhr = XHR()
xhr.post endpoint, headers, payload, (err, status, xhr) ->
return thankYou() if status == 409
return showError(err) if err?
# Fire tracking pixels
track()
thankYou()
false
(ev) ->
el.removeEventListener 'submit', addHandler
el.addEventListener 'submit', submitHandler
setTimeout ->
el.dispatchEvent new Event 'submit',
bubbles: false
cancelable: true
, 500
ev.preventDefault()
false
# Init all the things
init = ->
if called then return else called = true
props = ['container', 'forms', 'submits', 'errors', 'email', 'firstname', 'lastname', 'name']
for prop in props
selectors[prop] = (attr prop) ? ml.selectors?[prop]
# default selector for submit button
selectors.submits ?= 'input[type="submit"]'
# are we validating?
ml.validate ?= (attr 'validate') ? false
parent = getContainer script, selectors.container
forms = getElements parent, selectors.forms
handlers = getElements parent, selectors.submits
# find error divs
if selectors.errors
errors = getElements parent, selectors.errors
else
errors = []
console.log 'selectors', selectors
console.log 'forms', forms
console.log 'handlers', handlers
console.log 'errors', errors
for handler, i in handlers
do (handler, i) ->
return if handler.getAttribute 'data-hijacked'
handler.setAttribute 'data-hijacked', true
handler.addEventListener 'click', (addHandler forms[i], errors[i])
handler.addEventListener 'submit', (addHandler forms[i], errors[i])
# Get script tag, has to run before rest of DOM loads
script = getScript()
# Run init after DOM loads, attach various listeners
if document.addEventListener
document.addEventListener 'DOMContentLoaded', init, false
else if document.attachEvent
document.attachEvent 'onreadystatechange', ->
init() if document.readyState == 'complete'
if window.addEventListener
window.addEventListener 'load', init, false
else if window.attachEvent
window.attachEvent 'onload', init
return
+65
View File
@@ -0,0 +1,65 @@
module.exports = [
browserName: 'iphone'
platform: 'OS X 10.10'
version: '8.2'
deviceName: 'iPhone Simulator'
deviceOrientation: 'portrait'
,
browserName: 'iphone'
platform: 'OS X 10.10'
version: '7.1'
deviceName: 'iPhone Simulator'
deviceOrientation: 'portrait'
,
browserName: 'iphone'
platform: 'OS X 10.10'
version: '6.1'
deviceName: 'iPhone Simulator'
deviceOrientation: 'portrait'
,
browserName: 'android'
platform: 'Linux'
version: '5.1'
deviceName: 'Android Emulator'
deviceOrientation: 'portrait'
,
browserName: 'android'
platform: 'Linux'
version: '4.4'
deviceName: 'Android Emulator'
deviceOrientation: 'portrait'
,
browserName: 'android'
platform: 'Linux'
version: '4.3'
deviceName: 'Android Emulator'
deviceOrientation: 'portrait'
,
browserName: 'safari'
platform: 'OS X 10.10'
version: '8.0'
,
browserName: 'internet explorer'
platform: 'Windows 8.1'
version: '11.0'
,
browserName: 'internet explorer'
platform: 'Windows 8'
version: '10.0'
,
browserName: 'internet explorer'
platform: 'Windows 7'
version: '9.0'
,
browserName: 'internet explorer'
platform: 'Windows XP'
version: '8.0'
,
browserName: 'chrome'
platform: 'Linux'
version: '43.0'
,
browserName: 'firefox'
platform: 'Linux'
version: '38.0'
]
+11
View File
@@ -0,0 +1,11 @@
assert = require 'assert'
should = require('chai').should()
{getBrowser} = require './util'
describe "Inform (#{process.env.BROWSER})", ->
browser = getBrowser()
testPage = "http://localhost:#{process.env.PORT ? 3333}/test.html"
it 'Should load', ->
require '../src'
+32
View File
@@ -0,0 +1,32 @@
webdriver = require 'webdriverio'
exports.getBrowser = ->
caps =
browserName: process.env.BROWSER ? 'phantomjs'
platform: process.env.PLATFORM
version: process.env.VERSION
deviceName: process.env.DEVICE_NAME
deviceOrientation: process.env.DEVICE_ORIENTATION
opts =
desiredCapabilities: caps
if process.env.TRAVIS?
opts =
desiredCapabilities: caps
host: 'ondemand.saucelabs.com'
port: 80
user: process.env.SAUCE_USERNAME
key: process.env.SAUCE_ACCESS_KEY
logLevel: 'silent'
# annotate tests with travis info
caps.name = process.env.TRAVIS_COMMIT
caps.tags = [
process.env.TRAVIS_PULL_REQUEST
process.env.TRAVIS_BRANCH
process.env.TRAVIS_BUILD_NUMBER
]
caps['tunnel-identifier'] = process.env.TRAVIS_JOB_NUMBER
webdriver.remote(opts).init()