/*! @preserve * bootbox.js * version: 6.0.0 * author: Nick Payne * license: MIT * http://bootboxjs.com/ */ (function (root, factory) { 'use strict'; if (typeof define === 'function' && define.amd) { // AMD define(['jquery'], factory); } else if (typeof exports === 'object') { // Node, CommonJS-like module.exports = factory(require('jquery')); } else { // Browser globals (root is window) root.bootbox = factory(root.jQuery); } }(this, function init($, undefined) { 'use strict'; let exports = {}; let VERSION = '6.0.0'; exports.VERSION = VERSION; let locales = { 'en' : { OK : 'OK', CANCEL : 'Cancel', CONFIRM : 'OK' } }; let templates = { dialog: '', header: '', footer: '', closeButton: '', form: '
', button: '', option: '', promptMessage: '
', inputs: { text: '', textarea: '', email: '', select: '', checkbox: '
', radio: '
', date: '', time: '', number: '', password: '', range: '' } }; let defaults = { // Default language used when generating buttons for alert, confirm, and prompt dialogs locale: 'en', // Show backdrop or not. Default to static so user has to interact with dialog backdrop: 'static', // Animate the modal in/out animate: true, // Additional class string applied to the top level dialog className: null, // Whether or not to include a close button closeButton: true, // Show the dialog immediately by default show: true, // Dialog container container: 'body', // Default value (used by the prompt helper) value: '', // Default input type (used by the prompt helper) inputType: 'text', // Custom error message to report if prompt fails validation errorMessage: null, // Switch button order from cancel/confirm (default) to confirm/cancel swapButtonOrder: false, // Center modal vertically in page centerVertical: false, // Append "multiple" property to the select when using the "prompt" helper multiple: false, // Automatically scroll modal content when height exceeds viewport height scrollable: false, // Whether or not to destroy the modal on hide reusable: false, // The element which triggered the dialog relatedTarget: null, // The size of the modal to generate size: null, // A unique indentifier for this modal id: null }; // PUBLIC FUNCTIONS // ************************************************************************************************************* /** * Return all currently registered locales, or a specific locale if "name" is defined * @param {string} [name] * @returns {(Object|Object[])} An array of the available locale objects, or a single locale object if {name} is not null */ exports.locales = function (name) { return name ? locales[name] : locales; }; /** * Register localized strings for the OK, CONFIRM, and CANCEL buttons * @param {string} name - The key used to identify the new locale in the locales array * @param {Object} values - An object containing the localized string for each of the OK, CANCEL, and CONFIRM properties of a locale * @returns The updated bootbox object */ exports.addLocale = function (name, values) { $.each(['OK', 'CANCEL', 'CONFIRM'], function (_, v) { if (!values[v]) { throw new Error('Please supply a translation for "' + v + '"'); } }); locales[name] = { OK: values.OK, CANCEL: values.CANCEL, CONFIRM: values.CONFIRM }; return exports; }; /** * Remove a previously-registered locale * @param {string} name - The key identifying the locale to remove * @returns The updated bootbox object */ exports.removeLocale = function (name) { if (name !== 'en') { delete locales[name]; } else { throw new Error('"en" is used as the default and fallback locale and cannot be removed.'); } return exports; }; /** * Set the default locale * @param {string} name - The key identifying the locale to set as the default locale for all future bootbox calls * @returns The updated bootbox object */ exports.setLocale = function (name) { return exports.setDefaults('locale', name); }; /** * Override default value(s) of Bootbox. * @returns The updated bootbox object */ exports.setDefaults = function () { let values = {}; if (arguments.length === 2) { // Allow passing of single key/value... values[arguments[0]] = arguments[1]; } else { // ... and as an object too values = arguments[0]; } $.extend(defaults, values); return exports; }; /** * Hides all currently active Bootbox modals * @returns The current bootbox object */ exports.hideAll = function () { $('.bootbox').modal('hide'); return exports; }; /** * Allows the base init() function to be overridden * @param {function} _$ - A function to be called when the bootbox instance is created * @returns The current bootbox object */ exports.init = function (_$) { return init(_$ || $); }; // CORE HELPER FUNCTIONS // ************************************************************************************************************* /** * The core dialog helper function, which can be used to create any custom Bootstrap modal. * @param {Object} options - An object used to configure the various properties which define a Bootbox dialog * @returns A jQuery object upon which Bootstrap's modal function has been called */ exports.dialog = function (options) { if ($.fn.modal === undefined) { throw new Error( '"$.fn.modal" is not defined; please double check you have included the Bootstrap JavaScript library. See https://getbootstrap.com/docs/5.1/getting-started/introduction/ for more details.' ); } options = sanitize(options); if ($.fn.modal.Constructor.VERSION) { options.fullBootstrapVersion = $.fn.modal.Constructor.VERSION; let i = options.fullBootstrapVersion.indexOf('.'); options.bootstrap = options.fullBootstrapVersion.substring(0, i); } else { // Assuming version 2.3.2, as that was the last "supported" 2.x version options.bootstrap = '2'; options.fullBootstrapVersion = '2.3.2'; console.warn('Bootbox will *mostly* work with Bootstrap 2, but we do not officially support it. Please upgrade, if possible.'); } let dialog = $(templates.dialog); let innerDialog = dialog.find('.modal-dialog'); let body = dialog.find('.modal-body'); let header = $(templates.header); let footer = $(templates.footer); let buttons = options.buttons; let callbacks = { onEscape: options.onEscape }; body.find('.bootbox-body').html(options.message); // Only attempt to create buttons if at least one has been defined in the options object if (getKeyLength(options.buttons) > 0) { each(buttons, function (key, b) { let button = $(templates.button); button.data('bb-handler', key); button.addClass(b.className); switch (key) { case 'ok': case 'confirm': button.addClass('bootbox-accept'); break; case 'cancel': button.addClass('bootbox-cancel'); break; } button.html(b.label); if (b.id) { button.attr({ 'id': b.id }); } if (b.disabled === true) { button.prop({ disabled: true }); } footer.append(button); callbacks[key] = b.callback; }); body.after(footer); } if (options.animate === true) { dialog.addClass('fade'); } if (options.className) { dialog.addClass(options.className); } if (options.id) { dialog.attr({ 'id': options.id }); } if (options.size) { // Requires Bootstrap 3.1.0 or higher if (options.fullBootstrapVersion.substring(0, 3) < '3.1') { console.warn('"size" requires Bootstrap 3.1.0 or higher. You appear to be using ' + options.fullBootstrapVersion + '. Please upgrade to use this option.'); } switch (options.size) { case 'small': case 'sm': innerDialog.addClass('modal-sm'); break; case 'large': case 'lg': innerDialog.addClass('modal-lg'); break; case 'extra-large': case 'xl': innerDialog.addClass('modal-xl'); // Requires Bootstrap 4.2.0 or higher if (options.fullBootstrapVersion.substring(0, 3) < '4.2') { console.warn('Using size "xl"/"extra-large" requires Bootstrap 4.2.0 or higher. You appear to be using ' + options.fullBootstrapVersion + '. Please upgrade to use this option.'); } break; } } if (options.scrollable) { innerDialog.addClass('modal-dialog-scrollable'); // Requires Bootstrap 4.3.0 or higher if (options.fullBootstrapVersion.substring(0, 3) < '4.3') { console.warn('Using "scrollable" requires Bootstrap 4.3.0 or higher. You appear to be using ' + options.fullBootstrapVersion + '. Please upgrade to use this option.'); } } if(options.title || options.closeButton) { if (options.title) { header.find('.modal-title').html(options.title); } else { header.addClass('border-0'); } if (options.closeButton) { let closeButton = $(templates.closeButton); if (options.bootstrap < 5) { closeButton.html('×'); } /* Note: the close button for Bootstrap 5+ does not contain content */ if(options.bootstrap < 4) { /* Bootstrap 3 and under */ header.prepend(closeButton); } else { header.append(closeButton); } } body.before(header); } if (options.centerVertical) { innerDialog.addClass('modal-dialog-centered'); // Requires Bootstrap 4.0.0-beta.3 or higher if (options.fullBootstrapVersion < '4.0.0') { console.warn('"centerVertical" requires Bootstrap 4.0.0-beta.3 or higher. You appear to be using ' + options.fullBootstrapVersion + '. Please upgrade to use this option.'); } } // Bootstrap event listeners; these handle extra setup & teardown required after the underlying modal has performed certain actions. if(!options.reusable) { // make sure we unbind any listeners once the dialog has definitively been dismissed dialog.one('hide.bs.modal', { dialog: dialog }, unbindModal); dialog.one('hidden.bs.modal', { dialog: dialog }, destroyModal); } if (options.onHide) { if ($.isFunction(options.onHide)) { dialog.on('hide.bs.modal', options.onHide); } else { throw new Error('Argument supplied to "onHide" must be a function'); } } if (options.onHidden) { if ($.isFunction(options.onHidden)) { dialog.on('hidden.bs.modal', options.onHidden); } else { throw new Error('Argument supplied to "onHidden" must be a function'); } } if (options.onShow) { if ($.isFunction(options.onShow)) { dialog.on('show.bs.modal', options.onShow); } else { throw new Error('Argument supplied to "onShow" must be a function'); } } dialog.one('shown.bs.modal', { dialog: dialog }, focusPrimaryButton); if (options.onShown) { if ($.isFunction(options.onShown)) { dialog.on('shown.bs.modal', options.onShown); } else { throw new Error('Argument supplied to "onShown" must be a function'); } } // Bootbox event listeners; used to decouple some behaviours from their respective triggers if (options.backdrop === true) { let startedOnBody = false; // Prevents the event from propagating to the backdrop, when something inside the dialog is clicked dialog.on('mousedown', '.modal-content', function(e) { e.stopPropagation(); startedOnBody = true; }); // A boolean true/false according to the Bootstrap docs should show a dialog the user can dismiss by clicking on the background. // We always only ever pass static/false to the actual $.modal function because with "true" we can't trap this event (the .modal-backdrop swallows it). // However, we still want to sort-of respect true and invoke the escape mechanism instead dialog.on('click.dismiss.bs.modal', function (e) { if (startedOnBody || e.target !== e.currentTarget) { return; } dialog.trigger('escape.close.bb'); }); } dialog.on('escape.close.bb', function (e) { // The if() statement looks redundant but it isn't; without it, if we *didn't* have an onEscape handler then processCallback would automatically dismiss the dialog if (callbacks.onEscape) { processCallback(e, dialog, callbacks.onEscape); } }); dialog.on('click', '.modal-footer button:not(.disabled)', function (e) { let callbackKey = $(this).data('bb-handler'); if (callbackKey !== undefined) { // Only process callbacks for buttons we recognize: processCallback(e, dialog, callbacks[callbackKey]); } }); dialog.on('click', '.bootbox-close-button', function (e) { // onEscape might be falsy, but that's fine; the fact is if the user has managed to click the close button we have to close the dialog, callback or not processCallback(e, dialog, callbacks.onEscape); }); dialog.on('keyup', function (e) { if (e.which === 27) { dialog.trigger('escape.close.bb'); } }); /* The remainder of this method simply deals with adding our dialog element to the DOM, augmenting it with Bootstrap's modal functionality and then giving the resulting object back to our caller */ $(options.container).append(dialog); dialog.modal({ backdrop: options.backdrop, keyboard: false, show: false }); if (options.show) { dialog.modal('show', options.relatedTarget); } return dialog; }; /** * Helper function to simulate the native alert() behavior. **NOTE**: This is non-blocking, so any code that must happen after the alert is dismissed should be placed within the callback function for this alert. * @returns A jQuery object upon which Bootstrap's modal function has been called */ exports.alert = function () { let options; options = mergeDialogOptions('alert', ['ok'], ['message', 'callback'], arguments); // @TODO: can this move inside exports.dialog when we're iterating over each button and checking its button.callback value instead? if (options.callback && !$.isFunction(options.callback)) { throw new Error('alert requires the "callback" property to be a function when provided'); } // Override the ok and escape callback to make sure they just invoke the single user-supplied one (if provided) options.buttons.ok.callback = options.onEscape = function () { if ($.isFunction(options.callback)) { return options.callback.call(this); } return true; }; return exports.dialog(options); }; /** * Helper function to simulate the native confirm() behavior. **NOTE**: This is non-blocking, so any code that must happen after the confirm is dismissed should be placed within the callback function for this confirm. * @returns A jQuery object upon which Bootstrap's modal function has been called */ exports.confirm = function () { let options; options = mergeDialogOptions('confirm', ['cancel', 'confirm'], ['message', 'callback'], arguments); // confirm specific validation; they don't make sense without a callback so make sure it's present if (!$.isFunction(options.callback)) { throw new Error('confirm requires a callback'); } // Overrides; undo anything the user tried to set they shouldn't have options.buttons.cancel.callback = options.onEscape = function () { return options.callback.call(this, false); }; options.buttons.confirm.callback = function () { return options.callback.call(this, true); }; return exports.dialog(options); }; /** * Helper function to simulate the native prompt() behavior. **NOTE**: This is non-blocking, so any code that must happen after the prompt is dismissed should be placed within the callback function for this prompt. * @returns A jQuery object upon which Bootstrap's modal function has been called */ exports.prompt = function () { let options; let promptDialog; let form; let input; let shouldShow; let inputOptions; // We have to create our form first, otherwise its value is undefined when gearing up our options. // @TODO this could be solved by allowing message to be a function instead... form = $(templates.form); // prompt defaults are more complex than others in that users can override more defaults options = mergeDialogOptions('prompt', ['cancel', 'confirm'], ['title', 'callback'], arguments); if (!options.value) { options.value = defaults.value; } if (!options.inputType) { options.inputType = defaults.inputType; } // Capture the user's 'show' value; we always set this to false before spawning the dialog to give us a chance to attach some handlers to it, but we need to make sure we respect a preference not to show it shouldShow = (options.show === undefined) ? defaults.show : options.show; // This is required prior to calling the dialog builder below - we need to add an event handler just before the prompt is shown options.show = false; // Handles the 'cancel' action options.buttons.cancel.callback = options.onEscape = function () { return options.callback.call(this, null); }; // Prompt submitted - extract the prompt value. This requires a bit of work, given the different input types available. options.buttons.confirm.callback = function () { let value; if (options.inputType === 'checkbox') { value = input.find('input:checked').map(function () { return $(this).val(); }).get(); } else if (options.inputType === 'radio') { value = input.find('input:checked').val(); } else { let el = input[0]; // Clear any previous custom error message if(options.errorMessage) { el.setCustomValidity(''); } if (el.checkValidity && !el.checkValidity()) { // If a custom error message was provided, add it now if(options.errorMessage){ el.setCustomValidity(options.errorMessage); } if(el.reportValidity) { el.reportValidity(); } // prevents button callback from being called return false; } else { if (options.inputType === 'select' && options.multiple === true) { value = input.find('option:selected').map(function () { return $(this).val(); }).get(); } else { value = input.val(); } } } return options.callback.call(this, value); }; // prompt-specific validation if (!options.title) { throw new Error('prompt requires a title'); } if (!$.isFunction(options.callback)) { throw new Error('prompt requires a callback'); } if (!templates.inputs[options.inputType]) { throw new Error('Invalid prompt type'); } // Create the input based on the supplied type input = $(templates.inputs[options.inputType]); switch (options.inputType) { case 'text': case 'textarea': case 'email': case 'password': input.val(options.value); if (options.placeholder) { input.attr('placeholder', options.placeholder); } if (options.pattern) { input.attr('pattern', options.pattern); } if (options.maxlength) { input.attr('maxlength', options.maxlength); } if (options.required) { input.prop({ 'required': true }); } if (options.rows && !isNaN(parseInt(options.rows))) { if (options.inputType === 'textarea') { input.attr({ 'rows': options.rows }); } } break; case 'date': case 'time': case 'number': case 'range': input.val(options.value); if (options.placeholder) { input.attr('placeholder', options.placeholder); } if (options.pattern) { input.attr('pattern', options.pattern); } else { if(options.inputType === 'date') { // Add the ISO-8601 short date format as a fallback for browsers without native type="date" support input.attr('pattern', '\d{4}-\d{2}-\d{2}'); } else if(options.inputType === 'time') { // Add an HH:MM pattern as a fallback for browsers without native type="time" support input.attr('pattern', '\d{2}:\d{2}'); } } if (options.required) { input.prop({ 'required': true }); } // These input types have extra attributes which affect their input validation. // Warning: For most browsers, date inputs are buggy in their implementation of 'step', so this attribute will have no effect. Therefore, we don't set the attribute for date inputs. // @see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/date#Setting_maximum_and_minimum_dates if (options.inputType !== 'date') { if (options.step) { if (options.step === 'any' || (!isNaN(options.step) && parseFloat(options.step) > 0)) { input.attr('step', options.step); } else { throw new Error('"step" must be a valid positive number or the value "any". See https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#attr-step for more information.'); } } } if (minAndMaxAreValid(options.inputType, options.min, options.max)) { if (options.min !== undefined) { input.attr('min', options.min); } if (options.max !== undefined) { input.attr('max', options.max); } } break; case 'select': let groups = {}; inputOptions = options.inputOptions || []; if (!$.isArray(inputOptions)) { throw new Error('Please pass an array of input options'); } if (!inputOptions.length) { throw new Error('prompt with "inputType" set to "select" requires at least one option'); } if (options.required) { input.prop({ 'required': true }); } if (options.multiple) { input.prop({ 'multiple': true }); } each(inputOptions, function (_, option) { // Assume the element to attach to is the input... let elem = input; if (option.value === undefined || option.text === undefined) { throw new Error('each option needs a "value" property and a "text" property'); } // ... but override that element if this option sits in a group if (option.group) { // Initialise group if necessary if (!groups[option.group]) { groups[option.group] = $('').attr('label', option.group); } elem = groups[option.group]; } let o = $(templates.option); o.attr('value', option.value).text(option.text); elem.append(o); }); each(groups, function (_, group) { input.append(group); }); // Safe to set a select's value as per a normal input input.val(options.value); if (options.bootstrap < 5) { input.removeClass('form-select').addClass('form-control'); } break; case 'checkbox': let checkboxValues = $.isArray(options.value) ? options.value : [options.value]; inputOptions = options.inputOptions || []; if (!inputOptions.length) { throw new Error('prompt with "inputType" set to "checkbox" requires at least one option'); } // Checkboxes have to nest within a containing element, so they break the rules a bit and we end up re-assigning our 'input' element to this container instead input = $('
'); each(inputOptions, function (_, option) { if (option.value === undefined || option.text === undefined) { throw new Error('each option needs a "value" property and a "text" property'); } let checkbox = $(templates.inputs[options.inputType]); checkbox.find('input').attr('value', option.value); checkbox.find('label').append('\n' + option.text); // We've ensured values is an array, so we can always iterate over it each(checkboxValues, function (_, value) { if (value === option.value) { checkbox.find('input').prop('checked', true); } }); input.append(checkbox); }); break; case 'radio': // Make sure that value is not an array (only a single radio can ever be checked) if (options.value !== undefined && $.isArray(options.value)) { throw new Error('prompt with "inputType" set to "radio" requires a single, non-array value for "value"'); } inputOptions = options.inputOptions || []; if (!inputOptions.length) { throw new Error('prompt with "inputType" set to "radio" requires at least one option'); } // Radiobuttons have to nest within a containing element, so they break the rules a bit and we end up re-assigning our 'input' element to this container instead input = $('
'); // Radiobuttons should always have an initial checked input checked in a "group". // If value is undefined or doesn't match an input option, select the first radiobutton let checkFirstRadio = true; each(inputOptions, function (_, option) { if (option.value === undefined || option.text === undefined) { throw new Error('each option needs a "value" property and a "text" property'); } let radio = $(templates.inputs[options.inputType]); radio.find('input').attr('value', option.value); radio.find('label').append('\n' + option.text); if (options.value !== undefined) { if (option.value === options.value) { radio.find('input').prop('checked', true); checkFirstRadio = false; } } input.append(radio); }); if (checkFirstRadio) { input.find('input[type="radio"]').first().prop('checked', true); } break; } // Now place it in our form form.append(input); form.on('submit', function (e) { e.preventDefault(); // Fix for SammyJS (or similar JS routing library) hijacking the form post. e.stopPropagation(); // @TODO can we actually click *the* button object instead? // e.g. buttons.confirm.click() or similar promptDialog.find('.bootbox-accept').trigger('click'); }); if ($.trim(options.message) !== '') { // Add the form to whatever content the user may have added. let message = $(templates.promptMessage).html(options.message); form.prepend(message); options.message = form; } else { options.message = form; } // Generate the dialog promptDialog = exports.dialog(options); // Clear the existing handler focusing the submit button... promptDialog.off('shown.bs.modal', focusPrimaryButton); // ...and replace it with one focusing our input, if possible promptDialog.on('shown.bs.modal', function () { // Need the closure here since input isn'tcan object otherwise input.focus(); }); if (shouldShow === true) { promptDialog.modal('show'); } return promptDialog; }; // INTERNAL FUNCTIONS // ************************************************************************************************************* // Map a flexible set of arguments into a single returned object. // If args.length is already one just return it, otherwise use the properties argument to map the unnamed args to object properties. // So in the latter case: // // mapArguments(["foo", $.noop], ["message", "callback"]) // // results in // // { message: "foo", callback: $.noop } // function mapArguments(args, properties) { let argsLength = args.length; let options = {}; if (argsLength < 1 || argsLength > 2) { throw new Error('Invalid argument length'); } if (argsLength === 2 || typeof args[0] === 'string') { options[properties[0]] = args[0]; options[properties[1]] = args[1]; } else { options = args[0]; } return options; } // Merge a set of default dialog options with user supplied arguments function mergeArguments(defaults, args, properties) { return $.extend( // Deep merge true, // Ensure the target is an empty, unreferenced object {}, // The base options object for this type of dialog (often just buttons) defaults, // 'args' could be an object or array; if it's an array properties will map it to a proper options object mapArguments(args, properties) ); } // This entry-level method makes heavy use of composition to take a simple range of inputs and return valid options suitable for passing to bootbox.dialog function mergeDialogOptions(className, labels, properties, args) { let locale; if (args && args[0]) { locale = args[0].locale || defaults.locale; let swapButtons = args[0].swapButtonOrder || defaults.swapButtonOrder; if (swapButtons) { labels = labels.reverse(); } } // Build up a base set of dialog properties let baseOptions = { className: 'bootbox-' + className, buttons: createLabels(labels, locale) }; // Ensure the buttons properties generated, *after* merging with user args are still valid against the supplied labels return validateButtons( // Merge the generated base properties with user supplied arguments mergeArguments( baseOptions, args, // If args.length > 1, properties specify how each arg maps to an object key properties ), labels ); } // Checks each button object to see if key is valid. // This function will only be called by the alert, confirm, and prompt helpers. function validateButtons(options, buttons) { let allowedButtons = {}; each(buttons, function (key, value) { allowedButtons[value] = true; }); each(options.buttons, function (key) { if (allowedButtons[key] === undefined) { throw new Error('button key "' + key + '" is not allowed (options are ' + buttons.join(' ') + ')'); } }); return options; } // From a given list of arguments, return a suitable object of button labels. // All this does is normalise the given labels and translate them where possible. // e.g. "ok", "confirm" -> { ok: "OK", cancel: "Annuleren" } function createLabels(labels, locale) { let buttons = {}; for (let i = 0, j = labels.length; i < j; i++) { let argument = labels[i]; let key = argument.toLowerCase(); let value = argument.toUpperCase(); buttons[key] = { label: getText(value, locale) }; } return buttons; } // Get localized text from a locale. Defaults to 'en' locale if no locale provided or a non-registered locale is requested function getText(key, locale) { let labels = locales[locale]; return labels ? labels[key] : locales.en[key]; } // Filter and tidy up any user supplied parameters to this dialog. // Also looks for any shorthands used and ensures that the options which are returned are all normalized properly function sanitize(options) { let buttons; let total; if (typeof options !== 'object') { throw new Error('Please supply an object of options'); } if (!options.message) { throw new Error('"message" option must not be null or an empty string.'); } // Make sure any supplied options take precedence over defaults options = $.extend({}, defaults, options); // Make sure backdrop is either true, false, or 'static' if (!options.backdrop) { options.backdrop = (options.backdrop === false || options.backdrop === 0) ? false : 'static'; } else { options.backdrop = typeof options.backdrop === 'string' && options.backdrop.toLowerCase() === 'static' ? 'static' : true; } // No buttons is still a valid dialog but it's cleaner to always have a buttons object to iterate over, even if it's empty if (!options.buttons) { options.buttons = {}; } buttons = options.buttons; total = getKeyLength(buttons); each(buttons, function (key, button, index) { if ($.isFunction(button)) { // Short form, assume value is our callback. Since button isn't an object it isn't a reference either so re-assign it button = buttons[key] = { callback: button }; } // Before any further checks, make sure button is the correct type if ($.type(button) !== 'object') { throw new Error('button with key "' + key + '" must be an object'); } if (!button.label) { // The lack of an explicit label means we'll assume the key is good enough button.label = key; } if (!button.className) { let isPrimary = false; if (options.swapButtonOrder) { isPrimary = index === 0; } else { isPrimary = index === total - 1; } if (total <= 2 && isPrimary) { // always add a primary to the main option in a one or two-button dialog button.className = 'btn-primary'; } else { // adding both classes allows us to target both BS3 and BS4+ without needing to check the version button.className = 'btn-secondary btn-default'; } } }); return options; } // Returns a count of the properties defined on the object function getKeyLength(obj) { return Object.keys(obj).length; } // Tiny wrapper function around jQuery.each; just adds index as the third parameter function each(collection, iterator) { let index = 0; $.each(collection, function (key, value) { iterator(key, value, index++); }); } function focusPrimaryButton(e) { e.data.dialog.find('.bootbox-accept').first().trigger('focus'); } function destroyModal(e) { // Ensure we don't accidentally intercept hidden events triggered by children of the current dialog. // We shouldn't need to handle this anymore, now that Bootstrap namespaces its events, but still worth doing. if (e.target === e.data.dialog[0]) { e.data.dialog.remove(); } } function unbindModal(e) { if (e.target === e.data.dialog[0]) { e.data.dialog.off('escape.close.bb'); e.data.dialog.off('click'); } } // Handle the invoked dialog callback function processCallback(e, dialog, callback) { e.stopPropagation(); e.preventDefault(); // By default we assume a callback will get rid of the dialog, although it is given the opportunity to override this // If the callback can be invoked and it *explicitly returns false*, then we'll set a flag to keep the dialog active... let preserveDialog = $.isFunction(callback) && callback.call(dialog, e) === false; // ... otherwise we'll bin it if (!preserveDialog) { dialog.modal('hide'); } } // Validate `min` and `max` values based on the current `inputType` value function minAndMaxAreValid(type, min, max) { let result = false; let minValid = true; let maxValid = true; if (type === 'date') { if (min !== undefined && !(minValid = dateIsValid(min))) { console.warn('Browsers which natively support the "date" input type expect date values to be of the form "YYYY-MM-DD" (see ISO-8601 https://www.iso.org/iso-8601-date-and-time-format.html). Bootbox does not enforce this rule, but your min value may not be enforced by this browser.'); } else if (max !== undefined && !(maxValid = dateIsValid(max))) { console.warn('Browsers which natively support the "date" input type expect date values to be of the form "YYYY-MM-DD" (see ISO-8601 https://www.iso.org/iso-8601-date-and-time-format.html). Bootbox does not enforce this rule, but your max value may not be enforced by this browser.'); } } else if (type === 'time') { if (min !== undefined && !(minValid = timeIsValid(min))) { throw new Error('"min" is not a valid time. See https://www.w3.org/TR/2012/WD-html-markup-20120315/datatypes.html#form.data.time for more information.'); } else if (max !== undefined && !(maxValid = timeIsValid(max))) { throw new Error('"max" is not a valid time. See https://www.w3.org/TR/2012/WD-html-markup-20120315/datatypes.html#form.data.time for more information.'); } } else { if (min !== undefined && isNaN(min)) { minValid = false; throw new Error('"min" must be a valid number. See https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#attr-min for more information.'); } if (max !== undefined && isNaN(max)) { maxValid = false; throw new Error('"max" must be a valid number. See https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#attr-max for more information.'); } } if (minValid && maxValid) { if (max <= min) { throw new Error('"max" must be greater than "min". See https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#attr-max for more information.'); } else { result = true; } } return result; } function timeIsValid(value) { return /([01][0-9]|2[0-3]):[0-5][0-9]?:[0-5][0-9]/.test(value); } function dateIsValid(value) { return /(\d{4})-(\d{2})-(\d{2})/.test(value); } // The Bootbox object return exports; }));//https://midu.dev/cargar-scripts-asincronos-en-javascript/ //cargamos script necesarios // la función devuelve una promesa que se resolverá o rechazará // dependiendo de la carga del script const loadScript = (src) => new Promise((resolve, reject) => { // creamos un elemento script en el dom let script = document.createElement('script'); // añadimos la fuente src al script del archivo script.src = src; // usamos los eventos nativos del script para resolver // o rechazar la promesa dependiendo de si se ha cargado script.onload = resolve; script.onerror = reject; // añadimos el script al documento document.head.appendChild(script); }); /* //cargamos table-excel loadScript('https://iniciativaperu.com/assets/parzibyte/table-excel/xlsx.full.min.js') .then(() => { window.dataLayer = window.dataLayer || [] //gtag('js', new Date()) //gtag('config', 'UA-XXXXX-Y') }).catch(console.error); loadScript('https://iniciativaperu.com/assets/parzibyte/table-excel/FileSaver.min.js') .then(() => { window.dataLayer = window.dataLayer || [] //gtag('js', new Date()) //gtag('config', 'UA-XXXXX-Y') }).catch(console.error); loadScript('https://iniciativaperu.com/assets/parzibyte/table-excel/tableexport.min.js') .then(() => { window.dataLayer = window.dataLayer || [] //gtag('js', new Date()) //gtag('config', 'UA-XXXXX-Y') }).catch(console.error); */ function rf_comprueba_dominio(nombre_dominio){ var arr = new Array( '.com','.net','.org','.biz','.coop','.info','.museum','.name', '.pro','.edu','.gov','.int','.mil','.ac','.ad','.ae','.af','.ag', '.ai','.al','.am','.an','.ao','.aq','.ar','.as','.at','.au','.aw', '.az','.ba','.bb','.bd','.be','.bf','.bg','.bh','.bi','.bj','.bm', '.bn','.bo','.br','.bs','.bt','.bv','.bw','.by','.bz','.ca','.cc', '.cd','.cf','.cg','.ch','.ci','.ck','.cl','.cm','.cn','.co','.cr', '.cu','.cv','.cx','.cy','.cz','.de','.dj','.dk','.dm','.do','.dz', '.ec','.ee','.eg','.eh','.er','.es','.et','.fi','.fj','.fk','.fm', '.fo','.fr','.ga','.gd','.ge','.gf','.gg','.gh','.gi','.gl','.gm', '.gn','.gp','.gq','.gr','.gs','.gt','.gu','.gv','.gy','.hk','.hm', '.hn','.hr','.ht','.hu','.id','.ie','.il','.im','.in','.io','.iq', '.ir','.is','.it','.je','.jm','.jo','.jp','.ke','.kg','.kh','.ki', '.km','.kn','.kp','.kr','.kw','.ky','.kz','.la','.lb','.lc','.li', '.lk','.lr','.ls','.lt','.lu','.lv','.ly','.ma','.mc','.md','.mg', '.mh','.mk','.ml','.mm','.mn','.mo','.mp','.mq','.mr','.ms','.mt', '.mu','.mv','.mw','.mx','.my','.mz','.na','.nc','.ne','.nf','.ng', '.ni','.nl','.no','.np','.nr','.nu','.nz','.om','.pa','.pe','.pf', '.pg','.ph','.pk','.pl','.pm','.pn','.pr','.ps','.pt','.pw','.py', '.qa','.re','.ro','.rw','.ru','.sa','.sb','.sc','.sd','.se','.sg', '.sh','.si','.sj','.sk','.sl','.sm','.sn','.so','.sr','.st','.sv', '.sy','.sz','.tc','.td','.tf','.tg','.th','.tj','.tk','.tm','.tn', '.to','.tp','.tr','.tt','.tv','.tw','.tz','.ua','.ug','.uk','.um', '.us','.uy','.uz','.va','.vc','.ve','.vg','.vi','.vn','.vu','.ws', '.wf','.ye','.yt','.yu','.za','.zm','.zw'); var comprobacion = nombre_dominio; var val = true; var punto = comprobacion.lastIndexOf("."); var nombre_dominio = comprobacion.substring(0,punto); var extension = comprobacion.substring(punto,comprobacion.length); var rv_error=0; var rv_mensaje=""; if(punto>2 && punto<57){ for(var i=0; i"; rv_error++; }else{ for(var j=0; j 47 && hh<59) || (hh > 64 && hh<91) || (hh > 96 && hh<123) || hh==45 || hh==46){ if((j==0 || j==nombre_dominio.length-1) && hh == 45){ rv_mensaje += "Tu nombre de dominio no puede contener el simbolo guion '-' al principio ni al final
"; rv_error++; } }else{ rv_mensaje += "El dominio no puede contener caracteres especiales
"; rv_error++; } } } }else{ rv_mensaje += "El numero de caracteres insertado no es correcto para el nombre de dominio
"; rv_error++; } if(rv_error==0){ return ""; }else{ return rv_mensaje; } } let navegador = navigator.userAgent; if (navigator.userAgent.match(/Android/i) || navigator.userAgent.match(/webOS/i) || navigator.userAgent.match(/iPhone/i) || navigator.userAgent.match(/iPad/i) || navigator.userAgent.match(/iPod/i) || navigator.userAgent.match(/BlackBerry/i) || navigator.userAgent.match(/Windows Phone/i)) { var rv_movil=true; //console.log("Estás usando un dispositivo móvil!!"); } else { var rv_movil=false; //console.log("No estás usando un móvil"); } function rf_movil(){ let navegador = navigator.userAgent; if (navigator.userAgent.match(/Android/i) || navigator.userAgent.match(/webOS/i) || navigator.userAgent.match(/iPhone/i) || navigator.userAgent.match(/iPad/i) || navigator.userAgent.match(/iPod/i) || navigator.userAgent.match(/BlackBerry/i) || navigator.userAgent.match(/Windows Phone/i)) { return true; //console.log("Estás usando un dispositivo móvil!!"); } else { return false; //console.log("No estás usando un móvil"); } } /*constantes de fecha*/ const ra_nombre_mes = ["Enero", "Febrero", "Marzo", "Abril", "Mayo", "Junio", "Julio", "Agosto", "Setiembre", "Octubre", "Noviembre", "Diciembre"]; const ra_nombre_dia = ["Domingo", "Lunes", "Martes", "Miercoles", "Jueves", "Viernes", "Sabado"]; /*https://www.urianviera.com/javascript/crear-un-id-unico-con-javascript*/ function UniqueId() { return 'id-' + Date.now() + '-' + Math.floor(Math.random() * 1000); }; /***************************************** IDENTIFICADOES UNICOS **************************************************/ /***************************************** IDENTIFICADOES UNICOS **************************************************/ /***************************************** IDENTIFICADOES UNICOS **************************************************/ /* https://chat.qwenlm.ai/c/154850fe-b8a6-4a35-98fd-fb28d86bfa8d 1. Uso de la API navigator en JavaScript function generarIdentificadorUnico(); // Ejecutar la función y mostrar el identificador generarIdentificadorUnico().then(identificador => { console.log("Identificador único:", identificador); }); */ function uniqIdNavigator() { /* Recopilar datos específicos del navegador y dispositivo*/ const userAgent = navigator.userAgent; /* Información del navegador*/ const platform = navigator.platform; /* Plataforma del sistema operativo */ const language = navigator.language; /* Idioma del navegador */ const hardwareConcurrency = navigator.hardwareConcurrency || "unknown"; /* Número de núcleos de CPU*/ const deviceMemory = navigator.deviceMemory || "unknown"; /* Memoria del dispositivo (en GB)*/ const screenResolution = `${window.screen.width}x${window.screen.height}`; /* Resolución de pantalla*/ /* Combinar los datos en una cadena única*/ const cadenaUnica = userAgent + platform + language + hardwareConcurrency + deviceMemory + screenResolution; /* Generar un hash único usando SHA-256 (requiere Crypto API)*/ const encoder = new TextEncoder(); const data = encoder.encode(cadenaUnica); return crypto.subtle.digest("SHA-256", data).then(hash => { /* Convertir el hash a una representación hexadecimal*/ const hashArray = Array.from(new Uint8Array(hash)); const hashHex = hashArray.map(byte => byte.toString(16).padStart(2, "0")).join(""); return hashHex; }); }; /* 2. Uso de la API WebGL para identificar tarjetas gráficas function obtenerInformacionGrafica() { console.log("Información de la tarjeta gráfica:", obtenerInformacionGrafica()); */ function uniqIdWebGl() { const canvas = document.createElement("canvas"); const gl = canvas.getContext("webgl") || canvas.getContext("experimental-webgl"); if (!gl) { return "WebGL no soportado"; }; const debugInfo = gl.getExtension("WEBGL_debug_renderer_info"); if (debugInfo) { const vendor = gl.getParameter(debugInfo.UNMASKED_VENDOR_WEBGL); /* Fabricante de la GPU*/ const renderer = gl.getParameter(debugInfo.UNMASKED_RENDERER_WEBGL); /* Modelo de la GPU*/ return `${vendor} | ${renderer}`; } else { return "Información de GPU no disponible"; }; }; /* 3. Uso de la API FingerprintJS < scriptt src="https://cdn.jsdelivr.net/npm/@fingerprintjs/fingerprintjs@3/dist/fp.min.js" // Inicializar FingerprintJS FingerprintJS.load().then(fp => { // Obtener el identificador único fp.get().then(result => { const visitorId = result.visitorId; console.log("Identificador único generado por FingerprintJS:", visitorId); }); }); */ /* 4. Uso de la API DeviceOrientation o DeviceMotion if (window.DeviceOrientationEvent) { window.addEventListener("deviceorientation", event => { const alpha = event.alpha; // Rotación alrededor del eje Z const beta = event.beta; // Rotación alrededor del eje X const gamma = event.gamma; // Rotación alrededor del eje Y console.log(`Orientación: Alpha=${alpha}, Beta=${beta}, Gamma=${gamma}`); }); } */ /***************************************** IDENTIFICADOES UNICOS **************************************************/ /*https://stackoverflow.com/questions/566564/math-roundnum-vs-num-tofixed0-and-browser-inconsistencies*/ Number.prototype.round = function() { return Math.round(this * 100) / 100; } // https://developer.mozilla.org/es/docs/Web/JavaScript/Reference/Global_Objects/String/Trim if (!String.prototype.trim) { (function() { // Make sure we trim BOM and NBSP var rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g; String.prototype.trim = function() { return this.replace(rtrim, ''); }; })(); }; // globals.ts if(!structuredClone){ function structuredClone(objeto){ const stringified = JSON.stringify(objeto); const parsed = JSON.parse(stringified); return parsed; }; }; // https://flexiple.com/javascript/javascript-capitalize-first-letter/#section2 if (!String.prototype.capitalize) { (function() { String.prototype.capitalize = function(){ var str_capitalize = this.charAt(0).toUpperCase(); var str_text = this.slice(1).toLowerCase(); return str_capitalize + str_text; }; })(); }; //https://developer.mozilla.org/en-US/docs/Glossary/Base64 //function b64EncodeUnicode(str){return btoa(encodeURIComponent(str));} //function UnicodeDecodeB64(str){return decodeURIComponent(atob(str));} function base64_encode(str){return btoa(encodeURIComponent(str));} function base64_decode(str){return decodeURIComponent(atob(str));} /*function rf_url_estatica(reM){ str = reM.replace(/[0-9`~ñ!@#$%^&*()_|+\-=?;:'",.<>\{\}\[\]\\\/]/gi,''); return str; }*/ /* -------------------------------------------------------------------------------*/ /* funciones de texto*/ function rf_string_sin_espacio(arg_obj){ let string = arg_obj.value; arg_obj.value = string.replace(/ /g, ""); } function rf_string_correcto(arg_obj){ let string = arg_obj.value; arg_obj.value = string.replace(/ /g, " "); } /*function rf_tabla_excel(tableID, filename = ''){ //https://programacion.net/articulo/exportar_la_informacion_de_una_tabla_a_excel_mediante_javascript_2014 var downloadLink; var dataType = 'application/vnd.ms-excel'; var tableSelect = document.getElementById(tableID); var tableHTML = tableSelect.outerHTML.replace(/ /g, '%20'); // Specify file name filename = filename?filename+'.xls':'excel_data.xls'; // Create download link element downloadLink = document.createElement("a"); document.body.appendChild(downloadLink); if(navigator.msSaveOrOpenBlob){ var blob = new Blob(['ufeff', tableHTML], { type: dataType }); navigator.msSaveOrOpenBlob( blob, filename); }else{ // Create a link to the file downloadLink.href = 'data:' + dataType + ', ' + tableHTML; // Setting the file name downloadLink.download = filename; //triggering the function downloadLink.click(); } }*/ function rf_tabla_excel(arg_nombre_archivo="Reporte", arg_nombre_hoja="Libro"){ const $tabla = document.querySelector("#TblDatos"); let tableExport = new TableExport($tabla, { exportButtons: false, // No queremos botones filename: arg_nombre_archivo, //Nombre del archivo de Excel sheetname: "Reporte", //Título de la hoja formats: ['xlsx'] }); let datos = tableExport.getExportData(); let preferenciasDocumento = datos.TblDatos.xlsx; tableExport.export2file(preferenciasDocumento.data, preferenciasDocumento.mimeType, preferenciasDocumento.filename, preferenciasDocumento.fileExtension, preferenciasDocumento.merges, preferenciasDocumento.RTL, preferenciasDocumento.sheetname); }; function rf_formato_fecha(arg_fecha){ var fecha = new Date(arg_fecha).getTime(); //alert(fecha.getFullYear() + "-" + fecha.getMonth() + "-" + fecha.getDate()); return fecha.getFullYear() + "-" + fecha.getMonth() + "-" + fecha.getDate(); } //https://www.freecodecamp.org/espanol/news/como-formatear-fechas-en-javascript-con-una-linea-de-codigo/ function rf_fecha_actual(arg_segundo=false){ var fecha = new Date().toISOString(); //alert(fecha.getFullYear() + "-" + fecha.getMonth() + "-" + fecha.getDate()); //rv_fecha = fecha.getFullYear() + "-" + fecha.getMonth() + "-" + fecha.getDate(); ra_fecha = fecha.split("T"); if(arg_segundo){ ra_hora = ra_fecha[1].split("."); return ra_fecha[0] + " " + ra_hora[0]; } return ra_fecha[0]; } //https://es.stackoverflow.com/questions/22073/c%C3%B3mo-obtener-la-diferencia-de-d%C3%ADas-entre-dos-fechas-en-javascript function rf_diferencia_dias(arg_fecha_inicio, arg_fecha_fin){ var fechaInicio = new Date(arg_fecha_inicio).getTime(); var fechaFin = new Date(arg_fecha_fin).getTime(); var diff = fechaFin - fechaInicio; return (diff/(1000*60*60*24) ); } /*function rf_diferencia_minutos(arg_fecha_inicio, arg_fecha_fin){ var fechaInicio = new Date(arg_fecha_inicio).getTime(); var fechaFin = new Date(arg_fecha_fin).getTime(); var diff = fechaFin - fechaInicio; return (diff/(1000*60*60) ); }*/ //https://es.stackoverflow.com/questions/35631/calcular-tiempo-entre-dos-fechas-horas-minutos-y-segundos function rf_diferencia_minutos(arg_fecha_inicio, arg_fecha_fin){ //moment().tz("America/Lima").format(); moment.tz.setDefault("America/Lima"); var fecha1 = moment(arg_fecha_inicio, "YYYY-MM-DD HH:mm:ss"); var fecha2 = moment(arg_fecha_fin, "YYYY-MM-DD HH:mm:ss"); /*var diff = fecha2.diff(fecha1, 'd'); // Diff in days console.log(diff);*/ var diff = fecha2.diff(fecha1, 'm'); // Diff in minutes return (diff); } /*function rf_fecha_agregar_dias(arg_fecha, arg_dias){ var fecha = new Date(arg_fecha); fecha.setDate(fecha.getDate() + arg_dias); alert(fecha); alert(fecha.getMonth()); rv_fecha = fecha.getFullYear() + "-" + fecha.getMonth() + "-" + fecha.getDate(); alert(rv_fecha); return rv_fecha; }*/ function rf_fecha_agregar_dias(arg_fecha, arg_dias){ // https://es.stackoverflow.com/questions/136409/c%C3%B3mo-sumar-d%C3%ADas-a-una-fecha var fecha = new Date(arg_fecha+"T00:00:00"); // fuerza la zona horaria al formato yyyy-MM-ddT00:00:00, si no se hace esto los dias se resta uno (explicación? tiene que ver con la zona horaria y que resta tiempo automáticamente) arg_dias = parseInt(arg_dias); //mis horas que se suman se ingresan por un input fecha.setDate(fecha.getDate() + arg_dias); //lo mismo del pibe fecha.setMonth(fecha.getMonth()); //por alguna razón sumar 1 aquí no ayudaba var finanno = fecha.getFullYear();//guardo año var finmes = fecha.getMonth();//guardo mes var findia = fecha.getDate() < 10 ? '0' + fecha.getDate() : '' + fecha.getDate();//doy formato a dia para que sea de 2 dígitos "01", "05", "10", etc. finmes = finmes + 1; // sume + 1 por que parece que los meses inician desde "0" es decir que enero seria 0 y diciembre seria 11 (para que lo acepte el input date que tengo) finmes = finmes < 10 ? '0' + finmes : '' + finmes; // el mismo tratamiento del día //console.log(finanno+"-"+finmes+"-"+findia); //imprimo por consola la fecha ya correcta rv_fecha = finanno + "-" + finmes + "-" + findia; return rv_fecha; } function rf_calendario_crear_dias(arg_fecha_inicio, arg_fecha_fin){ // https://es.stackoverflow.com/questions/127627/como-hacer-para-mostrar-las-fechas-entre-un-rango-de-fechas-dadas-con-javascrip // https://parzibyte.me/blog/2020/03/09/javascript-dia-semana-segun-fecha/ var rv_fecha_actual=new Date(); var ra_dia = ["Dom","Lun","Mar","Mir","Juv","Vie","Sab"]; var ra_mes = ["Ene","Feb","Mar","Abr","May","Jun","Jul","Ago","Set","Oct","Nov","Dic"]; var rv_fechas=[]; var fechaInicio = new Date(arg_fecha_inicio); var fechaFin = new Date(arg_fecha_fin); while(fechaFin.getTime() >= fechaInicio.getTime()){ fechaInicio.setDate(fechaInicio.getDate() + 1); //rv_fecha_actual = fechaInicio.getFullYear() + '/' + (fechaInicio.getMonth() + 1) + '/' + fechaInicio.getDate(); rv_numero_dia = fechaInicio.getDay(); if(rv_fecha_actual.getFullYear() == fechaInicio.getFullYear() && rv_fecha_actual.getMonth() == fechaInicio.getMonth() && rv_fecha_actual.getDay() == fechaInicio.getDay()){ //if(rv_fecha_actual == fechaInicio){ rv_dia_actual = true; }else{ rv_dia_actual = false; } var rv_fecha = { FechaActual: rv_fecha_actual, NombreDia: ra_dia[rv_numero_dia], NombreMes: ra_mes[fechaInicio.getMonth()], DiaActual: rv_dia_actual, Dia: fechaInicio.getDate(), Mes: fechaInicio.getMonth(), Anio: fechaInicio.getFullYear() }; rv_fechas.push(rv_fecha); } //console.log(rv_fechas); return rv_fechas; } function rf_generar_password() { // https://barcelonageeks.com/como-generar-una-contrasena-aleatoria-usando-javascript/ var pass = ''; var str = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' + 'abcdefghijklmnopqrstuvwxyz0123456789@#$'; for (let i = 1; i <= 8; i++) { var char = Math.floor(Math.random() * str.length + 1); pass += str.charAt(char) } return pass; } /* *************************************************************************************************BOOTBOX*/ //cargamos bootbox /*loadScript('https://iniciativaperu.com/assets/bootbox/bootbox6.0.0.js') .then(() => { window.dataLayer = window.dataLayer || [] //gtag('js', new Date()) //gtag('config', 'UA-XXXXX-Y') }).catch(console.error);*/ function rf_alert(arg_mensaje, arg_function_ok=null, arg_modo="alert"){ bootbox.alert(arg_mensaje, function(){ if(arg_function_ok!=null){ arg_function_ok(); } }); }; function rf_confirm(arg_mensaje, arg_function_yes, arg_function_no=null){ //uso del Bootbox bootbox.confirm({ title: 'Sistema CMS', message: arg_mensaje, buttons: { cancel:{ label: ' Cancelar' }, confirm: { label: ' Aceptar' } }, callback: function (result) { if(result){ arg_function_yes(); }else{ if(arg_function_no!=null){ arg_function_no(); }; }; } }); /* alertify.confirm( "Sistema CMS", arg_mensaje, function(){ arg_function_yes(); },function(){ if(arg_function_no!=null){ arg_function_no(); }; });*/ }; function rf_dato_valida(arg_valor){ if(arg_valor==null || typeof arg_valor=="undefined"){ return false; }else{ return true; }; }; // https://parzibyte.me/blog/2019/05/20/previsualizar-imagen-input-file-javascript-html/ function rf_input_file_preview(arg_input_file, arg_image_preview){ const $seleccionArchivos = document.querySelector("#"+arg_input_file), $imagenPrevisualizacion = document.querySelector("#"+arg_image_preview); // Los archivos seleccionados, pueden ser muchos o uno const archivos = $seleccionArchivos.files; // Si no hay archivos salimos de la función y quitamos la imagen if (!archivos || !archivos.length) { $imagenPrevisualizacion.src = ""; return; } // Ahora tomamos el primer archivo, el cual vamos a previsualizar const primerArchivo = archivos[0]; // Lo convertimos a un objeto de tipo objectURL const objectURL = URL.createObjectURL(primerArchivo); // Y a la fuente de la imagen le ponemos el objectURL $imagenPrevisualizacion.src = objectURL; }; rf_fecha_formato=function(arg_fecha){ var f = new Date(arg_fecha); rv_dia=Number(); if(Number(f.getDate())<10){ rv_dia="0" + Number(f.getDate()); }else{ rv_dia=f.getDate(); }; rv_mes = f.getMonth() + 1; if(Number(rv_mes)<10){ rv_mes="0" + rv_mes; }else{ rv_mes=f.getDate(); }; return (f.getFullYear() + "-" + rv_mes + "-" + rv_dia); }; function rf_keypress_number(event){ /*https://es.stackoverflow.com/questions/70351/validacion-campo-input-text-solo-debe-aceptar-numeros-javascript*/ if(event.charCode >= 48 && event.charCode <= 57){return true;}; return false; }; function rf_ir_a(arg_url){document.location.href=arg_url;}; var rhino={ rf_url_estatica:function(arg_texto){ if(arg_texto==null){ return ""; }; str = arg_texto.replace(/[`~ñ!@#$%^&*()_|+\-=?;:'",.<>\{\}\[\]\\\/]/gi,'').replace(/ /g,'-'); str = str.toLowerCase(); return str; }, /**/ rf_dato_error:function(arg_input){ if(arg_input=="undefined"||typeof arg_input=="object"||arg_input=="null"||arg_input==""){ return true; }; return false; }, /*sistema*/ rf_copiar_texto:function(arg_text){ navigator.clipboard.writeText(arg_text); console.log("Texto Copiado!!!"); }, count:function (obj){ let lengthOfObject = Object.keys(obj).length; return(lengthOfObject); }, rf_fecha_guion:function(arg_fecha){ ra_fecha = arg_fecha.split("-"); var f = new Date(parseInt(ra_fecha[0]), parseInt(ra_fecha[1]) - 1, parseInt(ra_fecha[2])); return f; rv_dia = ra_nombre_dia[f.getDay()]; rv_mes = ra_nombre_mes[f.getMonth()]; rv_fecha = rv_dia + ", " + f.getDate() + " / " + rv_mes + " de " + f.getFullYear(); return rv_fecha; }, rf_fecha_texto:function(arg_fecha){ ra_fecha = arg_fecha.split("-"); var f = new Date(parseInt(ra_fecha[0]), parseInt(ra_fecha[1]) - 1, parseInt(ra_fecha[2])); rv_dia = ra_nombre_dia[f.getDay()]; rv_mes = ra_nombre_mes[f.getMonth()]; rv_fecha = rv_dia + ", " + f.getDate() + " de " + rv_mes + " de " + f.getFullYear(); return rv_fecha; }, rf_edad:function(fecha){ var hoy = new Date(); var cumpleanos = new Date(fecha); var edad = hoy.getFullYear() - cumpleanos.getFullYear(); var m = hoy.getMonth() - cumpleanos.getMonth(); if (m < 0 || (m === 0 && hoy.getDate() < cumpleanos.getDate())) { edad--; } return edad; }, rf_fecha_formato:function(arg_fecha, arg_todo=false){ var f = new Date(arg_fecha); rv_dia=Number(); if(Number(f.getDate())<10){ rv_dia="0" + Number(f.getDate()); }else{ rv_dia=f.getDate(); }; rv_mes = f.getMonth() + 1; if(Number(rv_mes)<10){ rv_mes="0" + rv_mes; };/*else{ rv_mes=f.getDate(); };*/ /*alert(rv_mes);*/ rv_fecha = (f.getFullYear() + "-" + rv_mes + "-" + rv_dia); if(arg_todo==false){ return rv_fecha; }else{ rv_hora=f.getHours()<10?"0"+f.getHours():f.getHours(); rv_minuto=f.getMinutes()<10?"0"+f.getHours():f.getMinutes(); rv_fecha += " " + rv_hora + ":" + rv_minuto + ":" + "00"; return rv_fecha; } }, rf_fecha_mes_formato(arg_mes){ arg_mes = Number(arg_mes); if(arg_mes<10){ return "0" + arg_mes; }else{ return arg_mes; } }, rf_fecha_hora_minuto:function(arg_fecha){ var f = new Date(arg_fecha); rv_hora=f.getHours()<10?"0"+f.getHours():f.getHours(); rv_minuto=f.getMinutes()<10?"0"+f.getMinutes():f.getMinutes(); rv_fecha = rv_hora + ":" + rv_minuto; rv_fecha += (f.getHours()<12)?" AM":" PM"; return rv_fecha; }, rf_fecha_string:function(arg_fecha){ ra_fecha = arg_fecha.split("-"); var f = new Date(parseInt(ra_fecha[0]), parseInt(ra_fecha[1]) - 1, parseInt(ra_fecha[2])); rv_dia = ra_nombre_dia[f.getDay()]; rv_mes = ra_nombre_mes[f.getMonth()]; rv_fecha = rv_dia + ", " + f.getDate() + " / " + rv_mes + " de " + f.getFullYear(); return rv_fecha; }, rf_fecha_2_igual:function(arg_fecha1, arg_fecha2){ var f1 = new Date(arg_fecha1); var f2 = new Date(arg_fecha2); if(f1.getFullYear()==f2.getFullYear() && f1.getMonth()==f2.getMonth() && f1.getDate()==f2.getDate()){ return true; }else{ return false; }; }, rf_fecha_aumenta_dias:function(arg_fecha, arg_dias=1){ /*https://codepen.io/logoys/pen/PRoZxJ*/ var date = arg_fecha.split("-"), rv_fecha_actual = new Date(date[0], date[1], date[2]), arg_dias = parseInt(arg_dias), rv_fecha_nueva = new Date(), /*dateResul = operacion == "sumar" ? hoy.getDate() + dias : hoy.getDate() - dias;*/ rv_resultado = rv_fecha_actual.getDate() + arg_dias; rv_fecha_nueva.setDate(rv_resultado); return this.rf_fecha_formato(rv_fecha_nueva); //return arg_fecha; var rv_fecha = new Date(arg_fecha); var rv_dias = arg_dias; /* Número de días a agregar */ rv_fecha.setDate(rv_fecha.getDate() + rv_dias); return this.rf_fecha_formato(rv_fecha); }, rf_fecha_aumenta_mes:function(arg_fecha, arg_mes = 1){ var rv_fecha_ingreso = moment(arg_fecha); var rv_fecha_final = rhino.rf_fecha_formato(rv_fecha_ingreso.clone().add(arg_mes, "month")); return this.rf_fecha_formato(rv_fecha_final); /*arg_fecha = new Date(arg_fecha + "T00:00:00"); arg_fecha.setMonth(arg_fecha.getMonth() + arg_mes); return this.rf_fecha_formato(arg_fecha);*/ }, rf_fecha_dias_mes:function(arg_anio, arg_mes) { return new Date(arg_anio, Number(arg_mes), 0).getDate(); }, rf_fecha_diferencia_dias:function(arg_fecha_inicio, arg_fecha_fin){ /* ******************* //https://es.stackoverflow.com/questions/22073/c%C3%B3mo-obtener-la-diferencia-de-d%C3%ADas-entre-dos-fechas-en-javascript //var fechaInicio = new Date('2016-07-12').getTime(); //var fechaFin = new Date('2016-08-01').getTime(); //var diff = fechaFin - fechaInicio; //console.log(diff/(1000*60*60*24) ); */ var fechaInicio = new Date(arg_fecha_inicio).getTime(); //var fechaInicio = new Date().getTime(); var fechaFin = new Date(arg_fecha_fin).getTime(); var diff = fechaFin - fechaInicio; return Math.trunc(diff/(1000*60*60*24)); }, rf_dato_diferente_de:function(...arg_param){ }, rf_url:function(arg_texto) { // Reemplaza los carácteres especiales | simbolos con un espacio arg_texto = arg_texto.replace(/[`~!@#$%^&*()_\-+=\[\]{};:'"\\|\/,.<>?\s]/g, ' ').toLowerCase(); // Corta los espacios al inicio y al final del sluging arg_texto = arg_texto.replace(/^\s+|\s+$/gm, ''); // Reemplaza el espacio con guión arg_texto = arg_texto.replace(/\s+/g, '-'); // Creo la URL en el campo de texto 'url' //var input = document.getElementById('url'); //input.value = arg_texto; // Creo la URL en el elemento span 'texto-url' // document.getElementById("texto-url").innerHTML = slug; return arg_texto; }, rf_rubro:function(arg_rubro){ return arg_rubro; }, };