1 window.onload = function () { // wait for load in a dumb way because B-0
2 var cw = '/*!\n * Bootstrap v3.0.0\n *\n * Copyright 2013 Twitter, Inc\n * Licensed under the Apache License v2.0\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Designed and built with all the love in the world @twitter by @mdo and @fat.\n */\n\n'
4 function showError(msg, err) {
5 $('<div id="bsCustomizerAlert" class="bs-customizer-alert">\
6 <div class="container">\
7 <a href="#bsCustomizerAlert" data-dismiss="alert" class="close pull-right">×</a>\
8 <p class="bs-customizer-alert-text"><span class="glyphicon glyphicon-warning-sign"></span>' + msg + '</p>' +
9 (err.extract ? '<pre class="bs-customizer-alert-extract">' + err.extract.join('\n') + '</pre>' : '') + '\
11 </div>').appendTo('body').alert()
15 function showCallout(msg, showUpTop) {
16 var callout = $('<div class="bs-callout bs-callout-danger">\
22 callout.appendTo('.bs-docs-container')
24 callout.insertAfter('.bs-customize-download')
28 function getQueryParam(key) {
29 key = key.replace(/[*+?^$.\[\]{}()|\\\/]/g, "\\$&"); // escape RegEx meta chars
30 var match = location.search.match(new RegExp("[?&]"+key+"=([^&]+)(&|$)"));
31 return match && decodeURIComponent(match[1].replace(/\+/g, " "));
34 function createGist(configData) {
36 "description": "Bootstrap Customizer Config",
40 "content": JSON.stringify(configData, null, 2)
45 url: 'https://api.github.com/gists',
48 data: JSON.stringify(data)
50 .success(function(result) {
51 history.replaceState(false, document.title, window.location.origin + window.location.pathname + '?id=' + result.id)
53 .error(function(err) {
54 showError('<strong>Ruh roh!</strong> Could not save gist file, configuration not saved.', err)
58 function getCustomizerData() {
61 $('#less-variables-section input')
63 $(this).val() && (vars[ $(this).prev().text() ] = $(this).val())
68 css: $('#less-section input:checked') .map(function () { return this.value }).toArray(),
69 js: $('#plugin-section input:checked').map(function () { return this.value }).toArray()
72 if ($.isEmptyObject(data.vars) && !data.css.length && !data.js.length) return
78 var id = getQueryParam('id')
83 url: 'https://api.github.com/gists/' + id,
87 .success(function(result) {
88 var data = JSON.parse(result.files['config.json'].content)
90 $('#plugin-section input').each(function () {
91 $(this).prop('checked', ~$.inArray(this.value, data.js))
95 $('#less-section input').each(function () {
96 $(this).prop('checked', ~$.inArray(this.value, data.css))
100 for (var i in data.vars) {
101 $('input[data-var="' + i + '"]').val(data.vars[i])
105 .error(function(err) {
106 showError('Error fetching bootstrap config file', err)
110 function generateZip(css, js, fonts, complete) {
111 if (!css && !js) return showError('<strong>Ruh roh!</strong> No Bootstrap files selected.', new Error('no Bootstrap'))
113 var zip = new JSZip()
116 var cssFolder = zip.folder('css')
117 for (var fileName in css) {
118 cssFolder.file(fileName, css[fileName])
123 var jsFolder = zip.folder('js')
124 for (var fileName in js) {
125 jsFolder.file(fileName, js[fileName])
130 var fontsFolder = zip.folder('fonts')
131 for (var fileName in fonts) {
132 fontsFolder.file(fileName, fonts[fileName])
136 var content = zip.generate({type:"blob"})
141 function generateCustomCSS(vars) {
144 for (var key in vars) {
145 result += key + ': ' + vars[key] + ';\n'
148 return result + '\n\n'
151 function generateFonts() {
152 var glyphicons = $('#less-section [value="glyphicons.less"]:checked')
153 if (glyphicons.length) {
158 function generateCSS() {
159 var $checked = $('#less-section input:checked')
161 if (!$checked.length) return false
167 $('#less-variables-section input')
169 $(this).val() && (vars[ $(this).prev().text() ] = $(this).val())
172 css += __less['variables.less']
173 if (vars) css += generateCustomCSS(vars)
174 css += __less['mixins.less']
175 css += __less['normalize.less']
176 css += __less['scaffolding.less']
178 .map(function () { return __less[this.value] })
182 css = css.replace(/@import[^\n]*/gi, '') //strip any imports
185 var parser = new less.Parser({
186 paths: ['variables.less', 'mixins.less']
188 , filename: 'bootstrap.css'
189 }).parse(css, function (err, tree) {
191 return showError('<strong>Ruh roh!</strong> Could not parse less files.', err)
194 'bootstrap.css' : cw + tree.toCSS(),
195 'bootstrap.min.css' : cw + tree.toCSS({ compress: true })
199 return showError('<strong>Ruh roh!</strong> Could not parse less files.', err)
205 function generateJavascript() {
206 var $checked = $('#plugin-section input:checked')
207 if (!$checked.length) return false
210 .map(function () { return __js[this.value] })
216 'bootstrap.min.js': cw + uglify(js)
220 var inputsComponent = $('#less-section input')
221 var inputsPlugin = $('#plugin-section input')
222 var inputsVariables = $('#less-variables-section input')
224 $('#less-section .toggle').on('click', function (e) {
226 inputsComponent.prop('checked', !inputsComponent.is(':checked'))
229 $('#plugin-section .toggle').on('click', function (e) {
231 inputsPlugin.prop('checked', !inputsPlugin.is(':checked'))
234 $('#less-variables-section .toggle').on('click', function (e) {
236 inputsVariables.val('')
239 $('[data-dependencies]').on('click', function () {
240 if (!$(this).is(':checked')) return
241 var dependencies = this.getAttribute('data-dependencies')
242 if (!dependencies) return
243 dependencies = dependencies.split(',')
244 for (var i = 0; i < dependencies.length; i++) {
245 var dependency = $('[value="' + dependencies[i] + '"]')
246 dependency && dependency.prop('checked', true)
250 $('[data-dependents]').on('click', function () {
251 if ($(this).is(':checked')) return
252 var dependents = this.getAttribute('data-dependents')
253 if (!dependents) return
254 dependents = dependents.split(',')
255 for (var i = 0; i < dependents.length; i++) {
256 var dependent = $('[value="' + dependents[i] + '"]')
257 dependent && dependent.prop('checked', false)
261 var $compileBtn = $('#btn-compile')
262 var $downloadBtn = $('#btn-download')
264 $compileBtn.on('click', function (e) {
267 $compileBtn.attr('disabled', 'disabled')
269 generateZip(generateCSS(), generateJavascript(), generateFonts(), function (blob) {
270 $compileBtn.removeAttr('disabled')
271 saveAs(blob, "bootstrap.zip")
272 createGist(getCustomizerData())
276 // browser support alerts
277 if (!window.URL && navigator.userAgent.toLowerCase().indexOf('safari') != -1) {
278 showCallout("Looks like you're using safari, which sadly doesn't have the best support\
279 for HTML5 blobs. Because of this your file will be downloaded with the name <code>\"untitled\"</code>.\
280 However, if you check your downloads folder, just rename this <code>\"untitled\"</code> file\
281 to <code>\"bootstrap.zip\"</code> and you should be good to go!")
282 } else if (!window.URL && !window.webkitURL) {
283 $('.bs-docs-section, .bs-sidebar').css('display', 'none')
285 showCallout("Looks like your current browser doesn't support the Bootstrap Customizer. Please take a second\
286 to <a href=\"https://www.google.com/intl/en/chrome/browser/\"> upgrade to a more modern browser</a>.", true)