mirror of
https://github.com/twbs/bootstrap.git
synced 2024-11-29 11:24:18 +01:00
Merge branch 'thomaswelton/11004-import-config'
This commit is contained in:
commit
87ce371018
@ -1,4 +1,6 @@
|
||||
// NOTE: DO NOT EDIT THE FOLLOWING SECTION DIRECTLY! It is autogenerated via the `build-customizer-html` Grunt task using the customizer-nav.jade template.
|
||||
li
|
||||
a(href='#import') Import
|
||||
li
|
||||
a(href='#less') Less components
|
||||
li
|
||||
|
@ -1378,6 +1378,30 @@ h1[id] {
|
||||
box-shadow: inset 0 2px 4px rgba(0,0,0,.05), 0 1px 0 rgba(255,255,255,.1);
|
||||
}
|
||||
|
||||
.bs-dropzone {
|
||||
position: relative;
|
||||
padding: 20px;
|
||||
margin-bottom: 20px;
|
||||
color: #777;
|
||||
text-align: center;
|
||||
border: 2px dashed #eee;
|
||||
border-radius: 4px;
|
||||
}
|
||||
.bs-dropzone h2 {
|
||||
margin-top: 0;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
.bs-dropzone .lead {
|
||||
margin-bottom: 10px;
|
||||
font-weight: normal;
|
||||
color: #333;
|
||||
}
|
||||
.bs-dropzone hr {
|
||||
width: 100px;
|
||||
}
|
||||
.bs-dropzone p:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Brand guidelines
|
||||
|
@ -16,6 +16,9 @@ window.onload = function () { // wait for load in a dumb way because B-0
|
||||
' * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n' +
|
||||
' */\n\n'
|
||||
|
||||
var supportsFile = (window.File && window.FileReader && window.FileList && window.Blob)
|
||||
var importDropTarget = $('#import-drop-target')
|
||||
|
||||
function showError(msg, err) {
|
||||
$('<div id="bsCustomizerAlert" class="bs-customizer-alert">' +
|
||||
'<div class="container">' +
|
||||
@ -46,6 +49,11 @@ window.onload = function () { // wait for load in a dumb way because B-0
|
||||
}
|
||||
}
|
||||
|
||||
function showAlert(type, msg, insertAfter) {
|
||||
$('<div class="alert alert-' + type + '">' + msg + '<button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button></div>')
|
||||
.insertAfter(insertAfter)
|
||||
}
|
||||
|
||||
function getQueryParam(key) {
|
||||
key = key.replace(/[*+?^$.\[\]{}()|\\\/]/g, '\\$&') // escape RegEx meta chars
|
||||
var match = location.search.match(new RegExp('[?&]' + key + '=([^&]+)(&|$)'))
|
||||
@ -106,6 +114,24 @@ window.onload = function () { // wait for load in a dumb way because B-0
|
||||
return data
|
||||
}
|
||||
|
||||
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])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function parseUrl() {
|
||||
var id = getQueryParam('id')
|
||||
|
||||
@ -118,21 +144,7 @@ window.onload = function () { // wait for load in a dumb way because B-0
|
||||
})
|
||||
.success(function (result) {
|
||||
var data = JSON.parse(result.files['config.json'].content)
|
||||
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])
|
||||
}
|
||||
}
|
||||
updateCustomizerFromJson(data)
|
||||
})
|
||||
.error(function (err) {
|
||||
showError('Error fetching bootstrap config file', err)
|
||||
@ -324,6 +336,61 @@ window.onload = function () { // wait for load in a dumb way because B-0
|
||||
}
|
||||
}
|
||||
|
||||
function removeImportAlerts() {
|
||||
importDropTarget.nextAll('.alert').remove()
|
||||
}
|
||||
|
||||
function handleConfigFileSelect(e) {
|
||||
e.stopPropagation()
|
||||
e.preventDefault()
|
||||
|
||||
var file = (e.originalEvent.hasOwnProperty('dataTransfer')) ? e.originalEvent.dataTransfer.files[0] : e.originalEvent.target.files[0]
|
||||
|
||||
if (!file.type.match('application/json')) {
|
||||
return showAlert('danger', '<strong>Ruh roh.</strong> We can only read <code>.json</code> files. Please try again.', importDropTarget)
|
||||
}
|
||||
|
||||
var reader = new FileReader()
|
||||
|
||||
reader.onload = (function () {
|
||||
return function (e) {
|
||||
var text = e.target.result
|
||||
|
||||
try {
|
||||
var json = JSON.parse(text)
|
||||
|
||||
if (typeof json != 'object') {
|
||||
throw new Error('JSON data from config file is not an object.')
|
||||
}
|
||||
|
||||
updateCustomizerFromJson(json)
|
||||
showAlert('success', '<strong>Woohoo!</strong> Your configuration was successfully uploaded. Tweak your settings, then hit Download.', importDropTarget)
|
||||
} catch (err) {
|
||||
return showAlert('danger', '<strong>Shucks.</strong> We can only read valid <code>.json</code> files. Please try again.', importDropTarget)
|
||||
}
|
||||
}
|
||||
})(file)
|
||||
|
||||
reader.readAsText(file)
|
||||
}
|
||||
|
||||
function handleConfigDragOver(e) {
|
||||
e.stopPropagation()
|
||||
e.preventDefault()
|
||||
e.originalEvent.dataTransfer.dropEffect = 'copy'
|
||||
|
||||
removeImportAlerts()
|
||||
}
|
||||
|
||||
if (supportsFile) {
|
||||
importDropTarget
|
||||
.on('dragover', handleConfigDragOver)
|
||||
.on('drop', handleConfigFileSelect)
|
||||
}
|
||||
|
||||
$('#import-file-select').on('select', handleConfigFileSelect)
|
||||
$('#import-manual-trigger').on('click', removeImportAlerts)
|
||||
|
||||
var inputsComponent = $('#less-section input')
|
||||
var inputsPlugin = $('#plugin-section input')
|
||||
var inputsVariables = $('#less-variables-section input')
|
||||
@ -410,7 +477,8 @@ window.onload = function () { // wait for load in a dumb way because B-0
|
||||
{ type: 'image/svg+xml;charset=utf-8' }
|
||||
)
|
||||
var objectUrl = url.createObjectURL(svg);
|
||||
if (/^blob:/.exec(objectUrl) === null) {
|
||||
|
||||
if (/^blob:/.exec(objectUrl) === null || !supportsFile) {
|
||||
// `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.
|
||||
|
@ -12,6 +12,7 @@ lead: Customize Bootstrap's components, Less variables, and jQuery plugins to ge
|
||||
<!--[if lt IE 9]>
|
||||
<style>
|
||||
.bs-customizer,
|
||||
.bs-customizer-import,
|
||||
.bs-docs-sidebar {
|
||||
display: none;
|
||||
}
|
||||
@ -23,6 +24,17 @@ lead: Customize Bootstrap's components, Less variables, and jQuery plugins to ge
|
||||
<![endif]-->
|
||||
|
||||
<!-- Customizer form -->
|
||||
|
||||
<div class="bs-docs-section bs-customizer-import">
|
||||
<div id="import-drop-target" class="bs-dropzone">
|
||||
<h2>✍</h2>
|
||||
<p class="lead">Have an existing configuration? Upload your <code>config.json</code> to import it.</p>
|
||||
<p>Drag and drop here, or <label id="import-manual-trigger" class="btn-link">manually upload<input type="file" id="import-file-select" class="hidden"></label>.</p>
|
||||
<hr>
|
||||
<p><strong>Don't have one?</strong> That's okay—just start customizing the fields below.</p>
|
||||
</div>
|
||||
</div><!-- /import -->
|
||||
|
||||
<form class="bs-customizer" role="form">
|
||||
<div class="bs-docs-section" id="less-section">
|
||||
<button class="btn btn-default toggle" type="button">Toggle all</button>
|
||||
@ -358,8 +370,6 @@ lead: Customize Bootstrap's components, Less variables, and jQuery plugins to ge
|
||||
{% include customizer-variables.html %}
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<div class="bs-docs-section">
|
||||
<h1 id="download" class="page-header">Download</h1>
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user