;(function () {
var warnTextNode
// extend swal with a function for adding forms
swal.withForm = function () {
// initialize with field values supplied on `swal.withForm` call
var swalForm = new SwalForm(arguments[0].formFields)
// make form values inserted by the user available at `doneFunction`
swalForm.addWayToGetFormValuesInDoneFunction(arguments)
// Prepare arguments with the form html and html flag
arguments[0].text = swalForm.generateHtmlForm()
arguments[0].html = true
// forward arguments
swal.apply({}, arguments)
swalForm.allowClickingDirectlyOnInputs()
swalForm.focusOnFirstInput()
swalForm.markFirstRadioButtons()
swalForm.addTabOrder()
}
// constructor for helper object
function SwalForm (formFields) {
this.formFields = formFields
}
// helper methods
extend(SwalForm.prototype, {
formClass: 'swal-form',
generateHtmlForm: function () {
var form = {
clazz: this.formClass,
innerHtml: this.formFields.map(toFormTag.bind(this)).reduce(toSingleString)
}
return t("
{innerHtml}
", form)
function toFormTag (field) {
var input = Input(field)
// to separate groups of checkboxes and radiobuttons in different lines
var conditionalLineBreak = (input.isRadioOrCheckbox() && this.lastFieldName !== field.name) ? ' ' : ''
this.lastFieldName = field.name
return conditionalLineBreak + input.toHtml()
}
},
addWayToGetFormValuesInDoneFunction: function (swalArgs) {
var swalFormInstance = this
var doneFunction = swalArgs[1]
swalArgs[1] = function (isConfirm) {
// make form values available at `this` variable inside doneFunction
this.swalForm = swalFormInstance.getFormValues(isConfirm)
if (doneFunction.apply(this, arguments) !== false) {
// clean form to not interfere in normals sweet alerts
document.querySelector('.swal-form').innerHTML = ''
}
}
},
getFormValues: function (isConfirm) {
var inputHtmlCollection = document.getElementsByClassName('swal-form-field')
var inputArray = [].slice.call(inputHtmlCollection)
return inputArray
.filter(uncheckedRadiosAndCheckboxes)
.map(toValuableAttrs)
.reduce(toSingleObject, {})
function uncheckedRadiosAndCheckboxes (tag) {
return (isRadioOrCheckbox(tag) ? tag.checked : true)
}
function toValuableAttrs (tag) {
var attr = {}
attr[tag.id || tag.name] = tag.value
if (isConfirm && tag.dataset.swalFormsRequired && !tag.value) {
var warnMsg = 'Missing required attribute: ' + (tag.name || tag.id)
warnTextNode && warnTextNode.remove && warnTextNode.remove()
warnTextNode = document.createTextNode(warnMsg)
document.querySelector('.swal-form').appendChild(warnTextNode)
throw new Error(warnMsg)
}
return attr
}
function toSingleObject (obj1, obj2) {
return extendPreventingOverrides(obj1, obj2)
// for checkboxes we want to obtain all selected values in an array
function extendPreventingOverrides (a, b) {
Object.keys(b).forEach(addContentFromBtoA)
return a
function addContentFromBtoA (key) {
if (a.hasOwnProperty(key)) {
mergeIntoAnArray(a, b, key)
} else {
a[key] = b[key]
}
}
}
function mergeIntoAnArray (a, b, key) {
if (Array.isArray(a[key])) {
a[key].push(b[key])
} else {
a[key] = [a[key], b[key]]
}
}
}
},
allowClickingDirectlyOnInputs: function () {
// sweet-alert attaches an onblur handler which prevents clicks on of non
// button elements until click is made on the modal
document.querySelector('.sweet-alert button.confirm').onblur = function () {}
document.querySelector('.sweet-alert button.cancel').onblur = function () {}
},
getSelector: function () {
var firstField = this.formFields[0]
return (firstField.id ? t('#{id}', firstField) : t("[name='{name}']", firstField))
},
focusOnFirstInput: function () {
setTimeout(focus.bind(this))
function focus () {
document.querySelector(this.getSelector()).focus()
}
},
markFirstRadioButtons: function () {
setTimeout(markAsChecked.bind(this))
function markAsChecked () {
document.querySelector(this.getSelector()).checked = true
}
},
addTabOrder: function () {
var formFields = Array.prototype.slice.call(document.querySelectorAll('.swal-form .swal-form-field'))
formFields.forEach(addToTabNavigation)
function addToTabNavigation (formField, index) {
var myInput = formField
var nextInput = formFields[index + 1]
var keyHandler = function (e) {
var TABKEY = 9
if (e.keyCode === TABKEY) {
var next = this
setTimeout(function () { next.focus() })
}
}
if (myInput.addEventListener) {
myInput.addEventListener('keydown', keyHandler.bind(nextInput), false)
} else if (myInput.attachEvent) {
myInput.attachEvent('onkeydown', keyHandler.bind(nextInput)) /* damn IE hack */
}
}
}
})
function isRadioOrCheckbox (tag) {
return tag.type === 'radio' || tag.type === 'checkbox'
}
function extend (o1, o2) {
for (var key in o2) {
if (o2.hasOwnProperty(key)) {
o1[key] = o2[key]
}
}
return o1
}
function Input (field) {
var input = {
id: field.id || '',
name: field.name || '',
label: field.label || '',
clazz: field.clazz || '',
placeholder: field.placeholder || camelCaseToHuman(field.id),
value: field.value || '',
type: field.type || 'text',
options: field.options || [],
required: field.required,
isRadioOrCheckbox: function () {
return isRadioOrCheckbox(input)
},
toHtml: function () {
var inputTag
if (input.type !== 'select') {
inputTag = t("', input)
} else {
inputTag = t("'
}
var labelTag = t("", input)
return inputTag + labelTag
function toHtmlOptions (optionsString, option) {
option.selected = option.selected ? ' selected' : ''
return optionsString + t("", option)
}
}
}
// Should this label be set to title or id instead of value?
input.label = input.isRadioOrCheckbox() && input.label === '' ? input.value : input.label
input.clazz += input.isRadioOrCheckbox() ? ' patch-swal-styles-for-inputs' : ' nice-input'
return input
function camelCaseToHuman (arg) {
if (arg) {
return arg
.replace(/([A-Z])/g, ' $1') // insert a space before all caps
.replace(/^./, function (str) { return str.toUpperCase() }) // uppercase the first character
} else {
return ''
}
}
}
// string interpolation hack
function t (template, data) {
for (var key in data) {
template = template.replace(new RegExp('{' + key + '}', 'g'), data[key] || '')
}
return template
}
function toSingleString (s1, s2) {
return s1 + s2
}
swal.withFormAsync = function (options) {
return new Promise(function (resolve, reject) {
swal.withForm(options, function (isConfirm) {
this._isConfirm = isConfirm
resolve(this)
})
})
}
})()