2013-10-17 20:33:04 +02:00
/ * !
2014-01-14 06:07:17 +01:00
* Bootstrap Customizer ( http : //getbootstrap.com/customize/)
2016-02-28 03:02:37 +01:00
* Copyright 2011 - 2016 Twitter , Inc .
2013-10-17 23:11:40 +02:00
*
* Licensed under the Creative Commons Attribution 3.0 Unported License . For
2015-05-17 11:43:04 +02:00
* details , see https : //creativecommons.org/licenses/by/3.0/.
2013-10-17 20:33:04 +02:00
* /
2016-03-03 09:18:19 +01:00
/* global JSON, JSZip, less, autoprefixer, saveAs, UglifyJS, __configBridge, __js, __less, __fonts */
2014-03-17 08:12:55 +01:00
2013-08-12 03:42:13 +02:00
window . onload = function ( ) { // wait for load in a dumb way because B-0
2014-03-17 08:12:55 +01:00
'use strict' ;
2015-04-29 11:11:58 +02:00
2013-12-19 00:37:46 +01:00
var cw = '/*!\n' +
2016-02-28 03:02:37 +01:00
' * Bootstrap v3.3.6 (http://getbootstrap.com)\n' +
2014-11-03 16:19:40 +01:00
' * Copyright 2011-' + new Date ( ) . getFullYear ( ) + ' Twitter, Inc.\n' +
2013-12-19 00:37:46 +01:00
' * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n' +
2014-02-07 19:31:08 +01:00
' */\n\n'
2013-08-12 03:42:13 +02:00
2015-04-26 12:53:45 +02:00
var supportsFile = window . File && window . FileReader && window . FileList && window . Blob
2015-04-29 11:11:58 +02:00
var $importDropTarget = $ ( '#import-drop-target' )
2014-06-11 12:06:32 +02:00
2013-08-18 09:28:52 +02:00
function showError ( msg , err ) {
2014-02-12 20:54:43 +01:00
$ ( '<div id="bsCustomizerAlert" class="bs-customizer-alert">' +
'<div class="container">' +
2014-11-11 23:41:21 +01:00
'<a href="#bsCustomizerAlert" data-dismiss="alert" class="close pull-right" aria-label="Close" role="button"><span aria-hidden="true">×</span></a>' +
'<p class="bs-customizer-alert-text"><span class="glyphicon glyphicon-warning-sign" aria-hidden="true"></span><span class="sr-only">Warning:</span>' + msg + '</p>' +
2014-12-05 21:58:47 +01:00
( err . message ? $ ( '<p></p>' ) . text ( 'Error: ' + err . message ) [ 0 ] . outerHTML : '' ) +
( err . extract ? $ ( '<pre class="bs-customizer-alert-extract"></pre>' ) . text ( err . extract . join ( '\n' ) ) [ 0 ] . outerHTML : '' ) +
2014-02-12 20:54:43 +01:00
'</div>' +
'</div>' ) . appendTo ( 'body' ) . alert ( )
2013-08-18 04:04:41 +02:00
throw err
}
2013-09-14 10:11:07 +02:00
function showSuccess ( msg ) {
2014-05-17 19:22:57 +02:00
$ ( '<div class="bs-callout bs-callout-info">' +
2014-11-11 23:41:21 +01:00
'<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">×</span></button>' + msg +
2013-09-14 10:11:07 +02:00
'</div>' ) . insertAfter ( '.bs-customize-download' )
}
2013-08-18 09:28:52 +02:00
function showCallout ( msg , showUpTop ) {
2015-04-29 11:11:58 +02:00
var $callout = $ ( '<div class="bs-callout bs-callout-danger">' +
2014-12-05 21:58:47 +01:00
'<h4>Attention!</h4>' +
2014-02-12 20:54:43 +01:00
'<p>' + msg + '</p>' +
'</div>' )
2013-08-18 09:28:52 +02:00
if ( showUpTop ) {
2015-04-29 11:11:58 +02:00
$callout . appendTo ( '.bs-docs-container' )
2013-08-18 09:28:52 +02:00
} else {
2015-04-29 11:11:58 +02:00
$callout . insertAfter ( '.bs-customize-download' )
2013-08-18 09:28:52 +02:00
}
}
2014-06-11 12:06:32 +02:00
function showAlert ( type , msg , insertAfter ) {
2014-11-11 23:41:21 +01:00
$ ( '<div class="alert alert-' + type + '">' + msg + '<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">×</span></button></div>' )
2014-06-11 12:06:32 +02:00
. insertAfter ( insertAfter )
}
2013-08-18 03:41:36 +02:00
function getQueryParam ( key ) {
2014-02-07 19:31:08 +01:00
key = key . replace ( /[*+?^$.\[\]{}()|\\\/]/g , '\\$&' ) // escape RegEx meta chars
var match = location . search . match ( new RegExp ( '[?&]' + key + '=([^&]+)(&|$)' ) )
return match && decodeURIComponent ( match [ 1 ] . replace ( /\+/g , ' ' ) )
2013-08-18 03:41:36 +02:00
}
2014-03-28 06:07:20 +01:00
function createGist ( configJson , callback ) {
2013-08-18 03:41:36 +02:00
var data = {
2014-03-09 10:10:15 +01:00
description : 'Bootstrap Customizer Config' ,
2013-09-18 18:50:02 +02:00
'public' : true ,
2014-03-09 10:10:15 +01:00
files : {
2013-09-18 18:50:02 +02:00
'config.json' : {
2014-03-09 10:10:15 +01:00
content : configJson
2013-08-18 03:41:36 +02:00
}
}
}
$ . ajax ( {
url : 'https://api.github.com/gists' ,
type : 'POST' ,
2014-08-18 00:41:53 +02:00
contentType : 'application/json; charset=UTF-8' ,
2013-08-18 03:41:36 +02:00
dataType : 'json' ,
data : JSON . stringify ( data )
} )
2013-09-18 20:37:55 +02:00
. success ( function ( result ) {
2013-09-14 10:11:07 +02:00
var gistUrl = result . html _url ;
2013-09-18 18:50:02 +02:00
var origin = window . location . protocol + '//' + window . location . host
2013-09-14 10:11:07 +02:00
var customizerUrl = origin + window . location . pathname + '?id=' + result . id
showSuccess ( '<strong>Success!</strong> Your configuration has been saved to <a href="' + gistUrl + '">' + gistUrl + '</a> ' +
'and can be revisited here at <a href="' + customizerUrl + '">' + customizerUrl + '</a> for further customization.' )
history . replaceState ( false , document . title , customizerUrl )
callback ( gistUrl , customizerUrl )
2013-08-18 03:41:36 +02:00
} )
2013-09-18 20:37:55 +02:00
. error ( function ( err ) {
2014-04-04 01:58:07 +02:00
try {
showError ( '<strong>Ruh roh!</strong> Could not save gist file, configuration not saved.' , err )
2014-05-29 06:35:22 +02:00
} catch ( sameErr ) {
2014-04-04 01:58:07 +02:00
// deliberately ignore the error
}
2014-03-28 06:07:20 +01:00
callback ( '<none>' , '<none>' )
2013-08-18 03:41:36 +02:00
} )
}
2013-08-18 09:28:52 +02:00
function getCustomizerData ( ) {
2013-08-12 03:42:13 +02:00
var vars = { }
$ ( '#less-variables-section input' )
2014-02-19 08:11:05 +01:00
. each ( function ( ) {
$ ( this ) . val ( ) && ( vars [ $ ( this ) . prev ( ) . text ( ) ] = $ ( this ) . val ( ) )
} )
2013-08-12 03:42:13 +02:00
var data = {
vars : vars ,
2013-08-18 03:41:36 +02:00
css : $ ( '#less-section input:checked' ) . map ( function ( ) { return this . value } ) . toArray ( ) ,
js : $ ( '#plugin-section input:checked' ) . map ( function ( ) { return this . value } ) . toArray ( )
2013-08-12 03:42:13 +02:00
}
2015-04-26 12:53:45 +02:00
if ( $ . isEmptyObject ( data . vars ) && ! data . css . length && ! data . js . length ) return null
2013-08-12 03:42:13 +02:00
2013-08-18 09:28:52 +02:00
return data
2013-08-12 03:42:13 +02:00
}
2014-06-11 12:06:32 +02:00
function updateCustomizerFromJson ( data ) {
if ( data . js ) {
$ ( '#plugin-section input' ) . each ( function ( ) {
$ ( this ) . prop ( 'checked' , ~ $ . inArray ( this . value , data . js ) )
} )
}
if ( data . css ) {
$ ( '#less-section input' ) . each ( function ( ) {
$ ( this ) . prop ( 'checked' , ~ $ . inArray ( this . value , data . css ) )
} )
}
if ( data . vars ) {
for ( var i in data . vars ) {
$ ( 'input[data-var="' + i + '"]' ) . val ( data . vars [ i ] )
}
}
}
2013-08-12 03:42:13 +02:00
function parseUrl ( ) {
2013-08-18 03:41:36 +02:00
var id = getQueryParam ( 'id' )
2013-08-12 03:42:13 +02:00
2013-08-18 03:41:36 +02:00
if ( ! id ) return
2013-08-12 03:42:13 +02:00
2013-08-18 03:41:36 +02:00
$ . ajax ( {
url : 'https://api.github.com/gists/' + id ,
type : 'GET' ,
dataType : 'json'
} )
2013-09-18 20:37:55 +02:00
. success ( function ( result ) {
2013-08-18 03:41:36 +02:00
var data = JSON . parse ( result . files [ 'config.json' ] . content )
2014-06-11 12:06:32 +02:00
updateCustomizerFromJson ( data )
2013-08-18 03:41:36 +02:00
} )
2013-09-18 20:37:55 +02:00
. error ( function ( err ) {
2013-08-18 04:04:41 +02:00
showError ( 'Error fetching bootstrap config file' , err )
2013-08-18 03:41:36 +02:00
} )
2013-08-12 03:42:13 +02:00
}
2013-09-14 10:26:42 +02:00
function generateZip ( css , js , fonts , config , complete ) {
2013-08-19 08:36:36 +02:00
if ( ! css && ! js ) return showError ( '<strong>Ruh roh!</strong> No Bootstrap files selected.' , new Error ( 'no Bootstrap' ) )
2013-08-12 03:42:13 +02:00
var zip = new JSZip ( )
if ( css ) {
var cssFolder = zip . folder ( 'css' )
for ( var fileName in css ) {
cssFolder . file ( fileName , css [ fileName ] )
}
}
if ( js ) {
var jsFolder = zip . folder ( 'js' )
2013-09-18 20:37:55 +02:00
for ( var jsFileName in js ) {
jsFolder . file ( jsFileName , js [ jsFileName ] )
2013-08-12 03:42:13 +02:00
}
}
2013-08-19 21:19:00 +02:00
if ( fonts ) {
var fontsFolder = zip . folder ( 'fonts' )
2013-09-18 20:37:55 +02:00
for ( var fontsFileName in fonts ) {
2014-03-17 08:12:55 +01:00
fontsFolder . file ( fontsFileName , fonts [ fontsFileName ] , { base64 : true } )
2013-08-19 21:19:00 +02:00
}
}
2013-09-14 10:26:42 +02:00
if ( config ) {
2013-09-18 18:50:02 +02:00
zip . file ( 'config.json' , config )
2013-09-14 10:26:42 +02:00
}
2013-09-18 18:50:02 +02:00
var content = zip . generate ( { type : 'blob' } )
2013-08-18 09:28:52 +02:00
complete ( content )
2013-08-12 03:42:13 +02:00
}
2014-03-28 04:43:44 +01:00
function generateCustomLess ( vars ) {
2013-08-12 03:42:13 +02:00
var result = ''
for ( var key in vars ) {
result += key + ': ' + vars [ key ] + ';\n'
}
return result + '\n\n'
}
2013-08-19 21:19:00 +02:00
function generateFonts ( ) {
2015-04-29 11:11:58 +02:00
var $glyphicons = $ ( '#less-section [value="glyphicons.less"]:checked' )
if ( $glyphicons . length ) {
2013-08-19 21:19:00 +02:00
return _ _fonts
}
}
2014-01-08 03:38:37 +01:00
// Returns an Array of @import'd filenames in the order
2013-09-24 08:29:45 +02:00
// in which they appear in the file.
2014-01-08 03:38:37 +01:00
function includedLessFilenames ( lessFilename ) {
2013-09-24 08:29:45 +02:00
var IMPORT _REGEX = /^@import \"(.*?)\";$/
2014-01-08 03:38:37 +01:00
var lessLines = _ _less [ lessFilename ] . split ( '\n' )
2013-09-24 08:29:45 +02:00
2014-03-28 05:28:21 +01:00
var imports = [ ]
$ . each ( lessLines , function ( index , lessLine ) {
var match = IMPORT _REGEX . exec ( lessLine )
if ( match ) {
var importee = match [ 1 ]
var transitiveImports = includedLessFilenames ( importee )
$ . each ( transitiveImports , function ( index , transitiveImportee ) {
if ( $ . inArray ( transitiveImportee , imports ) === - 1 ) {
imports . push ( transitiveImportee )
}
} )
imports . push ( importee )
}
} )
2013-09-24 08:29:45 +02:00
return imports
}
2014-01-08 03:38:37 +01:00
function generateLESS ( lessFilename , lessFileIncludes , vars ) {
var lessSource = _ _less [ lessFilename ]
2014-03-28 05:28:21 +01:00
var lessFilenames = includedLessFilenames ( lessFilename )
2014-03-17 08:12:55 +01:00
$ . each ( lessFilenames , function ( index , filename ) {
2014-01-08 03:38:37 +01:00
var fileInclude = lessFileIncludes [ filename ]
// Files not explicitly unchecked are compiled into the final stylesheet.
// Core stylesheets like 'normalize.less' are not included in the form
// since disabling them would wreck everything, and so their 'fileInclude'
// will be 'undefined'.
2015-04-26 12:53:45 +02:00
if ( fileInclude || fileInclude == null ) lessSource += _ _less [ filename ]
2014-01-08 03:38:37 +01:00
// Custom variables are added after Bootstrap variables so the custom
// ones take precedence.
2015-04-26 12:53:45 +02:00
if ( filename === 'variables.less' && vars ) lessSource += generateCustomLess ( vars )
2014-01-08 03:38:37 +01:00
} )
2014-06-19 11:41:23 +02:00
lessSource = lessSource . replace ( /@import[^\n]*/gi , '' ) // strip any imports
2014-01-08 03:38:37 +01:00
return lessSource
}
function compileLESS ( lessSource , baseFilename , intoResult ) {
2014-11-03 14:32:38 +01:00
var promise = $ . Deferred ( )
2014-01-08 03:38:37 +01:00
var parser = new less . Parser ( {
2014-02-13 09:05:04 +01:00
paths : [ 'variables.less' , 'mixins.less' ] ,
optimization : 0 ,
filename : baseFilename + '.css'
2014-03-01 17:19:50 +01:00
} )
2014-12-05 21:58:47 +01:00
parser . parse ( lessSource , function ( parseErr , tree ) {
if ( parseErr ) {
return promise . reject ( parseErr )
}
try {
intoResult [ baseFilename + '.css' ] = cw + tree . toCSS ( )
intoResult [ baseFilename + '.min.css' ] = cw + tree . toCSS ( { compress : true } )
2015-04-26 12:53:45 +02:00
} catch ( compileErr ) {
2014-12-05 21:58:47 +01:00
return promise . reject ( compileErr )
2014-01-08 03:38:37 +01:00
}
2014-11-03 14:32:38 +01:00
promise . resolve ( )
2014-01-08 03:38:37 +01:00
} )
2014-11-03 14:32:38 +01:00
return promise . promise ( )
2014-01-08 03:38:37 +01:00
}
2014-03-28 06:07:20 +01:00
function generateCSS ( preamble ) {
2014-11-03 14:32:38 +01:00
var promise = $ . Deferred ( )
2013-09-24 08:29:45 +02:00
var oneChecked = false
var lessFileIncludes = { }
2014-03-17 08:12:55 +01:00
$ ( '#less-section input' ) . each ( function ( ) {
2013-09-24 08:29:45 +02:00
var $this = $ ( this )
var checked = $this . is ( ':checked' )
lessFileIncludes [ $this . val ( ) ] = checked
oneChecked = oneChecked || checked
} )
2013-08-12 03:42:13 +02:00
2013-09-24 08:29:45 +02:00
if ( ! oneChecked ) return false
2013-08-12 03:42:13 +02:00
var result = { }
var vars = { }
$ ( '#less-variables-section input' )
2014-02-19 08:11:05 +01:00
. each ( function ( ) {
$ ( this ) . val ( ) && ( vars [ $ ( this ) . prev ( ) . text ( ) ] = $ ( this ) . val ( ) )
} )
2013-08-12 03:42:13 +02:00
2014-03-28 06:07:20 +01:00
var bsLessSource = preamble + generateLESS ( 'bootstrap.less' , lessFileIncludes , vars )
var themeLessSource = preamble + generateLESS ( 'theme.less' , lessFileIncludes , vars )
2013-08-12 03:42:13 +02:00
2014-11-03 14:32:38 +01:00
var prefixer = autoprefixer ( { browsers : _ _configBridge . autoprefixerBrowsers } )
$ . when (
compileLESS ( bsLessSource , 'bootstrap' , result ) ,
2014-01-08 03:57:15 +01:00
compileLESS ( themeLessSource , 'bootstrap-theme' , result )
2014-11-03 14:32:38 +01:00
) . done ( function ( ) {
for ( var key in result ) {
result [ key ] = prefixer . process ( result [ key ] ) . css
}
promise . resolve ( result )
} ) . fail ( function ( err ) {
2014-12-05 21:58:47 +01:00
showError ( '<strong>Ruh roh!</strong> Problem parsing or compiling Less files.' , err )
2014-11-03 14:32:38 +01:00
promise . reject ( )
} )
2013-08-12 03:42:13 +02:00
2014-11-03 14:32:38 +01:00
return promise . promise ( )
2013-08-12 03:42:13 +02:00
}
2014-03-28 19:05:59 +01:00
function uglify ( js ) {
var ast = UglifyJS . parse ( js )
ast . figure _out _scope ( )
var compressor = UglifyJS . Compressor ( )
var compressedAst = ast . transform ( compressor )
compressedAst . figure _out _scope ( )
compressedAst . compute _char _frequency ( )
compressedAst . mangle _names ( )
var stream = UglifyJS . OutputStream ( )
compressedAst . print ( stream )
return stream . toString ( )
}
function generateJS ( preamble ) {
2013-08-12 03:42:13 +02:00
var $checked = $ ( '#plugin-section input:checked' )
2014-11-03 16:19:40 +01:00
var jqueryCheck = _ _configBridge . jqueryCheck . join ( '\n' )
var jqueryVersionCheck = _ _configBridge . jqueryVersionCheck . join ( '\n' )
2014-03-28 19:08:42 +01:00
2013-08-12 03:42:13 +02:00
if ( ! $checked . length ) return false
var js = $checked
. map ( function ( ) { return _ _js [ this . value ] } )
. toArray ( )
. join ( '\n' )
2014-03-28 19:11:23 +01:00
preamble = cw + preamble
2014-10-22 20:52:15 +02:00
js = jqueryCheck + jqueryVersionCheck + js
2014-03-28 19:08:42 +01:00
2013-08-12 03:42:13 +02:00
return {
2014-03-28 06:07:20 +01:00
'bootstrap.js' : preamble + js ,
2014-03-28 19:11:23 +01:00
'bootstrap.min.js' : preamble + uglify ( js )
2013-08-12 03:42:13 +02:00
}
}
2014-06-11 12:06:32 +02:00
function removeImportAlerts ( ) {
2015-04-29 11:11:58 +02:00
$importDropTarget . nextAll ( '.alert' ) . remove ( )
2014-06-11 12:06:32 +02:00
}
function handleConfigFileSelect ( e ) {
e . stopPropagation ( )
e . preventDefault ( )
2015-04-26 12:53:45 +02:00
var file = e . originalEvent . hasOwnProperty ( 'dataTransfer' ) ? e . originalEvent . dataTransfer . files [ 0 ] : e . originalEvent . target . files [ 0 ]
2014-06-11 12:06:32 +02:00
var reader = new FileReader ( )
2014-11-05 19:10:48 +01:00
reader . onload = function ( e ) {
var text = e . target . result
2014-06-11 12:06:32 +02:00
2014-11-05 19:10:48 +01:00
try {
var json = JSON . parse ( text )
2014-06-11 12:06:32 +02:00
2014-11-05 19:10:48 +01:00
if ( ! $ . isPlainObject ( json ) ) {
throw new Error ( 'JSON data from config file is not an object.' )
2014-06-11 12:06:32 +02:00
}
2014-11-05 19:10:48 +01:00
updateCustomizerFromJson ( json )
2015-04-29 11:11:58 +02:00
showAlert ( 'success' , '<strong>Woohoo!</strong> Your configuration was successfully uploaded. Tweak your settings, then hit Download.' , $importDropTarget )
2014-11-05 19:10:48 +01:00
} catch ( err ) {
2015-04-29 11:11:58 +02:00
return showAlert ( 'danger' , '<strong>Shucks.</strong> We can only read valid <code>.json</code> files. Please try again.' , $importDropTarget )
2014-06-11 12:06:32 +02:00
}
2014-11-05 19:10:48 +01:00
}
2014-06-11 12:06:32 +02:00
2014-11-05 19:10:48 +01:00
reader . readAsText ( file , 'utf-8' )
2014-06-11 12:06:32 +02:00
}
function handleConfigDragOver ( e ) {
e . stopPropagation ( )
e . preventDefault ( )
e . originalEvent . dataTransfer . dropEffect = 'copy'
removeImportAlerts ( )
}
if ( supportsFile ) {
2015-04-29 11:11:58 +02:00
$importDropTarget
2014-06-11 12:06:32 +02:00
. on ( 'dragover' , handleConfigDragOver )
. on ( 'drop' , handleConfigFileSelect )
}
2014-10-31 10:58:03 +01:00
$ ( '#import-file-select' ) . on ( 'change' , handleConfigFileSelect )
2014-06-11 12:06:32 +02:00
$ ( '#import-manual-trigger' ) . on ( 'click' , removeImportAlerts )
2015-04-29 11:11:58 +02:00
var $inputsComponent = $ ( '#less-section input' )
var $inputsPlugin = $ ( '#plugin-section input' )
var $inputsVariables = $ ( '#less-variables-section input' )
2013-08-12 03:42:13 +02:00
$ ( '#less-section .toggle' ) . on ( 'click' , function ( e ) {
e . preventDefault ( )
2015-04-29 11:11:58 +02:00
$inputsComponent . prop ( 'checked' , ! $inputsComponent . is ( ':checked' ) )
2013-08-12 03:42:13 +02:00
} )
$ ( '#plugin-section .toggle' ) . on ( 'click' , function ( e ) {
e . preventDefault ( )
2015-04-29 11:11:58 +02:00
$inputsPlugin . prop ( 'checked' , ! $inputsPlugin . is ( ':checked' ) )
2013-08-12 03:42:13 +02:00
} )
$ ( '#less-variables-section .toggle' ) . on ( 'click' , function ( e ) {
e . preventDefault ( )
2015-04-29 11:11:58 +02:00
$inputsVariables . val ( '' )
2013-08-12 03:42:13 +02:00
} )
2013-08-18 06:50:01 +02:00
$ ( '[data-dependencies]' ) . on ( 'click' , function ( ) {
if ( ! $ ( this ) . is ( ':checked' ) ) return
var dependencies = this . getAttribute ( 'data-dependencies' )
if ( ! dependencies ) return
dependencies = dependencies . split ( ',' )
for ( var i = 0 ; i < dependencies . length ; i ++ ) {
2015-04-29 11:11:58 +02:00
var $dependency = $ ( '[value="' + dependencies [ i ] + '"]' )
$dependency && $dependency . prop ( 'checked' , true )
2013-08-18 06:50:01 +02:00
}
} )
$ ( '[data-dependents]' ) . on ( 'click' , function ( ) {
if ( $ ( this ) . is ( ':checked' ) ) return
var dependents = this . getAttribute ( 'data-dependents' )
if ( ! dependents ) return
dependents = dependents . split ( ',' )
for ( var i = 0 ; i < dependents . length ; i ++ ) {
2015-04-29 11:11:58 +02:00
var $dependent = $ ( '[value="' + dependents [ i ] + '"]' )
$dependent && $dependent . prop ( 'checked' , false )
2013-08-18 06:50:01 +02:00
}
} )
2013-08-18 09:28:52 +02:00
var $compileBtn = $ ( '#btn-compile' )
$compileBtn . on ( 'click' , function ( e ) {
2013-09-14 10:26:42 +02:00
var configData = getCustomizerData ( )
var configJson = JSON . stringify ( configData , null , 2 )
2013-08-18 09:28:52 +02:00
e . preventDefault ( )
$compileBtn . attr ( 'disabled' , 'disabled' )
2014-03-28 06:07:20 +01:00
createGist ( configJson , function ( gistUrl , customizerUrl ) {
configData . customizerUrl = customizerUrl
configJson = JSON . stringify ( configData , null , 2 )
var preamble = '/*!\n' +
' * Generated using the Bootstrap Customizer (' + customizerUrl + ')\n' +
' * Config saved to config.json and ' + gistUrl + '\n' +
' */\n'
2014-11-03 14:32:38 +01:00
$ . when (
generateCSS ( preamble ) ,
generateJS ( preamble ) ,
generateFonts ( )
) . done ( function ( css , js , fonts ) {
generateZip ( css , js , fonts , configJson , function ( blob ) {
$compileBtn . removeAttr ( 'disabled' )
2015-04-26 12:53:45 +02:00
setTimeout ( function ( ) {
saveAs ( blob , 'bootstrap.zip' )
} , 0 )
2014-11-03 14:32:38 +01:00
} )
2014-03-28 06:07:20 +01:00
} )
2013-08-18 09:28:52 +02:00
} )
2014-02-18 10:45:58 +01:00
} ) ;
// browser support alert
( function ( ) {
function failback ( ) {
$ ( '.bs-docs-section, .bs-docs-sidebar' ) . css ( 'display' , 'none' )
showCallout ( 'Looks like your current browser doesn\'t support the Bootstrap Customizer. Please take a second ' +
'to <a href="http://browsehappy.com/">upgrade to a more modern browser</a> (other than Safari).' , true )
}
/ * *
* Based on :
* Blob Feature Check v1 . 1.0
* https : //github.com/ssorallen/blob-feature-check/
* License : Public domain ( http : //unlicense.org)
* /
var url = window . webkitURL || window . URL // Safari 6 uses "webkitURL".
var svg = new Blob (
[ '<svg xmlns=\'http://www.w3.org/2000/svg\'></svg>' ] ,
2014-03-17 08:12:55 +01:00
{ type : 'image/svg+xml;charset=utf-8' }
2014-02-18 10:45:58 +01:00
)
var objectUrl = url . createObjectURL ( svg ) ;
2014-06-11 12:06:32 +02:00
if ( /^blob:/ . exec ( objectUrl ) === null || ! supportsFile ) {
2014-02-18 10:45:58 +01:00
// `URL.createObjectURL` created a URL that started with something other
// than "blob:", which means it has been polyfilled and is not supported by
// this browser.
failback ( )
2014-05-29 06:35:22 +02:00
} else {
2014-02-18 10:45:58 +01:00
$ ( '<img>' )
. on ( 'load' , function ( ) {
$compileBtn . prop ( 'disabled' , false )
} )
. on ( 'error' , failback )
. attr ( 'src' , objectUrl )
}
} ) ( ) ;
2013-08-18 09:28:52 +02:00
2013-08-18 03:41:36 +02:00
parseUrl ( )
2013-08-19 08:27:46 +02:00
}