├── .gitignore ├── .rubocop.yml ├── .rubocop_todo.yml ├── .travis.yml ├── Gemfile ├── LICENSE ├── README.md ├── lib ├── loadcss-rails.rb └── loadcss │ ├── rails.rb │ └── rails │ ├── engine.rb │ └── version.rb ├── loadcss-rails.gemspec └── vendor └── assets └── javascripts ├── cssrelpreload.js ├── loadCSS.js └── onloadCSS.js /.gitignore: -------------------------------------------------------------------------------- 1 | pkg/* 2 | tmp 3 | spec/support/*/Gemfile.lock 4 | spec/support/*/public/javascripts 5 | .ruby-version 6 | .bundle 7 | imports/* 8 | Gemfile.lock -------------------------------------------------------------------------------- /.rubocop.yml: -------------------------------------------------------------------------------- 1 | inherit_from: .rubocop_todo.yml 2 | 3 | AllCops: 4 | Exclude: 5 | - '*.gemspec' 6 | - 'spec/*_helper.rb' 7 | - 'Gemfile' 8 | - 'Rakefile' 9 | 10 | Documentation: 11 | Enabled: false -------------------------------------------------------------------------------- /.rubocop_todo.yml: -------------------------------------------------------------------------------- 1 | # This configuration was generated by 2 | # `rubocop --auto-gen-config` 3 | # on 2015-09-19 15:48:15 -0500 using RuboCop version 0.34.1. 4 | # The point is for the user to remove these configuration records 5 | # one by one as the offenses are removed from the code base. 6 | # Note that changes in the inspected code, or installation of new 7 | # versions of RuboCop, may require this file to be generated again. 8 | 9 | # Offense count: 1 10 | # Configuration parameters: Exclude. 11 | Style/FileName: 12 | Exclude: 13 | - 'lib/loadcss-rails.rb' 14 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: ruby 2 | rvm: 3 | - 2.0.0 4 | - 2.1.7 5 | - 2.2.3 -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | # A sample Gemfile 2 | source 'https://rubygems.org' 3 | 4 | gem 'rubocop', require: false 5 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) [2015] [Michael Misshore] 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # loadcss-rails [![Code Climate](https://codeclimate.com/github/michael-misshore/loadcss-rails/badges/gpa.svg)](https://codeclimate.com/github/michael-misshore/loadcss-rails) 2 | 3 | loadCSS (and onloadCSS) for Rails! Load CSS asynchronously! 4 | 5 | This gem provides: 6 | 7 | * loadCSS and onloadCSS 8 | 9 | These pieces of javascript were implemented by [Filament Group](https://github.com/filamentgroup/loadCSS/) 10 | 11 | ## Installation 12 | 13 | ``` 14 | gem 'loadcss-rails', '~> 2.0.1' 15 | ``` 16 | 17 | The loadCSS and onloadCSS files will be added to the asset pipeline and available for you to use. Add the lines that you need to your application's JS manifest (usually `app/assets/javascripts/application.js`). 18 | 19 | ```js 20 | //= require loadCSS 21 | //= require cssrelpreload 22 | //= require onloadCSS 23 | ``` 24 | 25 | ## Usage 26 | 27 | Here's a quick example of what you would drop in your application's layout (usually `app/views/layouts/application.html.erb`): 28 | 29 | ```html 30 | 31 | 32 | ``` 33 | 34 | More examples may be found here: [loadCSS](https://github.com/filamentgroup/loadCSS/) 35 | 36 | 37 | ## Versions 38 | 39 | The loadcss-rails gem follows these version guidelines to provide more control over your app's loadCSS version from your Gemfile: 40 | 41 | ``` 42 | patch version bump = updates to loadcss-rails and patch-level updates to loadCSS 43 | minor version bump = minor-level updates to loadCSS 44 | major version bump = major-level updates to loadCSS and updates to Rails which may be backwards-incompatible 45 | ``` 46 | 47 | ## Contributing 48 | 49 | Feel free to open an issue ticket if you find something that could be improved. A couple notes: 50 | 51 | * If the loadCSS scripts are outdated (i.e. maybe a new version of loadCSS was released yesterday), feel free to open an issue and prod us to get that thing updated. However, for security reasons, we won't be accepting pull requests with updated loadCSS scripts. 52 | 53 | Copyright Michael Misshore, released under the MIT License. 54 | -------------------------------------------------------------------------------- /lib/loadcss-rails.rb: -------------------------------------------------------------------------------- 1 | require 'loadcss/rails' 2 | -------------------------------------------------------------------------------- /lib/loadcss/rails.rb: -------------------------------------------------------------------------------- 1 | require 'loadcss/rails/engine' 2 | require 'loadcss/rails/version' 3 | 4 | module LoadCSS 5 | module Rails 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /lib/loadcss/rails/engine.rb: -------------------------------------------------------------------------------- 1 | module LoadCSS 2 | module Rails 3 | class Engine < ::Rails::Engine 4 | end 5 | end 6 | end 7 | -------------------------------------------------------------------------------- /lib/loadcss/rails/version.rb: -------------------------------------------------------------------------------- 1 | module LoadCSS 2 | module Rails 3 | VERSION = '2.0.1' 4 | LOADCSS_VERSION = '2.0.1' 5 | end 6 | end 7 | -------------------------------------------------------------------------------- /loadcss-rails.gemspec: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | require File.expand_path('../lib/loadcss/rails/version', __FILE__) 3 | 4 | Gem::Specification.new do |s| 5 | s.name = "loadcss-rails" 6 | s.version = LoadCSS::Rails::VERSION 7 | s.platform = Gem::Platform::RUBY 8 | s.authors = ["Michael Misshore"] 9 | s.email = ["mmisshore@gmail.com"] 10 | s.summary = "Use LoadCSS and OnloadCSS with Rails" 11 | s.description = "This gem provides LoadCSS and OnloadCSS for your Rails application." 12 | s.license = "MIT" 13 | 14 | # s.required_ruby_version = ">= 1.9.3" 15 | # s.required_rubygems_version = ">= 1.3.6" 16 | 17 | s.files = `git ls-files`.split("\n") 18 | s.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) } 19 | s.require_path = 'lib' 20 | end -------------------------------------------------------------------------------- /vendor/assets/javascripts/cssrelpreload.js: -------------------------------------------------------------------------------- 1 | /*! loadCSS. [c]2017 Filament Group, Inc. MIT License */ 2 | /* This file is meant as a standalone workflow for 3 | - testing support for link[rel=preload] 4 | - enabling async CSS loading in browsers that do not support rel=preload 5 | - applying rel preload css once loaded, whether supported or not. 6 | */ 7 | (function( w ){ 8 | "use strict"; 9 | // rel=preload support test 10 | if( !w.loadCSS ){ 11 | w.loadCSS = function(){}; 12 | } 13 | // define on the loadCSS obj 14 | var rp = loadCSS.relpreload = {}; 15 | // rel=preload feature support test 16 | // runs once and returns a function for compat purposes 17 | rp.support = (function(){ 18 | var ret; 19 | try { 20 | ret = w.document.createElement( "link" ).relList.supports( "preload" ); 21 | } catch (e) { 22 | ret = false; 23 | } 24 | return function(){ 25 | return ret; 26 | }; 27 | })(); 28 | 29 | // if preload isn't supported, get an asynchronous load by using a non-matching media attribute 30 | // then change that media back to its intended value on load 31 | rp.bindMediaToggle = function( link ){ 32 | // remember existing media attr for ultimate state, or default to 'all' 33 | var finalMedia = link.media || "all"; 34 | 35 | function enableStylesheet(){ 36 | link.media = finalMedia; 37 | } 38 | 39 | // bind load handlers to enable media 40 | if( link.addEventListener ){ 41 | link.addEventListener( "load", enableStylesheet ); 42 | } else if( link.attachEvent ){ 43 | link.attachEvent( "onload", enableStylesheet ); 44 | } 45 | 46 | // Set rel and non-applicable media type to start an async request 47 | // note: timeout allows this to happen async to let rendering continue in IE 48 | setTimeout(function(){ 49 | link.rel = "stylesheet"; 50 | link.media = "only x"; 51 | }); 52 | // also enable media after 3 seconds, 53 | // which will catch very old browsers (android 2.x, old firefox) that don't support onload on link 54 | setTimeout( enableStylesheet, 3000 ); 55 | }; 56 | 57 | // loop through link elements in DOM 58 | rp.poly = function(){ 59 | // double check this to prevent external calls from running 60 | if( rp.support() ){ 61 | return; 62 | } 63 | var links = w.document.getElementsByTagName( "link" ); 64 | for( var i = 0; i < links.length; i++ ){ 65 | var link = links[ i ]; 66 | // qualify links to those with rel=preload and as=style attrs 67 | if( link.rel === "preload" && link.getAttribute( "as" ) === "style" && !link.getAttribute( "data-loadcss" ) ){ 68 | // prevent rerunning on link 69 | link.setAttribute( "data-loadcss", true ); 70 | // bind listeners to toggle media back 71 | rp.bindMediaToggle( link ); 72 | } 73 | } 74 | }; 75 | 76 | // if unsupported, run the polyfill 77 | if( !rp.support() ){ 78 | // run once at least 79 | rp.poly(); 80 | 81 | // rerun poly on an interval until onload 82 | var run = w.setInterval( rp.poly, 500 ); 83 | if( w.addEventListener ){ 84 | w.addEventListener( "load", function(){ 85 | rp.poly(); 86 | w.clearInterval( run ); 87 | } ); 88 | } else if( w.attachEvent ){ 89 | w.attachEvent( "onload", function(){ 90 | rp.poly(); 91 | w.clearInterval( run ); 92 | } ); 93 | } 94 | } 95 | 96 | 97 | // commonjs 98 | if( typeof exports !== "undefined" ){ 99 | exports.loadCSS = loadCSS; 100 | } 101 | else { 102 | w.loadCSS = loadCSS; 103 | } 104 | }( typeof global !== "undefined" ? global : this ) ); -------------------------------------------------------------------------------- /vendor/assets/javascripts/loadCSS.js: -------------------------------------------------------------------------------- 1 | /*! loadCSS. [c]2017 Filament Group, Inc. MIT License */ 2 | (function(w){ 3 | "use strict"; 4 | /* exported loadCSS */ 5 | var loadCSS = function( href, before, media ){ 6 | // Arguments explained: 7 | // `href` [REQUIRED] is the URL for your CSS file. 8 | // `before` [OPTIONAL] is the element the script should use as a reference for injecting our stylesheet before 9 | // By default, loadCSS attempts to inject the link after the last stylesheet or script in the DOM. However, you might desire a more specific location in your document. 10 | // `media` [OPTIONAL] is the media type or query of the stylesheet. By default it will be 'all' 11 | var doc = w.document; 12 | var ss = doc.createElement( "link" ); 13 | var ref; 14 | if( before ){ 15 | ref = before; 16 | } 17 | else { 18 | var refs = ( doc.body || doc.getElementsByTagName( "head" )[ 0 ] ).childNodes; 19 | ref = refs[ refs.length - 1]; 20 | } 21 | 22 | var sheets = doc.styleSheets; 23 | ss.rel = "stylesheet"; 24 | ss.href = href; 25 | // temporarily set media to something inapplicable to ensure it'll fetch without blocking render 26 | ss.media = "only x"; 27 | 28 | // wait until body is defined before injecting link. This ensures a non-blocking load in IE11. 29 | function ready( cb ){ 30 | if( doc.body ){ 31 | return cb(); 32 | } 33 | setTimeout(function(){ 34 | ready( cb ); 35 | }); 36 | } 37 | // Inject link 38 | // Note: the ternary preserves the existing behavior of "before" argument, but we could choose to change the argument to "after" in a later release and standardize on ref.nextSibling for all refs 39 | // Note: `insertBefore` is used instead of `appendChild`, for safety re: http://www.paulirish.com/2011/surefire-dom-element-insertion/ 40 | ready( function(){ 41 | ref.parentNode.insertBefore( ss, ( before ? ref : ref.nextSibling ) ); 42 | }); 43 | // A method (exposed on return object for external use) that mimics onload by polling document.styleSheets until it includes the new sheet. 44 | var onloadcssdefined = function( cb ){ 45 | var resolvedHref = ss.href; 46 | var i = sheets.length; 47 | while( i-- ){ 48 | if( sheets[ i ].href === resolvedHref ){ 49 | return cb(); 50 | } 51 | } 52 | setTimeout(function() { 53 | onloadcssdefined( cb ); 54 | }); 55 | }; 56 | 57 | function loadCB(){ 58 | if( ss.addEventListener ){ 59 | ss.removeEventListener( "load", loadCB ); 60 | } 61 | ss.media = media || "all"; 62 | } 63 | 64 | // once loaded, set link's media back to `all` so that the stylesheet applies once it loads 65 | if( ss.addEventListener ){ 66 | ss.addEventListener( "load", loadCB); 67 | } 68 | ss.onloadcssdefined = onloadcssdefined; 69 | onloadcssdefined( loadCB ); 70 | return ss; 71 | }; 72 | // commonjs 73 | if( typeof exports !== "undefined" ){ 74 | exports.loadCSS = loadCSS; 75 | } 76 | else { 77 | w.loadCSS = loadCSS; 78 | } 79 | }( typeof global !== "undefined" ? global : this )); -------------------------------------------------------------------------------- /vendor/assets/javascripts/onloadCSS.js: -------------------------------------------------------------------------------- 1 | /*! onloadCSS. (onload callback for loadCSS) [c]2017 Filament Group, Inc. MIT License */ 2 | /* global navigator */ 3 | /* exported onloadCSS */ 4 | function onloadCSS( ss, callback ) { 5 | var called; 6 | function newcb(){ 7 | if( !called && callback ){ 8 | called = true; 9 | callback.call( ss ); 10 | } 11 | } 12 | if( ss.addEventListener ){ 13 | ss.addEventListener( "load", newcb ); 14 | } 15 | if( ss.attachEvent ){ 16 | ss.attachEvent( "onload", newcb ); 17 | } 18 | 19 | // This code is for browsers that don’t support onload 20 | // No support for onload (it'll bind but never fire): 21 | // * Android 4.3 (Samsung Galaxy S4, Browserstack) 22 | // * Android 4.2 Browser (Samsung Galaxy SIII Mini GT-I8200L) 23 | // * Android 2.3 (Pantech Burst P9070) 24 | 25 | // Weak inference targets Android < 4.4 26 | if( "isApplicationInstalled" in navigator && "onloadcssdefined" in ss ) { 27 | ss.onloadcssdefined( newcb ); 28 | } 29 | } --------------------------------------------------------------------------------