Warn about unsaved settings using jquery.areyousure

This commit is contained in:
Stefan Parviainen 2015-01-01 12:32:15 +01:00
parent 93b9470487
commit 9557908875
15 changed files with 1442 additions and 0 deletions

166
library/jquery.AreYouSure/.gitignore vendored Normal file
View file

@ -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/

View file

@ -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');
};

View file

@ -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

View file

@ -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"
}
}

View file

@ -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;
}
});
});

View file

@ -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"
}
}

View file

@ -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>

View file

@ -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);

View file

@ -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"
}
}

View file

@ -0,0 +1,4 @@
<form>
<input type="text" name="a">
<input type="submit">
</form>

View file

@ -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);
});
});
});

3
view/js/mod_admin.js Normal file
View file

@ -0,0 +1,3 @@
$(document).ready(function() {
$('form').areYouSure(); // Warn user about unsaved settings
});

3
view/js/mod_profiles.js Normal file
View file

@ -0,0 +1,3 @@
$(document).ready(function() {
$('form').areYouSure(); // Warn user about unsaved settings
});

View file

@ -2,6 +2,7 @@
var ispublic = aStr['everybody'] ;
$(document).ready(function() {
$('form').areYouSure(); // Warn user about unsaved settings
$("a#settings-default-perms-menu").colorbox({
'inline' : true,

View file

@ -44,6 +44,7 @@ head_add_js('docready.js');
head_add_js('library/colorbox/jquery.colorbox-min.js');
head_add_js('library/bootstrap-tagsinput/bootstrap-tagsinput.js');
head_add_js('library/jquery.AreYouSure/jquery.are-you-sure.js');
/**
* Those who require this feature will know what to do with it.
* Those who don't, won't.