From 22badc67cd9436bdde33d755185974b3e4f8d9ea Mon Sep 17 00:00:00 2001 From: Jonathan Sterling Date: Thu, 3 Sep 2015 14:56:46 -0700 Subject: [PATCH 1/5] Add .gitignore --- .gitignore | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 .gitignore 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/ From 7b59489a791aff272853b91cc112769beac5adf0 Mon Sep 17 00:00:00 2001 From: Jonathan Sterling Date: Thu, 3 Sep 2015 16:46:07 -0700 Subject: [PATCH 2/5] Initial implementation & demo --- README.md | 8 +++ bower.json | 24 ++++++++ docs/DOM/BrowserFeatures/Detectors.md | 11 ++++ docs/Data/BrowserFeatures.md | 9 +++ docs/Data/BrowserFeatures/InputType.md | 43 ++++++++++++++ gulpfile.js | 55 ++++++++++++++++++ package.json | 21 +++++++ src/DOM/BrowserFeatures/Detectors.js | 15 +++++ src/DOM/BrowserFeatures/Detectors.purs | 38 +++++++++++++ src/Data/BrowserFeatures.purs | 9 +++ src/Data/BrowserFeatures/InputType.purs | 75 +++++++++++++++++++++++++ test/Main.purs | 16 ++++++ test/index.html | 6 ++ 13 files changed, 330 insertions(+) create mode 100644 bower.json create mode 100644 docs/DOM/BrowserFeatures/Detectors.md create mode 100644 docs/Data/BrowserFeatures.md create mode 100644 docs/Data/BrowserFeatures/InputType.md create mode 100644 gulpfile.js create mode 100644 package.json create mode 100644 src/DOM/BrowserFeatures/Detectors.js create mode 100644 src/DOM/BrowserFeatures/Detectors.purs create mode 100644 src/Data/BrowserFeatures.purs create mode 100644 src/Data/BrowserFeatures/InputType.purs create mode 100644 test/Main.purs create mode 100644 test/index.html 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..916cb19 --- /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 (maybe) +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 : maybe false id <<< 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..e5802db --- /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) +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 $ flip traverse 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 + + + From 9e4d811e8b93fa78b7d17010fedd97d97e6678ff Mon Sep 17 00:00:00 2001 From: Jonathan Sterling Date: Fri, 4 Sep 2015 11:42:16 -0700 Subject: [PATCH 3/5] Add .travis.yml --- .travis.yml | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 .travis.yml 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 From 43d424f1019a5c788ed940cc4bcc9c0796ce236a Mon Sep 17 00:00:00 2001 From: Jonathan Sterling Date: Fri, 4 Sep 2015 12:09:03 -0700 Subject: [PATCH 4/5] [PR Feedback] use `for` instead of `flip traverse` thanks @cryogenian! --- test/Main.purs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/Main.purs b/test/Main.purs index e5802db..5ca0ff4 100644 --- a/test/Main.purs +++ b/test/Main.purs @@ -4,7 +4,7 @@ import Prelude import Control.Monad.Eff (Eff()) import Control.Monad.Eff.Console (CONSOLE(), log) -import Data.Traversable (traverse) +import Data.Traversable (traverse, for) import qualified Data.BrowserFeatures.InputType as IT import DOM import DOM.BrowserFeatures.Detectors @@ -12,5 +12,5 @@ import DOM.BrowserFeatures.Detectors main :: Eff (dom :: DOM, console :: CONSOLE) Unit main = do features <- detectBrowserFeatures - void $ flip traverse IT.allInputTypes \ty -> + void $ for IT.allInputTypes \ty -> log $ show ty ++ if features.inputTypeSupported ty then " supported" else " not supported" From 4c88f29066c1276fbdc379527eaeb256f1a1a1eb Mon Sep 17 00:00:00 2001 From: Jonathan Sterling Date: Fri, 4 Sep 2015 12:12:53 -0700 Subject: [PATCH 5/5] [PR Feedback] Use `fromMaybe` instead of `maybe _ id` --- src/DOM/BrowserFeatures/Detectors.purs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/DOM/BrowserFeatures/Detectors.purs b/src/DOM/BrowserFeatures/Detectors.purs index 916cb19..1a7c295 100644 --- a/src/DOM/BrowserFeatures/Detectors.purs +++ b/src/DOM/BrowserFeatures/Detectors.purs @@ -9,7 +9,7 @@ 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 (maybe) +import Data.Maybe (fromMaybe) import Data.Foldable (foldr) import Data.Traversable (traverse) import Data.Tuple @@ -33,6 +33,6 @@ detectInputTypeSupportMap = M.fromList <$> traverse (\t -> Tuple t <$> detectInp detectBrowserFeatures :: forall e. Eff (dom :: DOM | e) BrowserFeatures detectBrowserFeatures = do inputTypeSupportMap <- detectInputTypeSupportMap - pure { inputTypeSupported : maybe false id <<< flip M.lookup inputTypeSupportMap + pure { inputTypeSupported : fromMaybe false <<< flip M.lookup inputTypeSupportMap }