diff --git a/lib/Alchemy/Phrasea/Controller/Admin/Fields.php b/lib/Alchemy/Phrasea/Controller/Admin/Fields.php
index f8e287e835..fc62bd5901 100644
--- a/lib/Alchemy/Phrasea/Controller/Admin/Fields.php
+++ b/lib/Alchemy/Phrasea/Controller/Admin/Fields.php
@@ -17,6 +17,7 @@ use Silex\Application;
use Silex\ControllerProviderInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
+use PHPExiftool\Exception\TagUnknown;
class Fields implements ControllerProviderInterface
{
@@ -27,10 +28,18 @@ class Fields implements ControllerProviderInterface
$app['admin.fields.controller'] = $this;
$controllers->before(function(Request $request) use ($app) {
- $app['firewall']->requireAccessToModule('admin')
+ $app['firewall']
+ ->requireAccessToModule('admin')
->requireRight('bas_modify_struct');
});
+ $controllers->get('/language.json', 'admin.fields.controller:getLanguage')
+ ->bind('admin_fields_language');
+
+ $controllers->get('/{sbas_id}', 'admin.fields.controller:displayApp')
+ ->assert('sbas_id', '\d+')
+ ->bind('admin_fields');
+
$controllers->get('/{sbas_id}/fields', 'admin.fields.controller:listFields')
->assert('sbas_id', '\d+')
->bind('admin_fields_list');
@@ -75,9 +84,26 @@ class Fields implements ControllerProviderInterface
return $controllers;
}
+ public function getLanguage(Application $app) {
+ return $app->json(array(
+ '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'),
+ 'are_you_sure_delete' => _('Do you really want to delete the field %s ?'),
+ 'validation_blank' => _('Field can not be blank'),
+ ));
+ }
+
+ public function displayApp(Application $app, $sbas_id) {
+ return $app['twig']->render('/admin/fields/index.html.twig', array(
+ 'sbas_id' => $sbas_id,
+ 'js' => ''
+ ));
+ }
+
public function listDcFields(Application $app, Request $request)
{
- $data = $app['serializer']->serialize(\databox::get_available_dcfields(), 'json');
+ $data = $app['serializer']->serialize(array_values(\databox::get_available_dcfields()), 'json');
return new Response($data, 200, array('content-type' => 'application/json'));
}
@@ -120,7 +146,7 @@ class Fields implements ControllerProviderInterface
continue;
}
- $res[] = array(
+ $res[$tagname] = array(
'id' => $namespace . '/' . $tagname,
'label' => $datas['namespace'] . ' / ' . $datas['tagname'],
'value' => $datas['namespace'] . ':' . $datas['tagname'],
@@ -129,6 +155,8 @@ class Fields implements ControllerProviderInterface
}
}
+ ksort($res);
+
return $app->json($res);
}
@@ -141,21 +169,40 @@ class Fields implements ControllerProviderInterface
}
public function createField(Application $app, Request $request, $sbas_id) {
+ $json = array(
+ 'success' => false,
+ 'message' => _('Something wrong happened, please try again or contact an admin if problem persists'),
+ 'field' => array()
+ );
+ $headers = array();
$databox = $app['phraseanet.appbox']->get_databox((int) $sbas_id);
-
$data = $this->getFieldJsonFromRequest($app, $request);
- $field = \databox_field::create($app, $databox, $data['name'], $data['multi']);
- $this->updateFieldWithData($app, $field, $data);
- $field->save();
+ try {
+ $field = \databox_field::create($app, $databox, $data['name'], $data['multi']);
- return $app->json($field->toArray(), 201, array(
- 'Location' => $app->path('admin_fields_show_field', array(
- 'sbas_id' => $sbas_id,
- 'id' => $field->get_id(),
- ))
- ));
+ $this->updateFieldWithData($app, $field, $data);
+ $field->save();
+
+ $json['success'] = true;
+ $headers['location'] = $app->path('admin_fields_show_field', array(
+ 'sbas_id' => $sbas_id,
+ 'id' => $field->get_id(),
+ ));
+ $json['message'] = _(sprintf('Tag name %s has been created successfully', $data['name']));
+ $json['field'] = $field->toArray();
+ } catch (\PDOException $e) {
+ if ($e->errorInfo[1] == 1062) {
+ $json['message'] = _(sprintf('Field name %s already exists', $data['name']));
+ }
+ } catch (\Exception $e) {
+ if ($e instanceof \Exception_Databox_metadataDescriptionNotFound || $e->getPrevious() instanceof TagUnknown) {
+ $json['message'] = _(sprintf('Provided tag %s is unknown', $data['tag']));
+ }
+ }
+
+ return $app->json($json, 201, $headers);
}
public function listFields(Application $app, $sbas_id) {
diff --git a/templates/web/admin/fields/index.html.twig b/templates/web/admin/fields/index.html.twig
new file mode 100644
index 0000000000..f7bbb11eae
--- /dev/null
+++ b/templates/web/admin/fields/index.html.twig
@@ -0,0 +1,27 @@
+{# empty Twig template #}
+
+
+{% include 'admin/fields/templates.html.twig' %}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/templates/web/admin/fields/templates.html.twig b/templates/web/admin/fields/templates.html.twig
new file mode 100644
index 0000000000..fe6a31cd28
--- /dev/null
+++ b/templates/web/admin/fields/templates.html.twig
@@ -0,0 +1,201 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/templates/web/admin/index.html.twig b/templates/web/admin/index.html.twig
index ad05ea0b0f..ca0ecb342e 100644
--- a/templates/web/admin/index.html.twig
+++ b/templates/web/admin/index.html.twig
@@ -8,7 +8,7 @@
{% endblock %}
{% block stylesheet %}
-
+
{% endblock %}
diff --git a/templates/web/admin/tree.html.twig b/templates/web/admin/tree.html.twig
index 14bee0098d..59a05dae79 100644
--- a/templates/web/admin/tree.html.twig
+++ b/templates/web/admin/tree.html.twig
@@ -111,7 +111,7 @@
-
+
{% trans 'CHAMPS' %}
diff --git a/www/scripts/apps/admin/fields/app.js b/www/scripts/apps/admin/fields/app.js
index 887268d48a..1d911ff724 100644
--- a/www/scripts/apps/admin/fields/app.js
+++ b/www/scripts/apps/admin/fields/app.js
@@ -2,10 +2,48 @@ define([
'jquery',
'underscore',
'backbone',
- 'apps/admin/fields/router'
-], function($, _, Backbone, Router) {
+ 'i18n',
+ 'apps/admin/fields/collections/fields',
+ 'apps/admin/fields/collections/vocabularies',
+ 'apps/admin/fields/collections/dcFields',
+ 'apps/admin/fields/views/list'
+], function($, _, Backbone, i18n, FieldsCollection, VocabulariesCollection, DcFieldsCollection, FieldListView) {
var initialize = function() {
- Router.initialize();
+ window.AdminFieldApp = {};
+
+ window.AdminFieldApp.sbas_id = $('input[name=current_sbas_id]').val();
+
+ var fieldsCollection = new FieldsCollection(null, {
+ sbas_id : window.AdminFieldApp.sbas_id
+ });
+
+ var vocabulariesCollection = new VocabulariesCollection();
+ var dcFieldsCollection = new DcFieldsCollection();
+
+ // load strings synchronously
+ i18n.init({ resGetPath: '/admin/fields/language.json', getAsync: false });
+
+ var requests = [
+ fieldsCollection.fetch(),
+ vocabulariesCollection.fetch(),
+ dcFieldsCollection.fetch()
+ ];
+
+ $.when.apply($, requests).done(
+ function() {
+ window.AdminFieldApp.vocabularyCollection = vocabulariesCollection;
+ window.AdminFieldApp.dcFieldsCollection = dcFieldsCollection;
+
+ window.AdminFieldApp.fieldListView = new FieldListView({
+ collection: fieldsCollection,
+ el: $('.left-block')[0]
+ });
+
+ window.AdminFieldApp.fieldListView.render();
+ // click on first item list
+ _.first(window.AdminFieldApp.fieldListView.itemViews).clickAction().animate();
+ }
+ );
};
return {
diff --git a/www/scripts/apps/admin/fields/collections/dcFields.js b/www/scripts/apps/admin/fields/collections/dcFields.js
new file mode 100644
index 0000000000..e4837e013b
--- /dev/null
+++ b/www/scripts/apps/admin/fields/collections/dcFields.js
@@ -0,0 +1,17 @@
+define([
+ 'underscore',
+ 'backbone',
+ 'models/dcField'
+], function(_, Backbone, DcFieldModel) {
+ var DcFieldCollection = Backbone.Collection.extend({
+ model: DcFieldModel,
+ url: function() {
+ return '/admin/fields/dc-fields';
+ },
+ comparator: function(item) {
+ return item.get("label");
+ }
+ });
+
+ return DcFieldCollection;
+});
diff --git a/www/scripts/apps/admin/fields/collections/fields.js b/www/scripts/apps/admin/fields/collections/fields.js
index 21d2dfe9ab..4326571c0f 100644
--- a/www/scripts/apps/admin/fields/collections/fields.js
+++ b/www/scripts/apps/admin/fields/collections/fields.js
@@ -1,11 +1,58 @@
define([
'underscore',
'backbone',
- 'models/admin/field'
+ 'models/field'
], function(_, Backbone, FieldModel) {
var FieldCollection = Backbone.Collection.extend({
+ initialize: function(models, options) {
+ if (!"sbas_id" in options) {
+ throw "You must specify a sbasId option when creating a new field model"
+ }
+ this.sbasId = options.sbas_id;
+ },
model: FieldModel,
- url: '/admin/fields/1/fields'
+ url: function() {
+ return '/admin/fields/' + this.sbasId + '/fields';
+ },
+ search: function(letters) {
+ if (letters === "")
+ return this;
+
+ var pattern = new RegExp(letters, "gi");
+
+ return _(this.filter(function(data) {
+ return pattern.test(data.get("name"));
+ }));
+ },
+ comparator: function(item) {
+ return item.get("sorter");
+ },
+ nextIndex: function(model) {
+ var index = this.indexOf(model);
+
+ if (index < 0) {
+ throw "Model not found"
+ }
+
+ if ((index + 1) === this.length) {
+ return null;
+ }
+
+ return index + 1;
+ },
+ previousIndex: function(model) {
+ var index = this.indexOf(model);
+
+ if (index < 0) {
+ throw "Model not found"
+ }
+
+ if (index === 0) {
+ return null;
+ }
+
+ return index - 1;
+ }
});
return FieldCollection;
diff --git a/www/scripts/apps/admin/fields/collections/vocabularies.js b/www/scripts/apps/admin/fields/collections/vocabularies.js
new file mode 100644
index 0000000000..2b86d4109d
--- /dev/null
+++ b/www/scripts/apps/admin/fields/collections/vocabularies.js
@@ -0,0 +1,17 @@
+define([
+ 'underscore',
+ 'backbone',
+ 'models/vocabulary'
+], function(_, Backbone, VocabularyModel) {
+ var VocabularyCollection = Backbone.Collection.extend({
+ model: VocabularyModel,
+ url: function() {
+ return '/admin/fields/vocabularies';
+ },
+ comparator: function(item) {
+ return item.get("name");
+ }
+ });
+
+ return VocabularyCollection;
+});
diff --git a/www/scripts/apps/admin/fields/main.js b/www/scripts/apps/admin/fields/main.js
index 924276db79..748e149adb 100644
--- a/www/scripts/apps/admin/fields/main.js
+++ b/www/scripts/apps/admin/fields/main.js
@@ -1,15 +1,21 @@
require.config({
baseUrl: "/scripts",
paths: {
- jquery: '../assets/jquery/jquery',
+ 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',
underscore: '../assets/underscore-amd/underscore',
backbone: '../assets/backbone-amd/backbone',
twig: '../assets/twig/twig',
- i18n: '../assets/i18n/i18next.amd'
+ i18n: '../assets/i18n/i18next.amd',
+ bootstrap: ['//netdna.bootstrapcdn.com/twitter-bootstrap/2.2.1/js/bootstrap.min']
},
shim: {
twig: {
exports: 'Twig'
+ },
+ bootstrap : ['jquery'],
+ jqueryui: {
+ deps: [ 'jquery' ]
}
}
});
diff --git a/www/scripts/apps/admin/fields/router.js b/www/scripts/apps/admin/fields/router.js
deleted file mode 100644
index ce49bf1060..0000000000
--- a/www/scripts/apps/admin/fields/router.js
+++ /dev/null
@@ -1,59 +0,0 @@
-define([
- 'jquery',
- 'underscore',
- 'backbone',
- 'models/admin/field',
- 'apps/admin/fields/views/edit',
- 'apps/admin/fields/views/list',
- 'apps/admin/fields/collections/fields'
-], function($, _, Backbone, FieldModel, FieldEditView, FieldListView, FieldsCollection) {
- var AppRouter = Backbone.Router.extend({
- routes: {
- 'field/:id': "getField",
- 'fields': 'showFields',
- '*actions': 'defaultAction'
- }
- });
-
- var initialize = function() {
- var app_router = new AppRouter();
-
- app_router.on('route:getField', function (id) {
- var field = new FieldModel({id: id});
-
- field.fetch().done(function() {
- var fieldEditView = new FieldEditView({
- el: $('.right-block')[0],
- model: field
- });
-
- fieldEditView.render();
- });
- });
-
- app_router.on('route:showFields', function() {
- var fieldsCollection = new FieldsCollection();
- fieldsCollection.fetch().done(function() {
- var fieldListView = new FieldListView({
- collection: fieldsCollection,
- el: $('ul#collection-fields')[0]
- });
-
- fieldListView.render();
- });
- });
-
- app_router.on('route:defaultAction', function(actions) {
- console.log('No route:', actions);
- });
-
- Backbone.history.start();
-
- // Show fields on start up
- app_router.navigate('fields', { trigger: true });
- };
-
- return {
- initialize: initialize
- };
-});
diff --git a/www/scripts/apps/admin/fields/views/add.js b/www/scripts/apps/admin/fields/views/add.js
new file mode 100644
index 0000000000..973d2cb754
--- /dev/null
+++ b/www/scripts/apps/admin/fields/views/add.js
@@ -0,0 +1,51 @@
+define([
+ 'underscore',
+ 'backbone',
+ 'i18n'
+], function( _, Backbone, i18n, bootstrap) {
+ var AddView = Backbone.View.extend({
+ tagName: "div",
+ className: "add-field-block",
+ style: "display:none;",
+ events: {
+ "click .btn-submit-field": "createAction"
+ },
+ initialize: function() {},
+ render: function() {
+ var template = _.template($("#alert_template").html(), {
+ msg: this.msg
+ });
+
+ this.$el.after(template);
+
+ return this;
+ },
+ createAction: function(event) {
+ var self = this;
+
+ var field = new FieldModel({
+ "name": "AA" + new Date().getUTCMilliseconds(),
+ "tag": "IPTC:ObjectName"
+ }, {
+ sbas_id: AdminFieldApp.sbas_id
+ });
+
+ field.save(null, {
+ success: function(field) {
+ self.collection.add(field);
+ _.last(self.itemViews).clickAction().animate();
+ new AlertView({alert: 'success', message: 'A new field has been created'}).render();
+ },
+ error: function() {
+ new AlertView({alert: 'error', message: 'Something wrong happened'}).render();
+ }
+ });
+ },
+ destroy: function() {
+ this.remove();
+ }
+ });
+
+ return AddView;
+});
+
diff --git a/www/scripts/apps/admin/fields/views/alert.js b/www/scripts/apps/admin/fields/views/alert.js
new file mode 100644
index 0000000000..5b93fdbf85
--- /dev/null
+++ b/www/scripts/apps/admin/fields/views/alert.js
@@ -0,0 +1,36 @@
+define([
+ 'underscore',
+ 'backbone',
+ 'i18n',
+ 'bootstrap'
+], function(_, Backbone, i18n, bootstrap) {
+ var AlertView = Backbone.View.extend({
+ tagName: "div",
+ className: "alert",
+ initialize: function(options) {
+ var self = this;
+
+ if (options) {
+ this.alert = options.alert || "info";
+ this.message = options.message || "";
+ }
+ // remove view when alert is closed
+ this.$el.bind('closed', function () {
+ self.remove();
+ });
+ },
+ render: function() {
+ var template = _.template($("#alert_template").html(), {
+ msg: this.message
+ });
+
+ this.$el.addClass("alert-" + this.alert).html(template).alert();
+
+ $('.block-alert').empty().append(this.$el);
+
+ return this;
+ }
+ });
+
+ return AlertView;
+});
\ No newline at end of file
diff --git a/www/scripts/apps/admin/fields/views/dcField.js b/www/scripts/apps/admin/fields/views/dcField.js
new file mode 100644
index 0000000000..2ad1310099
--- /dev/null
+++ b/www/scripts/apps/admin/fields/views/dcField.js
@@ -0,0 +1,29 @@
+define([
+ 'underscore',
+ 'backbone',
+ 'i18n'
+], function( _, Backbone, i18n, bootstrap) {
+ var DcFieldsView = Backbone.View.extend({
+ tagName: "div",
+ className: "input-append",
+ events: {
+ "change select": "onChange"
+ },
+ render: function() {
+ var template = _.template($("#dc_fields_template").html(), {
+ dces_elements: this.collection.toJSON()
+ });
+
+ this.$el.html(template);
+
+ return this;
+ },
+ onChange: function(e) {
+ var index = $(e.target)[0].selectedIndex;
+ this.$el.closest('table').find('.dces-help-block').empty().append(this.collection.at(index).get('definition'));
+ }
+ });
+
+ return DcFieldsView;
+});
+
diff --git a/www/scripts/apps/admin/fields/views/edit.js b/www/scripts/apps/admin/fields/views/edit.js
index fb2816dc8b..f06b03c963 100644
--- a/www/scripts/apps/admin/fields/views/edit.js
+++ b/www/scripts/apps/admin/fields/views/edit.js
@@ -1,19 +1,133 @@
define([
- 'jquery',
'underscore',
'backbone',
- 'i18n'
-], function($, _, Backbone, i18n) {
+ 'i18n',
+ 'apps/admin/fields/views/alert',
+ 'apps/admin/fields/views/modal',
+ 'apps/admin/fields/views/dcField',
+], function(_, Backbone, i18n, AlertView, ModalView, DcFieldView) {
var FieldEditView = Backbone.View.extend({
tagName: "div",
className: "field-edit",
+ initialize: function() {
+ this.model.on('change', this.render, this);
+ this.model.on('change:name', this.onFieldChange, this);
+ this.model.on('change:tag', this.onFieldChange, this);
+
+ this.dcFieldsSubView = new DcFieldView({
+ collection: window.AdminFieldApp.dcFieldsCollection
+ });
+ },
render: function() {
- this.el.innerHTML = '';
- this.el.innerHTML = Twig.render(fieldsEdit, {
- field: this.model.attributes
+ var template = _.template($("#edit_template").html(), {
+ field: this.model.toJSON(),
+ vocabularyTypes: window.AdminFieldApp.vocabularyCollection.toJSON()
+ });
+
+ this.$el.empty().html(template);
+
+ this.assign({
+ '.dc-fields-subview' : this.dcFieldsSubView
+ });
+
+ $("#tag", this.$el).autocomplete({
+ source: function(request, response) {
+ $.ajax({
+ url: "/admin/fields/tags/search",
+ dataType: "json",
+ data: {
+ term: request.term
+ },
+ success: function(data) {
+ response($.map(data, function(item) {
+ return {
+ label: item.label,
+ value: item.value
+ };
+ }));
+ }
+ });
+ }
+ }).val(this.model.get('tag')).autocomplete("widget").addClass("ui-autocomplete-admin-field");
+
+ return this;
+ },
+ events: {
+ "click .delete-field": "deleteAction",
+ "focusout input[type=text]": "fieldChanged",
+ "change input[type=checkbox]": "fieldChanged",
+ "change select": "selectionChanged"
+ },
+ selectionChanged: function(e) {
+ var field = $(e.currentTarget);
+ var value = $("option:selected", field).val();
+ var data = {};
+ data[field.attr('id')] = value;
+ this.model.set(data);
+ },
+ fieldChanged: function(e) {
+ console.log('field change');
+ var field = $(e.currentTarget);
+ var data = {};
+ data[field.attr('id')] = field.is(":checkbox") ? field.is(":checked") : field.val();
+ this.model.set(data);
+ },
+ deleteAction: function() {
+ var self = this;
+ var modalView = new ModalView({
+ model: this.model,
+ 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) {
+ itemView = AdminFieldApp.fieldListView.itemViews[previousIndex];
+ } else if (nextIndex) {
+ itemView = AdminFieldApp.fieldListView.itemViews[nextIndex];
+ }
+
+ modalView.render();
+ modalView.on('modal:confirm', function() {
+ self.model.destroy({
+ success: function(model, response) {
+ AdminFieldApp.fieldListView.collection.remove(self.model);
+
+ if (itemView) {
+ itemView.clickAction().animate();
+ }
+
+ new AlertView({alert: 'info', message: i18n.t("deleted_success", { postProcess: "sprintf", sprintf: [model.get('name')] })}).render();
+ },
+ error: function(model, xhr) {
+ new AlertView({alert: 'error', message: i18n.t("something_wrong")}).render();
+ }
+ });
});
return this;
+ },
+ onFieldChange: function() {
+ console.log('on field changed');
+ AdminFieldApp.fieldListView.collection.remove(this.model, {silent: true});
+ AdminFieldApp.fieldListView.collection.add(this.model);
+ this.render();
+ },
+ assign: function(selector, view) {
+ var selectors;
+ if (_.isObject(selector)) {
+ selectors = selector;
+ }
+ else {
+ selectors = {};
+ selectors[selector] = view;
+ }
+ if (!selectors)
+ return;
+ _.each(selectors, function(view, selector) {
+ view.setElement(this.$(selector)).render();
+ }, this);
}
});
diff --git a/www/scripts/apps/admin/fields/views/list.js b/www/scripts/apps/admin/fields/views/list.js
index 37c64af81b..cc2234e079 100644
--- a/www/scripts/apps/admin/fields/views/list.js
+++ b/www/scripts/apps/admin/fields/views/list.js
@@ -1,30 +1,145 @@
define([
- 'jquery',
+ 'jqueryui',
'underscore',
'backbone',
- 'apps/admin/fields/views/listRow'
-], function($, _, Backbone, FieldListRowView) {
+ 'i18n',
+ 'apps/admin/fields/views/listRow',
+ 'apps/admin/fields/views/alert',
+ 'models/field'
+], function(jqueryui, _, Backbone, i18n, FieldListRowView, AlertView, FieldModel) {
var FieldListView = Backbone.View.extend({
+ events: {
+ "keyup #live_search": "searchAction",
+ "click .btn-submit-field": "createAction",
+ "click .btn-add-field": "toggleCreateFormAction",
+ "click .btn-cancel-field": "toggleCreateFormAction",
+ "update-sort": "onUpdateSort"
+ },
initialize: function() {
- var that = this;
- this._fieldViews = [];
+ // Store all single rendered views
+ this.itemViews = [];
- this.collection.each(function(field) {
- that._fieldViews.push(new FieldListRowView({
- model: field
- }));
- });
+ _.bindAll(this, "render");
+ // rerender whenever there is a change on the collection
+ this.collection.bind("reset", this.render, this);
+ this.collection.bind("add", this.render, this);
+ this.collection.bind("remove", this.render, this);
},
render: function() {
- var that = this;
- $(this.el).empty();
+ var template = _.template($("#item_list_view_template").html(), {});
- // Render each sub-view and append it to the parent view's element.
- _(this._fieldViews).each(function(singleView) {
- $(that.el).append(singleView.render().el);
- });
+ this.$el.empty().html(template);
+
+ this.$listEl = $("ul#collection-fields", this.$el);
+
+ this._renderList(this.collection);
+
+ $("#new-source", this.$el).autocomplete({
+ source: function(request, response) {
+ $.ajax({
+ url: "/admin/fields/tags/search",
+ dataType: "json",
+ data: {
+ term: request.term
+ },
+ success: function(data) {
+ response($.map(data, function(item) {
+ return {
+ label: item.label,
+ value: item.value
+ };
+ }));
+ }
+ });
+ }
+ }).autocomplete("widget").addClass("ui-autocomplete-admin-field");
return this;
+ },
+ _renderList: function(fields) {
+ var that = this;
+
+ this.$listEl.empty();
+ this.itemViews = [];
+
+ fields.each(function(field) {
+ var singleView = new FieldListRowView({
+ model: field,
+ id: 'field-' + field.get('id')
+ });
+ that.$listEl.append(singleView.render().el);
+ that.itemViews.push(singleView);
+ });
+
+ this.$listEl.sortable({
+ handle: ".handle",
+ start: function () {
+ console.log('start', AdminFieldApp.fieldEditView.model.get('id'));
+ },
+ stop: function(event, ui) {
+ ui.item.trigger('drop', ui.item.index());
+ }
+ });
+
+ this.$listEl.disableSelection();
+
+ this.$listEl.find('li:last').addClass('last');
+
+ return this;
+ },
+ searchAction: function(event) {
+ this._renderList(this.collection.search($("#live_search", this.$el).val()));
+ },
+ createAction: function(event) {
+ var self = this;
+
+ var fieldName = $("#new-name", this.$el);
+
+ if ('' == fieldName.val()) {
+ fieldName.closest('.control-group').addClass('error').find('.help-block').empty().append(i18n.t('validation_blank'));
+ return;
+ }
+
+ var field = new FieldModel({
+ "sbas-id": AdminFieldApp.sbas_id,
+ "name": fieldName.val(),
+ "tag": $("#new-source", this.$el).val(),
+ "multi": $("#new-multivalued", this.$el).is(':checked')
+ });
+
+ field.save(null, {
+ success: function(field, response, options) {
+ if (response.success) {
+ self.collection.add(field);
+ _.last(self.itemViews).clickAction().animate();
+ new AlertView({alert: 'success', message: response.message }).render();
+ } else {
+ new AlertView({alert: 'warning', message: response.message}).render();
+ }
+ },
+ error: function(model, xhr, options) {
+ new AlertView({alert: 'error', message: i18n.t("something_wrong")}).render();
+ self.toggleCreateFormAction();
+ }
+ });
+ },
+ toggleCreateFormAction: function(event) {
+ $('.add-field-block', this.$el).toggle();
+ },
+ onUpdateSort: function(event, model, position) {
+ this.collection.remove(model, {silent: true});
+
+ this.collection.each(function(model, index) {
+ var ordinal = index;
+ if (index >= position) ordinal += 1;
+ model.set('sorter', ordinal);
+ });
+
+ model.set('sorter', position);
+ this.collection.add(model, {at: position});
+
+ // update edit view
+ AdminFieldApp.fieldEditView.model = this.collection.find(function(el) { return el.get('id') === AdminFieldApp.fieldEditView.model.get('id') });
}
});
diff --git a/www/scripts/apps/admin/fields/views/listRow.js b/www/scripts/apps/admin/fields/views/listRow.js
index 06828d76e1..3195a2e343 100644
--- a/www/scripts/apps/admin/fields/views/listRow.js
+++ b/www/scripts/apps/admin/fields/views/listRow.js
@@ -1,19 +1,67 @@
define([
- 'jquery',
'underscore',
- 'backbone'
-], function($, _, Backbone) {
+ 'backbone',
+ 'apps/admin/fields/views/edit',
+ 'apps/admin/fields/views/alert'
+], function(_, Backbone, FieldEditView, AlertView) {
var FieldListRowView = Backbone.View.extend({
tagName: "li",
className: "field-row",
+ initialize: function() {
+ // destroy view is model is deleted
+ this.model.on('destroy', this.remove, this);
+ },
+ events : {
+ "click .trigger-click": "clickAction",
+ "drop" : "dropAction"
+ },
+ clickAction: function (e) {
+ this.select();
+ // first click create view else update model's view
+ if (typeof AdminFieldApp.fieldEditView === 'undefined') {
+ AdminFieldApp.fieldEditView = new FieldEditView({
+ el: $('.right-block')[0],
+ model: this.model
+ });
+ } else {
+ AdminFieldApp.fieldEditView.model = this.model;
+ }
+
+ AdminFieldApp.fieldEditView.render();
+
+ return this;
+ },
+ dropAction: function(event, index) {
+ this.$el.trigger('update-sort', [this.model, index]);
+ },
render: function() {
- this.el.innerHTML = Twig.render(fieldsRow, {
+ var template = _.template($("#list_row_template").html(), {
id: this.model.get('id'),
+ position: this.model.get('sorter'),
name: this.model.get('name'),
tag: this.model.get('tag')
});
+ this.$el.empty().html(template);
+
+ if (AdminFieldApp.fieldEditView && AdminFieldApp.fieldEditView.model.get('id') === this.model.get('id')) {
+ this.select();
+ }
return this;
+ },
+ // set selected class
+ select: function () {
+ $("li", this.$el.closest('ul')).removeClass('selected');
+ this.$el.addClass('selected');
+
+ return this;
+ },
+ animate: function () {
+ var offset = this.$el.offset();
+
+ this.$el.closest('div').animate({
+ scrollTop: offset.top - 20
+ });
}
});
diff --git a/www/scripts/apps/admin/fields/views/modal.js b/www/scripts/apps/admin/fields/views/modal.js
new file mode 100644
index 0000000000..418937676d
--- /dev/null
+++ b/www/scripts/apps/admin/fields/views/modal.js
@@ -0,0 +1,44 @@
+define([
+ 'underscore',
+ 'backbone',
+ 'i18n',
+ 'bootstrap'
+], function(_, Backbone, i18n, bootstrap) {
+ var ModalView = Backbone.View.extend({
+ tagName: "div",
+ className: "modal",
+ events: {
+ 'click .confirm': 'confirmAction'
+ },
+ initialize: function (options) {
+ var self = this;
+ // remove view when modal is closed
+ this.$el.on('hidden', function() {
+ self.remove();
+ });
+
+ if (options) {
+ this.message = options.message;
+ }
+ },
+ render: function() {
+ var template = _.template($("#modal_delete_confirm_template").html(), {
+ msg: this.message || ''
+ });
+
+ this.$el.html(template).modal();
+
+ return this;
+ },
+ confirmAction: function () {
+ this.trigger('modal:confirm');
+ this.$el.modal('hide');
+ this.remove();
+
+ return this;
+ }
+ });
+
+ return ModalView;
+});
+
diff --git a/www/scripts/models/admin/field.js b/www/scripts/models/admin/field.js
deleted file mode 100644
index 966d36369c..0000000000
--- a/www/scripts/models/admin/field.js
+++ /dev/null
@@ -1,11 +0,0 @@
-define([
- 'underscore',
- 'backbone'
-], function(_, Backbone) {
- var FieldModel = Backbone.Model.extend({
- urlRoot: '/admin/fields/1/fields'
- });
-
- // Return the model for the module
- return FieldModel;
-});
diff --git a/www/scripts/models/dcField.js b/www/scripts/models/dcField.js
new file mode 100644
index 0000000000..fa9ab138ba
--- /dev/null
+++ b/www/scripts/models/dcField.js
@@ -0,0 +1,13 @@
+define([
+ 'underscore',
+ 'backbone'
+], function(_, Backbone) {
+ var DcFieldModel = Backbone.Model.extend({
+ urlRoot: function () {
+ return '/admin/fields/dc-fields';
+ }
+ });
+
+ // Return the model for the module
+ return DcFieldModel;
+});
diff --git a/www/scripts/models/field.js b/www/scripts/models/field.js
new file mode 100644
index 0000000000..2881228e98
--- /dev/null
+++ b/www/scripts/models/field.js
@@ -0,0 +1,33 @@
+define([
+ 'underscore',
+ 'backbone'
+], function(_, Backbone) {
+ var FieldModel = Backbone.Model.extend({
+ initialize : function(attributes, options) {
+ if (attributes && ! "sbas-id" in attributes) {
+ throw "You must set a sbas id";
+ }
+ },
+ urlRoot: function () {
+ return '/admin/fields/'+ this.get('sbas-id') +'/fields';
+ },
+ defaults: {
+ "business": false,
+ "type": "string",
+ "thumbtitle": "0",
+ "tbranch": "",
+ "separator": "",
+ "required": false,
+ "report": true,
+ "readonly": false,
+ "multi": false,
+ "indexable": true,
+ "dces-element": null,
+ "vocabulary-type": null,
+ "vocabulary-restricted": false
+ }
+ });
+
+ // Return the model for the module
+ return FieldModel;
+});
diff --git a/www/scripts/models/vocabulary.js b/www/scripts/models/vocabulary.js
new file mode 100644
index 0000000000..7dcc9439ce
--- /dev/null
+++ b/www/scripts/models/vocabulary.js
@@ -0,0 +1,13 @@
+define([
+ 'underscore',
+ 'backbone'
+], function(_, Backbone) {
+ var VocabularyModel = Backbone.Model.extend({
+ urlRoot: function () {
+ return '/admin/fields/vocabularies';
+ }
+ });
+
+ // Return the model for the module
+ return VocabularyModel;
+});
diff --git a/www/skins/admin/css/fields.css b/www/skins/admin/css/fields.css
new file mode 100644
index 0000000000..2b138563eb
--- /dev/null
+++ b/www/skins/admin/css/fields.css
@@ -0,0 +1,73 @@
+#admin-field-app li {
+ background: #FFF;
+ border-top: 1px solid #ccc;
+ border-left: 1px solid #ccc;
+ border-right: 1px solid #ccc;
+}
+
+#admin-field-app li .field-name {
+ font-weight: bold;
+ font-size: 16px;
+ color: #666;
+}
+
+#admin-field-app li .handle, #admin-field-app li .position {
+ color: #ccc;
+ border-right: 1px solid #ccc;
+}
+
+#admin-field-app li.last {
+ border-bottom: 1px solid #ccc;
+}
+
+#admin-field-app li.selected {
+ border-top-color: #0080FF;
+ background: #FFF;
+ color: #000;
+}
+
+#admin-field-app li.selected + li {
+ border-top-color: #0080FF;
+}
+
+#admin-field-app li.selected .field-name {
+ color: #0080FF;
+}
+
+#admin-field-app .add-field-block .control-label {
+ width: 80px;
+ text-align: left;
+}
+
+#admin-field-app .add-field-block .controls {
+ margin-left: 100px;
+}
+
+#admin-field-app .edit-form label {
+ width: 160px;
+}
+
+#admin-field-app .edit-form select {
+ min-width: 220px;
+}
+
+.ui-autocomplete-admin-field {
+ list-style-type: none;
+ overflow-y: scroll;
+ height: 180px;
+ background: #FFF;
+ max-width: 300px;
+ -webkit-box-shadow: 0 10px 6px -6px #777;
+ -moz-box-shadow: 0 10px 6px -6px #777;
+ box-shadow: 0 10px 6px -6px #777;
+}
+
+.ui-autocomplete-admin-field li{
+ padding: 3px;
+}
+
+.ui-autocomplete-admin-field li a {
+ text-decoration: none;
+}
+
+