first commit

This commit is contained in:
2024-10-25 23:02:37 +02:00
commit faeb2e52e8
7653 changed files with 1095335 additions and 0 deletions

View File

@@ -0,0 +1,445 @@
(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',
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.
allowOverMax: false // false = use maxlength attribute and browswer functionality.
// true = removes maxlength attribute and replaces with 'data-bs-mxl'.
// 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(maxLengthThisInput, typedChars) {
var output = '';
if (options.message) {
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) {
maxLengthIndicator.html(updateMaxLengthHTML(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.allowOverMax) {
// 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),
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.addClass('maxlength-' + options.placement).css({ top: pos.top + pos.height, left: pos.left + pos.width / 2 - actualWidth / 2 });
break;
case 'top':
maxLengthIndicator.addClass('maxlength-' + options.placement).css({ top: pos.top - actualHeight, left: pos.left + pos.width / 2 - actualWidth / 2 });
break;
case 'left':
maxLengthIndicator.addClass('maxlength-' + options.placement).css({ top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth });
break;
case 'right':
maxLengthIndicator.addClass('maxlength-' + options.placement).css({ top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width });
break;
case 'bottom-right':
maxLengthIndicator.addClass('maxlength-' + options.placement).css({ top: pos.top + pos.height, left: pos.left + pos.width });
break;
case 'top-right':
maxLengthIndicator.addClass('maxlength-' + options.placement).css({ top: pos.top - actualHeight, left: pos.left + inputOuter });
break;
case 'top-left':
maxLengthIndicator.addClass('maxlength-' + options.placement).css({ top: pos.top - actualHeight, left: pos.left - outerWidth });
break;
case 'bottom-left':
maxLengthIndicator.addClass('maxlength-' + options.placement).css({ top: pos.top + currentInput.outerHeight(), left: pos.left - outerWidth });
break;
case 'centered-right':
maxLengthIndicator.addClass('maxlength-' + options.placement).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 retrieves the maximum length of currentInput
*
* @param currentInput
* @return {number}
*
*/
function getMaxLength(currentInput) {
var attr = 'maxlength';
if (options.allowOverMax) {
attr = 'data-bs-mxl';
}
return currentInput.attr(attr) || currentInput.attr('size');
}
return this.each(function () {
var currentInput = $(this),
maxLengthCurrentInput,
maxLengthIndicator;
$(window).resize(function () {
if (maxLengthIndicator) {
place(currentInput, maxLengthIndicator);
}
});
if (options.allowOverMax) {
$(this).attr('data-bs-mxl', $(this).attr('maxlength'));
$(this).removeAttr('maxlength');
}
function firstInit() {
var maxlengthContent = updateMaxLengthHTML(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);
}
//reposition the indicator if placement "bottom-right-inside" & "top-right-inside" is used
if (options.placement === 'bottom-right-inside' || options.placement === 'top-right-inside') {
place(currentInput, maxLengthIndicator);
}
return output;
});
});
}
});
}(jQuery));

View File

@@ -0,0 +1 @@
!function(a){"use strict";a.event.special.destroyed||(a.event.special.destroyed={remove:function(a){a.handler&&a.handler()}}),a.fn.extend({maxlength:function(b,c){function f(a){var c=a.val();c=b.twoCharLinebreak?c.replace(/\r(?!\n)|\n(?!\r)/g,"\r\n"):c.replace(new RegExp("\r?\n","g"),"\n");var d=0;return d=b.utf8?h(c):c.length}function g(a,c){var d=a.val(),e=0;b.twoCharLinebreak&&(d=d.replace(/\r(?!\n)|\n(?!\r)/g,"\r\n"),"\n"===d.substr(d.length-1)&&1===d.length%2&&(e=1)),a.val(d.substr(0,c-e))}function h(a){for(var b=0,c=0;c<a.length;c++){var d=a.charCodeAt(c);128>d?b++:b+=d>127&&2048>d?2:3}return b}function i(a,c,d){var e=!0;return!b.alwaysShow&&d-f(a)>c&&(e=!1),e}function j(a,b){var c=b-f(a);return c}function k(a,b){b.css({display:"block"}),a.trigger("maxlength.shown")}function l(a,b){b.css({display:"none"}),a.trigger("maxlength.hidden")}function m(a,c){var d="";return b.message?d=b.message.replace("%charsTyped%",c).replace("%charsRemaining%",a-c).replace("%charsTotal%",a):(b.preText&&(d+=b.preText),d+=b.showCharsTyped?c:a-c,b.showMaxLength&&(d+=b.separator+a),b.postText&&(d+=b.postText)),d}function n(a,c,d,e){e.html(m(d,d-a)),a>0?i(c,b.threshold,d)?k(c,e.removeClass(b.limitReachedClass).addClass(b.warningClass)):l(c,e):k(c,e.removeClass(b.warningClass).addClass(b.limitReachedClass)),b.allowOverMax&&(0>a?c.addClass("overmax"):c.removeClass("overmax"))}function o(b){var c=b[0];return a.extend({},"function"==typeof c.getBoundingClientRect?c.getBoundingClientRect():{width:c.offsetWidth,height:c.offsetHeight},b.offset())}function p(a,c){var d=o(a),e=a.outerWidth(),f=c.outerWidth(),g=c.width(),h=c.height();switch(b.appendToParent&&(d.top-=a.parent().offset().top,d.left-=a.parent().offset().left),b.placement){case"bottom":c.addClass("maxlength-"+b.placement).css({top:d.top+d.height,left:d.left+d.width/2-g/2});break;case"top":c.addClass("maxlength-"+b.placement).css({top:d.top-h,left:d.left+d.width/2-g/2});break;case"left":c.addClass("maxlength-"+b.placement).css({top:d.top+d.height/2-h/2,left:d.left-g});break;case"right":c.addClass("maxlength-"+b.placement).css({top:d.top+d.height/2-h/2,left:d.left+d.width});break;case"bottom-right":c.addClass("maxlength-"+b.placement).css({top:d.top+d.height,left:d.left+d.width});break;case"top-right":c.addClass("maxlength-"+b.placement).css({top:d.top-h,left:d.left+e});break;case"top-left":c.addClass("maxlength-"+b.placement).css({top:d.top-h,left:d.left-f});break;case"bottom-left":c.addClass("maxlength-"+b.placement).css({top:d.top+a.outerHeight(),left:d.left-f});break;case"centered-right":c.addClass("maxlength-"+b.placement).css({top:d.top+h/2,left:d.left+e-f-3});break;case"bottom-right-inside":c.css({top:d.top+d.height,left:d.left+d.width-f});break;case"top-right-inside":c.css({top:d.top-h,left:d.left+e-f});break;case"top-left-inside":c.css({top:d.top-h,left:d.left});break;case"bottom-left-inside":c.css({top:d.top+a.outerHeight(),left:d.left})}}function q(a){var c="maxlength";return b.allowOverMax&&(c="data-bs-mxl"),a.attr(c)||a.attr("size")}var d=a("body"),e={showOnReady:!1,alwaysShow:!1,threshold:10,warningClass:"label label-success",limitReachedClass:"label label-important label-danger",separator:" / ",preText:"",postText:"",showMaxLength:!0,placement:"bottom",showCharsTyped:!0,validate:!1,utf8:!1,appendToParent:!1,twoCharLinebreak:!0,allowOverMax:!1};return a.isFunction(b)&&!c&&(c=b,b={}),b=a.extend(e,b),this.each(function(){function h(){var g=m(e,"0");e=q(c),f||(f=a('<span class="bootstrap-maxlength"></span>').css({display:"none",position:"absolute",whiteSpace:"nowrap",zIndex:1099}).html(g)),c.is("textarea")&&(c.data("maxlenghtsizex",c.outerWidth()),c.data("maxlenghtsizey",c.outerHeight()),c.mouseup(function(){(c.outerWidth()!==c.data("maxlenghtsizex")||c.outerHeight()!==c.data("maxlenghtsizey"))&&p(c,f),c.data("maxlenghtsizex",c.outerWidth()),c.data("maxlenghtsizey",c.outerHeight())})),b.appendToParent?(c.parent().append(f),c.parent().css("position","relative")):d.append(f);var h=j(c,q(c));n(h,c,e,f),p(c,f)}var e,f,c=a(this);a(window).resize(function(){f&&p(c,f)}),b.allowOverMax&&(a(this).attr("data-bs-mxl",a(this).attr("maxlength")),a(this).removeAttr("maxlength")),b.showOnReady?c.ready(function(){h()}):c.focus(function(){h()}),c.on("maxlength.reposition",function(){p(c,f)}),c.on("destroyed",function(){f&&f.remove()}),c.on("blur",function(){f&&!b.showOnReady&&f.remove()}),c.on("input",function(){var a=q(c),d=j(c,a),h=!0;return b.validate&&0>d?(g(c,a),h=!1):n(d,c,e,f),("bottom-right-inside"===b.placement||"top-right-inside"===b.placement)&&p(c,f),h})})}})}(jQuery);