iqjax 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/LICENSE +13 -0
 - data/README.md +41 -0
 - data/Rakefile +10 -0
 - data/iqjax.gemspec +21 -0
 - data/iqjax.js +200 -0
 - data/lib/iqjax.rb +2 -0
 - data/lib/iqjax/engine.rb +5 -0
 - data/lib/iqjax/version.rb +4 -0
 - data/test/index.html +55 -0
 - data/test/lib/jquery.mockjax.js +382 -0
 - data/test/lib/qunit.css +226 -0
 - data/test/lib/qunit.js +1597 -0
 - data/test/lib/run-qunit.js +90 -0
 - data/test/test.rb +36 -0
 - data/test/tests.js +175 -0
 - data/vendor/assets/javascripts/iqjax.js +200 -0
 - data/vendor/jquery_ujs.js +367 -0
 - metadata +128 -0
 
    
        data/LICENSE
    ADDED
    
    | 
         @@ -0,0 +1,13 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            Copyright 2011 innoQ Deutschland GmbH
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            Licensed under the Apache License, Version 2.0 (the "License");
         
     | 
| 
      
 4 
     | 
    
         
            +
            you may not use this file except in compliance with the License.
         
     | 
| 
      
 5 
     | 
    
         
            +
            You may obtain a copy of the License at
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
                http://www.apache.org/licenses/LICENSE-2.0
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
            Unless required by applicable law or agreed to in writing, software
         
     | 
| 
      
 10 
     | 
    
         
            +
            distributed under the License is distributed on an "AS IS" BASIS,
         
     | 
| 
      
 11 
     | 
    
         
            +
            WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
         
     | 
| 
      
 12 
     | 
    
         
            +
            See the License for the specific language governing permissions and
         
     | 
| 
      
 13 
     | 
    
         
            +
            limitations under the License.
         
     | 
    
        data/README.md
    ADDED
    
    | 
         @@ -0,0 +1,41 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            iQjax
         
     | 
| 
      
 2 
     | 
    
         
            +
            =====
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
            This is an unobtrusive JavaScript component for doing Ajax in conformity 
         
     | 
| 
      
 5 
     | 
    
         
            +
            with the [ROCA-Style](http://roca-style.org). It enables your web application 
         
     | 
| 
      
 6 
     | 
    
         
            +
            to do Ajax without bigger impacts to your server side. 
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
            An iQjax enabled DOM node loads the target of annotated links it contains into a 
         
     | 
| 
      
 9 
     | 
    
         
            +
            specific container DOM node. This is done asynchronously via Ajax. If the 
         
     | 
| 
      
 10 
     | 
    
         
            +
            content contains a form, the form handling (especially error handling) will be 
         
     | 
| 
      
 11 
     | 
    
         
            +
            automatically done in the container too. After a form was successfully submitted, 
         
     | 
| 
      
 12 
     | 
    
         
            +
            iQjax provides methods to update the iQjax container without reloading the whole 
         
     | 
| 
      
 13 
     | 
    
         
            +
            page.
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
            E.g. given a iQjax enabled list of person names with links pointing to a
         
     | 
| 
      
 16 
     | 
    
         
            +
            form to edit the respective person name. Clicking on such a link will
         
     | 
| 
      
 17 
     | 
    
         
            +
            load the form to a given container DOM node. After submitting the form 
         
     | 
| 
      
 18 
     | 
    
         
            +
            with a changed name, the user would expect the list of names to be updated.
         
     | 
| 
      
 19 
     | 
    
         
            +
            iQjax can do this by searching the new list entry in the response of
         
     | 
| 
      
 20 
     | 
    
         
            +
            the form POST. Then it replaces the old node with the new one.
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
            Documentation
         
     | 
| 
      
 23 
     | 
    
         
            +
            -------------
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
            We distinguish six API parts of ROCA-Style JavaScript components:
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
            # The socket HTML markup the component initializes upon,
         
     | 
| 
      
 28 
     | 
    
         
            +
            # the constructor method together with it's parameters,
         
     | 
| 
      
 29 
     | 
    
         
            +
            # methods callable upon the component,
         
     | 
| 
      
 30 
     | 
    
         
            +
            # events triggered by the component,
         
     | 
| 
      
 31 
     | 
    
         
            +
            # HTML markup the component generates and
         
     | 
| 
      
 32 
     | 
    
         
            +
            # Ajax-Requests the component fires.
         
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
            ### Socket markup
         
     | 
| 
      
 35 
     | 
    
         
            +
             
     | 
| 
      
 36 
     | 
    
         
            +
            iQjax must be initialized on a DOM node with a `data-iqjax` attribute set. 
         
     | 
| 
      
 37 
     | 
    
         
            +
            The attribute must contain a selector for the container the Ajax-response 
         
     | 
| 
      
 38 
     | 
    
         
            +
            should be put in.
         
     | 
| 
      
 39 
     | 
    
         
            +
             
     | 
| 
      
 40 
     | 
    
         
            +
             
     | 
| 
      
 41 
     | 
    
         
            +
            ... TO BE DONE ...
         
     | 
    
        data/Rakefile
    ADDED
    
    
    
        data/iqjax.gemspec
    ADDED
    
    | 
         @@ -0,0 +1,21 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require File.expand_path('../lib/iqjax/version', __FILE__)
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            Gem::Specification.new do |s|
         
     | 
| 
      
 4 
     | 
    
         
            +
              s.name        = "iqjax"
         
     | 
| 
      
 5 
     | 
    
         
            +
              s.version     = Iqjax::VERSION
         
     | 
| 
      
 6 
     | 
    
         
            +
              s.platform    = Gem::Platform::RUBY
         
     | 
| 
      
 7 
     | 
    
         
            +
              s.authors     = ["FND", "Till Schulte-Coerne"]
         
     | 
| 
      
 8 
     | 
    
         
            +
              s.email       = ["", "till.schulte-coerne@innoq.com"]
         
     | 
| 
      
 9 
     | 
    
         
            +
              s.homepage    = "http://github.com/innoq/iqjax"
         
     | 
| 
      
 10 
     | 
    
         
            +
              s.summary     = "iQjax - a JS library for real unobtrusive Ajax"
         
     | 
| 
      
 11 
     | 
    
         
            +
              s.description = s.summary
         
     | 
| 
      
 12 
     | 
    
         
            +
              s.extra_rdoc_files = ['README.md', 'LICENSE']
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
              s.add_dependency "bundler"
         
     | 
| 
      
 15 
     | 
    
         
            +
              s.add_dependency "railties", ">= 3.2.0", "< 5.0"
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
              s.files = %w(LICENSE README.md Rakefile iqjax.gemspec iqjax.js) + Dir.glob("{lib,vendor,test}/**/*")
         
     | 
| 
      
 18 
     | 
    
         
            +
              s.test_files = Dir.glob("{test}/**/*")
         
     | 
| 
      
 19 
     | 
    
         
            +
              
         
     | 
| 
      
 20 
     | 
    
         
            +
               s.require_path = 'lib'
         
     | 
| 
      
 21 
     | 
    
         
            +
            end
         
     | 
    
        data/iqjax.js
    ADDED
    
    | 
         @@ -0,0 +1,200 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            /*jslint vars: true, unparam: true, browser: true, white: true */
         
     | 
| 
      
 2 
     | 
    
         
            +
            /*global jQuery */
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
            /* Copyright 2012 innoQ Deutschland GmbH
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
            Licensed under the Apache License, Version 2.0 (the "License");
         
     | 
| 
      
 7 
     | 
    
         
            +
            you may not use this file except in compliance with the License.
         
     | 
| 
      
 8 
     | 
    
         
            +
            You may obtain a copy of the License at
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
                 http://www.apache.org/licenses/LICENSE-2.0
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
            Unless required by applicable law or agreed to in writing, software
         
     | 
| 
      
 13 
     | 
    
         
            +
            distributed under the License is distributed on an "AS IS" BASIS,
         
     | 
| 
      
 14 
     | 
    
         
            +
            WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
         
     | 
| 
      
 15 
     | 
    
         
            +
            See the License for the specific language governing permissions and
         
     | 
| 
      
 16 
     | 
    
         
            +
            limitations under the License.
         
     | 
| 
      
 17 
     | 
    
         
            +
            */
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
            // dynamic loading of content
         
     | 
| 
      
 20 
     | 
    
         
            +
            // inspired by https://github.com/defunkt/jquery-iqjax - though minus the
         
     | 
| 
      
 21 
     | 
    
         
            +
            // History API and based on Rails's data-remote functionality and error handling
         
     | 
| 
      
 22 
     | 
    
         
            +
            (function($) {
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
            "use strict";
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
            var iqjax_uri, requestMethod;
         
     | 
| 
      
 27 
     | 
    
         
            +
             
     | 
| 
      
 28 
     | 
    
         
            +
            var IQjax = function(context, target) {
         
     | 
| 
      
 29 
     | 
    
         
            +
            	// NB: context and target must not be descendants of each other
         
     | 
| 
      
 30 
     | 
    
         
            +
            	this.context = context;
         
     | 
| 
      
 31 
     | 
    
         
            +
            	this.target = target;
         
     | 
| 
      
 32 
     | 
    
         
            +
            	this.indicator = $(".indicator", target);
         
     | 
| 
      
 33 
     | 
    
         
            +
            	if(!this.indicator.length) {
         
     | 
| 
      
 34 
     | 
    
         
            +
            		this.indicator = $('<div class="indicator hidden"></div>');
         
     | 
| 
      
 35 
     | 
    
         
            +
            	}
         
     | 
| 
      
 36 
     | 
    
         
            +
             
     | 
| 
      
 37 
     | 
    
         
            +
            	// NB: redefining `this` in event handlers (via `proxy`) is dangerously
         
     | 
| 
      
 38 
     | 
    
         
            +
            	// misleading, but avoids non-standard function signatures for event
         
     | 
| 
      
 39 
     | 
    
         
            +
            	// handlers - plus for instance methods, it's actually more intuitive
         
     | 
| 
      
 40 
     | 
    
         
            +
             
     | 
| 
      
 41 
     | 
    
         
            +
            	// cancel buttons
         
     | 
| 
      
 42 
     | 
    
         
            +
            	var uri = document.location.toString().split("#")[0]; // XXX: use as selector makes for brittle heuristic?
         
     | 
| 
      
 43 
     | 
    
         
            +
            	this.target.on("click", 'a[href="' + uri + '"]', $.proxy(this.onCancel, this));
         
     | 
| 
      
 44 
     | 
    
         
            +
             
     | 
| 
      
 45 
     | 
    
         
            +
            	var selector = "a[data-remote], form[data-remote]";
         
     | 
| 
      
 46 
     | 
    
         
            +
            	var handlers = {
         
     | 
| 
      
 47 
     | 
    
         
            +
            		"ajax:beforeSend": $.proxy(this.beforeSend, this),
         
     | 
| 
      
 48 
     | 
    
         
            +
            		"ajax:success": $.proxy(this.onSuccess, this),
         
     | 
| 
      
 49 
     | 
    
         
            +
            		"ajax:error": $.proxy(this.onError, this)
         
     | 
| 
      
 50 
     | 
    
         
            +
            	};
         
     | 
| 
      
 51 
     | 
    
         
            +
            	this.context.add(this.target).on(handlers, selector);
         
     | 
| 
      
 52 
     | 
    
         
            +
             
     | 
| 
      
 53 
     | 
    
         
            +
            	// dirty state: protect against accidental dismissal
         
     | 
| 
      
 54 
     | 
    
         
            +
            	var self = this;
         
     | 
| 
      
 55 
     | 
    
         
            +
            	this.target.on("change", "input, textarea, select", function(ev) {
         
     | 
| 
      
 56 
     | 
    
         
            +
            		self.dirty = true;
         
     | 
| 
      
 57 
     | 
    
         
            +
            	});
         
     | 
| 
      
 58 
     | 
    
         
            +
            };
         
     | 
| 
      
 59 
     | 
    
         
            +
            $.extend(IQjax.prototype, {
         
     | 
| 
      
 60 
     | 
    
         
            +
            	onCancel: function(ev) {
         
     | 
| 
      
 61 
     | 
    
         
            +
            		if(!this.checkDirty(ev)) {
         
     | 
| 
      
 62 
     | 
    
         
            +
            			this.reset();
         
     | 
| 
      
 63 
     | 
    
         
            +
            		}
         
     | 
| 
      
 64 
     | 
    
         
            +
            		ev.preventDefault();
         
     | 
| 
      
 65 
     | 
    
         
            +
            	},
         
     | 
| 
      
 66 
     | 
    
         
            +
            	beforeSend: function(ev, xhr, settings) {
         
     | 
| 
      
 67 
     | 
    
         
            +
            		if(this.checkDirty(ev)) {
         
     | 
| 
      
 68 
     | 
    
         
            +
            			return false;
         
     | 
| 
      
 69 
     | 
    
         
            +
            		}
         
     | 
| 
      
 70 
     | 
    
         
            +
             
     | 
| 
      
 71 
     | 
    
         
            +
            		var contextAction = $.contains(this.context[0], ev.currentTarget); // TODO: rename -- XXX: hacky?
         
     | 
| 
      
 72 
     | 
    
         
            +
            		if(contextAction) {
         
     | 
| 
      
 73 
     | 
    
         
            +
            			this.reset();
         
     | 
| 
      
 74 
     | 
    
         
            +
            		}
         
     | 
| 
      
 75 
     | 
    
         
            +
            		$(ev.currentTarget).addClass("active");
         
     | 
| 
      
 76 
     | 
    
         
            +
            		this.target.prepend(this.indicator);
         
     | 
| 
      
 77 
     | 
    
         
            +
            		this.indicator.show();
         
     | 
| 
      
 78 
     | 
    
         
            +
            		settings.url = iqjax_uri(settings.url);
         
     | 
| 
      
 79 
     | 
    
         
            +
            		this.target.children().not(this.indicator).css("opacity", 0.5);
         
     | 
| 
      
 80 
     | 
    
         
            +
            	},
         
     | 
| 
      
 81 
     | 
    
         
            +
            	onSuccess: function(ev, data, status, xhr) {
         
     | 
| 
      
 82 
     | 
    
         
            +
            		if(!ev.currentTarget.parentNode) {
         
     | 
| 
      
 83 
     | 
    
         
            +
            			// FIXME: it's not clear under what circumstances this occurs;
         
     | 
| 
      
 84 
     | 
    
         
            +
            			// apparently, for reasons yet unknown, this event is erroneously
         
     | 
| 
      
 85 
     | 
    
         
            +
            			// triggered twice (and not all such duplicate events are
         
     | 
| 
      
 86 
     | 
    
         
            +
            			// intercepted by this hack, e.g. DELETE operations)
         
     | 
| 
      
 87 
     | 
    
         
            +
            			return;
         
     | 
| 
      
 88 
     | 
    
         
            +
            		}
         
     | 
| 
      
 89 
     | 
    
         
            +
             
     | 
| 
      
 90 
     | 
    
         
            +
            		var targetAction = $.contains(this.target[0], ev.currentTarget), // TODO: rename -- XXX: hacky?
         
     | 
| 
      
 91 
     | 
    
         
            +
            			el = $(ev.currentTarget),
         
     | 
| 
      
 92 
     | 
    
         
            +
            			reqMethod = "GET",
         
     | 
| 
      
 93 
     | 
    
         
            +
            			origin;
         
     | 
| 
      
 94 
     | 
    
         
            +
             
     | 
| 
      
 95 
     | 
    
         
            +
            		if(el.is("form")) {
         
     | 
| 
      
 96 
     | 
    
         
            +
            			if(targetAction) {
         
     | 
| 
      
 97 
     | 
    
         
            +
            				this.onUpdate.call(this, data, status, xhr); // TODO: should trigger event
         
     | 
| 
      
 98 
     | 
    
         
            +
            				return;
         
     | 
| 
      
 99 
     | 
    
         
            +
            			} else {
         
     | 
| 
      
 100 
     | 
    
         
            +
            				reqMethod = requestMethod(el);
         
     | 
| 
      
 101 
     | 
    
         
            +
            				origin = el.closest(".iqjax-entity"); // TODO: document
         
     | 
| 
      
 102 
     | 
    
         
            +
            			}
         
     | 
| 
      
 103 
     | 
    
         
            +
            		}
         
     | 
| 
      
 104 
     | 
    
         
            +
             
     | 
| 
      
 105 
     | 
    
         
            +
            		if(origin && reqMethod === "DELETE") {
         
     | 
| 
      
 106 
     | 
    
         
            +
            			this.indicator.hide();
         
     | 
| 
      
 107 
     | 
    
         
            +
            			origin.slideUp($.proxy(origin.remove, origin));
         
     | 
| 
      
 108 
     | 
    
         
            +
            		} else {
         
     | 
| 
      
 109 
     | 
    
         
            +
            			this.display(data);
         
     | 
| 
      
 110 
     | 
    
         
            +
            		}
         
     | 
| 
      
 111 
     | 
    
         
            +
            	},
         
     | 
| 
      
 112 
     | 
    
         
            +
            	onError: function(ev, xhr, error, exc) {
         
     | 
| 
      
 113 
     | 
    
         
            +
            		var cType = xhr.getResponseHeader("Content-Type"),
         
     | 
| 
      
 114 
     | 
    
         
            +
            			isHTML = cType ? cType.match(/\btext\/html\b/) : false;
         
     | 
| 
      
 115 
     | 
    
         
            +
            		this.display(xhr.responseText || error, !isHTML);
         
     | 
| 
      
 116 
     | 
    
         
            +
            	},
         
     | 
| 
      
 117 
     | 
    
         
            +
            	onUpdate: function(data, status, xhr) {
         
     | 
| 
      
 118 
     | 
    
         
            +
            		var src = xhr.getResponseHeader("X-IQJAX"), // TODO: document
         
     | 
| 
      
 119 
     | 
    
         
            +
            			item = $("<div />").html(data).find("#" + src),
         
     | 
| 
      
 120 
     | 
    
         
            +
            			origin = $(".active", this.context),
         
     | 
| 
      
 121 
     | 
    
         
            +
            			container = origin.closest("[data-iqjax-collection]"), // TODO: document
         
     | 
| 
      
 122 
     | 
    
         
            +
            			form = $("form.active", this.target),
         
     | 
| 
      
 123 
     | 
    
         
            +
            			reqMethod = requestMethod(form);
         
     | 
| 
      
 124 
     | 
    
         
            +
             
     | 
| 
      
 125 
     | 
    
         
            +
            		this.target.empty();
         
     | 
| 
      
 126 
     | 
    
         
            +
             
     | 
| 
      
 127 
     | 
    
         
            +
            		container = container.jquery ? container : $(container);
         
     | 
| 
      
 128 
     | 
    
         
            +
            		// account for nested update targets -- XXX: hacky!?
         
     | 
| 
      
 129 
     | 
    
         
            +
            		if(reqMethod === "PUT" && origin.closest(".iqjax-entity")[0] === container[0]) {
         
     | 
| 
      
 130 
     | 
    
         
            +
            			container = container.parent().closest("[data-iqjax-collection]");
         
     | 
| 
      
 131 
     | 
    
         
            +
            		}
         
     | 
| 
      
 132 
     | 
    
         
            +
            		container = $(container.data("iqjax-collection"));
         
     | 
| 
      
 133 
     | 
    
         
            +
             
     | 
| 
      
 134 
     | 
    
         
            +
            		if(reqMethod === "GET") { // multi-step forms
         
     | 
| 
      
 135 
     | 
    
         
            +
            			this.display(data);
         
     | 
| 
      
 136 
     | 
    
         
            +
            		} else {
         
     | 
| 
      
 137 
     | 
    
         
            +
            			this.reset();
         
     | 
| 
      
 138 
     | 
    
         
            +
            		}
         
     | 
| 
      
 139 
     | 
    
         
            +
             
     | 
| 
      
 140 
     | 
    
         
            +
            		var el = $("#" + src, self.context);
         
     | 
| 
      
 141 
     | 
    
         
            +
            		if(el.length) {
         
     | 
| 
      
 142 
     | 
    
         
            +
            			el.replaceWith(item);
         
     | 
| 
      
 143 
     | 
    
         
            +
            		} else { // new
         
     | 
| 
      
 144 
     | 
    
         
            +
            			container.append(item);
         
     | 
| 
      
 145 
     | 
    
         
            +
            		}
         
     | 
| 
      
 146 
     | 
    
         
            +
             
     | 
| 
      
 147 
     | 
    
         
            +
            		item.addClass("success").removeClass("success", "glacial");
         
     | 
| 
      
 148 
     | 
    
         
            +
            		this.context.trigger("iqjax:update", { item: item, doc: data });
         
     | 
| 
      
 149 
     | 
    
         
            +
            	},
         
     | 
| 
      
 150 
     | 
    
         
            +
            	reset: function() {
         
     | 
| 
      
 151 
     | 
    
         
            +
            		this.target.empty();
         
     | 
| 
      
 152 
     | 
    
         
            +
            		this.dirty = false;
         
     | 
| 
      
 153 
     | 
    
         
            +
            		$(".active", this.context).removeClass("active");
         
     | 
| 
      
 154 
     | 
    
         
            +
            	},
         
     | 
| 
      
 155 
     | 
    
         
            +
            	display: function(txt, plain) {
         
     | 
| 
      
 156 
     | 
    
         
            +
            		this.indicator.hide();
         
     | 
| 
      
 157 
     | 
    
         
            +
            		this.target[plain ? "text" : "html"](txt).prepend(this.indicator);
         
     | 
| 
      
 158 
     | 
    
         
            +
            		// intercept interactions to prevent full page reload
         
     | 
| 
      
 159 
     | 
    
         
            +
            		$("form", this.target).attr("data-remote", true);
         
     | 
| 
      
 160 
     | 
    
         
            +
            		this.context.trigger("iqjax:content", { iqjax: this });
         
     | 
| 
      
 161 
     | 
    
         
            +
            	},
         
     | 
| 
      
 162 
     | 
    
         
            +
            	// dirty state: protect against accidental dismissal
         
     | 
| 
      
 163 
     | 
    
         
            +
            	dirtyMsg: "Es gibt ungespeicherte Änderungen - fortfahren (Änderungen werden verworfen)?", // TODO: rephrase
         
     | 
| 
      
 164 
     | 
    
         
            +
            	checkDirty: function(ev) {
         
     | 
| 
      
 165 
     | 
    
         
            +
            		var isSubmit = $(ev.currentTarget).is("form");
         
     | 
| 
      
 166 
     | 
    
         
            +
            		if(this.dirty && !isSubmit) {
         
     | 
| 
      
 167 
     | 
    
         
            +
            			if(confirm(this.dirtyMsg)) {
         
     | 
| 
      
 168 
     | 
    
         
            +
            				this.dirty = false;
         
     | 
| 
      
 169 
     | 
    
         
            +
            			} else {
         
     | 
| 
      
 170 
     | 
    
         
            +
            				return true;
         
     | 
| 
      
 171 
     | 
    
         
            +
            			}
         
     | 
| 
      
 172 
     | 
    
         
            +
            		}
         
     | 
| 
      
 173 
     | 
    
         
            +
            	}
         
     | 
| 
      
 174 
     | 
    
         
            +
            });
         
     | 
| 
      
 175 
     | 
    
         
            +
             
     | 
| 
      
 176 
     | 
    
         
            +
            // hack to prevent cache confusion (browser caches should distinguish between
         
     | 
| 
      
 177 
     | 
    
         
            +
            // iQjax and non-iQjax requests) - it'd be more elegant to modify the jqXHR's
         
     | 
| 
      
 178 
     | 
    
         
            +
            // `data` property here, but it appears that's being overridden by jQuery later
         
     | 
| 
      
 179 
     | 
    
         
            +
            iqjax_uri = function(uri) {
         
     | 
| 
      
 180 
     | 
    
         
            +
            	return uri + (uri.indexOf("?") === -1 ? "?" : "&") + "_iqjax=1";
         
     | 
| 
      
 181 
     | 
    
         
            +
            };
         
     | 
| 
      
 182 
     | 
    
         
            +
             
     | 
| 
      
 183 
     | 
    
         
            +
            requestMethod = function(form) {
         
     | 
| 
      
 184 
     | 
    
         
            +
            	var m = $("input[name=_method]", form).val() || form.attr("method") || "GET";
         
     | 
| 
      
 185 
     | 
    
         
            +
            	return m.toUpperCase();
         
     | 
| 
      
 186 
     | 
    
         
            +
            };
         
     | 
| 
      
 187 
     | 
    
         
            +
             
     | 
| 
      
 188 
     | 
    
         
            +
            // uses dynamic in-page loading for child elements matching `a[data-remote]`
         
     | 
| 
      
 189 
     | 
    
         
            +
            // options.target is the DOM element within which contents are to be displayed
         
     | 
| 
      
 190 
     | 
    
         
            +
            // (defaults to selector contained in context element's `data-iqjax` attribute)
         
     | 
| 
      
 191 
     | 
    
         
            +
            $.fn.iqjax = function(options) {
         
     | 
| 
      
 192 
     | 
    
         
            +
            	options = options || {};
         
     | 
| 
      
 193 
     | 
    
         
            +
            	return this.each(function(i, node) {
         
     | 
| 
      
 194 
     | 
    
         
            +
            		var context = $(this),
         
     | 
| 
      
 195 
     | 
    
         
            +
            			target = $(options.target || context.data("iqjax")); // TODO: document
         
     | 
| 
      
 196 
     | 
    
         
            +
            		new IQjax(context, target);
         
     | 
| 
      
 197 
     | 
    
         
            +
            	});
         
     | 
| 
      
 198 
     | 
    
         
            +
            };
         
     | 
| 
      
 199 
     | 
    
         
            +
             
     | 
| 
      
 200 
     | 
    
         
            +
            }(jQuery));
         
     | 
    
        data/lib/iqjax.rb
    ADDED
    
    
    
        data/lib/iqjax/engine.rb
    ADDED
    
    
    
        data/test/index.html
    ADDED
    
    | 
         @@ -0,0 +1,55 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            <!DOCTYPE html>
         
     | 
| 
      
 2 
     | 
    
         
            +
            <html>
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
              <head>
         
     | 
| 
      
 5 
     | 
    
         
            +
                <meta charset="utf-8">
         
     | 
| 
      
 6 
     | 
    
         
            +
                <title>iQjax QUnit Test Suite</title>
         
     | 
| 
      
 7 
     | 
    
         
            +
                <link rel="stylesheet" href="lib/qunit.css">
         
     | 
| 
      
 8 
     | 
    
         
            +
              </head>
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
              <body>
         
     | 
| 
      
 11 
     | 
    
         
            +
                <h1 id="qunit-header">QUnit Test Suite</h1>
         
     | 
| 
      
 12 
     | 
    
         
            +
                <h2 id="qunit-banner"></h2>
         
     | 
| 
      
 13 
     | 
    
         
            +
                <div id="qunit-testrunner-toolbar"></div>
         
     | 
| 
      
 14 
     | 
    
         
            +
                <h2 id="qunit-userAgent"></h2>
         
     | 
| 
      
 15 
     | 
    
         
            +
                <ol id="qunit-tests"></ol>
         
     | 
| 
      
 16 
     | 
    
         
            +
                <div id="qunit-fixture">
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
                  <div id="basic" data-iqjax-collection="#other-item-list">
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
                    <div data-iqjax-collection="#item-list">
         
     | 
| 
      
 21 
     | 
    
         
            +
                      <p><a href="/items/new" id="new" data-remote="true">New</a></p>
         
     | 
| 
      
 22 
     | 
    
         
            +
                      <ul id="item-list">
         
     | 
| 
      
 23 
     | 
    
         
            +
                        <li id="item1">
         
     | 
| 
      
 24 
     | 
    
         
            +
                          <a href="/items/1/edit" data-remote="true">Edit</a>
         
     | 
| 
      
 25 
     | 
    
         
            +
                        </li>
         
     | 
| 
      
 26 
     | 
    
         
            +
                        <li id="item2">
         
     | 
| 
      
 27 
     | 
    
         
            +
                          <a href="/items/2/edit" data-remote="true">Edit</a>
         
     | 
| 
      
 28 
     | 
    
         
            +
                        </li>
         
     | 
| 
      
 29 
     | 
    
         
            +
                        <li id="dummy-item-pointing-to-item3">
         
     | 
| 
      
 30 
     | 
    
         
            +
                          <a href="/items/3/edit" data-remote="true">Edit</a>
         
     | 
| 
      
 31 
     | 
    
         
            +
                        </li>
         
     | 
| 
      
 32 
     | 
    
         
            +
                      </ul>
         
     | 
| 
      
 33 
     | 
    
         
            +
                    </div>
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
      
 35 
     | 
    
         
            +
                    <ul id="other-item-list">
         
     | 
| 
      
 36 
     | 
    
         
            +
                      <li id="item3">Change me!</li>
         
     | 
| 
      
 37 
     | 
    
         
            +
                    </ul>
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
      
 39 
     | 
    
         
            +
                  </div>
         
     | 
| 
      
 40 
     | 
    
         
            +
             
     | 
| 
      
 41 
     | 
    
         
            +
                  <div id="my-container1"></div>
         
     | 
| 
      
 42 
     | 
    
         
            +
             
     | 
| 
      
 43 
     | 
    
         
            +
                </div>
         
     | 
| 
      
 44 
     | 
    
         
            +
             
     | 
| 
      
 45 
     | 
    
         
            +
                <script src="lib/qunit.js"></script>
         
     | 
| 
      
 46 
     | 
    
         
            +
                <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
         
     | 
| 
      
 47 
     | 
    
         
            +
                <script src="lib/jquery.mockjax.js"></script>
         
     | 
| 
      
 48 
     | 
    
         
            +
             
     | 
| 
      
 49 
     | 
    
         
            +
                <script src="../vendor/jquery_ujs.js"></script>
         
     | 
| 
      
 50 
     | 
    
         
            +
             
     | 
| 
      
 51 
     | 
    
         
            +
                <script src="../iqjax.js"></script>
         
     | 
| 
      
 52 
     | 
    
         
            +
                <script src="tests.js"></script>
         
     | 
| 
      
 53 
     | 
    
         
            +
              </body>
         
     | 
| 
      
 54 
     | 
    
         
            +
             
     | 
| 
      
 55 
     | 
    
         
            +
            </html>
         
     | 
| 
         @@ -0,0 +1,382 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            /*!
         
     | 
| 
      
 2 
     | 
    
         
            +
             * MockJax - jQuery Plugin to Mock Ajax requests
         
     | 
| 
      
 3 
     | 
    
         
            +
             *
         
     | 
| 
      
 4 
     | 
    
         
            +
             * Version:  1.4.0
         
     | 
| 
      
 5 
     | 
    
         
            +
             * Released: 2011-02-04
         
     | 
| 
      
 6 
     | 
    
         
            +
             * Source:   http://github.com/appendto/jquery-mockjax
         
     | 
| 
      
 7 
     | 
    
         
            +
             * Docs:     http://enterprisejquery.com/2010/07/mock-your-ajax-requests-with-mockjax-for-rapid-development
         
     | 
| 
      
 8 
     | 
    
         
            +
             * Plugin:   mockjax
         
     | 
| 
      
 9 
     | 
    
         
            +
             * Author:   Jonathan Sharp (http://jdsharp.com)
         
     | 
| 
      
 10 
     | 
    
         
            +
             * License:  MIT,GPL
         
     | 
| 
      
 11 
     | 
    
         
            +
             *
         
     | 
| 
      
 12 
     | 
    
         
            +
             * Copyright (c) 2010 appendTo LLC.
         
     | 
| 
      
 13 
     | 
    
         
            +
             * Dual licensed under the MIT or GPL licenses.
         
     | 
| 
      
 14 
     | 
    
         
            +
             * http://appendto.com/open-source-licenses
         
     | 
| 
      
 15 
     | 
    
         
            +
             */
         
     | 
| 
      
 16 
     | 
    
         
            +
            (function($) {
         
     | 
| 
      
 17 
     | 
    
         
            +
            	var _ajax = $.ajax,
         
     | 
| 
      
 18 
     | 
    
         
            +
            		mockHandlers = [];
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
            	function parseXML(xml) {
         
     | 
| 
      
 21 
     | 
    
         
            +
            		if ( window['DOMParser'] == undefined && window.ActiveXObject ) {
         
     | 
| 
      
 22 
     | 
    
         
            +
            			DOMParser = function() { };
         
     | 
| 
      
 23 
     | 
    
         
            +
            			DOMParser.prototype.parseFromString = function( xmlString ) {
         
     | 
| 
      
 24 
     | 
    
         
            +
            				var doc = new ActiveXObject('Microsoft.XMLDOM');
         
     | 
| 
      
 25 
     | 
    
         
            +
            		        doc.async = 'false';
         
     | 
| 
      
 26 
     | 
    
         
            +
            		        doc.loadXML( xmlString );
         
     | 
| 
      
 27 
     | 
    
         
            +
            				return doc;
         
     | 
| 
      
 28 
     | 
    
         
            +
            			};
         
     | 
| 
      
 29 
     | 
    
         
            +
            		}
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
      
 31 
     | 
    
         
            +
            		try {
         
     | 
| 
      
 32 
     | 
    
         
            +
            			var xmlDoc 	= ( new DOMParser() ).parseFromString( xml, 'text/xml' );
         
     | 
| 
      
 33 
     | 
    
         
            +
            			if ( $.isXMLDoc( xmlDoc ) ) {
         
     | 
| 
      
 34 
     | 
    
         
            +
            				var err = $('parsererror', xmlDoc);
         
     | 
| 
      
 35 
     | 
    
         
            +
            				if ( err.length == 1 ) {
         
     | 
| 
      
 36 
     | 
    
         
            +
            					throw('Error: ' + $(xmlDoc).text() );
         
     | 
| 
      
 37 
     | 
    
         
            +
            				}
         
     | 
| 
      
 38 
     | 
    
         
            +
            			} else {
         
     | 
| 
      
 39 
     | 
    
         
            +
            				throw('Unable to parse XML');
         
     | 
| 
      
 40 
     | 
    
         
            +
            			}
         
     | 
| 
      
 41 
     | 
    
         
            +
            		} catch( e ) {
         
     | 
| 
      
 42 
     | 
    
         
            +
            			var msg = ( e.name == undefined ? e : e.name + ': ' + e.message );
         
     | 
| 
      
 43 
     | 
    
         
            +
            			$(document).trigger('xmlParseError', [ msg ]);
         
     | 
| 
      
 44 
     | 
    
         
            +
            			return undefined;
         
     | 
| 
      
 45 
     | 
    
         
            +
            		}
         
     | 
| 
      
 46 
     | 
    
         
            +
            		return xmlDoc;
         
     | 
| 
      
 47 
     | 
    
         
            +
            	}
         
     | 
| 
      
 48 
     | 
    
         
            +
             
     | 
| 
      
 49 
     | 
    
         
            +
            	$.extend({
         
     | 
| 
      
 50 
     | 
    
         
            +
            		ajax: function(origSettings) {
         
     | 
| 
      
 51 
     | 
    
         
            +
            			var s = jQuery.extend(true, {}, jQuery.ajaxSettings, origSettings),
         
     | 
| 
      
 52 
     | 
    
         
            +
            			    mock = false;
         
     | 
| 
      
 53 
     | 
    
         
            +
            			// Iterate over our mock handlers (in registration order) until we find
         
     | 
| 
      
 54 
     | 
    
         
            +
            			// one that is willing to intercept the request
         
     | 
| 
      
 55 
     | 
    
         
            +
            			$.each(mockHandlers, function(k, v) {
         
     | 
| 
      
 56 
     | 
    
         
            +
            				if ( !mockHandlers[k] ) {
         
     | 
| 
      
 57 
     | 
    
         
            +
            					return;
         
     | 
| 
      
 58 
     | 
    
         
            +
            				}
         
     | 
| 
      
 59 
     | 
    
         
            +
            				var m = null;
         
     | 
| 
      
 60 
     | 
    
         
            +
            				// If the mock was registered with a function, let the function decide if we
         
     | 
| 
      
 61 
     | 
    
         
            +
            				// want to mock this request
         
     | 
| 
      
 62 
     | 
    
         
            +
            				if ( $.isFunction(mockHandlers[k]) ) {
         
     | 
| 
      
 63 
     | 
    
         
            +
            					m = mockHandlers[k](s);
         
     | 
| 
      
 64 
     | 
    
         
            +
            				} else {
         
     | 
| 
      
 65 
     | 
    
         
            +
            					m = mockHandlers[k];
         
     | 
| 
      
 66 
     | 
    
         
            +
            					// Inspect the URL of the request and check if the mock handler's url
         
     | 
| 
      
 67 
     | 
    
         
            +
            					// matches the url for this ajax request
         
     | 
| 
      
 68 
     | 
    
         
            +
            					if ( $.isFunction(m.url.test) ) {
         
     | 
| 
      
 69 
     | 
    
         
            +
            						// The user provided a regex for the url, test it
         
     | 
| 
      
 70 
     | 
    
         
            +
            						if ( !m.url.test( s.url ) ) {
         
     | 
| 
      
 71 
     | 
    
         
            +
            							m = null;
         
     | 
| 
      
 72 
     | 
    
         
            +
            						}
         
     | 
| 
      
 73 
     | 
    
         
            +
            					} else {
         
     | 
| 
      
 74 
     | 
    
         
            +
            						// Look for a simple wildcard '*' or a direct URL match
         
     | 
| 
      
 75 
     | 
    
         
            +
            						var star = m.url.indexOf('*');
         
     | 
| 
      
 76 
     | 
    
         
            +
            						if ( ( m.url != '*' && m.url != s.url && star == -1 ) ||
         
     | 
| 
      
 77 
     | 
    
         
            +
            							( star > -1 && m.url.substr(0, star) != s.url.substr(0, star) ) ) {
         
     | 
| 
      
 78 
     | 
    
         
            +
            							 // The url we tested did not match the wildcard *
         
     | 
| 
      
 79 
     | 
    
         
            +
            							 m = null;
         
     | 
| 
      
 80 
     | 
    
         
            +
            						}
         
     | 
| 
      
 81 
     | 
    
         
            +
            					}
         
     | 
| 
      
 82 
     | 
    
         
            +
            					if ( m ) {
         
     | 
| 
      
 83 
     | 
    
         
            +
            						// Inspect the data submitted in the request (either POST body or GET query string)
         
     | 
| 
      
 84 
     | 
    
         
            +
            						if ( m.data && s.data ) {
         
     | 
| 
      
 85 
     | 
    
         
            +
            							var identical = false;
         
     | 
| 
      
 86 
     | 
    
         
            +
            							// Deep inspect the identity of the objects
         
     | 
| 
      
 87 
     | 
    
         
            +
            							(function ident(mock, live) {
         
     | 
| 
      
 88 
     | 
    
         
            +
            								// Test for situations where the data is a querystring (not an object)
         
     | 
| 
      
 89 
     | 
    
         
            +
            								if (typeof live === 'string') {
         
     | 
| 
      
 90 
     | 
    
         
            +
            									// Querystring may be a regex
         
     | 
| 
      
 91 
     | 
    
         
            +
            									identical = $.isFunction( mock.test ) ? mock.test(live) : mock == live;
         
     | 
| 
      
 92 
     | 
    
         
            +
            									return identical;
         
     | 
| 
      
 93 
     | 
    
         
            +
            								}
         
     | 
| 
      
 94 
     | 
    
         
            +
            								$.each(mock, function(k, v) {
         
     | 
| 
      
 95 
     | 
    
         
            +
            									if ( live[k] === undefined ) {
         
     | 
| 
      
 96 
     | 
    
         
            +
            										identical = false;
         
     | 
| 
      
 97 
     | 
    
         
            +
            										return false;
         
     | 
| 
      
 98 
     | 
    
         
            +
            									} else {
         
     | 
| 
      
 99 
     | 
    
         
            +
            										identical = true;
         
     | 
| 
      
 100 
     | 
    
         
            +
            										if ( typeof live[k] == 'object' ) {
         
     | 
| 
      
 101 
     | 
    
         
            +
            											return ident(mock[k], live[k]);
         
     | 
| 
      
 102 
     | 
    
         
            +
            										} else {
         
     | 
| 
      
 103 
     | 
    
         
            +
            											if ( $.isFunction( mock[k].test ) ) {
         
     | 
| 
      
 104 
     | 
    
         
            +
            												identical = mock[k].test(live[k]);
         
     | 
| 
      
 105 
     | 
    
         
            +
            											} else {
         
     | 
| 
      
 106 
     | 
    
         
            +
            												identical = ( mock[k] == live[k] );
         
     | 
| 
      
 107 
     | 
    
         
            +
            											}
         
     | 
| 
      
 108 
     | 
    
         
            +
            											return identical;
         
     | 
| 
      
 109 
     | 
    
         
            +
            										}
         
     | 
| 
      
 110 
     | 
    
         
            +
            									}
         
     | 
| 
      
 111 
     | 
    
         
            +
            								});
         
     | 
| 
      
 112 
     | 
    
         
            +
            							})(m.data, s.data);
         
     | 
| 
      
 113 
     | 
    
         
            +
            							// They're not identical, do not mock this request
         
     | 
| 
      
 114 
     | 
    
         
            +
            							if ( identical == false ) {
         
     | 
| 
      
 115 
     | 
    
         
            +
            								m = null;
         
     | 
| 
      
 116 
     | 
    
         
            +
            							}
         
     | 
| 
      
 117 
     | 
    
         
            +
            						}
         
     | 
| 
      
 118 
     | 
    
         
            +
            						// Inspect the request type
         
     | 
| 
      
 119 
     | 
    
         
            +
            						if ( m && m.type && m.type != s.type ) {
         
     | 
| 
      
 120 
     | 
    
         
            +
            							// The request type doesn't match (GET vs. POST)
         
     | 
| 
      
 121 
     | 
    
         
            +
            							m = null;
         
     | 
| 
      
 122 
     | 
    
         
            +
            						}
         
     | 
| 
      
 123 
     | 
    
         
            +
            					}
         
     | 
| 
      
 124 
     | 
    
         
            +
            				}
         
     | 
| 
      
 125 
     | 
    
         
            +
            				if ( m ) {
         
     | 
| 
      
 126 
     | 
    
         
            +
            					mock = true;
         
     | 
| 
      
 127 
     | 
    
         
            +
             
     | 
| 
      
 128 
     | 
    
         
            +
            					// Handle console logging
         
     | 
| 
      
 129 
     | 
    
         
            +
            					var c = $.extend({}, $.mockjaxSettings, m);
         
     | 
| 
      
 130 
     | 
    
         
            +
            					if ( c.log && $.isFunction(c.log) ) {
         
     | 
| 
      
 131 
     | 
    
         
            +
            						c.log('MOCK ' + s.type.toUpperCase() + ': ' + s.url, $.extend({}, s));
         
     | 
| 
      
 132 
     | 
    
         
            +
            					}
         
     | 
| 
      
 133 
     | 
    
         
            +
             
     | 
| 
      
 134 
     | 
    
         
            +
            					var jsre = /=\?(&|$)/, jsc = (new Date()).getTime();
         
     | 
| 
      
 135 
     | 
    
         
            +
             
     | 
| 
      
 136 
     | 
    
         
            +
            					// Handle JSONP Parameter Callbacks, we need to replicate some of the jQuery core here
         
     | 
| 
      
 137 
     | 
    
         
            +
            					// because there isn't an easy hook for the cross domain script tag of jsonp
         
     | 
| 
      
 138 
     | 
    
         
            +
            					if ( s.dataType === "jsonp" ) {
         
     | 
| 
      
 139 
     | 
    
         
            +
            						if ( s.type.toUpperCase() === "GET" ) {
         
     | 
| 
      
 140 
     | 
    
         
            +
            							if ( !jsre.test( s.url ) ) {
         
     | 
| 
      
 141 
     | 
    
         
            +
            								s.url += (rquery.test( s.url ) ? "&" : "?") + (s.jsonp || "callback") + "=?";
         
     | 
| 
      
 142 
     | 
    
         
            +
            							}
         
     | 
| 
      
 143 
     | 
    
         
            +
            						} else if ( !s.data || !jsre.test(s.data) ) {
         
     | 
| 
      
 144 
     | 
    
         
            +
            							s.data = (s.data ? s.data + "&" : "") + (s.jsonp || "callback") + "=?";
         
     | 
| 
      
 145 
     | 
    
         
            +
            						}
         
     | 
| 
      
 146 
     | 
    
         
            +
            						s.dataType = "json";
         
     | 
| 
      
 147 
     | 
    
         
            +
            					}
         
     | 
| 
      
 148 
     | 
    
         
            +
             
     | 
| 
      
 149 
     | 
    
         
            +
            					// Build temporary JSONP function
         
     | 
| 
      
 150 
     | 
    
         
            +
            					if ( s.dataType === "json" && (s.data && jsre.test(s.data) || jsre.test(s.url)) ) {
         
     | 
| 
      
 151 
     | 
    
         
            +
            						jsonp = s.jsonpCallback || ("jsonp" + jsc++);
         
     | 
| 
      
 152 
     | 
    
         
            +
             
     | 
| 
      
 153 
     | 
    
         
            +
            						// Replace the =? sequence both in the query string and the data
         
     | 
| 
      
 154 
     | 
    
         
            +
            						if ( s.data ) {
         
     | 
| 
      
 155 
     | 
    
         
            +
            							s.data = (s.data + "").replace(jsre, "=" + jsonp + "$1");
         
     | 
| 
      
 156 
     | 
    
         
            +
            						}
         
     | 
| 
      
 157 
     | 
    
         
            +
             
     | 
| 
      
 158 
     | 
    
         
            +
            						s.url = s.url.replace(jsre, "=" + jsonp + "$1");
         
     | 
| 
      
 159 
     | 
    
         
            +
             
     | 
| 
      
 160 
     | 
    
         
            +
            						// We need to make sure
         
     | 
| 
      
 161 
     | 
    
         
            +
            						// that a JSONP style response is executed properly
         
     | 
| 
      
 162 
     | 
    
         
            +
            						s.dataType = "script";
         
     | 
| 
      
 163 
     | 
    
         
            +
             
     | 
| 
      
 164 
     | 
    
         
            +
            						// Handle JSONP-style loading
         
     | 
| 
      
 165 
     | 
    
         
            +
            						window[ jsonp ] = window[ jsonp ] || function( tmp ) {
         
     | 
| 
      
 166 
     | 
    
         
            +
            							data = tmp;
         
     | 
| 
      
 167 
     | 
    
         
            +
            							success();
         
     | 
| 
      
 168 
     | 
    
         
            +
            							complete();
         
     | 
| 
      
 169 
     | 
    
         
            +
            							// Garbage collect
         
     | 
| 
      
 170 
     | 
    
         
            +
            							window[ jsonp ] = undefined;
         
     | 
| 
      
 171 
     | 
    
         
            +
             
     | 
| 
      
 172 
     | 
    
         
            +
            							try {
         
     | 
| 
      
 173 
     | 
    
         
            +
            								delete window[ jsonp ];
         
     | 
| 
      
 174 
     | 
    
         
            +
            							} catch(e) {}
         
     | 
| 
      
 175 
     | 
    
         
            +
             
     | 
| 
      
 176 
     | 
    
         
            +
            							if ( head ) {
         
     | 
| 
      
 177 
     | 
    
         
            +
            								head.removeChild( script );
         
     | 
| 
      
 178 
     | 
    
         
            +
            							}
         
     | 
| 
      
 179 
     | 
    
         
            +
            						};
         
     | 
| 
      
 180 
     | 
    
         
            +
            					}
         
     | 
| 
      
 181 
     | 
    
         
            +
             
     | 
| 
      
 182 
     | 
    
         
            +
            					var rurl = /^(\w+:)?\/\/([^\/?#]+)/,
         
     | 
| 
      
 183 
     | 
    
         
            +
            						parts = rurl.exec( s.url ),
         
     | 
| 
      
 184 
     | 
    
         
            +
            						remote = parts && (parts[1] && parts[1] !== location.protocol || parts[2] !== location.host);
         
     | 
| 
      
 185 
     | 
    
         
            +
             
     | 
| 
      
 186 
     | 
    
         
            +
            					// Test if we are going to create a script tag (if so, intercept & mock)
         
     | 
| 
      
 187 
     | 
    
         
            +
            					if ( s.dataType === "script" && s.type.toUpperCase() === "GET" && remote ) {
         
     | 
| 
      
 188 
     | 
    
         
            +
            						// Synthesize the mock request for adding a script tag
         
     | 
| 
      
 189 
     | 
    
         
            +
            						var callbackContext = origSettings && origSettings.context || s;
         
     | 
| 
      
 190 
     | 
    
         
            +
             
     | 
| 
      
 191 
     | 
    
         
            +
            						function success() {
         
     | 
| 
      
 192 
     | 
    
         
            +
            							// If a local callback was specified, fire it and pass it the data
         
     | 
| 
      
 193 
     | 
    
         
            +
            							if ( s.success ) {
         
     | 
| 
      
 194 
     | 
    
         
            +
            								s.success.call( callbackContext, ( m.response ? m.response.toString() : m.responseText || ''), status, {} );
         
     | 
| 
      
 195 
     | 
    
         
            +
            							}
         
     | 
| 
      
 196 
     | 
    
         
            +
             
     | 
| 
      
 197 
     | 
    
         
            +
            							// Fire the global callback
         
     | 
| 
      
 198 
     | 
    
         
            +
            							if ( s.global ) {
         
     | 
| 
      
 199 
     | 
    
         
            +
            								trigger( "ajaxSuccess", [{}, s] );
         
     | 
| 
      
 200 
     | 
    
         
            +
            							}
         
     | 
| 
      
 201 
     | 
    
         
            +
            						}
         
     | 
| 
      
 202 
     | 
    
         
            +
             
     | 
| 
      
 203 
     | 
    
         
            +
            						function complete() {
         
     | 
| 
      
 204 
     | 
    
         
            +
            							// Process result
         
     | 
| 
      
 205 
     | 
    
         
            +
            							if ( s.complete ) {
         
     | 
| 
      
 206 
     | 
    
         
            +
            								s.complete.call( callbackContext, {} , status );
         
     | 
| 
      
 207 
     | 
    
         
            +
            							}
         
     | 
| 
      
 208 
     | 
    
         
            +
             
     | 
| 
      
 209 
     | 
    
         
            +
            							// The request was completed
         
     | 
| 
      
 210 
     | 
    
         
            +
            							if ( s.global ) {
         
     | 
| 
      
 211 
     | 
    
         
            +
            								trigger( "ajaxComplete", [{}, s] );
         
     | 
| 
      
 212 
     | 
    
         
            +
            							}
         
     | 
| 
      
 213 
     | 
    
         
            +
             
     | 
| 
      
 214 
     | 
    
         
            +
            							// Handle the global AJAX counter
         
     | 
| 
      
 215 
     | 
    
         
            +
            							if ( s.global && ! --jQuery.active ) {
         
     | 
| 
      
 216 
     | 
    
         
            +
            								jQuery.event.trigger( "ajaxStop" );
         
     | 
| 
      
 217 
     | 
    
         
            +
            							}
         
     | 
| 
      
 218 
     | 
    
         
            +
            						}
         
     | 
| 
      
 219 
     | 
    
         
            +
             
     | 
| 
      
 220 
     | 
    
         
            +
            						function trigger(type, args) {
         
     | 
| 
      
 221 
     | 
    
         
            +
            							(s.context ? jQuery(s.context) : jQuery.event).trigger(type, args);
         
     | 
| 
      
 222 
     | 
    
         
            +
            						}
         
     | 
| 
      
 223 
     | 
    
         
            +
             
     | 
| 
      
 224 
     | 
    
         
            +
            						if ( m.response && $.isFunction(m.response) ) {
         
     | 
| 
      
 225 
     | 
    
         
            +
            							m.response(origSettings);
         
     | 
| 
      
 226 
     | 
    
         
            +
            						} else {
         
     | 
| 
      
 227 
     | 
    
         
            +
            							$.globalEval(m.responseText);
         
     | 
| 
      
 228 
     | 
    
         
            +
            						}
         
     | 
| 
      
 229 
     | 
    
         
            +
            						success();
         
     | 
| 
      
 230 
     | 
    
         
            +
            						complete();
         
     | 
| 
      
 231 
     | 
    
         
            +
            						return false;
         
     | 
| 
      
 232 
     | 
    
         
            +
            					}
         
     | 
| 
      
 233 
     | 
    
         
            +
            					mock = _ajax.call($, $.extend(true, {}, origSettings, {
         
     | 
| 
      
 234 
     | 
    
         
            +
            						// Mock the XHR object
         
     | 
| 
      
 235 
     | 
    
         
            +
            						xhr: function() {
         
     | 
| 
      
 236 
     | 
    
         
            +
            							// Extend with our default mockjax settings
         
     | 
| 
      
 237 
     | 
    
         
            +
            							m = $.extend({}, $.mockjaxSettings, m);
         
     | 
| 
      
 238 
     | 
    
         
            +
             
     | 
| 
      
 239 
     | 
    
         
            +
            							if ( m.contentType ) {
         
     | 
| 
      
 240 
     | 
    
         
            +
            								m.headers['content-type'] = m.contentType;
         
     | 
| 
      
 241 
     | 
    
         
            +
            							}
         
     | 
| 
      
 242 
     | 
    
         
            +
             
     | 
| 
      
 243 
     | 
    
         
            +
            							// Return our mock xhr object
         
     | 
| 
      
 244 
     | 
    
         
            +
            							return {
         
     | 
| 
      
 245 
     | 
    
         
            +
            								status: m.status,
         
     | 
| 
      
 246 
     | 
    
         
            +
            								readyState: 1,
         
     | 
| 
      
 247 
     | 
    
         
            +
            								open: function() { },
         
     | 
| 
      
 248 
     | 
    
         
            +
            								send: function() {
         
     | 
| 
      
 249 
     | 
    
         
            +
            									// This is a substitute for < 1.4 which lacks $.proxy
         
     | 
| 
      
 250 
     | 
    
         
            +
            									var process = (function(that) {
         
     | 
| 
      
 251 
     | 
    
         
            +
            										return function() {
         
     | 
| 
      
 252 
     | 
    
         
            +
            											return (function() {
         
     | 
| 
      
 253 
     | 
    
         
            +
            												// The request has returned
         
     | 
| 
      
 254 
     | 
    
         
            +
            											 	this.status 		= m.status;
         
     | 
| 
      
 255 
     | 
    
         
            +
            												this.readyState 	= 4;
         
     | 
| 
      
 256 
     | 
    
         
            +
             
     | 
| 
      
 257 
     | 
    
         
            +
            												// We have an executable function, call it to give
         
     | 
| 
      
 258 
     | 
    
         
            +
            												// the mock handler a chance to update it's data
         
     | 
| 
      
 259 
     | 
    
         
            +
            												if ( $.isFunction(m.response) ) {
         
     | 
| 
      
 260 
     | 
    
         
            +
            													m.response(origSettings);
         
     | 
| 
      
 261 
     | 
    
         
            +
            												}
         
     | 
| 
      
 262 
     | 
    
         
            +
            												// Copy over our mock to our xhr object before passing control back to
         
     | 
| 
      
 263 
     | 
    
         
            +
            												// jQuery's onreadystatechange callback
         
     | 
| 
      
 264 
     | 
    
         
            +
            												if ( s.dataType == 'json' && ( typeof m.responseText == 'object' ) ) {
         
     | 
| 
      
 265 
     | 
    
         
            +
            													this.responseText = JSON.stringify(m.responseText);
         
     | 
| 
      
 266 
     | 
    
         
            +
            												} else if ( s.dataType == 'xml' ) {
         
     | 
| 
      
 267 
     | 
    
         
            +
            													if ( typeof m.responseXML == 'string' ) {
         
     | 
| 
      
 268 
     | 
    
         
            +
            														this.responseXML = parseXML(m.responseXML);
         
     | 
| 
      
 269 
     | 
    
         
            +
            													} else {
         
     | 
| 
      
 270 
     | 
    
         
            +
            														this.responseXML = m.responseXML;
         
     | 
| 
      
 271 
     | 
    
         
            +
            													}
         
     | 
| 
      
 272 
     | 
    
         
            +
            												} else {
         
     | 
| 
      
 273 
     | 
    
         
            +
            													this.responseText = m.responseText;
         
     | 
| 
      
 274 
     | 
    
         
            +
            												}
         
     | 
| 
      
 275 
     | 
    
         
            +
            												// jQuery < 1.4 doesn't have onreadystate change for xhr
         
     | 
| 
      
 276 
     | 
    
         
            +
            												if ( $.isFunction(this.onreadystatechange) ) {
         
     | 
| 
      
 277 
     | 
    
         
            +
            													this.onreadystatechange( m.isTimeout ? 'timeout' : undefined );
         
     | 
| 
      
 278 
     | 
    
         
            +
            												}
         
     | 
| 
      
 279 
     | 
    
         
            +
            											}).apply(that);
         
     | 
| 
      
 280 
     | 
    
         
            +
            										};
         
     | 
| 
      
 281 
     | 
    
         
            +
            									})(this);
         
     | 
| 
      
 282 
     | 
    
         
            +
             
     | 
| 
      
 283 
     | 
    
         
            +
            									if ( m.proxy ) {
         
     | 
| 
      
 284 
     | 
    
         
            +
            										// We're proxying this request and loading in an external file instead
         
     | 
| 
      
 285 
     | 
    
         
            +
            										_ajax({
         
     | 
| 
      
 286 
     | 
    
         
            +
            											global: false,
         
     | 
| 
      
 287 
     | 
    
         
            +
            											url: m.proxy,
         
     | 
| 
      
 288 
     | 
    
         
            +
            											type: m.proxyType,
         
     | 
| 
      
 289 
     | 
    
         
            +
            											data: m.data,
         
     | 
| 
      
 290 
     | 
    
         
            +
            											dataType: s.dataType,
         
     | 
| 
      
 291 
     | 
    
         
            +
            											complete: function(xhr, txt) {
         
     | 
| 
      
 292 
     | 
    
         
            +
            												m.responseXML = xhr.responseXML;
         
     | 
| 
      
 293 
     | 
    
         
            +
            												m.responseText = xhr.responseText;
         
     | 
| 
      
 294 
     | 
    
         
            +
            												this.responseTimer = setTimeout(process, m.responseTime || 0);
         
     | 
| 
      
 295 
     | 
    
         
            +
            											}
         
     | 
| 
      
 296 
     | 
    
         
            +
            										});
         
     | 
| 
      
 297 
     | 
    
         
            +
            									} else {
         
     | 
| 
      
 298 
     | 
    
         
            +
            										// type == 'POST' || 'GET' || 'DELETE'
         
     | 
| 
      
 299 
     | 
    
         
            +
            										if ( s.async === false ) {
         
     | 
| 
      
 300 
     | 
    
         
            +
            											// TODO: Blocking delay
         
     | 
| 
      
 301 
     | 
    
         
            +
            											process();
         
     | 
| 
      
 302 
     | 
    
         
            +
            										} else {
         
     | 
| 
      
 303 
     | 
    
         
            +
            											this.responseTimer = setTimeout(process, m.responseTime || 50);
         
     | 
| 
      
 304 
     | 
    
         
            +
            										}
         
     | 
| 
      
 305 
     | 
    
         
            +
            									}
         
     | 
| 
      
 306 
     | 
    
         
            +
            								},
         
     | 
| 
      
 307 
     | 
    
         
            +
            								abort: function() {
         
     | 
| 
      
 308 
     | 
    
         
            +
            									clearTimeout(this.responseTimer);
         
     | 
| 
      
 309 
     | 
    
         
            +
            								},
         
     | 
| 
      
 310 
     | 
    
         
            +
            								setRequestHeader: function() { },
         
     | 
| 
      
 311 
     | 
    
         
            +
            								getResponseHeader: function(header) {
         
     | 
| 
      
 312 
     | 
    
         
            +
            									// 'Last-modified', 'Etag', 'content-type' are all checked by jQuery
         
     | 
| 
      
 313 
     | 
    
         
            +
            									if ( m.headers && m.headers[header] ) {
         
     | 
| 
      
 314 
     | 
    
         
            +
            										// Return arbitrary headers
         
     | 
| 
      
 315 
     | 
    
         
            +
            										return m.headers[header];
         
     | 
| 
      
 316 
     | 
    
         
            +
            									} else if ( header.toLowerCase() == 'last-modified' ) {
         
     | 
| 
      
 317 
     | 
    
         
            +
            										return m.lastModified || (new Date()).toString();
         
     | 
| 
      
 318 
     | 
    
         
            +
            									} else if ( header.toLowerCase() == 'etag' ) {
         
     | 
| 
      
 319 
     | 
    
         
            +
            										return m.etag || '';
         
     | 
| 
      
 320 
     | 
    
         
            +
            									} else if ( header.toLowerCase() == 'content-type' ) {
         
     | 
| 
      
 321 
     | 
    
         
            +
            										return m.contentType || 'text/plain';
         
     | 
| 
      
 322 
     | 
    
         
            +
            									}
         
     | 
| 
      
 323 
     | 
    
         
            +
            								},
         
     | 
| 
      
 324 
     | 
    
         
            +
            								getAllResponseHeaders: function() {
         
     | 
| 
      
 325 
     | 
    
         
            +
            									var headers = '';
         
     | 
| 
      
 326 
     | 
    
         
            +
            									$.each(m.headers, function(k, v) {
         
     | 
| 
      
 327 
     | 
    
         
            +
            										headers += k + ': ' + v + "\n";
         
     | 
| 
      
 328 
     | 
    
         
            +
            									});
         
     | 
| 
      
 329 
     | 
    
         
            +
            									return headers;
         
     | 
| 
      
 330 
     | 
    
         
            +
            								}
         
     | 
| 
      
 331 
     | 
    
         
            +
            							};
         
     | 
| 
      
 332 
     | 
    
         
            +
            						}
         
     | 
| 
      
 333 
     | 
    
         
            +
            					}));
         
     | 
| 
      
 334 
     | 
    
         
            +
            					return false;
         
     | 
| 
      
 335 
     | 
    
         
            +
            				}
         
     | 
| 
      
 336 
     | 
    
         
            +
            			});
         
     | 
| 
      
 337 
     | 
    
         
            +
            			// We don't have a mock request, trigger a normal request
         
     | 
| 
      
 338 
     | 
    
         
            +
            			if ( !mock ) {
         
     | 
| 
      
 339 
     | 
    
         
            +
            				return _ajax.apply($, arguments);
         
     | 
| 
      
 340 
     | 
    
         
            +
            			} else {
         
     | 
| 
      
 341 
     | 
    
         
            +
            				return mock;
         
     | 
| 
      
 342 
     | 
    
         
            +
            			}
         
     | 
| 
      
 343 
     | 
    
         
            +
            		}
         
     | 
| 
      
 344 
     | 
    
         
            +
            	});
         
     | 
| 
      
 345 
     | 
    
         
            +
             
     | 
| 
      
 346 
     | 
    
         
            +
            	$.mockjaxSettings = {
         
     | 
| 
      
 347 
     | 
    
         
            +
            		//url:        null,
         
     | 
| 
      
 348 
     | 
    
         
            +
            		//type:       'GET',
         
     | 
| 
      
 349 
     | 
    
         
            +
            		log:          function(msg) {
         
     | 
| 
      
 350 
     | 
    
         
            +
            		              	window['console'] && window.console.log && window.console.log(msg);
         
     | 
| 
      
 351 
     | 
    
         
            +
            		              },
         
     | 
| 
      
 352 
     | 
    
         
            +
            		status:       200,
         
     | 
| 
      
 353 
     | 
    
         
            +
            		responseTime: 500,
         
     | 
| 
      
 354 
     | 
    
         
            +
            		isTimeout:    false,
         
     | 
| 
      
 355 
     | 
    
         
            +
            		contentType:  'text/plain',
         
     | 
| 
      
 356 
     | 
    
         
            +
            		response:     '',
         
     | 
| 
      
 357 
     | 
    
         
            +
            		responseText: '',
         
     | 
| 
      
 358 
     | 
    
         
            +
            		responseXML:  '',
         
     | 
| 
      
 359 
     | 
    
         
            +
            		proxy:        '',
         
     | 
| 
      
 360 
     | 
    
         
            +
            		proxyType:    'GET',
         
     | 
| 
      
 361 
     | 
    
         
            +
             
     | 
| 
      
 362 
     | 
    
         
            +
            		lastModified: null,
         
     | 
| 
      
 363 
     | 
    
         
            +
            		etag:         '',
         
     | 
| 
      
 364 
     | 
    
         
            +
            		headers: {
         
     | 
| 
      
 365 
     | 
    
         
            +
            			etag: 'IJF@H#@923uf8023hFO@I#H#',
         
     | 
| 
      
 366 
     | 
    
         
            +
            			'content-type' : 'text/plain'
         
     | 
| 
      
 367 
     | 
    
         
            +
            		}
         
     | 
| 
      
 368 
     | 
    
         
            +
            	};
         
     | 
| 
      
 369 
     | 
    
         
            +
             
     | 
| 
      
 370 
     | 
    
         
            +
            	$.mockjax = function(settings) {
         
     | 
| 
      
 371 
     | 
    
         
            +
            		var i = mockHandlers.length;
         
     | 
| 
      
 372 
     | 
    
         
            +
            		mockHandlers[i] = settings;
         
     | 
| 
      
 373 
     | 
    
         
            +
            		return i;
         
     | 
| 
      
 374 
     | 
    
         
            +
            	};
         
     | 
| 
      
 375 
     | 
    
         
            +
            	$.mockjaxClear = function(i) {
         
     | 
| 
      
 376 
     | 
    
         
            +
            		if ( arguments.length == 1 ) {
         
     | 
| 
      
 377 
     | 
    
         
            +
            			mockHandlers[i] = null;
         
     | 
| 
      
 378 
     | 
    
         
            +
            		} else {
         
     | 
| 
      
 379 
     | 
    
         
            +
            			mockHandlers = [];
         
     | 
| 
      
 380 
     | 
    
         
            +
            		}
         
     | 
| 
      
 381 
     | 
    
         
            +
            	};
         
     | 
| 
      
 382 
     | 
    
         
            +
            })(jQuery);
         
     |