diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..748273b --- /dev/null +++ b/.gitignore @@ -0,0 +1,9 @@ +/.* +!/.gitignore +!/.jscsrc +!/.jshintrc +!/.travis.yml +/bower_components/ +/node_modules/ +/output/ +/tmp/ diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..3eb47cd --- /dev/null +++ b/.travis.yml @@ -0,0 +1,16 @@ +language: node_js +sudo: false +node_js: + - 0.12.7 +env: + - PATH=$HOME/purescript:$PATH +install: + - TAG=$(wget -q -O - https://github.com/purescript/purescript/releases/latest --server-response --max-redirect 0 2>&1 | sed -n -e 's/.*Location:.*tag\///p') + - wget -O $HOME/purescript.tar.gz https://github.com/purescript/purescript/releases/download/$TAG/linux64.tar.gz + - tar -xvf $HOME/purescript.tar.gz -C $HOME/ + - chmod a+x $HOME/purescript + - npm install + - npm install -g bower + - bower install +script: + - npm run build diff --git a/README.md b/README.md index ae45cc9..ba5f14f 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,10 @@ # purescript-browserfeatures A data type for browser features and detectors to test for the features. + +To build, run + +``` +gulp +``` + +Then open `test/index.html` and observe the console to see this in action. diff --git a/bower.json b/bower.json new file mode 100644 index 0000000..d2cb7b6 --- /dev/null +++ b/bower.json @@ -0,0 +1,24 @@ +{ + "name": "purescript-browserfeatures", + "repository": { + "type": "git", + "url": "https://github.com/slamdata/purescript-browserfeatures" + }, + "homepage": "https://github.com/slamdata/purescript-browserfeatures", + "authors": [ + "Jon Sterling " + ], + "description": "A data type for browser features and detectors to test for the features", + "keywords": [ + "purescript", + "platform" + ], + "license": "Apache-2.0", + "dependencies": { + "purescript-base": "^0.1.0", + "purescript-exceptions": "v0.3.0", + "purescript-prelude": "<= 0.1.1", + "purescript-dom": "^0.1.2", + "purescript-maps": "^0.5.0" + } +} diff --git a/docs/DOM/BrowserFeatures/Detectors.md b/docs/DOM/BrowserFeatures/Detectors.md new file mode 100644 index 0000000..6dfb07d --- /dev/null +++ b/docs/DOM/BrowserFeatures/Detectors.md @@ -0,0 +1,11 @@ +## Module DOM.BrowserFeatures.Detectors + +#### `detectBrowserFeatures` + +``` purescript +detectBrowserFeatures :: forall e. Eff (dom :: DOM | e) BrowserFeatures +``` + +Detect browser features by testing them using the DOM. + + diff --git a/docs/Data/BrowserFeatures.md b/docs/Data/BrowserFeatures.md new file mode 100644 index 0000000..95c6b62 --- /dev/null +++ b/docs/Data/BrowserFeatures.md @@ -0,0 +1,9 @@ +## Module Data.BrowserFeatures + +#### `BrowserFeatures` + +``` purescript +type BrowserFeatures = { inputTypeSupported :: InputType -> Boolean } +``` + + diff --git a/docs/Data/BrowserFeatures/InputType.md b/docs/Data/BrowserFeatures/InputType.md new file mode 100644 index 0000000..1fb8443 --- /dev/null +++ b/docs/Data/BrowserFeatures/InputType.md @@ -0,0 +1,43 @@ +## Module Data.BrowserFeatures.InputType + +#### `InputType` + +``` purescript +data InputType + = Color + | Date + | DateTime + | DateTimeLocal + | Time + | Month + | Week + | Email + | Url + | Number + | Search + | Range +``` + +##### Instances +``` purescript +instance showInputType :: Show InputType +instance eqInputType :: Eq InputType +instance ordInputType :: Ord InputType +``` + +#### `allInputTypes` + +``` purescript +allInputTypes :: Array InputType +``` + +#### `renderInputType` + +``` purescript +renderInputType :: InputType -> String +``` + +Render an `InputType` into the corresponding value of the `type` attribute +on an `input` element. + + diff --git a/gulpfile.js b/gulpfile.js new file mode 100644 index 0000000..0674402 --- /dev/null +++ b/gulpfile.js @@ -0,0 +1,55 @@ +"use strict" + +var gulp = require("gulp"), + purescript = require("gulp-purescript"), + webpack = require("webpack-stream"); + +var sources = [ + "src/**/*.purs", + "bower_components/purescript-*/src/**/*.purs", + "test/*.purs" +]; +var foreigns = [ + "src/**/*.js", + "bower_components/purescript-*/src/**/*.js", + "test/*/*.js" +]; + +gulp.task("make", function() { + return purescript.psc({ src: sources, ffi: foreigns }); +}); + +gulp.task("docs", function() { + return purescript.pscDocs({ + src: sources, + docgen: { + "Data.BrowserFeatures": "docs/Data/BrowserFeatures.md", + "Data.BrowserFeatures.InputType": "docs/Data/BrowserFeatures/InputType.md", + "DOM.BrowserFeatures.Detectors": "docs/DOM/BrowserFeatures/Detectors.md" + } + }); +}); + +gulp.task("bundle", ["make"], function() { + return purescript.pscBundle({ + src: "output/**/*.js", + output: "tmp/test.js", + main: "Test.Main" + }); +}); + +gulp.task("bundle-test", ["bundle"], function() { + return gulp.src("tmp/test.js") + .pipe(webpack({ + resolve: { moduleDirectories: ["node_modules"] }, + output: { filename: "test.js" } + })) + .pipe(gulp.dest("tmp")); +}); + +gulp.task("dotpsci", function () { + return purescript.psci({ src: sources, ffi: foreigns }) + .pipe(gulp.dest(".")); +}); + +gulp.task("default", ["bundle-test", "docs", "dotpsci"]); diff --git a/package.json b/package.json new file mode 100644 index 0000000..438e3df --- /dev/null +++ b/package.json @@ -0,0 +1,21 @@ +{ + "name": "purescript-browserfeatures", + "description": "A PureScript interface to browserfeatures.js.", + "repository": { + "type": "git", + "url": "https://github.com/slamdata/purescript-browserfeatures.git" + }, + "author": "Jon Sterling ", + "license": "Apache-2.0", + "scripts": { + "build": "npm install && gulp bundle-test" + }, + "devDependencies": { + "gulp": "^3.9.0", + "gulp-purescript": "^0.5.0", + "purescript": "^0.7.1", + "webpack-stream": "^2.1.0" + }, + "dependencies": { + } +} diff --git a/src/DOM/BrowserFeatures/Detectors.js b/src/DOM/BrowserFeatures/Detectors.js new file mode 100644 index 0000000..dbf6330 --- /dev/null +++ b/src/DOM/BrowserFeatures/Detectors.js @@ -0,0 +1,15 @@ +// module DOM.BrowserFeatures.Detectors + +exports._detectInputTypeSupport = function(type) { + return function() { + var el = document.createElement("input"); + + try { + el.setAttribute("type", type); + } catch (exn) { + return false; + } + + return el.type === type; + }; +}; diff --git a/src/DOM/BrowserFeatures/Detectors.purs b/src/DOM/BrowserFeatures/Detectors.purs new file mode 100644 index 0000000..1a7c295 --- /dev/null +++ b/src/DOM/BrowserFeatures/Detectors.purs @@ -0,0 +1,38 @@ +module DOM.BrowserFeatures.Detectors + ( detectBrowserFeatures + ) where + +import Prelude +import Control.Monad.Eff +import Control.Monad.Eff.Exception + +import qualified Data.Array as Arr +import qualified Data.List as L +import qualified Data.Map as M +import Data.Maybe (fromMaybe) +import Data.Foldable (foldr) +import Data.Traversable (traverse) +import Data.Tuple + +import DOM +import Data.BrowserFeatures +import qualified Data.BrowserFeatures.InputType as IT + +foreign import _detectInputTypeSupport :: forall e. String -> Eff (dom :: DOM | e) Boolean + +detectInputTypeSupport :: forall e. IT.InputType -> Eff (dom :: DOM | e) Boolean +detectInputTypeSupport = _detectInputTypeSupport <<< IT.renderInputType + +detectInputTypeSupportMap :: forall e. Eff (dom :: DOM | e) (M.Map IT.InputType Boolean) +detectInputTypeSupportMap = M.fromList <$> traverse (\t -> Tuple t <$> detectInputTypeSupport t) inputTypes + where + inputTypes :: L.List IT.InputType + inputTypes = foldr L.Cons L.Nil IT.allInputTypes + +-- | Detect browser features by testing them using the DOM. +detectBrowserFeatures :: forall e. Eff (dom :: DOM | e) BrowserFeatures +detectBrowserFeatures = do + inputTypeSupportMap <- detectInputTypeSupportMap + pure { inputTypeSupported : fromMaybe false <<< flip M.lookup inputTypeSupportMap + } + diff --git a/src/Data/BrowserFeatures.purs b/src/Data/BrowserFeatures.purs new file mode 100644 index 0000000..d60cd53 --- /dev/null +++ b/src/Data/BrowserFeatures.purs @@ -0,0 +1,9 @@ +module Data.BrowserFeatures + ( BrowserFeatures(..) + ) where + +import Data.BrowserFeatures.InputType + +type BrowserFeatures = + { inputTypeSupported :: InputType -> Boolean + } diff --git a/src/Data/BrowserFeatures/InputType.purs b/src/Data/BrowserFeatures/InputType.purs new file mode 100644 index 0000000..31a2438 --- /dev/null +++ b/src/Data/BrowserFeatures/InputType.purs @@ -0,0 +1,75 @@ +module Data.BrowserFeatures.InputType + ( InputType(..) + , renderInputType + , allInputTypes + ) where + +import Prelude +import qualified Data.Array as Arr + +data InputType + = Color + | Date + | DateTime + | DateTimeLocal + | Time + | Month + | Week + | Email + | Url + | Number + | Search + | Range + +allInputTypes :: Array InputType +allInputTypes = + [ Color + , Date + , DateTime + , DateTimeLocal + , Time + , Month + , Week + , Email + , Url + , Number + , Search + , Range + ] + +instance showInputType :: Show InputType where + show Color = "Color" + show Date = "Date" + show DateTime = "DateTime" + show DateTimeLocal = "DateTimeLocal" + show Time = "Time" + show Month = "Month" + show Week = "Week" + show Email = "Email" + show Url = "Url" + show Number = "Number" + show Search = "Search" + show Range = "Range" + +-- | Render an `InputType` into the corresponding value of the `type` attribute +-- | on an `input` element. +renderInputType :: InputType -> String +renderInputType Color = "color" +renderInputType Date = "date" +renderInputType DateTime = "datetime" +renderInputType DateTimeLocal = "datetime-local" +renderInputType Time = "time" +renderInputType Month = "month" +renderInputType Week = "week" +renderInputType Email = "email" +renderInputType Url = "url" +renderInputType Number = "number" +renderInputType Search = "search" +renderInputType Range = "range" + +instance eqInputType :: Eq InputType where + eq x y = renderInputType x == renderInputType y + +instance ordInputType :: Ord InputType where + compare x y = compare (renderInputType x) (renderInputType y) + diff --git a/test/Main.purs b/test/Main.purs new file mode 100644 index 0000000..5ca0ff4 --- /dev/null +++ b/test/Main.purs @@ -0,0 +1,16 @@ +module Test.Main where + +import Prelude +import Control.Monad.Eff (Eff()) +import Control.Monad.Eff.Console (CONSOLE(), log) + +import Data.Traversable (traverse, for) +import qualified Data.BrowserFeatures.InputType as IT +import DOM +import DOM.BrowserFeatures.Detectors + +main :: Eff (dom :: DOM, console :: CONSOLE) Unit +main = do + features <- detectBrowserFeatures + void $ for IT.allInputTypes \ty -> + log $ show ty ++ if features.inputTypeSupported ty then " supported" else " not supported" diff --git a/test/index.html b/test/index.html new file mode 100644 index 0000000..4eda0ee --- /dev/null +++ b/test/index.html @@ -0,0 +1,6 @@ + + + Platform Test + + +