mirror of
https://github.com/alchemy-fr/Phraseanet.git
synced 2025-10-10 11:33:17 +00:00
Add global register feature
Tweak admin field app Fix typo Tweaks Fix typo
This commit is contained in:

committed by
Romain Neutron

parent
9a9235a15e
commit
0539db7598
@@ -40,6 +40,10 @@ class Fields implements ControllerProviderInterface
|
|||||||
->assert('sbas_id', '\d+')
|
->assert('sbas_id', '\d+')
|
||||||
->bind('admin_fields');
|
->bind('admin_fields');
|
||||||
|
|
||||||
|
$controllers->put('/{sbas_id}/fields', 'admin.fields.controller:updateFields')
|
||||||
|
->assert('sbas_id', '\d+')
|
||||||
|
->bind('admin_fields_register');
|
||||||
|
|
||||||
$controllers->get('/{sbas_id}/fields', 'admin.fields.controller:listFields')
|
$controllers->get('/{sbas_id}/fields', 'admin.fields.controller:listFields')
|
||||||
->assert('sbas_id', '\d+')
|
->assert('sbas_id', '\d+')
|
||||||
->bind('admin_fields_list');
|
->bind('admin_fields_list');
|
||||||
@@ -84,20 +88,94 @@ class Fields implements ControllerProviderInterface
|
|||||||
return $controllers;
|
return $controllers;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getLanguage(Application $app) {
|
public function updateFields(Application $app, Request $request, $sbas_id)
|
||||||
|
{
|
||||||
|
$json = array(
|
||||||
|
'success' => false,
|
||||||
|
// use to store the updated collection
|
||||||
|
'fields' => array(),
|
||||||
|
'messages' => array()
|
||||||
|
);
|
||||||
|
|
||||||
|
$databox = $app['phraseanet.appbox']->get_databox((int) $sbas_id);
|
||||||
|
$connection = $databox->get_connection();
|
||||||
|
$data = $this->getFieldsJsonFromRequest($app, $request);
|
||||||
|
|
||||||
|
// calculate max position
|
||||||
|
try {
|
||||||
|
$stmt = $connection->prepare('SELECT MAX(sorter) as max_position FROM metadatas_structure');
|
||||||
|
$stmt->execute();
|
||||||
|
$row = $stmt->fetch(\PDO::FETCH_ASSOC);
|
||||||
|
$stmt->closeCursor();
|
||||||
|
$maxPosition = $row['max_position'] + 1;
|
||||||
|
} catch (\PDOException $e) {
|
||||||
|
$app->abort(500);
|
||||||
|
}
|
||||||
|
|
||||||
|
$connection->beginTransaction();
|
||||||
|
$i = 0;
|
||||||
|
foreach ($data as $jsonField) {
|
||||||
|
try {
|
||||||
|
$jsonField['sorter'] = $jsonField['sorter'] + $maxPosition;
|
||||||
|
$field = \databox_field::get_instance($app, $databox, $jsonField['id']);
|
||||||
|
$this->updateFieldWithData($app, $field, $jsonField);
|
||||||
|
$field->save();
|
||||||
|
$json['fields'][] = $field->toArray();
|
||||||
|
$i++;
|
||||||
|
} catch (\PDOException $e) {
|
||||||
|
if ($e->errorInfo[1] == 1062) {
|
||||||
|
$json['messages'][] = _(sprintf('Field name %s already exists', $jsonField['name']));
|
||||||
|
} else {
|
||||||
|
$json['messages'][] = _(sprintf('Field %s could not be saved, please retry or contact an administrator if problem persists', $jsonField['name']));
|
||||||
|
}
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
if ($e instanceof \Exception_Databox_metadataDescriptionNotFound || $e->getPrevious() instanceof TagUnknown) {
|
||||||
|
$json['messages'][] = _(sprintf('Provided tag %s is unknown', $jsonField['tag']));
|
||||||
|
} else {
|
||||||
|
$json['messages'][] = _(sprintf('Field %s could not be saved, please retry or contact an administrator if problem persists', $jsonField['name']));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($i === count($data)) {
|
||||||
|
// update field position in database, this query forces to update all fields each time
|
||||||
|
$stmt = $connection->prepare(sprintf('UPDATE metadatas_structure SET sorter = (sorter - %s)', $maxPosition));
|
||||||
|
$row = $stmt->execute();
|
||||||
|
$stmt->closeCursor();
|
||||||
|
|
||||||
|
$connection->commit();
|
||||||
|
|
||||||
|
$json['success'] = true;
|
||||||
|
$json['messages'][] = _('Fields configuration has been saved');
|
||||||
|
|
||||||
|
// update field position in array
|
||||||
|
array_walk($json['fields'], function(&$field) use ($maxPosition) {
|
||||||
|
$field['sorter'] = $field['sorter'] - $maxPosition;
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
$connection->rollback();
|
||||||
|
}
|
||||||
|
|
||||||
|
return $app->json($json);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getLanguage(Application $app, Request $request)
|
||||||
|
{
|
||||||
return $app->json(array(
|
return $app->json(array(
|
||||||
'something_wrong' => _('Something wrong happened, please try again or contact an admin if problem persists'),
|
'something_wrong' => _('Something wrong happened, please try again or contact an admin if problem persists'),
|
||||||
'created_success' => _('%s field has been created with success'),
|
'deleted_success' => _('%s field has been deleted with success'),
|
||||||
'deleted_success' => _('%s field has been deleted with success'),
|
'are_you_sure_delete' => _('Do you really want to delete the field %s ?'),
|
||||||
'are_you_sure_delete' => _('Do you really want to delete the field %s ?'),
|
'validation_blank' => _('Field can not be blank'),
|
||||||
'validation_blank' => _('Field can not be blank'),
|
'validation_name_exists' => _('Field name already exists'),
|
||||||
|
'validation_tag_invalid' => _('Field source is not valid'),
|
||||||
|
'field_error' => _('Field %s contains errors'),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function displayApp(Application $app, $sbas_id) {
|
public function displayApp(Application $app, Request $request, $sbas_id)
|
||||||
|
{
|
||||||
return $app['twig']->render('/admin/fields/index.html.twig', array(
|
return $app['twig']->render('/admin/fields/index.html.twig', array(
|
||||||
'sbas_id' => $sbas_id,
|
'sbas_id' => $sbas_id
|
||||||
'js' => ''
|
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -192,9 +270,9 @@ class Fields implements ControllerProviderInterface
|
|||||||
$json['field'] = $field->toArray();
|
$json['field'] = $field->toArray();
|
||||||
} catch (\PDOException $e) {
|
} catch (\PDOException $e) {
|
||||||
if ($e->errorInfo[1] == 1062) {
|
if ($e->errorInfo[1] == 1062) {
|
||||||
$json['message'] = _(sprintf('Field name %s already exists', $data['name']));
|
$json['message'] = _(sprintf('Field name %s already exists', $data['name']));
|
||||||
}
|
}
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
if ($e instanceof \Exception_Databox_metadataDescriptionNotFound || $e->getPrevious() instanceof TagUnknown) {
|
if ($e instanceof \Exception_Databox_metadataDescriptionNotFound || $e->getPrevious() instanceof TagUnknown) {
|
||||||
$json['message'] = _(sprintf('Provided tag %s is unknown', $data['tag']));
|
$json['message'] = _(sprintf('Provided tag %s is unknown', $data['tag']));
|
||||||
}
|
}
|
||||||
@@ -246,11 +324,7 @@ class Fields implements ControllerProviderInterface
|
|||||||
$app->abort(400, 'Body must contain a valid JSON payload');
|
$app->abort(400, 'Body must contain a valid JSON payload');
|
||||||
}
|
}
|
||||||
|
|
||||||
$required = array(
|
$required = $this->getMandatoryFieldProperties();
|
||||||
'name', 'multi', 'thumbtitle', 'tag', 'business', 'indexable',
|
|
||||||
'required', 'separator', 'readonly', 'type', 'tbranch', 'report',
|
|
||||||
'vocabulary-type', 'vocabulary-restricted', 'dces-element'
|
|
||||||
);
|
|
||||||
|
|
||||||
foreach ($required as $key) {
|
foreach ($required as $key) {
|
||||||
if (false === array_key_exists($key, $data)) {
|
if (false === array_key_exists($key, $data)) {
|
||||||
@@ -261,9 +335,32 @@ class Fields implements ControllerProviderInterface
|
|||||||
return $data;
|
return $data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function getFieldsJsonFromRequest(Application $app, Request $request)
|
||||||
|
{
|
||||||
|
$body = $request->getContent();
|
||||||
|
$data = @json_decode($body, true);
|
||||||
|
|
||||||
|
if (JSON_ERROR_NONE !== json_last_error()) {
|
||||||
|
$app->abort(400, 'Body must contain a valid JSON payload');
|
||||||
|
}
|
||||||
|
|
||||||
|
$required = $this->getMandatoryFieldProperties();
|
||||||
|
|
||||||
|
foreach($data as $field) {
|
||||||
|
foreach ($required as $key) {
|
||||||
|
if (false === array_key_exists($key, $field)) {
|
||||||
|
$app->abort(400, sprintf('The entity must contain a key `%s`', $key));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
|
||||||
private function updateFieldWithData(Application $app, \databox_field $field, array $data)
|
private function updateFieldWithData(Application $app, \databox_field $field, array $data)
|
||||||
{
|
{
|
||||||
$field
|
$field
|
||||||
|
->set_name($data['name'])
|
||||||
->set_thumbtitle($data['thumbtitle'])
|
->set_thumbtitle($data['thumbtitle'])
|
||||||
->set_tag(\databox_field::loadClassFromTagName($data['tag']))
|
->set_tag(\databox_field::loadClassFromTagName($data['tag']))
|
||||||
->set_business($data['business'])
|
->set_business($data['business'])
|
||||||
@@ -277,6 +374,10 @@ class Fields implements ControllerProviderInterface
|
|||||||
->setVocabularyControl(null)
|
->setVocabularyControl(null)
|
||||||
->setVocabularyRestricted(false);
|
->setVocabularyRestricted(false);
|
||||||
|
|
||||||
|
if (isset($data['sorter'])) {
|
||||||
|
$field->set_position($data['sorter']);
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$vocabulary = VocabularyController::get($app, $data['vocabulary-type']);
|
$vocabulary = VocabularyController::get($app, $data['vocabulary-type']);
|
||||||
$field->setVocabularyControl($vocabulary);
|
$field->setVocabularyControl($vocabulary);
|
||||||
@@ -287,11 +388,20 @@ class Fields implements ControllerProviderInterface
|
|||||||
|
|
||||||
$dces_element = null;
|
$dces_element = null;
|
||||||
|
|
||||||
$class = 'databox_Field_DCES_' . $data['dces-element'];
|
$class = '\databox_Field_DCES_' . $data['dces-element'];
|
||||||
if (class_exists($class)) {
|
if (class_exists($class)) {
|
||||||
$dces_element = new $class();
|
$dces_element = new $class();
|
||||||
}
|
}
|
||||||
|
|
||||||
$field->set_dces_element($dces_element);
|
$field->set_dces_element($dces_element);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function getMandatoryFieldProperties()
|
||||||
|
{
|
||||||
|
return array(
|
||||||
|
'name', 'multi', 'thumbtitle', 'tag', 'business', 'indexable',
|
||||||
|
'required', 'separator', 'readonly', 'type', 'tbranch', 'report',
|
||||||
|
'vocabulary-type', 'vocabulary-restricted', 'dces-element'
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -350,6 +350,7 @@ class databox_field implements cache_cacheableInterface
|
|||||||
`report` = :report,
|
`report` = :report,
|
||||||
`type` = :type,
|
`type` = :type,
|
||||||
`tbranch` = :tbranch,
|
`tbranch` = :tbranch,
|
||||||
|
`sorter` = :position,
|
||||||
`thumbtitle` = :thumbtitle,
|
`thumbtitle` = :thumbtitle,
|
||||||
`VocabularyControlType` = :VocabularyControlType,
|
`VocabularyControlType` = :VocabularyControlType,
|
||||||
`RestrictToVocabularyControl` = :RestrictVocab
|
`RestrictToVocabularyControl` = :RestrictVocab
|
||||||
@@ -367,6 +368,7 @@ class databox_field implements cache_cacheableInterface
|
|||||||
':report' => $this->report ? '1' : '0',
|
':report' => $this->report ? '1' : '0',
|
||||||
':type' => $this->type,
|
':type' => $this->type,
|
||||||
':tbranch' => $this->tbranch,
|
':tbranch' => $this->tbranch,
|
||||||
|
':position' => $this->position,
|
||||||
':thumbtitle' => $this->thumbtitle,
|
':thumbtitle' => $this->thumbtitle,
|
||||||
':VocabularyControlType' => $this->Vocabulary ? $this->Vocabulary->getType() : null,
|
':VocabularyControlType' => $this->Vocabulary ? $this->Vocabulary->getType() : null,
|
||||||
':RestrictVocab' => $this->Vocabulary ? ($this->VocabularyRestriction ? '1' : '0') : '0',
|
':RestrictVocab' => $this->Vocabulary ? ($this->VocabularyRestriction ? '1' : '0') : '0',
|
||||||
@@ -417,6 +419,7 @@ class databox_field implements cache_cacheableInterface
|
|||||||
}
|
}
|
||||||
$meta->setAttribute('thumbtitle', $this->thumbtitle);
|
$meta->setAttribute('thumbtitle', $this->thumbtitle);
|
||||||
$meta->setAttribute('meta_id', $this->id);
|
$meta->setAttribute('meta_id', $this->id);
|
||||||
|
$meta->setAttribute('sorter', $this->position);
|
||||||
|
|
||||||
$this->delete_data_from_cache();
|
$this->delete_data_from_cache();
|
||||||
$this->databox->saveStructure($dom_struct);
|
$this->databox->saveStructure($dom_struct);
|
||||||
@@ -798,6 +801,24 @@ class databox_field implements cache_cacheableInterface
|
|||||||
{
|
{
|
||||||
return $this->name;
|
return $this->name;
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function get_position()
|
||||||
|
{
|
||||||
|
return $this->position;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function set_position($position)
|
||||||
|
{
|
||||||
|
$this->position = $position;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return true is the field is unknown
|
* Return true is the field is unknown
|
||||||
@@ -827,7 +848,7 @@ class databox_field implements cache_cacheableInterface
|
|||||||
'readonly' => $this->readonly,
|
'readonly' => $this->readonly,
|
||||||
'multi' => $this->multi,
|
'multi' => $this->multi,
|
||||||
'indexable' => $this->indexable,
|
'indexable' => $this->indexable,
|
||||||
'dces-element' => $this->dces_element,
|
'dces-element' => $this->dces_element ? $this->dces_element->get_label(): null,
|
||||||
'vocabulary-type' => $this->Vocabulary ? $this->Vocabulary->getType() : null,
|
'vocabulary-type' => $this->Vocabulary ? $this->Vocabulary->getType() : null,
|
||||||
'vocabulary-restricted' => $this->VocabularyRestriction,
|
'vocabulary-restricted' => $this->VocabularyRestriction,
|
||||||
);
|
);
|
||||||
|
@@ -1,20 +1,25 @@
|
|||||||
|
{# include js templates #}
|
||||||
{% include 'admin/fields/templates.html.twig' %}
|
{% include 'admin/fields/templates.html.twig' %}
|
||||||
|
|
||||||
<div id="admin-field-app" class="container-fluid">
|
<div id="admin-field-app" class="container-fluid">
|
||||||
|
{# sbas_id is saved in the dom and used to fetch right models and collections #}
|
||||||
<input type="hidden" name="current_sbas_id" value="{{ sbas_id }}">
|
<input type="hidden" name="current_sbas_id" value="{{ sbas_id }}">
|
||||||
<div class="row-fluid" style="min-height:60px; border-bottom: 1px solid #000">
|
<div class="row-fluid row-top">
|
||||||
<div class="span4">
|
<div class="span4 save-block">
|
||||||
<button type="button" class="btn btn-large btn-success"><i class="icon-hdd icon-white"></i> {% trans %}Save all changes{% endtrans %}</button>
|
{# set loading state, this will be removed once backbone application is fully loaded #}
|
||||||
|
<img src="/skins/icons/loaderFFF.gif"/>
|
||||||
|
{% trans %}Loading database documentary fields ...{% endtrans %}
|
||||||
</div>
|
</div>
|
||||||
<div class="span8">
|
<div class="span8">
|
||||||
<div class="block-alert well-small"></div>
|
<div class="block-alert"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row-fluid">
|
<div class="row-fluid row-bottom hidden">
|
||||||
<div class="left-block span4"></div>
|
<div class="left-block span4"></div>
|
||||||
<div class="right-block span8" style="border-left: 1px dashed #000"></div>
|
<div class="right-block span8"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{# bootstrap admin field application #}
|
|
||||||
|
{# bootstrap admin field backbone application #}
|
||||||
<script src="/assets/requirejs/require.js"></script>
|
<script src="/assets/requirejs/require.js"></script>
|
||||||
<script src="/scripts/apps/admin/fields/main.js"></script>
|
<script src="/scripts/apps/admin/fields/main.js"></script>
|
||||||
|
@@ -3,7 +3,13 @@
|
|||||||
<%= msg %>
|
<%= msg %>
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script type="text/template" id="modal_delete_confirm_template">
|
<script type="text/template" id="save_template">
|
||||||
|
<button type="button" class="btn btn-large btn-success save-all">
|
||||||
|
<i class="icon-hdd icon-white"></i> {% trans %}Save all changes{% endtrans %}
|
||||||
|
</button>
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script type="text/template" id="modal_template">
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
<p><%= msg %></p>
|
<p><%= msg %></p>
|
||||||
</div>
|
</div>
|
||||||
@@ -26,16 +32,17 @@
|
|||||||
<h3>{% trans %}Add a new field{% endtrans %}</h3>
|
<h3>{% trans %}Add a new field{% endtrans %}</h3>
|
||||||
<form class="form-horizontal">
|
<form class="form-horizontal">
|
||||||
<div class="control-group">
|
<div class="control-group">
|
||||||
<label class="control-label" for="inputLabel">{% trans %}Label{% endtrans %}</label>
|
<label class="control-label" for="new-name"">{% trans %}Label{% endtrans %}</label>
|
||||||
<div class="controls">
|
<div class="controls">
|
||||||
<input type="text" id="new-name" class="input-block-level" placeholder="">
|
<input type="text" id="new-name" class="input-block-level" placeholder="">
|
||||||
<span class="help-block"></span>
|
<span class="help-block"></span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="control-group">
|
<div class="control-group">
|
||||||
<label class="control-label" for="inputSource">{% trans %}Source{% endtrans %}</label>
|
<label class="control-label" for="new-source">{% trans %}Source{% endtrans %}</label>
|
||||||
<div class="controls">
|
<div class="controls">
|
||||||
<input type="text" id="new-source" class="input-block-level" placeholder="">
|
<input type="text" id="new-source" class="input-block-level" placeholder="">
|
||||||
|
<span class="help-block"></span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="control-group">
|
<div class="control-group">
|
||||||
@@ -52,7 +59,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row-fluid">
|
<div class="row-fluid">
|
||||||
<div class="span12">
|
<div class="span12 list-block">
|
||||||
<ul id="collection-fields" class="unstyled"></ul>
|
<ul id="collection-fields" class="unstyled"></ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -62,56 +69,60 @@
|
|||||||
<div class="edit-block">
|
<div class="edit-block">
|
||||||
<table>
|
<table>
|
||||||
<tr class="edit-order">
|
<tr class="edit-order">
|
||||||
<td>{% trans %}Order{% endtrans %}:</td>
|
<td>{% trans %}Order{% endtrans %}</td>
|
||||||
<td><%= field.sorter %></td>
|
<td><%= field.sorter %></td>
|
||||||
<td><button type="button" class="btn btn-danger delete-field pull-right"><i class="icon-trash icon-white"></i>delete</button></td>
|
<td><button type="button" class="btn btn-danger delete-field pull-right"><i class="icon-trash icon-white"></i>delete</button></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr class="edit-name">
|
<tr class="edit-name ">
|
||||||
<td colspan="2">
|
<td colspan="2" class="control-group <%= modelErrors && modelErrors.has('name') ? 'error' : '' %>">
|
||||||
<input id="name" value="<%= field.name %>" class="input-block-level">
|
<input id="name" type="text" value="<%= field.name %>" class="input-block-level">
|
||||||
|
<span class="help-block">
|
||||||
|
<% if(modelErrors && modelErrors.get('name')) { %>
|
||||||
|
<%= modelErrors.get('name').message %>
|
||||||
|
<% } %>
|
||||||
|
</span>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>{% trans %}Source{% endtrans %} : </td>
|
<td>{% trans %}Source{% endtrans %}</td>
|
||||||
<td><input id="tag" type="text" val="<%= field.tag %>" class="input-block-level"/></td>
|
<td class="control-group <%= modelErrors && modelErrors.has('tag') ? 'error' : '' %>">
|
||||||
|
<input id="tag" val="<%= field.tag %>" class="input-block-level"/>
|
||||||
|
<span class="help-block">
|
||||||
|
<% if(modelErrors && modelErrors.get('tag')) { %>
|
||||||
|
<%= modelErrors.get('tag').message %>
|
||||||
|
<% } %>
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>{% trans %}DCES{% endtrans %} : </td>
|
<td>{% trans %}DCES{% endtrans %}</td>
|
||||||
<td class="dc-fields-subview"></td>
|
<td class="dc-fields-subview"></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td colspan="3" class="dces-help-block"></td>
|
<td colspan="2" class="dces-help-block info"></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td colspan="2">
|
||||||
|
<% if(field.multi == true) { %>
|
||||||
|
<i class='icon-ok'></i>
|
||||||
|
<% } else { %>
|
||||||
|
<i class='icon-remove'></i>
|
||||||
|
<% } %> {% trans %}Multivalued{% endtrans %}
|
||||||
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<% if(field.multi == true) { %>
|
|
||||||
<tr>
|
|
||||||
<td colspan="2">
|
|
||||||
<i class='icon-ok'></i> {% trans %}Multivalued{% endtrans %}
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<% } %>
|
|
||||||
</table>
|
</table>
|
||||||
<div class="edit-form">
|
<div class="edit-form">
|
||||||
<h4>{% trans %}Advanced field parameter{% endtrans %}</h4>
|
<h4>{% trans %}Advanced field parameters{% endtrans %}</h4>
|
||||||
<table>
|
<table>
|
||||||
<tr>
|
<tr>
|
||||||
<td><label for="tbranch">{% trans %}Thesaurus branch{% endtrans %}</label></td>
|
<td><label for="tbranch">{% trans %}Thesaurus branch{% endtrans %}</label></td>
|
||||||
<td><input id="tbranch" type="text" value="<%= field.tbranch %>"/></td>
|
<td><input id="tbranch" type="text" value="<%= field.tbranch %>"/></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
|
||||||
<td><label for="vocabulary-type">{% trans %}Vocabulary type{% endtrans %}</label></td>
|
|
||||||
<td>
|
|
||||||
<select id="vocabulary-type" class="input-block-level">
|
|
||||||
<% _.each(vocabularyTypes, function(vocab) { %>
|
|
||||||
<option value="<%= vocab.type %>"><%= vocab.name %></option>
|
|
||||||
<% }); %>
|
|
||||||
</select>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
<tr>
|
||||||
<td><label for="type">{% trans %}Type{% endtrans %}</label></td>
|
<td><label for="type">{% trans %}Type{% endtrans %}</label></td>
|
||||||
<td>
|
<td>
|
||||||
<select id="type" class="input-block-level">
|
<select id="type">
|
||||||
<option value=""></option>
|
<option <%= field.type == '' ? 'selected' : '' %> value=""></option>
|
||||||
<option <%= field.type == 'string' ? 'selected' : '' %> value="string">string</option>
|
<option <%= field.type == 'string' ? 'selected' : '' %> value="string">string</option>
|
||||||
<option <%= field.type == 'text' ? 'selected' : '' %> value="text">text</option>
|
<option <%= field.type == 'text' ? 'selected' : '' %> value="text">text</option>
|
||||||
<option <%= field.type == 'number' ? 'selected' : '' %> value="number">number</option>
|
<option <%= field.type == 'number' ? 'selected' : '' %> value="number">number</option>
|
||||||
@@ -120,34 +131,77 @@
|
|||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td colspan="2"><label for="business" class="checkbox"><input id="business" type="checkbox" <%= field.business ? "checked='checked'" : "" %> />{% trans %}Business Fields{% endtrans %}</label></td>
|
<td><label for="vocabulary-type">{% trans %}Vocabulary type{% endtrans %}</label></td>
|
||||||
|
<td>
|
||||||
|
<select id="vocabulary-type">
|
||||||
|
<option <%= field['vocabulary-type'] == null ? 'selected' : '' %> value=''></option>
|
||||||
|
<% _.each(vocabularyTypes, function(vocab) { %>
|
||||||
|
<option <%= field['vocabulary-type'] == vocab.type ? 'selected' : '' %> value="<%= vocab.type %>"><%= vocab.name %></option>
|
||||||
|
<% }); %>
|
||||||
|
</select>
|
||||||
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td colspan="2"><label for="vocabulary-restricted" class="checkbox"><input id="vocabulary-restricted" type="checkbox" <%= field["vocavulary-restricted"] ? "checked='checked'" : "" %> />{% trans %}Limited vocabulary{% endtrans %}</label></td>
|
<td colspan="2">
|
||||||
|
<% if(field['vocabulary-type'] != null && field['vocabulary-type'] != '') { %>
|
||||||
|
<label for="vocabulary-restricted" class="checkbox">
|
||||||
|
<input id="vocabulary-restricted" type="checkbox" <%= field["vocabulary-restricted"] ? "checked='checked'" : "" %> />
|
||||||
|
{% trans %}Limited vocabulary{% endtrans %}
|
||||||
|
</label>
|
||||||
|
<% } %>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td colspan="2">
|
||||||
|
<label for="business" class="checkbox">
|
||||||
|
<input id="business" type="checkbox" <%= field.business ? "checked='checked'" : "" %> />
|
||||||
|
{% trans %}Business Fields{% endtrans %}
|
||||||
|
</label>
|
||||||
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td><label for="separator">{% trans %}Separator{% endtrans %}</label></td>
|
<td><label for="separator">{% trans %}Separator{% endtrans %}</label></td>
|
||||||
<td><input id="separator" type="text" value="<%= field.separator %>" /></td>
|
<td><input id="separator" type="text" value="<%= field.separator %>" /></td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
<h4>{% trans %}display & action settings{% endtrans %}</h4>
|
<h4>{% trans %}Display & action settings{% endtrans %}</h4>
|
||||||
<table>
|
<table>
|
||||||
<tr>
|
<tr>
|
||||||
<td colspan="2"><label for="required" class="checkbox"><input id="required" type="checkbox" <%= field.required ? "checked='checked'" : "" %> />{% trans %}Mandatory{% endtrans %}</label></td>
|
<td>
|
||||||
|
<label for="required" class="checkbox">
|
||||||
|
<input id="required" type="checkbox" <%= field.required ? "checked='checked'" : "" %> />
|
||||||
|
{% trans %}Mandatory{% endtrans %}
|
||||||
|
</label>
|
||||||
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td colspan="2"><label for="indexable" class="checkbox"><input id="indexable" type="checkbox" <%= field.indexable ? "checked='checked'" : "" %> />{% trans %}Indexable{% endtrans %}</label></td>
|
<td>
|
||||||
|
<label for="indexable" class="checkbox">
|
||||||
|
<input id="indexable" type="checkbox" <%= field.indexable ? "checked='checked'" : "" %> />
|
||||||
|
{% trans %}Indexable{% endtrans %}
|
||||||
|
</label>
|
||||||
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td colspan="2"><label for="readonly" class="checkbox"><input id="readonly" type="checkbox" <%= field.readonly ? "checked='checked'" : "" %> />{% trans %}Read only{% endtrans %}</label></td>
|
<td>
|
||||||
|
<label for="readonly" class="checkbox">
|
||||||
|
<input id="readonly" type="checkbox" <%= field.readonly ? "checked='checked'" : "" %> />
|
||||||
|
{% trans %}Read only{% endtrans %}
|
||||||
|
</label>
|
||||||
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td colspan="2"><label for="report" class="checkbox"><input id="report" type="checkbox" <%= field.report ? "checked='checked'" : "" %> />{% trans %}Report{% endtrans %}</label></td>
|
<td>
|
||||||
|
<label for="report" class="checkbox">
|
||||||
|
<input id="report" type="checkbox" <%= field.report ? "checked='checked'" : "" %> />
|
||||||
|
{% trans %}Report{% endtrans %}
|
||||||
|
</label>
|
||||||
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td><label for="thumbtitle">{% trans %}Display thumbnails{% endtrans %}</label></td>
|
<td><label for="thumbtitle">{% trans %}Display thumbnails{% endtrans %}</label></td>
|
||||||
<td>
|
<td>
|
||||||
<select id="thumbtitle" class="input-block-level">
|
<select id="thumbtitle">
|
||||||
<option value="1" <%= field.thumbtitle == "1" ? "selected" : "" %> >{% trans 'Tous' %}</option>
|
<option value="1" <%= field.thumbtitle == "1" ? "selected" : "" %> >{% trans 'Tous' %}</option>
|
||||||
<option value="0" <%= field.thumbtitle == "0" ? "selected" : "" %> >{% trans 'Aucun' %}</option>
|
<option value="0" <%= field.thumbtitle == "0" ? "selected" : "" %> >{% trans 'Aucun' %}</option>
|
||||||
<option value="fr" <%= field.thumbtitle == "fr" ? "selected" : "" %> >{% trans 'Francais' %}</option>
|
<option value="fr" <%= field.thumbtitle == "fr" ? "selected" : "" %> >{% trans 'Francais' %}</option>
|
||||||
@@ -163,7 +217,6 @@
|
|||||||
</div>
|
</div>
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
||||||
<script type="text/template" id="list_row_template">
|
<script type="text/template" id="list_row_template">
|
||||||
<table>
|
<table>
|
||||||
<tr>
|
<tr>
|
||||||
@@ -187,10 +240,18 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script type="text/template" id="dc_fields_template">
|
<script type="text/template" id="dc_fields_template">
|
||||||
<select id="dces-element" val="" class="input-block-level">
|
<select id="dces-element" class="input-block-level">
|
||||||
|
<option <%= field['dces-element'] == null ? 'selected' : '' %> value=''></option>
|
||||||
<% _.each(dces_elements, function(el) { %>
|
<% _.each(dces_elements, function(el) { %>
|
||||||
<option value="<%= el.label %>">DC:<%= el.label %></option>
|
<option <%= field['dces-element'] == el.label ? 'selected' : '' %> value="<%= el.label %>">DC:<%= el.label %></option>
|
||||||
<% }); %>
|
<% }); %>
|
||||||
</select>
|
</select>
|
||||||
<div class="help-block"></div>
|
</script>
|
||||||
|
|
||||||
|
<script type="text/template" id="field_error_template">
|
||||||
|
<% if(messages.length > 0) { %>
|
||||||
|
<div class="well well-small">
|
||||||
|
<i class="icon-exclamation-sign"></i> {% trans %} Current configuration contains some errors {% endtrans %}
|
||||||
|
</div>
|
||||||
|
<% } %>
|
||||||
</script>
|
</script>
|
||||||
|
@@ -7,6 +7,25 @@ use Alchemy\Phrasea\Vocabulary\Controller as VocabularyController;
|
|||||||
|
|
||||||
class ControllerFieldsTest extends \PhraseanetWebTestCaseAuthenticatedAbstract
|
class ControllerFieldsTest extends \PhraseanetWebTestCaseAuthenticatedAbstract
|
||||||
{
|
{
|
||||||
|
public function testRoot()
|
||||||
|
{
|
||||||
|
$databoxes = self::$DI['app']['phraseanet.appbox']->get_databoxes();
|
||||||
|
$databox = array_shift($databoxes);
|
||||||
|
|
||||||
|
self::$DI['client']->request("GET", "/admin/fields/" . $databox->get_sbas_id());
|
||||||
|
|
||||||
|
$this->assertTrue(self::$DI['client']->getResponse()->isOk());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testLanguage()
|
||||||
|
{
|
||||||
|
self::$DI['client']->request("GET", "/admin/fields/language.json");
|
||||||
|
$response = self::$DI['client']->getResponse();
|
||||||
|
|
||||||
|
$this->assertTrue($response->isOk());
|
||||||
|
$this->assertEquals("application/json", $response->headers->get("content-type"));
|
||||||
|
}
|
||||||
|
|
||||||
public function testGetTag()
|
public function testGetTag()
|
||||||
{
|
{
|
||||||
$tag = new ObjectName();
|
$tag = new ObjectName();
|
||||||
@@ -100,6 +119,99 @@ class ControllerFieldsTest extends \PhraseanetWebTestCaseAuthenticatedAbstract
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testUpdateFields()
|
||||||
|
{
|
||||||
|
$databoxes = self::$DI['app']['phraseanet.appbox']->get_databoxes();
|
||||||
|
$databox = array_shift($databoxes);
|
||||||
|
$fieldObjects = array();
|
||||||
|
// create two fields
|
||||||
|
$fields = array(
|
||||||
|
array(
|
||||||
|
'sbas-id' => $databox->get_sbas_id(),
|
||||||
|
'name' => 'testfield' . mt_rand(),
|
||||||
|
'multi' => true,
|
||||||
|
'thumbtitle' => false,
|
||||||
|
'tag' => 'XMP:XMP',
|
||||||
|
'business' => false,
|
||||||
|
'indexable' => true,
|
||||||
|
'required' => true,
|
||||||
|
'separator' => '=;',
|
||||||
|
'readonly' => false,
|
||||||
|
'type' => 'string',
|
||||||
|
'tbranch' => '',
|
||||||
|
'report' => true,
|
||||||
|
'dces-element' => null,
|
||||||
|
'vocabulary-type' => null,
|
||||||
|
'vocabulary-restricted' => false,
|
||||||
|
), array(
|
||||||
|
'sbas-id' => $databox->get_sbas_id(),
|
||||||
|
'name' => 'testfield' . mt_rand(),
|
||||||
|
'multi' => true,
|
||||||
|
'thumbtitle' => false,
|
||||||
|
'tag' => 'XMP:XMP',
|
||||||
|
'business' => false,
|
||||||
|
'indexable' => true,
|
||||||
|
'required' => true,
|
||||||
|
'separator' => '=;',
|
||||||
|
'readonly' => false,
|
||||||
|
'type' => 'string',
|
||||||
|
'tbranch' => '',
|
||||||
|
'report' => true,
|
||||||
|
'dces-element' => null,
|
||||||
|
'vocabulary-type' => null,
|
||||||
|
'vocabulary-restricted' => false,
|
||||||
|
));
|
||||||
|
|
||||||
|
foreach($fields as $fieldData) {
|
||||||
|
$field = \databox_field::create(self::$DI['app'], $databox, $fieldData['name'], $fieldData['multi']);
|
||||||
|
$field
|
||||||
|
->set_thumbtitle($fieldData['thumbtitle'])
|
||||||
|
->set_tag(\databox_field::loadClassFromTagName($fieldData['tag']))
|
||||||
|
->set_business($fieldData['business'])
|
||||||
|
->set_indexable($fieldData['indexable'])
|
||||||
|
->set_required($fieldData['required'])
|
||||||
|
->set_separator($fieldData['separator'])
|
||||||
|
->set_readonly($fieldData['readonly'])
|
||||||
|
->set_type($fieldData['type'])
|
||||||
|
->set_tbranch($fieldData['tbranch'])
|
||||||
|
->set_report($fieldData['report'])
|
||||||
|
->setVocabularyControl(null)
|
||||||
|
->setVocabularyRestricted(false);
|
||||||
|
$field->save();
|
||||||
|
$fieldObjects[] = $field;
|
||||||
|
}
|
||||||
|
|
||||||
|
// get body
|
||||||
|
$body = $databox->get_meta_structure()->toArray();
|
||||||
|
|
||||||
|
// change some body data
|
||||||
|
$body[count($body) - 2]['business'] = true;
|
||||||
|
$body[count($body) - 2]['indexable'] = false;
|
||||||
|
$body[count($body) - 1]['readonly'] = true;
|
||||||
|
$body[count($body) - 1]['required'] = false;
|
||||||
|
|
||||||
|
self::$DI['client']->request("PUT", sprintf("/admin/fields/%d/fields", $databox->get_sbas_id()), array(), array(), array(), json_encode($body));
|
||||||
|
|
||||||
|
$response = self::$DI['client']->getResponse()->getContent();
|
||||||
|
|
||||||
|
$this->assertEquals("application/json", self::$DI['client']->getResponse()->headers->get("content-type"));
|
||||||
|
|
||||||
|
$data = json_decode($response, true);
|
||||||
|
|
||||||
|
$this->assertArrayHasKey('success', $data);
|
||||||
|
$this->assertArrayHasKey('messages', $data);
|
||||||
|
$this->assertArrayHasKey('fields', $data);
|
||||||
|
|
||||||
|
// expect last 2 fields from body equals last 2 fields from response
|
||||||
|
$this->assertEquals(array_splice($body, -2), array_splice($data['fields'], -2));
|
||||||
|
|
||||||
|
// delete created fields
|
||||||
|
foreach($fieldObjects as $field) {
|
||||||
|
$field->delete();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
public function testCreateField()
|
public function testCreateField()
|
||||||
{
|
{
|
||||||
$databoxes = self::$DI['app']['phraseanet.appbox']->get_databoxes();
|
$databoxes = self::$DI['app']['phraseanet.appbox']->get_databoxes();
|
||||||
|
@@ -1,47 +1,83 @@
|
|||||||
define([
|
define([
|
||||||
'jquery',
|
"jquery",
|
||||||
'underscore',
|
"underscore",
|
||||||
'backbone',
|
"backbone",
|
||||||
'i18n',
|
"i18n",
|
||||||
'apps/admin/fields/collections/fields',
|
"apps/admin/fields/collections/fields",
|
||||||
'apps/admin/fields/collections/vocabularies',
|
"apps/admin/fields/collections/vocabularies",
|
||||||
'apps/admin/fields/collections/dcFields',
|
"apps/admin/fields/collections/dcFields",
|
||||||
'apps/admin/fields/views/list'
|
"apps/admin/fields/views/list",
|
||||||
], function($, _, Backbone, i18n, FieldsCollection, VocabulariesCollection, DcFieldsCollection, FieldListView) {
|
"apps/admin/fields/views/save",
|
||||||
|
"apps/admin/fields/views/fieldError",
|
||||||
|
"apps/admin/fields/errors/errorManager"
|
||||||
|
], function(
|
||||||
|
$, _, Backbone, i18n, FieldsCollection, VocabulariesCollection,
|
||||||
|
DcFieldsCollection, FieldListView, SaveView, FieldErrorView, ErrorManager) {
|
||||||
var initialize = function() {
|
var initialize = function() {
|
||||||
window.AdminFieldApp = {};
|
AdminFieldApp = {
|
||||||
|
$window : $(window),
|
||||||
|
$scope : $("#admin-field-app"),
|
||||||
|
$top : $(".row-top", this.$scope),
|
||||||
|
$bottom : $(".row-bottom", this.$scope),
|
||||||
|
$leftBlock : $(".left-block", this.$bottom),
|
||||||
|
$rightBlock : $(".right-block", this.$bottom),
|
||||||
|
resizeListBlock: function () {
|
||||||
|
var listBlock = $(".list-block", AdminFieldApp.$leftBlock);
|
||||||
|
listBlock.height(AdminFieldApp.$window.height() - listBlock.offset().top - 10);
|
||||||
|
},
|
||||||
|
resize: function () {
|
||||||
|
AdminFieldApp.resizeListBlock();
|
||||||
|
AdminFieldApp.$rightBlock.height(AdminFieldApp.$window.height() - AdminFieldApp.$rightBlock.offset().top - 10);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
window.AdminFieldApp.sbas_id = $('input[name=current_sbas_id]').val();
|
// bind resize
|
||||||
|
AdminFieldApp.$window.bind("resize", AdminFieldApp.resize);
|
||||||
|
|
||||||
var fieldsCollection = new FieldsCollection(null, {
|
// current sbas id
|
||||||
sbas_id : window.AdminFieldApp.sbas_id
|
AdminFieldApp.sbas_id = $("input[name=current_sbas_id]", AdminFieldApp.scope).val();
|
||||||
|
|
||||||
|
// global errors
|
||||||
|
AdminFieldApp.errorManager = new ErrorManager();
|
||||||
|
_.extend(AdminFieldApp.errorManager, Backbone.Events);
|
||||||
|
|
||||||
|
// initiliaze collections
|
||||||
|
AdminFieldApp.fieldsCollection = new FieldsCollection(null, {
|
||||||
|
sbas_id : AdminFieldApp.sbas_id
|
||||||
});
|
});
|
||||||
|
AdminFieldApp.vocabularyCollection = new VocabulariesCollection();
|
||||||
|
AdminFieldApp.dcFieldsCollection = new DcFieldsCollection();
|
||||||
|
|
||||||
var vocabulariesCollection = new VocabulariesCollection();
|
// load strings
|
||||||
var dcFieldsCollection = new DcFieldsCollection();
|
i18n.init({ resGetPath: "/admin/fields/language.json"});
|
||||||
|
|
||||||
// load strings synchronously
|
// load all collections
|
||||||
i18n.init({ resGetPath: '/admin/fields/language.json', getAsync: false });
|
$.when.apply($, [
|
||||||
|
AdminFieldApp.fieldsCollection.fetch(),
|
||||||
var requests = [
|
AdminFieldApp.vocabularyCollection.fetch(),
|
||||||
fieldsCollection.fetch(),
|
AdminFieldApp.dcFieldsCollection.fetch()
|
||||||
vocabulariesCollection.fetch(),
|
]).done(
|
||||||
dcFieldsCollection.fetch()
|
|
||||||
];
|
|
||||||
|
|
||||||
$.when.apply($, requests).done(
|
|
||||||
function() {
|
function() {
|
||||||
window.AdminFieldApp.vocabularyCollection = vocabulariesCollection;
|
// register views
|
||||||
window.AdminFieldApp.dcFieldsCollection = dcFieldsCollection;
|
AdminFieldApp.saveView = new SaveView({
|
||||||
|
el: $(".save-block", AdminFieldApp.scope)
|
||||||
window.AdminFieldApp.fieldListView = new FieldListView({
|
|
||||||
collection: fieldsCollection,
|
|
||||||
el: $('.left-block')[0]
|
|
||||||
});
|
});
|
||||||
|
AdminFieldApp.fieldErrorView = new FieldErrorView();
|
||||||
|
AdminFieldApp.fieldListView = new FieldListView({
|
||||||
|
collection: AdminFieldApp.fieldsCollection,
|
||||||
|
el: AdminFieldApp.$leftBlock
|
||||||
|
});
|
||||||
|
// render views
|
||||||
|
AdminFieldApp.saveView.render();
|
||||||
|
AdminFieldApp.fieldListView.render();
|
||||||
|
|
||||||
|
// show bottom
|
||||||
|
AdminFieldApp.$bottom.removeClass("hidden");
|
||||||
|
|
||||||
|
AdminFieldApp.$window.trigger("resize");
|
||||||
|
|
||||||
window.AdminFieldApp.fieldListView.render();
|
|
||||||
// click on first item list
|
// click on first item list
|
||||||
_.first(window.AdminFieldApp.fieldListView.itemViews).clickAction().animate();
|
_.first(AdminFieldApp.fieldListView.itemViews).clickAction().animate();
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@@ -1,12 +1,12 @@
|
|||||||
define([
|
define([
|
||||||
'underscore',
|
"underscore",
|
||||||
'backbone',
|
"backbone",
|
||||||
'models/dcField'
|
"models/dcField"
|
||||||
], function(_, Backbone, DcFieldModel) {
|
], function(_, Backbone, DcFieldModel) {
|
||||||
var DcFieldCollection = Backbone.Collection.extend({
|
var DcFieldCollection = Backbone.Collection.extend({
|
||||||
model: DcFieldModel,
|
model: DcFieldModel,
|
||||||
url: function() {
|
url: function() {
|
||||||
return '/admin/fields/dc-fields';
|
return "/admin/fields/dc-fields";
|
||||||
},
|
},
|
||||||
comparator: function(item) {
|
comparator: function(item) {
|
||||||
return item.get("label");
|
return item.get("label");
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
define([
|
define([
|
||||||
'underscore',
|
"underscore",
|
||||||
'backbone',
|
"backbone",
|
||||||
'models/field'
|
"models/field"
|
||||||
], function(_, Backbone, FieldModel) {
|
], function(_, Backbone, FieldModel) {
|
||||||
var FieldCollection = Backbone.Collection.extend({
|
var FieldCollection = Backbone.Collection.extend({
|
||||||
initialize: function(models, options) {
|
initialize: function(models, options) {
|
||||||
@@ -12,7 +12,7 @@ define([
|
|||||||
},
|
},
|
||||||
model: FieldModel,
|
model: FieldModel,
|
||||||
url: function() {
|
url: function() {
|
||||||
return '/admin/fields/' + this.sbasId + '/fields';
|
return "/admin/fields/" + this.sbasId + "/fields";
|
||||||
},
|
},
|
||||||
search: function(letters) {
|
search: function(letters) {
|
||||||
if (letters === "")
|
if (letters === "")
|
||||||
@@ -52,6 +52,10 @@ define([
|
|||||||
}
|
}
|
||||||
|
|
||||||
return index - 1;
|
return index - 1;
|
||||||
|
},
|
||||||
|
// save all collection
|
||||||
|
save: function(options) {
|
||||||
|
return Backbone.sync("update", this, options || {});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@@ -1,12 +1,12 @@
|
|||||||
define([
|
define([
|
||||||
'underscore',
|
"underscore",
|
||||||
'backbone',
|
"backbone",
|
||||||
'models/vocabulary'
|
"models/vocabulary"
|
||||||
], function(_, Backbone, VocabularyModel) {
|
], function(_, Backbone, VocabularyModel) {
|
||||||
var VocabularyCollection = Backbone.Collection.extend({
|
var VocabularyCollection = Backbone.Collection.extend({
|
||||||
model: VocabularyModel,
|
model: VocabularyModel,
|
||||||
url: function() {
|
url: function() {
|
||||||
return '/admin/fields/vocabularies';
|
return "/admin/fields/vocabularies";
|
||||||
},
|
},
|
||||||
comparator: function(item) {
|
comparator: function(item) {
|
||||||
return item.get("name");
|
return item.get("name");
|
||||||
|
13
www/scripts/apps/admin/fields/errors/error.js
Normal file
13
www/scripts/apps/admin/fields/errors/error.js
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
define([
|
||||||
|
"jquery",
|
||||||
|
"underscore"
|
||||||
|
], function($, _) {
|
||||||
|
|
||||||
|
var Error = function (model, fieldId, message) {
|
||||||
|
this.model = model;
|
||||||
|
this.fieldId = fieldId;
|
||||||
|
this.message = message;
|
||||||
|
};
|
||||||
|
|
||||||
|
return Error;
|
||||||
|
});
|
125
www/scripts/apps/admin/fields/errors/errorManager.js
Normal file
125
www/scripts/apps/admin/fields/errors/errorManager.js
Normal file
@@ -0,0 +1,125 @@
|
|||||||
|
define([
|
||||||
|
"jquery",
|
||||||
|
"underscore",
|
||||||
|
"backbone",
|
||||||
|
"apps/admin/fields/errors/errorModel"
|
||||||
|
], function($, _, Backbone, ErrorModel) {
|
||||||
|
|
||||||
|
var ErrorManager = function() {
|
||||||
|
this.errors = {};
|
||||||
|
_.extend(this, Backbone.Events);
|
||||||
|
};
|
||||||
|
|
||||||
|
ErrorManager.prototype = {
|
||||||
|
addModelError: function (model) {
|
||||||
|
return this.errors[model.get("id")] = new ErrorModel(model.get("id"));
|
||||||
|
},
|
||||||
|
getModelError: function (model) {
|
||||||
|
if (this.containsModelError(model)) {
|
||||||
|
return this.errors[model.get("id")];
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
removeModelError: function (model) {
|
||||||
|
if (this.containsModelError(model)) {
|
||||||
|
delete this.errors[model.get("id")];
|
||||||
|
}
|
||||||
|
},
|
||||||
|
containsModelError: function (model) {
|
||||||
|
return "undefined" !== typeof this.errors[model.get("id")];
|
||||||
|
},
|
||||||
|
addModelFieldError: function(error) {
|
||||||
|
if (! error instanceof Error) {
|
||||||
|
throw "Item must be an error object";
|
||||||
|
}
|
||||||
|
|
||||||
|
var model = error.model;
|
||||||
|
var fieldId = error.fieldId;
|
||||||
|
|
||||||
|
if (!this.containsModelError(model)) {
|
||||||
|
this.addModelError(model);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.getModelError(model).add(fieldId, error);
|
||||||
|
|
||||||
|
this.trigger("add-error", error);
|
||||||
|
|
||||||
|
return this;
|
||||||
|
},
|
||||||
|
removeModelFieldError: function(model, fieldId) {
|
||||||
|
var modelError = this.getModelError(model);
|
||||||
|
|
||||||
|
if (modelError) {
|
||||||
|
modelError.remove(fieldId);
|
||||||
|
this.trigger("remove-error", model, fieldId);
|
||||||
|
|
||||||
|
if (modelError.count() === 0) {
|
||||||
|
this.removeModelError(model);
|
||||||
|
|
||||||
|
if (!this.hasErrors()) {
|
||||||
|
this.trigger("no-error");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
clearModelFieldErrors: function(model, fieldId) {
|
||||||
|
var modelError = this.getModelError(model);
|
||||||
|
|
||||||
|
if (modelError) {
|
||||||
|
modelError.clear();
|
||||||
|
this.removeModelError(model);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this.hasErrors()) {
|
||||||
|
this.trigger("no-error");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
containsModelFieldError: function (model, fieldId) {
|
||||||
|
var modelError = this.getModelError(model);
|
||||||
|
|
||||||
|
if (modelError) {
|
||||||
|
return modelError.has(fieldId);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
getModelFieldError: function(model, fieldId) {
|
||||||
|
var modelError = this.getModelError(model);
|
||||||
|
|
||||||
|
if (modelError) {
|
||||||
|
return modelError.get(fieldId);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
clearAll: function() {
|
||||||
|
this.errors = {};
|
||||||
|
this.trigger("no-error");
|
||||||
|
},
|
||||||
|
hasErrors: function () {
|
||||||
|
return !_.isEmpty(this.errors);
|
||||||
|
},
|
||||||
|
count: function () {
|
||||||
|
var count = 0;
|
||||||
|
for (var k in this.errors) {
|
||||||
|
if (this.errors.hasOwnProperty(k)) {
|
||||||
|
++count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
},
|
||||||
|
all: function () {
|
||||||
|
var errors = [];
|
||||||
|
_.each(this.errors, function(modelErrors) {
|
||||||
|
_.each(modelErrors.all(), function(error) {
|
||||||
|
errors.push(error);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
return errors;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return ErrorManager;
|
||||||
|
});
|
50
www/scripts/apps/admin/fields/errors/errorModel.js
Normal file
50
www/scripts/apps/admin/fields/errors/errorModel.js
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
define([
|
||||||
|
"jquery",
|
||||||
|
"underscore"
|
||||||
|
], function($, _) {
|
||||||
|
var ErrorModel = function(id) {
|
||||||
|
this.id = id;
|
||||||
|
this.errors = {};
|
||||||
|
};
|
||||||
|
|
||||||
|
ErrorModel.prototype = {
|
||||||
|
add: function(id, error) {
|
||||||
|
if (! error instanceof Error) {
|
||||||
|
throw "Item must be an error object";
|
||||||
|
}
|
||||||
|
|
||||||
|
this.errors[id] = error;
|
||||||
|
},
|
||||||
|
get: function(id) {
|
||||||
|
if (this.has(id)) {
|
||||||
|
return this.errors[id];
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
has: function (id) {
|
||||||
|
return "undefined" !== typeof this.errors[id];
|
||||||
|
},
|
||||||
|
remove: function(id) {
|
||||||
|
if (this.has(id)) {
|
||||||
|
delete this.errors[id];
|
||||||
|
}
|
||||||
|
},
|
||||||
|
count: function() {
|
||||||
|
var count = 0;
|
||||||
|
for (var k in this.errors) {
|
||||||
|
if (this.errors.hasOwnProperty(k)) {
|
||||||
|
++count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
},
|
||||||
|
clear: function () {
|
||||||
|
this.errors = {};
|
||||||
|
},
|
||||||
|
all: function () {
|
||||||
|
return this.errors;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return ErrorModel;
|
||||||
|
});
|
@@ -1,25 +1,27 @@
|
|||||||
|
// configure AMD loading
|
||||||
require.config({
|
require.config({
|
||||||
baseUrl: "/scripts",
|
baseUrl: "/scripts",
|
||||||
paths: {
|
paths: {
|
||||||
jquery: '../include/minify/f=include/jslibs/jquery-1.7.1',
|
jquery: "../include/minify/f=include/jslibs/jquery-1.7.1",
|
||||||
jqueryui: '../include/jslibs/jquery-ui-1.8.17/js/jquery-ui-1.8.17.custom.min',
|
jqueryui: "../include/jslibs/jquery-ui-1.8.17/js/jquery-ui-1.8.17.custom.min",
|
||||||
underscore: '../assets/underscore-amd/underscore',
|
underscore: "../assets/underscore-amd/underscore",
|
||||||
backbone: '../assets/backbone-amd/backbone',
|
backbone: "../assets/backbone-amd/backbone",
|
||||||
twig: '../assets/twig/twig',
|
twig: "../assets/twig/twig",
|
||||||
i18n: '../assets/i18n/i18next.amd',
|
i18n: "../assets/i18n/i18next.amd",
|
||||||
bootstrap: '../skins/html5/bootstrap/js/bootstrap.min'
|
bootstrap: "../skins/html5/bootstrap/js/bootstrap.min"
|
||||||
},
|
},
|
||||||
shim: {
|
shim: {
|
||||||
twig: {
|
twig: {
|
||||||
exports: 'Twig'
|
exports: "Twig"
|
||||||
},
|
},
|
||||||
bootstrap : ['jquery'],
|
bootstrap : ["jquery"],
|
||||||
jqueryui: {
|
jqueryui: {
|
||||||
deps: [ 'jquery' ]
|
deps: [ "jquery" ]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
require(['apps/admin/fields/app'], function(App) {
|
// launch application
|
||||||
|
require(["apps/admin/fields/app"], function(App) {
|
||||||
App.initialize();
|
App.initialize();
|
||||||
});
|
});
|
||||||
|
@@ -1,9 +1,10 @@
|
|||||||
define([
|
define([
|
||||||
'underscore',
|
"jquery",
|
||||||
'backbone',
|
"underscore",
|
||||||
'i18n',
|
"backbone",
|
||||||
'bootstrap'
|
"i18n",
|
||||||
], function(_, Backbone, i18n, bootstrap) {
|
"bootstrap"
|
||||||
|
], function($, _, Backbone, i18n, bootstrap) {
|
||||||
var AlertView = Backbone.View.extend({
|
var AlertView = Backbone.View.extend({
|
||||||
tagName: "div",
|
tagName: "div",
|
||||||
className: "alert",
|
className: "alert",
|
||||||
@@ -15,7 +16,7 @@ define([
|
|||||||
this.message = options.message || "";
|
this.message = options.message || "";
|
||||||
}
|
}
|
||||||
// remove view when alert is closed
|
// remove view when alert is closed
|
||||||
this.$el.bind('closed', function () {
|
this.$el.bind("closed", function () {
|
||||||
self.remove();
|
self.remove();
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
@@ -26,7 +27,7 @@ define([
|
|||||||
|
|
||||||
this.$el.addClass("alert-" + this.alert).html(template).alert();
|
this.$el.addClass("alert-" + this.alert).html(template).alert();
|
||||||
|
|
||||||
$('.block-alert').empty().append(this.$el);
|
$(".block-alert").empty().append(this.$el);
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
@@ -1,26 +1,31 @@
|
|||||||
define([
|
define([
|
||||||
'underscore',
|
"jquery",
|
||||||
'backbone',
|
"underscore",
|
||||||
'i18n'
|
"backbone",
|
||||||
], function( _, Backbone, i18n, bootstrap) {
|
"i18n"
|
||||||
|
], function($, _, Backbone, i18n, bootstrap) {
|
||||||
var DcFieldsView = Backbone.View.extend({
|
var DcFieldsView = Backbone.View.extend({
|
||||||
tagName: "div",
|
tagName: "div",
|
||||||
className: "input-append",
|
className: "input-append",
|
||||||
events: {
|
initialize : function (options) {
|
||||||
"change select": "selectChangedAction"
|
this.field = options.field;
|
||||||
},
|
},
|
||||||
render: function() {
|
render: function() {
|
||||||
var template = _.template($("#dc_fields_template").html(), {
|
var template = _.template($("#dc_fields_template").html(), {
|
||||||
dces_elements: this.collection.toJSON()
|
dces_elements: this.collection.toJSON(),
|
||||||
|
field: this.field.toJSON()
|
||||||
});
|
});
|
||||||
|
|
||||||
this.$el.html(template);
|
this.$el.html(template);
|
||||||
|
|
||||||
|
var index = $("#dces-element", AdminFieldApp.$rightBlock)[0].selectedIndex - 1;
|
||||||
|
if (index > 0 ) {
|
||||||
|
$(".dces-help-block", AdminFieldApp.$rightBlock).html(
|
||||||
|
this.collection.at(index).get("definition")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
},
|
|
||||||
selectChangedAction: function(e) {
|
|
||||||
var index = $(e.target)[0].selectedIndex;
|
|
||||||
this.$el.closest('table').find('.dces-help-block').empty().append(this.collection.at(index).get('definition'));
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@@ -1,36 +1,47 @@
|
|||||||
define([
|
define([
|
||||||
'underscore',
|
"jquery",
|
||||||
'backbone',
|
"underscore",
|
||||||
'i18n',
|
"backbone",
|
||||||
'apps/admin/fields/views/alert',
|
"i18n",
|
||||||
'apps/admin/fields/views/modal',
|
"apps/admin/fields/views/alert",
|
||||||
'apps/admin/fields/views/dcField',
|
"apps/admin/fields/views/modal",
|
||||||
], function(_, Backbone, i18n, AlertView, ModalView, DcFieldView) {
|
"apps/admin/fields/views/dcField",
|
||||||
|
"apps/admin/fields/errors/error"
|
||||||
|
], function($, _, Backbone, i18n, AlertView, ModalView, DcFieldView, Error) {
|
||||||
var FieldEditView = Backbone.View.extend({
|
var FieldEditView = Backbone.View.extend({
|
||||||
tagName: "div",
|
tagName: "div",
|
||||||
className: "field-edit",
|
className: "field-edit",
|
||||||
initialize: function() {
|
initialize: function() {
|
||||||
this.model.on('change', this.render, this);
|
this.model.on("change", this._onModelChange, this);
|
||||||
this.model.on('change:name', this.onModelFieldChange, this);
|
|
||||||
this.model.on('change:tag', this.onModelFieldChange, this);
|
|
||||||
|
|
||||||
this.dcFieldsSubView = new DcFieldView({
|
this.dcFieldsSubView = new DcFieldView({
|
||||||
collection: window.AdminFieldApp.dcFieldsCollection
|
collection: AdminFieldApp.dcFieldsCollection,
|
||||||
|
field: this.model
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
updateModel: function(model) {
|
||||||
|
// unbind event to previous model
|
||||||
|
this.model.off("change");
|
||||||
|
this.model = model;
|
||||||
|
|
||||||
|
return this;
|
||||||
|
},
|
||||||
render: function() {
|
render: function() {
|
||||||
|
var self = this;
|
||||||
var template = _.template($("#edit_template").html(), {
|
var template = _.template($("#edit_template").html(), {
|
||||||
field: this.model.toJSON(),
|
field: this.model.toJSON(),
|
||||||
vocabularyTypes: window.AdminFieldApp.vocabularyCollection.toJSON()
|
vocabularyTypes: AdminFieldApp.vocabularyCollection.toJSON(),
|
||||||
|
modelErrors: AdminFieldApp.errorManager.getModelError(this.model)
|
||||||
});
|
});
|
||||||
|
|
||||||
this.$el.empty().html(template);
|
this.$el.empty().html(template);
|
||||||
|
|
||||||
this.assign({
|
this._assign({
|
||||||
'.dc-fields-subview' : this.dcFieldsSubView
|
".dc-fields-subview" : this.dcFieldsSubView
|
||||||
});
|
});
|
||||||
|
|
||||||
$("#tag", this.$el).autocomplete({
|
var completer = $("#tag", this.$el).autocomplete({
|
||||||
|
minLength: 2,
|
||||||
source: function(request, response) {
|
source: function(request, response) {
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url: "/admin/fields/tags/search",
|
url: "/admin/fields/tags/search",
|
||||||
@@ -47,72 +58,170 @@ define([
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
},
|
||||||
|
close: function(e) {
|
||||||
|
var fieldTag = $(e.target);
|
||||||
|
var fieldTagId = fieldTag.attr("id");
|
||||||
|
var fieldTagValue = fieldTag.val();
|
||||||
|
|
||||||
|
// check for format tag
|
||||||
|
if ("" !== fieldTagValue && false === /[a-z]+:[a-z0-9]+/i.test(fieldTagValue)) {
|
||||||
|
fieldTag
|
||||||
|
.closest(".control-group")
|
||||||
|
.addClass("error")
|
||||||
|
.find(".help-block")
|
||||||
|
.empty()
|
||||||
|
.append(i18n.t("validation_tag_invalid"));
|
||||||
|
// add error
|
||||||
|
AdminFieldApp.errorManager.addModelFieldError(new Error(
|
||||||
|
self.model, fieldTagId, i18n.t("validation_tag_invalid")
|
||||||
|
));
|
||||||
|
} else if (fieldTag.closest(".control-group").hasClass("error")) {
|
||||||
|
// remove error
|
||||||
|
AdminFieldApp.errorManager.removeModelFieldError(
|
||||||
|
self.model, fieldTagId
|
||||||
|
);
|
||||||
|
|
||||||
|
fieldTag
|
||||||
|
.closest(".control-group")
|
||||||
|
.removeClass("error")
|
||||||
|
.find(".help-block")
|
||||||
|
.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
var data = {};
|
||||||
|
data[fieldTagId] = fieldTagValue;
|
||||||
|
self.model.set(data);
|
||||||
}
|
}
|
||||||
}).val(this.model.get('tag')).autocomplete("widget").addClass("ui-autocomplete-admin-field");
|
});
|
||||||
|
|
||||||
|
completer
|
||||||
|
.val(this.model.get("tag"))
|
||||||
|
.autocomplete("widget")
|
||||||
|
.addClass("ui-autocomplete-admin-field");
|
||||||
|
|
||||||
|
this.delegateEvents();
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
},
|
},
|
||||||
events: {
|
events: {
|
||||||
|
"click": "focusAction",
|
||||||
"click .delete-field": "deleteAction",
|
"click .delete-field": "deleteAction",
|
||||||
|
"keyup #name": "changeNameAction",
|
||||||
"focusout input[type=text]": "fieldChangedAction",
|
"focusout input[type=text]": "fieldChangedAction",
|
||||||
"change input[type=checkbox]": "fieldChangedAction",
|
"change input[type=checkbox]": "fieldChangedAction",
|
||||||
"change select": "selectionChangedAction"
|
"change select": "selectionChangedAction"
|
||||||
},
|
},
|
||||||
|
focusAction: function() {
|
||||||
|
var index = AdminFieldApp.fieldListView.collection.indexOf(this.model);
|
||||||
|
if (index >= 0) {
|
||||||
|
AdminFieldApp.fieldListView.itemViews[index].animate();
|
||||||
|
}
|
||||||
|
|
||||||
|
return this;
|
||||||
|
},
|
||||||
|
// on input name keyup check for errors
|
||||||
|
changeNameAction: function(event) {
|
||||||
|
var self = this;
|
||||||
|
var fieldName = $(event.target);
|
||||||
|
var fieldNameId = fieldName.attr("id");
|
||||||
|
var fieldNameValue = fieldName.val();
|
||||||
|
|
||||||
|
// check for duplicate field name
|
||||||
|
if ("" === fieldNameValue || "undefined" !== typeof AdminFieldApp.fieldListView.collection.find(function(model) {
|
||||||
|
return model.get("name").toLowerCase() === fieldNameValue.toLowerCase() && self.model.get("id") !== model.get("id");
|
||||||
|
})) {
|
||||||
|
fieldName
|
||||||
|
.closest(".control-group")
|
||||||
|
.addClass("error")
|
||||||
|
.find(".help-block")
|
||||||
|
.empty()
|
||||||
|
.append(i18n.t("validation_name_exists"));
|
||||||
|
// add error
|
||||||
|
AdminFieldApp.errorManager.addModelFieldError(new Error(
|
||||||
|
self.model, fieldNameId, i18n.t("" === fieldNameValue ? "validation_blank" : "validation_name_exists")
|
||||||
|
));
|
||||||
|
} else if (fieldName.closest(".control-group").hasClass("error")) {
|
||||||
|
fieldName
|
||||||
|
.closest(".control-group")
|
||||||
|
.removeClass("error")
|
||||||
|
.find(".help-block")
|
||||||
|
.empty();
|
||||||
|
// remove error
|
||||||
|
AdminFieldApp.errorManager.removeModelFieldError(
|
||||||
|
self.model, fieldNameId
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
selectionChangedAction: function(e) {
|
selectionChangedAction: function(e) {
|
||||||
var field = $(e.currentTarget);
|
var field = $(e.currentTarget);
|
||||||
var value = $("option:selected", field).val();
|
|
||||||
var data = {};
|
var data = {};
|
||||||
data[field.attr('id')] = value;
|
data[field.attr("id")] = $("option:selected", field).val();
|
||||||
this.model.set(data);
|
this.model.set(data);
|
||||||
|
|
||||||
|
return this;
|
||||||
},
|
},
|
||||||
fieldChangedAction: function(e) {
|
fieldChangedAction: function(e) {
|
||||||
var field = $(e.currentTarget);
|
var field = $(e.currentTarget);
|
||||||
|
var fieldId = field.attr("id");
|
||||||
var data = {};
|
var data = {};
|
||||||
data[field.attr('id')] = field.is(":checkbox") ? field.is(":checked") : field.val();
|
data[fieldId] = field.is(":checkbox") ? field.is(":checked") : field.val();
|
||||||
this.model.set(data);
|
this.model.set(data);
|
||||||
|
|
||||||
|
return this;
|
||||||
},
|
},
|
||||||
deleteAction: function() {
|
deleteAction: function() {
|
||||||
var self = this;
|
var self = this;
|
||||||
var modalView = new ModalView({
|
var modalView = new ModalView({
|
||||||
model: this.model,
|
model: this.model,
|
||||||
message: i18n.t("are_you_sure_delete", { postProcess: "sprintf", sprintf: [this.model.get('name')] })
|
message: i18n.t("are_you_sure_delete", {
|
||||||
|
postProcess: "sprintf",
|
||||||
|
sprintf: [this.model.get("name")]
|
||||||
|
})
|
||||||
});
|
});
|
||||||
var previousIndex = AdminFieldApp.fieldListView.collection.previousIndex(this.model);
|
|
||||||
var nextIndex = AdminFieldApp.fieldListView.collection.nextIndex(this.model);
|
|
||||||
var itemView;
|
|
||||||
|
|
||||||
if (previousIndex) {
|
// get collection index of previous and next model
|
||||||
itemView = AdminFieldApp.fieldListView.itemViews[previousIndex];
|
var previousIndex = AdminFieldApp.fieldListView.collection.previousIndex(this.model);
|
||||||
} else if (nextIndex) {
|
var nextIndex = AdminFieldApp.fieldListView.collection.nextIndex(this.model);
|
||||||
itemView = AdminFieldApp.fieldListView.itemViews[nextIndex];
|
|
||||||
}
|
// get previous index if exists else next index - 1 as item is being deleted
|
||||||
|
var index = previousIndex ? previousIndex : (nextIndex ? nextIndex - 1 : -1);
|
||||||
|
|
||||||
modalView.render();
|
modalView.render();
|
||||||
modalView.on('modal:confirm', function() {
|
modalView.on("modal:confirm", function() {
|
||||||
self.model.destroy({
|
self.model.destroy({
|
||||||
success: function(model, response) {
|
success: function(model, response) {
|
||||||
AdminFieldApp.fieldListView.collection.remove(self.model);
|
AdminFieldApp.fieldListView.collection.remove(self.model);
|
||||||
|
self._selectModelView(index);
|
||||||
|
|
||||||
if (itemView) {
|
new AlertView({alert: "info", message: i18n.t("deleted_success", {
|
||||||
itemView.clickAction().animate();
|
postProcess: "sprintf",
|
||||||
}
|
sprintf: [model.get("name")]
|
||||||
|
})
|
||||||
new AlertView({alert: 'info', message: i18n.t("deleted_success", { postProcess: "sprintf", sprintf: [model.get('name')] })}).render();
|
}).render();
|
||||||
},
|
},
|
||||||
error: function(model, xhr) {
|
error: function(model, xhr) {
|
||||||
new AlertView({alert: 'error', message: i18n.t("something_wrong")}).render();
|
new AlertView({
|
||||||
|
alert: "error", message: i18n.t("something_wrong")
|
||||||
|
}).render();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
},
|
},
|
||||||
onModelFieldChange: function() {
|
_onModelChange: function() {
|
||||||
AdminFieldApp.fieldListView.collection.remove(this.model, {silent: true});
|
AdminFieldApp.fieldListView.collection.remove(this.model, {silent: true});
|
||||||
AdminFieldApp.fieldListView.collection.add(this.model);
|
AdminFieldApp.fieldListView.collection.add(this.model);
|
||||||
|
|
||||||
|
var index = AdminFieldApp.fieldListView.collection.indexOf(this.model);
|
||||||
|
|
||||||
|
this._selectModelView(index);
|
||||||
|
|
||||||
this.render();
|
this.render();
|
||||||
},
|
},
|
||||||
assign: function(selector, view) {
|
// bind a subview to a DOM element
|
||||||
|
_assign: function(selector, view) {
|
||||||
var selectors;
|
var selectors;
|
||||||
if (_.isObject(selector)) {
|
if (_.isObject(selector)) {
|
||||||
selectors = selector;
|
selectors = selector;
|
||||||
@@ -124,6 +233,13 @@ define([
|
|||||||
_.each(selectors, function(view, selector) {
|
_.each(selectors, function(view, selector) {
|
||||||
view.setElement(this.$(selector)).render();
|
view.setElement(this.$(selector)).render();
|
||||||
}, this);
|
}, this);
|
||||||
|
},
|
||||||
|
// select temView by index in itemList
|
||||||
|
_selectModelView: function(index) {
|
||||||
|
// select previous or next itemview
|
||||||
|
if (index >= 0) {
|
||||||
|
AdminFieldApp.fieldListView.itemViews[index].clickAction().animate();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
38
www/scripts/apps/admin/fields/views/fieldError.js
Normal file
38
www/scripts/apps/admin/fields/views/fieldError.js
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
define([
|
||||||
|
"jquery",
|
||||||
|
"underscore",
|
||||||
|
"backbone",
|
||||||
|
"i18n"
|
||||||
|
], function($, _, Backbone, i18n) {
|
||||||
|
var FieldErrorView = Backbone.View.extend({
|
||||||
|
initialize: function() {
|
||||||
|
AdminFieldApp.errorManager.on("add-error", this.render, this);
|
||||||
|
AdminFieldApp.errorManager.on("remove-error", this.render, this);
|
||||||
|
},
|
||||||
|
render: function() {
|
||||||
|
var messages = [];
|
||||||
|
var errors = AdminFieldApp.errorManager.all();
|
||||||
|
|
||||||
|
_.each(_.groupBy(errors, function(error) {
|
||||||
|
return error.model.get("name");
|
||||||
|
}), function(groupedErrors) {
|
||||||
|
_.each(groupedErrors, function(error) {
|
||||||
|
messages.push(i18n.t("field_error", {
|
||||||
|
postProcess: "sprintf",
|
||||||
|
sprintf: [error.model.get("name")]
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
var template = _.template($("#field_error_template").html(), {
|
||||||
|
messages: messages
|
||||||
|
});
|
||||||
|
|
||||||
|
$(".block-alert").html(template);
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return FieldErrorView;
|
||||||
|
});
|
@@ -1,12 +1,13 @@
|
|||||||
define([
|
define([
|
||||||
'jqueryui',
|
"jquery",
|
||||||
'underscore',
|
"jqueryui",
|
||||||
'backbone',
|
"underscore",
|
||||||
'i18n',
|
"backbone",
|
||||||
'apps/admin/fields/views/listRow',
|
"i18n",
|
||||||
'apps/admin/fields/views/alert',
|
"apps/admin/fields/views/listRow",
|
||||||
'models/field'
|
"apps/admin/fields/views/alert",
|
||||||
], function(jqueryui, _, Backbone, i18n, FieldListRowView, AlertView, FieldModel) {
|
"models/field"
|
||||||
|
], function($, jqueryui, _, Backbone, i18n, FieldListRowView, AlertView, FieldModel) {
|
||||||
var FieldListView = Backbone.View.extend({
|
var FieldListView = Backbone.View.extend({
|
||||||
events: {
|
events: {
|
||||||
"keyup #live_search": "searchAction",
|
"keyup #live_search": "searchAction",
|
||||||
@@ -16,14 +17,35 @@ define([
|
|||||||
"update-sort": "updateSortAction"
|
"update-sort": "updateSortAction"
|
||||||
},
|
},
|
||||||
initialize: function() {
|
initialize: function() {
|
||||||
// Store all single rendered views
|
var self = this;
|
||||||
|
// store all single rendered views
|
||||||
this.itemViews = [];
|
this.itemViews = [];
|
||||||
|
|
||||||
_.bindAll(this, "render");
|
|
||||||
// rerender whenever there is a change on the collection
|
// rerender whenever there is a change on the collection
|
||||||
this.collection.bind("reset", this.render, this);
|
this.collection.bind("reset", this.render, this);
|
||||||
this.collection.bind("add", this.render, this);
|
this.collection.bind("add", this.render, this);
|
||||||
this.collection.bind("remove", this.render, this);
|
this.collection.bind("remove", this.render, this);
|
||||||
|
|
||||||
|
AdminFieldApp.errorManager.on('add-error', function(error) {
|
||||||
|
var model = error.model;
|
||||||
|
var itemView = _.find(self.itemViews, function(view) {
|
||||||
|
return model.get('id') === view.model.get('id');
|
||||||
|
});
|
||||||
|
|
||||||
|
if ('undefined' !== typeof itemView) {
|
||||||
|
itemView.error(true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
AdminFieldApp.errorManager.on('remove-error', function(model) {
|
||||||
|
var itemView = _.find(self.itemViews, function(view) {
|
||||||
|
return model.get('id') === view.model.get('id');
|
||||||
|
});
|
||||||
|
|
||||||
|
if ('undefined' !== typeof itemView) {
|
||||||
|
itemView.error(false);
|
||||||
|
}
|
||||||
|
});
|
||||||
},
|
},
|
||||||
render: function() {
|
render: function() {
|
||||||
var template = _.template($("#item_list_view_template").html(), {});
|
var template = _.template($("#item_list_view_template").html(), {});
|
||||||
@@ -35,6 +57,7 @@ define([
|
|||||||
this._renderList(this.collection);
|
this._renderList(this.collection);
|
||||||
|
|
||||||
$("#new-source", this.$el).autocomplete({
|
$("#new-source", this.$el).autocomplete({
|
||||||
|
minLength: 2,
|
||||||
source: function(request, response) {
|
source: function(request, response) {
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url: "/admin/fields/tags/search",
|
url: "/admin/fields/tags/search",
|
||||||
@@ -54,8 +77,11 @@ define([
|
|||||||
}
|
}
|
||||||
}).autocomplete("widget").addClass("ui-autocomplete-admin-field");
|
}).autocomplete("widget").addClass("ui-autocomplete-admin-field");
|
||||||
|
|
||||||
|
AdminFieldApp.resizeListBlock();
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
},
|
},
|
||||||
|
// render list by appending single item view, also fill itemViews
|
||||||
_renderList: function(fields) {
|
_renderList: function(fields) {
|
||||||
var that = this;
|
var that = this;
|
||||||
|
|
||||||
@@ -63,45 +89,100 @@ define([
|
|||||||
this.itemViews = [];
|
this.itemViews = [];
|
||||||
|
|
||||||
fields.each(function(field) {
|
fields.each(function(field) {
|
||||||
|
var fieldErrors = AdminFieldApp.errorManager.getModelError(field);
|
||||||
|
|
||||||
var singleView = new FieldListRowView({
|
var singleView = new FieldListRowView({
|
||||||
model: field,
|
model: field,
|
||||||
id: 'field-' + field.get('id')
|
id: "field-" + field.get("id")
|
||||||
});
|
}).error(fieldErrors && fieldErrors.count() > 0);
|
||||||
|
|
||||||
that.$listEl.append(singleView.render().el);
|
that.$listEl.append(singleView.render().el);
|
||||||
that.itemViews.push(singleView);
|
that.itemViews.push(singleView);
|
||||||
});
|
});
|
||||||
|
|
||||||
this.$listEl.sortable({
|
this.$listEl.sortable({
|
||||||
handle: ".handle",
|
handle: ".handle",
|
||||||
|
placeholder: "item-list-placeholder",
|
||||||
|
start: function(event, ui) {
|
||||||
|
ui.item.addClass("border-bottom");
|
||||||
|
|
||||||
|
},
|
||||||
stop: function(event, ui) {
|
stop: function(event, ui) {
|
||||||
ui.item.trigger('drop', ui.item.index());
|
ui.firstItemPosition = $("li:first", $(this).sortable('widget')).position().top;
|
||||||
|
ui.item.trigger("drop", ui);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
this.$listEl.disableSelection();
|
this.$listEl.disableSelection();
|
||||||
|
|
||||||
this.$listEl.find('li:last').addClass('last');
|
this.$listEl.find("li:last").addClass("last");
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
},
|
},
|
||||||
searchAction: function(event) {
|
searchAction: function(event) {
|
||||||
this._renderList(this.collection.search($("#live_search", this.$el).val()));
|
this._renderList(this.collection.search($("#live_search", this.$el).val()));
|
||||||
|
|
||||||
|
return this;
|
||||||
},
|
},
|
||||||
createAction: function(event) {
|
createAction: function(event) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
var formErrors = 0;
|
||||||
|
|
||||||
var fieldName = $("#new-name", this.$el);
|
var fieldName = $("#new-name", this.$el);
|
||||||
|
var fieldNameValue = fieldName.val();
|
||||||
|
var fieldTag = $("#new-source", this.$el);
|
||||||
|
var fieldTagValue = fieldTag.val();
|
||||||
|
|
||||||
if ('' == fieldName.val()) {
|
// check for empty field name
|
||||||
fieldName.closest('.control-group').addClass('error').find('.help-block').empty().append(i18n.t('validation_blank'));
|
if ("" === fieldNameValue) {
|
||||||
|
fieldName
|
||||||
|
.closest(".control-group")
|
||||||
|
.addClass("error")
|
||||||
|
.find(".help-block")
|
||||||
|
.empty()
|
||||||
|
.append(i18n.t("validation_blank"));
|
||||||
|
|
||||||
|
formErrors++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check for duplicate field name
|
||||||
|
if ("undefined" !== typeof this.collection.find(function(model){
|
||||||
|
return model.get("name").toLowerCase() === fieldNameValue.toLowerCase();
|
||||||
|
})) {
|
||||||
|
fieldName
|
||||||
|
.closest(".control-group")
|
||||||
|
.addClass("error")
|
||||||
|
.find(".help-block")
|
||||||
|
.empty()
|
||||||
|
.append(i18n.t("validation_name_exists"));
|
||||||
|
|
||||||
|
formErrors++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check for format tag
|
||||||
|
if ("" !== fieldTagValue && false === /[a-z]+:[a-z0-9]+/i.test(fieldTagValue)) {
|
||||||
|
fieldTag
|
||||||
|
.closest(".control-group")
|
||||||
|
.addClass("error")
|
||||||
|
.find(".help-block")
|
||||||
|
.empty()
|
||||||
|
.append(i18n.t("validation_tag_invalid"));
|
||||||
|
|
||||||
|
formErrors++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (formErrors > 0 ) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var field = new FieldModel({
|
var field = new FieldModel({
|
||||||
"sbas-id": AdminFieldApp.sbas_id,
|
"sbas-id": AdminFieldApp.sbas_id,
|
||||||
"name": fieldName.val(),
|
"name": fieldNameValue,
|
||||||
"tag": $("#new-source", this.$el).val(),
|
"tag": fieldTagValue,
|
||||||
"multi": $("#new-multivalued", this.$el).is(':checked')
|
"multi": $("#new-multivalued", this.$el).is(":checked"),
|
||||||
|
"sorter": this.collection.max(function(model) {
|
||||||
|
return model.get("sorter");
|
||||||
|
}).get("sorter") + 1
|
||||||
});
|
});
|
||||||
|
|
||||||
field.save(null, {
|
field.save(null, {
|
||||||
@@ -109,36 +190,53 @@ define([
|
|||||||
if (response.success) {
|
if (response.success) {
|
||||||
self.collection.add(field);
|
self.collection.add(field);
|
||||||
_.last(self.itemViews).clickAction().animate();
|
_.last(self.itemViews).clickAction().animate();
|
||||||
new AlertView({alert: 'success', message: response.message }).render();
|
|
||||||
} else {
|
|
||||||
new AlertView({alert: 'warning', message: response.message}).render();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
new AlertView({
|
||||||
|
alert: response.success ? "success" : "error", message: response.message
|
||||||
|
}).render();
|
||||||
},
|
},
|
||||||
error: function(model, xhr, options) {
|
error: function(model, xhr, options) {
|
||||||
new AlertView({alert: 'error', message: i18n.t("something_wrong")}).render();
|
new AlertView({
|
||||||
|
alert: "error", message: i18n.t("something_wrong")}
|
||||||
|
).render();
|
||||||
|
|
||||||
self.toggleCreateFormAction();
|
self.toggleCreateFormAction();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
return this;
|
||||||
},
|
},
|
||||||
toggleCreateFormAction: function(event) {
|
toggleCreateFormAction: function(event) {
|
||||||
$('.add-field-block', this.$el).toggle();
|
var fieldBlock = $(".add-field-block", this.$el);
|
||||||
|
|
||||||
|
fieldBlock.is(":hidden") ? fieldBlock.show() : fieldBlock.hide();
|
||||||
|
AdminFieldApp.resizeListBlock();
|
||||||
|
|
||||||
|
return this;
|
||||||
},
|
},
|
||||||
updateSortAction: function(event, model, position) {
|
updateSortAction: function(event, model, ui) {
|
||||||
|
var position = ui.item.index();
|
||||||
this.collection.remove(model, {silent: true});
|
this.collection.remove(model, {silent: true});
|
||||||
|
|
||||||
|
// reorder all collection model
|
||||||
this.collection.each(function(model, index) {
|
this.collection.each(function(model, index) {
|
||||||
var ordinal = index;
|
var ordinal = index;
|
||||||
if (index >= position) ordinal += 1;
|
if (index >= position) ordinal += 1;
|
||||||
model.set('sorter', ordinal);
|
model.set("sorter", ordinal);
|
||||||
});
|
});
|
||||||
|
|
||||||
model.set('sorter', position);
|
model.set("sorter", position);
|
||||||
this.collection.add(model, {at: position});
|
this.collection.add(model, {at: position});
|
||||||
|
|
||||||
// update edit view
|
this.itemViews[0].animate(Math.abs(ui.firstItemPosition));
|
||||||
|
|
||||||
|
// update edit view model
|
||||||
AdminFieldApp.fieldEditView.model = this.collection.find(function(el) {
|
AdminFieldApp.fieldEditView.model = this.collection.find(function(el) {
|
||||||
return el.get('id') === AdminFieldApp.fieldEditView.model.get('id');
|
return el.get("id") === AdminFieldApp.fieldEditView.model.get("id");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
return this;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@@ -1,15 +1,15 @@
|
|||||||
define([
|
define([
|
||||||
'underscore',
|
"jquery",
|
||||||
'backbone',
|
"underscore",
|
||||||
'apps/admin/fields/views/edit',
|
"backbone",
|
||||||
'apps/admin/fields/views/alert'
|
"apps/admin/fields/views/edit"
|
||||||
], function(_, Backbone, FieldEditView, AlertView) {
|
], function($, _, Backbone, FieldEditView) {
|
||||||
var FieldListRowView = Backbone.View.extend({
|
var FieldListRowView = Backbone.View.extend({
|
||||||
tagName: "li",
|
tagName: "li",
|
||||||
className: "field-row",
|
className: "field-row",
|
||||||
initialize: function() {
|
initialize: function() {
|
||||||
// destroy view is model is deleted
|
// destroy view is model is deleted
|
||||||
this.model.on('destroy', this.remove, this);
|
this.model.on("destroy", this.remove, this);
|
||||||
},
|
},
|
||||||
events : {
|
events : {
|
||||||
"click .trigger-click": "clickAction",
|
"click .trigger-click": "clickAction",
|
||||||
@@ -17,51 +17,71 @@ define([
|
|||||||
},
|
},
|
||||||
clickAction: function (e) {
|
clickAction: function (e) {
|
||||||
this.select();
|
this.select();
|
||||||
// first click create view else update model's view
|
// first click create edit view else update model"s view
|
||||||
if (typeof AdminFieldApp.fieldEditView === 'undefined') {
|
if (typeof AdminFieldApp.fieldEditView === "undefined") {
|
||||||
AdminFieldApp.fieldEditView = new FieldEditView({
|
AdminFieldApp.fieldEditView = new FieldEditView({
|
||||||
el: $('.right-block')[0],
|
el: AdminFieldApp.$rightBlock,
|
||||||
model: this.model
|
model: this.model
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
AdminFieldApp.fieldEditView.model = this.model;
|
AdminFieldApp.fieldEditView.updateModel(this.model).initialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
AdminFieldApp.fieldEditView.render();
|
AdminFieldApp.fieldEditView.render();
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
},
|
},
|
||||||
dropAction: function(event, index) {
|
dropAction: function(event, ui) {
|
||||||
this.$el.trigger('update-sort', [this.model, index]);
|
this.$el.trigger("update-sort", [this.model, ui]);
|
||||||
|
|
||||||
|
return this;
|
||||||
},
|
},
|
||||||
render: function() {
|
render: function() {
|
||||||
var template = _.template($("#list_row_template").html(), {
|
var template = _.template($("#list_row_template").html(), {
|
||||||
id: this.model.get('id'),
|
id: this.model.get("id"),
|
||||||
position: this.model.get('sorter'),
|
position: this.model.get("sorter"),
|
||||||
name: this.model.get('name'),
|
name: this.model.get("name"),
|
||||||
tag: this.model.get('tag')
|
tag: this.model.get("tag")
|
||||||
});
|
});
|
||||||
|
|
||||||
this.$el.empty().html(template);
|
this.$el.empty().html(template);
|
||||||
|
|
||||||
if (AdminFieldApp.fieldEditView && AdminFieldApp.fieldEditView.model.get('id') === this.model.get('id')) {
|
// highlight view if edit view model match current view model
|
||||||
|
if (AdminFieldApp.fieldEditView
|
||||||
|
&& AdminFieldApp.fieldEditView.model.get("id") === this.model.get("id")) {
|
||||||
this.select();
|
this.select();
|
||||||
}
|
}
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
},
|
},
|
||||||
// set selected class
|
// set selected class to current view
|
||||||
select: function () {
|
select: function () {
|
||||||
$("li", this.$el.closest('ul')).removeClass('selected');
|
$("li", this.$el.closest("ul")).removeClass("selected");
|
||||||
this.$el.addClass('selected');
|
this.$el.addClass("selected");
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
},
|
},
|
||||||
animate: function () {
|
// scroll to current view in item list
|
||||||
var offset = this.$el.offset();
|
animate: function (top) {
|
||||||
|
top = top || null;
|
||||||
|
|
||||||
|
if (null === top) {
|
||||||
|
top = $(".field-row").index(this.$el) * this.$el.height();
|
||||||
|
}
|
||||||
|
|
||||||
this.$el.closest('div').animate({
|
this.$el.closest("div").scrollTop(top);
|
||||||
scrollTop: offset.top - 20
|
|
||||||
});
|
return this;
|
||||||
|
},
|
||||||
|
// add error class to item
|
||||||
|
error: function (errored) {
|
||||||
|
if (errored) {
|
||||||
|
this.$el.addClass("error");
|
||||||
|
} else {
|
||||||
|
this.$el.removeClass("error");
|
||||||
|
}
|
||||||
|
|
||||||
|
return this;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@@ -1,19 +1,20 @@
|
|||||||
define([
|
define([
|
||||||
'underscore',
|
"jquery",
|
||||||
'backbone',
|
"underscore",
|
||||||
'i18n',
|
"backbone",
|
||||||
'bootstrap'
|
"i18n",
|
||||||
], function(_, Backbone, i18n, bootstrap) {
|
"bootstrap"
|
||||||
|
], function($, _, Backbone, i18n, bootstrap) {
|
||||||
var ModalView = Backbone.View.extend({
|
var ModalView = Backbone.View.extend({
|
||||||
tagName: "div",
|
tagName: "div",
|
||||||
className: "modal",
|
className: "modal",
|
||||||
events: {
|
events: {
|
||||||
'click .confirm': 'confirmAction'
|
"click .confirm": "confirmAction"
|
||||||
},
|
},
|
||||||
initialize: function (options) {
|
initialize: function (options) {
|
||||||
var self = this;
|
var self = this;
|
||||||
// remove view when modal is closed
|
// remove view when modal is closed
|
||||||
this.$el.on('hidden', function() {
|
this.$el.on("hidden", function() {
|
||||||
self.remove();
|
self.remove();
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -22,8 +23,8 @@ define([
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
render: function() {
|
render: function() {
|
||||||
var template = _.template($("#modal_delete_confirm_template").html(), {
|
var template = _.template($("#modal_template").html(), {
|
||||||
msg: this.message || ''
|
msg: this.message || ""
|
||||||
});
|
});
|
||||||
|
|
||||||
this.$el.html(template).modal();
|
this.$el.html(template).modal();
|
||||||
@@ -31,8 +32,8 @@ define([
|
|||||||
return this;
|
return this;
|
||||||
},
|
},
|
||||||
confirmAction: function () {
|
confirmAction: function () {
|
||||||
this.trigger('modal:confirm');
|
this.trigger("modal:confirm");
|
||||||
this.$el.modal('hide');
|
this.$el.modal("hide");
|
||||||
this.remove();
|
this.remove();
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
|
95
www/scripts/apps/admin/fields/views/save.js
Normal file
95
www/scripts/apps/admin/fields/views/save.js
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
define([
|
||||||
|
"jquery",
|
||||||
|
"underscore",
|
||||||
|
"backbone",
|
||||||
|
"i18n",
|
||||||
|
"bootstrap",
|
||||||
|
"apps/admin/fields/views/alert"
|
||||||
|
], function($, _, Backbone, i18n, bootstrap, AlertView) {
|
||||||
|
var SaveView = Backbone.View.extend({
|
||||||
|
initialize: function() {
|
||||||
|
var self = this;
|
||||||
|
this.previousAttributes = [];
|
||||||
|
this.$overlay = null;
|
||||||
|
|
||||||
|
AdminFieldApp.errorManager.on("add-error", function(errors) {
|
||||||
|
self._disableSaveButton(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
AdminFieldApp.errorManager.on("no-error", function() {
|
||||||
|
self._disableSaveButton(false);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
events: {
|
||||||
|
"click button.save-all" : "clickSaveAction"
|
||||||
|
},
|
||||||
|
clickSaveAction: function(event) {
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
if (this._isModelDesync()) {
|
||||||
|
this._loadingState(true);
|
||||||
|
AdminFieldApp.fieldsCollection.save({
|
||||||
|
success: function(response) {
|
||||||
|
// reset collection with new one
|
||||||
|
if (response.success) {
|
||||||
|
AdminFieldApp.fieldsCollection.reset(response.fields);
|
||||||
|
}
|
||||||
|
|
||||||
|
new AlertView({
|
||||||
|
alert: response.success ? "success" : "error",
|
||||||
|
message: response.messages.join("<br />")
|
||||||
|
}).render();
|
||||||
|
},
|
||||||
|
error: function(model, xhr, options) {
|
||||||
|
new AlertView({
|
||||||
|
alert: "error", message: i18n.t("something_wrong")
|
||||||
|
}).render();
|
||||||
|
}
|
||||||
|
}).done(function() {
|
||||||
|
self._loadingState(false);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return this;
|
||||||
|
},
|
||||||
|
render: function () {
|
||||||
|
var template = _.template($("#save_template").html());
|
||||||
|
this.$el.html(template);
|
||||||
|
|
||||||
|
return this;
|
||||||
|
},
|
||||||
|
// check whether model has changed or not
|
||||||
|
_isModelDesync: function () {
|
||||||
|
return "undefined" !== typeof AdminFieldApp.fieldsCollection.find(function(model) {
|
||||||
|
return !_.isEmpty(model.previousAttributes());
|
||||||
|
});
|
||||||
|
},
|
||||||
|
// create a transparent overlay on top of the application
|
||||||
|
_overlay: function(showOrHide) {
|
||||||
|
if(showOrHide && !this.$overlay) {
|
||||||
|
this.$overlay = $("<div>").addClass("overlay");
|
||||||
|
AdminFieldApp.$bottom.append(this.$overlay);
|
||||||
|
} else if (!showOrHide && this.$overlay) {
|
||||||
|
this.$overlay.remove();
|
||||||
|
this.$overlay = null;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_disableSaveButton: function (active) {
|
||||||
|
$("button.save-all", this.$el).attr("disabled", active);
|
||||||
|
},
|
||||||
|
// put application on loading state (add overlay, add spinner, disable global save button)
|
||||||
|
_loadingState: function(active) {
|
||||||
|
if (active) {
|
||||||
|
$(".save-block", AdminFieldApp.$top).addClass("loading");
|
||||||
|
$(".block-alert", AdminFieldApp.$top).empty();
|
||||||
|
} else {
|
||||||
|
$(".save-block", AdminFieldApp.$top).removeClass("loading");
|
||||||
|
}
|
||||||
|
|
||||||
|
this._disableSaveButton(active);
|
||||||
|
this._overlay(active);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return SaveView;
|
||||||
|
});
|
@@ -1,10 +1,10 @@
|
|||||||
define([
|
define([
|
||||||
'underscore',
|
"underscore",
|
||||||
'backbone'
|
"backbone"
|
||||||
], function(_, Backbone) {
|
], function(_, Backbone) {
|
||||||
var DcFieldModel = Backbone.Model.extend({
|
var DcFieldModel = Backbone.Model.extend({
|
||||||
urlRoot: function () {
|
urlRoot: function () {
|
||||||
return '/admin/fields/dc-fields';
|
return "/admin/fields/dc-fields";
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
define([
|
define([
|
||||||
'underscore',
|
"underscore",
|
||||||
'backbone'
|
"backbone"
|
||||||
], function(_, Backbone) {
|
], function(_, Backbone) {
|
||||||
var FieldModel = Backbone.Model.extend({
|
var FieldModel = Backbone.Model.extend({
|
||||||
initialize : function(attributes, options) {
|
initialize : function(attributes, options) {
|
||||||
@@ -9,7 +9,7 @@ define([
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
urlRoot: function () {
|
urlRoot: function () {
|
||||||
return '/admin/fields/'+ this.get('sbas-id') +'/fields';
|
return "/admin/fields/"+ this.get("sbas-id") +"/fields";
|
||||||
},
|
},
|
||||||
defaults: {
|
defaults: {
|
||||||
"business": false,
|
"business": false,
|
||||||
|
@@ -1,10 +1,10 @@
|
|||||||
define([
|
define([
|
||||||
'underscore',
|
"underscore",
|
||||||
'backbone'
|
"backbone"
|
||||||
], function(_, Backbone) {
|
], function(_, Backbone) {
|
||||||
var VocabularyModel = Backbone.Model.extend({
|
var VocabularyModel = Backbone.Model.extend({
|
||||||
urlRoot: function () {
|
urlRoot: function () {
|
||||||
return '/admin/fields/vocabularies';
|
return "/admin/fields/vocabularies";
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
define(['chai'], function(shai) {
|
define(["chai"], function(shai) {
|
||||||
window.expect = shai.expect;
|
window.expect = shai.expect;
|
||||||
window.assert = shai.assert;
|
window.assert = shai.assert;
|
||||||
});
|
});
|
||||||
|
@@ -1,8 +1,8 @@
|
|||||||
require.config({
|
require.config({
|
||||||
baseUrl: "../../scripts",
|
baseUrl: "../../scripts",
|
||||||
paths: {
|
paths: {
|
||||||
specs: 'tests/specs',
|
specs: "tests/specs",
|
||||||
chai: '../assets/chai/chai'
|
chai: "../assets/chai/chai"
|
||||||
},
|
},
|
||||||
shim : {
|
shim : {
|
||||||
shai: {
|
shai: {
|
||||||
@@ -12,7 +12,7 @@ require.config({
|
|||||||
});
|
});
|
||||||
|
|
||||||
mocha.setup({
|
mocha.setup({
|
||||||
ui: 'bdd',
|
ui: "bdd",
|
||||||
ignoreLeaks: true
|
ignoreLeaks: true
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
define(function(require) {
|
define(function(require) {
|
||||||
it('should run', function () {
|
it("should run", function () {
|
||||||
expect(true).to.equal(true);
|
expect(true).to.equal(true);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@@ -1,69 +1,119 @@
|
|||||||
|
#admin-field-app .row-top {
|
||||||
|
min-height: 60px;
|
||||||
|
border-bottom: 1px solid #000;
|
||||||
|
}
|
||||||
|
|
||||||
|
#admin-field-app .row-bottom {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
#admin-field-app .right-block {
|
||||||
|
border-left: 1px dashed #000;
|
||||||
|
overflow: auto;
|
||||||
|
min-height: 200px;
|
||||||
|
}
|
||||||
|
|
||||||
#admin-field-app h4 {
|
#admin-field-app h4 {
|
||||||
padding: 10px 0;
|
padding: 10px 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#admin-field-app li {
|
#admin-field-app .left-block li {
|
||||||
background: #FFF;
|
background: #FFF;
|
||||||
border-top: 1px solid #ccc;
|
border-top: 1px solid #ccc;
|
||||||
border-left: 1px solid #ccc;
|
border-left: 1px solid #ccc;
|
||||||
border-right: 1px solid #ccc;
|
border-right: 1px solid #ccc;
|
||||||
|
height: 55px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#admin-field-app li table {
|
#admin-field-app .left-block li .trigger-click {
|
||||||
table-layout:fixed;
|
cursor: pointer;
|
||||||
width:100%;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#admin-field-app li .field-name {
|
#admin-field-app .left-block li.border-bottom{
|
||||||
|
border-bottom: 1px solid #ccc;
|
||||||
|
}
|
||||||
|
|
||||||
|
#admin-field-app .left-block li table {
|
||||||
|
table-layout: fixed;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
#admin-field-app .left-block li .field-name {
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
color: #666;
|
color: #666;
|
||||||
}
|
}
|
||||||
|
|
||||||
#admin-field-app li .handle {
|
#admin-field-app .left-block li .handle {
|
||||||
width: 10%;
|
width: 10%;
|
||||||
vertical-align:middle;
|
vertical-align: middle;
|
||||||
text-align:center;
|
text-align: center;
|
||||||
cursor: move;
|
cursor: move;
|
||||||
}
|
}
|
||||||
|
|
||||||
#admin-field-app li .trigger-click {
|
#admin-field-app .left-block li .trigger-click {
|
||||||
padding:10px;
|
padding: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#admin-field-app li .position {
|
#admin-field-app .left-block li .position {
|
||||||
width: 10%;
|
width: 10%;
|
||||||
vertical-align:bottom;
|
vertical-align: bottom;
|
||||||
text-align: center
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
#admin-field-app li .chip {
|
#admin-field-app .left-block li .chip {
|
||||||
width:10%;
|
width: 10%;
|
||||||
}
|
}
|
||||||
|
|
||||||
#admin-field-app li .handle, #admin-field-app li .position {
|
#admin-field-app .left-block li .handle, #admin-field-app li .position {
|
||||||
color: #ccc;
|
color: #ccc;
|
||||||
border-right: 1px solid #ccc;
|
border-right: 1px solid #ccc;
|
||||||
}
|
}
|
||||||
|
|
||||||
#admin-field-app li.last {
|
#admin-field-app .left-block li.last {
|
||||||
border-bottom: 1px solid #ccc;
|
border-bottom: 1px solid #ccc;
|
||||||
}
|
}
|
||||||
|
|
||||||
#admin-field-app li.selected {
|
#admin-field-app .left-block li.selected {
|
||||||
border-top-color: #0080FF;
|
border-top-color: #0080FF;
|
||||||
background: #FFF;
|
background: #FFF;
|
||||||
color: #000;
|
color: #000;
|
||||||
}
|
}
|
||||||
|
|
||||||
#admin-field-app li.selected + li {
|
#admin-field-app .left-block li.last.selected {
|
||||||
|
border-bottom-color: #0080FF;
|
||||||
|
}
|
||||||
|
|
||||||
|
#admin-field-app .left-block li.last.selected.error {
|
||||||
|
border-bottom-color: #9d261d;
|
||||||
|
}
|
||||||
|
|
||||||
|
#admin-field-app .left-block li.selected + li {
|
||||||
border-top-color: #0080FF;
|
border-top-color: #0080FF;
|
||||||
}
|
}
|
||||||
|
|
||||||
#admin-field-app li.selected .field-name {
|
#admin-field-app .left-block li.selected.error {
|
||||||
|
border-top-color: #9d261d;
|
||||||
|
}
|
||||||
|
|
||||||
|
#admin-field-app .left-block li.selected.error + li {
|
||||||
|
border-top-color: #9d261d;
|
||||||
|
}
|
||||||
|
|
||||||
|
#admin-field-app .left-block li.selected .field-name {
|
||||||
color: #0080FF;
|
color: #0080FF;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#admin-field-app .left-block li.error .field-name {
|
||||||
|
color: #9d261d;
|
||||||
|
}
|
||||||
|
|
||||||
|
#admin-field-app .item-list-placeholder {
|
||||||
|
border-top: 1px solid #ccc;
|
||||||
|
background-color: red;
|
||||||
|
height: 70px;
|
||||||
|
}
|
||||||
|
|
||||||
#admin-field-app .add-field-block .control-label {
|
#admin-field-app .add-field-block .control-label {
|
||||||
width: 80px;
|
width: 80px;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
@@ -85,13 +135,42 @@
|
|||||||
margin: 20px 0;
|
margin: 20px 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#admin-field-app #collection-fields {
|
#admin-field-app .list-block {
|
||||||
height:450px;
|
height: 450px;
|
||||||
|
min-height: 130px;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
#admin-field-app .edit-block {
|
#admin-field-app .edit-block {
|
||||||
padding: 5px 20px
|
padding: 5px 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#admin-field-app .edit-block table {
|
||||||
|
table-layout: fixed;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
#admin-field-app .edit-block table label {
|
||||||
|
margin: 0px;
|
||||||
|
width: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
#admin-field-app .edit-block table td:first-child {
|
||||||
|
width: 130px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#admin-field-app .edit-block td {
|
||||||
|
height: 25px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#admin-field-app .edit-block .dces-help-block {
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
#admin-field-app .info {
|
||||||
|
color: #aaa;
|
||||||
|
padding: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#admin-field-app .edit-block .edit-order {
|
#admin-field-app .edit-block .edit-order {
|
||||||
@@ -103,17 +182,38 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
#admin-field-app .edit-block input#name {
|
#admin-field-app .edit-block input#name {
|
||||||
font-size:28px;
|
font-size: 28px;
|
||||||
color:#0080FF;
|
color: #0080FF;
|
||||||
height:42px;
|
height: 42px;
|
||||||
line-height:42px;
|
line-height: 42px;
|
||||||
font-weight:bold
|
font-weight: bold
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#admin-field-app .overlay {
|
||||||
|
zoom: 1;
|
||||||
|
filter: alpha(opacity=50);
|
||||||
|
opacity: 0.5;
|
||||||
|
background: #fff;
|
||||||
|
position: absolute;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
z-index: 2000;
|
||||||
|
}
|
||||||
|
|
||||||
|
#admin-field-app .list-field-error li {
|
||||||
|
color: #9d261d;
|
||||||
|
}
|
||||||
|
|
||||||
|
#admin-field-app .save-block.loading {
|
||||||
|
background: url('/skins/icons/loaderFFF.gif') #fff no-repeat center right;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* jquery ui autocomplete style */
|
||||||
.ui-autocomplete-admin-field {
|
.ui-autocomplete-admin-field {
|
||||||
list-style-type: none;
|
list-style-type: none;
|
||||||
overflow-y: scroll;
|
overflow-y: auto;
|
||||||
height: 180px;
|
overflow-x: hidden;
|
||||||
|
max-height: 180px;
|
||||||
background: #FFF;
|
background: #FFF;
|
||||||
max-width: 300px;
|
max-width: 300px;
|
||||||
-webkit-box-shadow: 0 10px 6px -6px #777;
|
-webkit-box-shadow: 0 10px 6px -6px #777;
|
||||||
@@ -121,10 +221,25 @@
|
|||||||
box-shadow: 0 10px 6px -6px #777;
|
box-shadow: 0 10px 6px -6px #777;
|
||||||
}
|
}
|
||||||
|
|
||||||
.ui-autocomplete-admin-field li{
|
.ui-autocomplete-admin-field li {
|
||||||
padding: 3px;
|
padding: 5px;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ui-autocomplete-admin-field li:hover {
|
||||||
|
padding: 5px;
|
||||||
|
background: #ccc;
|
||||||
}
|
}
|
||||||
|
|
||||||
.ui-autocomplete-admin-field li a {
|
.ui-autocomplete-admin-field li a {
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.ui-autocomplete-admin-field li a:hover {
|
||||||
|
text-decoration: none;
|
||||||
|
background: none;
|
||||||
|
color: #000;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user