twbs_sass_rails 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (143) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +12 -0
  3. data/CONTRIBUTING.md +45 -0
  4. data/Gemfile +3 -0
  5. data/Gemfile.lock +142 -0
  6. data/LICENSE +30 -0
  7. data/README.md +138 -0
  8. data/Rakefile +108 -0
  9. data/VERSION +1 -0
  10. data/app/assets/fonts/fontawesome-webfont.eot +0 -0
  11. data/app/assets/fonts/fontawesome-webfont.svg +399 -0
  12. data/app/assets/fonts/fontawesome-webfont.ttf +0 -0
  13. data/app/assets/fonts/fontawesome-webfont.woff +0 -0
  14. data/app/assets/fonts/glyphicons-halflings-regular.eot +0 -0
  15. data/app/assets/fonts/glyphicons-halflings-regular.svg +228 -0
  16. data/app/assets/fonts/glyphicons-halflings-regular.ttf +0 -0
  17. data/app/assets/fonts/glyphicons-halflings-regular.woff +0 -0
  18. data/gemfiles/Gemfile.rails-3.2.x +9 -0
  19. data/gemfiles/Gemfile.rails-4.0.x +9 -0
  20. data/lib/generators/twbs_sass_rails/install/install_generator.rb +31 -0
  21. data/lib/generators/twbs_sass_rails/install/templates/application.css +15 -0
  22. data/lib/generators/twbs_sass_rails/install/templates/application.js +17 -0
  23. data/lib/generators/twbs_sass_rails/install/templates/twbs-variables.css.less +5 -0
  24. data/lib/generators/twbs_sass_rails/install/templates/twbs.css.less +10 -0
  25. data/lib/generators/twbs_sass_rails/install/templates/twbs.js.coffee +7 -0
  26. data/lib/tasks/twbs_sass_rails_tasks.rake +4 -0
  27. data/lib/twbs_sass_rails/engine.rb +7 -0
  28. data/lib/twbs_sass_rails/version.rb +3 -0
  29. data/lib/twbs_sass_rails.rb +4 -0
  30. data/test/dummy/README.rdoc +28 -0
  31. data/test/dummy/Rakefile +6 -0
  32. data/test/dummy/app/assets/images/.keep +0 -0
  33. data/test/dummy/app/assets/javascripts/application.js +14 -0
  34. data/test/dummy/app/assets/stylesheets/application.css +15 -0
  35. data/test/dummy/app/assets/stylesheets/default-twbs.css.less +1 -0
  36. data/test/dummy/app/assets/stylesheets/test.css.less +5 -0
  37. data/test/dummy/app/assets/stylesheets/twbs-variables.css.less +6 -0
  38. data/test/dummy/app/assets/stylesheets/twbs.css.less +10 -0
  39. data/test/dummy/app/controllers/application_controller.rb +5 -0
  40. data/test/dummy/app/controllers/concerns/.keep +0 -0
  41. data/test/dummy/app/helpers/application_helper.rb +2 -0
  42. data/test/dummy/app/mailers/.keep +0 -0
  43. data/test/dummy/app/models/.keep +0 -0
  44. data/test/dummy/app/models/concerns/.keep +0 -0
  45. data/test/dummy/app/views/layouts/application.html.erb +14 -0
  46. data/test/dummy/bin/bundle +3 -0
  47. data/test/dummy/bin/rails +4 -0
  48. data/test/dummy/bin/rake +4 -0
  49. data/test/dummy/config/application.rb +27 -0
  50. data/test/dummy/config/boot.rb +5 -0
  51. data/test/dummy/config/database.yml +25 -0
  52. data/test/dummy/config/environment.rb +5 -0
  53. data/test/dummy/config/environments/development.rb +29 -0
  54. data/test/dummy/config/environments/production.rb +80 -0
  55. data/test/dummy/config/environments/test.rb +36 -0
  56. data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
  57. data/test/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  58. data/test/dummy/config/initializers/inflections.rb +16 -0
  59. data/test/dummy/config/initializers/mime_types.rb +5 -0
  60. data/test/dummy/config/initializers/secret_token.rb +18 -0
  61. data/test/dummy/config/initializers/session_store.rb +3 -0
  62. data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
  63. data/test/dummy/config/locales/en.yml +23 -0
  64. data/test/dummy/config/routes.rb +56 -0
  65. data/test/dummy/config.ru +4 -0
  66. data/test/dummy/db/.keep +0 -0
  67. data/test/dummy/lib/assets/.keep +0 -0
  68. data/test/dummy/log/.keep +0 -0
  69. data/test/dummy/public/404.html +58 -0
  70. data/test/dummy/public/422.html +58 -0
  71. data/test/dummy/public/500.html +57 -0
  72. data/test/dummy/public/favicon.ico +0 -0
  73. data/test/generators/default_rails_assets/application.css +13 -0
  74. data/test/generators/default_rails_assets/application.js +16 -0
  75. data/test/generators/install_generator_test.rb +47 -0
  76. data/test/integration/assets_precompile_integration_test.rb +49 -0
  77. data/test/integration/twbs_sass_rails_integration_test.rb +37 -0
  78. data/test/test_helper.rb +38 -0
  79. data/twbs_sass_rails.gemspec +34 -0
  80. data/vendor/assets/javascripts/respond.js +342 -0
  81. data/vendor/assets/javascripts/twbs/bootstrap/affix.js +126 -0
  82. data/vendor/assets/javascripts/twbs/bootstrap/alert.js +98 -0
  83. data/vendor/assets/javascripts/twbs/bootstrap/button.js +109 -0
  84. data/vendor/assets/javascripts/twbs/bootstrap/carousel.js +217 -0
  85. data/vendor/assets/javascripts/twbs/bootstrap/collapse.js +179 -0
  86. data/vendor/assets/javascripts/twbs/bootstrap/dropdown.js +154 -0
  87. data/vendor/assets/javascripts/twbs/bootstrap/modal.js +246 -0
  88. data/vendor/assets/javascripts/twbs/bootstrap/popover.js +117 -0
  89. data/vendor/assets/javascripts/twbs/bootstrap/scrollspy.js +158 -0
  90. data/vendor/assets/javascripts/twbs/bootstrap/tab.js +135 -0
  91. data/vendor/assets/javascripts/twbs/bootstrap/tooltip.js +386 -0
  92. data/vendor/assets/javascripts/twbs/bootstrap/transition.js +56 -0
  93. data/vendor/assets/javascripts/twbs/bootstrap.js +12 -0
  94. data/vendor/assets/stylesheets/fontawesome/bootstrap.less +84 -0
  95. data/vendor/assets/stylesheets/fontawesome/core.less +129 -0
  96. data/vendor/assets/stylesheets/fontawesome/extras.less +93 -0
  97. data/vendor/assets/stylesheets/fontawesome/font-awesome.less +33 -0
  98. data/vendor/assets/stylesheets/fontawesome/icons.less +381 -0
  99. data/vendor/assets/stylesheets/fontawesome/mixins.less +48 -0
  100. data/vendor/assets/stylesheets/fontawesome/path.less +14 -0
  101. data/vendor/assets/stylesheets/fontawesome/variables.less +735 -0
  102. data/vendor/assets/stylesheets/twbs/bootstrap/alerts.less +67 -0
  103. data/vendor/assets/stylesheets/twbs/bootstrap/badges.less +51 -0
  104. data/vendor/assets/stylesheets/twbs/bootstrap/bootstrap.less +58 -0
  105. data/vendor/assets/stylesheets/twbs/bootstrap/breadcrumbs.less +23 -0
  106. data/vendor/assets/stylesheets/twbs/bootstrap/button-groups.less +248 -0
  107. data/vendor/assets/stylesheets/twbs/bootstrap/buttons.less +160 -0
  108. data/vendor/assets/stylesheets/twbs/bootstrap/carousel.less +209 -0
  109. data/vendor/assets/stylesheets/twbs/bootstrap/close.less +33 -0
  110. data/vendor/assets/stylesheets/twbs/bootstrap/code.less +56 -0
  111. data/vendor/assets/stylesheets/twbs/bootstrap/component-animations.less +29 -0
  112. data/vendor/assets/stylesheets/twbs/bootstrap/dropdowns.less +193 -0
  113. data/vendor/assets/stylesheets/twbs/bootstrap/forms.less +362 -0
  114. data/vendor/assets/stylesheets/twbs/bootstrap/glyphicons.less +236 -0
  115. data/vendor/assets/stylesheets/twbs/bootstrap/grid.less +346 -0
  116. data/vendor/assets/stylesheets/twbs/bootstrap/input-groups.less +127 -0
  117. data/vendor/assets/stylesheets/twbs/bootstrap/jumbotron.less +40 -0
  118. data/vendor/assets/stylesheets/twbs/bootstrap/labels.less +58 -0
  119. data/vendor/assets/stylesheets/twbs/bootstrap/list-group.less +88 -0
  120. data/vendor/assets/stylesheets/twbs/bootstrap/media.less +56 -0
  121. data/vendor/assets/stylesheets/twbs/bootstrap/mixins.less +744 -0
  122. data/vendor/assets/stylesheets/twbs/bootstrap/modals.less +141 -0
  123. data/vendor/assets/stylesheets/twbs/bootstrap/navbar.less +621 -0
  124. data/vendor/assets/stylesheets/twbs/bootstrap/navs.less +248 -0
  125. data/vendor/assets/stylesheets/twbs/bootstrap/normalize.less +396 -0
  126. data/vendor/assets/stylesheets/twbs/bootstrap/pager.less +55 -0
  127. data/vendor/assets/stylesheets/twbs/bootstrap/pagination.less +85 -0
  128. data/vendor/assets/stylesheets/twbs/bootstrap/panels.less +148 -0
  129. data/vendor/assets/stylesheets/twbs/bootstrap/popovers.less +133 -0
  130. data/vendor/assets/stylesheets/twbs/bootstrap/print.less +100 -0
  131. data/vendor/assets/stylesheets/twbs/bootstrap/progress-bars.less +95 -0
  132. data/vendor/assets/stylesheets/twbs/bootstrap/responsive-utilities.less +220 -0
  133. data/vendor/assets/stylesheets/twbs/bootstrap/scaffolding.less +130 -0
  134. data/vendor/assets/stylesheets/twbs/bootstrap/tables.less +238 -0
  135. data/vendor/assets/stylesheets/twbs/bootstrap/theme.less +241 -0
  136. data/vendor/assets/stylesheets/twbs/bootstrap/thumbnails.less +32 -0
  137. data/vendor/assets/stylesheets/twbs/bootstrap/tooltip.less +95 -0
  138. data/vendor/assets/stylesheets/twbs/bootstrap/type.less +242 -0
  139. data/vendor/assets/stylesheets/twbs/bootstrap/utilities.less +42 -0
  140. data/vendor/assets/stylesheets/twbs/bootstrap/variables.less +628 -0
  141. data/vendor/assets/stylesheets/twbs/bootstrap/wells.less +29 -0
  142. data/vendor/assets/stylesheets/twbs/bootstrap.less +1 -0
  143. metadata +388 -0
@@ -0,0 +1,47 @@
1
+ require 'test_helper'
2
+
3
+ class InstallGeneratorTest < ::Rails::Generators::TestCase
4
+ tests TwbsSassRails::Generators::InstallGenerator
5
+
6
+ destination File.expand_path('../../tmp', File.dirname(__FILE__))
7
+ setup :prepare_destination
8
+
9
+ test "Assert all files are properly created" do
10
+ run_generator
11
+ assert_file 'app/assets/stylesheets/application.css'
12
+ assert_file 'app/assets/stylesheets/twbs-variables.css.less' do |file_content|
13
+ template_file = File.expand_path('../../lib/generators/twbs_sass_rails/install/templates/twbs-variables.css.less', File.dirname(__FILE__))
14
+ assert_match file_content, File.read(template_file)
15
+ end
16
+ assert_file 'app/assets/stylesheets/twbs.css.less' do |file_content|
17
+ template_file = File.expand_path('../../lib/generators/twbs_sass_rails/install/templates/twbs.css.less', File.dirname(__FILE__))
18
+ assert_match file_content, File.read(template_file)
19
+ end
20
+ assert_file 'app/assets/javascripts/application.js'
21
+ assert_file 'app/assets/javascripts/twbs.js.coffee' do |file_content|
22
+ template_file = File.expand_path('../../lib/generators/twbs_sass_rails/install/templates/twbs.js.coffee', File.dirname(__FILE__))
23
+ assert_match file_content, File.read(template_file)
24
+ end
25
+ end
26
+
27
+ test "Assert existing application.css properly requires bootstrap" do
28
+ copy_default_asset 'application.css', 'stylesheets'
29
+ run_generator
30
+ assert_file 'app/assets/stylesheets/application.css', /^ \*\= stub twbs-variables$/
31
+ assert_file 'app/assets/stylesheets/application.css', /^ \*\= require twbs$/
32
+ end
33
+
34
+ test "Assert existing application.js properly requires bootstrap" do
35
+ copy_default_asset 'application.js', 'javascripts'
36
+ run_generator
37
+ assert_file 'app/assets/javascripts/application.js', /^\/\/\= require twbs\/bootstrap$/
38
+ end
39
+
40
+ def copy_default_asset(asset_name, asset_dir)
41
+ asset = File.expand_path("default_rails_assets/#{asset_name}", File.dirname(__FILE__))
42
+ destination = File.join(destination_root, "app/assets/#{asset_dir}")
43
+
44
+ FileUtils.mkdir_p(destination)
45
+ FileUtils.cp asset, destination
46
+ end
47
+ end
@@ -0,0 +1,49 @@
1
+ require 'test_helper'
2
+
3
+ describe "assets precompile in production environment integration" do
4
+ FileUtils::rm_rf 'test/dummy/public/assets'
5
+ system 'cd test/dummy && RAILS_ENV=production rake assets:precompile'
6
+
7
+ it "provides respond.js" do
8
+ visit "/assets/#{get_asset_name('respond','js')}"
9
+ end
10
+
11
+ it "provides fontawesome" do
12
+ ['eot', 'svg', 'ttf', 'woff'].each do |fmt|
13
+ font_file = get_asset_name('fontawesome-webfont', fmt)
14
+ # NOTE: Rails 3 skips fingerprint when asset has parameters.
15
+ font_file = 'fontawesome-webfont.svg' if Rails.version.start_with?('3')
16
+ visit "/assets/#{font_file}"
17
+ visit "/assets/#{get_asset_name('application', 'css')}"
18
+ page.text.must_include font_file
19
+ page.text.must_include "#{font_file}?\#iefix" if fmt == 'eot' && Rails.version.start_with?('4')
20
+ end
21
+ end
22
+
23
+ it "provides glyphicons" do
24
+ ['eot', 'svg', 'ttf', 'woff'].each do |fmt|
25
+ font_file = get_asset_name('glyphicons-halflings-regular', fmt)
26
+ # NOTE: Rails 3 skips fingerprint when asset has parameters.
27
+ font_file = 'glyphicons-halflings-regular.svg' if Rails.version.start_with?('3')
28
+ visit "/assets/#{font_file}"
29
+ visit "/assets/#{get_asset_name('application', 'css')}"
30
+ page.text.must_include font_file
31
+ page.text.must_include "#{font_file}?\#iefix" if fmt == 'eot' && Rails.version.start_with?('4')
32
+ end
33
+ end
34
+
35
+ it "overrides Bootstrap variables" do
36
+ visit "/assets/#{get_asset_name('application', 'css')}"
37
+ page.text.must_include 'color: #d10d10;'
38
+ end
39
+
40
+ it "overrides Bootstrap variables in user stylesheets" do
41
+ visit "/assets/#{get_asset_name('application', 'css')}"
42
+ page.text.must_include '.test-class { color: #d10d10; }'
43
+ end
44
+
45
+ private
46
+ def get_asset_name(asset_name, asset_ext)
47
+ Dir::glob("test/dummy/public/assets/#{asset_name}-*.#{asset_ext}").first.split('/').last
48
+ end
49
+ end
@@ -0,0 +1,37 @@
1
+ require 'test_helper'
2
+
3
+ describe "twbs sass rails integration" do
4
+ it "does not default to glyphicons" do
5
+ visit '/assets/default-twbs.css'
6
+ page.text.wont_include 'glyphicons'
7
+ end
8
+
9
+ it "provides bootstrap stylesheet on the asset pipeline" do
10
+ visit '/assets/application.css'
11
+ page.text.must_include '* Bootstrap'
12
+ end
13
+
14
+ it "provides bootstrap javscript on the asset pipeline" do
15
+ visit '/assets/application.js'
16
+ page.text.must_include '* Bootstrap'
17
+ end
18
+
19
+ it "provides respond.js on the asset pipeline" do
20
+ visit '/assets/respond.js'
21
+ page.text.must_include 'Respond.js'
22
+ end
23
+
24
+ it "provides fontawesome on the asset pipeline" do
25
+ visit '/assets/fontawesome-webfont.eot'
26
+ visit '/assets/fontawesome-webfont.svg'
27
+ visit '/assets/fontawesome-webfont.ttf'
28
+ visit '/assets/fontawesome-webfont.woff'
29
+ end
30
+
31
+ it "provides glyphicons on the asset pipeline" do
32
+ visit '/assets/glyphicons-halflings-regular.eot'
33
+ visit '/assets/glyphicons-halflings-regular.svg'
34
+ visit '/assets/glyphicons-halflings-regular.ttf'
35
+ visit '/assets/glyphicons-halflings-regular.woff'
36
+ end
37
+ end
@@ -0,0 +1,38 @@
1
+ # Configure Rails Environment
2
+ ENV['RAILS_ENV'] = 'test'
3
+
4
+ if ENV['CI']
5
+ require 'coveralls'
6
+ Coveralls.wear!
7
+ else
8
+ require 'simplecov'
9
+ SimpleCov.start 'rails'
10
+ end
11
+
12
+ require File.expand_path('../dummy/config/environment.rb', __FILE__)
13
+
14
+ require 'rails/test_help'
15
+ Rails.backtrace_cleaner.remove_silencers!
16
+
17
+ require 'minitest/autorun'
18
+ require 'capybara/rails'
19
+
20
+ require 'debugger'
21
+ Debugger.settings[:autoeval] = true
22
+
23
+ require 'turn'
24
+ Turn.config.format = :cool
25
+ Turn.config.natural = true
26
+ Turn.config.verbose = true
27
+
28
+ # Load support files
29
+ Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f }
30
+
31
+ # For generators
32
+ require 'rails/generators/test_case'
33
+ require 'generators/twbs_sass_rails/install/install_generator'
34
+
35
+ class IntegrationTest < MiniTest::Spec
36
+ include Capybara::DSL
37
+ register_spec_type(/integration$/, self)
38
+ end
@@ -0,0 +1,34 @@
1
+ $:.push File.expand_path('../lib', __FILE__)
2
+
3
+ # Maintain your gem's version:
4
+ require 'twbs_sass_rails/version'
5
+
6
+ # Describe your gem and declare its dependencies:
7
+ Gem::Specification.new do |s|
8
+ s.name = 'twbs_sass_rails'
9
+ s.version = TwbsSassRails::VERSION
10
+ s.authors = ['diowa']
11
+ s.email = ['dev@diowa.com']
12
+ s.homepage = 'https://github.com/diowa/twbs_sass_rails'
13
+ s.summary = 'Bootstrap Sass assets in a Rails application.'
14
+ s.description = s.summary
15
+ s.license = 'BSD 2-Clause'
16
+
17
+ s.files = `git ls-files`.split("\n") - `git ls-files -- {src/*,".*"}`.split("\n")
18
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
19
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
20
+ s.require_paths = ['lib']
21
+
22
+ s.add_runtime_dependency 'rails', '>= 3.2.14'
23
+ s.add_runtime_dependency 'therubyracer'
24
+ s.add_runtime_dependency 'less-rails'
25
+
26
+ s.add_development_dependency 'capybara'
27
+ s.add_development_dependency 'coveralls'
28
+ s.add_development_dependency 'debugger'
29
+ s.add_development_dependency 'minitest', '~> 4'
30
+ s.add_development_dependency 'rake'
31
+ s.add_development_dependency 'simplecov'
32
+ s.add_development_dependency 'sqlite3'
33
+ s.add_development_dependency 'turn'
34
+ end
@@ -0,0 +1,342 @@
1
+ /*! matchMedia() polyfill - Test a CSS media type/query in JS. Authors & copyright (c) 2012: Scott Jehl, Paul Irish, Nicholas Zakas. Dual MIT/BSD license */
2
+ /*! NOTE: If you're already including a window.matchMedia polyfill via Modernizr or otherwise, you don't need this part */
3
+
4
+ window.matchMedia = window.matchMedia || (function( doc, undefined ) {
5
+
6
+ "use strict";
7
+
8
+ var bool,
9
+ docElem = doc.documentElement,
10
+ refNode = docElem.firstElementChild || docElem.firstChild,
11
+ // fakeBody required for <FF4 when executed in <head>
12
+ fakeBody = doc.createElement( "body" ),
13
+ div = doc.createElement( "div" );
14
+
15
+ div.id = "mq-test-1";
16
+ div.style.cssText = "position:absolute;top:-100em";
17
+ fakeBody.style.background = "none";
18
+ fakeBody.appendChild(div);
19
+
20
+ return function(q){
21
+
22
+ div.innerHTML = "&shy;<style media=\"" + q + "\"> #mq-test-1 { width: 42px; }</style>";
23
+
24
+ docElem.insertBefore( fakeBody, refNode );
25
+ bool = div.offsetWidth === 42;
26
+ docElem.removeChild( fakeBody );
27
+
28
+ return {
29
+ matches: bool,
30
+ media: q
31
+ };
32
+
33
+ };
34
+
35
+ }( document ));
36
+
37
+
38
+
39
+
40
+
41
+ /*! Respond.js v1.3.0: min/max-width media query polyfill. (c) Scott Jehl. MIT/GPLv2 Lic. j.mp/respondjs */
42
+ (function( win ){
43
+
44
+ "use strict";
45
+
46
+ //exposed namespace
47
+ var respond = {};
48
+ win.respond = respond;
49
+
50
+ //define update even in native-mq-supporting browsers, to avoid errors
51
+ respond.update = function(){};
52
+
53
+ //expose media query support flag for external use
54
+ respond.mediaQueriesSupported = win.matchMedia && win.matchMedia( "only all" ).matches;
55
+
56
+ //if media queries are supported, exit here
57
+ if( respond.mediaQueriesSupported ){
58
+ return;
59
+ }
60
+
61
+ //define vars
62
+ var doc = win.document,
63
+ docElem = doc.documentElement,
64
+ mediastyles = [],
65
+ rules = [],
66
+ appendedEls = [],
67
+ parsedSheets = {},
68
+ resizeThrottle = 30,
69
+ head = doc.getElementsByTagName( "head" )[0] || docElem,
70
+ base = doc.getElementsByTagName( "base" )[0],
71
+ links = head.getElementsByTagName( "link" ),
72
+ requestQueue = [],
73
+
74
+ //loop stylesheets, send text content to translate
75
+ ripCSS = function(){
76
+
77
+ for( var i = 0; i < links.length; i++ ){
78
+ var sheet = links[ i ],
79
+ href = sheet.href,
80
+ media = sheet.media,
81
+ isCSS = sheet.rel && sheet.rel.toLowerCase() === "stylesheet";
82
+
83
+ //only links plz and prevent re-parsing
84
+ if( !!href && isCSS && !parsedSheets[ href ] ){
85
+ // selectivizr exposes css through the rawCssText expando
86
+ if (sheet.styleSheet && sheet.styleSheet.rawCssText) {
87
+ translate( sheet.styleSheet.rawCssText, href, media );
88
+ parsedSheets[ href ] = true;
89
+ } else {
90
+ if( (!/^([a-zA-Z:]*\/\/)/.test( href ) && !base) ||
91
+ href.replace( RegExp.$1, "" ).split( "/" )[0] === win.location.host ){
92
+ requestQueue.push( {
93
+ href: href,
94
+ media: media
95
+ } );
96
+ }
97
+ }
98
+ }
99
+ }
100
+ makeRequests();
101
+ },
102
+
103
+ //recurse through request queue, get css text
104
+ makeRequests = function(){
105
+ if( requestQueue.length ){
106
+ var thisRequest = requestQueue.shift();
107
+
108
+ ajax( thisRequest.href, function( styles ){
109
+ translate( styles, thisRequest.href, thisRequest.media );
110
+ parsedSheets[ thisRequest.href ] = true;
111
+
112
+ // by wrapping recursive function call in setTimeout
113
+ // we prevent "Stack overflow" error in IE7
114
+ win.setTimeout(function(){ makeRequests(); },0);
115
+ } );
116
+ }
117
+ },
118
+
119
+ //find media blocks in css text, convert to style blocks
120
+ translate = function( styles, href, media ){
121
+ var qs = styles.match( /@media[^\{]+\{([^\{\}]*\{[^\}\{]*\})+/gi ),
122
+ ql = qs && qs.length || 0;
123
+
124
+ //try to get CSS path
125
+ href = href.substring( 0, href.lastIndexOf( "/" ) );
126
+
127
+ var repUrls = function( css ){
128
+ return css.replace( /(url\()['"]?([^\/\)'"][^:\)'"]+)['"]?(\))/g, "$1" + href + "$2$3" );
129
+ },
130
+ useMedia = !ql && media;
131
+
132
+ //if path exists, tack on trailing slash
133
+ if( href.length ){ href += "/"; }
134
+
135
+ //if no internal queries exist, but media attr does, use that
136
+ //note: this currently lacks support for situations where a media attr is specified on a link AND
137
+ //its associated stylesheet has internal CSS media queries.
138
+ //In those cases, the media attribute will currently be ignored.
139
+ if( useMedia ){
140
+ ql = 1;
141
+ }
142
+
143
+ for( var i = 0; i < ql; i++ ){
144
+ var fullq, thisq, eachq, eql;
145
+
146
+ //media attr
147
+ if( useMedia ){
148
+ fullq = media;
149
+ rules.push( repUrls( styles ) );
150
+ }
151
+ //parse for styles
152
+ else{
153
+ fullq = qs[ i ].match( /@media *([^\{]+)\{([\S\s]+?)$/ ) && RegExp.$1;
154
+ rules.push( RegExp.$2 && repUrls( RegExp.$2 ) );
155
+ }
156
+
157
+ eachq = fullq.split( "," );
158
+ eql = eachq.length;
159
+
160
+ for( var j = 0; j < eql; j++ ){
161
+ thisq = eachq[ j ];
162
+ mediastyles.push( {
163
+ media : thisq.split( "(" )[ 0 ].match( /(only\s+)?([a-zA-Z]+)\s?/ ) && RegExp.$2 || "all",
164
+ rules : rules.length - 1,
165
+ hasquery : thisq.indexOf("(") > -1,
166
+ minw : thisq.match( /\(\s*min\-width\s*:\s*(\s*[0-9\.]+)(px|em)\s*\)/ ) && parseFloat( RegExp.$1 ) + ( RegExp.$2 || "" ),
167
+ maxw : thisq.match( /\(\s*max\-width\s*:\s*(\s*[0-9\.]+)(px|em)\s*\)/ ) && parseFloat( RegExp.$1 ) + ( RegExp.$2 || "" )
168
+ } );
169
+ }
170
+ }
171
+
172
+ applyMedia();
173
+ },
174
+
175
+ lastCall,
176
+
177
+ resizeDefer,
178
+
179
+ // returns the value of 1em in pixels
180
+ getEmValue = function() {
181
+ var ret,
182
+ div = doc.createElement('div'),
183
+ body = doc.body,
184
+ fakeUsed = false;
185
+
186
+ div.style.cssText = "position:absolute;font-size:1em;width:1em";
187
+
188
+ if( !body ){
189
+ body = fakeUsed = doc.createElement( "body" );
190
+ body.style.background = "none";
191
+ }
192
+
193
+ body.appendChild( div );
194
+
195
+ docElem.insertBefore( body, docElem.firstChild );
196
+
197
+ ret = div.offsetWidth;
198
+
199
+ if( fakeUsed ){
200
+ docElem.removeChild( body );
201
+ }
202
+ else {
203
+ body.removeChild( div );
204
+ }
205
+
206
+ //also update eminpx before returning
207
+ ret = eminpx = parseFloat(ret);
208
+
209
+ return ret;
210
+ },
211
+
212
+ //cached container for 1em value, populated the first time it's needed
213
+ eminpx,
214
+
215
+ //enable/disable styles
216
+ applyMedia = function( fromResize ){
217
+ var name = "clientWidth",
218
+ docElemProp = docElem[ name ],
219
+ currWidth = doc.compatMode === "CSS1Compat" && docElemProp || doc.body[ name ] || docElemProp,
220
+ styleBlocks = {},
221
+ lastLink = links[ links.length-1 ],
222
+ now = (new Date()).getTime();
223
+
224
+ //throttle resize calls
225
+ if( fromResize && lastCall && now - lastCall < resizeThrottle ){
226
+ win.clearTimeout( resizeDefer );
227
+ resizeDefer = win.setTimeout( applyMedia, resizeThrottle );
228
+ return;
229
+ }
230
+ else {
231
+ lastCall = now;
232
+ }
233
+
234
+ for( var i in mediastyles ){
235
+ if( mediastyles.hasOwnProperty( i ) ){
236
+ var thisstyle = mediastyles[ i ],
237
+ min = thisstyle.minw,
238
+ max = thisstyle.maxw,
239
+ minnull = min === null,
240
+ maxnull = max === null,
241
+ em = "em";
242
+
243
+ if( !!min ){
244
+ min = parseFloat( min ) * ( min.indexOf( em ) > -1 ? ( eminpx || getEmValue() ) : 1 );
245
+ }
246
+ if( !!max ){
247
+ max = parseFloat( max ) * ( max.indexOf( em ) > -1 ? ( eminpx || getEmValue() ) : 1 );
248
+ }
249
+
250
+ // if there's no media query at all (the () part), or min or max is not null, and if either is present, they're true
251
+ if( !thisstyle.hasquery || ( !minnull || !maxnull ) && ( minnull || currWidth >= min ) && ( maxnull || currWidth <= max ) ){
252
+ if( !styleBlocks[ thisstyle.media ] ){
253
+ styleBlocks[ thisstyle.media ] = [];
254
+ }
255
+ styleBlocks[ thisstyle.media ].push( rules[ thisstyle.rules ] );
256
+ }
257
+ }
258
+ }
259
+
260
+ //remove any existing respond style element(s)
261
+ for( var j in appendedEls ){
262
+ if( appendedEls.hasOwnProperty( j ) ){
263
+ if( appendedEls[ j ] && appendedEls[ j ].parentNode === head ){
264
+ head.removeChild( appendedEls[ j ] );
265
+ }
266
+ }
267
+ }
268
+
269
+ //inject active styles, grouped by media type
270
+ for( var k in styleBlocks ){
271
+ if( styleBlocks.hasOwnProperty( k ) ){
272
+ var ss = doc.createElement( "style" ),
273
+ css = styleBlocks[ k ].join( "\n" );
274
+
275
+ ss.type = "text/css";
276
+ ss.media = k;
277
+
278
+ //originally, ss was appended to a documentFragment and sheets were appended in bulk.
279
+ //this caused crashes in IE in a number of circumstances, such as when the HTML element had a bg image set, so appending beforehand seems best. Thanks to @dvelyk for the initial research on this one!
280
+ head.insertBefore( ss, lastLink.nextSibling );
281
+
282
+ if ( ss.styleSheet ){
283
+ ss.styleSheet.cssText = css;
284
+ }
285
+ else {
286
+ ss.appendChild( doc.createTextNode( css ) );
287
+ }
288
+
289
+ //push to appendedEls to track for later removal
290
+ appendedEls.push( ss );
291
+ }
292
+ }
293
+ },
294
+ //tweaked Ajax functions from Quirksmode
295
+ ajax = function( url, callback ) {
296
+ var req = xmlHttp();
297
+ if (!req){
298
+ return;
299
+ }
300
+ req.open( "GET", url, true );
301
+ req.onreadystatechange = function () {
302
+ if ( req.readyState !== 4 || req.status !== 200 && req.status !== 304 ){
303
+ return;
304
+ }
305
+ callback( req.responseText );
306
+ };
307
+ if ( req.readyState === 4 ){
308
+ return;
309
+ }
310
+ req.send( null );
311
+ },
312
+ //define ajax obj
313
+ xmlHttp = (function() {
314
+ var xmlhttpmethod = false;
315
+ try {
316
+ xmlhttpmethod = new win.XMLHttpRequest();
317
+ }
318
+ catch( e ){
319
+ xmlhttpmethod = new win.ActiveXObject( "Microsoft.XMLHTTP" );
320
+ }
321
+ return function(){
322
+ return xmlhttpmethod;
323
+ };
324
+ })();
325
+
326
+ //translate CSS
327
+ ripCSS();
328
+
329
+ //expose update for re-running respond later on
330
+ respond.update = ripCSS;
331
+
332
+ //adjust on resize
333
+ function callMedia(){
334
+ applyMedia( true );
335
+ }
336
+ if( win.addEventListener ){
337
+ win.addEventListener( "resize", callMedia, false );
338
+ }
339
+ else if( win.attachEvent ){
340
+ win.attachEvent( "onresize", callMedia );
341
+ }
342
+ })(this);
@@ -0,0 +1,126 @@
1
+ /* ========================================================================
2
+ * Bootstrap: affix.js v3.0.0
3
+ * http://twbs.github.com/bootstrap/javascript.html#affix
4
+ * ========================================================================
5
+ * Copyright 2012 Twitter, Inc.
6
+ *
7
+ * Licensed under the Apache License, Version 2.0 (the "License");
8
+ * you may not use this file except in compliance with the License.
9
+ * You may obtain a copy of the License at
10
+ *
11
+ * http://www.apache.org/licenses/LICENSE-2.0
12
+ *
13
+ * Unless required by applicable law or agreed to in writing, software
14
+ * distributed under the License is distributed on an "AS IS" BASIS,
15
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ * See the License for the specific language governing permissions and
17
+ * limitations under the License.
18
+ * ======================================================================== */
19
+
20
+
21
+ +function ($) { "use strict";
22
+
23
+ // AFFIX CLASS DEFINITION
24
+ // ======================
25
+
26
+ var Affix = function (element, options) {
27
+ this.options = $.extend({}, Affix.DEFAULTS, options)
28
+ this.$window = $(window)
29
+ .on('scroll.bs.affix.data-api', $.proxy(this.checkPosition, this))
30
+ .on('click.bs.affix.data-api', $.proxy(this.checkPositionWithEventLoop, this))
31
+
32
+ this.$element = $(element)
33
+ this.affixed =
34
+ this.unpin = null
35
+
36
+ this.checkPosition()
37
+ }
38
+
39
+ Affix.RESET = 'affix affix-top affix-bottom'
40
+
41
+ Affix.DEFAULTS = {
42
+ offset: 0
43
+ }
44
+
45
+ Affix.prototype.checkPositionWithEventLoop = function () {
46
+ setTimeout($.proxy(this.checkPosition, this), 1)
47
+ }
48
+
49
+ Affix.prototype.checkPosition = function () {
50
+ if (!this.$element.is(':visible')) return
51
+
52
+ var scrollHeight = $(document).height()
53
+ var scrollTop = this.$window.scrollTop()
54
+ var position = this.$element.offset()
55
+ var offset = this.options.offset
56
+ var offsetTop = offset.top
57
+ var offsetBottom = offset.bottom
58
+
59
+ if (typeof offset != 'object') offsetBottom = offsetTop = offset
60
+ if (typeof offsetTop == 'function') offsetTop = offset.top()
61
+ if (typeof offsetBottom == 'function') offsetBottom = offset.bottom()
62
+
63
+ var affix = this.unpin != null && (scrollTop + this.unpin <= position.top) ? false :
64
+ offsetBottom != null && (position.top + this.$element.height() >= scrollHeight - offsetBottom) ? 'bottom' :
65
+ offsetTop != null && (scrollTop <= offsetTop) ? 'top' : false
66
+
67
+ if (this.affixed === affix) return
68
+ if (this.unpin) this.$element.css('top', '')
69
+
70
+ this.affixed = affix
71
+ this.unpin = affix == 'bottom' ? position.top - scrollTop : null
72
+
73
+ this.$element.removeClass(Affix.RESET).addClass('affix' + (affix ? '-' + affix : ''))
74
+
75
+ if (affix == 'bottom') {
76
+ this.$element.offset({ top: document.body.offsetHeight - offsetBottom - this.$element.height() })
77
+ }
78
+ }
79
+
80
+
81
+ // AFFIX PLUGIN DEFINITION
82
+ // =======================
83
+
84
+ var old = $.fn.affix
85
+
86
+ $.fn.affix = function (option) {
87
+ return this.each(function () {
88
+ var $this = $(this)
89
+ var data = $this.data('bs.affix')
90
+ var options = typeof option == 'object' && option
91
+
92
+ if (!data) $this.data('bs.affix', (data = new Affix(this, options)))
93
+ if (typeof option == 'string') data[option]()
94
+ })
95
+ }
96
+
97
+ $.fn.affix.Constructor = Affix
98
+
99
+
100
+ // AFFIX NO CONFLICT
101
+ // =================
102
+
103
+ $.fn.affix.noConflict = function () {
104
+ $.fn.affix = old
105
+ return this
106
+ }
107
+
108
+
109
+ // AFFIX DATA-API
110
+ // ==============
111
+
112
+ $(window).on('load', function () {
113
+ $('[data-spy="affix"]').each(function () {
114
+ var $spy = $(this)
115
+ var data = $spy.data()
116
+
117
+ data.offset = data.offset || {}
118
+
119
+ if (data.offsetBottom) data.offset.bottom = data.offsetBottom
120
+ if (data.offsetTop) data.offset.top = data.offsetTop
121
+
122
+ $spy.affix(data)
123
+ })
124
+ })
125
+
126
+ }(window.jQuery);