UNPKG

laceside

Version:

In-browser JavaScript IDE and execution environment

489 lines (445 loc) 14.7 kB
import {a7} from '/lib/altseven/dist/a7.js'; import {bubble, constructor, dialog} from '/lib/gadget-ui/dist/gadget-ui.es.js'; export { formatDate, addModLazy, showNotice, showDialog, addTag, formatDateByOffset, takeOverConsole, detectClickOutside, debounce, checkPasswordStrength }; var formatDate = function( dateString, format ){ let date = new Date( dateString ); let dateStr = ""; let options = { month: 'short'}; switch( format ){ case "mm/dd/yyyy": dateStr = ( date.getMonth() + 1 ) + "/" + date.getDate() + "/" + date.getFullYear(); break; case "mmm dd": dateStr = new Intl.DateTimeFormat('en-US', options).format( date ) + " " + ( date.getMonth() + 1 ); dateStr += ordinalForNumber( dateStr.substring( dateStr.length - 1, dateStr.length ) ); break; case "mmm dd yyyy": dateStr = new Intl.DateTimeFormat('en-US', options).format( date ) + " " + ( date.getMonth() + 1 ) + " " + date.getFullYear(); break; } return dateStr; }, showNotice = function( message, selector ){ document.getElementById("headerMiddle").innerHTML = message; setTimeout( ()=>{ document.getElementById("headerMiddle").innerHTML = ''; },3000 ); }, showDialog = function( title, message, buttons ){ if( document.querySelector( "#dialog" ) === null ){ let div = document.createElement( "div" ); div.setAttribute( "id", "dialog" ); document.body.appendChild( div ); } return constructor( dialog, [ document.querySelector( "#dialog" ), { class: "sysDialog", width: 400, title : title, message: message, enableShrink : false, overflow: "hidden", buttons: buttons }] ); }, addModLazy = function( doc ){ let mlTag = doc.createElement("script"); mlTag.setAttribute( "src", "/lib/modlazy/dist/modlazy.js" ); mlTag.setAttribute( "class", "jsapp" ); doc.head.appendChild( mlTag ); }, addTag = function( arr, doc, type, href, code ){ arr.push( doc.createElement( type ) ); arr[ arr.length - 1 ].setAttribute( "class", "jsapp" ); if( type === 'link' ){ arr[ arr.length - 1 ].setAttribute( "rel", "stylesheet" ); arr[ arr.length - 1 ].setAttribute( "href", href ); } if( a7.model.get( "app" ).esModule && type === 'script' ){ arr[ arr.length - 1 ].setAttribute( "type", "module" ); } if( code !== undefined ){ let inline = doc.createTextNode( code ); arr[ arr.length - 1 ].appendChild( inline ); } return arr; }, formatDateByOffset = function( dateString ){ let now = new Date(); let date = new Date( dateString ); // divide to get difference in minutes let timediff = ( now - date ) / 60000; let dateStr = ""; if( timediff < 1 ){ dateStr = "now"; }else if( timediff < 60 ){ dateStr = Math.round( timediff ) + "m"; }else if( timediff < 1440 ){ dateStr = Math.round( timediff / 60 ) + "h"; }else if( now.getFullYear() === date.getFullYear() ){ dateStr = formatDate( dateString, "mmm dd" ); }else{ dateStr = formatDate( dateString, "mmm dd yyyy" ); } return dateStr; }, ordinalForNumber = function( number ){ let suffix = "th"; console.log( "date: " + number ); switch( parseInt( number ) ){ case 1: suffix = "st"; break; case 2: suffix = "nd"; break; case 3: suffix = "rd"; break; default: suffix = "th"; break; } return suffix; }, // this bit of code based on solution: // http://tobyho.com/2012/07/27/taking-over-console-log/ takeOverConsole = function(){ var win = document.getElementById('iframe').contentWindow; var console = win.console; if (!console) return; function intercept(method){ var original = console[method]; console[method] = function(){ let consoleText = a7.ui.views['console'].state.consoleText; a7.ui.views['console'].setState( { consoleText: consoleText + "<div class='log'>" + Array.prototype.slice.apply(arguments).join(' ') + "</div>" } ); if (original.apply){ // Do this for normal browsers original.apply(console, arguments); }else{ // Do this for IE var message = Array.prototype.slice.apply(arguments).join(' '); // capture and push to our output div a7.log.info( "intercept output: " + methods[i] ); original(message); } } } var methods = ['log', 'warn', 'error']; for (var i = 0; i < methods.length; i++){ intercept(methods[i]); } a7.error.on( 'scriptError', function( component, args ){ let consoleText = a7.ui.views['console'].state.consoleText; a7.ui.views['console'].setState( { consoleText: consoleText + "<div class='error'>" + args[0] + "</div>" } ); }); }, detectClickOutside = function( element ){ return new Promise( function( resolve, reject ){ const outsideClickListener = event => { if (!element.contains(event.target)) { // or use: event.target.closest(selector) === null removeClickListener() resolve() } } const removeClickListener = () => { document.removeEventListener('click', outsideClickListener) } document.addEventListener('click', outsideClickListener) }); }; // debounce extracted from Lodash, license below /** * @license * Lodash <https://lodash.com/> * Copyright JS Foundation and other contributors <https://js.foundation/> * Released under MIT license <https://lodash.com/license> * Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE> * Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors */ /** * Creates a debounced function that delays invoking `func` until after `wait` * milliseconds have elapsed since the last time the debounced function was * invoked. The debounced function comes with a `cancel` method to cancel * delayed `func` invocations and a `flush` method to immediately invoke them. * Provide `options` to indicate whether `func` should be invoked on the * leading and/or trailing edge of the `wait` timeout. The `func` is invoked * with the last arguments provided to the debounced function. Subsequent * calls to the debounced function return the result of the last `func` * invocation. * * **Note:** If `leading` and `trailing` options are `true`, `func` is * invoked on the trailing edge of the timeout only if the debounced function * is invoked more than once during the `wait` timeout. * * If `wait` is `0` and `leading` is `false`, `func` invocation is deferred * until to the next tick, similar to `setTimeout` with a timeout of `0`. * * See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/) * for details over the differences between `_.debounce` and `_.throttle`. * * @static * @memberOf _ * @since 0.1.0 * @category Function * @param {Function} func The function to debounce. * @param {number} [wait=0] The number of milliseconds to delay. * @param {Object} [options={}] The options object. * @param {boolean} [options.leading=false] * Specify invoking on the leading edge of the timeout. * @param {number} [options.maxWait] * The maximum time `func` is allowed to be delayed before it's invoked. * @param {boolean} [options.trailing=true] * Specify invoking on the trailing edge of the timeout. * @returns {Function} Returns the new debounced function. * @example * * // Avoid costly calculations while the window size is in flux. * jQuery(window).on('resize', _.debounce(calculateLayout, 150)); * * // Invoke `sendMail` when clicked, debouncing subsequent calls. * jQuery(element).on('click', _.debounce(sendMail, 300, { * 'leading': true, * 'trailing': false * })); * * // Ensure `batchLog` is invoked once after 1 second of debounced calls. * var debounced = _.debounce(batchLog, 250, { 'maxWait': 1000 }); * var source = new EventSource('/stream'); * jQuery(source).on('message', debounced); * * // Cancel the trailing debounced invocation. * jQuery(window).on('popstate', debounced.cancel); */ var debounce = function debounce(func, wait, options) { var lastArgs, lastThis, maxWait, result, timerId, lastCallTime, lastInvokeTime = 0, leading = false, maxing = false, trailing = true; if (typeof func != 'function') { throw new TypeError(FUNC_ERROR_TEXT); } wait = toNumber(wait) || 0; if (isObject(options)) { leading = !!options.leading; maxing = 'maxWait' in options; maxWait = maxing ? nativeMax(toNumber(options.maxWait) || 0, wait) : maxWait; trailing = 'trailing' in options ? !!options.trailing : trailing; } function invokeFunc(time) { var args = lastArgs, thisArg = lastThis; lastArgs = lastThis = undefined; lastInvokeTime = time; result = func.apply(thisArg, args); return result; } function leadingEdge(time) { // Reset any `maxWait` timer. lastInvokeTime = time; // Start the timer for the trailing edge. timerId = setTimeout(timerExpired, wait); // Invoke the leading edge. return leading ? invokeFunc(time) : result; } function remainingWait(time) { var timeSinceLastCall = time - lastCallTime, timeSinceLastInvoke = time - lastInvokeTime, timeWaiting = wait - timeSinceLastCall; return maxing ? nativeMin(timeWaiting, maxWait - timeSinceLastInvoke) : timeWaiting; } function shouldInvoke(time) { var timeSinceLastCall = time - lastCallTime, timeSinceLastInvoke = time - lastInvokeTime; // Either this is the first call, activity has stopped and we're at the // trailing edge, the system time has gone backwards and we're treating // it as the trailing edge, or we've hit the `maxWait` limit. return (lastCallTime === undefined || (timeSinceLastCall >= wait) || (timeSinceLastCall < 0) || (maxing && timeSinceLastInvoke >= maxWait)); } function timerExpired() { var time = now(); if (shouldInvoke(time)) { return trailingEdge(time); } // Restart the timer. timerId = setTimeout(timerExpired, remainingWait(time)); } function trailingEdge(time) { timerId = undefined; // Only invoke if we have `lastArgs` which means `func` has been // debounced at least once. if (trailing && lastArgs) { return invokeFunc(time); } lastArgs = lastThis = undefined; return result; } function cancel() { if (timerId !== undefined) { clearTimeout(timerId); } lastInvokeTime = 0; lastArgs = lastCallTime = lastThis = timerId = undefined; } function flush() { return timerId === undefined ? result : trailingEdge(now()); } function debounced() { var time = now(), isInvoking = shouldInvoke(time); lastArgs = arguments; lastThis = this; lastCallTime = time; if (isInvoking) { if (timerId === undefined) { return leadingEdge(lastCallTime); } if (maxing) { // Handle invocations in a tight loop. timerId = setTimeout(timerExpired, wait); return invokeFunc(lastCallTime); } } if (timerId === undefined) { timerId = setTimeout(timerExpired, wait); } return result; } debounced.cancel = cancel; debounced.flush = flush; return debounced; }; /** * Converts `value` to a number. * * @static * @memberOf _ * @since 4.0.0 * @category Lang * @param {*} value The value to process. * @returns {number} Returns the number. * @example * * _.toNumber(3.2); * // => 3.2 * * _.toNumber(Number.MIN_VALUE); * // => 5e-324 * * _.toNumber(Infinity); * // => Infinity * * _.toNumber('3.2'); * // => 3.2 */ var toNumber = function toNumber(value) { if (typeof value == 'number') { return value; } if (isSymbol(value)) { return NAN; } if (isObject(value)) { var other = typeof value.valueOf == 'function' ? value.valueOf() : value; value = isObject(other) ? (other + '') : other; } if (typeof value != 'string') { return value === 0 ? value : +value; } value = value.replace(reTrim, ''); var isBinary = reIsBinary.test(value); return (isBinary || reIsOctal.test(value)) ? freeParseInt(value.slice(2), isBinary ? 2 : 8) : (reIsBadHex.test(value) ? NAN : +value); }; /** * Checks if `value` is the * [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types) * of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`) * * @static * @memberOf _ * @since 0.1.0 * @category Lang * @param {*} value The value to check. * @returns {boolean} Returns `true` if `value` is an object, else `false`. * @example * * _.isObject({}); * // => true * * _.isObject([1, 2, 3]); * // => true * * _.isObject(_.noop); * // => true * * _.isObject(null); * // => false */ var isObject = function isObject(value) { var type = typeof value; return value != null && (type == 'object' || type == 'function'); }; /** * Gets the timestamp of the number of milliseconds that have elapsed since * the Unix epoch (1 January 1970 00:00:00 UTC). * * @static * @memberOf _ * @since 2.4.0 * @category Date * @returns {number} Returns the timestamp. * @example * * _.defer(function(stamp) { * console.log(_.now() - stamp); * }, _.now()); * // => Logs the number of milliseconds it took for the deferred invocation. */ var now = function() { return Date.now(); }; // https://github.com/deanilvincent/check-password-strength // Copyright (c) 2020 Mark Deanil Vicente // Licensed under the MIT License var checkPasswordStrength = function(password){ if (!password) { console.error("check-password-strength package - requires a password value."); return undefined; } let strength = {}; // Default const strongRegex = new RegExp( "^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[!@#$%^&*])(?=.{8,})" ); const mediumRegex = new RegExp( "^(((?=.*[a-z])(?=.*[A-Z]))|((?=.*[a-z])(?=.*[0-9]))|((?=.*[A-Z])(?=.*[0-9])))(?=.{6,})" ); if (strongRegex.test(password)) { strength = { id: 2, value: 'Strong' }; } else if (mediumRegex.test(password)) { strength = { id: 1, value: 'Medium' }; } else { strength = { id: 0, value: 'Weak' }; } return strength; };