var fiber_jQuery = $.noConflict(true);

// fiber namespace
var Fiber = {};
Fiber.enhance_textarea = function(textarea) {};
Fiber.remove_textarea = function(textarea) {};

(function($) { // start of jQuery noConflict mode

// some plugins use jQuery() instead of $()
jQuery = $;

var busyIndicator = {
	show: function() {
		$('#wpr-admin-busy').show();
	},
	hide: function() {
		$('#wpr-admin-busy').hide();
	}
};


// abstract class for a basic admin dialog
var AdminDialog = Class.extend({

	// default options
	defaults: {
		url: null,
		width: 744,
		height: 'auto',
		start_width: 744,
		start_height: 480
	},

	// constructor
	init: function(options) {
		this.options = $.extend({}, this.defaults, options); // TODO: get dialog dimensions and behavior from options
		this.create_dialog();
		this.init_dialog();
		this.open();
	},

	// create a basic dialog, use only as example
	create_dialog: function() {
		this.uiDialog = $(document.createElement('div')).dialog({
			autoOpen: false,
			modal: true,
			resizable: false,
			width: this.options.start_width,
			height: this.options.start_height,
			position: ['center', 40]
		});

		this.uiDialog.dialog('option', 'title', 'Action'); // TODO: dynamically fill in action

		this.uiDialog.dialog('option', 'buttons', {
			'Action': {
				text: 'Action', // TODO: dynamically fill in action
				click: $.proxy(function() {
					this.action_click();
				}, this)
			},
			'Cancel': {
				text: 'Cancel',
				click: $.proxy(function() {
					this.cancel_click();
				}, this)
			}
		});

		this.uiDialog.dialog('option', 'close', $.proxy(this.close, this));
	},

	// initialize the dialog
	init_dialog: function() {},

	redraw: function() {
		this.uiDialog.dialog('option', 'width', this.options.width);
		this.uiDialog.dialog('option', 'height', this.options.height);
		this.uiDialog.dialog('option', 'position', ['center', 40]);
	},

	cancel_click: function() {
		this.close();
	},

	// customize open dialog behavior
	open: function() {
		this.uiDialog.dialog('open');
		this.redraw();
	},

	// customize close dialog behavior
	close: function() {
		this.uiDialog.dialog('option', 'close', null); // prevent recursive calls to this function
		this.uiDialog.dialog('close');
	},

	// customize destroy dialog behavior
	destroy: function() {
		this.uiDialog.dialog('destroy');
	}
});

// abstract class for a basic admin form dialog
var AdminFormDialog = AdminDialog.extend({

	// create admin form dialog
	create_dialog: function() {
		this._super();
		this.uiDialog.dialog('option', 'close', $.proxy(this.destroy, this));
	},

	// initialize the admin form
	init_dialog: function() {
		this.admin_form = new AdminForm({
			url: this.options.url
		});
		this.admin_form.admin_form_load_success = $.proxy(function() {
			this.append_form();
			this.redraw();
		}, this);
		this.admin_form.load();
	},

	// append form to the dialog
	append_form: function() {
		this.uiDialog.append(this.admin_form.form);
	},

	// customize destroy dialog behavior
	destroy: function() {
		this.admin_form.destroy();
		this._super();
	}
});


// abstract class for a basic admin REST dialog
var AdminRESTDialog = AdminDialog.extend({

	// initialize the REST call
	init_dialog: function() {
		busyIndicator.show();

		$.ajax({
			url: this.options.url,
			context: this,
			success: function(data) {
				if (this.init_dialog_success) {
					this.init_dialog_success(data);
				}
			}
		});
	}
});


// abstract class for a basic admin form
var AdminForm = Class.extend({

	defaults: {},

	// constructor
	init: function(options) {
		this.options = $.extend({}, options, this.defaults);
	},

	// load form from HTML, set styling and interaction
	load: function() {
		busyIndicator.show();

		$.ajax({
			url: this.options.url,
			context: this,
			success: function(data) {
				this.get_form_from_HTML(data);
				this.set_form_action();
				this.set_styling();
				if (this.admin_form_load_success) {
					this.admin_form_load_success();
				}
				this.set_interaction();

				busyIndicator.hide();
			}
		});
	},

	// get the form element from the HTML that is returned by the XHR
	get_form_from_HTML: function(html) {
		var forms = $(document.createElement('div')).html(this.strip_HTML(html)).find('#content-main form[id$=_form]');
		if (forms.length == 1) {
			this.form = $(forms[0]);

			this.form.append('<input type="hidden" name="_continue" />'); // this prevents the redirect to the changelist
		}
	},

	// helper function for cleaning HTML
	strip_HTML: function(html) {
		return html
		.replace(/\n/g, '\uffff')
		.replace(/<script(.*?)<\/script>/gm, '')
		.replace(/<link(.*?)>/gm, '')
		.replace(/<style(.*?)<\/style>/gm, '')
		.replace(/\sstyle=['"](.*?)['"]/gm, '')
		.replace(/\uffff/g, '\n');
	},

	// customize form action
	set_form_action: function(url) {
		if (url) {
			this.form.attr('action', url);
		} else if (this.options.url) {
			this.form.attr('action', this.options.url);
		}
	},

	// placeholder function for modifying styling of the form
	set_styling: function() {},

	// placeholder function for modifying behavior of the form
	set_interaction: function() {},

	destroy: function() {
		this.form.remove();
	}
});


var LoginFormDialog = AdminFormDialog.extend({

	defaults: {
		url: '/admin/',
		width: 340,
		height: 'auto',
		start_width: 340
	},

	// initialize the login form
	init_dialog: function() {
		this.admin_form = new LoginForm({
			url: this.options.url
		});
		this.admin_form.admin_form_load_success = $.proxy(function() {
			this.append_form();
			this.redraw();
		}, this);
		this.admin_form.load();

		this.uiDialog.dialog('option', 'title', 'Fiber Login'); // TODO: dynamically fill in action
		// TODO: is this the correct place for this?
		var action_button = this.uiDialog.parent().find(':button:contains("Action")');
		action_button.find('.ui-button-text').text('Login').attr('id', 'login_button');

	},

	action_click: function() {
		this.admin_form.form.ajaxSubmit({
			cache: false,
			url: '/admin/fiber/login/',
			type: 'POST',
			context: this,
			datatype: 'json',
			success: function(data) {
				if (data.status == 'success') {
					this.after_action_success();
				} else {
					var errornote = this.admin_form.form.find('p.errornote');
					errornote.text(data.message);
				}
			}
		});
	},

	after_action_success: function() {
		// when successful, reload the page
		reloadPage();
	},

	cancel_click: function() {
		this.destroy();
	}
});


var LoginForm = AdminForm.extend({

	set_styling: function() {
		// remove submit button(s) and `delete` link
		this.form.find('div.submit-row').remove();

		// strip ':' from the end of labels
		this.form.find('label').each(function() {
			$(this).text($(this).text().replace(':', ''));
		});
	},

	// get the form element from the HTML that is returned by the XHR
	get_form_from_HTML: function(html) {
		var errornote = $(document.createElement('p')).addClass('errornote');
		var forms = $(document.createElement('div')).html(this.strip_HTML(html)).find('form');
		if (forms.length == 1) {
			this.form = $(forms[0]);
			this.form.prepend(errornote);
		}
	},

	set_interaction: function() {
		this.form.find('#id_username').focus();
		this.form.find('#id_password').keypress(function (e) {
				if ((e.which && e.which == 13) || (e.keyCode && e.keyCode == 13)) {
					$('#login_button').click();
					return false;
				} else {
					return true;
				}
		});
	},

	destroy: function() {
		this.form.remove();
	}
});


var ChangeFormDialog = AdminFormDialog.extend({

	// initialize the change form
	init_dialog: function() {
		this.admin_form = new ChangeForm({
			url: this.options.url
		});
		this.admin_form.admin_form_load_success = $.proxy(function() {
			this.append_form();
			this.redraw();
		}, this);
		this.admin_form.load();

		// TODO: is this the correct place for this?
		var action_button = this.uiDialog.parent().find(':button:contains("Action")');
		action_button.find('.ui-button-text').text('Save');
	},

	action_click: function() {
		busyIndicator.show();

		this.admin_form.form.ajaxSubmit({
			cache: false,
			context: this,
			success: function(responseText, statusText, xhr, $form) {
				var response_change_form = new ChangeForm();

				response_change_form.get_form_from_HTML(responseText);

				if (response_change_form.form.find('p.errornote').length) {
					this.admin_form.destroy();
					this.admin_form = response_change_form;

					this.admin_form.set_form_action();
					this.admin_form.set_styling();
					this.append_form();
					this.admin_form.set_interaction();
				} else {
					this.after_action_success(responseText, statusText, xhr, $form);
				}
			}
		});
	},

	after_action_success: function(responseText, statusText, xhr, $form) {
		this.admin_form.destroy();
		this.close();
		reloadPage();
	},

	cancel_click: function() {
		this.destroy();
	}
});

function enhance_textareas(container) {
	container.find('textarea.fiber-editor').each(function() {
		Fiber.enhance_textarea(this);
	});
}

var ChangeForm = AdminForm.extend({

	set_styling: function() {
		// remove submit button(s) and `delete` link
		this.form.find('div.submit-row').remove();

		// strip ':' from the end of labels
		this.form.find('label').each(function() {
			$(this).text($(this).text().replace(':', ''));
		});
	},

	set_interaction: function() {
		enhance_textareas(this.form);
	},

	destroy: function() {
		this.form.find('textarea.fiber-editor').each(function() {
			Fiber.remove_textarea(this);
		});

		this.form.remove();
	}
});


var BaseFileSelectDialog = AdminRESTDialog.extend({

	open: function() {
		this._super();
		// Create the upload button after displaying the dialog, because plupload must know the dimensions of the button.
		this.create_upload_button();
	},

	get_upload_path: function() {
		// override this
	},

	refresh_grid: function() {
		// override this
	},

	create_upload_button: function() {
		var button_id = 'upload_file_button';
		var button_pane_id = 'select-file-buttonpane';

		var button_pane = this.uiDialog.parent().find('.ui-dialog-buttonpane');

		$('<button type="button">Upload a new file</button>')
			.prependTo(button_pane)
			.attr({
				'class': 'upload',
				'id': button_id
			})
			.button({
				icons: {
					primary: 'ui-icon-circle-plus'
				}
			});

		// Give button pane an id, so we can use it as container for uploader.
		button_pane.attr('id', button_pane_id);

		var uploader = new plupload.Uploader({
			runtimes: 'html5,flash',
			browse_button: button_id,
			url: this.get_upload_path(),
			flash_swf_url: STATIC_URL + 'fiber/js/plupload/plupload.flash.swf',
			multipart_params: {
				'sessionid': $.cookie('sessionid')
			},
			container: button_pane_id
		});

		uploader.bind('Init', function() {
			// connect 'FilesAdded' event after successful init
			uploader.bind('FilesAdded', function() {
				// start upload automatically
				uploader.start();
			});
		});

		uploader.bind('Error', function(up, error) {
			if (error.code != plupload.INIT_ERROR) {
				alert('Upload failed.');
			}
		});

		uploader.init();

		// Bind the 'FileUploaded' event after the init. Otherwise 'total.queued' has a wrong value.
		uploader.bind('FileUploaded', $.proxy(function() {
			if (uploader.total.queued === 0) {
				// all files are uploaded
				this.refresh_grid();
			}
		}, this));
	}
});


Fiber.ImageSelectDialog = BaseFileSelectDialog.extend({

	defaults: {
		url: '/api/v1/images.jqgrid-json',
		width: 480,
		height: 'auto',
		start_width: 480,
		start_height: 'auto'
	},

	// override default dialog window
	init_dialog: function() {
		// don't call _super, just call init_dialog_success at the end

		// enhance action button
		var action_button = this.uiDialog.parent().find(':button:contains("Action")');
		action_button.attr('id', 'action-button');

		action_button.find('.ui-button-text').text('Select');

		action_button.attr('disabled', 'disabled');
		action_button.addClass('ui-button-disabled ui-state-disabled');

		this.uiDialog.dialog('option', 'title', 'Select an image');

		this.init_dialog_success();
	},

	init_dialog_success: function(data) {

		var action_button = this.uiDialog.parent().find('#action-button');
		var filename = '';

		this.image_select_grid = $(document.createElement('table')).attr('id', 'ui-image-select-grid'); // the id attribute is necessary for jqGrid
		this.image_select_grid_pager = $(document.createElement('div')).attr('id', 'ui-image-select-grid-pager');
		this.image_select_filter = $(document.createElement('div')).attr('id', 'ui-image-select-filter');
		this.image_select_filter.append($(document.createElement('label')).attr({ id: 'ui-image-select-filter-label'}).text('Filter by filename'));
		this.image_select_filter.append($(document.createElement('input')).attr({ id: 'ui-image-select-filter-input', name: 'filter', value: '', type: 'text' }));
		this.uiDialog.append(this.image_select_filter);
		this.uiDialog.append(this.image_select_grid);
		this.uiDialog.append(this.image_select_grid_pager);

		$('#ui-image-select-filter-input').keyup(function() {
			var new_filename = $('#ui-image-select-filter-input').val();
			if (filename != new_filename) {
				filename = new_filename;
				$("#ui-image-select-grid").jqGrid('setGridParam',{ postData:{ filename: $('#ui-image-select-filter-input').val() }, search: true }).trigger("reloadGrid");
			}
		});

		var thumbnail_formatter = function(cellvalue, options, rowObject) {
			return '<img src="' + cellvalue + '" title="' + rowObject[2] + '" />';
		};

		this.image_select_grid.jqGrid({
			url: this.options.url,
			datatype: 'json',
			colNames: ['url', 'Image', 'Filename', 'Size', 'Updated'],
			colModel: [
				{ name: 'url', index: 'url', hidden: true },
				{ name: 'image', index: 'image', width: 120, resizable: false, sortable: false, formatter: thumbnail_formatter },
				{ name: 'filename', index: 'filename', width: 160, resizable: false },
				{ name: 'size', index: 'size', width: 80, resizable: false },
				{ name: 'updated', index: 'updated', width: 120, resizable: false }
			],
			rowNum: 50,
			pager: '#ui-image-select-grid-pager',
			shrinkToFit: false,
			width: 480,
			height: 300,
			sortname: 'updated',
			sortorder: 'desc',
			onSelectRow: function(id) {
				action_button.attr('disabled', '');
				action_button.removeClass('ui-button-disabled ui-state-disabled');
			},
			gridComplete: function() {
				var num_pages = $("#ui-image-select-grid").getGridParam('lastpage');
			    if (num_pages > 1) {
					$('#ui-image-select-grid-pager').show();
				} else {
					$("#ui-image-select-grid-pager").hide();
				}
			}
		});
	},

	get_upload_path: function() {
		return '/api/v1/images/';
	},

	refresh_grid: function() {
		this.image_select_grid.trigger('reloadGrid');
	},

	close: function() {
		this.image_select_grid.GridDestroy();
		this._super();
	},

	destroy: function() {
		this.image_select_grid.GridDestroy();
		this._super();
	}
});


Fiber.FileSelectDialog = BaseFileSelectDialog.extend({

	defaults: {
		url: '/api/v1/files.jqgrid-json',
		width: 480,
		height: 'auto',
		start_width: 480,
		start_height: 'auto'
	},

	// override default dialog window
	init_dialog: function() {
		// don't call _super, just call init_dialog_success at the end

		// enhance action button
		var actionButton = this.uiDialog.parent().find(':button:contains("Action")');
		actionButton.attr('id', 'action-button');

		actionButton.find('.ui-button-text').text('Select');

		actionButton.attr('disabled', 'disabled');
		actionButton.addClass('ui-button-disabled ui-state-disabled');

		this.uiDialog.dialog('option', 'title', 'Select a file');

		this.init_dialog_success();
	},

	init_dialog_success: function(data) {
		var action_button = this.uiDialog.parent().find('#action-button');
		var filename = '';

		this.file_select_grid = $(document.createElement('table')).attr('id', 'ui-file-select-grid'); // the id attribute is necessary for jqGrid
		this.file_select_grid_pager = $(document.createElement('div')).attr('id', 'ui-file-select-grid-pager');
		this.file_select_filter = $(document.createElement('div')).attr('id', 'ui-file-select-filter');
		this.file_select_filter.append($(document.createElement('label')).attr({ id: 'ui-file-select-filter-label'}).text('Filter by filename'));
		this.file_select_filter.append($(document.createElement('input')).attr({ id: 'ui-file-select-filter-input', name: 'filter', value: '', type: 'text' }));
		this.uiDialog.append(this.file_select_filter);
		this.uiDialog.append(this.file_select_grid);
		this.uiDialog.append(this.file_select_grid_pager);

		$('#ui-file-select-filter-input').keyup(function() {
			var new_filename = $('#ui-file-select-filter-input').val();
			if (filename != new_filename) {
				filename = new_filename;
				$("#ui-file-select-grid").jqGrid('setGridParam',{ postData:{ filename: $('#ui-file-select-filter-input').val() }, search: true }).trigger('reloadGrid');
			}
		});
		this.file_select_grid.jqGrid({
			url: this.options.url,
			datatype: 'json',
			data: { 'filename': 'praxis'},
			colNames: ['url', 'Filename', 'Updated'],
			colModel: [
				{ name: 'url', index: 'url', hidden: true },
				{ name: 'filename', index: 'filename', width: 360, resizable: false },
				{ name: 'updated', index: 'updated', width: 120, resizable: false }
			],
			rowNum: 50,
			pager: '#ui-file-select-grid-pager',
			shrinkToFit: false,
			width: 480,
			height: 300,
			sortname: 'updated',
			sortorder: 'desc',
			onSelectRow: function(id) {
				action_button.attr('disabled', '');
				action_button.removeClass('ui-button-disabled ui-state-disabled');
			},
			gridComplete: function() {
				var num_pages = $("#ui-file-select-grid").getGridParam('lastpage');
			    if (num_pages > 1) {
					$('#ui-file-select-grid-pager').show();
				} else {
					$("#ui-file-select-grid-pager").hide();
				}
			}
		});
	},

	get_upload_path: function() {
		return '/api/v1/files/';
	},

	refresh_grid: function() {
		this.file_select_grid.trigger('reloadGrid');
	},

	action_click: function() {
		// do something
	},

	cancel_click: function() {
		this.destroy();
	},

	close: function() {
		this.file_select_grid.GridDestroy();
		this._super();
	},

	destroy: function() {
		this.file_select_grid.GridDestroy();
		this._super();
	}
});


Fiber.PageSelectDialog = AdminRESTDialog.extend({

	defaults: {
		url: '/api/v1/pages.json',
		width: 480,
		height: 320,
		start_width: 480,
		start_height: 320
	},

	// override default dialog window
	init_dialog: function() {
		// don't call _super, just call init_dialog_success at the end

		// enhance action button
		var action_button = this.uiDialog.parent().find(':button:contains("Action")');
		action_button.attr('id', 'action-button');

		action_button.find('.ui-button-text').text('Select');

		action_button.attr('disabled', 'disabled');
		action_button.addClass('ui-button-disabled ui-state-disabled');

		this.uiDialog.dialog('option', 'title', 'Select page');

		this.init_dialog_success();
	},

	init_dialog_success: function(data) {
		var action_button = this.uiDialog.parent().find('#action-button');

		var page_tree_div = $(document.createElement('div'));
		this.uiDialog.append(page_tree_div);

		page_tree_div.bind(
			'select_node.jstree',
			function(event, data) {
				var id = data.rslt.obj.attr('id');
				action_button.attr('disabled', '');
				action_button.removeClass('ui-button-disabled ui-state-disabled');
			}
		);
		page_tree_div.bind(
			'loaded.jstree',
			function(event, data) {
				var menu_nodes = data.inst.get_container().find('li:visible');
				menu_nodes.find('a:visible, ins:visible').hide(); // hide menu node contents
				data.inst.get_container().css('marginLeft', -32); // move entire tree one level to the left
				data.inst.open_node(menu_nodes, false, false); // expand menu nodes
			}
		).jstree({
			core: {
				animation: 200
			},
			'json_data': {
				'ajax': {
					'url': '/api/v1/pages.json'
				}
			},
			plugins: ['json_data', 'ui', 'themeroller']
		});

	},

	action_click: function() {
		// do something
	},

	cancel_click: function() {
		this.destroy();
	}
});


var ChangePageFormDialog = ChangeFormDialog.extend({

	init_dialog: function() {
		var extra_field;
		this._super();

		this.admin_form.options.before_page_id = this.options.before_page_id;
		this.admin_form.options.below_page_id = this.options.below_page_id;
		this.admin_form.options.base_url = this.options.base_url;
		this.admin_form.set_interaction = function() {
			if (this.options.before_page_id) {
				extra_field = $('<input type="hidden" name="before_page_id" />');
				extra_field.val(this.options.before_page_id);
				this.form.append(extra_field);
			}

			if (this.options.below_page_id) {
				extra_field = $('<input type="hidden" name="below_page_id" />');
				extra_field.val(this.options.below_page_id);
				this.form.append(extra_field);
			}

			// automatically slugify the title field
			$('#id_title').attr('autocomplete', 'off');
			$('#id_title').slugify('#id_url');

		};
	}
});


var AddButton = Class.extend({ // TODO: subclass to AddPageButton / AddContentItemButton / AddOtherButton

	// default options
	defaults: {},

	init: function(fiber_item, options) {
		this.fiber_item = fiber_item;
		this.mouse_is_over = null;

		this.admin_layer = $('#admin-layer');

		this.set_options(options);
		this.set_appearance();
		this.attach_events();
	},

	set_options: function(options) {
		var params = this.fiber_item.element_data;
		this.options = $.extend({}, this.defaults, params, options);
	},

	set_appearance: function() {
		this.add_button = $('<a href="#" class="ui-button ui-widget ui-state-default add"></a>'); // TODO: rename to this.$element?
		this.admin_layer.append(this.add_button);
	},

	set_position: function() {
		this.add_button.position(this.fiber_item.button_position());
	},

	on_click: function() {
		// TODO: split this into subclasses
		if (this.fiber_item.element_data.type == 'page') {
			params = {
				url: this.options.add_url,
				before_page_id: this.options.before_page_id,
				below_page_id: this.options.parent_id, // TODO: rename below_page_id to parent_id?
				base_url: this.options.base_url
			};

			new ChangePageFormDialog(params); // TODO: create AddPageFormDialog?
		} else if (this.fiber_item.element_data.type == 'content_item') {
			params = {
				url: this.options.add_url,
				block_name: this.options.block_name,
				page_id: this.options.page_id,
				before_page_content_item_id: this.options.before_page_content_item_id
			};

			new AddContentItemFormDialog(params);
		}

		adminPage.hide_admin_elements();
		return false;
	},

	attach_events: function() {
		this.add_button.hover(
			$.proxy(this.on_mouseenter, this),
			$.proxy(this.on_mouseleave, this)
		);

		this.add_button.click(
			$.proxy(this.on_click, this)
		);
	},

	on_mouseenter: function(e) {
		e.stopPropagation();
		this.fiber_item.$element.trigger('mouseenter');
		this.add_button.addClass('ui-state-hover');
	},

	on_mouseleave: function(e) {
		e.stopPropagation();
		this.fiber_item.$element.trigger('mouseleave');
		this.add_button.removeClass('ui-state-hover');
	},

	show: function() {
		if ($.browser.msie && parseInt($.browser.version, 10) == 7) {
			this.add_button.addClass('ui-button'); // only necessary for IE7
		}
		this.add_button.show();
		this.set_position();
	},

	hide: function() {
		if ($.browser.msie && parseInt($.browser.version, 10) == 7) {
			this.add_button.removeClass('ui-button'); // only necessary for IE7
		}
		this.add_button.hide();
	}
});


var DroppableArea = Class.extend({

	// default options
	defaults: {},

	init: function(fiber_item, options) {
		this.fiber_item = fiber_item;

		this.admin_layer = $('#admin-layer');

		this.set_options(options);
		this.set_appearance();
		this.make_droppable();
	},

	set_options: function(options) {
		var params = $.parseJSON(this.fiber_item.$element.dataset('fiber-data'));
		this.options = $.extend({}, this.defaults, params, options);
	},

	set_appearance: function() {
		this.droppable_area = $('<div class="ui-droppable"></div>');

		this.admin_layer.append(this.droppable_area);
	},

	make_droppable: function() {
		this.droppable_area.droppable({
			scope: 'content_item',
			drop: $.proxy(function(event, ui) {
				var fiber_item_data = $.parseJSON($(ui.draggable).dataset('fiber-data'));
				if (fiber_item_data.type == 'content_item') {
					if (fiber_item_data.block_name) {
						// move content item
						this.move_content_item(fiber_item_data);
					}
					else {
						// drag content from menu
						this.add_content_item(fiber_item_data.id);
					}
				}
			}, this),
			tolerance: 'pointer',
			hoverClass: 'ui-state-hover',
			activeClass: 'ui-state-active'
		});
	},

	add_content_item: function(content_item_id) { // TODO: move to utils? (DRY)
		// perform an AJAX call to add the added object to the current page,
		// optionally placed before the beforePageContentItem
		var data = {
			content_item_id: content_item_id,
			page_id: this.options.page_id,
			block_name: this.options.block_name
		};

		if (this.options.before_page_content_item_id) {
			data.before_page_content_item_id = this.options.before_page_content_item_id;
		}

		busyIndicator.show();

		$.ajax({
			url: '/api/v1/page_content_items/',
			type: 'POST',
			data: data,
			success: function(data) {
				// when successful, reload the page
				reloadPage();
			}
		});
	},

	move_content_item: function(fiber_item_data) {
		busyIndicator.show();

		$.ajax({
			url: '/api/v1/page_content_item/' + fiber_item_data.page_content_item_id + '/',
			type: 'PUT',
			data: {
				before_page_content_item_id: this.fiber_item.element_data.page_content_item_id,
				action: 'move',
				block_name: this.fiber_item.element_data.block_name
			},
			success: function() {
				reloadPage();
			}
		});
	},

	set_position: function() {
		this.droppable_area.width(this.fiber_item.$element.outerWidth());
		this.droppable_area.position(this.fiber_item.droppable_position());
	},

	show: function() {
		this.droppable_area.show();
		this.set_position();
	},

	hide: function() {
		this.droppable_area.hide();
	}
});


var ChangeContentItemFormDialog = ChangeFormDialog.extend({

	init_dialog: function() {
		this._super();

		this.admin_form.options.page_id = this.options.page_id;
		this.admin_form.options.block_name = this.options.block_name;
		this.admin_form.options.before_page_content_item_id = this.options.before_page_content_item_id;
	}
});


var AddContentItemFormDialog = ChangeContentItemFormDialog.extend({

	init_dialog: function() {
		this._super();

		this.after_action_success = $.proxy(function(responseText, statusText, xhr, $form) {
			// find id of added content item
			var added_content_item_id = xhr.responseXML.URL.replace(/\/$/,'').split('/').pop();

			if (added_content_item_id) {
				this.add_content_item(added_content_item_id);
			}
		}, this);
	},

	add_content_item: function(content_item_id) { // TODO: move to utils? (DRY)
		// perform an AJAX call to add the added object to the current page,
		// placed before the beforeElement
		var data = {
			content_item_id: content_item_id,
			page_id: this.options.page_id,
			block_name: this.options.block_name
		};

		if (this.options.before_page_content_item_id) {
			data.before_page_content_item_id = this.options.before_page_content_item_id;
		}

		busyIndicator.show();

		$.ajax({
			url: '/api/v1/page_content_items/',
			type: 'POST',
			data: data,
			success: function(data) {
				// when successful, reload the page
				reloadPage();
			}
		});
	}
});


var adminPage = {
	all_fiber_items: [],

	create_fiber_item: function($fiber_element) {
		// create new FiberItem
		var fiber_item = new FiberItem($fiber_element);
		this.all_fiber_items.push(fiber_item);

		// find closest parent, and see if it is already a FiberItem
		var closest_parent = $fiber_element.parent().closest('[data-fiber-data]:not(body)');
		if (closest_parent.length) {
			var parent = null;
			$.each(this.all_fiber_items, function(i, all_fiber_item) {
				if (all_fiber_item.$element[0] == closest_parent[0]) {
					parent = all_fiber_item;
					return false;
				}
			});
			if (!parent) {
				parent = this.create_fiber_item(closest_parent);
			}
			parent.add_child(fiber_item);
			fiber_item.parent = parent;
		}
		return fiber_item;
	},

	get_fiber_item_containers: function() {
		var fiber_item_containers = [];
		$.each(this.all_fiber_items, function(i, fiber_item) {
			if (!fiber_item.parent) {
				fiber_item_containers.push(fiber_item);
			}
		});

		return fiber_item_containers;
	},

	init_admin_elements: function() {
		var fiber_elements = this.get_fiber_elements();

		// create nested structure of Fiber items
		$.each(this.get_fiber_elements(), $.proxy(function(i, fiber_element) {
			this.create_fiber_item($(fiber_element));
		}, this));

		$.each(this.all_fiber_items, function(i, fiber_item) {
			fiber_item.post_init();
		});
	},

	hide_admin_elements: function() {
		$.each(this.get_fiber_item_containers(), function(i, fiber_item_container) {
			fiber_item_container.hide_admin_elements();
		});
	},

	show_droppables: function() {
		$.each(this.get_fiber_item_containers(), function(i, fiber_item_container) {
			fiber_item_container.show_droppables();
		});
	},

	hide_droppables: function() {
		$.each(this.get_fiber_item_containers(), function(i, fiber_item_container) {
			fiber_item_container.hide_droppables();
		});
	},

	// get fiber elements in page (excluding admin divs).
	get_fiber_elements: function() {
		var page_divs = $(document.body).children(':visible').not('#wpr-admin-layer, #wpr-admin-sidebar');
		return page_divs.find('[data-fiber-data]');
	},

	// get page id from node (li)
	// TODO: move this to a more appropriate place? utils?
	get_page_id: function(node) {
		$node = $(node);
		return $.parseJSON(
			$node.find('a').first()
			.dataset('fiber-data')
		).id;
	},

	// TODO: move this to a more appropriate place? utils?
	get_parent_page_id: function(tree, node) {
		var parent_node = tree._get_parent(node);
		if (parent_node != -1) {
			return this.get_page_id(parent_node);
		} else {
			return 0;
		}
	},

	// TODO: move this to a more appropriate place? utils?
	get_left_page_id: function(tree, node) {
		var left_node = tree._get_prev(node, true);
		if (left_node) {
			return this.get_page_id(left_node);
		} else {
			return 0;
		}
	},

	// TODO: move this to a more appropriate place? utils?
	ajax_move_page: function(page_id, parent_id, left_id) {
		busyIndicator.show();

		$.ajax({
			url: '/api/v1/page/' + page_id + '/',
			type: 'PUT',
			dataType: 'json',
			data: {
				action: 'move',
				parent_id: parent_id,
				left_id: left_id
			},
			success: function(data) {
				reloadPage();
			}
		});
	},

	init_page_tree: function() {
		// remove menu nodes
		var root_ul = this.admin_page_tree.children('ul').first();
		var menu_nodes = root_ul.children('li');
		menu_nodes.each(function(i) {
			$this = $(this);
			var page_nodes = $this.children('ul').first().children('li');
			page_nodes.detach();
			$this.remove();
			root_ul.append(page_nodes);

			if (i !== 0) {
				page_nodes.first().addClass('menu-separator');
			}
		});

		// create page tree
		this.admin_page_tree.bind(
			'select_node.jstree',
			function(event, data) {
				var id = data.rslt.obj.attr('id');
				// TODO: handle page selection
			}
		);
		this.admin_page_tree.bind(
			'loaded.jstree',
			$.proxy(
				function(event, data) {
					var links = data.inst.get_container().find('a');

					links.each(function(i, link) {
						$link = $(link);

						// li's need an id, to be able to reopen and reselect them using cookies
						var data = $link.dataset('fiber-data');
						if (data) {
							$link.parent('li').attr('id', 'page-li-' + $.parseJSON(data).id);
						}

						// add context menu
						$link.bind('contextmenu', function(event) {
							$this = $(this);

							event.preventDefault();
							event.stopPropagation();

							// remove other visible context menus
							$(document.body).find('.ui-context-menu').remove();

							var page_data = $.parseJSON($this.dataset('fiber-data'));
							if (page_data) {
								var contextmenu = $('<ul class="ui-context-menu"></ul>');

								contextmenu.append(
									$('<li><a href="#">Edit</a></li>').click($.proxy(function() {
										var change_page_form_dialog = new ChangePageFormDialog({
											url: page_data.url,
											page_id: page_data.id,
											base_url: page_data.base_url
										});
									}, this))
								);

								contextmenu.append(
									$('<li><a href="#">Add sub page</a></li>').click($.proxy(function() {
										var add_page_form_dialog = new ChangePageFormDialog({
											url: page_data.add_url,
											below_page_id: page_data.id,
											base_url: page_data.base_url
										});
									}, this))
								);

								contextmenu.append(
									$('<li><a href="#">Delete</a></li>').click($.proxy(function() {

										// show a confirmation dialog, that also warns about sub pages that will be removed
										var confirmation_dialog = $('<div></div>').dialog({
											modal: true,
											resizable: false,
											width: 400,
											position: ['center', 40],
											buttons: {
												'Delete': function() {
													$this = $(this);
													$this.dialog('close');

													busyIndicator.show();

													$.ajax({
														url: '/api/v1/page/' + page_data.id + '/',
														type: 'DELETE',
														data: {},
														success: function(data) {
															// when successful, reload the current page
															reloadPage({
																error: function() {
																	// If page reload fails, because current page is deleted, then
																	// go to the parent of the deleted page.
																	reloadPage({
																		id: page_data.parent_id
																	});
																}
															});
														}
													});

												},
												'Cancel': function() {
													$this = $(this);
													$this.dialog('close');
												}
											}
										});

										var confirmation_text = '<p>Are you sure you want to delete the page "<strong>' + $.trim($this.text()) + '</strong>"?</p>';
										var num_sub_pages = $this.parent('li').find('li a').size();
										if (num_sub_pages) {
											if (num_sub_pages == 1) {
												confirmation_text += '<p>There is <strong>' + num_sub_pages + ' page</strong> below this page that will also be deleted.</p>';
											} else {
												confirmation_text += '<p>There are <strong>' + num_sub_pages + ' pages</strong> below this page that will also be deleted.</p>';
											}
										}

										confirmation_dialog.dialog('option', 'title', 'Are you sure?');
										confirmation_dialog.html(confirmation_text);
									}, this))
								);

								contextmenu.menu().removeClass('ui-corner-all');
								$(document.body).append(contextmenu);
								contextmenu.offset({ left: event.pageX, top: event.pageY });
							}
						});

					});

					this.admin_page_tree.show();
				},
				this
			)
		)
		.bind('click.jstree',
			$.proxy(
				function(event) {
					if ($(event.target).is('a')) {
						window.location = event.target.href;
					}
				},
				this
			)
		)
		.bind('move_node.jstree',
			$.proxy(
				function(event, data) {
					var tree = data.inst;
					var node = data.rslt.o;

					this.ajax_move_page(
						this.get_page_id(node),
						this.get_parent_page_id(tree, node),
						this.get_left_page_id(tree, node)
					);
				},
				this
			)
		)
		.jstree({
			core: {
				animation: 0
			},
			cookies: {
				'cookie_options': { path: '/' },
				'save_opened': 'page_tree_opened',
				'save_selected': 'page_tree_selected'
			},
			ui: {
				'select_multiple_modifier': false
			},
			plugins: ['ui', 'themeroller', 'cookies', 'html_data', 'dnd']
		});
	},

	init_content_tree: function() {
		this.admin_content_tree.bind(
			'loaded.jstree',
			$.proxy(
				function(event, data) {
					var links = data.inst.get_container().find('li');

					// li's need an id, to be able to reopen and reselect them using cookies
					links.each(function() {
						var data = $(this).dataset('fiber-data');
						if (data) {
							$(this).attr('id', 'content-li-' + $.parseJSON(data).id);
						}
					});

					this.admin_content_tree.find('li').each(function() {
						var data = $.parseJSON($(this).dataset('fiber-data'));
						if (data && data.type == 'content_item') {
							$(this).draggable({
								scope: 'content_item',
								revert: 'invalid',
								helper: 'clone'
							});
							$(this).bind('dragstart', function() {
								adminPage.show_droppables();
							});
							$(this).bind('dragstop', function() {
								adminPage.hide_droppables();
							});
						}
					});

					this.admin_content_tree.bind('contextmenu', function(event) {
						var link = $(event.target).closest('a');

						if (link.length) {
							event.preventDefault();
							event.stopPropagation();

							var data = $.parseJSON(link.parent('li').dataset('fiber-data'));

							$(document.body).find('.ui-context-menu').remove();

							var contextmenu = $('<ul class="ui-context-menu"></ul>');

							contextmenu.append(
								$('<li><a href="#">Edit</a></li>').click(function() {
									new ChangeContentItemFormDialog({
										url: data.url
									});
								})
							);

							contextmenu.append(
								$('<li><a href="#">Delete</a></li>').click(function() {
									var confirmationDialog = $('<div></div>').dialog({
										modal: true,
										resizable: false,
										width: 400,
										position: ['center', 40],
										buttons: {
											'Delete': function() {
												$(this).dialog('close');

												busyIndicator.show();

												$.ajax({
													url: '/api/v1/content_item/' + data.id + '/',
													type: 'DELETE',
													data: {},
													success: function(data) {
														reloadPage();
													}
												});
											},
											'Cancel': function() {
												$(this).dialog('close');
											}
										}
									});
									confirmationDialog.dialog('option', 'title', 'Are you sure?');
									confirmationDialog.html('<p>Are you sure you want to delete this item?</p>');
								})
							);

							contextmenu.menu().removeClass('ui-corner-all');
							$(document.body).append(contextmenu);
							contextmenu.offset({ left: event.pageX, top: event.pageY });
						}
					});

					this.admin_content_tree.show();
				},
				this
			)
		)
		.jstree({
			core: {
				animation: 0
			},
			cookies: {
				'cookie_options': { path: '/' },
				'save_opened': 'content_tree_opened',
				'save_selected': 'content_tree_selected'
			},
			ui: {
				'select_multiple_modifier': false
			},
			themeroller: {
				'item_a': 'dummy' // disable hover effect for content items
			},
			plugins: ['ui', 'themeroller', 'html_data', 'cookies']
		});
	},

	toggleAdminSidebar: function() {
		var animation_duration = 200;

		var wpr_admin_sidebar = this.wpr_admin_sidebar;
		var toggle_button = this.toggle_button;

		// define animation values
		var animate_sidebar_left_to = wpr_admin_sidebar.hidden ? 0 : (10 - 240);
		var animate_body_left_to = wpr_admin_sidebar.hidden ? 240 : 10;

		function toggle_sidebar() {
			wpr_admin_sidebar.hidden = wpr_admin_sidebar.hidden ? false : true;
			$.cookie('admin-sidebar-hidden', wpr_admin_sidebar.hidden, { path: '/' });
			if (wpr_admin_sidebar.hidden) {
				this.hide_sidebar();
			} else {
				this.show_sidebar();
			}
		}

		wpr_admin_sidebar.animate(
			{
				left: animate_sidebar_left_to
			},
			animation_duration,
			$.proxy(toggle_sidebar, this)
		);

		$('#wpr-body').animate(
			{
				left: animate_body_left_to,
				marginRight: animate_body_left_to
			},
			animation_duration
		);

		this.hide_admin_elements();
	},

	init_toggle_admin_sidebar: function() {
		var hidden = $.cookie('admin-sidebar-hidden') == 'true' ? true : false;
		if (hidden) {
			this.hide_sidebar();
		}
		else {
			this.show_sidebar();
		}

		this.toggle_button.click(
			$.proxy(this.toggleAdminSidebar, this)
		);
	},

	show_sidebar: function() {
		this.wpr_admin_sidebar.hidden = false;

		$('body').addClass('admin-sidebar');
		this.toggle_button.removeClass('hidden');
		this.wpr_admin_sidebar.removeClass('hidden');
	},

	hide_sidebar: function() {
		this.wpr_admin_sidebar.hidden = true;

		$('body').removeClass('admin-sidebar');
		this.toggle_button.addClass('hidden');
		this.wpr_admin_sidebar.addClass('hidden');
	},

	init_admin_sidebar: function() {
		this.wpr_admin_layer = $('#wpr-admin-layer');
		this.wpr_admin_sidebar = $('#wpr-admin-sidebar');
		this.admin_sidebar = $('#admin-sidebar');
		this.admin_page_tree = $('#admin-sidebar-page-tree');
		this.admin_content_tree = $('#admin-sidebar-content-tree');
		this.toggle_button = $('#btn-toggle-admin-sidebar');

		$(document.body)
			.children(':first-child')
			.nextUntil('#wpr-admin-layer')
			.andSelf()
			.wrapAll('<div id="wpr-body"></div>');

		this.admin_page_tree.hide();
		this.admin_content_tree.hide();

		this.init_page_tree();
		this.init_content_tree();
		this.init_toggle_admin_sidebar();
	},

	init_backend: function() {
		enhance_textareas($(document.body));
	},

	init: function(body_fiber_data) {
		this.body_fiber_data = body_fiber_data;

		if (body_fiber_data.frontend) {
			this.init_admin_sidebar();
			this.init_admin_elements();
		}
		else if (body_fiber_data.backend) {
			this.init_backend();
		}

		// TODO: move context menu hiding to another place
		// hide context menus when scrolling or resizing the window
		$(window).bind('scroll resize', function() {
			$(document.body).find('.ui-context-menu').remove();
		});

		// hide context menus when scrolling the sidebar
		$('#admin-sidebar').bind('scroll', function() {
			$(document.body).find('.ui-context-menu').remove();
		});

		// hide context menus when (right)clicking somewhere else
		$(document.body).bind('click contextmenu', function() {
			$(document.body).find('.ui-context-menu').remove();
		});
	}
};

/* Reload page.
  If this is a fiber page, then obtain the current url from the server api.
  Otherwise, use the current url.

  params (optional): dictionary
	id (optional): page id to reload, default is the current page
	error (optional): callback function if the page cannot be reloaded

  Examples:
	// reload the current page
	reloadPage();

	// reload this page id
	reloadPage({
		id: page_id
	});

	// reload current page, if it fails load a fallback page
	reloadPage({
		error: function() {
			reloadPage(fallback_page_id);
		}
	});
*/
function reloadPage(params) {
	var page_id;

	if (params && params.id) {
		page_id = params.id;
	}

	if (!page_id) {
		// Get the id of the current page.
		page_id = $.parseJSON($('body').dataset('fiber-data')).page_id;
	}

	if (!page_id) {
		// Page id is not available, so this is not a fiber page.
		// Reload current url.
		window.location.replace(window.location);
	} else {
		busyIndicator.show();

		$.ajax({
			url: '/api/v1/page/' + page_id + '/',
			type: 'GET',
			success: function(data) {
				window.location.replace(data.data.attr.href);
			},
			error: function() {
				if (params && params.error) {
					params.error();
				}
			}
		});
	}
}


// TODO: subclass for specific uses (add / change) and types (page / content / other)
var FiberItem = Class.extend({
	// TODO: add defaults?

	init: function($element) {
		this.$element = $element;
		this.element_data = $.parseJSON(this.$element.dataset('fiber-data'));

		this.parent = null;
		this.children = [];
	},

	// this is run after the nested structure of fiber items is generated
	post_init: function() {
		this.button = null;
		this.droppable = null;

		// set minimum height of (possibly empty) containers
		// TODO: also do this for menus?
		if (this.element_data.type == 'content_item' && !this.parent) {
			this.$element.css('min-height', '20px');
		}

		this.attach_events();
		this.make_draggable();
	},

	add_child: function(child) {
		this.children.push(child);
	},

	show_admin_element: function() {
		if (!this.button) {
			this.create_button();
		}
		this.button.show();
	},

	show_admin_elements: function() {
		// show nested admin elements
		$.each(this.children, function(i, child) {
			child.show_admin_elements();
		});

		this.show_admin_element();
	},

	hide_admin_element: function() {
		if (this.button) {
			this.button.hide();
		}
	},

	hide_admin_elements: function() {
		// hide nested admin elements
		$.each(this.children, function(i, child) {
			child.hide_admin_elements();
		});

		this.hide_admin_element();
	},

	show_droppable: function() {
		// TODO: move to separate content_item class
		if (this.element_data.type == 'content_item') {
			if (!this.droppable) {
				this.create_droppable();
			}
			this.droppable.show();
		}
	},

	show_droppables: function() {
		// show nested droppables
		$.each(this.children, function(i, child) {
			child.show_droppables();
		});

		this.show_droppable();
	},

	hide_droppable: function() {
		if (this.droppable) {
			this.droppable.hide();
		}
	},

	hide_droppables: function() {
		// hide nested droppables
		$.each(this.children, function(i, child) {
			child.hide_droppables();
		});

		this.hide_droppable();
	},

	make_draggable: function() {
		if (this.element_data.type == 'content_item' && this.parent) {
			this.$element.draggable({
				scope: 'content_item',
				revert: 'invalid',
				zIndex: 1001,
				start: function() {
					adminPage.show_droppables();
				},
				stop: function() {
					adminPage.hide_droppables();
				}
			});
		}
	},

	orientation: function() {
		if (this.parent) {
			return this.parent.orientation();
		} else {
			if (!this._orientation) {
				if (this.$element.is('ul')) {
					var second = $('<li><a href="#">2</a></li>').prependTo(this.$element);
					var first = $('<li><a href="#">1</a></li>').prependTo(this.$element);
					if (first.offset().left < second.offset().left) {
						this._orientation = 'horizontal';
					} else {
						this._orientation = 'vertical';
					}
					first.remove();
					second.remove();
				}
			}
			return this._orientation;
		}
	},

	create_button: function() {
		// TODO: split this into subclasses
		if (this.element_data.type == 'page') {
			params = {
				before_page_id: this.element_data.id
			};
		} else if (this.element_data.type == 'content_item') {
			params = {
				before_page_content_item_id: this.element_data.id
			};
		}

		this.button = new AddButton(
			this, params
		);
	},

	button_position: function() {
		position_params = {
			my: 'center center',
			at: 'left top',
			of: this.$element
		};

		if (this.element_data.type == 'page') {

			if (this.orientation() == 'horizontal') {
				if (this.element_data.url) {
					// menu items should have a '+' before them
					position_params = {
						my: 'center center',
						at: 'left center',
						of: this.$element.parent('li')
					};
				} else {
					// menu item containers should have a '+' at the end
					position_params = {
						my: 'center center',
						at: 'right center',
						of: this.$element.children('li').length ? this.$element.children('li:last') : this.$element
					};
				}
			} else if (this.orientation() == 'vertical') {
				if (this.element_data.url) {
					// menu items should have a '+' before them
					position_params = {
						my: 'center center',
						at: 'center top',
						of: this.$element.parent('li')
					};
				} else {
					// menu item containers should have a '+' at the end
					position_params = {
						my: 'center center',
						at: 'center bottom',
						of: this.$element.children('li').length ? this.$element.children('li:last') : this.$element
					};
				}
			}

		} else if (this.element_data.type == 'content_item') {
			// content item containers should have a '+' at the end
			if (!this.element_data.url) {
				if (this.children.length) {
					position_params.at = 'left bottom';
				}
			}
		}

		return position_params;
	},

	create_droppable: function() {
		this.droppable = new DroppableArea(
			this
		);
	},

	droppable_position: function() {
		position_params = {
			my: 'left top',
			at: 'left top',
			of: this.$element,
			offset: '0 -8'
		};

		if (!this.element_data.url) {
			// containers should have a droppable at the end
			if (this.children.length) {
				position_params.at = 'left bottom';
			} else {
				position_params.at = 'left top';
			}
		}

		return position_params;
	},

	attach_events: function() {
		this.$element.hover(
			$.proxy(this.on_mouseenter, this),
			$.proxy(this.on_mouseleave, this)
		);

		this.$element.dblclick(
			$.proxy(this.on_dblclick, this)
		);

		this.$element.bind('contextmenu',
			$.proxy(this.on_contextmenu, this)
		);
	},

	on_mouseenter: function(e) {
		// bubble mouseenter to containers
		e.stopPropagation();
		if (!this.parent) {
			this.show_admin_elements();
		} else {
			this.parent.$element.trigger('mouseenter');
		}
	},

	on_mouseleave: function(e) {
		// bubble mouseleave to containers
		e.stopPropagation();
		if (!this.parent) {
			this.hide_admin_elements();
		} else {
			this.parent.$element.trigger('mouseleave');
		}
	},

	on_dblclick: function() {
		this.edit_content_item();
		return false;
	},

	on_contextmenu: function(e) {
		e.preventDefault();
		e.stopPropagation();

		// remove other visible context menus
		$(document.body).find('.ui-context-menu').remove();

		var contextmenu = $('<ul class="ui-context-menu"></ul>');

		if (this.element_data.type == 'page') {
			contextmenu.append(
				$('<li><a href="#">Edit</a></li>').click(
					$.proxy(this.edit_page, this)
				)
			);
		} else if (this.element_data.type == 'content_item') {
			contextmenu.append(
				$('<li><a href="#">Edit</a></li>').click(
					$.proxy(this.edit_content_item, this)
				)
			);

			contextmenu.append(
				$('<li><a href="#">Remove from page</a></li>').click(
					$.proxy(this.remove_from_page, this)
				)
			);
		}

		contextmenu.menu().removeClass('ui-corner-all');
		$(document.body).append(contextmenu);

		contextmenu.offset({ left: e.pageX, top: e.pageY });
	},

	// TODO: move to page specific class (remove / delete)
	remove_from_page: function() {
		busyIndicator.show();
		adminPage.hide_admin_elements();

		$.ajax({
			url: '/api/v1/page_content_item/' + this.element_data.page_content_item_id + '/',
			type: 'DELETE',
			data: {},
			success: function(data) {
				reloadPage();
			}
		});
	},

	// TODO: move to page specific class (edit)
	edit_page: function() {
		adminPage.hide_admin_elements();

		var changePageFormDialog = new ChangePageFormDialog({
			url: this.element_data.url,
			page_id: this.element_data.id,
			base_url: this.element_data.base_url
		});
	},

	// TODO: move to content item specific class (edit)
	edit_content_item: function() {
		adminPage.hide_admin_elements();

		new ChangeContentItemFormDialog({
			url: this.element_data.url
		});
	}
});


$(window).ready(function() {
	var body_fiber_data = $.parseJSON($('body').dataset('fiber-data'));
	adminPage.init(body_fiber_data);

	if (body_fiber_data.show_login) {
		loginform = new LoginFormDialog();
	}
});

})(fiber_jQuery); // end of jQuery noConflict mode
