Frontend.Controller = Class.extend({
	/**
	 * Controller vars set server-side with Frontend->setJson()
	 *
	 * @var obj
	 */
	_frontendData: {},
	/**
	 * String list of the used components
	 *
	 * @var Array
	 */
	components: [],
	baseComponents: [],
	/**
	 * Holds a reference to the parentController, if set.
	 *
	 * @return Controller
	 */
	parentController: null,
	name: null,
	action: null,
	/**
	 * Holds the DOM element of this controller.
	 *
	 * @var DOMElement
	 */
	_dom: null,
	$: null,
	/**
	 * Class constructor
	 *
	 * @param	obj		vars	The controller vars made available by setJson()
	 * @param	Controller	parentController	(optional) Parent controller instance.
	 * @return	void
	 */
	init: function(frontendData, parentController) {
		this.parentController = parentController;
		this._frontendData = frontendData;
		this.name = this._frontendData.request.controller;
		this.action = this._frontendData.request.action;

		var selector = 'div.controller.' + this._frontendData.request.controller + '-' + stringUnderscore(this._frontendData.request.action);
		this._dom = $(selector);
		this.$ = this._dom.find.bind(this._dom);

		this._dom.find('.dialog-ajax-form').each(function(i, el) {
			this._ajaxDialogFormSetup($(el));
		}.bind(this));

		this.__initComponents();
		this._initialize();
	},
	/**
	 * Returns the contents of a view var, otherwise null
	 *
	 * @param string	key		The var name
	 * @return mixed
	 */
	getVar: function(key) {
		if (typeof this._frontendData.jsonData[ key ] != 'undefined') {
			return this._frontendData.jsonData[ key ];
		}
		return null;
	},
	/**
	 * Startup callback - can be implemented by sub controllers
	 *
	 * @return void
	 */
	_initialize: function() {
		this.startup();
	},
	/**
	 * Startup callback - can be implemented by sub controllers
	 *
	 * @return void
	 */
	startup: function() {},
	/**
	 * Initializes the configured components
	 *
	 * @return void
	 */
	__initComponents: function() {
		for(var i in this.baseComponents) {
			this.components.push(this.baseComponents[ i ]);
		}
		for(var i in this.components) {
			var name = this.components[i] + 'Component';
			if (typeof window['App']['Components'][ name ] == "function") {
				this[ this.components[i] ] = new window['App']['Components'][ name ](this);
				this[ this.components[i] ].startup();
			}
			else if (typeof this.components[i] == 'string') {
				console.error("Component %s not found", this.components[i]);
			}
		}
	},
	/**
	 * Makes an AJAX request to the server and returns the results.
	 *
	 * @param mixed		url		Either a string url or a Router-compatible url object
	 * @param Object	data	(optional)	POST data
	 * @param Function	responseCallback	The function which will receive the response
	 * @return void
	 */
	request: function(url, data, responseCallback) {
		App.Main.request(url, data, responseCallback);
	},
	isAjax: function() {
		return this.getVar('isAjax') === true;
	},
	/**
	 * Returns Server-side state value for mobile-check
	 *
	 * @return {boolean}
	 */
	isMobile: function() {
		return this.getVar('isMobile');
	},
	/**
	 * If the current request was made via ajax, bind the submit event, make an ajax
	 * POST request and update the dialog
	 * TODO: make URL and loadJsonAction options configurable
	 * @return {void}
	 */
	_ajaxDialogFormSetup: function($form, callback) {
		if (!this.isAjax()) {
			return false;
		}
		var url = {
			controller: camelCase(this.name),
			action: this.action,
			pass: this._frontendData.request.pass,
			plugin: this._frontendData.request.plugin,
			query: this._frontendData.request.query
		};
		$form.submit(function(e) {
			e.preventDefault();
			App.Main.UIBlocker.blockElement(this._dom);
			App.Main.loadJsonAction(url, {
				target: this._dom.parent(),
				data: $form.serialize(),
				parentController: this.parentController,
				onComplete: function(controller, response) {
					if ($form.hasClass('dialog-ajax-form-close-on-success') && response.data.frontendData.jsonData.success) {
						$('.modal').modal('hide').data('bs.modal', null);
						App.Main.publishEvent('ajaxDialog.closed', response);
					}
					App.Main.UIBlocker.unblockElement(this._dom);
					if (typeof callback === 'function') {
						callback(controller, response);
					}
				}
			});
			return false;
		}.bind(this));
	},
	/**
	 * If the current request was made via ajax, bind the submit event, make an ajax
	 * POST request and update the dialog
	 * TODO: make this more configurable
	 * @return {void}
	 */
	openDialog: function(url, onClose) {
		this._dialog = new Frontend.Dialog({
			onClose: onClose
		});
		this._dialog.blockUi();
		App.Main.loadJsonAction(url, {
			parentController: this,
			dialog: this._dialog,
			target: this._dialog.getContent(),
			onComplete: function() {
				this._dialog.show();
				this._dialog.unblockUi();
			}.bind(this)
		});
	}
});

@@ -3586,16 +3586,111 @@
 ry%0A%09%09%7D;%0A
+%09%09if ($form.hasClass('dialog-ajax-form-use-form-action')) %7B%0A%09%09%09url = $form.attr('action');%0A%09%09%7D%0A
 %09%09$form.

Fix plugin routing