mirror of
https://github.com/twbs/bootstrap.git
synced 2025-01-31 23:52:18 +01:00
Add drag and drop config import; closes #11004
Closes #13790 by merging a rebased version of it.
This commit is contained in:
parent
f026cfb831
commit
9739271c04
@ -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.
|
// 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
|
li
|
||||||
a(href='#less') Less components
|
a(href='#less') Less components
|
||||||
li
|
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);
|
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
|
* 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' +
|
' * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n' +
|
||||||
' */\n\n'
|
' */\n\n'
|
||||||
|
|
||||||
|
var supportsFile = (window.File && window.FileReader && window.FileList && window.Blob)
|
||||||
|
var importDropTarget = $('#import-drop-target')
|
||||||
|
|
||||||
function showError(msg, err) {
|
function showError(msg, err) {
|
||||||
$('<div id="bsCustomizerAlert" class="bs-customizer-alert">' +
|
$('<div id="bsCustomizerAlert" class="bs-customizer-alert">' +
|
||||||
'<div class="container">' +
|
'<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) {
|
function getQueryParam(key) {
|
||||||
key = key.replace(/[*+?^$.\[\]{}()|\\\/]/g, '\\$&') // escape RegEx meta chars
|
key = key.replace(/[*+?^$.\[\]{}()|\\\/]/g, '\\$&') // escape RegEx meta chars
|
||||||
var match = location.search.match(new RegExp('[?&]' + key + '=([^&]+)(&|$)'))
|
var match = location.search.match(new RegExp('[?&]' + key + '=([^&]+)(&|$)'))
|
||||||
@ -106,18 +114,7 @@ window.onload = function () { // wait for load in a dumb way because B-0
|
|||||||
return data
|
return data
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseUrl() {
|
function updateCustomizerFromJson(data) {
|
||||||
var id = getQueryParam('id')
|
|
||||||
|
|
||||||
if (!id) return
|
|
||||||
|
|
||||||
$.ajax({
|
|
||||||
url: 'https://api.github.com/gists/' + id,
|
|
||||||
type: 'GET',
|
|
||||||
dataType: 'json'
|
|
||||||
})
|
|
||||||
.success(function (result) {
|
|
||||||
var data = JSON.parse(result.files['config.json'].content)
|
|
||||||
if (data.js) {
|
if (data.js) {
|
||||||
$('#plugin-section input').each(function () {
|
$('#plugin-section input').each(function () {
|
||||||
$(this).prop('checked', ~$.inArray(this.value, data.js))
|
$(this).prop('checked', ~$.inArray(this.value, data.js))
|
||||||
@ -133,6 +130,21 @@ window.onload = function () { // wait for load in a dumb way because B-0
|
|||||||
$('input[data-var="' + i + '"]').val(data.vars[i])
|
$('input[data-var="' + i + '"]').val(data.vars[i])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseUrl() {
|
||||||
|
var id = getQueryParam('id')
|
||||||
|
|
||||||
|
if (!id) return
|
||||||
|
|
||||||
|
$.ajax({
|
||||||
|
url: 'https://api.github.com/gists/' + id,
|
||||||
|
type: 'GET',
|
||||||
|
dataType: 'json'
|
||||||
|
})
|
||||||
|
.success(function (result) {
|
||||||
|
var data = JSON.parse(result.files['config.json'].content)
|
||||||
|
updateCustomizerFromJson(data)
|
||||||
})
|
})
|
||||||
.error(function (err) {
|
.error(function (err) {
|
||||||
showError('Error fetching bootstrap config file', 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 inputsComponent = $('#less-section input')
|
||||||
var inputsPlugin = $('#plugin-section input')
|
var inputsPlugin = $('#plugin-section input')
|
||||||
var inputsVariables = $('#less-variables-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' }
|
{ type: 'image/svg+xml;charset=utf-8' }
|
||||||
)
|
)
|
||||||
var objectUrl = url.createObjectURL(svg);
|
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
|
// `URL.createObjectURL` created a URL that started with something other
|
||||||
// than "blob:", which means it has been polyfilled and is not supported by
|
// than "blob:", which means it has been polyfilled and is not supported by
|
||||||
// this browser.
|
// this browser.
|
||||||
|
@ -12,6 +12,7 @@ lead: Customize Bootstrap's components, Less variables, and jQuery plugins to ge
|
|||||||
<!--[if lt IE 9]>
|
<!--[if lt IE 9]>
|
||||||
<style>
|
<style>
|
||||||
.bs-customizer,
|
.bs-customizer,
|
||||||
|
.bs-customizer-import,
|
||||||
.bs-docs-sidebar {
|
.bs-docs-sidebar {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
@ -23,6 +24,17 @@ lead: Customize Bootstrap's components, Less variables, and jQuery plugins to ge
|
|||||||
<![endif]-->
|
<![endif]-->
|
||||||
|
|
||||||
<!-- Customizer form -->
|
<!-- 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">
|
<form class="bs-customizer" role="form">
|
||||||
<div class="bs-docs-section" id="less-section">
|
<div class="bs-docs-section" id="less-section">
|
||||||
<button class="btn btn-default toggle" type="button">Toggle all</button>
|
<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 %}
|
{% include customizer-variables.html %}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<div class="bs-docs-section">
|
<div class="bs-docs-section">
|
||||||
<h1 id="download" class="page-header">Download</h1>
|
<h1 id="download" class="page-header">Download</h1>
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user