pax_global_header 0000666 0000000 0000000 00000000064 12755631514 0014523 g ustar 00root root 0000000 0000000 52 comment=a4da3b4909b2ca081de3c6f99064403623bfe1fb jquery-ujs-1.2.2/ 0000775 0000000 0000000 00000000000 12755631514 0013643 5 ustar 00root root 0000000 0000000 jquery-ujs-1.2.2/.gitignore 0000664 0000000 0000000 00000000117 12755631514 0015632 0 ustar 00root root 0000000 0000000 test/public/vendor/jquery.js node_modules *.swp *.swo .#* .bundle .DS_Store *~ jquery-ujs-1.2.2/.jshintrc 0000664 0000000 0000000 00000011561 12755631514 0015474 0 ustar 00root root 0000000 0000000 { "maxerr" : 50, // {int} Maximum error before stopping // Enforcing "bitwise" : true, // true: Prohibit bitwise operators (&, |, ^, etc.) "camelcase" : true, // true: Identifiers must be in camelCase "curly" : false, // true: Require {} for every new block or scope "eqeqeq" : true, // true: Require triple equals (===) for comparison "forin" : true, // true: Require filtering for..in loops with obj.hasOwnProperty() "freeze" : true, // true: prohibits overwriting prototypes of native objects such as Array, Date etc. "immed" : false, // true: Require immediate invocations to be wrapped in parens e.g. `(function () { } ());` "indent" : 2, // {int} Number of spaces to use for indentation "latedef" : false, // true: Require variables/functions to be defined before being used "newcap" : false, // true: Require capitalization of all constructor functions e.g. `new F()` "noarg" : true, // true: Prohibit use of `arguments.caller` and `arguments.callee` "noempty" : true, // true: Prohibit use of empty blocks "nonbsp" : true, // true: Prohibit "non-breaking whitespace" characters. "nonew" : false, // true: Prohibit use of constructors for side-effects (without assignment) "plusplus" : false, // true: Prohibit use of `++` & `--` "quotmark" : "single", // Quotation mark consistency: // false : do nothing (default) // true : ensure whatever is used is consistent // "single" : require single quotes // "double" : require double quotes "undef" : true, // true: Require all non-global variables to be declared (prevents global leaks) "unused" : true, // Unused variables: // true : all variables, last function parameter // "vars" : all variables only // "strict" : all variables, all function parameters "strict" : true, // true: Requires all functions run in ES5 Strict Mode "maxparams" : false, // {int} Max number of formal params allowed per function "maxdepth" : false, // {int} Max depth of nested blocks (within functions) "maxstatements" : false, // {int} Max number statements per function "maxcomplexity" : false, // {int} Max cyclomatic complexity per function "maxlen" : false, // {int} Max number of characters per line // Relaxing "asi" : false, // true: Tolerate Automatic Semicolon Insertion (no semicolons) "boss" : false, // true: Tolerate assignments where comparisons would be expected "debug" : false, // true: Allow debugger statements e.g. browser breakpoints. "eqnull" : false, // true: Tolerate use of `== null` "es5" : false, // true: Allow ES5 syntax (ex: getters and setters) "esnext" : false, // true: Allow ES.next (ES6) syntax (ex: `const`) "moz" : false, // true: Allow Mozilla specific syntax (extends and overrides esnext features) // (ex: `for each`, multiple try/catch, function expression…) "evil" : false, // true: Tolerate use of `eval` and `new Function()` "expr" : false, // true: Tolerate `ExpressionStatement` as Programs "funcscope" : false, // true: Tolerate defining variables inside control statements "globalstrict" : false, // true: Allow global "use strict" (also enables 'strict') "iterator" : false, // true: Tolerate using the `__iterator__` property "lastsemic" : false, // true: Tolerate omitting a semicolon for the last statement of a 1-line block "laxbreak" : false, // true: Tolerate possibly unsafe line breakings "laxcomma" : false, // true: Tolerate comma-first style coding "loopfunc" : false, // true: Tolerate functions being defined in loops "multistr" : false, // true: Tolerate multi-line strings "noyield" : false, // true: Tolerate generator functions with no yield statement in them. "notypeof" : false, // true: Tolerate invalid typeof operator values "proto" : false, // true: Tolerate using the `__proto__` property "scripturl" : false, // true: Tolerate script-targeted URLs "shadow" : false, // true: Allows re-define variables later in code e.g. `var x=1; x=2;` "sub" : false, // true: Tolerate using `[]` notation when it can still be expressed in dot notation "supernew" : false, // true: Tolerate `new function () { ... };` and `new Object;` "validthis" : false, // true: Tolerate using this in a non-constructor function // Environments "browser" : true, // Web Browser (window, document, etc) "jquery" : true, "devel" : true, // Development/debugging (alert, confirm, etc) "globals" : {} } jquery-ujs-1.2.2/.npmignore 0000664 0000000 0000000 00000000040 12755631514 0015634 0 ustar 00root root 0000000 0000000 script/ test/ Rakefile Gemfile* jquery-ujs-1.2.2/.travis.yml 0000664 0000000 0000000 00000001217 12755631514 0015755 0 ustar 00root root 0000000 0000000 language: ruby sudo: false cache: - bundler - directories: - $HOME/.npm script: ./script/cibuild before_install: - "npm install jshint -g" env: - JQUERY_VERSION: 1.8.0 - JQUERY_VERSION: 1.8.1 - JQUERY_VERSION: 1.8.2 - JQUERY_VERSION: 1.8.3 - JQUERY_VERSION: 1.9.0 - JQUERY_VERSION: 1.9.1 - JQUERY_VERSION: 1.10.0 - JQUERY_VERSION: 1.10.1 - JQUERY_VERSION: 1.10.2 - JQUERY_VERSION: 1.11.0 - JQUERY_VERSION: 1.11.1 - JQUERY_VERSION: 1.11.2 - JQUERY_VERSION: 1.12.0 - JQUERY_VERSION: 2.0.0 - JQUERY_VERSION: 2.1.0 - JQUERY_VERSION: 2.1.1 - JQUERY_VERSION: 2.1.2 - JQUERY_VERSION: 2.1.3 - JQUERY_VERSION: 2.2.0 jquery-ujs-1.2.2/CONTRIBUTING.md 0000664 0000000 0000000 00000006517 12755631514 0016105 0 ustar 00root root 0000000 0000000 Contributing to jquery-ujs ===================== [](https://travis-ci.org/rails/jquery-ujs) jquery-ujs is work of [many contributors](https://github.com/rails/jquery-ujs/graphs/contributors). You're encouraged to submit [pull requests](https://github.com/rails/jquery-ujs/pulls), [propose features and discuss issues](https://github.com/rails/jquery-ujs/issues). #### Fork the Project Fork the [project on Github](https://github.com/rails/jquery-ujs) and check out your copy. ``` git clone https://github.com/contributor/jquery-ujs.git cd jquery-ujs git remote add upstream https://github.com/rails/jquery-ujs.git ``` #### Create a Topic Branch Make sure your fork is up-to-date and create a topic branch for your feature or bug fix. ``` git checkout master git pull upstream master git checkout -b my-feature-branch ``` #### Bundle Install and Test Ensure that you can build the project and run tests. Run `rake test:server` first, and then run the web tests by visiting [[http://localhost:4567]] in your browser. Click the version links at the top right of the page to run the test suite with the different supported versions of jQuery. ``` bundle install rake test:server ``` #### Write Tests Try to write a test that reproduces the problem you're trying to fix or describes a feature that you want to build. Add to [test](test). Here are some additional notes to keep in mind when developing your patch for jquery-ujs. * The tests can be found in: ``` |~test |~public |~test ``` * Some tests ensure consistent behavior across the major browsers, meaning it is possible for tests to pass in Firefox, but fail in Internet Explorer. If possible, it helps if you can run the test suite in multiple browsers before submitting patches. We definitely appreciate pull requests that highlight or reproduce a problem, even without a fix. #### Write Code Implement your feature or bug fix. Make sure that `bundle exec rake test` completes without errors. #### Write Documentation Document any external behavior in the [README](README.md). #### Commit Changes Make sure git knows your name and email address: ``` git config --global user.name "Your Name" git config --global user.email "contributor@example.com" ``` Writing good commit logs is important. A commit log should describe what changed and why. ``` git add ... git commit ``` #### Push ``` git push origin my-feature-branch ``` #### Make a Pull Request Go to https://github.com/contributor/jquery-ujs and select your feature branch. Click the 'Pull Request' button and fill out the form. Pull requests are usually reviewed within a few days. #### Rebase If you've been working on a change for a while, rebase with upstream/master. ``` git fetch upstream git rebase upstream/master git push origin my-feature-branch -f ``` #### Check on Your Pull Request Go back to your pull request after a few minutes and see whether it passed muster with Travis-CI. Everything should look green, otherwise fix issues and amend your commit as described above. #### Be Patient It's likely that your change will not be merged and that the nitpicky maintainers will ask you to do more, or fix seemingly benign problems. Hang on there! #### Thank You Please do know that we really appreciate and value your time and work. We love you, really. jquery-ujs-1.2.2/Gemfile 0000664 0000000 0000000 00000000211 12755631514 0015130 0 ustar 00root root 0000000 0000000 source 'https://rubygems.org' gem 'sinatra', '~> 1.0' gem 'shotgun', :group => :reloadable gem 'thin', :group => :reloadable gem 'rake' jquery-ujs-1.2.2/Gemfile.lock 0000664 0000000 0000000 00000000755 12755631514 0016074 0 ustar 00root root 0000000 0000000 GEM remote: https://rubygems.org/ specs: daemons (1.1.9) eventmachine (1.0.4) rack (1.6.0) rack-protection (1.5.3) rack rake (10.4.2) shotgun (0.9) rack (>= 1.0) sinatra (1.4.5) rack (~> 1.4) rack-protection (~> 1.4) tilt (~> 1.3, >= 1.3.4) thin (1.6.3) daemons (~> 1.0, >= 1.0.9) eventmachine (~> 1.0) rack (~> 1.0) tilt (1.4.1) PLATFORMS ruby DEPENDENCIES rake shotgun sinatra (~> 1.0) thin jquery-ujs-1.2.2/MIT-LICENSE 0000664 0000000 0000000 00000002130 12755631514 0015273 0 ustar 00root root 0000000 0000000 Copyright (c) 2007-2016 Contributors at http://github.com/rails/jquery-ujs/contributors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. jquery-ujs-1.2.2/README.md 0000664 0000000 0000000 00000005265 12755631514 0015132 0 ustar 00root root 0000000 0000000 Unobtrusive scripting adapter for jQuery ======================================== This unobtrusive scripting support file is developed for the Ruby on Rails framework, but is not strictly tied to any specific backend. You can drop this into any application to: - force confirmation dialogs for various actions; - make non-GET requests from hyperlinks; - make forms or hyperlinks submit data asynchronously with Ajax; - have submit buttons become automatically disabled on form submit to prevent double-clicking. These features are achieved by adding certain ["data" attributes][data] to your HTML markup. In Rails, they are added by the framework's template helpers. Full [documentation is on the wiki][wiki], including the [list of published Ajax events][events]. Requirements ------------ - [jQuery 1.8.x or higher][jquery]; - HTML5 doctype (optional). If you don't use HTML5, adding "data" attributes to your HTML4 or XHTML pages might make them fail [W3C markup validation][validator]. However, this shouldn't create any issues for web browsers or other user agents. Installation using the jquery-rails gem ------------ For automated installation in Rails, use the "jquery-rails" gem. Place this in your Gemfile: ```ruby gem 'jquery-rails' ``` And run: ```shell $ bundle install ``` Require both `jquery` and `jquery_ujs` into your application.js manifest. ```javascript //= require jquery //= require jquery_ujs ``` Installation using npm. ------------ Run `npm install --save jquery-ujs` to install the jquery-ujs package. Installation using Bower ------------ Run `bower install jquery-ujs --save` to install the jquery-ujs package. Usage ------------ Require both `jquery` and `jquery-ujs` into your application.js manifest. ```javascript //= require jquery //= require jquery-ujs ``` How to run tests ------------ Follow [this wiki](https://github.com/rails/jquery-ujs/wiki/Running-Tests-and-Contributing) to run tests. ## Contributing to jquery-ujs jquery-ujs is work of many contributors. You're encouraged to submit pull requests, propose features and discuss issues. See [CONTRIBUTING](CONTRIBUTING.md). ## License jquery-ujs is released under the [MIT License](MIT-LICENSE). [data]: http://www.w3.org/TR/html5/dom.html#embedding-custom-non-visible-data-with-the-data-*-attributes "Embedding custom non-visible data with the data-* attributes" [wiki]: https://github.com/rails/jquery-ujs/wiki [events]: https://github.com/rails/jquery-ujs/wiki/ajax [jquery]: http://docs.jquery.com/Downloading_jQuery [validator]: http://validator.w3.org/ [csrf]: http://api.rubyonrails.org/classes/ActionController/RequestForgeryProtection.html [adapter]: https://github.com/rails/jquery-ujs/raw/master/src/rails.js jquery-ujs-1.2.2/RELEASE.md 0000664 0000000 0000000 00000000671 12755631514 0015251 0 ustar 00root root 0000000 0000000 ## Releasing jquery-ujs ### Releasing to npm Make sure npm's configuration `sign-git-tag` is set to true. ``` npm config set sign-git-tag true ``` Release it to npm using the [npm version command](https://docs.npmjs.com/cli/version). Like: ``` npm version patch ``` This will: * Bump a patch version * Commit the change * Generate the tag * Push the commit and the tag to the repository * Publish the package in https://www.npmjs.com jquery-ujs-1.2.2/Rakefile 0000664 0000000 0000000 00000002444 12755631514 0015314 0 ustar 00root root 0000000 0000000 desc %(Starts the test server and opens it in a web browser) multitask :default => ['test:server', 'test:open'] PORT = 4567 namespace :test do desc %(Starts the test server) task :server do system 'bundle exec ruby test/server.rb' end desc %(Starts the test server which reloads everything on each refresh) task :reloadable do exec "bundle exec shotgun test/config.ru -p #{PORT} --server thin" end task :open do url = "http://localhost:#{PORT}" puts "Opening test app at #{url} ..." sleep 3 system( *browse_cmd(url) ) end end # Returns an array e.g.: ['open', 'http://example.com'] def browse_cmd(url) require 'rbconfig' browser = ENV['BROWSER'] || (RbConfig::CONFIG['host_os'].include?('darwin') && 'open') || (RbConfig::CONFIG['host_os'] =~ /msdos|mswin|djgpp|mingw|windows/ && 'start') || %w[xdg-open x-www-browser firefox opera mozilla netscape].find { |comm| which comm } abort('ERROR: no web browser detected') unless browser Array(browser) << url end # which('ruby') #=> /usr/bin/ruby def which cmd exts = ENV['PATHEXT'] ? ENV['PATHEXT'].split(';') : [''] ENV['PATH'].split(File::PATH_SEPARATOR).each do |path| exts.each { |ext| exe = "#{path}/#{cmd}#{ext}" return exe if File.executable? exe } end return nil end jquery-ujs-1.2.2/bower.json 0000664 0000000 0000000 00000000641 12755631514 0015655 0 ustar 00root root 0000000 0000000 { "name": "jquery-ujs", "homepage": "https://github.com/rails/jquery-ujs", "authors": ["Stephen St. Martin", "Steve Schwartz"], "description": "Ruby on Rails unobtrusive scripting adapter for jQuery", "main": "src/rails.js", "license": "MIT", "dependencies": { "jquery": ">1.8.*" }, "ignore": [ "**/.*", "Gemfile*", "Rakefile", "bower_components", "script", "test" ] } jquery-ujs-1.2.2/package.json 0000664 0000000 0000000 00000001277 12755631514 0016140 0 ustar 00root root 0000000 0000000 { "name": "jquery-ujs", "version": "1.2.2", "description": "Unobtrusive scripting adapter for jQuery", "main": "src/rails.js", "scripts": { "test": "echo \"See the wiki: https://github.com/rails/jquery-ujs/wiki/Running-Tests-and-Contributing\" && exit 1", "postversion": "git push && git push --tags && npm publish" }, "repository": { "type": "git", "url": "https://github.com/rails/jquery-ujs.git" }, "author": [ "Stephen St. Martin", "Steve Schwartz" ], "license": "MIT", "bugs": { "url": "https://github.com/rails/jquery-ujs/issues" }, "homepage": "https://github.com/rails/jquery-ujs#readme", "dependencies": { "jquery": ">=1.8.0" } } jquery-ujs-1.2.2/script/ 0000775 0000000 0000000 00000000000 12755631514 0015147 5 ustar 00root root 0000000 0000000 jquery-ujs-1.2.2/script/cibuild 0000775 0000000 0000000 00000001153 12755631514 0016510 0 ustar 00root root 0000000 0000000 #!/bin/bash port=4567 start_server() { mkdir -p log bundle exec ruby test/server.rb > log/test.log 2>&1 & } run_tests() { jshint src/*.js && phantomjs script/runner.js http://localhost:$port/ } server_started() { lsof -i :${1?} >/dev/null } timestamp() { date +%s } wait_for_server() { timeout=$(( `timestamp` + $1 )) while true; do if server_started "$2"; then break elif [ `timestamp` -gt "$timeout" ]; then echo "timed out after $1 seconds" >&2 exit 1 fi done } start_server server_pid=$! wait_for_server 5 $port run_tests result=$? kill $server_pid exit $result jquery-ujs-1.2.2/script/runner.js 0000664 0000000 0000000 00000007267 12755631514 0017032 0 ustar 00root root 0000000 0000000 /* * PhantomJS Runner QUnit Plugin 1.2.0 * * PhantomJS binaries: http://phantomjs.org/download.html * Requires PhantomJS 1.6+ (1.7+ recommended) * * Run with: * phantomjs runner.js [url-of-your-qunit-testsuite] * * e.g. * phantomjs runner.js http://localhost/qunit/test/index.html */ /*global phantom:false, require:false, console:false, window:false, QUnit:false */ (function() { 'use strict'; var url, page, timeout, args = require('system').args; // arg[0]: scriptName, args[1...]: arguments if (args.length < 2 || args.length > 3) { console.error('Usage:\n phantomjs runner.js [url-of-your-qunit-testsuite] [timeout-in-seconds]'); phantom.exit(1); } url = args[1]; page = require('webpage').create(); if (args[2] !== undefined) { timeout = parseInt(args[2], 10); } // Route `console.log()` calls from within the Page context to the main Phantom context (i.e. current `this`) page.onConsoleMessage = function(msg) { console.log(msg); }; page.onInitialized = function() { page.evaluate(addLogging); }; page.onCallback = function(message) { var result, failed; if (message) { if (message.name === 'QUnit.done') { result = message.data; failed = !result || !result.total || result.failed; if (!result.total) { console.error('No tests were executed. Are you loading tests asynchronously?'); } phantom.exit(failed ? 1 : 0); } } }; page.open(url, function(status) { if (status !== 'success') { console.error('Unable to access network: ' + status); phantom.exit(1); } else { // Cannot do this verification with the 'DOMContentLoaded' handler because it // will be too late to attach it if a page does not have any script tags. var qunitMissing = page.evaluate(function() { return (typeof QUnit === 'undefined' || !QUnit); }); if (qunitMissing) { console.error('The `QUnit` object is not present on this page.'); phantom.exit(1); } // Set a timeout on the test running, otherwise tests with async problems will hang forever if (typeof timeout === 'number') { setTimeout(function() { console.error('The specified timeout of ' + timeout + ' seconds has expired. Aborting...'); phantom.exit(1); }, timeout * 1000); } // Do nothing... the callback mechanism will handle everything! } }); function addLogging() { window.document.addEventListener('DOMContentLoaded', function() { var currentTestAssertions = []; QUnit.log(function(details) { var response; // Ignore passing assertions if (details.result) { return; } response = details.message || ''; if (typeof details.expected !== 'undefined') { if (response) { response += ', '; } response += 'expected: ' + details.expected + ', but was: ' + details.actual; } if (details.source) { response += "\n" + details.source; } currentTestAssertions.push('Failed assertion: ' + response); }); QUnit.testDone(function(result) { var i, len, name = ''; if (result.module) { name += result.module + ': '; } name += result.name; if (result.failed) { console.log('\n' + 'Test failed: ' + name); for (i = 0, len = currentTestAssertions.length; i < len; i++) { console.log(' ' + currentTestAssertions[i]); } } currentTestAssertions.length = 0; }); QUnit.done(function(result) { console.log('\n' + 'Took ' + result.runtime + 'ms to run ' + result.total + ' tests. ' + result.passed + ' passed, ' + result.failed + ' failed.'); if (typeof window.callPhantom === 'function') { window.callPhantom({ 'name': 'QUnit.done', 'data': result }); } }); }, false); } })(); jquery-ujs-1.2.2/src/ 0000775 0000000 0000000 00000000000 12755631514 0014432 5 ustar 00root root 0000000 0000000 jquery-ujs-1.2.2/src/rails.js 0000664 0000000 0000000 00000052140 12755631514 0016104 0 ustar 00root root 0000000 0000000 (function($, undefined) { /** * Unobtrusive scripting adapter for jQuery * https://github.com/rails/jquery-ujs * * Requires jQuery 1.8.0 or later. * * Released under the MIT license * */ // Cut down on the number of issues from people inadvertently including jquery_ujs twice // by detecting and raising an error when it happens. 'use strict'; if ( $.rails !== undefined ) { $.error('jquery-ujs has already been loaded!'); } // Shorthand to make it a little easier to call public rails functions from within rails.js var rails; var $document = $(document); $.rails = rails = { // Link elements bound by jquery-ujs linkClickSelector: 'a[data-confirm], a[data-method], a[data-remote]:not([disabled]), a[data-disable-with], a[data-disable]', // Button elements bound by jquery-ujs buttonClickSelector: 'button[data-remote]:not([form]):not(form button), button[data-confirm]:not([form]):not(form button)', // Select elements bound by jquery-ujs inputChangeSelector: 'select[data-remote], input[data-remote], textarea[data-remote]', // Form elements bound by jquery-ujs formSubmitSelector: 'form', // Form input elements bound by jquery-ujs formInputClickSelector: 'form input[type=submit], form input[type=image], form button[type=submit], form button:not([type]), input[type=submit][form], input[type=image][form], button[type=submit][form], button[form]:not([type])', // Form input elements disabled during form submission disableSelector: 'input[data-disable-with]:enabled, button[data-disable-with]:enabled, textarea[data-disable-with]:enabled, input[data-disable]:enabled, button[data-disable]:enabled, textarea[data-disable]:enabled', // Form input elements re-enabled after form submission enableSelector: 'input[data-disable-with]:disabled, button[data-disable-with]:disabled, textarea[data-disable-with]:disabled, input[data-disable]:disabled, button[data-disable]:disabled, textarea[data-disable]:disabled', // Form required input elements requiredInputSelector: 'input[name][required]:not([disabled]), textarea[name][required]:not([disabled])', // Form file input elements fileInputSelector: 'input[name][type=file]:not([disabled])', // Link onClick disable selector with possible reenable after remote submission linkDisableSelector: 'a[data-disable-with], a[data-disable]', // Button onClick disable selector with possible reenable after remote submission buttonDisableSelector: 'button[data-remote][data-disable-with], button[data-remote][data-disable]', // Up-to-date Cross-Site Request Forgery token csrfToken: function() { return $('meta[name=csrf-token]').attr('content'); }, // URL param that must contain the CSRF token csrfParam: function() { return $('meta[name=csrf-param]').attr('content'); }, // Make sure that every Ajax request sends the CSRF token CSRFProtection: function(xhr) { var token = rails.csrfToken(); if (token) xhr.setRequestHeader('X-CSRF-Token', token); }, // Make sure that all forms have actual up-to-date tokens (cached forms contain old ones) refreshCSRFTokens: function(){ $('form input[name="' + rails.csrfParam() + '"]').val(rails.csrfToken()); }, // Triggers an event on an element and returns false if the event result is false fire: function(obj, name, data) { var event = $.Event(name); obj.trigger(event, data); return event.result !== false; }, // Default confirm dialog, may be overridden with custom confirm dialog in $.rails.confirm confirm: function(message) { return confirm(message); }, // Default ajax function, may be overridden with custom function in $.rails.ajax ajax: function(options) { return $.ajax(options); }, // Default way to get an element's href. May be overridden at $.rails.href. href: function(element) { return element[0].href; }, // Checks "data-remote" if true to handle the request through a XHR request. isRemote: function(element) { return element.data('remote') !== undefined && element.data('remote') !== false; }, // Submits "remote" forms and links with ajax handleRemote: function(element) { var method, url, data, withCredentials, dataType, options; if (rails.fire(element, 'ajax:before')) { withCredentials = element.data('with-credentials') || null; dataType = element.data('type') || ($.ajaxSettings && $.ajaxSettings.dataType); if (element.is('form')) { method = element.data('ujs:submit-button-formmethod') || element.attr('method'); url = element.data('ujs:submit-button-formaction') || element.attr('action'); data = $(element[0]).serializeArray(); // memoized value from clicked submit button var button = element.data('ujs:submit-button'); if (button) { data.push(button); element.data('ujs:submit-button', null); } element.data('ujs:submit-button-formmethod', null); element.data('ujs:submit-button-formaction', null); } else if (element.is(rails.inputChangeSelector)) { method = element.data('method'); url = element.data('url'); data = element.serialize(); if (element.data('params')) data = data + '&' + element.data('params'); } else if (element.is(rails.buttonClickSelector)) { method = element.data('method') || 'get'; url = element.data('url'); data = element.serialize(); if (element.data('params')) data = data + '&' + element.data('params'); } else { method = element.data('method'); url = rails.href(element); data = element.data('params') || null; } options = { type: method || 'GET', data: data, dataType: dataType, // stopping the "ajax:beforeSend" event will cancel the ajax request beforeSend: function(xhr, settings) { if (settings.dataType === undefined) { xhr.setRequestHeader('accept', '*/*;q=0.5, ' + settings.accepts.script); } if (rails.fire(element, 'ajax:beforeSend', [xhr, settings])) { element.trigger('ajax:send', xhr); } else { return false; } }, success: function(data, status, xhr) { element.trigger('ajax:success', [data, status, xhr]); }, complete: function(xhr, status) { element.trigger('ajax:complete', [xhr, status]); }, error: function(xhr, status, error) { element.trigger('ajax:error', [xhr, status, error]); }, crossDomain: rails.isCrossDomain(url) }; // There is no withCredentials for IE6-8 when // "Enable native XMLHTTP support" is disabled if (withCredentials) { options.xhrFields = { withCredentials: withCredentials }; } // Only pass url to `ajax` options if not blank if (url) { options.url = url; } return rails.ajax(options); } else { return false; } }, // Determines if the request is a cross domain request. isCrossDomain: function(url) { var originAnchor = document.createElement('a'); originAnchor.href = location.href; var urlAnchor = document.createElement('a'); try { urlAnchor.href = url; // This is a workaround to a IE bug. urlAnchor.href = urlAnchor.href; // If URL protocol is false or is a string containing a single colon // *and* host are false, assume it is not a cross-domain request // (should only be the case for IE7 and IE compatibility mode). // Otherwise, evaluate protocol and host of the URL against the origin // protocol and host. return !(((!urlAnchor.protocol || urlAnchor.protocol === ':') && !urlAnchor.host) || (originAnchor.protocol + '//' + originAnchor.host === urlAnchor.protocol + '//' + urlAnchor.host)); } catch (e) { // If there is an error parsing the URL, assume it is crossDomain. return true; } }, // Handles "data-method" on links such as: // Delete handleMethod: function(link) { var href = rails.href(link), method = link.data('method'), target = link.attr('target'), csrfToken = rails.csrfToken(), csrfParam = rails.csrfParam(), form = $('
'), metadataInput = ''; if (csrfParam !== undefined && csrfToken !== undefined && !rails.isCrossDomain(href)) { metadataInput += ''; } if (target) { form.attr('target', target); } form.hide().append(metadataInput).appendTo('body'); form.submit(); }, // Helper function that returns form elements that match the specified CSS selector // If form is actually a "form" element this will return associated elements outside the from that have // the html form attribute set formElements: function(form, selector) { return form.is('form') ? $(form[0].elements).filter(selector) : form.find(selector); }, /* Disables form elements: - Caches element value in 'ujs:enable-with' data store - Replaces element text with value of 'data-disable-with' attribute - Sets disabled property to true */ disableFormElements: function(form) { rails.formElements(form, rails.disableSelector).each(function() { rails.disableFormElement($(this)); }); }, disableFormElement: function(element) { var method, replacement; method = element.is('button') ? 'html' : 'val'; replacement = element.data('disable-with'); if (replacement !== undefined) { element.data('ujs:enable-with', element[method]()); element[method](replacement); } element.prop('disabled', true); element.data('ujs:disabled', true); }, /* Re-enables disabled form elements: - Replaces element text with cached value from 'ujs:enable-with' data store (created in `disableFormElements`) - Sets disabled property to false */ enableFormElements: function(form) { rails.formElements(form, rails.enableSelector).each(function() { rails.enableFormElement($(this)); }); }, enableFormElement: function(element) { var method = element.is('button') ? 'html' : 'val'; if (element.data('ujs:enable-with') !== undefined) { element[method](element.data('ujs:enable-with')); element.removeData('ujs:enable-with'); // clean up cache } element.prop('disabled', false); element.removeData('ujs:disabled'); }, /* For 'data-confirm' attribute: - Fires `confirm` event - Shows the confirmation dialog - Fires the `confirm:complete` event Returns `true` if no function stops the chain and user chose yes; `false` otherwise. Attaching a handler to the element's `confirm` event that returns a `falsy` value cancels the confirmation dialog. Attaching a handler to the element's `confirm:complete` event that returns a `falsy` value makes this function return false. The `confirm:complete` event is fired whether or not the user answered true or false to the dialog. */ allowAction: function(element) { var message = element.data('confirm'), answer = false, callback; if (!message) { return true; } if (rails.fire(element, 'confirm')) { try { answer = rails.confirm(message); } catch (e) { (console.error || console.log).call(console, e.stack || e); } callback = rails.fire(element, 'confirm:complete', [answer]); } return answer && callback; }, // Helper function which checks for blank inputs in a form that match the specified CSS selector blankInputs: function(form, specifiedSelector, nonBlank) { var foundInputs = $(), input, valueToCheck, radiosForNameWithNoneSelected, radioName, selector = specifiedSelector || 'input,textarea', requiredInputs = form.find(selector), checkedRadioButtonNames = {}; requiredInputs.each(function() { input = $(this); if (input.is('input[type=radio]')) { // Don't count unchecked required radio as blank if other radio with same name is checked, // regardless of whether same-name radio input has required attribute or not. The spec // states https://www.w3.org/TR/html5/forms.html#the-required-attribute radioName = input.attr('name'); // Skip if we've already seen the radio with this name. if (!checkedRadioButtonNames[radioName]) { // If none checked if (form.find('input[type=radio]:checked[name="' + radioName + '"]').length === 0) { radiosForNameWithNoneSelected = form.find( 'input[type=radio][name="' + radioName + '"]'); foundInputs = foundInputs.add(radiosForNameWithNoneSelected); } // We only need to check each name once. checkedRadioButtonNames[radioName] = radioName; } } else { valueToCheck = input.is('input[type=checkbox],input[type=radio]') ? input.is(':checked') : !!input.val(); if (valueToCheck === nonBlank) { foundInputs = foundInputs.add(input); } } }); return foundInputs.length ? foundInputs : false; }, // Helper function which checks for non-blank inputs in a form that match the specified CSS selector nonBlankInputs: function(form, specifiedSelector) { return rails.blankInputs(form, specifiedSelector, true); // true specifies nonBlank }, // Helper function, needed to provide consistent behavior in IE stopEverything: function(e) { $(e.target).trigger('ujs:everythingStopped'); e.stopImmediatePropagation(); return false; }, // Replace element's html with the 'data-disable-with' after storing original html // and prevent clicking on it disableElement: function(element) { var replacement = element.data('disable-with'); if (replacement !== undefined) { element.data('ujs:enable-with', element.html()); // store enabled state element.html(replacement); } element.bind('click.railsDisable', function(e) { // prevent further clicking return rails.stopEverything(e); }); element.data('ujs:disabled', true); }, // Restore element to its original state which was disabled by 'disableElement' above enableElement: function(element) { if (element.data('ujs:enable-with') !== undefined) { element.html(element.data('ujs:enable-with')); // set to old enabled state element.removeData('ujs:enable-with'); // clean up cache } element.unbind('click.railsDisable'); // enable element element.removeData('ujs:disabled'); } }; if (rails.fire($document, 'rails:attachBindings')) { $.ajaxPrefilter(function(options, originalOptions, xhr){ if ( !options.crossDomain ) { rails.CSRFProtection(xhr); }}); // This event works the same as the load event, except that it fires every // time the page is loaded. // // See https://github.com/rails/jquery-ujs/issues/357 // See https://developer.mozilla.org/en-US/docs/Using_Firefox_1.5_caching $(window).on('pageshow.rails', function () { $($.rails.enableSelector).each(function () { var element = $(this); if (element.data('ujs:disabled')) { $.rails.enableFormElement(element); } }); $($.rails.linkDisableSelector).each(function () { var element = $(this); if (element.data('ujs:disabled')) { $.rails.enableElement(element); } }); }); $document.on('ajax:complete', rails.linkDisableSelector, function() { rails.enableElement($(this)); }); $document.on('ajax:complete', rails.buttonDisableSelector, function() { rails.enableFormElement($(this)); }); $document.on('click.rails', rails.linkClickSelector, function(e) { var link = $(this), method = link.data('method'), data = link.data('params'), metaClick = e.metaKey || e.ctrlKey; if (!rails.allowAction(link)) return rails.stopEverything(e); if (!metaClick && link.is(rails.linkDisableSelector)) rails.disableElement(link); if (rails.isRemote(link)) { if (metaClick && (!method || method === 'GET') && !data) { return true; } var handleRemote = rails.handleRemote(link); // Response from rails.handleRemote() will either be false or a deferred object promise. if (handleRemote === false) { rails.enableElement(link); } else { handleRemote.fail( function() { rails.enableElement(link); } ); } return false; } else if (method) { rails.handleMethod(link); return false; } }); $document.on('click.rails', rails.buttonClickSelector, function(e) { var button = $(this); if (!rails.allowAction(button) || !rails.isRemote(button)) return rails.stopEverything(e); if (button.is(rails.buttonDisableSelector)) rails.disableFormElement(button); var handleRemote = rails.handleRemote(button); // Response from rails.handleRemote() will either be false or a deferred object promise. if (handleRemote === false) { rails.enableFormElement(button); } else { handleRemote.fail( function() { rails.enableFormElement(button); } ); } return false; }); $document.on('change.rails', rails.inputChangeSelector, function(e) { var link = $(this); if (!rails.allowAction(link) || !rails.isRemote(link)) return rails.stopEverything(e); rails.handleRemote(link); return false; }); $document.on('submit.rails', rails.formSubmitSelector, function(e) { var form = $(this), remote = rails.isRemote(form), blankRequiredInputs, nonBlankFileInputs; if (!rails.allowAction(form)) return rails.stopEverything(e); // Skip other logic when required values are missing or file upload is present if (form.attr('novalidate') === undefined) { if (form.data('ujs:formnovalidate-button') === undefined) { blankRequiredInputs = rails.blankInputs(form, rails.requiredInputSelector, false); if (blankRequiredInputs && rails.fire(form, 'ajax:aborted:required', [blankRequiredInputs])) { return rails.stopEverything(e); } } else { // Clear the formnovalidate in case the next button click is not on a formnovalidate button // Not strictly necessary to do here, since it is also reset on each button click, but just to be certain form.data('ujs:formnovalidate-button', undefined); } } if (remote) { nonBlankFileInputs = rails.nonBlankInputs(form, rails.fileInputSelector); if (nonBlankFileInputs) { // Slight timeout so that the submit button gets properly serialized // (make it easy for event handler to serialize form without disabled values) setTimeout(function(){ rails.disableFormElements(form); }, 13); var aborted = rails.fire(form, 'ajax:aborted:file', [nonBlankFileInputs]); // Re-enable form elements if event bindings return false (canceling normal form submission) if (!aborted) { setTimeout(function(){ rails.enableFormElements(form); }, 13); } return aborted; } rails.handleRemote(form); return false; } else { // Slight timeout so that the submit button gets properly serialized setTimeout(function(){ rails.disableFormElements(form); }, 13); } }); $document.on('click.rails', rails.formInputClickSelector, function(event) { var button = $(this); if (!rails.allowAction(button)) return rails.stopEverything(event); // Register the pressed submit button var name = button.attr('name'), data = name ? {name:name, value:button.val()} : null; var form = button.closest('form'); if (form.length === 0) { form = $('#' + button.attr('form')); } form.data('ujs:submit-button', data); // Save attributes from button form.data('ujs:formnovalidate-button', button.attr('formnovalidate')); form.data('ujs:submit-button-formaction', button.attr('formaction')); form.data('ujs:submit-button-formmethod', button.attr('formmethod')); }); $document.on('ajax:send.rails', rails.formSubmitSelector, function(event) { if (this === event.target) rails.disableFormElements($(this)); }); $document.on('ajax:complete.rails', rails.formSubmitSelector, function(event) { if (this === event.target) rails.enableFormElements($(this)); }); $(function(){ rails.refreshCSRFTokens(); }); } })( jQuery ); jquery-ujs-1.2.2/test/ 0000775 0000000 0000000 00000000000 12755631514 0014622 5 ustar 00root root 0000000 0000000 jquery-ujs-1.2.2/test/config.ru 0000664 0000000 0000000 00000000136 12755631514 0016437 0 ustar 00root root 0000000 0000000 $LOAD_PATH.unshift File.expand_path('..', __FILE__) require 'server' run Sinatra::Application jquery-ujs-1.2.2/test/public/ 0000775 0000000 0000000 00000000000 12755631514 0016100 5 ustar 00root root 0000000 0000000 jquery-ujs-1.2.2/test/public/test/ 0000775 0000000 0000000 00000000000 12755631514 0017057 5 ustar 00root root 0000000 0000000 jquery-ujs-1.2.2/test/public/test/call-remote-callbacks.js 0000664 0000000 0000000 00000041203 12755631514 0023536 0 ustar 00root root 0000000 0000000 (function(){ module('call-remote-callbacks', { setup: function() { $('#qunit-fixture').append($('', { action: '/echo', method: 'get', 'data-remote': 'true' })); }, teardown: function() { $(document).undelegate('form[data-remote]', 'ajax:beforeSend'); $(document).undelegate('form[data-remote]', 'ajax:before'); $(document).undelegate('form[data-remote]', 'ajax:send'); $(document).undelegate('form[data-remote]', 'ajax:complete'); $(document).undelegate('form[data-remote]', 'ajax:success'); $(document).unbind('ajaxStop'); $(document).unbind('iframe:loading'); } }); function start_after_submit(form) { form.bind('ajax:complete', function() { ok(true, 'ajax:complete'); start(); }); } function submit(fn) { var form = $('form'); start_after_submit(form); if (fn) fn(form); form.trigger('submit'); } function submit_with_button(submit_button) { var form = $('form'); start_after_submit(form); submit_button.trigger('click'); } asyncTest('modifying form fields with "ajax:before" sends modified data in request', 4, function(){ $('form[data-remote]') .append($('')) .append($('')) .bind('ajax:before', function() { var form = $(this); form .append($('',{name: 'other_user_name',value: 'jonathan'})) .find('input[name="removed_user_name"]').remove(); form .find('input[name="user_name"]').val('steve'); }); submit(function(form) { form.bind('ajax:success', function(e, data, status, xhr) { equal(data.params.user_name, 'steve', 'modified field value should have been submitted'); equal(data.params.other_user_name, 'jonathan', 'added field value should have been submitted'); equal(data.params.removed_user_name, undefined, 'removed field value should be undefined'); }); }); }); asyncTest('modifying data("type") with "ajax:before" requests new dataType in request', 2, function(){ $('form[data-remote]').data('type','html') .bind('ajax:before', function() { var form = $(this); form.data('type','xml'); }); submit(function(form) { form.bind('ajax:beforeSend', function(e, xhr, settings) { equal(settings.dataType, 'xml', 'modified dataType should have been requested'); }); }); }); asyncTest('setting data("with-credentials",true) with "ajax:before" uses new setting in request', 2, function(){ $('form[data-remote]').data('with-credentials',false) .bind('ajax:before', function() { var form = $(this); form.data('with-credentials',true); }); submit(function(form) { form.bind('ajax:beforeSend', function(e, xhr, settings) { equal(settings.xhrFields && settings.xhrFields.withCredentials, true, 'setting modified in ajax:before should have forced withCredentials request'); }); }); }); asyncTest('stopping the "ajax:beforeSend" event aborts the request', 1, function() { submit(function(form) { form.bind('ajax:beforeSend', function() { ok(true, 'aborting request in ajax:beforeSend'); return false; }); form.unbind('ajax:send').bind('ajax:send', function() { ok(false, 'ajax:send should not run'); }); form.unbind('ajax:complete').bind('ajax:complete', function() { ok(false, 'ajax:complete should not run'); }); form.bind('ajax:error', function(e, xhr, status, error) { ok(false, 'ajax:error should not run'); }); $(document).bind('ajaxStop', function() { start(); }); }); }); asyncTest('blank required form input field should abort request and trigger "ajax:aborted:required" event', 5, function() { $(document).bind('iframe:loading', function() { ok(false, 'form should not get submitted'); }); var form = $('form[data-remote]') .append($('')) .append($('')) .bind('ajax:beforeSend', function() { ok(false, 'ajax:beforeSend should not run'); }) .bind('ajax:aborted:required', function(e,data){ ok(data.length == 2, 'ajax:aborted:required event is passed all blank required inputs (jQuery objects)'); ok(data.first().is('input[name="user_name"]') , 'ajax:aborted:required adds blank required input to data'); ok(data.last().is('textarea[name="user_bio"]'), 'ajax:aborted:required adds blank required textarea to data'); ok(true, 'ajax:aborted:required should run'); }) .trigger('submit'); setTimeout(function() { form.find('input[required],textarea[required]').val('Tyler'); form.unbind('ajax:beforeSend'); submit(); }, 13); }); asyncTest('blank required form input for non-remote form should abort normal submission', 1, function() { var form = $('form[data-remote]') .append($('')) .removeAttr('data-remote') .bind('ujs:everythingStopped', function() { ok(true, 'ujs:everythingStopped should run'); }) .trigger('submit'); setTimeout(function() { start(); }, 13); }); asyncTest('form should be submitted with blank required fields if handler is bound to "ajax:aborted:required" event that returns false', 1, function(){ var form = $('form[data-remote]') .append($('')) .bind('ajax:beforeSend', function() { ok(true, 'ajax:beforeSend should run'); }) .bind('ajax:aborted:required', function() { return false; }) .trigger('submit'); setTimeout(function() { start(); }, 13); }); asyncTest('disabled fields should not be included in blank required check', 2, function() { var form = $('form[data-remote]') .append($('')) .append($('')) .bind('ajax:beforeSend', function() { ok(true, 'ajax:beforeSend should run'); }) .bind('ajax:aborted:required', function() { ok(false, 'ajax:aborted:required should not run'); }); submit(); }); asyncTest('form should be submitted with blank required fields if it has the "novalidate" attribute', 2, function(){ var form = $('form[data-remote]') .append($('')) .attr("novalidate", "novalidate") .bind('ajax:beforeSend', function() { ok(true, 'ajax:beforeSend should run'); }) .bind('ajax:aborted:required', function() { ok(false, 'ajax:aborted:required should not run'); }); submit(); }); asyncTest('form should be submitted with blank required fields if the button has the "formnovalidate" attribute', 2, function(){ var submit_button = $(''); var form = $('form[data-remote]') .append($('')) .append(submit_button) .bind('ajax:beforeSend', function() { ok(true, 'ajax:beforeSend should run'); }) .bind('ajax:aborted:required', function() { ok(false, 'ajax:aborted:required should not run'); }); submit_with_button(submit_button); }); asyncTest('blank required form input for non-remote form with "novalidate" attribute should not abort normal submission', 1, function() { $(document).bind('iframe:loading', function() { ok(true, 'form should get submitted'); }); var form = $('form[data-remote]') .append($('')) .removeAttr('data-remote') .attr("novalidate","novalidate") .trigger('submit'); setTimeout(function() { start(); }, 13); }); asyncTest('unchecked required checkbox should abort form submission', 1, function() { var form = $('form[data-remote]') .append($('')) .removeAttr('data-remote') .bind('ujs:everythingStopped', function() { ok(true, 'ujs:everythingStopped should run'); }) .trigger('submit'); setTimeout(function() { start(); }, 13); }); asyncTest('unchecked required radio should abort form submission', 1, function() { var form = $('form[data-remote]') .append($('')) .append($('')) .removeAttr('data-remote') .bind('ujs:everythingStopped', function() { ok(true, 'ujs:everythingStopped should run'); }) .trigger('submit'); setTimeout(function() { start(); }, 13); }); asyncTest('required radio should only require one to be checked', 1, function() { $(document).bind('iframe:loading', function() { ok(true, 'form should get submitted'); }); var form = $('form[data-remote]') .append($('')) .append($('')) .removeAttr('data-remote') .bind('ujs:everythingStopped', function() { ok(false, 'ujs:everythingStopped should not run'); }) .find('#checkme').prop('checked', true) .end() .trigger('submit'); setTimeout(function() { start(); }, 13); }); asyncTest('required radio should only require one to be checked if not all radios are required', 1, function() { $(document).bind('iframe:loading', function() { ok(true, 'form should get submitted'); }); var form = $('form[data-remote]') // Check the radio that is not required .append($('')) // Check the radio that is not required .append($('')) // Only one needs to be required .append($('')) .removeAttr('data-remote') .bind('ujs:everythingStopped', function() { ok(false, 'ujs:everythingStopped should not run'); }) .find('#checkme').prop('checked', true) .end() .trigger('submit'); setTimeout(function() { start(); }, 13); }); function skipIt() { // This test cannot work due to the security feature in browsers which makes the value // attribute of file input fields readonly, so it cannot be set with default value. // This is what the test would look like though if browsers let us automate this test. asyncTest('non-blank file form input field should abort remote request, but submit normally', 5, function() { var form = $('form[data-remote]') .append($('')) .bind('ajax:beforeSend', function() { ok(false, 'ajax:beforeSend should not run'); }) .bind('iframe:loading', function() { ok(true, 'form should get submitted'); }) .bind('ajax:aborted:file', function(e,data) { ok(data.length == 1, 'ajax:aborted:file event is passed all non-blank file inputs (jQuery objects)'); ok(data.first().is('input[name="attachment"]') , 'ajax:aborted:file adds non-blank file input to data'); ok(true, 'ajax:aborted:file event should run'); }) .trigger('submit'); setTimeout(function() { form.find('input[type="file"]').val(''); form.unbind('ajax:beforeSend'); submit(); }, 13); }); asyncTest('file form input field should not abort remote request if file form input does not have a name attribute', 5, function() { var form = $('form[data-remote]') .append($('')) .bind('ajax:beforeSend', function() { ok(true, 'ajax:beforeSend should run'); }) .bind('iframe:loading', function() { ok(true, 'form should get submitted'); }) .bind('ajax:aborted:file', function(e,data) { ok(false, 'ajax:aborted:file should not run'); }) .trigger('submit'); setTimeout(function() { form.find('input[type="file"]').val(''); form.unbind('ajax:beforeSend'); submit(); }, 13); }); asyncTest('blank file input field should abort request entirely if handler bound to "ajax:aborted:file" event that returns false', 1, function() { var form = $('form[data-remote]') .append($('')) .bind('ajax:beforeSend', function() { ok(false, 'ajax:beforeSend should not run'); }) .bind('iframe:loading', function() { ok(false, 'form should not get submitted'); }) .bind('ajax:aborted:file', function() { return false; }) .trigger('submit'); setTimeout(function() { form.find('input[type="file"]').val(''); form.unbind('ajax:beforeSend'); submit(); }, 13); }); } asyncTest('"ajax:beforeSend" can be observed and stopped with event delegation', 1, function() { $(document).delegate('form[data-remote]', 'ajax:beforeSend', function() { ok(true, 'ajax:beforeSend observed with event delegation'); return false; }); submit(function(form) { form.unbind('ajax:send').bind('ajax:send', function() { ok(false, 'ajax:send should not run'); }); form.unbind('ajax:complete').bind('ajax:complete', function() { ok(false, 'ajax:complete should not run'); }); $(document).bind('ajaxStop', function() { start(); }); }); }); asyncTest('"ajax:beforeSend", "ajax:send", "ajax:success" and "ajax:complete" are triggered', 9, function() { submit(function(form) { form.bind('ajax:beforeSend', function(e, xhr, settings) { ok(xhr.setRequestHeader, 'first argument to "ajax:beforeSend" should be an XHR object'); equal(settings.url, '/echo', 'second argument to "ajax:beforeSend" should be a settings object'); }); form.bind('ajax:send', function(e, xhr) { ok(xhr.abort, 'first argument to "ajax:send" should be an XHR object'); }); form.bind('ajax:success', function(e, data, status, xhr) { ok(data.REQUEST_METHOD, 'first argument to ajax:success should be a data object'); equal(status, 'success', 'second argument to ajax:success should be a status string'); ok(xhr.getResponseHeader, 'third argument to "ajax:success" should be an XHR object'); }); form.bind('ajax:complete', function(e, xhr, status) { ok(xhr.getResponseHeader, 'first argument to "ajax:complete" should be an XHR object'); equal(status, 'success', 'second argument to ajax:complete should be a status string'); }); }); }); if(window.phantom !== undefined) { asyncTest('"ajax:beforeSend", "ajax:send", "ajax:error" and "ajax:complete" are triggered on error', 7, function() { submit(function(form) { form.attr('action', '/error'); form.bind('ajax:beforeSend', function(arg) { ok(true, 'ajax:beforeSend') }); form.bind('ajax:send', function(arg) { ok(true, 'ajax:send') }); form.bind('ajax:error', function(e, xhr, status, error) { ok(xhr.getResponseHeader, 'first argument to "ajax:error" should be an XHR object'); equal(status, 'error', 'second argument to ajax:error should be a status string'); // Firefox 8 returns "Forbidden " with trailing space equal($.trim(error), 'Forbidden', 'third argument to ajax:error should be an HTTP status response'); // Opera returns "0" for HTTP code equal(xhr.status, window.opera ? 0 : 403, 'status code should be 403'); }); }); }); } // IF THIS TEST IS FAILING, TRY INCREASING THE TIMEOUT AT THE BOTTOM TO > 100 asyncTest('binding to ajax callbacks via .delegate() triggers handlers properly', 4, function() { $(document) .delegate('form[data-remote]', 'ajax:beforeSend', function() { ok(true, 'ajax:beforeSend handler is triggered'); }) .delegate('form[data-remote]', 'ajax:send', function() { ok(true, 'ajax:send handler is triggered'); }) .delegate('form[data-remote]', 'ajax:complete', function() { ok(true, 'ajax:complete handler is triggered'); }) .delegate('form[data-remote]', 'ajax:success', function() { ok(true, 'ajax:success handler is triggered'); }); $('form[data-remote]').trigger('submit'); setTimeout(function() { start(); }, 63); }); asyncTest('binding to ajax:send event to call jquery methods on ajax object', 2, function() { $('form[data-remote]') .bind('ajax:send', function(e, xhr) { ok(true, 'event should fire'); equal(typeof(xhr.abort), 'function', 'event should pass jqXHR object'); xhr.abort(); }) .trigger('submit'); setTimeout(function() { start(); }, 35); }); })(); jquery-ujs-1.2.2/test/public/test/call-remote.js 0000664 0000000 0000000 00000014114 12755631514 0021622 0 ustar 00root root 0000000 0000000 (function(){ function buildForm(attrs) { attrs = $.extend({ action: '/echo', 'data-remote': 'true' }, attrs); $('#qunit-fixture').append($('', attrs)) .find('form').append($('')); }; module('call-remote'); function submit(fn) { $('form') .bind('ajax:success', fn) .bind('ajax:complete', function() { start() }) .trigger('submit'); } asyncTest('form method is read from "method" and not from "data-method"', 1, function() { buildForm({ method: 'post', 'data-method': 'get' }); submit(function(e, data, status, xhr) { App.assertPostRequest(data); }); }); asyncTest('form method is not read from "data-method" attribute in case of missing "method"', 1, function() { buildForm({ 'data-method': 'put' }); submit(function(e, data, status, xhr) { App.assertGetRequest(data); }); }); asyncTest('form method is read from submit button "formmethod" if submit is triggered by that button', 1, function() { var submitButton = $('') buildForm({ method: 'post' }); $('#qunit-fixture').find('form').append(submitButton) .bind('ajax:success', function(e, data, status, xhr) { App.assertGetRequest(data); }) .bind('ajax:complete', function() { start() }); submitButton.trigger('click'); }); asyncTest('form default method is GET', 1, function() { buildForm(); submit(function(e, data, status, xhr) { App.assertGetRequest(data); }); }); asyncTest('form url is picked up from "action"', 1, function() { buildForm({ method: 'post' }); submit(function(e, data, status, xhr) { App.assertRequestPath(data, '/echo'); }); }); asyncTest('form url is read from "action" not "href"', 1, function() { buildForm({ method: 'post', href: '/echo2' }); submit(function(e, data, status, xhr) { App.assertRequestPath(data, '/echo'); }); }); asyncTest('form url is read from submit button "formaction" if submit is triggered by that button', 1, function() { var submitButton = $('') buildForm({ method: 'post', href: '/echo2' }); $('#qunit-fixture').find('form').append(submitButton) .bind('ajax:success', function(e, data, status, xhr) { App.assertRequestPath(data, '/echo'); }) .bind('ajax:complete', function() { start() }); submitButton.trigger('click'); }); asyncTest('prefer JS, but accept any format', 1, function() { buildForm({ method: 'post' }); submit(function(e, data, status, xhr) { var accept = data.HTTP_ACCEPT; ok(accept.indexOf('*/*;q=0.5, text/javascript, application/javascript') === 0, 'Accept: ' + accept); }); }); asyncTest('accept application/json if "data-type" is json', 1, function() { buildForm({ method: 'post', 'data-type': 'json' }); submit(function(e, data, status, xhr) { equal(data.HTTP_ACCEPT, 'application/json, text/javascript, */*; q=0.01'); }); }); asyncTest('allow empty "data-remote" attribute', 1, function() { var form = $('#qunit-fixture').append($('')).find('form'); submit(function() { ok(true, 'form with empty "data-remote" attribute is also allowed'); }); }); asyncTest('allow empty form "action"', 1, function() { var currentLocation, ajaxLocation; buildForm({ action: '' }); $('#qunit-fixture').find('form') .bind('ajax:beforeSend', function(e, xhr, settings) { // Get current location (the same way jQuery does) try { currentLocation = location.href; } catch(e) { currentLocation = document.createElement( "a" ); currentLocation.href = ""; currentLocation = currentLocation.href; } currentLocation = currentLocation.replace(/\?$/, ''); // Actual location (strip out settings.data that jQuery serializes and appends) // HACK: can no longer use settings.data below to see what was appended to URL, as of // jQuery 1.6.3 (see http://bugs.jquery.com/ticket/10202 and https://github.com/jquery/jquery/pull/544) ajaxLocation = settings.url.replace("user_name=john","").replace(/&$/, "").replace(/\?$/, ""); equal(ajaxLocation.match(/^(.*)/)[1], currentLocation, 'URL should be current page by default'); // Prevent the request from actually getting sent to the current page and // causing an error. return false; }) .trigger('submit'); setTimeout(function() { start(); }, 13); }); asyncTest('sends CSRF token in custom header', 1, function() { buildForm({ method: 'post' }); $('#qunit-fixture').append(''); submit(function(e, data, status, xhr) { equal(data.HTTP_X_CSRF_TOKEN, 'cf50faa3fe97702ca1ae', 'X-CSRF-Token header should be sent'); }); }); asyncTest('intelligently guesses crossDomain behavior when target URL has a different protocol and/or hostname', 1, function(e, xhr) { // Don't set data-cross-domain here, just set action to be a different domain than localhost buildForm({ action: 'http://www.alfajango.com' }); $('#qunit-fixture').append(''); $('#qunit-fixture').find('form') .bind('ajax:beforeSend', function(e, xhr, settings) { equal(settings.crossDomain, true, 'crossDomain should be set to true'); // prevent request from actually getting sent off-domain return false; }) .trigger('submit'); setTimeout(function() { start(); }, 13); }); asyncTest('intelligently guesses crossDomain behavior when target URL consists of only a path', 1, function(e, xhr) { // Don't set data-cross-domain here, just set action to be a different domain than localhost buildForm({ action: '/just/a/path' }); $('#qunit-fixture').append(''); $('#qunit-fixture').find('form') .bind('ajax:beforeSend', function(e, xhr, settings) { equal(settings.crossDomain, false, 'crossDomain should be set to false'); // prevent request from actually getting sent off-domain return false; }) .trigger('submit'); setTimeout(function() { start(); }, 13); }); })(); jquery-ujs-1.2.2/test/public/test/csrf-refresh.js 0000664 0000000 0000000 00000001214 12755631514 0022004 0 ustar 00root root 0000000 0000000 (function(){ module('csrf-refresh', {}); asyncTest('refresh all csrf tokens', 1, function() { var correctToken = "cf50faa3fe97702ca1ae"; var form = $('') var input = $('').attr({ type: 'hidden', name: 'authenticity_token', id: 'authenticity_token', value: 'foo' }) input.appendTo(form) $('#qunit-fixture') .append('') .append('') .append(form); $.rails.refreshCSRFTokens(); currentToken = $('#qunit-fixture #authenticity_token').val(); start(); equal(currentToken, correctToken); }); })(); jquery-ujs-1.2.2/test/public/test/csrf-token.js 0000664 0000000 0000000 00000001121 12755631514 0021463 0 ustar 00root root 0000000 0000000 (function(){ module('csrf-token', {}); asyncTest('find csrf token', 1, function() { var correctToken = "cf50faa3fe97702ca1ae"; $('#qunit-fixture').append(''); currentToken = $.rails.csrfToken(); start(); equal(currentToken, correctToken); }); asyncTest('find csrf param', 1, function() { var correctParam = "authenticity_token"; $('#qunit-fixture').append(''); currentParam = $.rails.csrfParam(); start(); equal(currentParam, correctParam); }); })(); jquery-ujs-1.2.2/test/public/test/data-confirm.js 0000664 0000000 0000000 00000016666 12755631514 0022000 0 ustar 00root root 0000000 0000000 module('data-confirm', { setup: function() { $('#qunit-fixture').append($('', { href: '/echo', 'data-remote': 'true', 'data-confirm': 'Are you absolutely sure?', text: 'my social security number' })); $('#qunit-fixture').append($('', { 'data-url': '/echo', 'data-remote': 'true', 'data-confirm': 'Are you absolutely sure?', text: 'Click me' })); $('#qunit-fixture').append($('', { id: 'confirm', action: '/echo', 'data-remote': 'true' })); $('#qunit-fixture').append($('', { type: 'submit', form: 'confirm', 'data-confirm': 'Are you absolutely sure?' })); this.windowConfirm = window.confirm; }, teardown: function() { window.confirm = this.windowConfirm; } }); asyncTest('clicking on a link with data-confirm attribute. Confirm yes.', 6, function() { var message; // auto-confirm: window.confirm = function(msg) { message = msg; return true }; $('a[data-confirm]') .bind('confirm:complete', function(e, data) { App.assertCallbackInvoked('confirm:complete'); ok(data == true, 'confirm:complete passes in confirm answer (true)'); }) .bind('ajax:success', function(e, data, status, xhr) { App.assertCallbackInvoked('ajax:success'); App.assertRequestPath(data, '/echo'); App.assertGetRequest(data); equal(message, 'Are you absolutely sure?'); start(); }) .trigger('click'); }); asyncTest('clicking on a button with data-confirm attribute. Confirm yes.', 6, function() { var message; // auto-confirm: window.confirm = function(msg) { message = msg; return true }; $('button[data-confirm]') .bind('confirm:complete', function(e, data) { App.assertCallbackInvoked('confirm:complete'); ok(data == true, 'confirm:complete passes in confirm answer (true)'); }) .bind('ajax:success', function(e, data, status, xhr) { App.assertCallbackInvoked('ajax:success'); App.assertRequestPath(data, '/echo'); App.assertGetRequest(data); equal(message, 'Are you absolutely sure?'); start(); }) .trigger('click'); }); asyncTest('clicking on a link with data-confirm attribute. Confirm No.', 3, function() { var message; // auto-decline: window.confirm = function(msg) { message = msg; return false }; $('a[data-confirm]') .bind('confirm:complete', function(e, data) { App.assertCallbackInvoked('confirm:complete'); ok(data == false, 'confirm:complete passes in confirm answer (false)'); }) .bind('ajax:beforeSend', function(e, data, status, xhr) { App.assertCallbackNotInvoked('ajax:beforeSend'); }) .trigger('click'); setTimeout(function() { equal(message, 'Are you absolutely sure?'); start(); }, 50); }); asyncTest('clicking on a button with data-confirm attribute. Confirm No.', 3, function() { var message; // auto-decline: window.confirm = function(msg) { message = msg; return false }; $('button[data-confirm]') .bind('confirm:complete', function(e, data) { App.assertCallbackInvoked('confirm:complete'); ok(data == false, 'confirm:complete passes in confirm answer (false)'); }) .bind('ajax:beforeSend', function(e, data, status, xhr) { App.assertCallbackNotInvoked('ajax:beforeSend'); }) .trigger('click'); setTimeout(function() { equal(message, 'Are you absolutely sure?'); start(); }, 50); }); asyncTest('clicking on a button with data-confirm attribute. Confirm error.', 3, function() { var message; // auto-decline: window.confirm = function(msg) { message = msg; throw "some random error"; }; $('button[data-confirm]') .bind('confirm:complete', function(e, data) { App.assertCallbackInvoked('confirm:complete'); ok(data == false, 'confirm:complete passes in confirm answer (false)'); }) .bind('ajax:beforeSend', function(e, data, status, xhr) { App.assertCallbackNotInvoked('ajax:beforeSend'); }) .trigger('click'); setTimeout(function() { equal(message, 'Are you absolutely sure?'); start(); }, 50); }); asyncTest('clicking on a submit button with form and data-confirm attributes. Confirm No.', 3, function() { var message; // auto-decline: window.confirm = function(msg) { message = msg; return false }; $('input[type=submit][form]') .bind('confirm:complete', function(e, data) { App.assertCallbackInvoked('confirm:complete'); ok(data == false, 'confirm:complete passes in confirm answer (false)'); }) .bind('ajax:beforeSend', function(e, data, status, xhr) { App.assertCallbackNotInvoked('ajax:beforeSend'); }) .trigger('click'); setTimeout(function() { equal(message, 'Are you absolutely sure?'); start(); }, 50); }); asyncTest('binding to confirm event of a link and returning false', 1, function() { // redefine confirm function so we can make sure it's not called window.confirm = function(msg) { ok(false, 'confirm dialog should not be called'); }; $('a[data-confirm]') .bind('confirm', function() { App.assertCallbackInvoked('confirm'); return false; }) .bind('confirm:complete', function() { App.assertCallbackNotInvoked('confirm:complete'); }) .trigger('click'); setTimeout(function() { start(); }, 50); }); asyncTest('binding to confirm event of a button and returning false', 1, function() { // redefine confirm function so we can make sure it's not called window.confirm = function(msg) { ok(false, 'confirm dialog should not be called'); }; $('button[data-confirm]') .bind('confirm', function() { App.assertCallbackInvoked('confirm'); return false; }) .bind('confirm:complete', function() { App.assertCallbackNotInvoked('confirm:complete'); }) .trigger('click'); setTimeout(function() { start(); }, 50); }); asyncTest('binding to confirm:complete event of a link and returning false', 2, function() { // auto-confirm: window.confirm = function(msg) { ok(true, 'confirm dialog should be called'); return true; }; $('a[data-confirm]') .bind('confirm:complete', function() { App.assertCallbackInvoked('confirm:complete'); return false; }) .bind('ajax:beforeSend', function() { App.assertCallbackNotInvoked('ajax:beforeSend'); }) .trigger('click'); setTimeout(function() { start(); }, 50); }); asyncTest('binding to confirm:complete event of a button and returning false', 2, function() { // auto-confirm: window.confirm = function(msg) { ok(true, 'confirm dialog should be called'); return true; }; $('button[data-confirm]') .bind('confirm:complete', function() { App.assertCallbackInvoked('confirm:complete'); return false; }) .bind('ajax:beforeSend', function() { App.assertCallbackNotInvoked('ajax:beforeSend'); }) .trigger('click'); setTimeout(function() { start(); }, 50); }); asyncTest('a button inside a form only confirms once', 1, function() { var confirmations = 0; window.confirm = function(msg) { confirmations++; return true; }; $('#qunit-fixture').append($('').append($('', { 'data-remote': 'true', 'data-confirm': 'Are you absolutely sure?', text: 'Click me' }))); $('form > button[data-confirm]').trigger('click'); ok(confirmations === 1, 'confirmation counter should be 1, but it was ' + confirmations); start(); }); jquery-ujs-1.2.2/test/public/test/data-disable-with.js 0000664 0000000 0000000 00000027072 12755631514 0022710 0 ustar 00root root 0000000 0000000 module('data-disable-with', { setup: function() { $('#qunit-fixture').append($('', { action: '/echo', 'data-remote': 'true', method: 'post' })) .find('form') .append($('')); $('#qunit-fixture').append($('', { action: '/echo', method: 'post', id: 'not_remote' })) .find('form:last') // WEEIRDD: the form won't submit to an iframe if the button is name="submit" (??!) .append($('')); $('#qunit-fixture').append($('', { text: 'Click me', href: '/echo', 'data-disable-with': 'clicking...' })); $('#qunit-fixture').append($('', { type: 'submit', form: 'not_remote', 'data-disable-with': 'form attr submitting', name: 'submit3', value: 'Form Attr Submit' })); $('#qunit-fixture').append($('', { text: 'Click me', 'data-remote': true, 'data-url': '/echo', 'data-disable-with': 'clicking...' })); }, teardown: function() { $(document).unbind('iframe:loaded'); } }); asyncTest('form input field with "data-disable-with" attribute', 7, function() { var form = $('form[data-remote]'), input = form.find('input[type=text]'); App.checkEnabledState(input, 'john'); form.bind('ajax:success', function(e, data) { setTimeout(function() { App.checkEnabledState(input, 'john'); equal(data.params.user_name, 'john'); start(); }, 13); }); form.trigger('submit'); App.checkDisabledState(input, 'processing ...'); }); asyncTest('blank form input field with "data-disable-with" attribute', 7, function() { var form = $('form[data-remote]'), input = form.find('input[type=text]'); input.val(''); App.checkEnabledState(input, ''); form.bind('ajax:success', function(e, data) { setTimeout(function() { App.checkEnabledState(input, ''); equal(data.params.user_name, ''); start(); }, 13); }); form.trigger('submit'); App.checkDisabledState(input, 'processing ...'); }); asyncTest('form button with "data-disable-with" attribute', 6, function() { var form = $('form[data-remote]'), button = $(''); form.append(button); App.checkEnabledState(button, 'Submit'); form.bind('ajax:success', function(e, data) { setTimeout(function() { App.checkEnabledState(button, 'Submit'); start(); }, 13); }); form.trigger('submit'); App.checkDisabledState(button, 'submitting ...'); }); asyncTest('form input[type=submit][data-disable-with] disables', 6, function(){ var form = $('form:not([data-remote])'), input = form.find('input[type=submit]'); App.checkEnabledState(input, 'Submit'); // WEEIRDD: attaching this handler makes the test work in IE7 $(document).bind('iframe:loading', function(e, form) {}); $(document).bind('iframe:loaded', function(e, data) { setTimeout(function() { App.checkDisabledState(input, 'submitting ...'); start(); }, 30); }); form.trigger('submit'); setTimeout(function() { App.checkDisabledState(input, 'submitting ...'); }, 30); }); test('form input[type=submit][data-disable-with] re-enables when `pageshow` event is triggered', function(){ var form = $('form:not([data-remote])'), input = form.find('input[type=submit]'); App.checkEnabledState(input, 'Submit'); // Emulate the disabled state without submitting the form at all, what is the // state after going back on firefox after submitting a form. // // See https://github.com/rails/jquery-ujs/issues/357 $.rails.disableFormElements(form); App.checkDisabledState(input, 'submitting ...'); $(window).trigger('pageshow'); App.checkEnabledState(input, 'Submit'); }); asyncTest('form[data-remote] input[type=submit][data-disable-with] is replaced in ajax callback', 2, function(){ var form = $('form:not([data-remote])').attr('data-remote', 'true'), origFormContents = form.html(); form.bind('ajax:success', function(){ form.html(origFormContents); setTimeout(function(){ var input = form.find('input[type=submit]'); App.checkEnabledState(input, 'Submit'); start(); }, 30); }).trigger('submit'); }); asyncTest('form[data-remote] input[data-disable-with] is replaced with disabled field in ajax callback', 2, function(){ var form = $('form:not([data-remote])').attr('data-remote', 'true'), input = form.find('input[type=submit]'), newDisabledInput = input.clone().attr('disabled', 'disabled'); form.bind('ajax:success', function(){ input.replaceWith(newDisabledInput); setTimeout(function(){ App.checkEnabledState(newDisabledInput, 'Submit'); start(); }, 30); }).trigger('submit'); }); asyncTest('form input[type=submit][data-disable-with] using "form" attribute disables', 6, function() { var form = $('#not_remote'), input = $('input[form=not_remote]'); App.checkEnabledState(input, 'Form Attr Submit'); // WEEIRDD: attaching this handler makes the test work in IE7 $(document).bind('iframe:loading', function(e, form) {}); $(document).bind('iframe:loaded', function(e, data) { setTimeout(function() { App.checkDisabledState(input, 'form attr submitting'); start(); }, 30); }); form.trigger('submit'); setTimeout(function() { App.checkDisabledState(input, 'form attr submitting'); }, 30); }); asyncTest('form[data-remote] textarea[data-disable-with] attribute', 3, function() { var form = $('form[data-remote]'), textarea = $('').appendTo(form); form.bind('ajax:success', function(e, data) { setTimeout(function() { equal(data.params.user_bio, 'born, lived, died.'); start(); }, 13); }); form.trigger('submit'); App.checkDisabledState(textarea, 'processing ...'); }); asyncTest('a[data-disable-with] disables', 4, function() { var link = $('a[data-disable-with]'); App.checkEnabledState(link, 'Click me'); link.trigger('click'); App.checkDisabledState(link, 'clicking...'); start(); }); test('a[data-disable-with] re-enables when `pageshow` event is triggered', function() { var link = $('a[data-disable-with]'); App.checkEnabledState(link, 'Click me'); link.trigger('click'); App.checkDisabledState(link, 'clicking...'); $(window).trigger('pageshow'); App.checkEnabledState(link, 'Click me'); }); asyncTest('a[data-remote][data-disable-with] disables and re-enables', 6, function() { var link = $('a[data-disable-with]').attr('data-remote', true); App.checkEnabledState(link, 'Click me'); link .bind('ajax:beforeSend', function() { App.checkDisabledState(link, 'clicking...'); }) .bind('ajax:complete', function() { setTimeout( function() { App.checkEnabledState(link, 'Click me'); start(); }, 15); }) .trigger('click'); }); asyncTest('a[data-remote][data-disable-with] re-enables when `ajax:before` event is cancelled', 6, function() { var link = $('a[data-disable-with]').attr('data-remote', true); App.checkEnabledState(link, 'Click me'); link .bind('ajax:before', function() { App.checkDisabledState(link, 'clicking...'); return false; }) .trigger('click'); setTimeout(function() { App.checkEnabledState(link, 'Click me'); start(); }, 30); }); asyncTest('a[data-remote][data-disable-with] re-enables when `ajax:beforeSend` event is cancelled', 6, function() { var link = $('a[data-disable-with]').attr('data-remote', true); App.checkEnabledState(link, 'Click me'); link .bind('ajax:beforeSend', function() { App.checkDisabledState(link, 'clicking...'); return false; }) .trigger('click'); setTimeout(function() { App.checkEnabledState(link, 'Click me'); start(); }, 30); }); asyncTest('a[data-remote][data-disable-with] re-enables when `ajax:error` event is triggered', 6, function() { var link = $('a[data-disable-with]').attr('data-remote', true).attr('href', '/error'); App.checkEnabledState(link, 'Click me'); link .bind('ajax:beforeSend', function() { App.checkDisabledState(link, 'clicking...'); }) .trigger('click'); setTimeout(function() { App.checkEnabledState(link, 'Click me'); start(); }, 30); }); asyncTest('form[data-remote] input|button|textarea[data-disable-with] does not disable when `ajax:beforeSend` event is cancelled', 8, function() { var form = $('form[data-remote]'), input = form.find('input:text'), button = $('').appendTo(form), textarea = $('').appendTo(form), submit = $('').appendTo(form); form .bind('ajax:beforeSend', function() { return false; }) .trigger('submit'); App.checkEnabledState(input, 'john'); App.checkEnabledState(button, 'Submit'); App.checkEnabledState(textarea, 'born, lived, died.'); App.checkEnabledState(submit, 'Submit'); start(); }); asyncTest('ctrl-clicking on a link does not disables the link', 6, function() { var link = $('a[data-disable-with]'), e; e = $.Event('click'); e.metaKey = true; App.checkEnabledState(link, 'Click me'); link.trigger(e); App.checkEnabledState(link, 'Click me'); e = $.Event('click'); e.ctrlKey = true; link.trigger(e); App.checkEnabledState(link, 'Click me'); start(); }); asyncTest('button[data-remote][data-disable-with] disables and re-enables', 6, function() { var button = $('button[data-remote][data-disable-with]'); App.checkEnabledState(button, 'Click me'); button .bind('ajax:send', function() { App.checkDisabledState(button, 'clicking...'); }) .bind('ajax:complete', function() { setTimeout( function() { App.checkEnabledState(button, 'Click me'); start(); }, 15); }) .trigger('click'); }); asyncTest('button[data-remote][data-disable-with] re-enables when `ajax:before` event is cancelled', 6, function() { var button = $('button[data-remote][data-disable-with]'); App.checkEnabledState(button, 'Click me'); button .bind('ajax:before', function() { App.checkDisabledState(button, 'clicking...'); return false; }) .trigger('click'); setTimeout(function() { App.checkEnabledState(button, 'Click me'); start(); }, 30); }); asyncTest('button[data-remote][data-disable-with] re-enables when `ajax:beforeSend` event is cancelled', 6, function() { var button = $('button[data-remote][data-disable-with]'); App.checkEnabledState(button, 'Click me'); button .bind('ajax:beforeSend', function() { App.checkDisabledState(button, 'clicking...'); return false; }) .trigger('click'); setTimeout(function() { App.checkEnabledState(button, 'Click me'); start(); }, 30); }); asyncTest('button[data-remote][data-disable-with] re-enables when `ajax:error` event is triggered', 6, function() { var button = $('a[data-disable-with]').attr('data-remote', true).attr('href', '/error'); App.checkEnabledState(button, 'Click me'); button .bind('ajax:send', function() { App.checkDisabledState(button, 'clicking...'); }) .trigger('click'); setTimeout(function() { App.checkEnabledState(button, 'Click me'); start(); }, 30); }); jquery-ujs-1.2.2/test/public/test/data-disable.js 0000664 0000000 0000000 00000022053 12755631514 0021731 0 ustar 00root root 0000000 0000000 module('data-disable', { setup: function() { $('#qunit-fixture').append($('', { action: '/echo', 'data-remote': 'true', method: 'post' })) .find('form') .append($('')); $('#qunit-fixture').append($('', { action: '/echo', method: 'post' })) .find('form:last') // WEEIRDD: the form won't submit to an iframe if the button is name="submit" (??!) .append($('')); $('#qunit-fixture').append($('', { text: 'Click me', href: '/echo', 'data-disable': 'true' })); $('#qunit-fixture').append($('', { text: 'Click me', 'data-remote': true, 'data-url': '/echo', 'data-disable': 'true' })); }, teardown: function() { $(document).unbind('iframe:loaded'); } }); asyncTest('form input field with "data-disable" attribute', 7, function() { var form = $('form[data-remote]'), input = form.find('input[type=text]'); App.checkEnabledState(input, 'john'); form.bind('ajax:success', function(e, data) { setTimeout(function() { App.checkEnabledState(input, 'john'); equal(data.params.user_name, 'john'); start(); }, 13) }) form.trigger('submit'); App.checkDisabledState(input, 'john'); }); asyncTest('form button with "data-disable" attribute', 7, function() { var form = $('form[data-remote]'), button = $(''); form.append(button); App.checkEnabledState(button, 'Submit'); form.bind('ajax:success', function(e, data) { setTimeout(function() { App.checkEnabledState(button, 'Submit'); start(); }, 13) }) form.trigger('submit'); App.checkDisabledState(button, 'Submit'); equal(button.data('ujs:enable-with'), undefined); }); asyncTest('form input[type=submit][data-disable] disables', 6, function(){ var form = $('form:not([data-remote])'), input = form.find('input[type=submit]'); App.checkEnabledState(input, 'Submit'); // WEEIRDD: attaching this handler makes the test work in IE7 $(document).bind('iframe:loading', function(e, form) {}); $(document).bind('iframe:loaded', function(e, data) { setTimeout(function() { App.checkDisabledState(input, 'Submit'); start(); }, 30); }); form.trigger('submit'); setTimeout(function() { App.checkDisabledState(input, 'Submit'); }, 30); }); asyncTest('form[data-remote] input[type=submit][data-disable] is replaced in ajax callback', 2, function(){ var form = $('form:not([data-remote])').attr('data-remote', 'true'), origFormContents = form.html(); form.bind('ajax:success', function(){ form.html(origFormContents); setTimeout(function(){ var input = form.find('input[type=submit]'); App.checkEnabledState(input, 'Submit'); start(); }, 30); }).trigger('submit'); }); asyncTest('form[data-remote] input[data-disable] is replaced with disabled field in ajax callback', 2, function(){ var form = $('form:not([data-remote])').attr('data-remote', 'true'), input = form.find('input[type=submit]'), newDisabledInput = input.clone().attr('disabled', 'disabled'); form.bind('ajax:success', function(){ input.replaceWith(newDisabledInput); setTimeout(function(){ App.checkEnabledState(newDisabledInput, 'Submit'); start(); }, 30); }).trigger('submit'); }); asyncTest('form[data-remote] textarea[data-disable] attribute', 3, function() { var form = $('form[data-remote]'), textarea = $('').appendTo(form); form.bind('ajax:success', function(e, data) { setTimeout(function() { equal(data.params.user_bio, 'born, lived, died.'); start(); }, 13) }) form.trigger('submit'); App.checkDisabledState(textarea, 'born, lived, died.'); }); asyncTest('a[data-disable] disables', 5, function() { var link = $('a[data-disable]'); App.checkEnabledState(link, 'Click me'); link.trigger('click'); App.checkDisabledState(link, 'Click me'); equal(link.data('ujs:enable-with'), undefined); start(); }); asyncTest('a[data-remote][data-disable] disables and re-enables', 6, function() { var link = $('a[data-disable]').attr('data-remote', true); App.checkEnabledState(link, 'Click me'); link .bind('ajax:send', function() { App.checkDisabledState(link, 'Click me'); }) .bind('ajax:complete', function() { setTimeout( function() { App.checkEnabledState(link, 'Click me'); start(); }, 15); }) .trigger('click'); }); asyncTest('a[data-remote][data-disable] re-enables when `ajax:before` event is cancelled', 6, function() { var link = $('a[data-disable]').attr('data-remote', true); App.checkEnabledState(link, 'Click me'); link .bind('ajax:before', function() { App.checkDisabledState(link, 'Click me'); return false; }) .trigger('click'); setTimeout(function() { App.checkEnabledState(link, 'Click me'); start(); }, 30); }); asyncTest('a[data-remote][data-disable] re-enables when `ajax:beforeSend` event is cancelled', 6, function() { var link = $('a[data-disable]').attr('data-remote', true); App.checkEnabledState(link, 'Click me'); link .bind('ajax:beforeSend', function() { App.checkDisabledState(link, 'Click me'); return false; }) .trigger('click'); setTimeout(function() { App.checkEnabledState(link, 'Click me'); start(); }, 30); }); asyncTest('a[data-remote][data-disable] re-enables when `ajax:error` event is triggered', 6, function() { var link = $('a[data-disable]').attr('data-remote', true).attr('href', '/error'); App.checkEnabledState(link, 'Click me'); link .bind('ajax:send', function() { App.checkDisabledState(link, 'Click me'); }) .trigger('click'); setTimeout(function() { App.checkEnabledState(link, 'Click me'); start(); }, 30); }); asyncTest('form[data-remote] input|button|textarea[data-disable] does not disable when `ajax:beforeSend` event is cancelled', 8, function() { var form = $('form[data-remote]'), input = form.find('input:text'), button = $('').appendTo(form), textarea = $('').appendTo(form), submit = $('').appendTo(form); form .bind('ajax:beforeSend', function() { return false; }) .trigger('submit'); App.checkEnabledState(input, 'john'); App.checkEnabledState(button, 'Submit'); App.checkEnabledState(textarea, 'born, lived, died.'); App.checkEnabledState(submit, 'Submit'); start(); }); asyncTest('ctrl-clicking on a link does not disables the link', 6, function() { var link = $('a[data-disable]'), e; e = $.Event('click'); e.metaKey = true; App.checkEnabledState(link, 'Click me'); link.trigger(e); App.checkEnabledState(link, 'Click me'); e = $.Event('click'); e.ctrlKey = true; link.trigger(e); App.checkEnabledState(link, 'Click me'); start(); }); asyncTest('button[data-remote][data-disable] disables and re-enables', 6, function() { var button = $('button[data-remote][data-disable]'); App.checkEnabledState(button, 'Click me'); button .bind('ajax:send', function() { App.checkDisabledState(button, 'Click me'); }) .bind('ajax:complete', function() { setTimeout( function() { App.checkEnabledState(button, 'Click me'); start(); }, 15); }) .trigger('click'); }); asyncTest('button[data-remote][data-disable] re-enables when `ajax:before` event is cancelled', 6, function() { var button = $('button[data-remote][data-disable]'); App.checkEnabledState(button, 'Click me'); button .bind('ajax:before', function() { App.checkDisabledState(button, 'Click me'); return false; }) .trigger('click'); setTimeout(function() { App.checkEnabledState(button, 'Click me'); start(); }, 30); }); asyncTest('button[data-remote][data-disable] re-enables when `ajax:beforeSend` event is cancelled', 6, function() { var button = $('button[data-remote][data-disable]'); App.checkEnabledState(button, 'Click me'); button .bind('ajax:beforeSend', function() { App.checkDisabledState(button, 'Click me'); return false; }) .trigger('click'); setTimeout(function() { App.checkEnabledState(button, 'Click me'); start(); }, 30); }); asyncTest('button[data-remote][data-disable] re-enables when `ajax:error` event is triggered', 6, function() { var button = $('a[data-disable]').attr('data-remote', true).attr('href', '/error'); App.checkEnabledState(button, 'Click me'); button .bind('ajax:send', function() { App.checkDisabledState(button, 'Click me'); }) .trigger('click'); setTimeout(function() { App.checkEnabledState(button, 'Click me'); start(); }, 30); }); jquery-ujs-1.2.2/test/public/test/data-method.js 0000664 0000000 0000000 00000003557 12755631514 0021616 0 ustar 00root root 0000000 0000000 (function(){ module('data-method', { setup: function() { $('#qunit-fixture').append($('', { href: '/echo', 'data-method': 'delete', text: 'destroy!' })); }, teardown: function() { $(document).unbind('iframe:loaded'); } }); function submit(fn, options) { $(document).bind('iframe:loaded', function(e, data) { fn(data); start(); }); $('#qunit-fixture').find('a') .trigger('click'); } asyncTest('link with "data-method" set to "delete"', 3, function() { submit(function(data) { equal(data.REQUEST_METHOD, 'DELETE'); strictEqual(data.params.authenticity_token, undefined); strictEqual(data.HTTP_X_CSRF_TOKEN, undefined); }); }); asyncTest('link with "data-method" and CSRF', 1, function() { $('#qunit-fixture') .append('') .append(''); submit(function(data) { equal(data.params.authenticity_token, 'cf50faa3fe97702ca1ae'); }); }); asyncTest('link "target" should be carried over to generated form', 1, function() { $('a[data-method]').attr('target', 'super-special-frame'); submit(function(data) { equal(data.params._target, 'super-special-frame'); }); }); asyncTest('link with "data-method" and cross origin', 1, function() { var data = {}; $('#qunit-fixture') .append('') .append(''); $(document).on('submit', 'form', function(e) { $(e.currentTarget).serializeArray().map(function(item) { data[item.name] = item.value; }); return false; }); var link = $('#qunit-fixture').find('a'); link.attr('href', 'http://www.alfajango.com'); link.trigger('click'); start(); notEqual(data.authenticity_token, 'cf50faa3fe97702ca1ae'); }); })(); jquery-ujs-1.2.2/test/public/test/data-remote.js 0000664 0000000 0000000 00000026235 12755631514 0021627 0 ustar 00root root 0000000 0000000 module('data-remote', { setup: function() { $('#qunit-fixture') .append($('', { href: '/echo', 'data-remote': 'true', 'data-params': 'data1=value1&data2=value2', text: 'my address' })) .append($('', { 'data-url': '/echo', 'data-remote': 'true', 'data-params': 'data1=value1&data2=value2', text: 'my button' })) .append($('', { action: '/echo', 'data-remote': 'true', method: 'post', id: 'my-remote-form' })) .append($('', { href: '/echo', 'data-remote': 'true', disabled: 'disabled', text: 'Disabed link' })) .find('form').append($('')); } }); asyncTest('ctrl-clicking on a link does not fire ajaxyness', 0, function() { var link = $('a[data-remote]'), e; // Ideally, we'd setup an iframe to intercept normal link clicks // and add a test to make sure the iframe:loaded event is triggered. // However, jquery doesn't actually cause a native `click` event and // follow links using `trigger('click')`, it only fires bindings. link .removeAttr('data-params') .bind('ajax:beforeSend', function() { ok(false, 'ajax should not be triggered'); }); e = $.Event('click'); e.metaKey = true; link.trigger(e); e = $.Event('click'); e.ctrlKey = true; link.trigger(e); setTimeout(function(){ start(); }, 13); }); asyncTest('ctrl-clicking on a link still fires ajax for non-GET links and for links with "data-params"', 2, function() { var link = $('a[data-remote]'), e; e = $.Event('click'); e.metaKey = true; link .removeAttr('data-params') .attr('data-method', 'POST') .bind('ajax:beforeSend', function() { ok(true, 'ajax should be triggered'); }) .trigger(e); e = $.Event('click'); e.metaKey = true; link .removeAttr('data-method') .attr('data-params', 'name=steve') .trigger(e); setTimeout(function(){ start(); }, 13); }); asyncTest('clicking on a link with data-remote attribute', 5, function() { $('a[data-remote]') .bind('ajax:success', function(e, data, status, xhr) { App.assertCallbackInvoked('ajax:success'); App.assertRequestPath(data, '/echo'); equal(data.params.data1, 'value1', 'ajax arguments should have key data1 with right value'); equal(data.params.data2, 'value2', 'ajax arguments should have key data2 with right value'); App.assertGetRequest(data); }) .bind('ajax:complete', function() { start() }) .trigger('click'); }); asyncTest('clicking on a link with disabled attribute', 0, function() { $('a[disabled]') .bind("ajax:before", function(e, data, status, xhr) { App.assertCallbackNotInvoked('ajax:success') }) .bind('ajax:complete', function() { start() }) .trigger('click') setTimeout(function() { start(); }, 13); }); asyncTest('clicking on a button with data-remote attribute', 5, function() { $('button[data-remote]') .bind('ajax:success', function(e, data, status, xhr) { App.assertCallbackInvoked('ajax:success'); App.assertRequestPath(data, '/echo'); equal(data.params.data1, 'value1', 'ajax arguments should have key data1 with right value'); equal(data.params.data2, 'value2', 'ajax arguments should have key data2 with right value'); App.assertGetRequest(data); }) .bind('ajax:complete', function() { start() }) .trigger('click'); }); asyncTest('changing a select option with data-remote attribute', 5, function() { $('form') .append( $('', { 'name': 'user_data', 'data-remote': 'true', 'data-params': 'data1=value1', 'data-url': '/echo' }) .append($('', {value: 'optionValue1', text: 'option1'})) .append($('', {value: 'optionValue2', text: 'option2'})) ); $('select[data-remote]') .bind('ajax:success', function(e, data, status, xhr) { App.assertCallbackInvoked('ajax:success'); App.assertRequestPath(data, '/echo'); equal(data.params.user_data, 'optionValue2', 'ajax arguments should have key term with right value'); equal(data.params.data1, 'value1', 'ajax arguments should have key data1 with right value'); App.assertGetRequest(data); }) .bind('ajax:complete', function() { start() }) .val('optionValue2') .trigger('change'); }); asyncTest('submitting form with data-remote attribute', 4, function() { $('form[data-remote]') .bind('ajax:success', function(e, data, status, xhr) { App.assertCallbackInvoked('ajax:success'); App.assertRequestPath(data, '/echo'); equal(data.params.user_name, 'john', 'ajax arguments should have key user_name with right value'); App.assertPostRequest(data); }) .bind('ajax:complete', function() { start() }) .trigger('submit'); }); asyncTest('submitting form with data-remote attribute should include inputs in a fieldset only once', 3, function() { $('form[data-remote]') .append('') .bind('ajax:success', function(e, data, status, xhr) { App.assertCallbackInvoked('ajax:success'); equal(data.params.items.length, 1, 'ajax arguments should only have the item once') App.assertPostRequest(data); }) .bind('ajax:complete', function() { $('form[data-remote], fieldset').remove() start() }) .trigger('submit'); }); asyncTest('submitting form with data-remote attribute submits input with matching [form] attribute', 5, function() { $('#qunit-fixture') .append($('')); $('form[data-remote]') .bind('ajax:success', function(e, data, status, xhr) { App.assertCallbackInvoked('ajax:success'); App.assertRequestPath(data, '/echo'); equal(data.params.user_name, 'john', 'ajax arguments should have key user_name with right value'); equal(data.params.user_data, 'value1', 'ajax arguments should have key user_data with right value'); App.assertPostRequest(data); }) .bind('ajax:complete', function() { start() }) .trigger('submit'); }); asyncTest('submitting form with data-remote attribute by clicking button with matching [form] attribute', 5, function() { $('form[data-remote]') .bind('ajax:success', function(e, data, status, xhr) { App.assertCallbackInvoked('ajax:success'); App.assertRequestPath(data, '/echo'); equal(data.params.user_name, 'john', 'ajax arguments should have key user_name with right value'); equal(data.params.user_data, 'value2', 'ajax arguments should have key user_data with right value'); App.assertPostRequest(data); }) .bind('ajax:complete', function() { start() }); $('', { type: "submit", name: "user_data", value: "value1", form: "my-remote-form" }) .appendTo($('#qunit-fixture')); $('', { type: "submit", name: "user_data", value: "value2", form: "my-remote-form" }) .appendTo($('#qunit-fixture')) .trigger('click'); }); asyncTest('form\'s submit bindings in browsers that don\'t support submit bubbling', 5, function() { var form = $('form[data-remote]'), directBindingCalled = false; ok(!directBindingCalled, 'nothing is called'); form .append($('')) .bind('submit', function(event){ ok(event.type == 'submit', 'submit event handlers are called with submit event'); ok(true, 'binding handler is called'); directBindingCalled = true; }) .bind('ajax:beforeSend', function(){ ok(true, 'form being submitted via ajax'); ok(directBindingCalled, 'binding handler already called'); }) .bind('ajax:complete', function(){ start(); }); if(!$.support.submitBubbles) { // Must indrectly submit form via click to trigger jQuery's manual submit bubbling in IE form.find('input[type=submit]') .trigger('click'); } else { form.trigger('submit'); } }); asyncTest('returning false in form\'s submit bindings in non-submit-bubbling browsers', 1, function(){ var form = $('form[data-remote]'); form .append($('')) .bind('submit', function(){ ok(true, 'binding handler is called'); return false; }) .bind('ajax:beforeSend', function(){ ok(false, 'form should not be submitted'); }); if (!$.support.submitBubbles) { // Must indrectly submit form via click to trigger jQuery's manual submit bubbling in IE form.find('input[type=submit]').trigger('click'); } else { form.trigger('submit'); } setTimeout(function(){ start(); }, 13); }); asyncTest('clicking on a link with falsy "data-remote" attribute does not fire ajaxyness', 0, function() { $('a[data-remote]') .attr('data-remote', 'false') .bind('ajax:beforeSend', function() { ok(false, 'ajax should not be triggered'); }) .bind('click', function() { return false; }) .trigger('click'); setTimeout(function(){ start(); }, 20); }); asyncTest('ctrl-clicking on a link with falsy "data-remote" attribute does not fire ajaxyness even if "data-params" present', 0, function() { var link = $('a[data-remote]'), e; e = $.Event('click'); e.metaKey = true; link .removeAttr('data-params') .attr('data-remote', 'false') .attr('data-method', 'POST') .bind('ajax:beforeSend', function() { ok(false, 'ajax should not be triggered'); }) .bind('click', function() { return false; }) .trigger(e); e = $.Event('click'); e.metaKey = true; link .removeAttr('data-method') .attr('data-params', 'name=steve') .trigger(e); setTimeout(function(){ start(); }, 20); }); asyncTest('clicking on a button with falsy "data-remote" attribute', 0, function() { $('button[data-remote]:first') .attr('data-remote', 'false') .bind('ajax:beforeSend', function() { ok(false, 'ajax should not be triggered'); }) .bind('click', function() { return false; }) .trigger('click'); setTimeout(function(){ start(); }, 20); }); asyncTest('submitting a form with falsy "data-remote" attribute', 0, function() { $('form[data-remote]:first') .attr('data-remote', 'false') .bind('ajax:beforeSend', function() { ok(false, 'ajax should not be triggered'); }) .bind('submit', function() { return false; }) .trigger('submit'); setTimeout(function(){ start(); }, 20); }); asyncTest('changing a select option with falsy "data-remote" attribute', 0, function() { $('form') .append( $('', { 'name': 'user_data', 'data-remote': 'false', 'data-params': 'data1=value1', 'data-url': '/echo' }) .append($('', {value: 'optionValue1', text: 'option1'})) .append($('', {value: 'optionValue2', text: 'option2'})) ); $('select[data-remote=false]:first') .bind('ajax:beforeSend', function() { ok(false, 'ajax should not be triggered'); }) .val('optionValue2') .trigger('change'); setTimeout(function(){ start(); }, 20); }); jquery-ujs-1.2.2/test/public/test/override.js 0000664 0000000 0000000 00000004235 12755631514 0021240 0 ustar 00root root 0000000 0000000 (function(){ module('override', { setup: function() { window.realHref = $.rails.href; $('#qunit-fixture') .append($('', { href: '/real/href', 'data-method': 'delete', 'data-href': '/data/href' })) .append($('', { href: '/other/href', 'data-custom-remote-link': 'true' })); }, teardown: function() { $.rails.href = window.realHref; } }); asyncTest("the getter for an element's href is publicly accessible", 1, function() { ok($.rails.href); start(); }); asyncTest("the getter for an element's href is overridable", 1, function() { $.rails.href = function(element) { return element.data('href'); } $.rails.ajax = function(options) { equal('/data/href', options.url); } $.rails.handleRemote($('#qunit-fixture').find('a')); start(); }); asyncTest("the getter for an element's href works normally if not overridden", 1, function() { $.rails.ajax = function(options) { equal(location.protocol + '//' + location.host + '/real/href', options.url); } $.rails.handleRemote($('#qunit-fixture').find('a')); start(); }); asyncTest("the event selector strings are overridable", 2, function() { var documentClickBindings = $._data(document, 'events').click, linkClickBinding = $.grep(documentClickBindings, function(a) { return a.selector && a.selector.indexOf('a[data-remote]') != -1; })[0]; ok($.rails.linkClickSelector.indexOf(', a[data-custom-remote-link]') != -1, 'linkClickSelector contains custom selector'); ok(linkClickBinding.selector.indexOf(', a[data-custom-remote-link]') != -1, 'actual document binding contains custom selector'); start(); }); // Not sure why this test isn't working in jquery 1.7, // or why the error message doesn't show in the console in 1.8 // when the test is run. // //asyncTest("including jquery-ujs multiple times throws error", 1, function() { // var script = document.createElement( 'script' ); // script.type = 'text/javascript'; // script.src = '/src/rails.js'; // raises(function() { // $("#qunit-fixture").append( script ); // }, 'appending rails.js again throws error'); // setTimeout(function() { start(); }, 50); //}); })(); jquery-ujs-1.2.2/test/public/test/settings.js 0000664 0000000 0000000 00000003723 12755631514 0021262 0 ustar 00root root 0000000 0000000 var App = App || {}; App.assertCallbackInvoked = function(callbackName) { ok(true, callbackName + ' callback should have been invoked'); }; App.assertCallbackNotInvoked = function(callbackName) { ok(false, callbackName + ' callback should not have been invoked'); }; App.assertGetRequest = function(requestEnv){ equal(requestEnv['REQUEST_METHOD'], 'GET', 'request type should be GET'); }; App.assertPostRequest = function(requestEnv){ equal(requestEnv['REQUEST_METHOD'], 'POST', 'request type should be POST'); }; App.assertRequestPath = function(requestEnv, path) { equal(requestEnv['PATH_INFO'], path, 'request should be sent to right url'); }; App.getVal = function(el) { return el.is('input,textarea,select') ? el.val() : el.text(); }; App.disabled = function(el) { return el.is('input,textarea,select,button') ? (el.is(':disabled') && el.data('ujs:disabled')) : el.data('ujs:disabled'); }; App.checkEnabledState = function(el, text) { ok(!App.disabled(el), el.get(0).tagName + ' should not be disabled'); equal(App.getVal(el), text, el.get(0).tagName + ' text should be original value'); }; App.checkDisabledState = function(el, text) { ok(App.disabled(el), el.get(0).tagName + ' should be disabled'); equal(App.getVal(el), text, el.get(0).tagName + ' text should be disabled value'); }; // hijacks normal form submit; lets it submit to an iframe to prevent // navigating away from the test suite $(document).bind('submit', function(e) { if (!e.isDefaultPrevented()) { var form = $(e.target), action = form.attr('action'), name = 'form-frame' + jQuery.guid++, iframe = $(''), targetInput = ''; if (action && action.indexOf('iframe') < 0) form.attr('action', action + '?iframe=true') form.attr('target', name).append(targetInput); $('#qunit-fixture').append(iframe); $.event.trigger('iframe:loading', form); } }); jquery-ujs-1.2.2/test/public/vendor/ 0000775 0000000 0000000 00000000000 12755631514 0017375 5 ustar 00root root 0000000 0000000 jquery-ujs-1.2.2/test/public/vendor/jquery.metadata.js 0000664 0000000 0000000 00000007563 12755631514 0023044 0 ustar 00root root 0000000 0000000 /* * Metadata - jQuery plugin for parsing metadata from elements * * Copyright (c) 2006 John Resig, Yehuda Katz, J�örn Zaefferer, Paul McLanahan * * Dual licensed under the MIT and GPL licenses: * http://www.opensource.org/licenses/mit-license.php * http://www.gnu.org/licenses/gpl.html * * Revision: $Id: jquery.metadata.js 4187 2007-12-16 17:15:27Z joern.zaefferer $ * */ /** * Sets the type of metadata to use. Metadata is encoded in JSON, and each property * in the JSON will become a property of the element itself. * * There are three supported types of metadata storage: * * attr: Inside an attribute. The name parameter indicates *which* attribute. * * class: Inside the class attribute, wrapped in curly braces: { } * * elem: Inside a child element (e.g. a script tag). The * name parameter indicates *which* element. * * The metadata for an element is loaded the first time the element is accessed via jQuery. * * As a result, you can define the metadata type, use $(expr) to load the metadata into the elements * matched by expr, then redefine the metadata type and run another $(expr) for other elements. * * @name $.metadata.setType * * @exampleThis is a p
* @before $.metadata.setType("class") * @after $("#one").metadata().item_id == 1; $("#one").metadata().item_label == "Label" * @desc Reads metadata from the class attribute * * @exampleThis is a p
* @before $.metadata.setType("attr", "data") * @after $("#one").metadata().item_id == 1; $("#one").metadata().item_label == "Label" * @desc Reads metadata from a "data" attribute * * @exampleThis is a p
* @before $.metadata.setType("elem", "script") * @after $("#one").metadata().item_id == 1; $("#one").metadata().item_label == "Label" * @desc Reads metadata from a nested script element * * @param String type The encoding type * @param String name The name of the attribute to be used to get metadata (optional) * @cat Plugins/Metadata * @descr Sets the type of encoding to be used when loading metadata for the first time * @type undefined * @see metadata() */ (function($) { $.extend({ metadata : { defaults : { type: 'class', name: 'metadata', cre: /({.*})/, single: 'metadata' }, setType: function( type, name ){ this.defaults.type = type; this.defaults.name = name; }, get: function( elem, opts ){ var settings = $.extend({},this.defaults,opts); // check for empty string in single property if ( !settings.single.length ) settings.single = 'metadata'; var data = $.data(elem, settings.single); // returned cached data if it already exists if ( data ) return data; data = "{}"; if ( settings.type == "class" ) { var m = settings.cre.exec( elem.className ); if ( m ) data = m[1]; } else if ( settings.type == "elem" ) { if( !elem.getElementsByTagName ) return undefined; var e = elem.getElementsByTagName(settings.name); if ( e.length ) data = $.trim(e[0].innerHTML); } else if ( elem.getAttribute != undefined ) { var attr = elem.getAttribute( settings.name ); if ( attr ) data = attr; } if ( data.indexOf( '{' ) <0 ) data = "{" + data + "}"; data = eval("(" + data + ")"); $.data( elem, settings.single, data ); return data; } } }); /** * Returns the metadata object for the first member of the jQuery object. * * @name metadata * @descr Returns element's metadata object * @param Object opts An object contianing settings to override the defaults * @type jQuery * @cat Plugins/Metadata */ $.fn.metadata = function( opts ){ return $.metadata.get( this[0], opts ); }; })(jQuery); jquery-ujs-1.2.2/test/public/vendor/qunit.css 0000664 0000000 0000000 00000010412 12755631514 0021245 0 ustar 00root root 0000000 0000000 /*! * QUnit 1.14.0 * http://qunitjs.com/ * * Copyright 2013 jQuery Foundation and other contributors * Released under the MIT license * http://jquery.org/license * * Date: 2014-01-31T16:40Z */ /** Font Family and Sizes */ #qunit-tests, #qunit-header, #qunit-banner, #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult { font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif; } #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult, #qunit-tests li { font-size: small; } #qunit-tests { font-size: smaller; } /** Resets */ #qunit-tests, #qunit-header, #qunit-banner, #qunit-userAgent, #qunit-testresult, #qunit-modulefilter { margin: 0; padding: 0; } /** Header */ #qunit-header { padding: 0.5em 0 0.5em 1em; color: #8699A4; background-color: #0D3349; font-size: 1.5em; line-height: 1em; font-weight: 400; border-radius: 5px 5px 0 0; } #qunit-header a { text-decoration: none; color: #C2CCD1; } #qunit-header a:hover, #qunit-header a:focus { color: #FFF; } #qunit-testrunner-toolbar label { display: inline-block; padding: 0 0.5em 0 0.1em; } #qunit-banner { height: 5px; } #qunit-testrunner-toolbar { padding: 0.5em 0 0.5em 2em; color: #5E740B; background-color: #EEE; overflow: hidden; } #qunit-userAgent { padding: 0.5em 0 0.5em 2.5em; background-color: #2B81AF; color: #FFF; text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px; } #qunit-modulefilter-container { float: right; } /** Tests: Pass/Fail */ #qunit-tests { list-style-position: inside; } #qunit-tests li { padding: 0.4em 0.5em 0.4em 2.5em; border-bottom: 1px solid #FFF; list-style-position: inside; } #qunit-tests.hidepass li.pass, #qunit-tests.hidepass li.running { display: none; } #qunit-tests li strong { cursor: pointer; } #qunit-tests li a { padding: 0.5em; color: #C2CCD1; text-decoration: none; } #qunit-tests li a:hover, #qunit-tests li a:focus { color: #000; } #qunit-tests li .runtime { float: right; font-size: smaller; } .qunit-assert-list { margin-top: 0.5em; padding: 0.5em; background-color: #FFF; border-radius: 5px; } .qunit-collapsed { display: none; } #qunit-tests table { border-collapse: collapse; margin-top: 0.2em; } #qunit-tests th { text-align: right; vertical-align: top; padding: 0 0.5em 0 0; } #qunit-tests td { vertical-align: top; } #qunit-tests pre { margin: 0; white-space: pre-wrap; word-wrap: break-word; } #qunit-tests del { background-color: #E0F2BE; color: #374E0C; text-decoration: none; } #qunit-tests ins { background-color: #FFCACA; color: #500; text-decoration: none; } /*** Test Counts */ #qunit-tests b.counts { color: #000; } #qunit-tests b.passed { color: #5E740B; } #qunit-tests b.failed { color: #710909; } #qunit-tests li li { padding: 5px; background-color: #FFF; border-bottom: none; list-style-position: inside; } /*** Passing Styles */ #qunit-tests li li.pass { color: #3C510C; background-color: #FFF; border-left: 10px solid #C6E746; } #qunit-tests .pass { color: #528CE0; background-color: #D2E0E6; } #qunit-tests .pass .test-name { color: #366097; } #qunit-tests .pass .test-actual, #qunit-tests .pass .test-expected { color: #999; } #qunit-banner.qunit-pass { background-color: #C6E746; } /*** Failing Styles */ #qunit-tests li li.fail { color: #710909; background-color: #FFF; border-left: 10px solid #EE5757; white-space: pre; } #qunit-tests > li:last-child { border-radius: 0 0 5px 5px; } #qunit-tests .fail { color: #000; background-color: #EE5757; } #qunit-tests .fail .test-name, #qunit-tests .fail .module-name { color: #000; } #qunit-tests .fail .test-actual { color: #EE5757; } #qunit-tests .fail .test-expected { color: #008000; } #qunit-banner.qunit-fail { background-color: #EE5757; } /** Result */ #qunit-testresult { padding: 0.5em 0.5em 0.5em 2.5em; color: #2B81AF; background-color: #D2E0E6; border-bottom: 1px solid #FFF; } #qunit-testresult .module-name { font-weight: 700; } /** Fixture */ #qunit-fixture { position: absolute; top: -10000px; left: -10000px; width: 1000px; height: 1000px; } jquery-ujs-1.2.2/test/public/vendor/qunit.js 0000664 0000000 0000000 00000167151 12755631514 0021106 0 ustar 00root root 0000000 0000000 /*! * QUnit 1.14.0 * http://qunitjs.com/ * * Copyright 2013 jQuery Foundation and other contributors * Released under the MIT license * http://jquery.org/license * * Date: 2014-01-31T16:40Z */ (function( window ) { var QUnit, assert, config, onErrorFnPrev, testId = 0, fileName = (sourceFromStacktrace( 0 ) || "" ).replace(/(:\d+)+\)?/, "").replace(/.+\//, ""), toString = Object.prototype.toString, hasOwn = Object.prototype.hasOwnProperty, // Keep a local reference to Date (GH-283) Date = window.Date, setTimeout = window.setTimeout, clearTimeout = window.clearTimeout, defined = { document: typeof window.document !== "undefined", setTimeout: typeof window.setTimeout !== "undefined", sessionStorage: (function() { var x = "qunit-test-string"; try { sessionStorage.setItem( x, x ); sessionStorage.removeItem( x ); return true; } catch( e ) { return false; } }()) }, /** * Provides a normalized error string, correcting an issue * with IE 7 (and prior) where Error.prototype.toString is * not properly implemented * * Based on http://es5.github.com/#x15.11.4.4 * * @param {String|Error} error * @return {String} error message */ errorString = function( error ) { var name, message, errorString = error.toString(); if ( errorString.substring( 0, 7 ) === "[object" ) { name = error.name ? error.name.toString() : "Error"; message = error.message ? error.message.toString() : ""; if ( name && message ) { return name + ": " + message; } else if ( name ) { return name; } else if ( message ) { return message; } else { return "Error"; } } else { return errorString; } }, /** * Makes a clone of an object using only Array or Object as base, * and copies over the own enumerable properties. * * @param {Object} obj * @return {Object} New object with only the own properties (recursively). */ objectValues = function( obj ) { // Grunt 0.3.x uses an older version of jshint that still has jshint/jshint#392. /*jshint newcap: false */ var key, val, vals = QUnit.is( "array", obj ) ? [] : {}; for ( key in obj ) { if ( hasOwn.call( obj, key ) ) { val = obj[key]; vals[key] = val === Object(val) ? objectValues(val) : val; } } return vals; }; // Root QUnit object. // `QUnit` initialized at top of scope QUnit = { // call on start of module test to prepend name to all tests module: function( name, testEnvironment ) { config.currentModule = name; config.currentModuleTestEnvironment = testEnvironment; config.modules[name] = true; }, asyncTest: function( testName, expected, callback ) { if ( arguments.length === 2 ) { callback = expected; expected = null; } QUnit.test( testName, expected, callback, true ); }, test: function( testName, expected, callback, async ) { var test, nameHtml = "" + escapeText( testName ) + ""; if ( arguments.length === 2 ) { callback = expected; expected = null; } if ( config.currentModule ) { nameHtml = "" + escapeText( config.currentModule ) + ": " + nameHtml; } test = new Test({ nameHtml: nameHtml, testName: testName, expected: expected, async: async, callback: callback, module: config.currentModule, moduleTestEnvironment: config.currentModuleTestEnvironment, stack: sourceFromStacktrace( 2 ) }); if ( !validTest( test ) ) { return; } test.queue(); }, // Specify the number of expected assertions to guarantee that failed test (no assertions are run at all) don't slip through. expect: function( asserts ) { if (arguments.length === 1) { config.current.expected = asserts; } else { return config.current.expected; } }, start: function( count ) { // QUnit hasn't been initialized yet. // Note: RequireJS (et al) may delay onLoad if ( config.semaphore === undefined ) { QUnit.begin(function() { // This is triggered at the top of QUnit.load, push start() to the event loop, to allow QUnit.load to finish first setTimeout(function() { QUnit.start( count ); }); }); return; } config.semaphore -= count || 1; // don't start until equal number of stop-calls if ( config.semaphore > 0 ) { return; } // ignore if start is called more often then stop if ( config.semaphore < 0 ) { config.semaphore = 0; QUnit.pushFailure( "Called start() while already started (QUnit.config.semaphore was 0 already)", null, sourceFromStacktrace(2) ); return; } // A slight delay, to avoid any current callbacks if ( defined.setTimeout ) { setTimeout(function() { if ( config.semaphore > 0 ) { return; } if ( config.timeout ) { clearTimeout( config.timeout ); } config.blocking = false; process( true ); }, 13); } else { config.blocking = false; process( true ); } }, stop: function( count ) { config.semaphore += count || 1; config.blocking = true; if ( config.testTimeout && defined.setTimeout ) { clearTimeout( config.timeout ); config.timeout = setTimeout(function() { QUnit.ok( false, "Test timed out" ); config.semaphore = 1; QUnit.start(); }, config.testTimeout ); } } }; // We use the prototype to distinguish between properties that should // be exposed as globals (and in exports) and those that shouldn't (function() { function F() {} F.prototype = QUnit; QUnit = new F(); // Make F QUnit's constructor so that we can add to the prototype later QUnit.constructor = F; }()); /** * Config object: Maintain internal state * Later exposed as QUnit.config * `config` initialized at top of scope */ config = { // The queue of tests to run queue: [], // block until document ready blocking: true, // when enabled, show only failing tests // gets persisted through sessionStorage and can be changed in UI via checkbox hidepassed: false, // by default, run previously failed tests first // very useful in combination with "Hide passed tests" checked reorder: true, // by default, modify document.title when suite is done altertitle: true, // by default, scroll to top of the page when suite is done scrolltop: true, // when enabled, all tests must call expect() requireExpects: false, // add checkboxes that are persisted in the query-string // when enabled, the id is set to `true` as a `QUnit.config` property urlConfig: [ { id: "noglobals", label: "Check for Globals", tooltip: "Enabling this will test if any test introduces new properties on the `window` object. Stored as query-strings." }, { id: "notrycatch", label: "No try-catch", tooltip: "Enabling this will run tests outside of a try-catch block. Makes debugging exceptions in IE reasonable. Stored as query-strings." } ], // Set of all modules. modules: {}, // logging callback queues begin: [], done: [], log: [], testStart: [], testDone: [], moduleStart: [], moduleDone: [] }; // Initialize more QUnit.config and QUnit.urlParams (function() { var i, current, location = window.location || { search: "", protocol: "file:" }, params = location.search.slice( 1 ).split( "&" ), length = params.length, urlParams = {}; if ( params[ 0 ] ) { for ( i = 0; i < length; i++ ) { current = params[ i ].split( "=" ); current[ 0 ] = decodeURIComponent( current[ 0 ] ); // allow just a key to turn on a flag, e.g., test.html?noglobals current[ 1 ] = current[ 1 ] ? decodeURIComponent( current[ 1 ] ) : true; if ( urlParams[ current[ 0 ] ] ) { urlParams[ current[ 0 ] ] = [].concat( urlParams[ current[ 0 ] ], current[ 1 ] ); } else { urlParams[ current[ 0 ] ] = current[ 1 ]; } } } QUnit.urlParams = urlParams; // String search anywhere in moduleName+testName config.filter = urlParams.filter; // Exact match of the module name config.module = urlParams.module; config.testNumber = []; if ( urlParams.testNumber ) { // Ensure that urlParams.testNumber is an array urlParams.testNumber = [].concat( urlParams.testNumber ); for ( i = 0; i < urlParams.testNumber.length; i++ ) { current = urlParams.testNumber[ i ]; config.testNumber.push( parseInt( current, 10 ) ); } } // Figure out if we're running the tests from a server or not QUnit.isLocal = location.protocol === "file:"; }()); extend( QUnit, { config: config, // Initialize the configuration options init: function() { extend( config, { stats: { all: 0, bad: 0 }, moduleStats: { all: 0, bad: 0 }, started: +new Date(), updateRate: 1000, blocking: false, autostart: true, autorun: false, filter: "", queue: [], semaphore: 1 }); var tests, banner, result, qunit = id( "qunit" ); if ( qunit ) { qunit.innerHTML = "Expected: | " + expected + " |
---|---|
Result: | " + actual + " |
Diff: | " + QUnit.diff( expected, actual ) + " |
Source: | " + escapeText( source ) + " |
Result: | " + escapeText( actual ) + " |
---|---|
Source: | " + escapeText( source ) + " |
Source: | " + escapeText( source ) + " |
---|
You shouldn't be seeing this. Go back
HTML else content_type 'text/plain' status 400 "ERROR: #{request.path} requested without ajax" end } end get '/error' do status 403 end jquery-ujs-1.2.2/test/views/ 0000775 0000000 0000000 00000000000 12755631514 0015757 5 ustar 00root root 0000000 0000000 jquery-ujs-1.2.2/test/views/index.erb 0000664 0000000 0000000 00000001417 12755631514 0017563 0 ustar 00root root 0000000 0000000 <% @title = "jquery-ujs test" %> <%= test 'data-confirm', 'data-remote', 'data-disable', 'data-disable-with', 'call-remote', 'call-remote-callbacks', 'data-method', 'override', 'csrf-refresh', 'csrf-token' %>