@pi0/framework7
Version:
Full featured mobile HTML framework for building iOS & Android apps
229 lines (219 loc) • 8.07 kB
JavaScript
import $ from 'dom7';
import Utils from '../../utils/utils';
const Input = {
ignoreTypes: ['checkbox', 'button', 'submit', 'range', 'radio', 'image'],
createTextareaResizableShadow() {
const $shadowEl = $(document.createElement('textarea'));
$shadowEl.addClass('textarea-resizable-shadow');
$shadowEl.prop({
disabled: true,
readonly: true,
});
Input.textareaResizableShadow = $shadowEl;
},
textareaResizableShadow: undefined,
resizeTextarea(textareaEl) {
const app = this;
const $textareaEl = $(textareaEl);
if (!Input.textareaResizableShadow) {
Input.createTextareaResizableShadow();
}
const $shadowEl = Input.textareaResizableShadow;
if (!$textareaEl.length) return;
if (!$textareaEl.hasClass('resizable')) return;
if (Input.textareaResizableShadow.parents().length === 0) {
app.root.append($shadowEl);
}
const styles = window.getComputedStyle($textareaEl[0]);
('padding margin width font-size font-family font-style font-weight line-height font-variant text-transform letter-spacing border box-sizing display').split(' ').forEach((style) => {
let styleValue = styles[style];
if (('font-size line-height letter-spacing width').split(' ').indexOf(style) >= 0) {
styleValue = styleValue.replace(',', '.');
}
$shadowEl.css(style, styleValue);
});
const currentHeight = $textareaEl[0].clientHeight;
$shadowEl.val('');
const initialHeight = $shadowEl[0].scrollHeight;
$shadowEl.val($textareaEl.val());
$shadowEl.css('height', 0);
const scrollHeight = $shadowEl[0].scrollHeight;
if (currentHeight !== scrollHeight) {
if (scrollHeight > initialHeight) {
$textareaEl.css('height', `${scrollHeight}px`);
$textareaEl.trigger('textarea:resize', initialHeight, currentHeight, scrollHeight);
} else if (scrollHeight < currentHeight) {
$textareaEl.css('height', '');
$textareaEl.trigger('textarea:resize', initialHeight, currentHeight, initialHeight);
}
}
},
validate(inputEl) {
const $inputEl = $(inputEl);
if (!$inputEl.length) return;
const $itemInputEl = $inputEl.parents('.item-input');
const validity = $inputEl[0].validity;
const validationMessage = $inputEl.dataset().errorMessage || $inputEl[0].validationMessage || '';
if (!validity) return;
if (!validity.valid) {
let $errorEl = $inputEl.nextAll('.item-input-error-message');
if (validationMessage) {
if ($errorEl.length === 0) {
$errorEl = $('<div class="item-input-error-message"></div>');
$errorEl.insertAfter($inputEl);
}
$errorEl.text(validationMessage);
}
if ($errorEl.length > 0) {
$itemInputEl.addClass('item-input-with-error-message');
}
$itemInputEl.addClass('item-input-invalid');
$inputEl.addClass('input-invalid');
} else {
$itemInputEl.removeClass('item-input-invalid item-input-with-error-message');
$inputEl.removeClass('input-invalid');
}
},
validateInputs(el) {
const app = this;
$(el).find('input, textarea, select').each((index, inputEl) => {
app.input.validate(inputEl);
});
},
focus(inputEl) {
const $inputEl = $(inputEl);
const type = $inputEl.attr('type');
if (Input.ignoreTypes.indexOf(type) >= 0) return;
const $itemInputEl = $inputEl.parents('.item-input');
$itemInputEl.addClass('item-input-focused');
$inputEl.addClass('input-focused');
},
blur(inputEl) {
$(inputEl).parents('.item-input').removeClass('item-input-focused');
$(inputEl).removeClass('input-focused');
},
checkEmptyState(inputEl) {
const $inputEl = $(inputEl);
const value = $inputEl.val();
const $itemInputEl = $inputEl.parents('.item-input');
if ((value && (typeof value === 'string' && value.trim() !== '')) || (Array.isArray(value) && value.length > 0)) {
$itemInputEl.addClass('item-input-with-value');
$inputEl.addClass('input-with-value');
$inputEl.trigger('input:notempty');
} else {
$itemInputEl.removeClass('item-input-with-value');
$inputEl.removeClass('input-with-value');
$inputEl.trigger('input:empty');
}
},
init() {
const app = this;
Input.createTextareaResizableShadow();
function onFocus() {
app.input.focus(this);
}
function onBlur() {
const $inputEl = $(this);
const tag = $inputEl[0].nodeName.toLowerCase();
app.input.blur($inputEl);
if ($inputEl.dataset().validate || $inputEl.attr('validate') !== null) {
app.input.validate($inputEl);
}
// Resize textarea
if (tag === 'textarea' && $inputEl.hasClass('resizable')) {
if (Input.textareaResizableShadow) Input.textareaResizableShadow.remove();
}
}
function onChange() {
const $inputEl = $(this);
const type = $inputEl.attr('type');
const tag = $inputEl[0].nodeName.toLowerCase();
if (Input.ignoreTypes.indexOf(type) >= 0) return;
// Check Empty State
app.input.checkEmptyState($inputEl);
// Check validation
if ($inputEl.dataset().validate || $inputEl.attr('validate') !== null) {
app.input.validate($inputEl);
}
// Resize textarea
if (tag === 'textarea' && $inputEl.hasClass('resizable')) {
app.input.resizeTextarea($inputEl);
}
}
function onInvalid(e) {
const $inputEl = $(this);
if ($inputEl.dataset().validate || $inputEl.attr('validate') !== null) {
e.preventDefault();
app.input.validate($inputEl);
}
}
function clearInput() {
const $clicked = $(this);
const $inputEl = $clicked.siblings('input, textarea').eq(0);
const previousValue = $inputEl.val();
$inputEl
.val('')
.trigger('change')
.focus()
.trigger('input:clear', previousValue);
}
$(document).on('click', '.input-clear-button', clearInput);
$(document).on('change input', 'input, textarea, select', onChange, true);
$(document).on('focus', 'input, textarea, select', onFocus, true);
$(document).on('blur', 'input, textarea, select', onBlur, true);
$(document).on('invalid', 'input, textarea, select', onInvalid, true);
},
};
export default {
name: 'input',
create() {
const app = this;
Utils.extend(app, {
input: {
focus: Input.focus.bind(app),
blur: Input.blur.bind(app),
validate: Input.validate.bind(app),
validateInputs: Input.validate.bind(app),
checkEmptyState: Input.checkEmptyState.bind(app),
resizeTextarea: Input.resizeTextarea.bind(app),
init: Input.init.bind(app),
},
});
},
on: {
init() {
const app = this;
app.input.init();
},
tabMounted(tabEl) {
const app = this;
const $tabEl = $(tabEl);
$tabEl.find('.item-input').each((itemInputIndex, itemInputEl) => {
const $itemInputEl = $(itemInputEl);
$itemInputEl.find('input, select, textarea').each((inputIndex, inputEl) => {
const $inputEl = $(inputEl);
if (Input.ignoreTypes.indexOf($inputEl.attr('type')) >= 0) return;
app.input.checkEmptyState($inputEl);
});
});
$tabEl.find('textarea.resizable').each((textareaIndex, textareaEl) => {
app.input.resizeTextarea(textareaEl);
});
},
pageInit(page) {
const app = this;
const $pageEl = page.$el;
$pageEl.find('.item-input').each((itemInputIndex, itemInputEl) => {
const $itemInputEl = $(itemInputEl);
$itemInputEl.find('input, select, textarea').each((inputIndex, inputEl) => {
const $inputEl = $(inputEl);
if (Input.ignoreTypes.indexOf($inputEl.attr('type')) >= 0) return;
app.input.checkEmptyState($inputEl);
});
});
$pageEl.find('textarea.resizable').each((textareaIndex, textareaEl) => {
app.input.resizeTextarea(textareaEl);
});
},
},
};