| <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.5.0/css/font-awesome.min.css">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css"
      integrity="sha384-1q8mTJOASx8j1Au+a5WDVnPi2lkFfwwEAa8hDDdjZlpLegxhjVME1fgjWPGmkzs7" crossorigin="anonymous">
<link rel="stylesheet" href="../node_modules/eonasdan-bootstrap-datetimepicker/build/css/bootstrap-datetimepicker.min.css">
<link rel="stylesheet" href="../node_modules/mesour-editable/dist/css/mesour.editable.min.css">
<style>
</style>
<?php
define('SRC_DIR', __DIR__ . '/../src/');
require_once __DIR__ . '/../vendor/autoload.php';
@mkdir(__DIR__ . '/log');
@mkdir(__DIR__ . '/tmp');
if (file_exists(__DIR__ . '/environment.php')) {
	require_once __DIR__ . '/environment.php';
}
\Tracy\Debugger::enable(\Tracy\Debugger::DEVELOPMENT, __DIR__ . '/log');
\Tracy\Debugger::$strictMode = true;
use \Mesour\Editable\Rules\RuleType;
$loader = new Nette\Loaders\RobotLoader;
$loader->addDirectory(SRC_DIR);
$loader->setCacheStorage(new Nette\Caching\Storages\FileStorage(__DIR__ . '/tmp'));
$loader->register();
// CONNECTION & NDBT
$connection = new \Nette\Database\Connection(
	'mysql:host=127.0.0.1;dbname=mesour_editable',
	'root',
	'root'
);
$cacheMemoryStorage = new \Nette\Caching\Storages\MemoryStorage();
$structure = new \Nette\Database\Structure($connection, $cacheMemoryStorage);
$conventions = new \Nette\Database\Conventions\DiscoveredConventions($structure);
$context = new \Nette\Database\Context($connection, $structure, $conventions, $cacheMemoryStorage);
// SELECTION
$selection = $context->table('users');
$selection->select('users.*');
// SOURCE
$source = new \Mesour\Sources\NetteDbTableSource('users', 'id', $selection, $context);
$dataStructure = $source->getDataStructure();
$dataStructure->renameColumn('groups', 'group');
$dataStructure->renameColumn('user_addresses', 'addresses');
$dataStructure->renameColumn('wallets', 'wallet');
/** @var \Mesour\Sources\Structures\Columns\ManyToOneColumnStructure $groupColumn */
$groupColumn = $dataStructure->getColumn('group');
$groupColumn->setPattern('{name} ({members})');
/** @var \Mesour\Sources\Structures\Columns\OneToManyColumnStructure $addressColumn */
$addressColumn = $dataStructure->getColumn('addresses');
$addressColumn->setPattern('{street}, {zip} {city}, {country}');
/** @var \Mesour\Sources\Structures\Columns\ManyToManyColumnStructure $companiesColumn */
$companiesColumn = $dataStructure->getColumn('companies');
$companiesColumn->setPattern('{name}');
/** @var \Mesour\Sources\Structures\Columns\OneToOneColumnStructure $walletColumn */
$walletColumn = $dataStructure->getColumn('wallet');
$walletColumn->setPattern('{amount}');
// EDITABLE STRUCTURE
$structure = \Mesour\Editable\Structures\DataStructure::fromSource($source);
$structure->addText('name', 'Name')
	->stripHtml(false)
	->setInline()
	->addRule(RuleType::EMAIL, 'Test email message.');
$structure->addCustom('special', 'special', 'Special')
	->setParameter('test', ['value' => 123]);
$groupsElement = $structure->getElement('groups');
$groupsElement->addText('name', 'Name')
	->addRule(RuleType::PATTERN, 'Test email message.', '[0-9a-z]{6}');
$groupsElement->addEnum('type', 'Type')
	->setNullable(false)
	->setValues([
		null => '--',
		'Group' => [
			'first' => 'First',
			'second' => 'Second',
		],
	]);
$groupsElement->addDate('date', 'Date')
	->setFormat('Y-m-d H:i:s');
$groupsElement->addNumber('members', 'Members')
	->addRule(RuleType::RANGE, 'Rule type range error', [0, 50])
	->setUnit('EUR')
	->setDecimals(2)
	->setDecimalPoint(',')
	->setThousandSeparator('.');
$addressesElement = $structure->getElement('user_addresses');
$addressesElement->addText('street', 'Street')
	->setTextarea();
$addressesElement->addText('city', 'City');
$addressesElement->addText('zip', 'Zip');
$addressesElement->addText('country', 'Country');
$companiesElement = $structure->getElement('companies');
$companiesElement->addText('name', 'Name');
$companiesElement->addText('reg_num', 'Reg. number');
$companiesElement->addBool('verified', 'Verified');
$companiesElement->addCustom('special', 'special', 'Special');
$walletElement = $structure->getElement('wallets');
$walletElement->addNumber('amount', 'Amount')
	->setDecimalPoint(',')
	->setThousandSeparator('.')
	->setDecimals(2);
$walletElement->addEnum('currency', 'Currency');
$domains = $structure->getOrCreateElement('domains', 'id');
$domains->addText('url', 'Url')
	->addRule(RuleType::URL, 'Url is not valid');
function createForUser(\Mesour\Editable\Structures\IDataStructure $structure, $userId)
{
	$structure->addText('name', 'Name', $userId)
		->setTextarea()
		->addRule(\Mesour\Editable\Rules\RuleType::FILLED, 'Test error message.')
		->setEditPermission('user-editable', 'name-edit');
	$structure->addNumber('surname', 'Surname', $userId)
		->setNullable()
		->setEditPermission('user-editable', 'surname-edit')
		->addRule(RuleType::NUMERIC, 'Surname must be number.');
	$structure->addText('email', 'Email', $userId)
		->setEditPermission('user-editable', 'email-edit');
	$structure->addNumber('amount', 'Amount', $userId)
		->setUnit('EUR')
		->setDecimalPoint(',')
		->setThousandSeparator('.')
		->setDecimals(2)
		->setEditPermission('user-editable', 'amount-edit');
	$structure->addDate('last_login', 'Last login', $userId)
		->setFormat('Y-m-d H:i:s')
		->setEditPermission('user-editable', 'last_login-edit');
	$structure->addEnum('role', 'Role', $userId)
		->setValues([
				'Main' => [
					'admin' => 'Admin',
					'moderator' => 'Moderator',
				],
				'Other' => [
					'test' => 'Test',
				],
		])
		->setEditPermission('user-editable', 'role-edit');
	$structure->addBool('has_pro', 'Has PRO', $userId)
		->setDescription('Has PRO')
		->setEditPermission('user-editable', 'has_pro-edit');
	$domains = $structure->addOneToOne('domains', 'Domains', $userId);
	$domains->setReference('domains', 'id', null, '{url}');
	$domains->enableCreateNewRow();
	$domains->enableRemoveRow();
	$domains->useCustomData([
		[
			'id' => 0,
			'url' => 'http://example.com',
		]
	]);
	$structure->addOneToOne('wallet', 'Wallet', $userId)
		->enableRemoveRow()
		->enableCreateNewRow()
		->setEditPermission('user-editable', 'wallet-edit');
	$structure->addManyToOne('group', 'Group', $userId)
		->enableEditCurrentRow()
		->enableEditCurrentRow()
		->enableCreateNewRow()
		->setEditPermission('user-editable', 'group-edit')
		->setRemovePermission('user-editable', 'group-remove')
		->setCreatePermission('user-editable', 'group-create');
	$structure->addOneToMany('addresses', 'Addresses', $userId)
		->enableCreateNewRow()
		->enableRemoveRow()
		->setEditPermission('user-editable', 'addresses-edit')
		->setRemovePermission('user-editable', 'addresses-remove')
		->setCreatePermission('user-editable', 'addresses-create');
	$structure->addManyToMany('companies', 'Companies', $userId)
		->enableCreateNewRow()
		->enableRemoveRow()
		->enableAttachRow()
		->setEditPermission('user-editable', 'companies-edit')
		->setRemovePermission('user-editable', 'companies-remove')
		->setAttachPermission('user-editable', 'companies-attach')
		->setCreatePermission('user-editable', 'companies-create');
}
// APPLICATION
$application = new \Mesour\UI\Application('mesourApp');
$application->setRequest($_REQUEST);
$application->setUserRole('admin');
$auth = $application->getAuthorizator();
$auth->addRole('guest');
$auth->addRole('registered', 'guest');
$auth->addRole('admin', 'registered');
$auth->addResource('user-editable');
$auth->allow('admin', 'user-editable');
$auth->deny('registered', 'user-editable', 'companies-edit');
$auth->deny('registered', 'user-editable', 'companies-create');
$auth->deny('registered', 'user-editable', 'companies-remove');
$auth->deny('registered', 'user-editable', 'companies-attach');
$application->run();
// EDITABLE
$editable = new \Mesour\UI\Editable('editableTest', $application);
createForUser($structure, 1);
$editable->setDataStructure($structure);
//$editable->setInline();
//$editable->disableInlineAlerts();
$editable->onCreate[] = function (
	\Mesour\Editable\Structures\Fields\IStructureElementField $field,
	array $newValues,
	$identifier = null,
	array $params = []
) use ($context) {
	if ($field->getName() === 'companies') {
		if (!strlen(trim($newValues['name']))) {
			$exception = new \Mesour\Editable\ValidatorException('Company name is required');
			$exception->setFieldName('name');
			throw $exception;
		}
		$company = $context->table('companies')->insert($newValues);
		$context->table('user_companies')->insert(
			[
				'user_id' => $identifier,
				'company_id' => $company->getPrimary(),
			]
		);
	} elseif ($field->getName() === 'group') {
		if (!strlen(trim($newValues['name']))) {
			$exception = new \Mesour\Editable\ValidatorException('Group name is required');
			$exception->setFieldName('name');
			throw $exception;
		}
		$group = $context->table('groups')->insert($newValues);
		$context->table('users')
			->where('id = ?', $identifier)
			->update(
				[
					'group_id' => $group->getPrimary(),
				]
			);
	} elseif ($field->getName() === 'wallet') {
		$newValues['user_id'] = $identifier;
		$wallet = $context->table('wallets')->insert($newValues);
		$context->table('users')
			->where('id = ?', $identifier)
			->update(
				[
					'wallet_id' => $wallet->getPrimary(),
				]
			);
	} elseif ($field->getName() === 'addresses') {
		if (!strlen(trim($newValues['country']))) {
			$exception = new \Mesour\Editable\ValidatorException('Country is required');
			$exception->setFieldName('country');
			throw $exception;
		}
		$context->table('user_addresses')->insert(
			array_merge(
				$newValues,
				[
					'user_id' => $identifier,
				]
			)
		);
	}
};
$editable->onRemove[] = function (
	\Mesour\Editable\Structures\Fields\IStructureElementField $field,
	$value,
	$identifier = null
) use ($context) {
	if ($field->getName() === 'companies') {
		$reference = $field->getReference();
		$companyPrimaryKey = $reference['self_column'];
		$userPrimaryKey = $reference['column'];
		$context->table('user_companies')
			->where($companyPrimaryKey . ' = ?', $value)
			->where($userPrimaryKey . ' = ?', $identifier)
			->delete();
	} elseif ($field->getName() === 'addresses') {
		$context->table('user_addresses')
			->where('id = ?', $value)
			->delete();
	} elseif ($field->getName() === 'wallet') {
		$context->table('wallets')
			->where('id = ?', $value)
			->delete();
	}
};
$editable->onAttach[] = function (
	\Mesour\Editable\Structures\Fields\IStructureElementField $field,
	\Mesour\Editable\Structures\Reference $reference,
	$identifier = null,
	array $params = []
) use ($context) {
	if ($field->getName() === 'companies') {
		$context->table('user_companies')
			->insert(
				[
					$reference->getFromId() => $reference->getFromValue(),
					$reference->getToId() => $reference->getToValue(),
				]
			);
	}
};
$editable->onEditElement[] = function (
	\Mesour\Editable\Structures\Fields\IStructureElementField $field,
	array $values,
	array $oldValues,
	\Mesour\Editable\Structures\Reference $reference,
	$identifier = null,
	array $params = []
) use ($context) {
	if ($field->getName() === 'addresses') {
		unset($values['id']);
		$context->table('user_addresses')
			->where('id = ?', $reference->getToValue())
			->update($values);
	} elseif ($field->getName() === 'companies') {
		unset($values['id'], $values['special'], $values['special-select']);
		$context->table('companies')
			->where('id = ?', $reference->getToValue())
			->update($values);
	} elseif ($field->getName() === 'group') {
		unset($values['id']);
		$context->table('groups')
			->where('id = ?', $reference->getToValue())
			->update($values);
	} elseif ($field->getName() === 'wallet') {
		unset($values['id'], $values['wallet_id']);
		$context->table('wallets')
			->where('id = ?', $reference->getToValue())
			->update($values);
	}
};
$editable->onEditField[] = function (
	\Mesour\Editable\Structures\Fields\IStructureField $field,
	$newValue,
	$oldValue,
	$identifier = null,
	array $params = []
) use ($context, $source) {
	if ($field->getName() === 'special') {
		dump(func_get_args());
	} elseif ($field->getName() === 'group') {
		$data = [
			'group_id' => !$newValue ? null : $newValue,
		];
	} else {
		if ($field->getName() === 'email' && !\Nette\Utils\Validators::isEmail($newValue)) {
			$exception = new \Mesour\Editable\ValidatorException('Value must be valid email.');
			$exception->setFieldName($field->getName());
			throw $exception;
		}
		$data = [
			$field->getName() => $newValue === false ? 0 : $newValue,
		];
	}
	$context->table('users')
		->where('id = ?', $identifier)
		->update($data);
};
$created = $editable->create();
$currentUser = $source->fetch();
$currentUserId = $currentUser['id'];
?>
<hr style="margin-bottom: 50px;">
<div class="container"<?php echo $editable->createSnippet()->attributes(); ?>>
	<?php echo $created; ?>
	<div class="panel panel-info">
		<div class="panel-heading">
			<h3 class="panel-title">User detail</h3>
		</div>
		<div class="panel-body">
			<div class="row">
				<div class="col-lg-6">
					<table class="table styled-table">
						<tr>
							<th>Name</th>
							<td data-editable="name" data-id="<?php echo $currentUserId; ?>" title="Enter firstname">
								<span><?php echo $currentUser['name']; ?></span>
							</td>
						</tr>
						<tr>
							<th>Surname</th>
							<td data-editable="surname" data-id="<?php echo $currentUserId; ?>" title="Enter lastname">
								<?php echo $currentUser['surname']; ?>
							</td>
						</tr>
						<tr>
							<th>Email</th>
							<td data-editable="email" data-id="<?php echo $currentUserId; ?>" title="Enter email">
								<?php echo $currentUser['email']; ?>
							</td>
						</tr>
						<tr>
							<th>Special</th>
							<td data-editable="special" data-id="<?php echo $currentUserId; ?>" title="Enter email">
								Static test
							</td>
						</tr>
						<tr>
							<th>Birth date</th>
							<?php $lastLogin = $currentUser['last_login'] ? $currentUser['last_login']->format(
								'Y-m-d H:i:s'
							) : null; ?>
							<td data-editable="last_login" data-id="<?php echo $currentUserId; ?>" data-value="<?php echo $lastLogin; ?>" title="Enter birth date">
								<?php echo $lastLogin ? $lastLogin : '<i>none</i>'; ?>
							</td>
						</tr>
						<tr>
							<th>Domains</th>
							<td>
								<ul>
									<li data-editable="domains" data-no-action="true">
										<span data-editable="domains" data-id="<?php echo $currentUserId; ?>"
										      data-value="0">example.com</span>
										<a href="#" class="fa fa-remove" data-editable="domains"
										   data-id="<?php echo $currentUserId; ?>"
										   data-value="0"
										   data-confirm="Really delete domain example.com?"
										   data-is-remove="true"></a>
									</li>
									<li>
										<a data-editable="domains" data-is-add="true"
										   data-id="<?php echo $currentUserId; ?>" class="add-new">
											<i class="fa fa-plus"></i>
											Add new domain
										</a>
									</li>
								</ul>
							</td>
						</tr>
						<tr>
							<th>Addresses</th>
							<td>
								<ul>
									<?php foreach ($currentUser['addresses'] as $address) : ?>
										<?php $addressString = $address['street'] . ', ' . $address['zip'] . ' ' . $address['city'] . ', ' . $address['country'] ?>
										<li data-editable="addresses" data-no-action="true">
										<span data-editable="addresses" data-id="<?php echo $currentUserId; ?>"
										      data-value="<?php echo $address['id']; ?>"><?php echo $addressString; ?></span>
											<a href="#" class="fa fa-remove" data-editable="addresses"
											   data-id="<?php echo $currentUserId; ?>"
											   data-value="<?php echo $address['id']; ?>"
											   data-confirm="Really delete address <?php echo $addressString; ?>?"
											   data-is-remove="true"></a>
										</li>
									<?php endforeach; ?>
									<li>
										<a data-editable="addresses" data-is-add="true"
										   data-id="<?php echo $currentUserId; ?>" class="add-new">
											<i class="fa fa-plus"></i>
											Add new address
										</a>
									</li>
								</ul>
							</td>
						</tr>
					</table>
				</div>
				<div class="col-lg-6">
					<table class="table styled-table">
						<tr>
							<th>Amount</th>
							<td data-editable="amount" data-id="<?php echo $currentUserId; ?>" title="Enter amount">
								<?php
								echo $currentUser['amount']
									? (number_format($currentUser['amount'], 2, ',', '.') . ' EUR')
									: '<i>null</i>';
								?>
							</td>
						</tr>
						<tr>
							<th>Role</th>
							<td data-editable="role" data-id="<?php echo $currentUserId; ?>"
							    data-value="<?php echo $currentUser['role']; ?>" title="Select role">
								<?php echo $currentUser['role'] ? ucfirst($currentUser['role']) : '<i>none</i>'; ?>
							</td>
						</tr>
						<tr>
							<th>Group</th>
							<td data-editable="group" data-id="<?php echo $currentUserId; ?>"
							    data-value="<?php echo $currentUser['group_id']; ?>" title="Select group">
								<?php echo $currentUser['group'] && count(
									$currentUser['group']
								) > 0 ? $currentUser['group']['_pattern'] : '<i>none</i>'; ?>
								<?php if (!$currentUser['group']) { ?>
									<i class="fa fa-plus"></i>
									<span data-editable="group" data-is-add="true" title="Select group"
									      data-id="<?php echo $currentUserId; ?>" class="attach">
										Attach group
									</span>
								<?php } ?>
							</td>
						</tr>
						<tr>
							<th>Has PRO</th>
							<td data-editable="has_pro" data-id="<?php echo $currentUserId; ?>"
							    data-value="<?php echo (int) $currentUser['has_pro']; ?>" title="Set PRO">
								<?php echo(is_null($currentUser['has_pro'])
									? '<i>none</i>' : ($currentUser['has_pro'] ? '<b style="color:green">Yes</b>' : '<b style="color:red">No</b>')); ?>
							</td>
						</tr>
						<tr>
							<th>Wallet</th>
							<td data-editable="wallet" data-no-action="true">
								<span data-editable="wallet" data-id="<?php echo $currentUserId; ?>"
								      data-value="<?php echo $currentUser['wallet_id']; ?>">
									<?php echo count(
										$currentUser['wallet']
									) > 0 ? $currentUser['wallet']['_pattern'] : ''; ?></span>
								<?php if (!count($currentUser['wallet'])) { ?>
									<i class="fa fa-plus"></i>
									<span data-editable="wallet" data-is-add="true" title="Create new wallet"
									      data-id="<?php echo $currentUserId; ?>" class="attach">
										Create new wallet
									</span>
								<?php } else { ?>
									<a href="#" class="fa fa-remove" data-editable="wallet"
									   data-id="<?php echo $currentUserId; ?>"
									   data-value="<?php echo $currentUser['wallet_id']; ?>"
									   data-confirm="Really remove wallet with: <?php echo $currentUser['wallet']['amount'] . ' ' . $currentUser['wallet']['currency']; ?>?"
									   data-is-remove="true"></a>
								<?php } ?>
							</td>
						</tr>
						<tr>
							<th>Companies</th>
							<td>
								<ul>
									<?php foreach ($currentUser['companies'] as $company) : ?>
										<li data-editable="companies" data-no-action="true">
										<span data-editable="companies" data-id="<?php echo $currentUserId; ?>"
										      data-value="<?php echo $company['id']; ?>"><?php echo $company['name']; ?></span>
											<a href="#" class="fa fa-remove" data-editable="companies"
											   data-id="<?php echo $currentUserId; ?>"
											   data-value="<?php echo $company['id']; ?>"
											   data-confirm="Really unattach company <?php echo $company['name']; ?>?"
											   data-is-remove="true"></a>
										</li>
									<?php endforeach; ?>
									<li>
										<a data-editable="companies" data-is-add="true"
										   data-id="<?php echo $currentUserId; ?>" class="add-new">
											<i class="fa fa-plus"></i>
											Add new address
										</a>
									</li>
								</ul>
							</td>
						</tr>
					</table>
				</div>
			</div>
		</div>
	</div>
</div>
<hr>
<!-- Latest compiled and minified JavaScript -->
<script src="https://code.jquery.com/jquery-2.1.4.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js"
        integrity="sha384-0mSbJDEHialfmuBBQP6A4Qrprq5OVfW37PRR3j5ELqxss1yVqOtnepnHVP9aJ7xS"
        crossorigin="anonymous"></script>
<script src="../node_modules/moment/min/moment.min.js"></script>
<script src="../node_modules/eonasdan-bootstrap-datetimepicker/build/js/bootstrap-datetimepicker.min.js"></script>
<script src="../node_modules/mesour-editable/dist/js/mesour.editable.js"></script>
<script>
	$(function() {
		var COMPONENT_NAME = 'mesourApp-editableTest';
		var CustomField = function(fieldStructure, editableClosure, element, parameters, identifier, value) {
			var parameters = parameters || {},
				oldValue = value ? value : $.trim(element.html()),
				rules = fieldStructure['rules'] || [],
				isNullable = fieldStructure['nullable'],
				fieldName = fieldStructure['name'],
				getEditable = function() {
					return editableClosure();
				},
				_this = this;
			var group = $('<div class="input-group input-group-sm">');
			var select = $('<select id="lunch" class="form-control">');
			select.append('<option>Baby Back Ribs</option>');
			group.append(select);
			var input = $('<input type="text" value="' + oldValue + '" class="form-control" name="' + fieldName + '">');
			group.append(input);
			input.on('keydown.mesour-editable', function(e) {
				if (e.keyCode === 13) {
					getEditable().save(fieldName, identifier);
				} else if (e.keyCode === 27) {
					_this.reset();
				}
			});
			var popover = getEditable()
				.createEditablePopover(fieldStructure, identifier, editableClosure, element, group);
			popover.onSave(function() {
				var isValid = mesour.editable.validators.validate(
					rules,
					input.val(),
					input,
					true,
					isNullable,
					function() {return _this}
				);
				if (isValid) {
					getEditable().save(fieldName, identifier);
				}
			});
			popover.onReset(function() {
				_this.reset();
			});
			input.focus();
			this.getElement = function() {
				return element;
			};
			this.getValue = function() {
				return {
					oldValue: oldValue,
					value: {
						'input': input.val(),
						'select': select.val()
					},
					params: parameters
				};
			};
			this.reset = function() {
				popover.destroy();
			};
			this.save = function() {
				popover.destroy();
				element.empty().text(input.val());
			};
		};
		var Field = function() {
			this.getFieldInstance = function(fieldStructure, editableClosure, element, parameters, identifier, value) {
				return new CustomField(fieldStructure, editableClosure, element, parameters, identifier, value);
			};
			this.createFormElement = function(group, id, fieldStructure, editableClosure) {
				var title = fieldStructure['title'],
					name = fieldStructure['name'];
				var label = jQuery('<label for="' + id + '">' + title + '</label>');
				group.append(label);
				var inputGroup = $('<div class="input-group">');
				var select = $('<select id="lunch" class="form-control" name="' + name + '-select">');
				select.append('<option>--</option>');
				select.append('<option value="1">Baby Back Ribs</option>');
				select.append('<option value="2">Foo value</option>');
				inputGroup.append(select);
				var input = $('<input type="text" class="form-control" id="' + id + '" name="' + name + '">');
				inputGroup.append(input);
				group.append(inputGroup);
				//textField.data('rules', fieldStructure['rules'] || []);
			};
		};
		window.mesour = !window.mesour ? {} : window.mesour;
		window.mesour.editable = !window.mesour.editable ? [] : window.mesour.editable;
		window.mesour.editable.push(['addCustomField', COMPONENT_NAME, 'special', new Field()]);
		$(document).on('click', '[data-editable]', function(e) {
			var $this = $(this);
			if ($this.attr('data-no-action')) {
				return;
			}
			var name = $this.attr('data-editable'),
				isRemove = $this.attr('data-is-remove'),
				isAdd = $this.attr('data-is-add'),
				value = $this.attr('data-value'),
				id = $this.attr('data-id');
			if (!isRemove && (e.ctrlKey || e.metaKey)) {
				e.preventDefault();
				mesour.editable.getComponent(COMPONENT_NAME).edit(name, $this, id, value);
			} else if (isRemove || isAdd) {
				e.preventDefault();
				if (isAdd) {
					mesour.editable.getComponent(COMPONENT_NAME).newEntry(name, $this, id);
				} else {
					var confirmText = $this.attr('data-confirm');
					if (!confirmText || (confirmText && confirm(confirmText))) {
						mesour.editable.getComponent(COMPONENT_NAME).remove(name, $this, id, value);
					}
				}
			}
			mesour.editable.getComponent(COMPONENT_NAME).setOnCompleteCallback(function(fieldName) {
				var $this = $('[data-editable="' + fieldName + '"]');
				$this.css('background-color', '#bce8f1');
				$this.animate({ backgroundColor: "#fff" }, 1200);
			});
		});
	});
	/**!
	 * @preserve Color animation 1.6.0
	 * http://www.bitstorm.org/jquery/color-animation/
	 * Copyright 2011, 2013 Edwin Martin
	 * Released under the MIT and GPL licenses.
	 */
	(function($) {
		/**
		 * Check whether the browser supports RGBA color mode.
		 *
		 * Author Mehdi Kabab <http://pioupioum.fr>
		 * @return {boolean} True if the browser support RGBA. False otherwise.
		 */
		function isRGBACapable() {
			var $script = $('script:first'),
				color = $script.css('color'),
				result = false;
			if (/^rgba/.test(color)) {
				result = true;
			} else {
				try {
					result = ( color != $script.css('color', 'rgba(0, 0, 0, 0.5)').css('color') );
					$script.css('color', color);
				} catch (e) {
				}
			}
			return result;
		}
		$.extend(true, $, {
			support: {
				'rgba': isRGBACapable()
			}
		});
		var properties = ['color', 'backgroundColor', 'borderBottomColor', 'borderLeftColor', 'borderRightColor', 'borderTopColor', 'outlineColor'];
		$.each(properties, function(i, property) {
			$.Tween.propHooks[ property ] = {
				get: function(tween) {
					return $(tween.elem).css(property);
				},
				set: function(tween) {
					var style = tween.elem.style;
					var p_begin = parseColor($(tween.elem).css(property));
					var p_end = parseColor(tween.end);
					tween.run = function(progress) {
						style[property] = calculateColor(p_begin, p_end, progress);
					}
				}
			}
		});
		// borderColor doesn't fit in standard fx.step above.
		$.Tween.propHooks.borderColor = {
			set: function(tween) {
				var style = tween.elem.style;
				var p_begin = [];
				var borders = properties.slice(2, 6); // All four border properties
				$.each(borders, function(i, property) {
					p_begin[property] = parseColor($(tween.elem).css(property));
				});
				var p_end = parseColor(tween.end);
				tween.run = function(progress) {
					$.each(borders, function(i, property) {
						style[property] = calculateColor(p_begin[property], p_end, progress);
					});
				}
			}
		}
		// Calculate an in-between color. Returns "#aabbcc"-like string.
		function calculateColor(begin, end, pos) {
			var color = 'rgb' + ($.support['rgba'] ? 'a' : '') + '('
				+ parseInt((begin[0] + pos * (end[0] - begin[0])), 10) + ','
				+ parseInt((begin[1] + pos * (end[1] - begin[1])), 10) + ','
				+ parseInt((begin[2] + pos * (end[2] - begin[2])), 10);
			if ($.support['rgba']) {
				color += ',' + (begin && end ? parseFloat(begin[3] + pos * (end[3] - begin[3])) : 1);
			}
			color += ')';
			return color;
		}
		// Parse an CSS-syntax color. Outputs an array [r, g, b]
		function parseColor(color) {
			var match, quadruplet;
			// Match #aabbcc
			if (match = /#([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})/.exec(color)) {
				quadruplet = [parseInt(match[1], 16), parseInt(match[2], 16), parseInt(match[3], 16), 1];
				// Match #abc
			} else if (match = /#([0-9a-fA-F])([0-9a-fA-F])([0-9a-fA-F])/.exec(color)) {
				quadruplet = [parseInt(match[1], 16) * 17, parseInt(match[2], 16) * 17, parseInt(match[3], 16) * 17, 1];
				// Match rgb(n, n, n)
			} else if (match = /rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/.exec(color)) {
				quadruplet = [parseInt(match[1]), parseInt(match[2]), parseInt(match[3]), 1];
			} else if (match = /rgba\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9\.]*)\s*\)/.exec(color)) {
				quadruplet = [parseInt(match[1], 10), parseInt(match[2], 10), parseInt(match[3], 10),parseFloat(match[4])];
				// No browser returns rgb(n%, n%, n%), so little reason to support this format.
			} else {
				quadruplet = colors[color];
			}
			return quadruplet;
		}
		// Some named colors to work with, added by Bradley Ayers
		// From Interface by Stefan Petre
		// http://interface.eyecon.ro/
		var colors = {
			'aqua': [0,255,255,1],
			'azure': [240,255,255,1],
			'beige': [245,245,220,1],
			'black': [0,0,0,1],
			'blue': [0,0,255,1],
			'brown': [165,42,42,1],
			'cyan': [0,255,255,1],
			'darkblue': [0,0,139,1],
			'darkcyan': [0,139,139,1],
			'darkgrey': [169,169,169,1],
			'darkgreen': [0,100,0,1],
			'darkkhaki': [189,183,107,1],
			'darkmagenta': [139,0,139,1],
			'darkolivegreen': [85,107,47,1],
			'darkorange': [255,140,0,1],
			'darkorchid': [153,50,204,1],
			'darkred': [139,0,0,1],
			'darksalmon': [233,150,122,1],
			'darkviolet': [148,0,211,1],
			'fuchsia': [255,0,255,1],
			'gold': [255,215,0,1],
			'green': [0,128,0,1],
			'indigo': [75,0,130,1],
			'khaki': [240,230,140,1],
			'lightblue': [173,216,230,1],
			'lightcyan': [224,255,255,1],
			'lightgreen': [144,238,144,1],
			'lightgrey': [211,211,211,1],
			'lightpink': [255,182,193,1],
			'lightyellow': [255,255,224,1],
			'lime': [0,255,0,1],
			'magenta': [255,0,255,1],
			'maroon': [128,0,0,1],
			'navy': [0,0,128,1],
			'olive': [128,128,0,1],
			'orange': [255,165,0,1],
			'pink': [255,192,203,1],
			'purple': [128,0,128,1],
			'violet': [128,0,128,1],
			'red': [255,0,0,1],
			'silver': [192,192,192,1],
			'white': [255,255,255,1],
			'yellow': [255,255,0,1],
			'transparent': [255,255,255,0]
		};
	})(jQuery);
</script>
 |