5.0.4 • Published 1 year ago

@lawrencesim/web-common v5.0.4

Weekly downloads
324
License
MIT
Repository
github
Last release
1 year ago

Web Common

Web Common is a collection of polyfills, extensions, and modules I repeatedly found myself reapplying on new projects.

Lawrence Sim © 2024

This library is licensed under the MIT License. See LICENSE file for full text.

Content

Usage

Installation is best handled via NPM:

npm install @lawrencesim/web-common

Libraries can be imported with ES6 syntax as follows:

import common from '@lawrencesim/web-common';
import '@lawrencesim/web-common/style.css';
import CommonTable from '@lawrencesim/web-common/CommonTable';

The first import will bring in the common module, including polyfills/extensions, and the UI submodule. If using the UI submodule or CommonTable module, you will also need to load the styles (second line), but otherwise, this can be left out. Note that depending on build configuration (e.g. Webpack) you may need proper style handlers to load the CSS styles. The final line loads the optional CommonTable class.

If using script imports in HTML, import the paths to common.js, style.css, and/or CommonTable.js as needed in the main directory. The main module will be added as common and CommonTable as CommonTable to the global namespace.

 

Version 5 breaking changes

  • Number.prototype.addCommasSmart() is removed. Use Number.prototype.stringFormat() instead.
  • String.prototype.heuristicCompare() is removed. Use String.prototype.semanticCompare() instead.
  • common.extend(), parameters are renamed overwrite, deep, and modify from allowOverwrite, deepCopy, and modifyObj. While detection is still left in for older names for backwards compatibility, it may be deprecated at some point.
  • common.newWindow() no longer accepts flat parameters. All parameters except for url (and optoinally name) must be specified in an options object.
  • common.animate(), parameters are renamed duration and timing from durationMs, and timingFunction. While detection is still left in for older names for backwards compatibility, it may be deprecated at some point.

 

Polyfills

Ensures the below functions exists, many of which are missing in Internet Explorer (pre-Edge) and Opera Mini.

Note that this is just a personal list of functions I tended to require (combined with a history of having to work with gov't clients that were still stuck in IE land). These days, probably less necessary, and if so, better to use a more complete polyfill library like core-js.

# Array.from(arrayLike[, mapFn, thisArg])

Create array from array-like or iterable.

See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/from

# Array.prototype.find(callback, thisArg)

Find item in an array.

See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find

# Array.prototype.findIndex(callback, thisArg)

Find index of an item in an array.

See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/findIndex

# Array.prototype.findLast(callback, thisArg)

Find item in an array, searching in reverse.

See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/findLast

# Array.prototype.findLastIndex(callback, thisArg)

Find index of an item in an array, searching in reverse.

See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/findLastIndex

# Array.prototype.flat(depth)

Flatten an array to a desired depth (or default single-depth).

See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/flat

# Array.prototype.includes(searchElement, fromIndex)

Find if an item exists in an array.

See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/includes

# Element.prototype.remove()

Remove element.

See https://developer.mozilla.org/en-US/docs/Web/API/ChildNode/remove

# Element.prototype.append(nodes)

Append to element.

See https://developer.mozilla.org/en-US/docs/Web/API/ParentNode/append

# Element.prototype.prepend(nodes)

Prepend to element.

See https://developer.mozilla.org/en-US/docs/Web/API/ParentNode/prepend

# Element.prototype.matches(selectors)

Check if element matches selector.

See https://developer.mozilla.org/en-US/docs/Web/API/Element/matches

# Element.prototype.closest(selectors)

Find closest element matching selector.

See https://developer.mozilla.org/en-US/docs/Web/API/Element/closest

# Element.classList

Ensures existence of contains(), add(), remove(), toggle(), and replace() functions in element's classList property.

See https://developer.mozilla.org/en-US/docs/Web/API/Element/classList

Note that IE and Edge cannot support classList on SVG elements (no polyfill available).

# NodeList.prototype.forEach(callback, *thisArg*)

Functionally iterate through a NodeList.

See https://developer.mozilla.org/en-US/docs/Web/API/NodeList/forEach

# String.prototype.startsWith(searchString, position)

Check string starts with sequence.

See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/startsWith

# String.prototype.endsWith(searchString, length)

Check string ends with sequence.

See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/endsWith

# String.prototype.repeat(count)

Repeat string content.

See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/repeat

 

Promises

Internally, taylorhakes/promise-polyfill is called, if necessary, to polyfill for Promises. However, it is only used locally and not added to the global namespace. As it's very lightweight (and I don't want to simply wrap/repackage Taylor's work), I recommend installing his library directly to your projects if you need a polyfill for Promises. Thus, if you think you will need to polyfill for Promises, bring in this library to your dependencies or else a error will occur when using common.ajax() or common.animate() in a browser without support for Promises.

 

Global Browser Variable

Two variables are added to the window namespace (if it exists) that stores browser information.

ParamDescription
browserStores information on browser type and version.
browserTypeAlias for browser, left for backwards compatibility.

Note there are two formats in which data exists as browser information. One is a simple string parse of the UserAgent and version as key name and value. For certain user agents this may return multiple results. However there may exist a secondary is- variable, which is heuristically determined, that will give the specific browser it is most likely determined to be.

E.g. for Opera browsers, with an example user agent of "Mozilla/5.0 (Windows NT 10.0; WOW64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.150 Safari/537.36 OPR/74.0.3911.75", the browser object will show three separate browser versions and an isOpera variable:

{
  chrome: 88, 
  safari: 537, 
  opera: 74, 
  isOpera: true
}

Similarly, the variable might be isChrome or isFirefox or isEdge, as the case dictates.

Currently, this checks for the following known browsers: isChrome, isFirefox, isEdge, isIE, isSafari, isOpera, isBrave, isSamsungInternet, isUCBrowser, isYandex, is360SecureBrowser, isQQBrowser, isInstabridge, isVivaldi, isCocCoc (Cốc Cốc), isWhale (Navar Whale), isPuffin, isSleipnir, isAmazonSilk, and isQtWebEngine.

For browsers on iOS – which Apple forces to be basically skins of Safari Mobile – these may not always be identified correctly as Safari through the user agent name. For what it's worth, Chrome, Firefox, and Edge flavors will have versions under crios, fiox, and edgios while correctly identifying it as a Safari Browser.

Note that this method of parsing the UserAgent string is somewhat brittle and can be unreliable, especially for those lesser-seen browsers or those specific to devices (like tablets, smart TVs, or gaming consoles). Where browser detection critical, it is generally preferred to use feature detection instead.

 

Prototype Modifications

These useful functions are added to common object prototypes.

# Array.getOverlaps(a, b) ⇒ Array # Array.prototype.getOverlaps(arr) ⇒ Array

Get overlapping values with second array. Can be called from array instance or Array global. Uses strict equality.

# Array.overlaps(a, b) ⇒ boolean # Array.prototype.overlaps(arr) ⇒ boolean

Check if at least one value overlaps with second array. Can be called from array instance or Array global. Uses strict equality.

# Array.prototype.remove(value[, index, limit]) ⇒ Array

Remove all instances of a value from an array. Value matching uses strict equality. Creates a copy of the array without modifying the original array.

Set index to define the index at which to start indexing. Negatives are allowed to find a position from reverse. If the index is greater than or equal to the length of the array, the array is not searched and nothing is removed.

Set limit to a positive value to define a limit to the number of times the value will be removed. Otherwise, the removal allowance is unlimited.

# Element.prototype.isVisible() ⇒ boolean

Check is element is visible. Uses getBoundingClientRect method, which is more reliable than the old offsetParent trick.

# Element.prototype.setAttributes(attrs)

Sets multiple attributes (given as a dictionary-like object of key-value pairs) at once.

# Element.prototype.css(style, value)

Much like the JQuery css() function, sets inline style, either as style name and value provided as strings, or as a dictionary-like object of style names and values and key-value pairs.

# Element.prototype.center()

Will center an element on screen using absolute positioning.

# Number.prototype.addCommas(precision) ⇒ string

Will convert a given number to a string, using the supplied precision, with commas.

# Number.prototype.stringFormat([minimum=0.001, zeroFormat="0.0") ⇒ string

Basically wraps Number.prototype.addCommas() with heuristic guessing on precision to use. The minimum parameter rounds any value whose absolute value is less than this to zero. The zeroFormat parameter can be used to customize how zero values are printed. By default it is "0.0".

Current heuristics are:

  • Evaluation to zero is always written in the zero format (default "0.0")
  • \<0.01 as scientific notation with three significant figures
  • \<0.1 as scientific notation with two significant figures
  • \<0.3 as number with three decimal places
  • \<1.0 as number with two decimal places
  • \<100 as number with one decimal place
  • ≥100 as number with no decimal places

# Object.isObject(obj) ⇒ boolean

Check is given object is an object-type. That is, not a primitive, string, or array. This includes any inheritance of the object prototype, except for arrays.

Uses typeof check with extra handling to invalidate array types.

# Object.isObjectLiteral(obj) ⇒ boolean

Check is given object is an object literal-type. That is, not a primitive, string, array, or even any inheritance of the Object prototype. Must be a base object created either as an object literal or via new Object(). Useful for when parameters must be ensured as an object-literal/dictionary.

Uses Object.getPrototypeOf() check.

# String.prototype.capitalize(breaks) ⇒ string

Will capitalize the each word in the string (using whitespace to delineate words).

Additional break characters can be provided as either an array of characters or a string of all characters in the optional parameter breaks. E.g., to include hyphens, "up-to-date".capitalize("-") will output Up-To-Date.

# String.prototype.semanticCompare(compareString, options) ⇒ number

A semantic comparison of strings with numeric values within them. Compare the numbers in a string such that a "number" is not compared alphabetically by character but as the entire numeric value.

E.g., a typical string comparisons would result in '20' coming before '5', because string comparisons evaluate character by character, first looking at the '2' and '5' characters. This function ensures the entire '20' is considered as one number.

Returns numeric indicating whether this string comes before (-1), after (1), or is equal (0) to compared string. As such, can be inserted into most sort functions such as Array.prototype.sort() within the compare function.

"x01x02".semanticCompare("x1x2");  //  0 is semantically equal
"x20".semanticCompare("x1");       //  1 comes after
"x9".semanticCompare("x999");      // -1 comes before
"b1".semanticCompare("a2");        //  1 comes after

Each string is broken into chunks of parsable numeric and non-numeric chunks. Each chunk is compared in similar sequences. When both compared chunks are parsable numbers, they will be compared numerically. If either is not, they will be compared as strings. E.g. "a10bc40" and "a10b50c" would be broken up into ['a', '10', 'bc', '40'] and ['a', '10', 'b', '50', 'c'] respectively. The crux of the comparison would happen at the chunks "bc" vs "b" (wherein "b" comes before "bc"), and the comparison of chunks "40" and "50" would be irrelevant.

"a10bc40".semanticCompare("a10b50c");  // 1

By default, negative numbers and decimals are not handled as dashes and periods may not be considered part of the number, depending on the string. This can be switched by setting as truthy either/both the optional parameters options.handleNegative and/or options.handleDeciaml. If enabling decimals in particular, ensure numbers are properly formatted. E.g. a value of "3.2.1" would result in a numeric parsing two separate values of "3.2" and "0.1".

"x-2".semanticCompare("x-1");  // 1
"x-2".semanticCompare("x-1", {handleNegative: true});  // -1

 

Date (UTC) Modifications

Additional functions for handling basic Date objects are added. Specifically to ensure UTC handling.

# DateUTC(year, month, day[, hour[, min, sec]]) ⇒ Date

Creates a datetime, forced as UTC. Month is to be indicated as number from 1-12 (unlike traditional Date constructor as 0-11).

# Date.prototype.asUTC() ⇒ Date

Converts datetime to UTC assuming time given (assumed localtime) was actually meant as UTC time. That is to say, Does not convert localtime to UTC and simply passes the time values as they exist. The date/time in localtime will be kept as the UTC date/time, only changing the timezone to UTC.

d = new Date(2019, 0, 1, 20);  // Tue Jan 01 2019 20:00:00 GMT-0800 (Pacific Standard Time)
d.asUTC();                     // Tue Jan 01 2019 12:00:00 GMT-0800 (Pacific Standard Time)

In the above conversion, assumed the date of Jan 1 2019 at 20:00 was meant as UTC and adjust the timezone without converting the time. When printing the date, which in javascript is by default converted to localtime (in this case PST), it 8 hours earlier but corresponds to 20:00 UTC.

# Date.prototype.toUTC() ⇒ Date

Creates new DateUTC using the UTC datetime of this object, converted from localtime.

d = new Date(2019, 0, 1, 20);  // Tue Jan 01 2019 20:00:00 GMT-0800 (Pacific Standard Time)
d.toUTC();                     // Tue Jan 01 2019 20:00:00 GMT-0800 (Pacific Standard Time)

As printing is always done in localtime, conversion is mostly symbolic. This function only left in for completeness, but really doesn't do anything.

# Date.prototype.asUTCDate() ⇒ Date

Converts date by dropping any time information and assuming 12:00 AM UTC. Does not convert localtime to UTC and simply passes the time values as they exist.

d = new Date(2019, 0, 1, 20);  // Tue Jan 01 2019 20:00:00 GMT-0800 (Pacific Standard Time)
d.asUTCDate();                 // Mon Dec 31 2018 16:00:00 GMT-0800 (Pacific Standard Time)

In the above conversion, converts Jan 1, 2019 (date-only) in UTC time (though constructed with localtime). Drops time information, making it Jan 1, 2019 at 00:00 UTC. Printed, which is in localtime by default in javascript, it shows as 16:00 PST the previous day.

# Date.prototype.toUTCDate() ⇒ Date

Converts date by first converting the time to UTC, then dropping any time information and assuming 12:00 AM UTC.

d = new Date(2019, 0, 1, 20);  // Tue Jan 01 2019 20:00:00 GMT-0800 (Pacific Standard Time)
d.toUTCDate();                 // Tue Jan 01 2019 16:00:00 GMT-0800 (Pacific Standard Time)

In the above conversion, first converts Jan 1, 2019 at 20:00 in PST to 04:00 UTC the following day. Then it drops time information, making it Jan 2, 2019 at 00:00 UTC. Printed, which is in localtime by default in javascript, it shows as 16:00 PST the previous day (which is still Jan 1).

# Date.prototype.addDays(days) ⇒ Date

Returns new date with days added (or removed if negative).

# Date.prototype.monthOfYear() ⇒ number

Returns the month of the year as 1-12 number (as opposed to 0-11 for getMonth()).

# Date.prototype.daysInMonth() ⇒ number

Returns number of days in the month for this date.

 

Common Object

Returned as object if instantiated via CommonJS or AMD import. Otherwise appended to root as common (e.g. window.common).

# common.getElement(element) ⇒ Element

Given an input, returns an Element (or object derived from the Element prototype) as best determined from what is provided.

ParamTypeDescription
element--Input to filter for and/or convert to Element.

    Returns:

  • If a single Element is provided, simply returns it.
  • If a jQuery object is provided, returns first Element given by calling get() on it.
  • If an array is provided, returns the first item this is an Element or undefined.
  • If a NodeList or other iterable is provided, returns value of next() or null if done.
  • If string is provided, returns result of document.querySelector() using the string as the selector.
  • If none of the above apply, returns undefined.

# common.getElementList(input) ⇒ Element[]

Given an input, converts it into an array of Elements (or objects derived from the Element prototype).

ParamTypeDescription
input--Input to filter for and/or convert to an array of Elements.

    Returns:

  • If a NodeList, array, or other iterable is provided, converts to an array via Array.from(), then filters for elements that are derived from the Element prototype.
  • If a jQuery object is provided, returns array given by calling get() on it.
  • If a string is provided, returns result of document.querySelectorAll(), using the string as the selector, converted into an array.
  • Otherwise, wraps the input in an array, then filters for elements that are derived from the Element prototype.

# common.extend(obj, extend, options) ⇒ Object # common.extend(obj, extend[, overwrite[, deep, modify]]) ⇒ Object

Copy given object and extended with new values. The passed objects are not modified in any way unless modify is set as truthy.

ParamTypeDescription
objObjectBase object.
extendObjectObject of extensions to the copy of the base object.
optionsObjectOptions object, or options may be specified in flat series of parameters.
options.overwriteBooleanUnless true, items in extend matching existing values in obj by key are not copied over.
options.allowOverwriteBooleanSame as above.
options.deepBooleanIf true, all values are copied via structuredClone() or, as a fallback, JSON.parse(JSON.stringify()).
options.deepCopyBooleanSame as above.
options.modifyBooleanIf true, the input base object (obj) is modified directly, instead of cloning.
options.modifyObjBooleanSame as above.

If either extend or obj is null or undefined (or evaluates as falsy), a copy of whatever remaining object is returned. Otherwise, values in obj and extend are copied to a cloned object by passing the value. Thus primitive types are copied by value, but objects will be copied by reference, unless deepCopy is true.

In the case that the value being copied from and the value being copied over are both object literals, the copying will be recursed into the next level for each the origin and extending object.

Deep copy is done via structuredClone(), if available, or fallbacks to the JSON.parse(JSON.stringify()) method. Note that the former method may throw a DataCloneError exception and the latter will results in some values (such as dates, functions, or circular references) not being correctly carried over.

    Returns: The object with extended values (if modify is falsy, this is a new object).

# common.getUrlGetVars() ⇒ Object

Retrieve GET parameters in current URL as an object literal (dictionary format).

    Returns: Object literal of GET parameters found in URL.

# common.newWindow(url, options) ⇒ WindowProxy # common.newWindow(url, name, options) ⇒ WindowProxy

Creates a new, centered window.

ParamTypeDescription
urlStringURL for new window or an object literal with all parameters as properties.
nameStringNew window name.
optionsObject
options.nameStringNew window name may also be specified in the options.
options.widthNumberWidth in pixels. If not specified, defaults to 600.
options.heightNumberHeight in pixels. If not specified, defaults to 400.
options.minimalBooleanOptional. If truthy, forces hiding of menubar, statusbar, and location – although with many modern browsers this has no effect as it is not allowed.
options.optionsObjectOptional. Additional window options (passed as windowFeatures parameter). Specify as key-value pairing. Will overwrite any options set by function or other parameters.
options.errorCallbackOptional. Callback to run when the new window is detected to have been immediately closed (likely due to pop-up blocking). Given the WindowProxy returned by window.open().

    Returns: The WindowProxy returned by window.open().

# common.ajax(params) ⇒ XMLHttpRequest | Promise

Mimics jQuery.ajax() function call with XMLHttpRequest.

However, if the project allows, I'd nowadays recommend using the Fetch API instead (if needed, a polyfill is also available as whatwg-fetch in NPM).

ParamTypeDefaultDescription
params.urlStringThe URL of the request.
params.asyncBooleantrueAsynchronous. Defaults to true.
params.methodString"GET"Method for passing data.
params.dataObjectOptional dictionary of data to send with request.
params.dataTypeStringType of returned data given by XMLHttpRequest.responseType.
params.successCallbackCallback on success. Passes parameters of XMLHttpRequest.responseText, XMLHttpRequest.statusText, and the XMLHttpRequest instance itself.
params.errorCallbackCallback on error. Passes parameters the XMLHttpRequest instance, XMLHttpRequest.statusText, and XMLHttpRequest.responseText.
params.completeCallbackCallback on completion (whether success or error). Passes parameters the XMLHttpRequest instance and XMLHttpRequest.statusText.
params.userStringOptional username, if necessitated.
params.passwordStringOptional password, if necessitated.
params.promiseBooleanOptionally return as Promise that resolves when the request resolves.

    Returns: XMLHttpRequest or Promise on completion for the request.

# common.animate(options) ⇒ Promise # common.animate(element, options) ⇒ Promise # common.animate(element, properties, options) ⇒ Promise # common.animate(element, properties, duration, options) ⇒ Promise

Mimics jQuery.animate() function using CSS transitions by first applying a transition property for the requisite CSS properties to be applied, then, after a short delay (5 ms), applying the properties. All this is done as modifications to the element's inline styles, and will thus overwrite any existing inline styles and will be subject to any CSS rule overrides (such as an existing, applicable CSS rule with the !imporant flag).

ParamTypeDescription
elementElementThe Element to animate
propertiesObjectCSS properties to animate to. Note that not all properties are can be animated.
durationNumberDuration of animation, in milliseconds. Optional, but if not supplied, the animation is somewhat pointless as the transition is instant.
optionsObject
options.elementElementThe element parameter may also be specified in the options.
options.propertiesObjectThe properties parameter may also be specified in the options.
options.durationNumberThe duration parameter may also be specified in the options.
options.durationMsNumberSame as above.
options.timingStringTiming/easing function, defaults to "ease". See: transition-timing-function.
options.timingFunctionStringSame as above.
options.completeCallbackOptional callback to run on completion.

    Returns: A Promise tied to the animation duration, if the Promise API is available.

 

Common UI

Packaged with common as common.ui.

The Common UI modules allow for some simple, commonly-used UI functionality, mostly through CSS. As such, common.min.css is required.

For modal dialog usage, ensure your dependency-manager/import-function is caching requires/imports of the common object, or that you are passing the object by reference. Calling multiple instances of common.ui in the same window can result in odd behavior for modal management.

# common.ui.addGrabCursorFunctionality(element)

Adds grab cursor functionality to draggable element. The input may be a single Element, a NodeList or array of Elements, or a jQuery selection.

Adds class "grab" to element, and class "grabbing" when being dragged.

ParamTypeDescription
element--Element(s) to add functionality to. See common.getElementList() for evaluation of this parameter.

# common.ui.createDropdown(element, menu)

Create a dropdown menu on an element. menu parameter is an array of object literals defining the menu. The parameters id, class, style, and html/text, if they exist, are applied. For functionality, either add href and optionally target parameters or supply a callback to an onClick parameter. To create a submenu, simply add a menu parameter with the same nested structure.

Elements with be created with classes prefixed by "cm-dropdown".

ParamTypeDescription
element--Element(s) to add dropdown to. See common.getElementList() for evaluation of this parameter.
menuObject[]JSON map of menu

Example usage:

common.ui.createDropdown("#menu", 
  [
    {
      id:      "menu-btn-1", 
      text:    "Homepage", 
      href:    "index.html", 
      style:   {"font-weight": "bold"}, 
      onClick: () => console.log("menu item 1 clicked")
    }, 
    {
      id:    "submenu", 
      text:  "Totally Work Related", 
      style: {"font-style": "italic"}, 
      menu: [
        {text: "Business Stuff", href: "https://facebook.com"},
        {text: "Web Dev. Stuff", href: "https://reddit.com"} 
      ]
    }
  ]
);

# common.ui.clearDropdown(element)

Remove dropdown menu functionality from an element.

ParamTypeDescription
element--Element(s) to remove dropdown from. See common.getElementList() for evaluation of this parameter.

 

Tooltips & help icons

The tooltips and help icons functionality can be applied via the functions (described below) or manually.

Common UI Help Icon

To add a tooltip manually, add the class cm-tooltip-left, cm-tooltip-top, cm-tooltip-right, or cm-tooltip-bottom and the attribute cm-tooltip-msg with the tooltip message. To create a help icon, simply create the element <i>?</i>, with class cm-icon.

# common.ui.addTooltip(element, options) # common.ui.addTooltip(element, message[, direction, force])

Add hover tooltip to element(s).

Elements will be created with classes prefixed by cm-tooltip.

ParamTypeDescription
element--Element(s) to add tooltip to. See common.getElementList() for evaluation of this parameter.
optionsObjectOptions object, or options may be specified in flat series of parameters.
options.messageStringTooltip message/HTML.
options.directionStringDirection of tooltip (defaults to top).
options.forceBooleanIf truthy, forces tooltip visible.

# common.ui.removeTooltip(element)

Remove hover tooltip from element(s).

ParamTypeDescription
element--Element(s) to remove tooltip from. See common.getElementList() for evaluation of this parameter.

# common.ui.appendHelpIcon(element, options) # common.ui.appendHelpIcon(element, message[, direction[, style, force]])

Add help icon to element(s) as (?) styled icon with tooltip.

Icon element will be created with class cm-icon.

ParamTypeDescription
element--Element(s) to add help icon too. See common.getElementList() for evaluation of this parameter.
optionsObjectOptions object, or options may be specified in flat series of parameters.
options.messageStringTooltip message/HTML.
options.directionStringDirection of tooltip (defaults to top).
options.styleObjectDictionary of inline style key-values for icon.
options.forceBooleanIf truthy, forces tooltip visible.

# common.ui.removeHelpIcon(element)

Remove help icon from element(s).

ParamTypeDescription
element--Element(s) to remove help icon from. See common.getElementList() for evaluation of this parameter.

 

Modal dialogs

For modal dialog usage, ensure your dependency-manager/import-function is caching requires/imports of the common object, or that you are passing the object by reference. Calling multiple instances of common.ui in the same window can result in odd behavior for modal management. common.getElementList()

Common UI Modal

Model elements will be created with classes prefixed by .cm-modal.

When a modal function is first called, this library appends a hidden div to body to handle modals/dialogs. This includes a container div (#cm-modal-container), an outer modal div (#cm-modal-outer) with absolute positioning, and an inner div (.cm-modal-inner) which represents the actual dialog. You may (and are in fact recommended to) tweak the CSS rules attached to these as necessary.

Only one modal may be open at a time. Opening another modal will replace the current one.

# common.ui.isModalOpen() ⇒ boolean

Check whether modal is open.

# common.ui.setModal(visible, content, options) ⇒ Element # common.ui.openModal(content, options) ⇒ Element

Creates a new modal dialog (or closes, if visible is falsy). Function openModal() is the same with visible defaulted to true.

ParamTypeDescription
visibleBooleanWhether to open or close modal
contentStringModal content HTML
optionsObject
options.idStringId of inner modal dialog element.
options.showBackgroundBooleanIf truthy, creates a semi-transparent background over window.
options.notExitableBooleanNormally modal closes on clicking anywhere outside modal dialog element. If truthy, this prevents this functionality.
options.hideCloserBooleanIf truthy, does not apply the automatically placed "X" to close dialog on upper-right.
options.onCloseCallbackCallback to run on modal being closed.

    Returns: Element of modal content div (.cm-modal-inner).

# common.ui.setModalAsLoading([content, options]) ⇒ Element

Opens a modal dialog with default values prepped for loading. As such, no options are required, but can be provided to overwrite defaults.

ParamTypeDefaultDescription
contentString"Loading.."Modal content HTML
optionsObject
options.idString"modal-loading-dialog"Id of inner modal dialog element.
options.showBackgroundBooleantrueIf truthy, creates a semi-transparent background over window.
options.notExitableBooleantrueNormally modal closes on clicking anywhere outside modal dialog element. If truthy, this prevents this functionality.
options.hideCloserBooleantrueIf truthy, does not apply the automatically placed "X" to close dialog on upper-right.
options.addDetailsBooleantrueIf truthy, adds smaller subtext below the main modal content.
options.addDetailsTextString"Please wait.."The content for subtext below the main modal content, if addDetails is truthy.

    Returns: Element of modal content div (.cm-modal-inner).

# common.ui.changeModal(content[, prepContentCallback, hideCloser]) ⇒ Element

Change modal dialog content while leaving all other options the same. Keeps the content-size changes from being too jarring when swapping content by adding small CSS animation to fit new size. If there was a custom width/height defined in the modal's style, these will be lost.

ParamTypeDescription
contentStringModal content HTML
prepContentCallbackCallbackIf some prep work is needed before determining the new dimensions of the modal for size change animation.
hideCloserBooleanDue to HTML refresh, closer will be readded unless this is set as truthy.

    Returns: Element of modal content div (.cm-modal-inner).

# common.ui.closeModal(suppressOnClose) # common.ui.hideModal(suppressOnClose)

Hide any currently visible modal.

ParamTypeDescription
suppressOnCloseBooleanIf truthy, suppresses onClose event callback, if one is attached.

 

CommonTable Class

Table handling object which handles data formatting, grouped columns, column sorting, and basic styling.

Must be separately imported. Returned as object if instantiated via CommonJS or AMD import. Otherwise appended to root as CommonTable class. Require base Common module to have been imported, as it depends on some the prototype modifications defined there.

To use, begin by creating instance and adding columns with CommonTable.prototype.addColumn(). The key parameter defines how to assign the data to each column. Other parameters allow various style and formatting methods. Once all columns are added, add data and draw the table with CommonTable.prototype.populateTable(). The data, sent as an array of object literals/dictionaries, is mapped to the columns automatically with the key defined for each column.

# CommonTable([tableId[, tableClass, container]])

Creates new CommonTable. The table will be given the class of cm-table, more classes can be appended through the options.

ParamTypeDescription
tableIdStringTable ID
tableClassString | String[]Table classname (use array to add multiple)
containerElementElement to append table to

# CommonTable.prototype.appendTo(container)

Appends table to element.

ParamTypeDescription
containerElementElement to append table in

# CommonTable.prototype.prependTo(container)

Prepends table to element.

ParamTypeDescription
containerElementElement to prepend table in

# CommonTable.prototype.addColumn(options) # CommonTable.prototype.addColumn(group, title, key, options)

Add a column to the table.

ParamTypeDescription
groupStringThe header group. If not null, used to group two or more headers as subheaders under a banner header (via colspan).
titleStringThe title to display the header as.
keyStringThe key used to retrieve data from this header.
optionsObject
options.groupStringgroup may be specified in the options instead.
options.titleStringtitle may be specified in the options instead.
options.keyStringkey may be specified in the options instead.
options.formatCallbackOptional function such that format(value), returns the formatted value for the table cell. Run in try-catch block, so if it fails, simply continues with raw value.
options.hdrStylesString | ObjectOptional styles to apply to the header. Overrides any colStyles properties.
options.colStylesString | ObjectOptional styles to apply to every row in this column (including header). If you only want to apply to non-header cells, must override values in hdrStyles.
options.onClickCallbackOptional onClick listener to add to each cell (excluding header). Callback will be given the entire row's data as the parameter.
options.sortableBooleanOptional flag to set/disable sortable column on this column. By default columns are sortable, so set as falsy or null to disable.

# CommonTable.prototype.createHeaders(options)

Redraw table. Unlike populateTable(), this only redraws the headers (rest of the rows are lost).

ParamTypeDescription
optionsObject
options.sortOnKeyStringOptional key to sort on.
options.ascendingBooleanIf sorting, whether ascending or descending order.

Alternatively, parameters may be expanded out as individual arguments.

# CommonTable.prototype.createHeaders([sortOnKey, ascending])

ParamTypeDescription
sortOnKeyStringOptional key to sort on.
ascendingBooleanIf sorting, whether ascending or descending order.

See above.

# CommonTable.prototype.populateTable(options)

Populate and redraw table.

ParamTypeDescription
optionsObject
options.tableDataObject[]Array of objects, representing data by row. Data is not stored to object or dynamically bound in any way. To update table, must be redrawn, passing the updated data array.
options.sortOnKeyStringOptional key to sort on.
options.ascendingBooleanIf sorting, whether ascending or descending order.

Alternatively, parameters may be expanded out as individual arguments.

# CommonTable.prototype.populateTable(tableData[, sortOnKey, ascending]])

See above.

ParamTypeDescription
tableDataObject[]Array of objects, representing data by row. Data is not stored to object or dynamically bound in any way. To update table, must be redrawn, passing the updated data array.
sortOnKeyStringOptional key to sort on.
ascendingBooleanIf sorting, whether ascending or descending order.

 


Example usage:

CommonTable example

var tbl = new CommonTable("my-table-id", "my-table-class");
tbl.appendTo(document.body);

// first three columns under "Name" header group
tbl.addColumn({group: "Name", title: "First", key: "firstName"});
tbl.addColumn({group: "Name", title: "Nickname", key: "nickName"});
tbl.addColumn({group: "Name", title: "Last", key: "lastName"});
// add generic meta-data (to be used later)
tbl.addColumn({
  title:  "Birthday", 
  key:    "birthDate", 
  format: function(val) {
    return (
      (val.getMonth()+1).toString() + "/" 
      + val.getDate().toString() + "/" 
      + val.getFullYear().toString()
    );
  }
});
// other columns
tbl.addColumn({title: "Wins", key: "winCount"});
tbl.addColumn({title: "Losses", key: "lossCount"});
tbl.addColumn({title: "Draws", key: "drawCount"});

var data = [
  {
    firstName: "Tony", 
    nickName:  "El Cucuy", 
    lastName:  "Ferguson", 
    winCount:  25, 
    lossCount: 8, 
    drawCount: 0, 
    birthDate: new DateUTC(1984, 2, 12)
  }, 
  {
    firstName: "Khabib", 
    nickName:  "The Eagle", 
    lastName:  "Nurmagomedov", 
    winCount:  29, 
    lossCount: 0, 
    drawCount: 0, 
    birthDate: new DateUTC(1988, 9, 20)
  }, 
  // etc...
];

tbl.populateTable({
  tableData: data, 
  sortOnKey: "winCount", 
  ascending: false  // sort by wins descending
});

Acknowledgments

A huge bulk of this library was built on solutions found through the Mozilla Developers Network, StackOverflow, and many other smart folks. I would also like to thank SFEI, podcasts, and coffee.

5.0.4

1 year ago

5.0.3

1 year ago

5.0.2

1 year ago

5.0.1

2 years ago

5.0.0

2 years ago

4.3.1

2 years ago

4.3.0

2 years ago

4.2.2

2 years ago

4.2.1

2 years ago

4.2.0

3 years ago

4.1.0

3 years ago

4.1.1

3 years ago

4.0.11

3 years ago

4.0.9

3 years ago

4.0.8

3 years ago

4.0.10

3 years ago

4.0.7

3 years ago

4.0.5

3 years ago

4.0.4

3 years ago

4.0.3

3 years ago

4.0.2

4 years ago

4.0.1

4 years ago

4.0.0

4 years ago

3.2.3

4 years ago

3.2.2

4 years ago

3.2.1

4 years ago

3.2.0

4 years ago

0.3.2

4 years ago

0.3.1

4 years ago

0.3.0

6 years ago

0.2.10

6 years ago

0.2.9

6 years ago

0.2.7

6 years ago

0.2.4

6 years ago