From f2c0e987d8fc679274624dfda495d5d32b3097b3 Mon Sep 17 00:00:00 2001 From: Gabriel Le Breton Date: Sat, 5 Nov 2016 11:36:19 -0400 Subject: [PATCH] Added eslint and stylelint + husky auto fixing --- .eslintignore | 1 + .eslintrc.yml | 19 +++++++++++++ .stylelintrc | 19 +++++++++++++ index.js | 60 +++++++++++++++++++-------------------- package.json | 11 ++++++-- smart-app-banner.css | 54 ++++++++++++++++++----------------- smart-app-banner.js | 67 ++++++++++++++++++++++---------------------- 7 files changed, 139 insertions(+), 92 deletions(-) create mode 100644 .eslintignore create mode 100644 .eslintrc.yml create mode 100644 .stylelintrc diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 0000000..292c152 --- /dev/null +++ b/.eslintignore @@ -0,0 +1 @@ +smart-app-banner.js diff --git a/.eslintrc.yml b/.eslintrc.yml new file mode 100644 index 0000000..26ff6ea --- /dev/null +++ b/.eslintrc.yml @@ -0,0 +1,19 @@ +env: + browser: true + node: true +extends: 'eslint:recommended' +rules: + no-undef: + - ignore + indent: + - error + - tab + linebreak-style: + - error + - unix + quotes: + - error + - single + semi: + - error + - always diff --git a/.stylelintrc b/.stylelintrc new file mode 100644 index 0000000..d485fb2 --- /dev/null +++ b/.stylelintrc @@ -0,0 +1,19 @@ +{ + "rules": { + "block-no-empty": null, + "color-no-invalid-hex": true, + "comment-empty-line-before": [ "always", { + "ignore": ["stylelint-commands", "between-comments"], + } ], + "declaration-colon-space-after": "always", + "indentation": ["space", { + "except": ["value"] + }], + "max-empty-lines": 2, + "rule-nested-empty-line-before": [ "always", { + "except": ["first-nested"], + "ignore": ["after-comment"], + } ], + "unit-whitelist": ["em", "rem", "%", "s"] + } +} diff --git a/index.js b/index.js index ce9b220..1fe43ee 100644 --- a/index.js +++ b/index.js @@ -1,9 +1,12 @@ var extend = require('xtend/mutable'); var q = require('component-query'); var doc = require('get-doc'); -var root = doc && doc.documentElement; var cookie = require('cookie-cutter'); var ua = require('ua-parser-js'); + +var root = doc && doc.documentElement; + +/* global navigator */ var userLang = navigator.language.slice(-2) || navigator.userLanguage.slice(-2) || 'us'; // platform dependent functionality @@ -11,27 +14,27 @@ var mixins = { ios: { appMeta: 'apple-itunes-app', iconRels: ['apple-touch-icon-precomposed', 'apple-touch-icon'], - getStoreLink: function() { + getStoreLink: function () { return 'https://itunes.apple.com/' + this.options.appStoreLanguage + '/app/id' + this.appId; } }, android: { appMeta: 'google-play-app', iconRels: ['android-touch-icon', 'apple-touch-icon-precomposed', 'apple-touch-icon'], - getStoreLink: function() { + getStoreLink: function () { return 'http://play.google.com/store/apps/details?id=' + this.appId; } }, windows: { appMeta: 'msApplication-ID', iconRels: ['windows-touch-icon', 'apple-touch-icon-precomposed', 'apple-touch-icon'], - getStoreLink: function() { + getStoreLink: function () { return 'http://www.windowsphone.com/s?appid=' + this.appId; } } }; -var SmartBanner = function(options) { +var SmartBanner = function (options) { var agent = ua(navigator.userAgent); this.options = extend({}, { daysHidden: 15, @@ -55,18 +58,15 @@ var SmartBanner = function(options) { this.type = this.options.force; } else if (agent.os.name === 'Windows Phone' || agent.os.name === 'Windows Mobile') { this.type = 'windows'; - //iOS >= 6 has native support for SmartAppBanner - } else if (agent.os.name === 'iOS' && parseInt(agent.os.version) < 6) { + // iOS >= 6 has native support for SmartAppBanner + } else if (agent.os.name === 'iOS' && Number(agent.os.version) < 6) { this.type = 'ios'; } else if (agent.os.name === 'Android') { this.type = 'android'; } // Don't show banner if device isn't iOS or Android, website is loaded in app, user dismissed banner, or we have no app id in meta - if (!this.type - || navigator.standalone - || cookie.get('smartbanner-closed') - || cookie.get('smartbanner-installed')) { + if (!this.type || navigator.standalone || cookie.get('smartbanner-closed') || cookie.get('smartbanner-installed')) { return; } @@ -83,12 +83,12 @@ var SmartBanner = function(options) { SmartBanner.prototype = { constructor: SmartBanner, - create: function() { + create: function () { var link = this.getStoreLink(); var inStore = this.options.price[this.type] + ' - ' + this.options.store[this.type]; var icon; for (var i = 0; i < this.iconRels.length; i++) { - var rel = q('link[rel="'+this.iconRels[i]+'"]'); + var rel = q('link[rel="' + this.iconRels[i] + '"]'); if (rel) { icon = rel.getAttribute('href'); break; @@ -100,52 +100,50 @@ SmartBanner.prototype = { sb.innerHTML = '
' + '×' + - '' + + '' + '
' + - '
'+this.options.title+'
' + - '
'+this.options.author+'
' + - ''+inStore+'' + + '
' + this.options.title + '
' + + '
' + this.options.author + '
' + + '' + inStore + '' + '
' + - '' + - ''+this.options.button+'' + + '' + + '' + this.options.button + '' + '' + '
'; - //there isn’t neccessary a body + // there isn’t neccessary a body if (doc.body) { doc.body.appendChild(sb); - } - else if (doc) { - doc.addEventListener('DOMContentLoaded', function(){ + } else if (doc) { + doc.addEventListener('DOMContentLoaded', function () { doc.body.appendChild(sb); }); } q('.smartbanner-button', sb).addEventListener('click', this.install.bind(this), false); q('.smartbanner-close', sb).addEventListener('click', this.close.bind(this), false); - }, - hide: function() { + hide: function () { root.classList.remove('smartbanner-show'); }, - show: function() { + show: function () { root.classList.add('smartbanner-show'); }, - close: function() { + close: function () { this.hide(); cookie.set('smartbanner-closed', 'true', { path: '/', - expires: +new Date() + this.options.daysHidden * 1000 * 60 * 60 * 24 + expires: Number(new Date()) + (this.options.daysHidden * 1000 * 60 * 60 * 24) }); }, - install: function() { + install: function () { this.hide(); cookie.set('smartbanner-installed', 'true', { path: '/', - expires: +new Date() + this.options.daysReminder * 1000 * 60 * 60 * 24 + expires: Number(new Date()) + (this.options.daysReminder * 1000 * 60 * 60 * 24) }); }, - parseAppId: function() { + parseAppId: function () { var meta = q('meta[name="' + this.appMeta + '"]'); if (!meta) { return; diff --git a/package.json b/package.json index 2311f7e..a959ff7 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,9 @@ "description": "Smart banner for Android or iOS", "main": "index.js", "scripts": { - "build": "browserify index.js -s SmartBanner | ccjs - > smart-app-banner.js" + "build": "browserify index.js -s SmartBanner | ccjs - > smart-app-banner.js", + "precommit": "xo --fix index.js && fixmyjs && stylefmt smart-app-banner.css && npm run test && npm run build", + "test": "xo" }, "repository": { "type": "git", @@ -45,6 +47,11 @@ "devDependencies": { "browserify": "^10.2.4", "ccjs": "^0.2.0", - "closurecompiler": "^1.5.1" + "closurecompiler": "^1.5.1", + "eslint": "^3.9.1", + "fixmyjs": "^1.0.3", + "jshint": "^2.9.4", + "stylefmt": "^4.3.1", + "xo": "^0.17.0" } } diff --git a/smart-app-banner.css b/smart-app-banner.css index df6757c..60e8108 100644 --- a/smart-app-banner.css +++ b/smart-app-banner.css @@ -1,6 +1,7 @@ .smartbanner-show { margin-top: 80px; } + .smartbanner-show .smartbanner { display: block; } @@ -39,7 +40,7 @@ text-decoration: none; border: 0; border-radius: 14px; - -webkit-font-smoothing: subpixel-antialiased; + -webkit-font-smoothing: subpixel-antialiased; } .smartbanner-close:active, @@ -63,11 +64,11 @@ width: 44%; font-size: 11px; line-height: 1.2em; - font-weight: bold; + font-weight: bold; } .smartbanner-title { - font-size:13px; + font-size: 13px; line-height: 18px; } @@ -88,7 +89,8 @@ text-shadow: 0 1px 0 rgba(255, 255, 255, 0.8); } -.smartbanner-button:active, .smartbanner-button:hover { +.smartbanner-button:active, +.smartbanner-button:hover { color: #aaa; } @@ -112,10 +114,10 @@ width: 18px; height: 18px; line-height: 18px; - font-family: Arial; + font-family: Arial; color: #888; text-shadow: 0 1px 0 white; - -webkit-font-smoothing: none; + -webkit-font-smoothing: none; } .smartbanner-ios .smartbanner-close:active, @@ -127,23 +129,23 @@ background-size: cover; } -.smartbanner-ios .smartbanner-info { +.smartbanner-ios .smartbanner-info { color: #6a6a6a; text-shadow: 0 1px 0 rgba(255, 255, 255, 0.8); - font-weight:300; + font-weight: 300; } .smartbanner-ios .smartbanner-title { - color:#4d4d4d; + color: #4d4d4d; font-weight: 500; } .smartbanner-ios .smartbanner-button { - padding: 0 10px; - font-size: 15px; - min-width: 10%; - font-weight: 400; - color: #0C71FD; + padding: 0 10px; + font-size: 15px; + min-width: 10%; + font-weight: 400; + color: #0c71fd; } .smartbanner-ios .smartbanner-button:active, @@ -162,7 +164,7 @@ /** Android **/ .smartbanner-android { background: #3d3d3d url('dark_background_stripes.gif'); - box-shadow: inset 0 4px 0 #88B131; + box-shadow: inset 0 4px 0 #88b131; line-height: 82px; } @@ -189,23 +191,23 @@ } .smartbanner-android .smartbanner-info { - color:#ccc; - text-shadow:0 1px 2px #000; + color: #ccc; + text-shadow: 0 1px 2px #000; } .smartbanner-android .smartbanner-title { - color:#fff; + color: #fff; font-weight: bold; } .smartbanner-android .smartbanner-button { min-width: 12%; color: #d1d1d1; - font-weight: bold; + font-weight: bold; padding: 0; background: none; border-radius: 0; - box-shadow: 0 0 0 1px #333, 0 0 0 2px #DDDCDC; + box-shadow: 0 0 0 1px #333, 0 0 0 2px #dddcdc; } .smartbanner-android .smartbanner-button:active, @@ -217,8 +219,8 @@ text-align: center; display: block; padding: 0 10px; - background: #42B6C9; - background: linear-gradient(to bottom, #42B6C9, #39A9BB); + background: #42b6c9; + background: linear-gradient(to bottom, #42b6c9, #39a9bb); text-transform: none; text-shadow: none; box-shadow: none; @@ -226,7 +228,7 @@ .smartbanner-android .smartbanner-button-text:active, .smartbanner-android .smartbanner-button-text:hover { - background: #2AC7E1; + background: #2ac7e1; } @@ -253,9 +255,9 @@ } .smartbanner-windows .smartbanner-icon { - background: rgba(0,0,0,0.6); + background: rgba(0, 0, 0, 0.6); background-size: cover; - box-shadow: 0 1px 3px rgba(0,0,0,0.3); + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3); } .smartbanner-windows .smartbanner-info { @@ -264,7 +266,7 @@ } .smartbanner-windows .smartbanner-title { - color:#4d4d4d; + color: #4d4d4d; font-weight: bold; } diff --git a/smart-app-banner.js b/smart-app-banner.js index de403c9..8545590 100644 --- a/smart-app-banner.js +++ b/smart-app-banner.js @@ -1,33 +1,34 @@ -(function(t){"object"===typeof exports&&"undefined"!==typeof module?module.exports=t():"function"===typeof define&&define.amd?define([],t):("undefined"!==typeof window?window:"undefined"!==typeof global?global:"undefined"!==typeof self?self:this).SmartBanner=t()})(function(){return function d(g,f,e){function b(c,n){if(!f[c]){if(!g[c]){var k="function"==typeof require&&require;if(!n&&k)return k(c,!0);if(a)return a(c,!0);k=Error("Cannot find module '"+c+"'");throw k.code="MODULE_NOT_FOUND",k;}k=f[c]= -{exports:{}};g[c][0].call(k.exports,function(a){var e=g[c][1][a];return b(e?e:a)},k,k.exports,d,g,f,e)}return f[c].exports}for(var a="function"==typeof require&&require,c=0;cparseInt(a.os.version)?this.type="ios":"Android"===a.os.name&&(this.type="android");!this.type||navigator.standalone|| -q.get("smartbanner-closed")||q.get("smartbanner-installed")||(e(this,k[this.type]),this.parseAppId()&&(this.create(),this.show()))};d.prototype={constructor:d,create:function(){for(var c=this.getStoreLink(),e=this.options.price[this.type]+" - "+this.options.store[this.type],d,u=0;u
'+this.options.title+"
"+this.options.author+"
"+e+'
'+this.options.button+"";a.body?a.body.appendChild(p):a&&a.addEventListener("DOMContentLoaded",function(){a.body.appendChild(p)});b(".smartbanner-button",p).addEventListener("click",this.install.bind(this),!1);b(".smartbanner-close",p).addEventListener("click", -this.close.bind(this),!1)},hide:function(){c.classList.remove("smartbanner-show")},show:function(){c.classList.add("smartbanner-show")},close:function(){this.hide();q.set("smartbanner-closed","true",{path:"/",expires:+new Date+864E5*this.options.daysHidden})},install:function(){this.hide();q.set("smartbanner-installed","true",{path:"/",expires:+new Date+864E5*this.options.daysReminder})},parseAppId:function(){var a=b('meta[name="'+this.appMeta+'"]');if(a)return this.appId="windows"===this.type?a.getAttribute("content"): -/app-id=([^\s,]+)/.exec(a.getAttribute("content"))[1]}};g.exports=d},{"component-query":2,"cookie-cutter":3,"get-doc":4,"ua-parser-js":6,"xtend/mutable":7}],2:[function(d,g,f){function e(b,a){return a.querySelector(b)}f=g.exports=function(b,a){a=a||document;return e(b,a)};f.all=function(b,a){a=a||document;return a.querySelectorAll(b)};f.engine=function(b){if(!b.one)throw Error(".one callback required");if(!b.all)throw Error(".all callback required");e=b.one;f.all=b.all;return f}},{}],3:[function(d, -g,f){f=g.exports=function(e){e||(e={});"string"===typeof e&&(e={cookie:e});void 0===e.cookie&&(e.cookie="");return{get:function(b){for(var a=e.cookie.split(/;\s*/),c=0;cNumber(c.os.version)?this.type="ios":"Android"===c.os.name&&(this.type= +"android");!this.type||navigator.standalone||d.get("smartbanner-closed")||d.get("smartbanner-installed")||(e(this,l[this.type]),this.parseAppId()&&(this.create(),this.show()))};b.prototype={constructor:b,create:function(){for(var d=this.getStoreLink(),e=this.options.price[this.type]+" - "+this.options.store[this.type],u,t=0;t
'+this.options.title+"
"+this.options.author+"
"+e+'
'+this.options.button+"";a.body?a.body.appendChild(b):a&& +a.addEventListener("DOMContentLoaded",function(){a.body.appendChild(b)});c(".smartbanner-button",b).addEventListener("click",this.install.bind(this),!1);c(".smartbanner-close",b).addEventListener("click",this.close.bind(this),!1)},hide:function(){n.classList.remove("smartbanner-show")},show:function(){n.classList.add("smartbanner-show")},close:function(){this.hide();d.set("smartbanner-closed","true",{path:"/",expires:Number(new Date)+864E5*this.options.daysHidden})},install:function(){this.hide(); +d.set("smartbanner-installed","true",{path:"/",expires:Number(new Date)+864E5*this.options.daysReminder})},parseAppId:function(){var a=c('meta[name="'+this.appMeta+'"]');if(a)return this.appId="windows"===this.type?a.getAttribute("content"):/app-id=([^\s,]+)/.exec(a.getAttribute("content"))[1]}};k.exports=b},{"component-query":2,"cookie-cutter":3,"get-doc":4,"ua-parser-js":6,"xtend/mutable":7}],2:[function(b,k,f){function e(c,a){return a.querySelector(c)}f=k.exports=function(c,a){a=a||document;return e(c, +a)};f.all=function(c,a){a=a||document;return a.querySelectorAll(c)};f.engine=function(c){if(!c.one)throw Error(".one callback required");if(!c.all)throw Error(".all callback required");e=c.one;f.all=c.all;return f}},{}],3:[function(b,k,f){f=k.exports=function(e){e||(e={});"string"===typeof e&&(e={cookie:e});void 0===e.cookie&&(e.cookie="");return{get:function(c){for(var a=e.cookie.split(/;\s*/),d=0;d