Important note: Webshim is not compatible with upcoming jQuery 3.x and I do not plan to work on a new major version. I will still fix critical bugs in the future though.

Webshim is a polyfill library that enables you to reliably use HTML5 features across browsers, even if native support is lacking.

The project is hosted on GitHub, and is available for use under the MIT software license.

You can report bugs and discuss features on the GitHub issues page.

Downloads & Dependencies

(Right-click, and use "Save As")

Download

Webshim depends on jQuery.

Introduction

There are many appealing HTML5 features such as form validation, geolocation, mediaelements and UI widgets which ease the burden of writing rich web applications.

Webshim is a polyfill solution. It adds these features in a way that is transparent to the end user and developer. It enables coding against the browser standards rather than learning and maintaining abstractions. It results in less code that is simpler and easier to maintain.

Webshim is also more than a polyfill, it has become a UI component and widget library. Webshim enables a developer to also enhance HTML5 capable browsers with more highly customizable, extensible and flexible UI components and widgets. Its capability based loading system enables webshim to only load those files, which are needed for the specific browser/device and only when it is needed (deferred loading), to reduce especially the initial network payload.

Installation

Take the 'js-webshim' folder and add it to your project. (You will find a minified and a dev folder there. Put the whole folder, not only the polyfiller.js file into your project!) Here is an example showing how to include dependencies and load webshims:

<script src="js/jquery.js"></script> <script src="js-webshim/minified/polyfiller.js"></script> <script> //webshim.setOptions('basePath', '/js-webshim/minified/shims/'); //request the features you need: webshim.polyfill('es5 mediaelement forms'); $(function(){ // use all implemented API-features on DOM-ready }); </script>

Configuration

The polyfill method accepts an optional whitespace-separated feature list. Call it as soon as possible (before DOM ready.) webshim.polyfill( "canvas geolocation" );

canvas

details

es5

filereader (implements FileReader, XHR2 (CORS/FormData), FormData, and an input[type="file"] picker)

forms (form validation and form features: fieldset[disabled], <input form="idref" />, placeholder...)

forms-ext (input wigets)

geolocation

matchMedia (includes matchMedia and matchMedia.addListener polyfill)

mediaelement

picture (responsive images: picture andsrcset)

promise

url (window.URL)

usermedia (navigator.getUserMedia)

sticky ( position : sticky )

: ) track (subtitles, catptions and textTrack API)

xhr2 (an alias for filereader)

setOptions should always be called before the polyfill method.

The available options for webshim.setOptions :

extendNative Webshims lib will automatically extend DOM-Objects with polyfilled methods and will additionally generate a jQuery plugin with this method name. If extendNative is set to false, webshims lib won't touch any DOM-Objects and will only implement jQuery plugins. Setting this option to false might improve DOM performance.

default: false

Webshims lib will automatically extend DOM-Objects with polyfilled methods and will additionally generate a jQuery plugin with this method name. If extendNative is set to false, webshims lib won't touch any DOM-Objects and will only implement jQuery plugins. Setting this option to false might improve DOM performance. default: false basePath The path to your shims folder. This is computed dynamically. More information. Example:

webshim.setOptions('basePath', '/yourFolderTo/shims/');

default: computed path to shims folder

The path to your shims folder. This is computed dynamically. More information. Example: default: computed path to shims folder waitReady Setting this to true delays jQuery's ready-event until all polyfilled features are ready. This option should be set to false, if webshims lib polyfiller.js is loaded asynchronously. This option can also be set to false, if a website is using only HTML5 markup APIs (pure HTML or $.attr) and doesn't use any DOM-/JS-APIs on DOM-ready. If this feature is set to false, scripted access to polyfilled APIs have to be added inside of a webshim.ready callback.

default: true

Setting this to true delays jQuery's ready-event until all polyfilled features are ready. This option should be set to false, if webshims lib polyfiller.js is loaded asynchronously. This option can also be set to false, if a website is using only HTML5 markup APIs (pure HTML or $.attr) and doesn't use any DOM-/JS-APIs on DOM-ready. If this feature is set to false, scripted access to polyfilled APIs have to be added inside of a callback. default: true loadStyles If loadStyles is set false webshims won't load any default styles. In this case a site has to provide all styles for the used widgets. A developer also can copy all used webshim styles into his own stylesheet and minimize requests/only use needed styles for used widgets. See also Customizing styles and UI

default: true

If is set webshims won't load any default styles. In this case a site has to provide all styles for the used widgets. A developer also can copy all used webshim styles into his own stylesheet and minimize requests/only use needed styles for used widgets. See also Customizing styles and UI default: true debug Setting debug to true enables debug informations to be printed in the developer console. Note the polyfiller.js in the dev folder has more debug informations and pretty printed code.

default: undefined

Setting to true enables debug informations to be printed in the developer console. Note the polyfiller.js in the dev folder has more debug informations and pretty printed code. default: undefined enhanceAuto If set to true configuration values with the keyword ' auto ' are treated as true, if this is false the keyword ' auto ' is treated as false .

default: dynamically computed (mainly false for Smartphone devices and IE8 otherwise true: window.Audio && (!window.matchMedia || matchMedia('(min-device-width: 721px)').matches) )

// enhanceAuto will be false for devices smaller than 720px (i.e. Smartphones or for devices smaller than 1024px and with touchevents (i.e.: Tablets) webshim.setOptions('enhanceAuto', !(matchMedia('(max-device-width: 720px)').matches || matchMedia('(max-device-width: 1024px)').matches && Modernizr.touchevents) ); webshim.setOptions({ 'forms-ext': { replaceUI: 'auto' }, 'mediaelement', { replaceUI: 'auto' } }); //webshims will implement those features in all browsers/devices // but will only enhance capable browsers on desktop with custom styleable mediaelement controls and form widgets webshim.polyfill('forms forms-ext mediaelement');

setOptions can also take a single options parameter:

webshim.setOptions({ extendNative: true });

Feature specific options are nested options with the feature name as their key.

webshim.setOptions({ // configure generally option extendNative: true, // configure canvas-shim canvas: { type: 'flash' // use flashcanvas instead of excanvas as polyfill }, // configure forms-shim forms: { lazyCustomMessages: true // implement customValidationMessages } });

Fire When Ready

Not every feature is ready immediately in all browsers; some shims might take time to load before you can use them. You can use one of jQuery's ready methods to delay working with elements until the DOM and any necessary shims are ready.

$(function(){ // work with DOM + all implemented features }); $(document).ready(function(){ // work with DOM + all features });

If you want to use a feature as soon as possible or you have set the waitReady option to false , you can use webshim.ready and pass the feature name(s) and a callback function:

webshim.ready('geolocation es5', function(){ // work with geolocation and es5 });

Note that this callback function may be called before the DOM is ready. If you want to use a feature after DOM-Ready, simply pass the string 'DOM':

webshim.ready('DOM canvas', function(){ // work with canvas in the document });

DOM Abstractions

Due to the fact that we cannot extend accessors of elements in all browsers, we always use jQuery as an extension-wrapper.

Accessing DOM properties/attribute IDLs : if the feature allows accessing a specific attribute or property, always use jQuery's built-in $.prop (in case of IDL attributes/properties) or $.attr / $.removeAttr (in case of content attributes) methods: // instead of accessing a property directly (e.g. this.validity), // use $.fn.prop $(this).prop('validity'); // or: //$.prop(this, 'validity'); //setting a property $('video').prop('currentTime', 200); // or: //$.prop(videoElement, 'currentTime', 200);

calling a DOM method : While DOM properties have to be accessed through jQuery's $.prop/$.attr methods, DOM methods can be accesed using $.prop and executed in the context of the DOM element. // "this" refers to a DOM element, not a jQuery object var fn = $.prop(this, 'checkValidity'); fn.apply(this); To make this more easier Webshims lib also generates a jQuery plugin which wraps the featured method, so you can use jQuery too: $(this).checkValidity(); $(this).callProp('checkValidity'); // $(this).callProp('play'); The jQuerified method can also take some arguments, if specified by the spec. $('video').addTextTrack('subtitles', 'just a test', 'en'); $('video').callProp('addTextTrack', ['subtitles', 'just a test', 'en']); If you pass a list of nodes and the method doesn't return anything, the method will be called on each element in this list, otherwise it will be called on the first element. In case a developer wants to make method calling "feel 100% native", the general option extendNative can be set to true . webshim.setOptions('extendNative', true); webshim.polyfill('forms'); // ... this.checkValidity() // or use $(this).callProp('checkValidity') $('video').get(0).addTextTrack('subtitles', 'just a test', 'en');

binding to events : Always use jQuery's on method to register your event listeners. addEventListener or inline event handler won't work in polyfilled browsers. Most events in the HTML5 specification are so-called simple events. Simple events do not bubble. Due to the fact that developers really like event delegation and jQuery cannot distinguish between the event phases (capturing/propagation), we use event capturing in the native implementation and $.fn.trigger in the shim. This means that some HTML5 events go down the DOM tree in capable browsers and go up the tree in polyfilled browsers. This can create differences if you are calling event.stopPropagation(); or return false; in your event handler. If you only want to prevent the default, don't use return false; , use event.preventDefault(); instead.

manipulation methods/dynamically adding HTML5 content : To insert/copy new HTML5 content dynamically, use .htmlPolyfill() , .appendPolyfill() , .prependPolyfill() , .afterPolyfill() , .beforePolyfill() , .replaceWithPolyfill() and .clonePolyfill() : // three different examples $('form').appendPolyfill('<fieldset><input type="date" /></fieldset>'); $('#canvas-box').htmlPolyfill('<canvas></canvas>'); $('datalist#list select').prependPolyfill('<option value="new suggestion item" />'); See also dynamic HTML5 description.

no shadowdom: Webshims lib sometimes has to add additional DOM elements to mimic the UI of HTML5 elements. This can sometimes create differences, between polyfilled and non polyfilled browsers. Webshims lib gives you a method called 'getShadowElement' to access the shadowelement from the native element and a method called 'getNativeElement' to access the native element from the shadowelement. If the element has no shadowelement the element itself is returned. // get the UI component element of input[type="date"] $('input[type="date"]').getShadowElement(); Another problem can be, that some styles of your website may conflict with webshims styles. This normally happens if a tagname selector without a specific class or attribute is used as last selector part: /* do not use */ fieldset > div { /* some styles */ } /* instead write something like this: */ .form-row { /* some styles */ } Some styles like float or display: none/block are not reflected by the shadowdom, it is a good approach to do this on a wrapper element or to also add those styles to the generated UI components yourself: <!-- instead of --> <div class="form-field"> <label for="date" style="display: none;">Birthdate</label> <input type="date" id="date" style="display: none;" /> </div> <!-- do this: --> <div class="form-field" style="display: none;"> <label for="date">Birthdate</label> <input type="date" id="date" /> </div> <!-- or instead of: --> <div class="mediaplayer"> <video src="file.mp4" controls style="margin: 0 10px 5px 0; float: left"> </video> </div> <!-- do this: --> <div class="mediaplayer" style="margin: 0 10px 5px 0; float: left"> <video src="file.mp4" controls></video> </div> This could be also fixed by adding those styles to the polyfilled component: /* do not use */ video { margin: 0 10px 5px 0; float: left; } /* do something like this: */ video, .polyfill-video { margin: 0 10px 5px 0; float: left; } /* or better */ .video-wrapper { margin: 0 10px 5px 0; float: left; } re-rendering shadowelements: On dynamic websites shadowelements dimensions and/or positions sometimes need to be updated, this can be achieved by triggering the updateshadowdom . $(document).trigger('updateshadowdom'); The updateshadowdom event is automatically and lazily triggered on window.resize/emchange events.

HTML5 shiv and innershiv

IE8- isn't capable of rendering HTML5 elements. Webshims lib in combination with Modernizr or HTML5shiv automatically fixes this issue and adds WAI-ARIA landmarks to enable accessibility of HTML5.

Dynamically adding HTML5 markup

Additionally it implements the following manipulation methods to allow dynamic creation of HTML5 elements: .updatePolyfill() , .htmlPolyfill() , .appendPolyfill() , .prependPolyfill() , .afterPolyfill() , .beforePolyfill() .replaceWithPolyfill() , .appendPolyfillTo() , .prependPolyfillTo() , .insertPolyfillAfter() , .insertPolyfillBefore() , .replacePolyfillAll()

var html = '<section><form action="#">' + '<input type="text" placeholder="name" name="test" required/>' + '<input type="date" required="required" name="test2" />' + '<input type="submit" />' + '</form></section>'; $('#Shiv-dynamic-html5-test').htmlPolyfill(html);

If a plugin, script or framework is used, which uses a "normal" JS/jQuery manipulation method instead of the corresponding webshims enhanced manipulation method to generate new HTML5 content (i.e.: .html() instead of .htmlPolyfill() ), the method .updatePolyfill() can be used to polyfill the dynamic content:

$('#my-dynamic-container').load('ajax/test.html', function(){ $(this).updatePolyfill(); });

jQuery mobile example

//set waitReady to false webshim.setOptions('waitReady', false); // call webshim.polyfill() before domready webshim.polyfill(); // bind to the pageinit event after domready... $(document).on('pageinit', function(e){ // ...and call updatePolyfill on the changed element container $(e.target).updatePolyfill(); });

For jQuery Mobile see also webshims and jQ mobile

ES5

The es5 feature uses the ES5 shim by Kris Kowal (all object methods, which can't be used cross-browser are removed.).

The script implements the following methods:

Object : keys

: keys Array : isArray

: isArray Array.prototype : forEach, map, filter, every, some, reduce, reduceRight, indexOf, lastIndexOf

: forEach, map, filter, every, some, reduce, reduceRight, indexOf, lastIndexOf Date : now

: now Date.prototype : toISOString, toJSON

: toISOString, toJSON Function.prototype : bind

: bind String.prototype: trim

Note: All methods added to the prototype object are visible inside of a for in loop, while native implementations aren't enumerable. (use hasOwnProperty)

webshim.ready('es5', function(){ [1, 2, 3].forEach(function(){ // do stuff }); });

Abstractions

Webshims Lib adds the following methods: webshim.objectCreate , webshim.defineProperty , webshim.defineProperties , webshim.getOwnPropertyDescriptor and corresponding support flags: webshim.support.objectAccessor (true in all modern Browsers including IE9, getters and setters can be used on all objects) and webshim.support.advancedObjectProperties (true in FF4, IE9, Chrome 10..., the full ES5 specification of defineProperty is implemented (including writeable, enumerable and configurable).

webshim.objectCreate(proto [, propertiesObject, options ])

webshim.objectCreate works very similar to Object.create

If propertiesObject is defined, the method goes through this object and sets writeable, enumerable and configurable to true, if the corresponding property is undefined.

After this, it will pass proto and propertiesObject to Object.create (if defined) or will use Crockfords begetObject -Method on the proto -object and then calls webshim.defineProperties with the returned object and the propertiesObject .

If you pass the options parameter and the Object already has a Options-property. The options-property on the object will be deeply extended otherwise an new options-property will be created.

If the object has a method called _create , it will call this method with options as first argument.

After this, the created object will be returned.

var carProto = { options: { foo: 'bar', baz: 'boom' }, wheels: 4, drive: function(){ this.isDriving = true; } }; var myCar = Object.create(carProto, { _create: { value: function(){ this.drive(); } }, jumps: { value: function(){ //implements jumping } }, {baz: 'jo'} ); // myCar will look like this: { // own property: options: { foo: 'bar', baz: 'jo' }, // prototype: wheels: 4, // prototype drive: function(){ this.isDriving = true; }, // own property: _create: function(){ this.drive(); }, // own property: jumps: function(){ //implements jumping }, // own property: isDriving: true }

webshim.defineProperties (object, props)

webshim.defineProperties works similar to Object.defineProperties

It will go through the props properties and will set writeable, enumerable and configurable to true, if they are undefined.

After this either Object.defineProperties will be invoked or legacy code is used.

Forms

The forms (constraint validation without number, date etc.) and forms-ext (number, date, range etc.) features of the webshim lib are implementing support for the constraint validation API, some input widgets and the placeholder-attribute.

The forms feature also implements an easy and cross browser way to control the validation UI (error message and styling the validation bubble).

Implemented/fixed in forms :

1. You need to wrap the datalist options in a select element (datalist > select > option)!

2. multiple is only implemented for type=email (also works in conjunction with pattern). Implementation for [type="file"][multiple] or [accept] see filereader!

Implemented/fixed in forms-ext :

types : datetime-local, time, date, number, month, range

: datetime-local, time, date, number, month, range content attributes and properties (IDL attributes) : step, max, min

: step, max, min properties/IDLs : valueAsNumber, valueAsDate, labels

: valueAsNumber, valueAsDate, labels methods: stepUp/stepDown

forms Options

A typical configuration would look like this:

webshim.setOptions("forms", { lazyCustomMessages: true, replaceValidationUI: true, customDatalist: "auto", list: { "filter": "^" } }); webshim.polyfill('forms');

customMessages boolean If set to true, Webshims will implement a DOM-Property called customValidationMessage, which can be changed through the webshim.validityMessages-Array.

default: false

boolean If set to true, Webshims will implement a DOM-Property called customValidationMessage, which can be changed through the webshim.validityMessages-Array. default: false lazyCustomMessages boolean Similar to customMessages , but the data is lazily loaded after window.onload or as soon as the user starts to interact with a form for better performance. The customValidationMessage property is therefore not available on DOM-Ready.

default: false

boolean Similar to , but the data is lazily loaded after window.onload or as soon as the user starts to interact with a form for better performance. The customValidationMessage property is therefore not available on DOM-Ready. default: false replaceValidationUI boolean Replaces the browser validation UI with a custom styleable UI.

default: false

boolean Replaces the browser validation UI with a custom styleable UI. default: false iVal mixed object Adds and configures a user friendly form validation UI.

default: webshim.setOptions("forms", { iVal: { "sel": ".ws-validate", "handleBubble": "hide", "recheckDelay": 400, "fieldWrapper": ":not(span):not(label):not(em):not(strong):not(p)", "events": "focusout change", "errorClass": "user-error", "errorWrapperClass": "ws-invalid", "successWrapperClass": "ws-success", "errorBoxClass": "ws-errorbox", "errorMessageClass": "ws-errormessage", "fx": "slide", "submitCheck": false } });

mixed object Adds and configures a user friendly form validation UI. default: addValidators boolean Should Webshims implement some new custom validators. custom validity example

default: false

boolean Should Webshims implement some new custom validators. custom validity example default: false customDatalist boolean|String 'auto' Allows to use custom styleable datalist elements in all browsers. If the string 'auto' is used, input widgets are only replaced in desktop browser or incapable browsers.

default: false

boolean|String 'auto' Allows to use custom styleable datalist elements in all browsers. If the string 'auto' is used, input widgets are only replaced in desktop browser or incapable browsers. default: false list mixed object Options object for the datalist/[list] feature (can be also controlled using data-list markup).

default: webshim.setOptions("forms", { list: { "filter": "*", "multiple": false, "focus": false, "highlight": false, "valueCompletion": false, "inlineValue": false, "noHtmlEscape": false, "popover": { "constrainWidth": true } } });

forms-ext Options

replaceUI boolean|mixed object|String 'auto' If set to true the UI of all input widgets (number, time, month, date, range) are replaced in all browsers (also in browser, which have implemented these types). This is useful, if you want to style the UI in all browsers. If the string 'auto' is used, input widgets are only replaced in desktop browser or incapable browsers.

default: false

boolean|mixed object|String 'auto' If set to true the UI of all input widgets (number, time, month, date, range) are replaced in all browsers (also in browser, which have implemented these types). This is useful, if you want to style the UI in all browsers. If the string 'auto' is used, input widgets are only replaced in desktop browser or incapable browsers. default: false types string A white space separated string. Possible values are 'datetime-local range date time number month color' . If one of the listed input types is not supported, Webshim will load the forms-ext API and UI package and implement all types.

default: date time range number

string A white space separated string. Possible values are . If one of the listed input types is not supported, Webshim will load the forms-ext API and UI package and implement all types. default: date time range number widgets object widgets is a general options object for all input widgets. example widgets with different themes, example widgets with different configurations webshim.setOptions("forms-ext", { "widgets": { "startView": 0, "minView": 0, "inlinePicker": false, "size": 1, "splitInput": false, "yearSelect": false, "monthSelect": false, "daySelect": false, "noChangeDismiss": false, "openOnFocus": false, "buttonOnly": false, "classes": "", "popover": { //popover options }, "calculateWidth": true, "animate": true, "toFixed": 0, "onlyFixFloat": false } });

object widgets is a general options object for all input widgets. example widgets with different themes, example widgets with different configurations date object Overrides widgets option object, can be also configured through data-date attribute (datepicker Configurator)

object Overrides widgets option object, can be also configured through data-date attribute (datepicker Configurator) month object Overrides widgets option object, can be also configured through data-month attribute (monthpicker Configurator)

object Overrides widgets option object, can be also configured through data-month attribute (monthpicker Configurator) number object Overrides widgets option object, can be also configured through data-number attribute (number/spinbutton Configurator)

object Overrides widgets option object, can be also configured through data-number attribute (number/spinbutton Configurator) time object Overrides widgets option object, can be also configured through data-time attribute (timepicker Configurator)

object Overrides widgets option object, can be also configured through data-time attribute (timepicker Configurator) range object Overrides widgets option object, can be also configured through data-range attribute (slider/range Configurator)

object Overrides widgets option object, can be also configured through data-range attribute (slider/range Configurator) color object Overrides widgets option object, can be also configured through data-color attribute (colorpicker Configurator)

object Overrides widgets option object, can be also configured through data-color attribute (colorpicker Configurator) datetime-local object Overrides widgets option object, can be also configured through data-color attribute (datetimepicker Configurator)

A typical configuration would look like this:

//configure forms features webshim.setOptions("forms", { lazyCustomMessages: true, replaceValidationUI: true, customDatalist: "auto", list: { "filter": "^" } }); //configure forms-ext features webshim.setOptions("forms-ext", { replaceUI: "auto", types: "date range number", date: { startView: 2, openOnFocus: true, classes: "show-week" }, number: { calculateWidth: false }, range: { classes: "show-activevaluetooltip" } }); //load forms and forms-ext features webshim.polyfill('forms forms-ext');

Extensions

event: firstinvalid : firstinvalid is a simple, bubbling event, which is triggered on the first invalid form element. Preventing the default of firstinvalid will automatically prevent the default behavior of all current invalid elements.

: is a simple, bubbling event, which is triggered on the first invalid form element. Preventing the default of firstinvalid will automatically prevent the default behavior of all current invalid elements. event: lastinvalid : lastinvalid is an extended, bubbling, (but) uncancelable event, which is triggered on the last invalid form element. The property invalidlist is a jQuery-collection of all current invalid elements.

: is an extended, bubbling, (but) uncancelable event, which is triggered on the last invalid form element. The property is a jQuery-collection of all current invalid elements. event: changedvalid/changedinvalid : Event is triggered, if the value of the element was changed and is marked as valid/invalid (see also: .form-ui-valid/.form-ui-invalid).

: Event is triggered, if the value of the element was changed and is marked as valid/invalid (see also: .form-ui-valid/.form-ui-invalid). event: datalistselect : Event is triggered on each input[list] for each option, in case the callback returns a string this is used to construct the datalist polyfill

: Event is triggered on each input[list] for each option, in case the callback returns a string this is used to construct the datalist polyfill event: getoptioncontent : Event is triggered on the input element, for each option of a datalist. The return value (must be a string) is used to build each list item. Good to enhance list items (For example to add images or more complex HTML)

: Event is triggered on the input element, for each option of a datalist. The return value (must be a string) is used to build each list item. Good to enhance list items (For example to add images or more complex HTML) event: datalistcreated : Event is triggered on the input element, after the list was created.

: Event is triggered on the input element, after the list was created. selectors for CSS/JS: .ws-validate (.ws-invalid/.ws-success) : The class 'ws-validate' on a form element will implement UX improved Instant Validation for this form. The classes .ws-invalid (similiar to :user-error) and .ws-success will mark either "touched" invalid element wrappers or valid and "filled" element wrappers. example

: The class 'ws-validate' on a form element will implement UX improved Instant Validation for this form. The classes .ws-invalid (similiar to :user-error) and .ws-success will mark either "touched" invalid element wrappers or valid and "filled" element wrappers. example selectors for CSS/JS: .user-success/.user-error : which work similar to :-moz-ui-valid/:-moz-ui-invalid or :user-error

: which work similar to :-moz-ui-valid/:-moz-ui-invalid or :user-error selectors for CSS/JS: .placeholder-visible : which work similar to :-moz-placeholder, :-ms-input-placeholder and ::-webkit-input-placeholder

: which work similar to :-moz-placeholder, :-ms-input-placeholder and ::-webkit-input-placeholder $().getErrorMessage : very similar to the standard validationMessage, but gives more control over the validationMessage.

: very similar to the standard validationMessage, but gives more control over the validationMessage. attribute: data-errormessage or -x-moz-errormessage : Attribute with text, which is used be custom validityAlert/customValidationMessage to show a custom error message for the field.

: Attribute with text, which is used be custom validityAlert/customValidationMessage to show a custom error message for the field. helper method: webshim.validityAlert.showFor: takes a DOM-Object/Selector/jQuery-Object and shows the invalid message for this element. (simply look into the prototype i.e. console.log(webshim.validityAlert) to make changes)

Canvas

the canvas feature implements one jQuery method .getContext() .

var ctx = $('#my-canvas').getContext('2d'); ctx.clearRect(10, 10, 100, 100); ctx.fillStyle = "rgb(200,0,0)"; ctx.fillRect(10, 10, 55, 50); ctx.fillStyle = "rgba(0, 0, 200, 0.5)"; ctx.fillRect(30, 30, 55, 50);

Webshim Lib can implement excanvas or FlashCanvas/FlashCanvas Pro:

// always run configuration before calling webshim.polyfill(); window.FlashCanvasOptions = { disableContextMenu: true }; webshim.setOptions('canvas', { type: 'flashpro' // excanvas | flash | flashpro }); //start polyfilling forms webshim.polyfill('forms');

Webshim will implement a bridge between the native/polyfilled drawImage canvas API and the polyfilled mediaelement API. To get this work in IE8 the 'flashpro' option type for the canvas feature has to be used.

Options for the canvas feature

type string Enumeration with value flash or flashpro or excanvas

Media

Audio, video and source

The mediaelement feature implements the audio, video and source elements including their API and enables playing mp4, mp3, flv, fla etc. media files and playing rtmp streams in incapable browsers.

Implemented/fixed elements, attributes, properties, methods, events

elements : video, audio, source

: video, audio, source attributes and IDL/properties : controls, loop, autoplay, src, media, type, muted

: controls, loop, autoplay, src, media, type, muted properties/IDLs : paused, ended, muted, volume, currentTime, duration, buffered 1 , currentSrc, readyState, networkState, videoHeight, videoWidth, seeking, defaultMuted

: paused, ended, muted, volume, currentTime, duration, buffered , currentSrc, readyState, networkState, videoHeight, videoWidth, seeking, defaultMuted methods : play, pause, load (mediaLoad 3 ), canPlayType 4

: play, pause, load (mediaLoad ), canPlayType events: loadedmetadata, play, pause, playing, canplay, ended, waiting, timeupdate, progress, emptied, volumechange, durationchange, seeking, seeked

1.buffered is a little bit buggy with youtube videos.

2.videoHeight/videoWidth not supported with youtube videos.

3. mediaLoad is the jQuery plugin method, which corresponds to the native load method (Webshims lib does not override jQuery's own load-method), ( $('video')[0].load() === $('video:first').mediaLoad() ).

4. canPlayType returns "maybe" if native player can't play, but Flash can and is installed. (i.e.: $('video').canPlayType('video/flv') might return "mabe")

Options for the mediaelement feature

replaceUI boolean|string If set to true, all audio and video elements inside a container with the class mediaplayer get custom styleable controls. If set to the string 'auto', only desktop browsers (except IE8) will get those extra styleable controls.

boolean|string If set to true, all audio and video elements inside a container with the class get custom styleable controls. If set to the string 'auto', only desktop browsers (except IE8) will get those extra styleable controls. preferFlash boolean If set to true the mediaelements will be replaced by flash, if flash is available. Otherwise, only if mediaelements aren't supported or the current audio/video container/codec isn't supported by the browser.

default: false

boolean If set to true the mediaelements will be replaced by flash, if flash is available. Otherwise, only if mediaelements aren't supported or the current audio/video container/codec isn't supported by the browser. default: false vars Flashvars Object configuration for Jarisplayer. This general configuration can be changed via a data-vars attribute too.

Flashvars Object configuration for Jarisplayer. This general configuration can be changed via a data-vars attribute too. changeSWF function Callback function to modify the flashvars object for Jarisplayer.

Playing HLS / RTMP Streams

<video poster="poster.jpg" controls=""> <!-- Mac OS / iOS HLS Streaming --> <source src="http://server.com/path/file.m3u8" type="application/x-mpegURL" /> <!-- rtmp streaming: using the data-server attribute --> <source data-server="rtmp://server.com/path/" src="file.mp4" type="video/rtmp" /> <!-- rtmp streaming: using an identifier (i.e.: mp4:) --> <source src="rtmp://server.com/path/identifier:file.mp4" type="video/rtmp" /> </video>

Loading youtube videos with different Qualities

Video quality can be suggested by using the vq parameter. Possible values are: small, medium, large, hd720, hd1080, highres

<video poster="poster.jpg" controls="" src="http://www.youtube.com/watch?v=siOHh0uzcuY&vq=large"> </video>

Using customstyleable controls

<style> /* add basic styles */ .mediaplayer { position: relative; height: 0; width: 100%; padding-bottom: 56.25%; /* 16/9 */ } .mediaplayer video, .mediaplayer .polyfill-video { position: absolute; top: 0; left: 0; height: 100%; width: 100%; } </style> <script> webshim.setOptions('mediaelement', {replaceUI: 'auto'}); webshim.polyfill('mediaelement'); </script> <div class="mediaplayer"> <video poster="poster.jpg" src="http://www.youtube.com/watch?v=siOHh0uzcuY&vq=large"> </video> </div>

Webshim will implement a bridge between the native/polyfilled canvas.drawImage API and the polyfilled mediaelement API (flash).

<script> webshim.setOptions({ canvas: { type: 'flashpro' }, mediaelement: { replaceUI: 'auto' } }); webshim.polyfill('mediaelement canvas'); </script> <script> $(function(){ var context, $video; function initCanvas() { var $canvas = document.getElementsByTagName("canvas")[0]; $video = $("video"); context = $canvas.getContext("2d"); $video.on("timeupdate", paintFrame); } function paintFrame(e) { context.drawImage($video[0], 0, 0); //timeupdate is dispatched every 250ms, let's paint the frame more often, //but only if a real timeupdate was dispatched if(e){ setTimeout(paintFrame, 65); setTimeout(paintFrame, 130); setTimeout(paintFrame, 195); } } initCanvas(); }); </script> <div class="mediaplayer ratio-16-9"> <video controls preload="none" poster="sintel-trailer.jpg"> <source src="sintel-trailer.mp4" type="video/mp4" /> </video> </div> <canvas style="border: 1px solid black;" height="280" width="500"></canvas>

Here you can find more information about customizing controls and extending the mediaplayer's behavior.

Examples/Demos

Track Element Support

The track feature implements the track element width a WebVTT parser and the corresponding DOM- and JS-APIs.

Implemented/fixed elements, attributes, properties, methods, events

1. Use additional [] to bind events to Array-like objects ( $([ $('video').prop('textTracks') ]).on('addtrack', function(e){console.log('track was added');}); )

2. Use $.prop to get activeCues property. (i.e.: $.prop(track, 'activeCues'); ).

Options for the track feature

override (false): Overrides native track implementation. If set to 'auto', the track implementation will be overridden only in desktop browsers. (Good to use with mediaelement's replaceUI option). In case you have to deal with some cross-browser issues with native implementation.

(false): Overrides native track implementation. If set to 'auto', the track implementation will be overridden only in desktop browsers. (Good to use with mediaelement's replaceUI option). In case you have to deal with some cross-browser issues with native implementation. positionDisplay (true): Positions the cue display via JavaScript.

Examples

Geolocation

The geolocation -feature implements the navigator.geolocation API. The following methods are available:

navigator.getCurrentPosition: successCallback, errorCallback and options ({timeout: number}) are supported

navigator.watchPosition: in shim identical to getCurrentPosition, except it returns an useless ID

navigator.clearWatch: is noop in shim

The shim uses the geolocation information provided by http://freegeoip.net and/or googles API-Loader

Options for geolocation

confirmText string confirm text for requesting access to geo data.

webshim.setOptions('geolocation', { confirmText: '{location} wants to know your position. It is Ok to press Ok.' });

navigator.geolocation.getCurrentPosition(function(pos){ alert("Thx, you are @ latitude: "+ pos.coords.latitude +"/longitude: " + pos.coords.longitude); });

Details & Summary

The HTML5 details element is an interactive element. If the open attribute is set the details are shown, if not the details are hidden.

click to toggle visibility Here are the details of this element: Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore mag

Dynamically creating a details element (always use htmlPolyfill, afterPolyfill, beforePolyfill etc.):

$('details:first').afterPolyfill('<details open="open"><p>Here is some text</p></details>');

The openness of a details element can be also scripted. Simply change the open IDL-attribute:

// set the open attribute of the first details element ... // ... to its opposite value $('details:first').prop('open', !$('details').prop('open') );

Options for the details feature

text string The summary text which is generated if no summary element is found as first child of the details element.

default: Details

string The summary text which is generated if no summary element is found as first child of the details element. default: Details animate boolean If set to true, the visibility toggle of details will be animated.

default: false

webshim.setOptions('details', {animate: true});

Constraints of the details polyfill

The polyfill currently only allows other elements as direct children of the details. Simple text is not allowed as direct child of details.

The details and summary element can be considered as experimental . It is not clear wether and if yes, how a developer can style the summary element. Safari nightly (6) and Chrome 12 are currently the only browsers supporting this element. Note: Please read Bruce Lawson's blog post.

. It is not clear wether and if yes, how a developer can style the summary element. Safari nightly (6) and Chrome 12 are currently the only browsers supporting this element. Note: Please read Bruce Lawson's blog post. We currently haven't coded unit tests for this feature

FileReader/FormData/CORS

The filereader feature enables accessing and reading a file from an input[type="file"]. Additionally it can be processed over AJAX to a server. Due to its obtrusive nature an input has to have an additional class with the name ws-filereader :

Implemented/fixed elements, attributes, properties, methods, events

1. [accept], [multiple] and the .files property is only polyfilled on input elements with the additional class 'ws-filereader'

2. For full support of all features Flash or Silverliegt should be installed. But webshim falls back to other technologies (i.e.: iframe solutions), if those aren't installed. Therefore for full CORS support a crossdomain.xml has to be on the server!

3. FormData shim can currently only handle one file per AJAX request!

An example of how to read a file as a base64 string from a form control:

<!-- add ws-filereader class to all shimable type="file" inputs --> <input type="file" class="ws-filereader" id="user-photo" multiple="" accept="image/*" />

//load the filereader webshim.polyfill('filereader'); //on DOM ready filereader is shimmed $(function(){ $('#user-photo').on('change', function (evt) { var reader, file; reader = new FileReader(); reader.onload = function (evt) { var fileData = evt.target.result; // fileData is the base64 encoded image }; //use $.prop to access files property file = $(this).prop('files')[0]; reader.readAsDataURL(file); }); });

To get the file transferred to a server the FormData constructor in conjunction with AJAX can be used:

$('form[data-action].ajax-form').on('submit', function(){ //FormData is similar to $.serializeArray, but can handle type="file" in AJAX var data = new FormData(this); $.ajax({ url: $form.data('action'), success: function(data){ //success }, error: function(){ //error }, data: data, processData: false, contentType: false, type: 'POST' }); e.preventDefault(); });

For the code above to fully work it is important, that everything is either in the same origin or a crossdomain.xml is on the server. A featured example including php code can be found in the filereader directory.

In case webshim is not served from the same domain (for exmaple using a CDN) a crossdomain.xml like the following should be reachable on your server root:

<?xml version="1.0"?> <!DOCTYPE cross-domain-policy SYSTEM "http://www.macromedia.com/xml/dtds/cross-domain-policy.dtd"> <cross-domain-policy> <allow-access-from domain="*" secure="false" /> </cross-domain-policy>

In case you don't have full access to your server's root to do so, you can host Moxie.min.swf (Flash) on your server and tell webshim to load them from there:

webshim.setOptions('filereader', { swfpath: '/assests/Moxie.min.swf' });

The filereader feature is also lazy loaded by webhsim's form feature as soon as an element matching the input.ws-filereader selector is used. Additionally the forms features enables custom styleable [type=file] elements if it finds a wrapper with the class ws-custom-file :

<script> //filereader is lazyLoaded no need to call feature webshim.polyfill('forms'); </script> <div class="ws-custom-file"> <!-- add ws-filereader class to all shimable type="file" inputs --> <input type="file" class="ws-filereader" id="user-photo" multiple="" accept="image/*" /> <!-- button and .ws-file-value for custom filepicker UI --> <button type="button">Browse</button> <span class="ws-file-value">...</span> </div>

The filereader feature is based on code from https://github.com/moxiecode/moxie.

matchMedia

The matchMedia feature is a polyfill of matchMedia. It includes also a polyfill for matchMedia('(max-width: 480px').addListener .

This feature is based on code from https://github.com/paulirish/matchMedia.js.

usermedia

The usermedia feature is a polyfill of navigator.getUserMedia. It includes also a polyfill for URL and the srcObj property.

A demo with code example of getUserMedia polyfill.

url

The url feature is a polyfill of WHATWG URL Spec. It also includes the searchParams object.

The URL object has the following properties:

href

origin

protocol

username

password

host

hostname

port

pathname

search

searchParams append(name, value) delete(name) get(name) getAll(name) has(name) set(name, value)

hash

Usage

var link = new URL('http://afarkas.github.io/webshim/demos/index.html?param1=value1'); link.protocol; // returns 'http:' link.searchParams.get('param1'); // returns 'value1' link.searchParams.append('param2', 'value2'); link.href // returns 'http://afarkas.github.io/webshim/demos/index.html?param1=value1¶m2=value2'

This feature is based on code from https://github.com/inexorabletash/polyfill/blob/master/url.js.

Promise

The promise feature is a polyfill of ES6 Promises. For instructions on using promises and details of the API, read JavaScript Promises at HTML5Rocks.

This feature is based on code from https://github.com/paulmillr/es6-shim.

Responsive Images

A strict polyfill of the picture element draft specification from the Responsive Images Community Group, including the srcset and sizes attributes.

webshim.polyfill('picture'):

This feature is based on code from https://github.com/aFarkas/respimage/. Complete documentation is available there.

sticky (position: sticky)

The sticky feature is a polyfill for the CSS position value sticky (position sticky demo).

Descriptive/Markup Usage

Simply add the class ws-sticky to all elements, which should become sticky and define either a top or bottom value:

<section> <header class="ws-sticky"> <!-- ... --> </header> <!-- ... --> <footer class="ws-sticky"> <!-- ... --> </footer> </section>

Sticky and responsive webdesign. The sticky position can be also used in conjunction with mediaqueries. Simply add a data-stickymedia attribute with your mediaquery to your element:

<section> <header class="ws-sticky" data-stickymedia="(max-width: 480px)"> <!-- ... --> </header> <!-- ... --> </section>

JS Usage

Often you don't want to add the class 'ws-sticky' directly into your HTML, in this case you can use the JS-API. Simply trigger the event 'wssticky' on all elements, which should become sticky:

$('table.long-table > thead') .addClass('ws-sticky') .trigger('wssticky') ;

Example with mediaqueries:

$('table.long-table > thead') .addClass('ws-sticky') .data('stickymedia', '(max-width: 480px)') .trigger('wssticky') ;

The stickyness of an element, can also be removed or updated with the JS API:

//use destroysticky to remove sticky $('dl.list-view > dt') .removeClass('ws-sticky') .trigger('destroysticky') ; //use updatesticky to remove sticky $('dl.list-view > dt').trigger('updatesticky');

Webshim sticky implementation supports sticky in conjunction with either top or bottom properties and on most elements including table headers (thead) and table footer (tfoot). It also implements "local" sticky areas, where the parent element of the 'sticky element' has set the overflow value to 'auto/scroll'.

Known restrictions:

Don't set the margin-left and margin-right value of the sticky element to 'auto'

The left and the right value of the sticky element has to be 'auto'.

Webshim's opinionated enhancement cross browser development strategy

Webshim has evolved form a general polyfill library to a sophisticated UI component / UI widget library which makes it easy to create scalable, responsive and highly adaptable websites and webapps.

While webshim polyfills older browsers and automatically fixes a lot of bugs, it enables the developer to also enhance even modern browsers with highly customizable widgets (datepicker, form validation, slider, autosuggest, custom stylable controls for video/audio).

Webshim is opinionated, that a developer should always solve a problem the HTML5 way.

For example most datepickers have a direct configuration option to disable certain days to be picked from the control. This is not possible with current implementations of input[type="date"] , but it is possible to use the HTML 5 form validation API to constrain the user input to certain days. Therefore webshim offers a way to constrain the user input and those constraints are used to decide whether certain days should be disabled in the pickercontrol.

This way a developer can switch between polyfilled/enhanced and native widgets. While the appearance might be different the base functionality will work in all browsers. But if a certain feature is barley possible with HTML5 or a developer needs full control in all browsers/devices, he can always switch to a enhance all strategy.

Webshim automatically scales your enhancements

Webshim might in total load a bunch of files to implement or enhance features. This might look crazy at first glance. But due to the fact that webshim uses conditionally and deferred loading techniques, it turns out, that these techniques help to build large and fast responding websites and webapps. Webshim often initially loads only few (often only one file) and small files depending on the capabilities of the device and the requested features and then delays loading a bunch of other files either as soon as they are needed or after onload also depending on the capabilities of the device.

Webshim's mobile strategy

Often a developer might choose not to "enhance" a widget on smartphones and use built-in UI widgets, to create fast responding websites. In case a developer switches to Webshim's custom UI widgets, he gets fully responsive, font-size scalable and touch-optimized widgets.

Tip: Enlarge touch target size of UI widgets by using the font-size scalability:

/* enlarge mediacontrols by factor 1.5 from 16px to 24px */ .touchevents .mediaplayer { font-size: 24px; } /* enlarge rangeslider, datepicker by factor ~1.5 from 13px to 19px */ .touchevents .ws-popover, .touchevents .ws-range { font-size: 19px; } @media (pointer:coarse), (-moz-touch-enabled), (-webkit-touch-enabled), (touch-enabled) { .mediaplayer { font-size: 24px; } .ws-popover, .ws-range { font-size: 19px; } }

Webshim and accessibility

All UI components of webshim are fully accessible and conform to WCAG 2.0 (Level A and AA) and are therefore also Section 508-compliant. Webshim not only adds some WAI-ARIA roles, but also conforms to the ARIA Best Practices and tests all widgets with real screenreaders.

Typical project setup and JS optimizations (requirejs, concatination of JS files)

While most scripts only use one JS file to include the whole behavior, Webshims is using the polyfiller.js file, a polyfiller named AMD module, as an entry point and loads conditionally other resources. This means webshims needs to know, where those resources are.

The code inside of the polyfiller.js automatically detects the path to the script it is run from and assumes, that the shims folder is in the same directory. This means, you have to make sure, that either the shims folder is placed parallel to the code of the polyfiller.js or to configure the path using the basePath option.

Configuring the path manually

//configure path manually webshim.setOptions('basePath', '/yourFolderTo/shims/'); //polyfill webshim.polyfill('forms mediaelement');

Optimizing into the same folder

The following example, shows a very simple setup where the shims folder is parallel to the normal polyfiller.js file and the optimized js file (i.e.: app.min.js):

+-- projectfolder |-- index.html +-- scripts +-- vendor |-- jquery.js +-- shims |-- main.js |-- require.js |-- app.min.js (optimized code, which also includes the polyfiller.js code) |-- polyfiller.js

Optimizing into a different folder

A better way is to output the concatenated and compressed code into a different directory for deployment. For a webshims project this means beside an optimization task (concat and minify) often another simple task to copy the shims folder parallel to the optimized script package:

|-- projectfolder |-- index.html +-- bower_components |-- jquery +-- js-webshim +-- dev |-- polyfiller.js |-- shims |-- minified +-- scripts +-- vendor |-- main.js (requires polyfiller.js from the **dev** folder) |-- require.js +-- optimized-scripts (folder with optimized scripts) |-- app.min.js (optimized code, which also includes the polyfiller.js code) |-- shims (copied shims folder from the **minified** folder)

Customizing Webshim

Customizing styles and UI

Webshim offers a lot of different config options to change the behavior of widgets and controls. The pre-defined styles loaded by webshim are just an offer. A developer is appealed to enhance/change those styles. Even all animation are done with CSS and can be changed.

Webshim pre-defined selectors are sometime overqualified to minimize conflicts with existing page styles.

There are two different main strategies to customize webshim widget's styles. In case you only want to make small changes, you can simply override the styles with your own modification. But in case you either want to have full control or need to make more changes, it is wise to set loadStyles to false and write you own styles.

In case you are setting loadStyles to false you can either start from scratch or grab/copy the default styles from webshim included in the dev folder.

webshim.setOptions('loadStyles', false);

Some widget's also use inline styles to calculate the position or the dimension of the widget. This can be turned off depending on the widget settings. (Pro Tip: This can also improve performance, especially in old IE8 or some mobile browsers.):

webshim.setOptions({ loadStyles: false, 'forms-ext': { widgets: { calculateWidth: false } }, track: { positionDisplay: false } });

In case you have made some nice changes and want to share those with the community, feel free to add those to the themes-directory and do start a pr .

Writing a New Polyfill

A Pollyfill is always split into at least two parts. First the test and loader definition, and then the implementation.

Assume there is a new method magicMethod on the window object that we want to polyfill if the browser doesn't provide it. An implementation would look like this:

webshim.addPolyfill('magicMethod', { test: function(){ return ('magicMethod' in window); } }); // loads magicMethod.js from shim-folder if test returns false

Create a file called magicMethod with your polyfill code and place it in the shim folder:

window.magicMethod = function(){ // your polyfill implementation };

If your implementation has dependencies on other polyfills/modules, you can add a dependencies property to make sure they're loaded too:

webshim.addPolyfill('magicMethod', { test: function(){ return ('magicMethod' in window); }, d: ['es5'] // d = dependencies }); // load magicMethod.js and its dependencies if test returns false

If your shim has dependencies, you have to register your implementation code with webshim.register :

webshim.register('magicMethod', function($, webshims, window, document, undefined, options){ // now you can use es5-feature feature window.magicMethod = function(){ // your polyfill implementation }; });

In case of a DOM extension, webshims lib comes with some useful extension-methods.

webshim.addPolyfill('mediaelement', { test: function(){ return ('canPlayType' in document.createElement('video')); }, d: ['dom-support'], methodNames: ['play'] // pause, load }); // load mediaelement.js and DOM extension features from shim folder // if test returns false and always create a jQuery plugin called play, // which tries to invoke native or polyfilled play // listen to 'play' events in the capturing phase // can use event delegation with jQuery's bind method webshim.capturingEvents(['play']);

Now put a mediaelement.js inside of your shim folder and start implementing some features. The dom-support feature of Webshims lib comes with some very useful implementation helpers. Here are two of them:

webshim.defineNodeNamesProperty (nodeNames, property, descriptor)

(nodeNames, property, descriptor) webshim.defineNodeNamesBooleanProperty (nodeNames, property, descriptor)