From 59d8cbe742ff78a70eee74805a440b96b3930a88 Mon Sep 17 00:00:00 2001 From: Kegan Dougal Date: Wed, 28 Oct 2015 17:39:50 +0000 Subject: [PATCH 1/4] Use Modernizr to check for browser compatibility Add a CompatibilityPage which is shown for incompatible clients. If they continue on regardless, proceed as if it never happened. --- .modernizr.json | 12 ++++ package.json | 2 + .../vector/css/pages/CompatibilityPage.css | 19 ++++++ .../vector/views/pages/CompatibilityPage.js | 58 +++++++++++++++++ src/vector/index.js | 62 +++++++++++++++++-- src/vector/modernizr.js | 3 + 6 files changed, 150 insertions(+), 6 deletions(-) create mode 100644 .modernizr.json create mode 100644 src/skins/vector/css/pages/CompatibilityPage.css create mode 100644 src/skins/vector/views/pages/CompatibilityPage.js create mode 100644 src/vector/modernizr.js diff --git a/.modernizr.json b/.modernizr.json new file mode 100644 index 0000000000..6d28fa8649 --- /dev/null +++ b/.modernizr.json @@ -0,0 +1,12 @@ +{ + "minify": true, + "classPrefix": "modernizr_", + "options": [ + "setClasses" + ], + "feature-detects": [ + "test/css/displaytable", + "test/css/flexbox", + "test/es5/specification" + ] +} \ No newline at end of file diff --git a/package.json b/package.json index 275ef4c293..9ed43f6db9 100644 --- a/package.json +++ b/package.json @@ -11,6 +11,7 @@ "style": "bundle.css", "scripts": { "reskindex": "reskindex vector -h src/skins/vector/header", + "build:modernizr": "modernizr -c .modernizr.json -d src/vector/modernizr.js", "build:css": "catw \"src/skins/vector/css/**/*.css\" -o vector/bundle.css -c uglifycss --no-watch", "build:compile": "babel --source-maps -d lib src", "build:bundle": "NODE_ENV=production webpack -p lib/vector/index.js vector/bundle.js", @@ -29,6 +30,7 @@ "linkifyjs": "^2.0.0-beta.4", "matrix-js-sdk": "^0.2.2", "matrix-react-sdk": "^0.0.1", + "modernizr": "^3.1.0", "q": "^1.4.1", "react": "^0.13.3", "react-loader": "^1.4.0" diff --git a/src/skins/vector/css/pages/CompatibilityPage.css b/src/skins/vector/css/pages/CompatibilityPage.css new file mode 100644 index 0000000000..f3f032c975 --- /dev/null +++ b/src/skins/vector/css/pages/CompatibilityPage.css @@ -0,0 +1,19 @@ +.mx_CompatibilityPage { + width: 100%; + height: 100%; + background-color: #e55; +} + +.mx_CompatibilityPage_box { + position: absolute; + top: 0; + bottom: 0; + left: 0; + right: 0; + margin: auto; + width: 500px; + height: 300px; + border: 1px solid; + padding: 10px; + background-color: #fcc; +} \ No newline at end of file diff --git a/src/skins/vector/views/pages/CompatibilityPage.js b/src/skins/vector/views/pages/CompatibilityPage.js new file mode 100644 index 0000000000..610630dce4 --- /dev/null +++ b/src/skins/vector/views/pages/CompatibilityPage.js @@ -0,0 +1,58 @@ +/* +Copyright 2015 OpenMarket Ltd + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +'use strict'; + +var React = require('react'); + +module.exports = React.createClass({ + displayName: 'CompatibilityPage', + propTypes: { + onAccept: React.PropTypes.func + }, + + getDefaultProps: function() { + return { + onAccept: function() {} // NOP + }; + }, + + onAccept: function() { + this.props.onAccept(); + }, + + render: function() { + + return ( +
+
+

Sorry, your browser is not able to run Vector.

+

+ Buttons and images may appear out of place, communication may + not be possible and all manner of chaos may be unleashed. +

+

+ Though if you like taking risks with your life, you can still try it + out by clicking that you understand the risks involved. +

+ +
+
+ ); + } +}); diff --git a/src/vector/index.js b/src/vector/index.js index 22db05a38f..52e267ab73 100644 --- a/src/vector/index.js +++ b/src/vector/index.js @@ -16,6 +16,7 @@ limitations under the License. 'use strict'; +var RunModernizrTests = require("./modernizr"); // this side-effects a global var React = require("react"); var sdk = require("matrix-react-sdk"); sdk.loadSkin(require('../skins/vector/skindex')); @@ -25,6 +26,33 @@ var qs = require("querystring"); var lastLocationHashSet = null; +function checkBrowserFeatures(featureList) { + if (!window.Modernizr) { + console.error("Cannot check features - Modernizr global is missing."); + return false; + } + var featureComplete = true; + for (var i = 0; i < featureList.length; i++) { + if (window.Modernizr[featureList[i]] === undefined) { + console.error( + "Looked for feature '%s' but Modernizr has no results for this. " + + "Has it been configured correctly?", featureList[i] + ); + return false; + } + if (window.Modernizr[featureList[i]] === false) { + console.error("Browser missing feature: '%s'", featureList[i]); + // toggle flag rather than return early so we log all missing features + // rather than just the first. + featureComplete = false; + } + } + return featureComplete; +} + +var validBrowser = checkBrowserFeatures([ + "displaytable", "flexbox", "es5object", "es5function", "foo" +]); // We want to support some name / value pairs in the fragment // so we're re-using query string like format @@ -84,14 +112,11 @@ var makeRegistrationUrl = function() { '#/register'; } -var MatrixChat = sdk.getComponent('pages.MatrixChat'); -window.matrixChat = React.render( - , - document.getElementById('matrixchat') -); - window.addEventListener('hashchange', onHashChange); window.onload = function() { + if (!validBrowser) { + return; + } routeUrl(window.location); loaded = true; if (lastLoadedScreen) { @@ -100,3 +125,28 @@ window.onload = function() { } } +function loadApp() { + if (validBrowser) { + var MatrixChat = sdk.getComponent('pages.MatrixChat'); + window.matrixChat = React.render( + , + document.getElementById('matrixchat') + ); + } + else { + console.error("Browser is missing required features."); + // take to a different landing page to AWOOOOOGA at the user + var CompatibilityPage = require("../skins/vector/views/pages/CompatibilityPage"); + window.matrixChat = React.render( + , + document.getElementById('matrixchat') + ); + } +} + +loadApp(); diff --git a/src/vector/modernizr.js b/src/vector/modernizr.js new file mode 100644 index 0000000000..f9641a763e --- /dev/null +++ b/src/vector/modernizr.js @@ -0,0 +1,3 @@ +/*! modernizr 3.1.0 (Custom Build) | MIT * + * http://modernizr.com/download/?-displaytable-es5-flexbox-cssclassprefix:modernizr_ !*/ +!function(window,document,undefined){function is(e,t){return typeof e===t}function testRunner(){var e,t,r,n,o,s,i;for(var d in tests){if(e=[],t=tests[d],t.name&&(e.push(t.name.toLowerCase()),t.options&&t.options.aliases&&t.options.aliases.length))for(r=0;rd;d++)if(l=e[d],c=mStyle.style[l],contains(l,"-")&&(l=cssToDOM(l)),mStyle.style[l]!==undefined){if(n||is(r,"undefined"))return o(),"pfx"==t?l:!0;try{mStyle.style[l]=r}catch(u){}if(mStyle.style[l]!=c)return o(),"pfx"==t?l:!0}return o(),!1}function fnBind(e,t){return function(){return e.apply(t,arguments)}}function testDOMProps(e,t,r){var n;for(var o in e)if(e[o]in t)return r===!1?e[o]:(n=t[e[o]],is(n,"function")?fnBind(n,r||t):n);return!1}function testPropsAll(e,t,r,n,o){var s=e.charAt(0).toUpperCase()+e.slice(1),i=(e+" "+cssomPrefixes.join(s+" ")+s).split(" ");return is(t,"string")||is(t,"undefined")?testProps(i,t,n,o):(i=(e+" "+domPrefixes.join(s+" ")+s).split(" "),testDOMProps(i,t,r))}function testAllProps(e,t,r){return testPropsAll(e,undefined,undefined,t,r)}var tests=[],ModernizrProto={_version:"3.1.0",_config:{classPrefix:"modernizr_",enableClasses:!0,enableJSClass:!0,usePrefixes:!0},_q:[],on:function(e,t){var r=this;setTimeout(function(){t(r[e])},0)},addTest:function(e,t,r){tests.push({name:e,fn:t,options:r})},addAsyncTest:function(e){tests.push({name:null,fn:e})}},Modernizr=function(){};Modernizr.prototype=ModernizrProto,Modernizr=new Modernizr;var classes=[],docElement=document.documentElement,isSVG="svg"===docElement.nodeName.toLowerCase(),testStyles=ModernizrProto.testStyles=injectElementWithStyles;testStyles("#modernizr{display: table; direction: ltr}#modernizr div{display: table-cell; padding: 10px}",function(e){var t,r=e.childNodes;t=r[0].offsetLeft Date: Wed, 28 Oct 2015 17:42:19 +0000 Subject: [PATCH 2/4] Remove test feature --- src/vector/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vector/index.js b/src/vector/index.js index 52e267ab73..8567cc030c 100644 --- a/src/vector/index.js +++ b/src/vector/index.js @@ -51,7 +51,7 @@ function checkBrowserFeatures(featureList) { } var validBrowser = checkBrowserFeatures([ - "displaytable", "flexbox", "es5object", "es5function", "foo" + "displaytable", "flexbox", "es5object", "es5function" ]); // We want to support some name / value pairs in the fragment From 511b1f409cf8eccacc5a172d1e28d0e4cdd14cca Mon Sep 17 00:00:00 2001 From: Kegan Dougal Date: Thu, 29 Oct 2015 15:56:03 +0000 Subject: [PATCH 3/4] Add objectfit and localstorage to browser features --- .modernizr.json | 4 +++- src/vector/index.js | 3 ++- src/vector/modernizr.js | 4 ++-- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/.modernizr.json b/.modernizr.json index 6d28fa8649..29e620a5ba 100644 --- a/.modernizr.json +++ b/.modernizr.json @@ -7,6 +7,8 @@ "feature-detects": [ "test/css/displaytable", "test/css/flexbox", - "test/es5/specification" + "test/es5/specification", + "test/css/objectfit", + "test/storage/localstorage" ] } \ No newline at end of file diff --git a/src/vector/index.js b/src/vector/index.js index 8567cc030c..298861973e 100644 --- a/src/vector/index.js +++ b/src/vector/index.js @@ -51,7 +51,8 @@ function checkBrowserFeatures(featureList) { } var validBrowser = checkBrowserFeatures([ - "displaytable", "flexbox", "es5object", "es5function" + "displaytable", "flexbox", "es5object", "es5function", "localstorage", + "objectfit" ]); // We want to support some name / value pairs in the fragment diff --git a/src/vector/modernizr.js b/src/vector/modernizr.js index f9641a763e..5ef7778aeb 100644 --- a/src/vector/modernizr.js +++ b/src/vector/modernizr.js @@ -1,3 +1,3 @@ /*! modernizr 3.1.0 (Custom Build) | MIT * - * http://modernizr.com/download/?-displaytable-es5-flexbox-cssclassprefix:modernizr_ !*/ -!function(window,document,undefined){function is(e,t){return typeof e===t}function testRunner(){var e,t,r,n,o,s,i;for(var d in tests){if(e=[],t=tests[d],t.name&&(e.push(t.name.toLowerCase()),t.options&&t.options.aliases&&t.options.aliases.length))for(r=0;rd;d++)if(l=e[d],c=mStyle.style[l],contains(l,"-")&&(l=cssToDOM(l)),mStyle.style[l]!==undefined){if(n||is(r,"undefined"))return o(),"pfx"==t?l:!0;try{mStyle.style[l]=r}catch(u){}if(mStyle.style[l]!=c)return o(),"pfx"==t?l:!0}return o(),!1}function fnBind(e,t){return function(){return e.apply(t,arguments)}}function testDOMProps(e,t,r){var n;for(var o in e)if(e[o]in t)return r===!1?e[o]:(n=t[e[o]],is(n,"function")?fnBind(n,r||t):n);return!1}function testPropsAll(e,t,r,n,o){var s=e.charAt(0).toUpperCase()+e.slice(1),i=(e+" "+cssomPrefixes.join(s+" ")+s).split(" ");return is(t,"string")||is(t,"undefined")?testProps(i,t,n,o):(i=(e+" "+domPrefixes.join(s+" ")+s).split(" "),testDOMProps(i,t,r))}function testAllProps(e,t,r){return testPropsAll(e,undefined,undefined,t,r)}var tests=[],ModernizrProto={_version:"3.1.0",_config:{classPrefix:"modernizr_",enableClasses:!0,enableJSClass:!0,usePrefixes:!0},_q:[],on:function(e,t){var r=this;setTimeout(function(){t(r[e])},0)},addTest:function(e,t,r){tests.push({name:e,fn:t,options:r})},addAsyncTest:function(e){tests.push({name:null,fn:e})}},Modernizr=function(){};Modernizr.prototype=ModernizrProto,Modernizr=new Modernizr;var classes=[],docElement=document.documentElement,isSVG="svg"===docElement.nodeName.toLowerCase(),testStyles=ModernizrProto.testStyles=injectElementWithStyles;testStyles("#modernizr{display: table; direction: ltr}#modernizr div{display: table-cell; padding: 10px}",function(e){var t,r=e.childNodes;t=r[0].offsetLeftd;d++)if(l=e[d],c=mStyle.style[l],contains(l,"-")&&(l=cssToDOM(l)),mStyle.style[l]!==undefined){if(n||is(r,"undefined"))return o(),"pfx"==t?l:!0;try{mStyle.style[l]=r}catch(u){}if(mStyle.style[l]!=c)return o(),"pfx"==t?l:!0}return o(),!1}function fnBind(e,t){return function(){return e.apply(t,arguments)}}function testDOMProps(e,t,r){var n;for(var o in e)if(e[o]in t)return r===!1?e[o]:(n=t[e[o]],is(n,"function")?fnBind(n,r||t):n);return!1}function testPropsAll(e,t,r,n,o){var s=e.charAt(0).toUpperCase()+e.slice(1),i=(e+" "+cssomPrefixes.join(s+" ")+s).split(" ");return is(t,"string")||is(t,"undefined")?testProps(i,t,n,o):(i=(e+" "+domPrefixes.join(s+" ")+s).split(" "),testDOMProps(i,t,r))}function testAllProps(e,t,r){return testPropsAll(e,undefined,undefined,t,r)}var tests=[],ModernizrProto={_version:"3.1.0",_config:{classPrefix:"modernizr_",enableClasses:!0,enableJSClass:!0,usePrefixes:!0},_q:[],on:function(e,t){var r=this;setTimeout(function(){t(r[e])},0)},addTest:function(e,t,r){tests.push({name:e,fn:t,options:r})},addAsyncTest:function(e){tests.push({name:null,fn:e})}},Modernizr=function(){};Modernizr.prototype=ModernizrProto,Modernizr=new Modernizr;var classes=[],docElement=document.documentElement,isSVG="svg"===docElement.nodeName.toLowerCase(),testStyles=ModernizrProto.testStyles=injectElementWithStyles;testStyles("#modernizr{display: table; direction: ltr}#modernizr div{display: table-cell; padding: 10px}",function(e){var t,r=e.childNodes;t=r[0].offsetLefto;o++){var s=prefixes[o],i=s.toUpperCase()+"_"+t;if(i in n)return"@-"+s.toLowerCase()+"-"+e}return!1};ModernizrProto.atRule=atRule;var prefixed=ModernizrProto.prefixed=function(e,t,r){return 0===e.indexOf("@")?atRule(e):(-1!=e.indexOf("-")&&(e=cssToDOM(e)),t?testPropsAll(e,t,r):testPropsAll(e,"pfx"))};Modernizr.addTest("objectfit",!!prefixed("objectFit"),{aliases:["object-fit"]}),Modernizr.addTest("localstorage",function(){var e="modernizr";try{return localStorage.setItem(e,e),localStorage.removeItem(e),!0}catch(t){return!1}}),testRunner(),setClasses(classes),delete ModernizrProto.addTest,delete ModernizrProto.addAsyncTest;for(var i=0;i Date: Fri, 30 Oct 2015 14:58:47 +0000 Subject: [PATCH 4/4] Review comments: add chrome blurb. --- src/skins/vector/views/pages/CompatibilityPage.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/skins/vector/views/pages/CompatibilityPage.js b/src/skins/vector/views/pages/CompatibilityPage.js index 610630dce4..129ed512bf 100644 --- a/src/skins/vector/views/pages/CompatibilityPage.js +++ b/src/skins/vector/views/pages/CompatibilityPage.js @@ -45,6 +45,10 @@ module.exports = React.createClass({ not be possible and all manner of chaos may be unleashed.

+ Please install Chrome for + the best experience. +

+

Though if you like taking risks with your life, you can still try it out by clicking that you understand the risks involved.