mirror of
https://github.com/janickiy/yii2-nomer
synced 2025-03-09 15:39:59 +00:00
add files to project
This commit is contained in:
commit
5cac498444
3729 changed files with 836998 additions and 0 deletions
513
web/metronic/global/plugins/bootstrap-maxlength/bootstrap-maxlength.js
vendored
Normal file
513
web/metronic/global/plugins/bootstrap-maxlength/bootstrap-maxlength.js
vendored
Normal file
|
@ -0,0 +1,513 @@
|
|||
(function ($) {
|
||||
'use strict';
|
||||
/**
|
||||
* We need an event when the elements are destroyed
|
||||
* because if an input is removed, we have to remove the
|
||||
* maxlength object associated (if any).
|
||||
* From:
|
||||
* http://stackoverflow.com/questions/2200494/jquery-trigger-event-when-an-element-is-removed-from-the-dom
|
||||
*/
|
||||
if (!$.event.special.destroyed) {
|
||||
$.event.special.destroyed = {
|
||||
remove: function (o) {
|
||||
if (o.handler) {
|
||||
o.handler();
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
$.fn.extend({
|
||||
maxlength: function (options, callback) {
|
||||
var documentBody = $('body'),
|
||||
defaults = {
|
||||
showOnReady: false, // true to always show when indicator is ready
|
||||
alwaysShow: false, // if true the indicator it's always shown.
|
||||
threshold: 10, // Represents how many chars left are needed to show up the counter
|
||||
warningClass: 'label label-success',
|
||||
limitReachedClass: 'label label-important label-danger',
|
||||
separator: ' / ',
|
||||
preText: '',
|
||||
postText: '',
|
||||
showMaxLength: true,
|
||||
placement: 'bottom',
|
||||
message: null, // an alternative way to provide the message text
|
||||
showCharsTyped: true, // show the number of characters typed and not the number of characters remaining
|
||||
validate: false, // if the browser doesn't support the maxlength attribute, attempt to type more than
|
||||
// the indicated chars, will be prevented.
|
||||
utf8: false, // counts using bytesize rather than length. eg: '£' is counted as 2 characters.
|
||||
appendToParent: false, // append the indicator to the input field's parent instead of body
|
||||
twoCharLinebreak: true, // count linebreak as 2 characters to match IE/Chrome textarea validation. As well as DB storage.
|
||||
customMaxAttribute: null // null = use maxlength attribute and browser functionality, string = use specified attribute instead.
|
||||
// Form submit validation is handled on your own. when maxlength has been exceeded 'overmax' class added to element
|
||||
};
|
||||
|
||||
if ($.isFunction(options) && !callback) {
|
||||
callback = options;
|
||||
options = {};
|
||||
}
|
||||
options = $.extend(defaults, options);
|
||||
|
||||
/**
|
||||
* Return the length of the specified input.
|
||||
*
|
||||
* @param input
|
||||
* @return {number}
|
||||
*/
|
||||
function inputLength(input) {
|
||||
var text = input.val();
|
||||
|
||||
if (options.twoCharLinebreak) {
|
||||
// Count all line breaks as 2 characters
|
||||
text = text.replace(/\r(?!\n)|\n(?!\r)/g, '\r\n');
|
||||
} else {
|
||||
// Remove all double-character (\r\n) linebreaks, so they're counted only once.
|
||||
text = text.replace(new RegExp('\r?\n', 'g'), '\n');
|
||||
}
|
||||
|
||||
var currentLength = 0;
|
||||
|
||||
if (options.utf8) {
|
||||
currentLength = utf8Length(text);
|
||||
} else {
|
||||
currentLength = text.length;
|
||||
}
|
||||
return currentLength;
|
||||
}
|
||||
|
||||
/**
|
||||
* Truncate the text of the specified input.
|
||||
*
|
||||
* @param input
|
||||
* @param limit
|
||||
*/
|
||||
function truncateChars(input, maxlength) {
|
||||
var text = input.val();
|
||||
var newlines = 0;
|
||||
|
||||
if (options.twoCharLinebreak) {
|
||||
text = text.replace(/\r(?!\n)|\n(?!\r)/g, '\r\n');
|
||||
|
||||
if (text.substr(text.length - 1) === '\n' && text.length % 2 === 1) {
|
||||
newlines = 1;
|
||||
}
|
||||
}
|
||||
|
||||
input.val(text.substr(0, maxlength - newlines));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the length of the specified input in UTF8 encoding.
|
||||
*
|
||||
* @param input
|
||||
* @return {number}
|
||||
*/
|
||||
function utf8Length(string) {
|
||||
var utf8length = 0;
|
||||
for (var n = 0; n < string.length; n++) {
|
||||
var c = string.charCodeAt(n);
|
||||
if (c < 128) {
|
||||
utf8length++;
|
||||
}
|
||||
else if ((c > 127) && (c < 2048)) {
|
||||
utf8length = utf8length + 2;
|
||||
}
|
||||
else {
|
||||
utf8length = utf8length + 3;
|
||||
}
|
||||
}
|
||||
return utf8length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the indicator should be showing up.
|
||||
*
|
||||
* @param input
|
||||
* @param thereshold
|
||||
* @param maxlength
|
||||
* @return {number}
|
||||
*/
|
||||
function charsLeftThreshold(input, thereshold, maxlength) {
|
||||
var output = true;
|
||||
if (!options.alwaysShow && (maxlength - inputLength(input) > thereshold)) {
|
||||
output = false;
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns how many chars are left to complete the fill up of the form.
|
||||
*
|
||||
* @param input
|
||||
* @param maxlength
|
||||
* @return {number}
|
||||
*/
|
||||
function remainingChars(input, maxlength) {
|
||||
var length = maxlength - inputLength(input);
|
||||
return length;
|
||||
}
|
||||
|
||||
/**
|
||||
* When called displays the indicator.
|
||||
*
|
||||
* @param indicator
|
||||
*/
|
||||
function showRemaining(currentInput, indicator) {
|
||||
indicator.css({
|
||||
display: 'block'
|
||||
});
|
||||
currentInput.trigger('maxlength.shown');
|
||||
}
|
||||
|
||||
/**
|
||||
* When called shows the indicator.
|
||||
*
|
||||
* @param indicator
|
||||
*/
|
||||
function hideRemaining(currentInput, indicator) {
|
||||
indicator.css({
|
||||
display: 'none'
|
||||
});
|
||||
currentInput.trigger('maxlength.hidden');
|
||||
}
|
||||
|
||||
/**
|
||||
* This function updates the value in the indicator
|
||||
*
|
||||
* @param maxLengthThisInput
|
||||
* @param typedChars
|
||||
* @return String
|
||||
*/
|
||||
function updateMaxLengthHTML(currentInputText, maxLengthThisInput, typedChars) {
|
||||
var output = '';
|
||||
if (options.message) {
|
||||
if (typeof options.message === 'function') {
|
||||
output = options.message(currentInputText, maxLengthThisInput);
|
||||
} else {
|
||||
output = options.message.replace('%charsTyped%', typedChars)
|
||||
.replace('%charsRemaining%', maxLengthThisInput - typedChars)
|
||||
.replace('%charsTotal%', maxLengthThisInput);
|
||||
}
|
||||
} else {
|
||||
if (options.preText) {
|
||||
output += options.preText;
|
||||
}
|
||||
if (!options.showCharsTyped) {
|
||||
output += maxLengthThisInput - typedChars;
|
||||
}
|
||||
else {
|
||||
output += typedChars;
|
||||
}
|
||||
if (options.showMaxLength) {
|
||||
output += options.separator + maxLengthThisInput;
|
||||
}
|
||||
if (options.postText) {
|
||||
output += options.postText;
|
||||
}
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function updates the value of the counter in the indicator.
|
||||
* Wants as parameters: the number of remaining chars, the element currently managed,
|
||||
* the maxLength for the current input and the indicator generated for it.
|
||||
*
|
||||
* @param remaining
|
||||
* @param currentInput
|
||||
* @param maxLengthCurrentInput
|
||||
* @param maxLengthIndicator
|
||||
*/
|
||||
function manageRemainingVisibility(remaining, currentInput, maxLengthCurrentInput, maxLengthIndicator) {
|
||||
if (maxLengthIndicator) {
|
||||
maxLengthIndicator.html(updateMaxLengthHTML(currentInput.val(), maxLengthCurrentInput, (maxLengthCurrentInput - remaining)));
|
||||
|
||||
if (remaining > 0) {
|
||||
if (charsLeftThreshold(currentInput, options.threshold, maxLengthCurrentInput)) {
|
||||
showRemaining(currentInput, maxLengthIndicator.removeClass(options.limitReachedClass).addClass(options.warningClass));
|
||||
} else {
|
||||
hideRemaining(currentInput, maxLengthIndicator);
|
||||
}
|
||||
} else {
|
||||
showRemaining(currentInput, maxLengthIndicator.removeClass(options.warningClass).addClass(options.limitReachedClass));
|
||||
}
|
||||
}
|
||||
|
||||
if (options.customMaxAttribute) {
|
||||
// class to use for form validation on custom maxlength attribute
|
||||
if (remaining < 0) {
|
||||
currentInput.addClass('overmax');
|
||||
} else {
|
||||
currentInput.removeClass('overmax');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This function returns an object containing all the
|
||||
* informations about the position of the current input
|
||||
*
|
||||
* @param currentInput
|
||||
* @return object {bottom height left right top width}
|
||||
*
|
||||
*/
|
||||
function getPosition(currentInput) {
|
||||
var el = currentInput[0];
|
||||
return $.extend({}, (typeof el.getBoundingClientRect === 'function') ? el.getBoundingClientRect() : {
|
||||
width: el.offsetWidth,
|
||||
height: el.offsetHeight
|
||||
}, currentInput.offset());
|
||||
}
|
||||
|
||||
/**
|
||||
* This function places the maxLengthIndicator at the
|
||||
* top / bottom / left / right of the currentInput
|
||||
*
|
||||
* @param currentInput
|
||||
* @param maxLengthIndicator
|
||||
* @return null
|
||||
*
|
||||
*/
|
||||
function place(currentInput, maxLengthIndicator) {
|
||||
var pos = getPosition(currentInput);
|
||||
|
||||
// Supports custom placement handler
|
||||
if ($.type(options.placement) === 'function'){
|
||||
options.placement(currentInput, maxLengthIndicator, pos);
|
||||
return;
|
||||
}
|
||||
|
||||
// Supports custom placement via css positional properties
|
||||
if ($.isPlainObject(options.placement)){
|
||||
placeWithCSS(options.placement, maxLengthIndicator);
|
||||
return;
|
||||
}
|
||||
|
||||
var inputOuter = currentInput.outerWidth(),
|
||||
outerWidth = maxLengthIndicator.outerWidth(),
|
||||
actualWidth = maxLengthIndicator.width(),
|
||||
actualHeight = maxLengthIndicator.height();
|
||||
|
||||
// get the right position if the indicator is appended to the input's parent
|
||||
if (options.appendToParent) {
|
||||
pos.top -= currentInput.parent().offset().top;
|
||||
pos.left -= currentInput.parent().offset().left;
|
||||
}
|
||||
|
||||
switch (options.placement) {
|
||||
case 'bottom':
|
||||
maxLengthIndicator.css({ top: pos.top + pos.height, left: pos.left + pos.width / 2 - actualWidth / 2 });
|
||||
break;
|
||||
case 'top':
|
||||
maxLengthIndicator.css({ top: pos.top - actualHeight, left: pos.left + pos.width / 2 - actualWidth / 2 });
|
||||
break;
|
||||
case 'left':
|
||||
maxLengthIndicator.css({ top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth });
|
||||
break;
|
||||
case 'right':
|
||||
maxLengthIndicator.css({ top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width });
|
||||
break;
|
||||
case 'bottom-right':
|
||||
maxLengthIndicator.css({ top: pos.top + pos.height, left: pos.left + pos.width });
|
||||
break;
|
||||
case 'top-right':
|
||||
maxLengthIndicator.css({ top: pos.top - actualHeight, left: pos.left + inputOuter });
|
||||
break;
|
||||
case 'top-left':
|
||||
maxLengthIndicator.css({ top: pos.top - actualHeight, left: pos.left - outerWidth });
|
||||
break;
|
||||
case 'bottom-left':
|
||||
maxLengthIndicator.css({ top: pos.top + currentInput.outerHeight(), left: pos.left - outerWidth });
|
||||
break;
|
||||
case 'centered-right':
|
||||
maxLengthIndicator.css({ top: pos.top + (actualHeight / 2), left: pos.left + inputOuter - outerWidth - 3 });
|
||||
break;
|
||||
|
||||
// Some more options for placements
|
||||
case 'bottom-right-inside':
|
||||
maxLengthIndicator.css({ top: pos.top + pos.height, left: pos.left + pos.width - outerWidth });
|
||||
break;
|
||||
case 'top-right-inside':
|
||||
maxLengthIndicator.css({ top: pos.top - actualHeight, left: pos.left + inputOuter - outerWidth });
|
||||
break;
|
||||
case 'top-left-inside':
|
||||
maxLengthIndicator.css({ top: pos.top - actualHeight, left: pos.left });
|
||||
break;
|
||||
case 'bottom-left-inside':
|
||||
maxLengthIndicator.css({ top: pos.top + currentInput.outerHeight(), left: pos.left });
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This function places the maxLengthIndicator based on placement config object.
|
||||
*
|
||||
* @param {object} placement
|
||||
* @param {$} maxLengthIndicator
|
||||
* @return null
|
||||
*
|
||||
*/
|
||||
function placeWithCSS(placement, maxLengthIndicator) {
|
||||
if (!placement || !maxLengthIndicator){
|
||||
return;
|
||||
}
|
||||
|
||||
var POSITION_KEYS = [
|
||||
'top',
|
||||
'bottom',
|
||||
'left',
|
||||
'right',
|
||||
'position'
|
||||
];
|
||||
|
||||
var cssPos = {};
|
||||
|
||||
// filter css properties to position
|
||||
$.each(POSITION_KEYS, function (i, key) {
|
||||
var val = options.placement[key];
|
||||
if (typeof val !== 'undefined'){
|
||||
cssPos[key] = val;
|
||||
}
|
||||
});
|
||||
|
||||
maxLengthIndicator.css(cssPos);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function returns true if the indicator position needs to
|
||||
* be recalculated when the currentInput changes
|
||||
*
|
||||
* @return {boolean}
|
||||
*
|
||||
*/
|
||||
function isPlacementMutable() {
|
||||
return options.placement === 'bottom-right-inside' || options.placement === 'top-right-inside' || typeof options.placement === 'function' || (options.message && typeof options.message === 'function');
|
||||
}
|
||||
|
||||
/**
|
||||
* This function retrieves the maximum length of currentInput
|
||||
*
|
||||
* @param currentInput
|
||||
* @return {number}
|
||||
*
|
||||
*/
|
||||
function getMaxLength(currentInput) {
|
||||
var max = currentInput.attr('maxlength');
|
||||
|
||||
if (options.customMaxAttribute) {
|
||||
var custom = currentInput.attr(options.customMaxAttribute);
|
||||
if (!max || custom < max) {
|
||||
max = custom;
|
||||
}
|
||||
}
|
||||
|
||||
if (!max) {
|
||||
max = currentInput.attr('size');
|
||||
}
|
||||
return max;
|
||||
}
|
||||
|
||||
return this.each(function () {
|
||||
|
||||
var currentInput = $(this),
|
||||
maxLengthCurrentInput,
|
||||
maxLengthIndicator;
|
||||
|
||||
$(window).resize(function () {
|
||||
if (maxLengthIndicator) {
|
||||
place(currentInput, maxLengthIndicator);
|
||||
}
|
||||
});
|
||||
|
||||
function firstInit() {
|
||||
var maxlengthContent = updateMaxLengthHTML(currentInput.val(), maxLengthCurrentInput, '0');
|
||||
maxLengthCurrentInput = getMaxLength(currentInput);
|
||||
|
||||
if (!maxLengthIndicator) {
|
||||
maxLengthIndicator = $('<span class="bootstrap-maxlength"></span>').css({
|
||||
display: 'none',
|
||||
position: 'absolute',
|
||||
whiteSpace: 'nowrap',
|
||||
zIndex: 1099
|
||||
}).html(maxlengthContent);
|
||||
}
|
||||
|
||||
// We need to detect resizes if we are dealing with a textarea:
|
||||
if (currentInput.is('textarea')) {
|
||||
currentInput.data('maxlenghtsizex', currentInput.outerWidth());
|
||||
currentInput.data('maxlenghtsizey', currentInput.outerHeight());
|
||||
|
||||
currentInput.mouseup(function () {
|
||||
if (currentInput.outerWidth() !== currentInput.data('maxlenghtsizex') || currentInput.outerHeight() !== currentInput.data('maxlenghtsizey')) {
|
||||
place(currentInput, maxLengthIndicator);
|
||||
}
|
||||
|
||||
currentInput.data('maxlenghtsizex', currentInput.outerWidth());
|
||||
currentInput.data('maxlenghtsizey', currentInput.outerHeight());
|
||||
});
|
||||
}
|
||||
|
||||
if (options.appendToParent) {
|
||||
currentInput.parent().append(maxLengthIndicator);
|
||||
currentInput.parent().css('position', 'relative');
|
||||
} else {
|
||||
documentBody.append(maxLengthIndicator);
|
||||
}
|
||||
|
||||
var remaining = remainingChars(currentInput, getMaxLength(currentInput));
|
||||
manageRemainingVisibility(remaining, currentInput, maxLengthCurrentInput, maxLengthIndicator);
|
||||
place(currentInput, maxLengthIndicator);
|
||||
}
|
||||
|
||||
if (options.showOnReady) {
|
||||
currentInput.ready(function () {
|
||||
firstInit();
|
||||
});
|
||||
} else {
|
||||
currentInput.focus(function () {
|
||||
firstInit();
|
||||
});
|
||||
}
|
||||
|
||||
currentInput.on('maxlength.reposition', function () {
|
||||
place(currentInput, maxLengthIndicator);
|
||||
});
|
||||
|
||||
|
||||
currentInput.on('destroyed', function () {
|
||||
if (maxLengthIndicator) {
|
||||
maxLengthIndicator.remove();
|
||||
}
|
||||
});
|
||||
|
||||
currentInput.on('blur', function () {
|
||||
if (maxLengthIndicator && !options.showOnReady) {
|
||||
maxLengthIndicator.remove();
|
||||
}
|
||||
});
|
||||
|
||||
currentInput.on('input', function () {
|
||||
var maxlength = getMaxLength(currentInput),
|
||||
remaining = remainingChars(currentInput, maxlength),
|
||||
output = true;
|
||||
|
||||
if (options.validate && remaining < 0) {
|
||||
truncateChars(currentInput, maxlength);
|
||||
output = false;
|
||||
} else {
|
||||
manageRemainingVisibility(remaining, currentInput, maxLengthCurrentInput, maxLengthIndicator);
|
||||
}
|
||||
|
||||
if (isPlacementMutable()) {
|
||||
place(currentInput, maxLengthIndicator);
|
||||
}
|
||||
|
||||
return output;
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
}(jQuery));
|
Loading…
Add table
Add a link
Reference in a new issue