framework7
Version:
Full featured mobile HTML framework for building iOS & Android apps
311 lines (302 loc) • 9.47 kB
JavaScript
import { getWindow, getDocument } from 'ssr-window';
import $ from '../../shared/dom7.js';
import { extend, serializeObject } from '../../shared/utils.js';
// Form Data
const FormData = {
store(form, data) {
const app = this;
const window = getWindow();
let formId = form;
const $formEl = $(form);
if ($formEl.length && $formEl.is('form') && $formEl.attr('id')) {
formId = $formEl.attr('id');
}
// Store form data in app.formsData
app.form.data[`form-${formId}`] = data;
// Store form data in local storage also
window.localStorage[`f7form-${formId}`] = JSON.stringify(data);
},
get(form) {
const app = this;
const window = getWindow();
let formId = form;
const $formEl = $(form);
if ($formEl.length && $formEl.is('form') && $formEl.attr('id')) {
formId = $formEl.attr('id');
}
if (window.localStorage[`f7form-${formId}`]) {
return JSON.parse(window.localStorage[`f7form-${formId}`]);
}
if (app.form.data[`form-${formId}`]) {
return app.form.data[`form-${formId}`];
}
return undefined;
},
remove(form) {
const app = this;
const window = getWindow();
let formId = form;
const $formEl = $(form);
if ($formEl.length && $formEl.is('form') && $formEl.attr('id')) {
formId = $formEl.attr('id');
}
// Delete form data from app.formsData
if (app.form.data[`form-${formId}`]) {
app.form.data[`form-${formId}`] = '';
delete app.form.data[`form-${formId}`];
}
// Delete form data from local storage also
if (window.localStorage[`f7form-${formId}`]) {
window.localStorage[`f7form-${formId}`] = '';
window.localStorage.removeItem(`f7form-${formId}`);
}
}
};
// Form Storage
const FormStorage = {
init(formEl) {
const app = this;
const $formEl = $(formEl);
const formId = $formEl.attr('id');
if (!formId) return;
const initialData = app.form.getFormData(formId);
if (initialData) {
app.form.fillFromData($formEl, initialData);
}
function store() {
const data = app.form.convertToData($formEl);
if (!data) return;
app.form.storeFormData(formId, data);
$formEl.trigger('form:storedata', data);
app.emit('formStoreData', $formEl[0], data);
}
$formEl.on('change submit', store);
},
destroy(formEl) {
const $formEl = $(formEl);
$formEl.off('change submit');
}
};
// Form To/From Data
function formToData(formEl) {
const app = this;
const $formEl = $(formEl).eq(0);
if ($formEl.length === 0) return undefined;
// Form data
const data = {};
// Skip input types
const skipTypes = ['submit', 'image', 'button', 'file'];
const skipNames = [];
$formEl.find('input, select, textarea').each(inputEl => {
const $inputEl = $(inputEl);
if ($inputEl.hasClass('ignore-store-data') || $inputEl.hasClass('no-store-data')) {
return;
}
const name = $inputEl.attr('name');
const type = $inputEl.attr('type');
const tag = inputEl.nodeName.toLowerCase();
if (skipTypes.indexOf(type) >= 0) return;
if (skipNames.indexOf(name) >= 0 || !name) return;
if (tag === 'select' && $inputEl.prop('multiple')) {
skipNames.push(name);
data[name] = [];
$formEl.find(`select[name="${name}"] option`).each(el => {
if (el.selected) data[name].push(el.value);
});
} else {
switch (type) {
case 'checkbox':
skipNames.push(name);
data[name] = [];
$formEl.find(`input[name="${name}"]`).each(el => {
if (el.checked) data[name].push(el.value);
});
break;
case 'radio':
skipNames.push(name);
$formEl.find(`input[name="${name}"]`).each(el => {
if (el.checked) data[name] = el.value;
});
break;
default:
data[name] = $inputEl.val();
break;
}
}
});
$formEl.trigger('form:todata', data);
app.emit('formToData', $formEl[0], data);
return data;
}
function formFromData(formEl, formData) {
const app = this;
const $formEl = $(formEl).eq(0);
if (!$formEl.length) return;
let data = formData;
const formId = $formEl.attr('id');
if (!data && formId) {
data = app.form.getFormData(formId);
}
if (!data) return;
// Skip input types
const skipTypes = ['submit', 'image', 'button', 'file'];
const skipNames = [];
$formEl.find('input, select, textarea').each(inputEl => {
const $inputEl = $(inputEl);
if ($inputEl.hasClass('ignore-store-data') || $inputEl.hasClass('no-store-data')) {
return;
}
const name = $inputEl.attr('name');
const type = $inputEl.attr('type');
const tag = inputEl.nodeName.toLowerCase();
if (typeof data[name] === 'undefined' || data[name] === null) return;
if (skipTypes.indexOf(type) >= 0) return;
if (skipNames.indexOf(name) >= 0 || !name) return;
if (tag === 'select' && $inputEl.prop('multiple')) {
skipNames.push(name);
$formEl.find(`select[name="${name}"] option`).each(el => {
const selectEl = el;
if (data[name].indexOf(el.value) >= 0) selectEl.selected = true;else selectEl.selected = false;
});
} else {
switch (type) {
case 'checkbox':
skipNames.push(name);
$formEl.find(`input[name="${name}"]`).each(el => {
const checkboxEl = el;
if (data[name].indexOf(el.value) >= 0) checkboxEl.checked = true;else checkboxEl.checked = false;
});
break;
case 'radio':
skipNames.push(name);
$formEl.find(`input[name="${name}"]`).each(el => {
const radioEl = el;
if (data[name] === el.value) radioEl.checked = true;else radioEl.checked = false;
});
break;
default:
$inputEl.val(data[name]);
break;
}
}
if (tag === 'select' || tag === 'input' || tag === 'textarea') {
$inputEl.trigger('change', 'fromdata');
}
});
$formEl.trigger('form:fromdata', data);
app.emit('formFromData', $formEl[0], data);
}
function initAjaxForm() {
const app = this;
const window = getWindow();
const document = getDocument();
function onSubmitChange(e, fromData) {
const $formEl = $(this);
if (e.type === 'change' && !$formEl.hasClass('form-ajax-submit-onchange')) return;
if (e.type === 'submit') e.preventDefault();
if (e.type === 'change' && fromData === 'fromdata') return;
const method = ($formEl.attr('method') || 'GET').toUpperCase();
const contentType = $formEl.attr('enctype') || $formEl.prop('enctype');
let url = $formEl.attr('action');
if (!url) return;
let data;
if (method === 'POST') {
if (contentType === 'application/x-www-form-urlencoded' || contentType === 'application/json') {
data = app.form.convertToData($formEl[0]);
if (contentType === 'application/json') {
data = JSON.stringify(data);
}
} else {
data = new window.FormData($formEl[0]);
}
} else {
data = serializeObject(app.form.convertToData($formEl[0]));
if (url.includes('?')) {
url += `&${data}`;
} else {
url += `?${data}`;
}
}
$formEl.trigger('formajax:beforesend', {
data
});
app.emit('formAjaxBeforeSend', $formEl[0], data);
fetch(url, {
method,
headers: {
'Content-Type': contentType || 'application/x-www-form-urlencoded'
},
...(method === 'POST' || method === 'PUT' ? {
body: data
} : {})
}).then(response => {
$formEl.trigger('formajax:complete', {
data,
response
});
app.emit('formAjaxComplete', $formEl[0], data, response);
$formEl.trigger('formajax:success', {
data,
response
});
app.emit('formAjaxSuccess', $formEl[0], data, response);
}).catch(error => {
$formEl.trigger('formajax:error', {
data,
error
});
app.emit('formAjaxError', $formEl[0], data, error);
});
}
$(document).on('submit change', 'form.form-ajax-submit, form.form-ajax-submit-onchange', onSubmitChange);
}
export default {
name: 'form',
create() {
const app = this;
extend(app, {
form: {
data: {},
storeFormData: FormData.store.bind(app),
getFormData: FormData.get.bind(app),
removeFormData: FormData.remove.bind(app),
convertToData: formToData.bind(app),
fillFromData: formFromData.bind(app),
storage: {
init: FormStorage.init.bind(app),
destroy: FormStorage.destroy.bind(app)
}
}
});
},
on: {
init() {
const app = this;
initAjaxForm.call(app);
},
tabBeforeRemove(tabEl) {
const app = this;
$(tabEl).find('.form-store-data').each(formEl => {
app.form.storage.destroy(formEl);
});
},
tabMounted(tabEl) {
const app = this;
$(tabEl).find('.form-store-data').each(formEl => {
app.form.storage.init(formEl);
});
},
pageBeforeRemove(page) {
const app = this;
page.$el.find('.form-store-data').each(formEl => {
app.form.storage.destroy(formEl);
});
},
pageInit(page) {
const app = this;
page.$el.find('.form-store-data').each(formEl => {
app.form.storage.init(formEl);
});
}
}
};