diff options
author | Thomas Welton <thomaswelton@me.com> | 2014-06-11 14:06:32 +0400 |
---|---|---|
committer | Chris Rebert <code@rebertia.com> | 2014-07-31 22:45:21 +0400 |
commit | 9739271c04646ca49d8937043e45a6c9f6930bbc (patch) | |
tree | 0d7df4a11e2ddbc46788b82a1ec58f63c2adaf83 /docs/assets/js/src/customizer.js | |
parent | f026cfb8310f31db94823d031a382de5d5b0520b (diff) |
Add drag and drop config import; closes #11004
Closes #13790 by merging a rebased version of it.
Diffstat (limited to 'docs/assets/js/src/customizer.js')
-rw-r--r-- | docs/assets/js/src/customizer.js | 100 |
1 files changed, 84 insertions, 16 deletions
diff --git a/docs/assets/js/src/customizer.js b/docs/assets/js/src/customizer.js index c3a212f2c7..7340f1668f 100644 --- a/docs/assets/js/src/customizer.js +++ b/docs/assets/js/src/customizer.js @@ -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. |