diff options
author | Stefan Parviainen <saparvia@caterva.eu> | 2015-01-01 12:32:15 +0100 |
---|---|---|
committer | Stefan Parviainen <saparvia@caterva.eu> | 2015-01-01 12:32:15 +0100 |
commit | 9557908875af76d167797a36e980798349fc63b5 (patch) | |
tree | 8033d8edd0a16ae3d176080ca360d4eb414277ed /library/jquery.AreYouSure | |
parent | 93b94704878c1b66ee95987de2b24dc39163763a (diff) | |
download | volse-hubzilla-9557908875af76d167797a36e980798349fc63b5.tar.gz volse-hubzilla-9557908875af76d167797a36e980798349fc63b5.tar.bz2 volse-hubzilla-9557908875af76d167797a36e980798349fc63b5.zip |
Warn about unsaved settings using jquery.areyousure
Diffstat (limited to 'library/jquery.AreYouSure')
-rw-r--r-- | library/jquery.AreYouSure/.gitignore | 166 | ||||
-rw-r--r-- | library/jquery.AreYouSure/Gruntfile.js | 26 | ||||
-rw-r--r-- | library/jquery.AreYouSure/README.md | 297 | ||||
-rw-r--r-- | library/jquery.AreYouSure/are-you-sure.jquery.json | 39 | ||||
-rw-r--r-- | library/jquery.AreYouSure/ays-beforeunload-shim.js | 31 | ||||
-rw-r--r-- | library/jquery.AreYouSure/bower.json | 30 | ||||
-rw-r--r-- | library/jquery.AreYouSure/demo/are-you-sure-demo.html | 576 | ||||
-rw-r--r-- | library/jquery.AreYouSure/jquery.are-you-sure.js | 192 | ||||
-rw-r--r-- | library/jquery.AreYouSure/package.json | 45 | ||||
-rw-r--r-- | library/jquery.AreYouSure/spec/javascripts/fixtures/input-text.html | 4 | ||||
-rw-r--r-- | library/jquery.AreYouSure/spec/javascripts/jquery.are-you-sure_spec.js | 28 |
11 files changed, 1434 insertions, 0 deletions
diff --git a/library/jquery.AreYouSure/.gitignore b/library/jquery.AreYouSure/.gitignore new file mode 100644 index 000000000..345f0dbeb --- /dev/null +++ b/library/jquery.AreYouSure/.gitignore @@ -0,0 +1,166 @@ +################# +## Eclipse +################# + +*.pydevproject +.project +.metadata +bin/ +tmp/ +*.tmp +*.bak +*.swp +*~.nib +local.properties +.classpath +.settings/ +.loadpath + +# External tool builders +.externalToolBuilders/ + +# Locally stored "Eclipse launch configurations" +*.launch + +# CDT-specific +.cproject + +# PDT-specific +.buildpath + + +################# +## Visual Studio +################# + +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +# User-specific files +*.suo +*.user +*.sln.docstates + +# Build results +[Dd]ebug/ +[Rr]elease/ +*_i.c +*_p.c +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.vspscc +.builds +*.dotCover + +## TODO: If you have NuGet Package Restore enabled, uncomment this +#packages/ + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opensdf +*.sdf + +# Visual Studio profiler +*.psess +*.vsp + +# ReSharper is a .NET coding add-in +_ReSharper* + +# Installshield output folder +[Ee]xpress + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish + +# Others +[Bb]in +[Oo]bj +sql +TestResults +*.Cache +ClientBin +stylecop.* +~$* +*.dbmdl +Generated_Code #added for RIA/Silverlight projects + +# Backup & report files from converting an old project file to a newer +# Visual Studio version. Backup files are not needed, because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML + + + +############ +## Windows +############ + +# Windows image file caches +Thumbs.db + +# Folder config file +Desktop.ini + + +############# +## Python +############# + +*.py[co] + +# Packages +*.egg +*.egg-info +dist +build +eggs +parts +bin +var +sdist +develop-eggs +.installed.cfg + +# Installer logs +pip-log.txt + +# Unit test / coverage reports +.coverage +.tox + +#Translations +*.mo + +#Mr Developer +.mr.developer.cfg + +# Mac crap +.DS_Store + +bower_components/ +node_modules/ diff --git a/library/jquery.AreYouSure/Gruntfile.js b/library/jquery.AreYouSure/Gruntfile.js new file mode 100644 index 000000000..efca34c0a --- /dev/null +++ b/library/jquery.AreYouSure/Gruntfile.js @@ -0,0 +1,26 @@ +module.exports = function(grunt) { + grunt.config.init({ + karma: { + options: { + browsers: [ 'Chrome', 'Firefox', 'Safari', 'IE' ], + frameworks: [ 'jasmine' ], + reportSlowerThan: 500, + singleRun: true + }, + unit: { + files: [ + { pattern: 'bower_components/jquery/dist/jquery.min.js' }, + { pattern: 'bower_components/jasmine-jquery/lib/jasmine-jquery.js' }, + { pattern: 'jquery.are-you-sure.js' }, + { pattern: 'spec/javascripts/*.js' }, + { pattern: 'spec/javascripts/fixtures/**/*.html', included: false } + ] + } + } + }); + + grunt.registerTask('test', 'Run tests.', [ 'karma' ]); + grunt.registerTask('default', [ 'test' ]); + + grunt.loadNpmTasks('grunt-karma'); +}; diff --git a/library/jquery.AreYouSure/README.md b/library/jquery.AreYouSure/README.md new file mode 100644 index 000000000..6a538648a --- /dev/null +++ b/library/jquery.AreYouSure/README.md @@ -0,0 +1,297 @@ +Are You Sure? - A light "dirty forms" JQuery Plugin +====== +**Version:** 1.9 + +*Are-you-sure* (```jquery.are-you-sure.js```) is simple light-weight "dirty +form" JQuery Plugin for modern browsers. It helps prevent users from losing +unsaved HTML Form changes by promoting the user to save/submit. + +It's simple to use. Just add the following line to your page's ready +function: + +```javascript +$('form').areYouSure(); +``` + +*Are-you-sure* is a minimal plugin for modern browsers. There are plenty of +"dirty forms" implementations out there, however they all seemed very +heavyweight and over-engineered...! Most were written some time back and +contain many 'hacks' to support legacy browsers, and/or rely on other fat +dependencies such as FaceBox or jQueryUI. *Are-you-sure* solves this by +doing this simple task in the simplest possible way. + +*Are-you-sure* is as simple as it gets: + + * 100% JS with zero dependencies and no external CSS. + * Leverages `onBeforeUnload` to detect all page/browser exit events. + * Works on forms of any size. + * Correct state management - if a user edits then restores a value, the form + is not considered dirty. + * Easy to understand - less than a "terminal screen" of code! + * Graceful degradation on legacy browsers (i.e. if you're running an old + browser... remember to save :-) + +###Basic Usage + +```javascript + +$(function() { + + // Enable on all forms + $('form').areYouSure(); + + // Enable on selected forms + $('form.dirty-check').areYouSure(); + + // With a custom message + $('form').areYouSure( {'message':'Your profile details are not saved!'} ); + +} +``` +To ignore selected fields from the dirtyness check: + +```html + <form id="myForm" name="myform" action="/post" method="post"> + + Field 1: (checked) <input type="text" name="field1"> <br /> + Field 2: (ignored): <input type="text" name="field2" data-ays-ignore="true"> <br /> + Field 3: (ignored): <input type="text" name="field3" class="ays-ignore"> <br /> + + <input type="submit" value="Submit"> + + </form> +``` + +###Advanced Usage + +```javascript + +$(function() { + + /* + * Make Are-You-Sure "silent" by disabling the warning message + * (tracking/monitoring only mode). This option is useful when you wish to + * use the dirty/save events and/or use the dirtyness tracking in your own + * beforeunload handler. + */ + $('form').areYouSure( {'silent':true} ); + + /* + * Dirtyness Change Events + * Are-You-Sure fires off "dirty" and "clean" events when the form's state + * changes. You can bind() or on(), these events to implement your own form + * state logic. A good example is enabling/disabling a Save button. + * + * "this" refers to the form that fired the event. + */ + $('form').on('dirty.areYouSure', function() { + // Enable save button only as the form is dirty. + $(this).find('input[type="submit"]').removeAttr('disabled'); + }); + $('form').on('clean.areYouSure', function() { + // Form is clean so nothing to save - disable the save button. + $(this).find('input[type="submit"]').attr('disabled', 'disabled'); + }); + + /* + * It's easy to test if a form is dirty in your own code - just check + * to see if it has a "dirty" CSS class. + */ + if ($('#my-form').hasClass('dirty')) { + // Do something + } + + /* + * If you're dynamically adding new fields/inputs, and would like to track + * their state, trigger Are-You-Sure to rescan the form like this: + */ + $('#my-form').trigger('rescan.areYouSure'); + + /* + * If you'd like to reset/reinitialize the form's state as clean and + * start tracking again from this new point onwards, trigger the + * reinitalize as follows. This is handy if say you've managing your + * own form save/submit via asyc AJAX. + */ + $('#my-form').trigger('reinitialize.areYouSure'); + + /* + * In some situations it may be desirable to look for other form + * changes such as adding/removing fields. This is useful for forms that + * can change their field count, such as address/phone contact forms. + * Form example, you might remove a phone number from a contact form + * but update nothing else. This should mark the form as dirty. + */ + $('form').areYouSure( {'addRemoveFieldsMarksDirty':true} ); + + /* + * Sometimes you may have advanced forms that change their state via + * custom JavaScript or 3rd-party component JavaScript. Are-You-Sure may + * not automatically detect these state changes. Examples include: + * - Updating a hidden input field via background JS. + * - Using a [rich WYSIWYG edit control](https://github.com/codedance/jquery.AreYouSure/issues/17). + * One solution is to manually trigger a form check as follows: + */ + $('#my-form').trigger('checkform.areYouSure'); + + /* + * As an alternative to using events, you can pass in a custom change + * function. + */ + $('#my-adv-form').areYouSure({ + change: function() { + // Enable save button only if the form is dirty. i.e. something to save. + if ($(this).hasClass('dirty')) { + $(this).find('input[type="submit"]').removeAttr('disabled'); + } else { + $(this).find('input[type="submit"]').attr('disabled', 'disabled'); + } + } + }); + + /* + * Mixing in your own logic into the warning. + */ + $('#my-form').areYouSure( {'silent':true} ); + $(window).on('beforeunload', function() { + isSunday = (0 == (new Date()).getDay()); + if ($('#my-form').hasClass('dirty') && isSunday) { + return "Because it's Sunday, I'll be nice and let you know you forgot to save!"; + } + } + +} +``` +The [demo page](http://www.papercut.com/products/free_software/are-you-sure/demo/are-you-sure-demo.html) +shows the advanced usage options in more detail. + + +###Install +Are-You-Sure is a light-weight jQuery plugin - it's a single standalone +JavaScript file. You can download the +[jquery.are-you-sure.js](https://raw.github.com/codedance/jquery.AreYouSure/master/jquery.are-you-sure.js) +file and include it in your page. Because it's so simple it seems a shame +to add an extra browser round trip. It's recommended that you consider +concatenating it with other common JS lib files, and/or even cut-n-pasting +the code (and license header) into one of your existing JS files. + +For experimental Mobile Safari support, also include ```ays-beforeunload-shim.js``` +(see Known Issues below). + +*Are-you-sure* may also be installed with [Bower](http://twitter.github.com/bower/): + +```bash +$ bower install jquery.are-you-sure +``` + +If you're using, or like, *Are-you-sure* make sure you **star/watch** this project +so you can stay up-to-date with updates. + +###Demo +This [demo page](http://www.papercut.com/products/free_software/are-you-sure/demo/are-you-sure-demo.html) +hosts a number of example forms. + +###Supported Browsers +*Are-you-sure* has been tested on and fully supports the following browsers: + +* IE 9 through 11 +* Google Chrome (versions since 2012) +* Firefox (versions since 2012) +* Safari (versions since 2012) + +Experimental support is available on iOS and Opera via the *beforeunload* shim (see below). + +###Known Issues & Limitations + +####Mobile Safari and Opera +The ```windows.beforeunload``` event is not supported on iOS (iPhone, iPad, and iPod). An +experimental shim offering partial *beforeunload* emulation is provided to help plug this gap. +It works by scanning the page for anchor links and augments the default behaviour to first +check with *Are-you-sure* before navigating away. To use, simply include +```ays-beforeunload-shim.js``` in your page. + +####Firefox +The custom message option may not work on Firefox ([Firefox bug 588292](https://bugzilla.mozilla.org/show_bug.cgi?id=588292)). + +###Development +The aim is to keep *Are-you-sure* simple and light. If you think you have +a good idea which is aligned with this objective, please voice your thoughts +in the issues list. + +####Pull Requests +If possible, please submit your pull request against the most recent ```dev-*``` branch rather than master. This will make it easier to merge your code into the next planned release. + +####Running tests +```bash +$ npm install +$ npm test +``` + +###Release History + +**2014-08-13** (1.9) - This is a minor bugfix release: + +* Addressed issue [#45](https://github.com/codedance/jquery.AreYouSure/issues/55) seen with empty select fields. +* Thanks [valgen](https://github.com/valgen) and [tus124](https://github.com/tus124) for the contribution. + +**2014-06-22** (1.8) - This is a minor bugfix release: + +* Fixed NPE that may occur when using a 'multiple' option field. +* Minor timing tweak to help mitigate bypass issue raised in [#45](https://github.com/codedance/jquery.AreYouSure/issues/45) +* Thanks [apassant](https://github.com/apassant) and [amatenkov](https://github.com/amatenkov) for the contribution. + +**2014-05-28** (1.7) + +* Fixed multiple warning dialogs that may appear on IE and recent versions of Chrome +* Experimental support for iOS Mobile Safari (via a *beforeunload* shim) +* Various minor fixes (e.g. support input fields with no type=) +* Minor performance improvements on pages with multiple forms +* Improved documentation and examples +* Thanks to [lfjeff](https://github.com/lfjeff) and [aqlong](https://github.com/aqlong) for the contribution and ideas! + +**2014-02-07** (1.6) + +* Add field count tracking (```addRemoveFieldsMarksDirty```) (contrib *jonegerton*) +* Added event to manually trigger a form check/recheck (contrib *jonegerton*) +* Thanks to [jonegerton](https://github.com/jonegerton) for the contribution! + +**2013-11-15** (1.5) + +* Added support for HTML5 input field types. (contrib *albinsunnanbo*) +* New option to reinitialize/reset the dirty state. This is handy if you're managing your own async submit/save using AJAX. (contrib *albinsunnanbo*) +* Thanks to [albinsunnanbo](https://github.com/albinsunnanbo) for the contribution! + +**2013-10-2** (1.4) + +* Added dirty and clean "events" +* Added an option to disable the message (dirty tracking only) +* Added an option to rescan a form to look/detect any new fields + +**2013-07-24** - Minor fix - don't fail if form elements have no "name" attribute. + +**2013-05-14** - Added support for form reset buttons (contributed by codev). + +**2013-05-01** - Added support for hidden and disabled form fields. + +**2013-02-03** - Add demo page. + +**2013-01-28** - Add ```change``` event support and a demo page. + +**2012-10-26** - Use dashes in class names rather than camel case. + +**2012-10-24** - Initial public release. + + +###Prerequisites +jQuery version 1.4.2 or higher. 2.0+ or 1.10+ recommended. + + +###License +The same as JQuery... + + jQuery Plugin: Are-You-Sure (Dirty Form Detection) + https://github.com/codedance/jquery.AreYouSure/ + + Copyright (c) 2012-2014, Chris Dance - PaperCut Software http://www.papercut.com/ + Dual licensed under the MIT or GPL Version 2 licenses. + http://jquery.org/license diff --git a/library/jquery.AreYouSure/are-you-sure.jquery.json b/library/jquery.AreYouSure/are-you-sure.jquery.json new file mode 100644 index 000000000..9c699b72b --- /dev/null +++ b/library/jquery.AreYouSure/are-you-sure.jquery.json @@ -0,0 +1,39 @@ +{ + "name": "are-you-sure", + "title": "Are You Sure? - a dirty forms check plugin", + "description": "Are-you-sure is simple light-weight dirty forms JQuery Plugin for modern browsers. It helps prevent users from loosing unsaved form changes by prompting the user to save/submit. It's dependency free and designed for modern browsers... just the features you need and nothing more! See the project page and demo for usage and examples.", + "keywords": [ + "form", + "dirty", + "field", + "change", + "save", + "save-check", + "save-warning" + ], + "version": "1.9.0", + "author": { + "name": "Chris Dance (codedance) at PaperCut Software", + "url": "https://github.com/codedance" + }, + "maintainers": [ + { + "name": "Chris Dance", + "email": "chris.dance@papercut.com", + "url": "http://www.papercut.com/" + } + ], + "licenses": [ + { + "type": "MIT", + "url": "https://github.com/codedance/jquery.AreYouSure/blob/master/README.md" + } + ], + "bugs": "https://github.com/codedance/jquery.AreYouSure/issues", + "homepage": "https://github.com/codedance/jquery.AreYouSure", + "docs": "https://github.com/codedance/jquery.AreYouSure", + "demo": "http://www.papercut.com/products/free_software/are-you-sure/demo/are-you-sure-demo.html", + "dependencies": { + "jquery": ">=1.4.2" + } +} diff --git a/library/jquery.AreYouSure/ays-beforeunload-shim.js b/library/jquery.AreYouSure/ays-beforeunload-shim.js new file mode 100644 index 000000000..cb864cdeb --- /dev/null +++ b/library/jquery.AreYouSure/ays-beforeunload-shim.js @@ -0,0 +1,31 @@ +/*! + * An experimental shim to partially emulate onBeforeUnload on iOS. + * Part of https://github.com/codedance/jquery.AreYouSure/ + * + * Copyright (c) 2012-2014, Chris Dance and PaperCut Software http://www.papercut.com/ + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * Author: chris.dance@papercut.com + * Date: 19th May 2014 + */ +$(function() { + if (!navigator.userAgent.toLowerCase().match(/iphone|ipad|ipod|opera/)) { + return; + } + $('a').bind('click', function(evt) { + var href = $(evt.target).closest('a').attr('href'); + if (href !== undefined && !(href.match(/^#/) || href.trim() == '')) { + var response = $(window).triggerHandler('beforeunload', response); + if (response && response != "") { + var msg = response + "\n\n" + + "Press OK to leave this page or Cancel to stay."; + if (!confirm(msg)) { + return false; + } + } + window.location.href = href; + return false; + } + }); +}); diff --git a/library/jquery.AreYouSure/bower.json b/library/jquery.AreYouSure/bower.json new file mode 100644 index 000000000..8591dc0d0 --- /dev/null +++ b/library/jquery.AreYouSure/bower.json @@ -0,0 +1,30 @@ +{ + "name": "jquery.are-you-sure", + "version": "1.9.0", + "homepage": "https://github.com/codedance/jquery.AreYouSure", + "authors": [ + "CodeDance <chris.dance@papercut.com>" + ], + "description": "A light-weight jQuery 'dirty forms' Plugin - it monitors html forms and alerts users to unsaved changes if they attempt to close the browser or navigate away from the page. (Are you sure?)", + "main": "jquery.are-you-sure.js", + "keywords": [ + "form", + "dirty", + "field", + "change", + "save-check", + "are-you-sure", + "save-warning" + ], + "license": "MIT/GPLv2", + "ignore": [ + "**/.*", + "demo" + ], + "dependencies": { + "jquery": ">=1.4.2" + }, + "devDependencies": { + "jasmine-jquery": "~2.0.3" + } +} diff --git a/library/jquery.AreYouSure/demo/are-you-sure-demo.html b/library/jquery.AreYouSure/demo/are-you-sure-demo.html new file mode 100644 index 000000000..3f0327b2e --- /dev/null +++ b/library/jquery.AreYouSure/demo/are-you-sure-demo.html @@ -0,0 +1,576 @@ +<!DOCTYPE html> +<html> + <head> + <title>Demo: Are You Sure? - a dirty forms jQuery Plugin</title> + + <!-- + + We'll use an old version of jQuery to show we're backwards compatible. In + production we recommend using a later version. e.g. + + <script src="http://code.jquery.com/jquery-1.11.1.min.js"></script> + <script src="http://code.jquery.com/jquery-2.1.1.min.js"></script> + + --> + + <script src="http://code.jquery.com/jquery-1.4.2.min.js"></script> + <script src="../jquery.are-you-sure.js"></script> + <script src="../ays-beforeunload-shim.js"></script> + <script> + + $(function() { + + // Example 1 - ... in one line of code + $('#example-1-form').areYouSure(); + + + // Example 2 - ignore a dynamic field + $('#example-2-form').areYouSure(); + + var defaultPickup15min = new Date((new Date()).getTime() + 15 * 60000); + $('#pickup').val(defaultPickup15min.getHours() + + ':' + defaultPickup15min.getMinutes()); + + + // Example 3 - custom message and hooking the dirty change events + $('#example-3-form').areYouSure( + { + message: "Did you forget to save your standard coffee order?" + } + ); + // Enable save button only if the form is dirty - using events. + $('#example-3-form').bind('dirty.areYouSure', function() { + $(this).find('input[type="submit"]').removeAttr('disabled'); + }); + $('#example-3-form').bind('clean.areYouSure', function() { + $(this).find('input[type="submit"]').attr('disabled', 'disabled'); + }); + + + // Example 4 - dynamically change and add form fields. + $('#example-4-form').areYouSure( + { + message: "Did you forget to submit your coffee order?" + } + ); + + $('#example-4-lastorder').click(function() { + // ... set our saved coffee type. + $('#example-4-coffee').val('espresso'); + // Because we've made a change from our own JavaScript, we need to fire + // off manual 'form check'. + $('#example-4-form').trigger('checkform.areYouSure'); + }); + + // If it's warm enough, offer an iced coffee special. + $.getJSON("http://api.openweathermap.org/data/2.5/weather?q=Melbourne,AU&mode=json&units=metric&callback=?", + function(data) { + var temp = data.main.temp; + if (temp > 5) { + $('#example-4-special').append('<p>It\'s currently ' + + temp + 'C in Melbourne. Ice it up!</p>'); + $('#example-4-special').append('<input type="checkbox" name="make-it-iced" value="true" />' + + ' Make it an iced coffee<br />'); + + // Trigger rescan event on the form so we start tracking the new field. + $('#example-4-form').trigger('rescan.areYouSure'); + } + } + ); + + + /* + * Example 5 + * - extra shots button to enable/disable shots options + * - like/unlike button (changing hidden form field value) + * - hook dirty change event to enable/disable submit (using method), + * to more easily demonstrate when the form is dirty + */ + $('#example-5-extra-shots').click(function() { + // we trigger a change event on the fields so that the AreYouSure event handler is called + $('#example-5-form input[name=shots]').removeAttr('disabled').change(); + $('#example-5-extra-shots').hide(); + $('#example-5-shots-options').show(); + return false; + }); + $('#example-5-like-button').click(function() { + var currentLike = $('#example-5-like').val() == 'true'; + var newLike = !currentLike; + // we trigger a change event on the fields so that the areYouSure event handler is called + $('#example-5-like').val(newLike).change(); + $('#example-5-like-button').text(newLike ? 'Unlike' : 'Like'); + return false; + }); + $('#example-5-form').areYouSure({ + change: function() { + // Enable save button only if the form is dirty. + if ($(this).hasClass('dirty')) { + $(this).find('input[type="submit"]').removeAttr('disabled'); + } else { + $(this).find('input[type="submit"]').attr('disabled', 'disabled'); + } + } + }); + + // Example 6 - HTML5 input types + $('#example-6-form').areYouSure(); + + // Example 7 - ... in one line of code for the form and some more optional to toggle disabled state of the save button + $('#example-7-form').areYouSure(); + $('#example-7-save-button').click(function () { + $('#example-7-form').trigger('reinitialize.areYouSure'); + }); + // code below is optional to handle disabled state of the save button + $('#example-7-form').bind('dirty.areYouSure', function () { + // Enable save button only as the form is dirty. + $('#example-7-save-button').attr({ 'disabled': false }); + }); + $('#example-7-form').bind('clean.areYouSure', function () { + // Form is clean so nothing to save - disable the save button. + $('#example-7-save-button').attr({ 'disabled': true }); + }); + }); + + </script> + + <style type="text/css"> + body { + font-family: myriad-pro-1, myriad-pro-2, 'Lucida Grande', 'Arial', sans-serif; + margin: 25px; + } + + form { + width: 350px; + border: 1px solid #AA5303; + padding: 10px 20px; + background-image: -webkit-linear-gradient(top, rgba(170,83,3, 0.1), rgba(170,83,3, 0.5)); + background-image: -moz-linear-gradient(top, rgba(170,83,3, 0.1), rgba(170,83,3, 0.5)); + background-image: -ms-linear-gradient(top, rgba(170,83,3, 0.1), rgba(170,83,3, 0.5)); + background-image: -o-linear-gradient(top, rgba(170,83,3, 0.1), rgba(170,83,3, 0.5)); + background-image: linear-gradient(top, rgba(170,83,3, 0.1), rgba(170,83,3, 0.5)); + border-radius: 5px; + } + + /* A bit of custom styling on example 3 */ + #example-3-form.dirty, #example-4-form.dirty { + box-shadow: 0 0 8px rgba(255, 0, 0, 1); + -webkit-box-shadow: 0 0 8px rgba(255, 0, 0, 1); + -moz-box-shadow: 0 0 8px rgba(255, 0, 0, 1); + border:1px solid rgba(255,0,0, 0.8); + } + + form h2 { + font-size: 22px; + } + + form > div { + padding: 8px; + font-size: 12px; + } + form > div input[type="text"], + form > div input[type="color"], + form > div input[type="date"], + form > div input[type="datetime"], + form > div input[type="datetime-local"], + form > div input[type="email"], + form > div input[type="month"], + form > div input[type="number"], + form > div input[type="range"], + form > div input[type="search"], + form > div input[type="tel"], + form > div input[type="time"], + form > div input[type="url"], + form > div input[type="week"], + form > div input:not([type]), + form > div textarea, + form > div select, + form > div button { + float: right; + width: 200px; + } + + form > div input[type="radio"], + form > div input[type="checkbox"] { + display: inline-block; + margin-left: 130px; + } + + form > div input[type="submit"] { + float: right; + } + form > div.buttons { + clear: both; + padding-bottom: 20px; + } + </style> + </head> + + <body> + <h1>jQuery Plugin Demo: Are You Sure?</h1> + <p> + This page hosts a demo of the <a href="https://github.com/codedance/jquery.AreYouSure">jQuery Are-You-Sure</a> plugin (<code>jquery.are-you-sure.js</code>). + </p> + <p> + <i>Are-you-sure</i> is simple light-weight "dirty forms" JQuery Plugin for modern browsers. It helps prevent users from loosing unsaved form changes. + </p> + <p> + <strong>Features:</strong> + <ul> + <li>Light weight - only the features you need!</li> + <li>Dependency free.</li> + <li>Correct state management - if a user edits then restores a value, the form is not considered dirty.</li> + <li>Easy to understand - less than a "terminal screen" of code!</li> + <li>... and <a href="https://github.com/codedance/jquery.AreYouSure">more</a>.</li> + </ul> + </p> + + <h2>Example 1: It's simple!</h2> + <p> + This example shows how easy it is to add a dirty check to your form(s) with one line + of code. (View the page's source) + </p> + + <form id="example-1-form" name="coffeeOrder1" method="post"> + <h2>Enter Your Coffee Order</h2> + <div> + <label for="example-1-coffee">Coffee</label> + <select name="coffee" id="example-1-coffee"> + <option value="espresso">Espresso</option> + <option value="dbl-espresso">Caffe Doppio</option> + <option value="latte">Caffe Latte</option> + <option value="macciato">Machhiato</option> + <option value="cappuccino">Cappuccino</option> + </select> + </div> + <div> + <label>Shots</label><br /> + <input type="radio" name="shots" value="1" checked /> 1 Shot - Standard<br /> + <input type="radio" name="shots" value="2" /> 2 Shots - Morning wakeup!<br /> + <input type="radio" name="shots" value="3" /> 3 Shots - Overdrive!<br /> + </div> + <div> + <label for="example-1-sugar">Sugar</label> <input type="text" name="sugar" value="0" id="example-1-sugar" /> + </div> + <div> + <label for="example-1-instructions">Special Instructions</label> + <textarea name="instructions" rows="5" id="example-1-instructions"></textarea> + </div> + + <div class="buttons"> + <input type="checkbox" name="remember" value="true" /> Remember my order<br /> + <input type="submit" value="Submit"> + <input type="reset" value="Reset"> + </div> + <div> + <p>... or visit <a href="http://www.google.com/">Google</a> or close the window without saving!</p> + </div> + </form> + + <h2>Example 2: Ignore the unimportant!</h2> + <p> + This example highlights how to disregard a field from the dirty check. In this form + the first field is dynamically populated and hence a change on this field should <em>not</em> + mark the form as dirty. + </p> + <form id="example-2-form" name="coffeeOrder2" method="post"> + <h2>Enter Your Coffee Order</h2> + <div> + <!-- The ays-ignore class means a change on this field is not considered "dirty" --> + <label for="pickup">Pickup Time</label> + <input class="ays-ignore" type="text" name="pickup" id="pickup" /> + <!-- or you can use a data attribute like this: + <label for="pickup">Pickup Time</label> <input data-ays-ignore="true" type="text" name="pickup" id="pickup" /> + --> + </div> + <div> + <label for="example-2-coffee">Coffee</label> + <select name="coffee" id="example-2-coffee"> + <option value="espresso">Espresso</option> + <option value="dbl-espresso">Caffe Doppio</option> + <option value="latte">Caffe Latte</option> + <option value="macciato">Machhiato</option> + <option value="cappuccino">Cappuccino</option> + </select> + </div> + <div> + <label>Shots</label><br /> + <input type="radio" name="shots" value="1" checked /> 1 Shot - Standard<br /> + <input type="radio" name="shots" value="2" /> 2 Shots - Morning wakeup!<br /> + <input type="radio" name="shots" value="3" /> 3 Shots - Overdrive!<br /> + </div> + <div> + <label for="example-2-sugar">Sugar</label> <input type="text" name="sugar" value="0" id="example-2-sugar" /> + </div> + <div> + <label for="example-2-instructions">Special Instructions</label> + <textarea name="instructions" rows="5" id="example-2-instructions"></textarea> + </div> + + <div class="buttons"> + <input type="checkbox" name="remember" value="true" /> Remember my order<br /> + <input type="submit" value="Submit"> + </div> + <div> + <p>... or visit <a href="http://www.google.com/">Google</a> or close the window without saving!</p> + </div> + </form> + + + <h2>Example 3: Lets be intelligent!</h2> + <p> + This is a more advanced example. The <code>dirty</code> and <code>clean</code> change events are + intercepted so the save button is only enabled if the form is dirty (i.e. something to save). + It also demonstrates how to customize the warning message and change the style of a dirty + form (CSS styling using the <code>.dirty</code> class). + </p> + <form id="example-3-form" name="coffeeOrder3" method="post"> + <h2>Update My Standard Order</h2> + <div> + <label for="example-3-coffee">Coffee</label> + <select name="coffee" id="example-3-coffee"> + <option value=""></option> + <option value="cappuccino">Cappuccino</option> + <option value="espresso">Espresso</option> + <option value="dbl-espresso">Caffe Doppio</option> + <option value="latte">Caffe Latte</option> + <option value="macciato">Machhiato</option> + </select> + </div> + <div> + <label>Shots</label><br /> + <input type="radio" name="shots" value="1" /> 1 Shot - Standard<br /> + <input type="radio" name="shots" value="2" checked /> 2 Shots - Morning wakeup!<br /> + <input type="radio" name="shots" value="3" /> 3 Shots - Overdrive!<br /> + </div> + <div> + <label for="example-3-sugar">Sugar</label> + <input type="text" name="sugar" value="1" id="example-3-sugar" /> + </div> + <div> + <label for="example-3-instructions">Special Instructions</label> + <textarea name="instructions" rows="5" id="example-3-instructions">No chocolate please</textarea> + </div> + + <div class="buttons"> + <input type="submit" value="Save" disabled="disabled"> + </div> + <div> + <p>... or visit <a href="http://www.google.com/">Google</a> or close the window without saving!</p> + </div> + </form> + + <h2>Example 4: Lets be dynamic!</h2> + <p> + In this example we'll dymaically add a field and fire off the <code>rescan</code> event. After + the rescan, Are-You-Sure will start looking for changes on the new fields as well. + </p> + <form id="example-4-form" name="coffeeOrder4" method="post"> + <h2>Order Coffee For Pickup Now</h2> + <div> + <a id="example-4-lastorder" href="javascript:void(0);">Set my preferences from my last order</a><br /> + </div> + <div> + <label for="example-4-coffee">Coffee</label> + <select name="coffee" id="example-4-coffee"> + <option value="cappuccino">Cappuccino</option> + <option value="espresso">Espresso</option> + <option value="dbl-espresso">Caffe Doppio</option> + <option value="latte">Caffe Latte</option> + </select> + </div> + <div id="example-4-special"></div> + <div class="buttons"> + <input type="submit" value="Place Order"> + </div> + <div> + <p>... or visit <a href="http://www.google.com/">Google</a> or close the window without saving!</p> + </div> + </form> + + <h2>Example 5: Edge cases</h2> + <p> + This example demonstrates tracking of hidden and disabled form elements that are changed by non-input elements. + E.g.: + </p> + <ul> + <li>clicking a link or non-input button that changes the value of a hidden form field, or</li> + <li> + clicking a link or non-input button that enables or disables some form fields (which has an effect on whether + or not those fields will be submitted with the form, despite the values not changing). + </li> + </ul> + <form id="example-5-form" name="coffeeOrder5" method="post"> + <h2>Update My Standard Order</h2> + <div> + <label for="example-5-coffee">Coffee</label> + <select name="coffee" id="example-3-coffee"> + <option value="cappuccino">Cappuccino</option> + <option value="espresso">Espresso</option> + <option value="dbl-espresso">Caffe Doppio</option> + <option value="latte">Caffe Latte</option> + <option value="macciato">Machhiato</option> + </select> + </div> + <div> + <label>Shots</label> + <!-- + The visually hidden "shots" radio buttons are disabled and would not normally be submitted with the form. + Clicking the following button will visually show and enable these buttons, resulting in a form state change + (and hence the form is considered dirty) without the values having changed. + --> + <button id="example-5-extra-shots">I want extra shots</button> + <div id="example-5-shots-options" style="display: none;"> + <input type="radio" name="shots" value="1" disabled /> 1 Shot - Standard<br /> + <input type="radio" name="shots" value="2" disabled /> 2 Shots - Morning wakeup!<br /> + <input type="radio" name="shots" value="3" disabled /> 3 Shots - Overdrive!<br /> + </div> + </div> + <div> + <label>Do you like us?</label> + <input type="hidden" name="like" value="false" id="example-5-like" /> + <button id="example-5-like-button">Like</button> + </div> + <div class="buttons"> + <input type="submit" value="Save" disabled="disabled"> + </div> + <div> + <p>... or visit <a href="http://www.google.com/">Google</a> or close the window without saving!</p> + </div> + </form> + + <h2>Example 6: HTML5 inputs!</h2> + <p> + This example shows support for HTML5 input types. It's not a coffee order form, + but you need coffee if you're working with HTML5 :-) + </p> + + <form id="example-6-form" name="coffeeOrder6" method="post"> + <h2>Doing HTML5? You'll need coffee!</h2> + <div> + <label for="example-6-color">color</label> + <input type="color" name="example-6-color" /> + </div> + <div> + <label for="example-6-date">date</label> + <input type="date" name="example-6-date" /> + </div> + <div> + <label for="example-6-datetime">datetime</label> + <input type="datetime" name="example-6-datetime" /> + </div> + <div> + <label for="example-6-datetime-local">datetime-local</label> + <input type="datetime-local" name="example-6-datetime-local" /> + </div> + <div> + <label for="example-6-email">email</label> + <input type="email" name="example-6-email" /> + </div> + <div> + <label for="example-6-month">month</label> + <input type="month" name="example-6-month" /> + </div> + <div> + <label for="example-6-number">number</label> + <input type="number" name="example-6-number" /> + </div> + <div> + <label for="example-6-range">range</label> + <input type="range" name="example-6-range" /> + </div> + <div> + <label for="example-6-search">search</label> + <input type="search" name="example-6-search" /> + </div> + <div> + <label for="example-6-tel">tel</label> + <input type="tel" name="example-6-tel" /> + </div> + <div> + <label for="example-6-time">time</label> + <input type="time" name="example-6-time" /> + </div> + <div> + <label for="example-6-url">url</label> + <input type="url" name="example-6-url" /> + </div> + <div> + <label for="example-6-week">week</label> + <input type="week" name="example-6-week" /> + </div> + <div> + <label for="example-6-select">select/optgroup</label> + <select> + <optgroup label="Beans"> + <option value="india">India</option> + <option value="indonesia" selected="selected">Indonesia</option> + <option value="brazil">Brazil</option> + </optgroup> + <optgroup label="Roast"> + <option value="l">Light</option> + <option value="m">Medium</option> + <option value="h">Heavy</option> + </optgroup> + </select> + </div> + <div> + <label for="example-6-mselect">multi select</label> + <select multiple> + <option value="arabica">Arabica</option> + <option value="arabica">Peaberry</option> + <option value="malabar " selected="selected">Malabar</option> + <option value="robusta ">Robusta</option> + </select> + </div> + <div style="clear:both;"></div> + <div> + <label for="example-6-plain">plain old field</label> + <input name="example-6-plain" /> + </div> + + <div class="buttons"> + <input type="submit" value="Submit"> + <input type="reset" value="Reset"> + </div> + <div> + <p>... or visit <a href="http://www.google.com/">Google</a> or close the window without saving!</p> + </div> + </form> + <h2>Example 7: Mark current state as not dirty!</h2> + <p> + This example shows how you can mark the current state as not dirty. Handy for AJAX forms + we're you're managing your own submits. + </p> + + <form id="example-7-form" name="coffeeOrder7" method="post"> + <h2>Tell us your default coffee</h2> + <div> + <label for="example-7-coffee">Default coffee</label> + <select name="coffee" id="example-7-coffee"> + <option value="espresso">Espresso</option> + <option value="dbl-espresso">Caffe Doppio</option> + <option value="latte">Caffe Latte</option> + <option value="macciato">Machhiato</option> + <option value="cappuccino">Cappuccino</option> + </select> + </div> + <div> + <button id="example-7-save-button" disabled="disabled">Save without submit</button> + </div> + <div class="buttons"> + <input type="submit" value="Submit"> + </div> + <div> + <p>... or visit <a href="http://www.google.com/">Google</a> or close the window without saving!</p> + </div> + </form> + + <p> + This jQuery plugin is developed by <a href="https://github.com/codedance">Chris Dance</a> + at <a href="http://www.papercut.com/">PaperCut Software</a> - Are-You-Sure is used in + PaperCut's printing management software and it has been open sourced with help of + Tom, Jack and Matt from PaperCut's dev team. + </p> + + </body> +</html> diff --git a/library/jquery.AreYouSure/jquery.are-you-sure.js b/library/jquery.AreYouSure/jquery.are-you-sure.js new file mode 100644 index 000000000..3c41e2fcc --- /dev/null +++ b/library/jquery.AreYouSure/jquery.are-you-sure.js @@ -0,0 +1,192 @@ +/*! + * jQuery Plugin: Are-You-Sure (Dirty Form Detection) + * https://github.com/codedance/jquery.AreYouSure/ + * + * Copyright (c) 2012-2014, Chris Dance and PaperCut Software http://www.papercut.com/ + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * Author: chris.dance@papercut.com + * Version: 1.9.0 + * Date: 13th August 2014 + */ +(function($) { + + $.fn.areYouSure = function(options) { + + var settings = $.extend( + { + 'message' : 'You have unsaved changes!', + 'dirtyClass' : 'dirty', + 'change' : null, + 'silent' : false, + 'addRemoveFieldsMarksDirty' : false, + 'fieldEvents' : 'change keyup propertychange input', + 'fieldSelector': ":input:not(input[type=submit]):not(input[type=button])" + }, options); + + var getValue = function($field) { + if ($field.hasClass('ays-ignore') + || $field.hasClass('aysIgnore') + || $field.attr('data-ays-ignore') + || $field.attr('name') === undefined) { + return null; + } + + if ($field.is(':disabled')) { + return 'ays-disabled'; + } + + var val; + var type = $field.attr('type'); + if ($field.is('select')) { + type = 'select'; + } + + switch (type) { + case 'checkbox': + case 'radio': + val = $field.is(':checked'); + break; + case 'select': + val = ''; + $field.find('option').each(function(o) { + var $option = $(this); + if ($option.is(':selected')) { + val += $option.val(); + } + }); + break; + default: + val = $field.val(); + } + + return val; + }; + + var storeOrigValue = function($field) { + $field.data('ays-orig', getValue($field)); + }; + + var checkForm = function(evt) { + + var isFieldDirty = function($field) { + var origValue = $field.data('ays-orig'); + if (undefined === origValue) { + return false; + } + return (getValue($field) != origValue); + }; + + var $form = ($(this).is('form')) + ? $(this) + : $(this).parents('form'); + + // Test on the target first as it's the most likely to be dirty + if (isFieldDirty($(evt.target))) { + setDirtyStatus($form, true); + return; + } + + $fields = $form.find(settings.fieldSelector); + + if (settings.addRemoveFieldsMarksDirty) { + // Check if field count has changed + var origCount = $form.data("ays-orig-field-count"); + if (origCount != $fields.length) { + setDirtyStatus($form, true); + return; + } + } + + // Brute force - check each field + var isDirty = false; + $fields.each(function() { + $field = $(this); + if (isFieldDirty($field)) { + isDirty = true; + return false; // break + } + }); + + setDirtyStatus($form, isDirty); + }; + + var initForm = function($form) { + var fields = $form.find(settings.fieldSelector); + $(fields).each(function() { storeOrigValue($(this)); }); + $(fields).unbind(settings.fieldEvents, checkForm); + $(fields).bind(settings.fieldEvents, checkForm); + $form.data("ays-orig-field-count", $(fields).length); + setDirtyStatus($form, false); + }; + + var setDirtyStatus = function($form, isDirty) { + var changed = isDirty != $form.hasClass(settings.dirtyClass); + $form.toggleClass(settings.dirtyClass, isDirty); + + // Fire change event if required + if (changed) { + if (settings.change) settings.change.call($form, $form); + + if (isDirty) $form.trigger('dirty.areYouSure', [$form]); + if (!isDirty) $form.trigger('clean.areYouSure', [$form]); + $form.trigger('change.areYouSure', [$form]); + } + }; + + var rescan = function() { + var $form = $(this); + var fields = $form.find(settings.fieldSelector); + $(fields).each(function() { + var $field = $(this); + if (!$field.data('ays-orig')) { + storeOrigValue($field); + $field.bind(settings.fieldEvents, checkForm); + } + }); + // Check for changes while we're here + $form.trigger('checkform.areYouSure'); + }; + + var reinitialize = function() { + initForm($(this)); + } + + if (!settings.silent && !window.aysUnloadSet) { + window.aysUnloadSet = true; + $(window).bind('beforeunload', function() { + $dirtyForms = $("form").filter('.' + settings.dirtyClass); + if ($dirtyForms.length == 0) { + return; + } + // Prevent multiple prompts - seen on Chrome and IE + if (navigator.userAgent.toLowerCase().match(/msie|chrome/)) { + if (window.aysHasPrompted) { + return; + } + window.aysHasPrompted = true; + window.setTimeout(function() {window.aysHasPrompted = false;}, 900); + } + return settings.message; + }); + } + + return this.each(function(elem) { + if (!$(this).is('form')) { + return; + } + var $form = $(this); + + $form.submit(function() { + $form.removeClass(settings.dirtyClass); + }); + $form.bind('reset', function() { setDirtyStatus($form, false); }); + // Add a custom events + $form.bind('rescan.areYouSure', rescan); + $form.bind('reinitialize.areYouSure', reinitialize); + $form.bind('checkform.areYouSure', checkForm); + initForm($form); + }); + }; +})(jQuery); diff --git a/library/jquery.AreYouSure/package.json b/library/jquery.AreYouSure/package.json new file mode 100644 index 000000000..0b4c38dde --- /dev/null +++ b/library/jquery.AreYouSure/package.json @@ -0,0 +1,45 @@ +{ + "name": "jquery.AreYouSure", + "description": "A light-weight jQuery \"dirty forms\" Plugin - it monitors HTML forms and alerts users to unsaved changes if they attempt to close the browser or navigate away from the page. (Are you sure?)", + "homepage": "https://github.com/codedance/jquery.AreYouSure", + "author": "Chris Dance <chris.dance@papercut.com> (https://github.com/codedance)", + "contributors": [ + "Tom Clift <tom.clift@papercut.com> (https://github.com/tclift)", + "Jon Egerton <jon@ja2.co.uk> (http://www.jonegerton.com/)", + "Scadoodles (https://github.com/Scadoodles)", + "Albin Sunnanbo (https://github.com/albinsunnanbo)", + "Marc Sutton <ashre@iname.com> (http://www.codev.co.uk)" + ], + "version": "1.9.0", + "license": "MIT/GPLv2", + "keywords": [ "dirty", "form", "onbeforeunload", "save", "check" ], + "main": "jquery.are-you-sure.js", + "engines": { + "node": ">=0.8.0" + }, + "repository": { + "type": "git", + "url": "https://github.com/codedance/jquery.AreYouSure" + }, + "bugs": { + "url": "https://github.com/codedance/jquery.AreYouSure/issues" + }, + "dependencies": { + "jquery": ">=1.4.2" + }, + "devDependencies": { + "bower": "^1.3.1", + "grunt": "^0.4.5", + "grunt-cli": "^0.1.13", + "grunt-karma": "^0.8.3", + "karma-chrome-launcher": "^0.1.4", + "karma-jasmine": "^0.2.2", + "karma-ie-launcher": "^0.1.5", + "karma-firefox-launcher": "^0.1.3", + "karma-safari-launcher": "^0.1.1" + }, + "scripts": { + "postinstall": "node_modules/.bin/bower install", + "test": "node_modules/.bin/grunt test" + } +} diff --git a/library/jquery.AreYouSure/spec/javascripts/fixtures/input-text.html b/library/jquery.AreYouSure/spec/javascripts/fixtures/input-text.html new file mode 100644 index 000000000..1b2850759 --- /dev/null +++ b/library/jquery.AreYouSure/spec/javascripts/fixtures/input-text.html @@ -0,0 +1,4 @@ +<form> + <input type="text" name="a"> + <input type="submit"> +</form> diff --git a/library/jquery.AreYouSure/spec/javascripts/jquery.are-you-sure_spec.js b/library/jquery.AreYouSure/spec/javascripts/jquery.are-you-sure_spec.js new file mode 100644 index 000000000..5e02f7cb0 --- /dev/null +++ b/library/jquery.AreYouSure/spec/javascripts/jquery.are-you-sure_spec.js @@ -0,0 +1,28 @@ +'use strict'; + +// Karma adds 'base/' to the default path +jasmine.getFixtures().fixturesPath = 'base/spec/javascripts/fixtures'; + +describe("A form's", function() { + var $form = undefined; + + describe('text input', function() { + var $textInput = undefined; + + beforeEach(function() { + loadFixtures('input-text.html'); + $form = $('form'); + $textInput = $('input[type=text]'); + $form.areYouSure(); + }); + + it('should cause dirtyness after its value changes', function(done) { + expect($form.hasClass('dirty')).toBe(false); + $textInput.val('new').change(); + setTimeout(function() { + expect($form.hasClass('dirty')).toBe(true); + done(); + }, 0); + }); + }); +}); |