mirror of https://github.com/lidarr/Lidarr
Moved to regions for quality profile editor
This commit is contained in:
parent
75decad601
commit
191db1c541
|
@ -137,6 +137,7 @@
|
||||||
<Compile Include="Missing\MissingModule.cs" />
|
<Compile Include="Missing\MissingModule.cs" />
|
||||||
<Compile Include="Config\NamingSampleResource.cs" />
|
<Compile Include="Config\NamingSampleResource.cs" />
|
||||||
<Compile Include="NzbDroneRestModuleWithSignalR.cs" />
|
<Compile Include="NzbDroneRestModuleWithSignalR.cs" />
|
||||||
|
<Compile Include="Qualities\QualityProfileValidation.cs" />
|
||||||
<Compile Include="Queue\QueueModule.cs" />
|
<Compile Include="Queue\QueueModule.cs" />
|
||||||
<Compile Include="Queue\QueueResource.cs" />
|
<Compile Include="Queue\QueueResource.cs" />
|
||||||
<Compile Include="ResourceChangeMessage.cs" />
|
<Compile Include="ResourceChangeMessage.cs" />
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using NzbDrone.Core.Qualities;
|
using NzbDrone.Core.Qualities;
|
||||||
using NzbDrone.Api.Mapping;
|
using NzbDrone.Api.Mapping;
|
||||||
using System.Linq;
|
|
||||||
using FluentValidation;
|
using FluentValidation;
|
||||||
|
|
||||||
namespace NzbDrone.Api.Qualities
|
namespace NzbDrone.Api.Qualities
|
||||||
|
@ -9,27 +8,19 @@ namespace NzbDrone.Api.Qualities
|
||||||
public class QualityProfileModule : NzbDroneRestModule<QualityProfileResource>
|
public class QualityProfileModule : NzbDroneRestModule<QualityProfileResource>
|
||||||
{
|
{
|
||||||
private readonly IQualityProfileService _qualityProfileService;
|
private readonly IQualityProfileService _qualityProfileService;
|
||||||
private readonly IQualityDefinitionService _qualityDefinitionService;
|
|
||||||
|
|
||||||
public QualityProfileModule(IQualityProfileService qualityProfileService,
|
public QualityProfileModule(IQualityProfileService qualityProfileService)
|
||||||
IQualityDefinitionService qualityDefinitionService)
|
|
||||||
: base("/qualityprofiles")
|
: base("/qualityprofiles")
|
||||||
{
|
{
|
||||||
_qualityProfileService = qualityProfileService;
|
_qualityProfileService = qualityProfileService;
|
||||||
_qualityDefinitionService = qualityDefinitionService;
|
|
||||||
|
|
||||||
SharedValidator.RuleFor(c => c.Name).NotEmpty();
|
SharedValidator.RuleFor(c => c.Name).NotEmpty();
|
||||||
SharedValidator.RuleFor(c => c.Cutoff).NotNull();
|
SharedValidator.RuleFor(c => c.Cutoff).NotNull();
|
||||||
SharedValidator.RuleFor(c => c.Items).NotEmpty();
|
SharedValidator.RuleFor(c => c.Items).MustHaveAllowedQuality();//.SetValidator(new AllowedValidator<QualityProfileItemResource>());
|
||||||
|
|
||||||
GetResourceAll = GetAll;
|
GetResourceAll = GetAll;
|
||||||
|
|
||||||
GetResourceById = GetById;
|
GetResourceById = GetById;
|
||||||
|
|
||||||
UpdateResource = Update;
|
UpdateResource = Update;
|
||||||
|
|
||||||
CreateResource = Create;
|
CreateResource = Create;
|
||||||
|
|
||||||
DeleteResource = DeleteProfile;
|
DeleteResource = DeleteProfile;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,43 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using FluentValidation;
|
||||||
|
using FluentValidation.Validators;
|
||||||
|
|
||||||
|
namespace NzbDrone.Api.Qualities
|
||||||
|
{
|
||||||
|
public static class QualityProfileValidation
|
||||||
|
{
|
||||||
|
public static IRuleBuilderOptions<T, IList<QualityProfileItemResource>> MustHaveAllowedQuality<T>(this IRuleBuilder<T, IList<QualityProfileItemResource>> ruleBuilder)
|
||||||
|
{
|
||||||
|
ruleBuilder.SetValidator(new NotEmptyValidator(null));
|
||||||
|
|
||||||
|
return ruleBuilder.SetValidator(new AllowedValidator<T>());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class AllowedValidator<T> : PropertyValidator
|
||||||
|
{
|
||||||
|
public AllowedValidator()
|
||||||
|
: base("Must contain at least one allowed quality")
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override bool IsValid(PropertyValidatorContext context)
|
||||||
|
{
|
||||||
|
var list = context.PropertyValue as IList<QualityProfileItemResource>;
|
||||||
|
|
||||||
|
if (list == null)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!list.Any(c => c.Allowed))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,6 +4,6 @@ define(
|
||||||
'marionette'
|
'marionette'
|
||||||
], function (Marionette) {
|
], function (Marionette) {
|
||||||
return Marionette.ItemView.extend({
|
return Marionette.ItemView.extend({
|
||||||
template : 'Settings/Quality/Profile/EditQualityProfileItemViewTemplate'
|
template : 'Settings/Quality/Profile/Edit/EditQualityProfileItemViewTemplate'
|
||||||
});
|
});
|
||||||
});
|
});
|
|
@ -0,0 +1,92 @@
|
||||||
|
'use strict';
|
||||||
|
define(
|
||||||
|
[
|
||||||
|
'underscore',
|
||||||
|
'vent',
|
||||||
|
'marionette',
|
||||||
|
'backbone',
|
||||||
|
'Settings/Quality/Profile/Edit/EditQualityProfileItemView',
|
||||||
|
'Settings/Quality/Profile/Edit/QualitySortableCollectionView',
|
||||||
|
'Settings/Quality/Profile/Edit/EditQualityProfileView',
|
||||||
|
'Config'
|
||||||
|
], function (_, vent, Marionette, Backbone, EditQualityProfileItemView, QualitySortableCollectionView, EditQualityProfileView, Config) {
|
||||||
|
|
||||||
|
return Marionette.Layout.extend({
|
||||||
|
template: 'Settings/Quality/Profile/Edit/EditQualityProfileLayoutTemplate',
|
||||||
|
|
||||||
|
regions: {
|
||||||
|
fields : '#x-fields',
|
||||||
|
qualities: '#x-qualities'
|
||||||
|
},
|
||||||
|
|
||||||
|
events: {
|
||||||
|
'click .x-save': '_saveQualityProfile'
|
||||||
|
},
|
||||||
|
|
||||||
|
initialize: function (options) {
|
||||||
|
this.profileCollection = options.profileCollection;
|
||||||
|
this.itemsCollection = new Backbone.Collection(_.toArray(this.model.get('items')).reverse());
|
||||||
|
},
|
||||||
|
|
||||||
|
onShow: function () {
|
||||||
|
this.fieldsView = new EditQualityProfileView({ model: this.model });
|
||||||
|
this._showFieldsView();
|
||||||
|
|
||||||
|
this.sortableListView = new QualitySortableCollectionView({
|
||||||
|
selectable : true,
|
||||||
|
selectMultiple : true,
|
||||||
|
clickToSelect : true,
|
||||||
|
clickToToggle : true,
|
||||||
|
sortable : Config.getValueBoolean(Config.Keys.AdvancedSettings, false),
|
||||||
|
|
||||||
|
sortableOptions : {
|
||||||
|
handle: '.x-drag-handle'
|
||||||
|
},
|
||||||
|
|
||||||
|
collection: this.itemsCollection,
|
||||||
|
model : this.model
|
||||||
|
});
|
||||||
|
|
||||||
|
this.sortableListView.setSelectedModels(this.itemsCollection.filter(function(item) { return item.get('allowed') === true; }));
|
||||||
|
this.qualities.show(this.sortableListView);
|
||||||
|
|
||||||
|
this.listenTo(this.sortableListView, 'selectionChanged', this._selectionChanged);
|
||||||
|
this.listenTo(this.sortableListView, 'sortStop', this._updateModel);
|
||||||
|
},
|
||||||
|
|
||||||
|
_selectionChanged: function(newSelectedModels, oldSelectedModels) {
|
||||||
|
var addedModels = _.difference(newSelectedModels, oldSelectedModels);
|
||||||
|
var removeModels = _.difference(oldSelectedModels, newSelectedModels);
|
||||||
|
|
||||||
|
_.each(removeModels, function(item) { item.set('allowed', false); });
|
||||||
|
_.each(addedModels, function(item) { item.set('allowed', true); });
|
||||||
|
|
||||||
|
this._updateModel();
|
||||||
|
},
|
||||||
|
|
||||||
|
_updateModel: function() {
|
||||||
|
this.model.set('items', this.itemsCollection.toJSON().reverse());
|
||||||
|
|
||||||
|
this._showFieldsView();
|
||||||
|
},
|
||||||
|
|
||||||
|
_saveQualityProfile: function () {
|
||||||
|
var self = this;
|
||||||
|
var cutoff = this.fieldsView.getCutoff();
|
||||||
|
this.model.set('cutoff', cutoff);
|
||||||
|
|
||||||
|
var promise = this.model.save();
|
||||||
|
|
||||||
|
if (promise) {
|
||||||
|
promise.done(function () {
|
||||||
|
self.profileCollection.add(self.model, { merge: true });
|
||||||
|
vent.trigger(vent.Commands.CloseModalCommand);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
_showFieldsView: function () {
|
||||||
|
this.fields.show(this.fieldsView);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,29 @@
|
||||||
|
<div class="modal-header">
|
||||||
|
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
||||||
|
{{#if id}}
|
||||||
|
<h3>Edit</h3>
|
||||||
|
{{else}}
|
||||||
|
<h3>Add</h3>
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<div class="form-horizontal">
|
||||||
|
<div id="x-fields"></div>
|
||||||
|
<div class="control-group">
|
||||||
|
<label class="control-label">Qualities</label>
|
||||||
|
<div class="controls qualities-controls">
|
||||||
|
<span id="x-qualities"></span>
|
||||||
|
<span class="help-inline">
|
||||||
|
<i class="icon-question-sign" title="Qualities higher in the list are more preferred. Only checked qualities will be wanted."/>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
{{#if id}}
|
||||||
|
<button class="btn btn-danger pull-left x-delete">delete</button>
|
||||||
|
{{/if}}
|
||||||
|
<button class="btn" data-dismiss="modal">cancel</button>
|
||||||
|
<button class="btn btn-primary x-save">save</button>
|
||||||
|
</div>
|
|
@ -0,0 +1,26 @@
|
||||||
|
'use strict';
|
||||||
|
define(
|
||||||
|
[
|
||||||
|
'underscore',
|
||||||
|
'marionette',
|
||||||
|
'Mixins/AsModelBoundView',
|
||||||
|
'Mixins/AsValidatedView'
|
||||||
|
], function (_, Marionette, AsModelBoundView, AsValidatedView) {
|
||||||
|
|
||||||
|
var view = Marionette.ItemView.extend({
|
||||||
|
template: 'Settings/Quality/Profile/Edit/EditQualityProfileViewTemplate',
|
||||||
|
|
||||||
|
ui: {
|
||||||
|
cutoff : '.x-cutoff'
|
||||||
|
},
|
||||||
|
|
||||||
|
getCutoff: function () {
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
return _.findWhere(_.pluck(this.model.get('items'), 'quality'), { id: parseInt(self.ui.cutoff.val(), 10)});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
AsValidatedView.call(view);
|
||||||
|
return AsModelBoundView.call(view);
|
||||||
|
});
|
|
@ -0,0 +1,21 @@
|
||||||
|
<div class="control-group">
|
||||||
|
<label class="control-label">Name</label>
|
||||||
|
<div class="controls">
|
||||||
|
<input type="text" name="name">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="control-group">
|
||||||
|
<label class="control-label">Cutoff</label>
|
||||||
|
<div class="controls">
|
||||||
|
<select class="x-cutoff" name="cutoff.id" validation-name="cutoff">
|
||||||
|
{{#eachReverse items}}
|
||||||
|
{{#if allowed}}
|
||||||
|
<option value="{{quality.id}}">{{quality.name}}</option>
|
||||||
|
{{/if}}
|
||||||
|
{{/eachReverse}}
|
||||||
|
</select>
|
||||||
|
<span class="help-inline">
|
||||||
|
<i class="icon-question-sign" title="Once this quality is reached NzbDrone will no longer download episodes"/>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
|
@ -0,0 +1,24 @@
|
||||||
|
'use strict';
|
||||||
|
define(
|
||||||
|
[
|
||||||
|
'backbone.collectionview',
|
||||||
|
'Settings/Quality/Profile/Edit/EditQualityProfileItemView'
|
||||||
|
], function (BackboneSortableCollectionView, EditQualityProfileItemView) {
|
||||||
|
return BackboneSortableCollectionView.extend({
|
||||||
|
|
||||||
|
className: 'qualities',
|
||||||
|
modelView: EditQualityProfileItemView,
|
||||||
|
|
||||||
|
attributes: {
|
||||||
|
'validation-name': 'items'
|
||||||
|
},
|
||||||
|
|
||||||
|
events: {
|
||||||
|
'click li, td' : '_listItem_onMousedown',
|
||||||
|
'dblclick li, td' : '_listItem_onDoubleClick',
|
||||||
|
'click' : '_listBackground_onClick',
|
||||||
|
'click ul.collection-list, table.collection-list' : '_listBackground_onClick',
|
||||||
|
'keydown' : '_onKeydown'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
|
@ -1,89 +0,0 @@
|
||||||
'use strict';
|
|
||||||
define(
|
|
||||||
[
|
|
||||||
'underscore',
|
|
||||||
'vent',
|
|
||||||
'marionette',
|
|
||||||
'backbone',
|
|
||||||
'Settings/Quality/Profile/QualitySortableCollectionView',
|
|
||||||
'Settings/Quality/Profile/EditQualityProfileItemView',
|
|
||||||
'Mixins/AsModelBoundView',
|
|
||||||
'Mixins/AsValidatedView',
|
|
||||||
'Config'
|
|
||||||
], function (_, vent, Marionette, Backbone, QualitySortableCollectionView, EditQualityProfileItemView, AsModelBoundView, AsValidatedView, Config) {
|
|
||||||
|
|
||||||
var view = Marionette.ItemView.extend({
|
|
||||||
template: 'Settings/Quality/Profile/EditQualityProfileViewTemplate',
|
|
||||||
|
|
||||||
ui: {
|
|
||||||
allowed : '.x-allowed-list',
|
|
||||||
cutoff : '.x-cutoff'
|
|
||||||
},
|
|
||||||
|
|
||||||
events: {
|
|
||||||
'click .x-save': '_saveQualityProfile'
|
|
||||||
},
|
|
||||||
|
|
||||||
initialize: function (options) {
|
|
||||||
this.profileCollection = options.profileCollection;
|
|
||||||
|
|
||||||
this.itemsCollection = new Backbone.Collection(_.toArray(this.model.get('items')).reverse());
|
|
||||||
},
|
|
||||||
|
|
||||||
onRender: function() {
|
|
||||||
|
|
||||||
var listViewAllowed = new QualitySortableCollectionView({
|
|
||||||
el : this.ui.allowed,
|
|
||||||
modelView : EditQualityProfileItemView,
|
|
||||||
selectable : true,
|
|
||||||
selectMultiple : true,
|
|
||||||
clickToSelect : true,
|
|
||||||
clickToToggle : true,
|
|
||||||
sortable : Config.getValueBoolean(Config.Keys.AdvancedSettings, false),
|
|
||||||
collection : this.itemsCollection
|
|
||||||
});
|
|
||||||
|
|
||||||
listViewAllowed.setSelectedModels(this.itemsCollection.filter(function(item) { return item.get('allowed') === true; }));
|
|
||||||
|
|
||||||
listViewAllowed.render();
|
|
||||||
|
|
||||||
this.listenTo(listViewAllowed, 'selectionChanged', this._selectionChanged);
|
|
||||||
this.listenTo(listViewAllowed, 'sortStop', this._updateModel);
|
|
||||||
},
|
|
||||||
|
|
||||||
_selectionChanged: function(newSelectedModels, oldSelectedModels) {
|
|
||||||
var addedModels = _.difference(newSelectedModels, oldSelectedModels);
|
|
||||||
var removeModels = _.difference(oldSelectedModels, newSelectedModels);
|
|
||||||
|
|
||||||
_.each(removeModels, function(item) { item.set('allowed', false); });
|
|
||||||
_.each(addedModels, function(item) { item.set('allowed', true); });
|
|
||||||
|
|
||||||
this._updateModel();
|
|
||||||
},
|
|
||||||
|
|
||||||
_updateModel: function() {
|
|
||||||
this.model.set('items', this.itemsCollection.toJSON().reverse());
|
|
||||||
|
|
||||||
this.render();
|
|
||||||
},
|
|
||||||
|
|
||||||
_saveQualityProfile: function () {
|
|
||||||
var self = this;
|
|
||||||
var cutoff = _.findWhere(_.pluck(this.model.get('items'), 'quality'), { id: parseInt(self.ui.cutoff.val(), 10)});
|
|
||||||
this.model.set('cutoff', cutoff);
|
|
||||||
|
|
||||||
var promise = this.model.save();
|
|
||||||
|
|
||||||
if (promise) {
|
|
||||||
promise.done(function () {
|
|
||||||
self.profileCollection.add(self.model, { merge: true });
|
|
||||||
vent.trigger(vent.Commands.CloseModalCommand);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
AsValidatedView.call(view);
|
|
||||||
return AsModelBoundView.call(view);
|
|
||||||
|
|
||||||
});
|
|
|
@ -1,49 +0,0 @@
|
||||||
<div class="modal-header">
|
|
||||||
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
|
||||||
{{#if id}}
|
|
||||||
<h3>Edit</h3>
|
|
||||||
{{else}}
|
|
||||||
<h3>Add</h3>
|
|
||||||
{{/if}}
|
|
||||||
</div>
|
|
||||||
<div class="modal-body">
|
|
||||||
<div class="form-horizontal">
|
|
||||||
<div class="control-group">
|
|
||||||
<label class="control-label">Name</label>
|
|
||||||
<div class="controls">
|
|
||||||
<input type="text" name="name">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="control-group">
|
|
||||||
<label class="control-label">Cutoff</label>
|
|
||||||
<div class="controls">
|
|
||||||
<select class="x-cutoff" name="cutoff.id" validation-name="cutoff">
|
|
||||||
{{#eachReverse items}}
|
|
||||||
{{#if allowed}}
|
|
||||||
<option value="{{quality.id}}">{{quality.name}}</option>
|
|
||||||
{{/if}}
|
|
||||||
{{/eachReverse}}
|
|
||||||
</select>
|
|
||||||
<span class="help-inline">
|
|
||||||
<i class="icon-question-sign" title="Once this quality is reached NzbDrone will no longer download episodes"/>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="control-group">
|
|
||||||
<label class="control-label">Qualities</label>
|
|
||||||
<div class="controls qualities-controls">
|
|
||||||
<ul class="qualities x-allowed-list" validation-name="allowed"></ul>
|
|
||||||
<span class="help-inline">
|
|
||||||
<i class="icon-question-sign" title="Qualities higher in the list are more preferred. Only checked qualities will be wanted."/>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="modal-footer">
|
|
||||||
{{#if id}}
|
|
||||||
<button class="btn btn-danger pull-left x-delete">delete</button>
|
|
||||||
{{/if}}
|
|
||||||
<button class="btn" data-dismiss="modal">cancel</button>
|
|
||||||
<button class="btn btn-primary x-save">save</button>
|
|
||||||
</div>
|
|
|
@ -3,7 +3,7 @@
|
||||||
define(['AppLayout',
|
define(['AppLayout',
|
||||||
'marionette',
|
'marionette',
|
||||||
'Settings/Quality/Profile/QualityProfileView',
|
'Settings/Quality/Profile/QualityProfileView',
|
||||||
'Settings/Quality/Profile/EditQualityProfileView',
|
'Settings/Quality/Profile/Edit/EditQualityProfileLayout',
|
||||||
'Settings/Quality/Profile/QualityProfileSchemaCollection',
|
'Settings/Quality/Profile/QualityProfileSchemaCollection',
|
||||||
'underscore'
|
'underscore'
|
||||||
], function (AppLayout, Marionette, QualityProfileView, EditProfileView, ProfileCollection, _) {
|
], function (AppLayout, Marionette, QualityProfileView, EditProfileView, ProfileCollection, _) {
|
||||||
|
|
|
@ -4,7 +4,7 @@ define(
|
||||||
[
|
[
|
||||||
'AppLayout',
|
'AppLayout',
|
||||||
'marionette',
|
'marionette',
|
||||||
'Settings/Quality/Profile/EditQualityProfileView',
|
'Settings/Quality/Profile/Edit/EditQualityProfileLayout',
|
||||||
'Settings/Quality/Profile/DeleteView',
|
'Settings/Quality/Profile/DeleteView',
|
||||||
'Series/SeriesCollection',
|
'Series/SeriesCollection',
|
||||||
'Mixins/AsModelBoundView',
|
'Mixins/AsModelBoundView',
|
||||||
|
@ -13,7 +13,7 @@ define(
|
||||||
], function (AppLayout, Marionette, EditProfileView, DeleteProfileView, SeriesCollection, AsModelBoundView) {
|
], function (AppLayout, Marionette, EditProfileView, DeleteProfileView, SeriesCollection, AsModelBoundView) {
|
||||||
|
|
||||||
var view = Marionette.ItemView.extend({
|
var view = Marionette.ItemView.extend({
|
||||||
template: 'Settings/Quality/Profile/QualityProfileTemplate',
|
template: 'Settings/Quality/Profile/QualityProfileViewTemplate',
|
||||||
tagName : 'li',
|
tagName : 'li',
|
||||||
|
|
||||||
ui: {
|
ui: {
|
||||||
|
|
|
@ -1,27 +0,0 @@
|
||||||
'use strict';
|
|
||||||
define(
|
|
||||||
[
|
|
||||||
'backbone.collectionview'
|
|
||||||
], function (BackboneSortableCollectionView) {
|
|
||||||
return BackboneSortableCollectionView.extend({
|
|
||||||
|
|
||||||
events : {
|
|
||||||
'click li, td' : '_listItem_onMousedown',
|
|
||||||
'dblclick li, td' : '_listItem_onDoubleClick',
|
|
||||||
'click' : '_listBackground_onClick',
|
|
||||||
'click ul.collection-list, table.collection-list' : '_listBackground_onClick',
|
|
||||||
'keydown' : '_onKeydown',
|
|
||||||
'click .x-move' : '_onClickMove'
|
|
||||||
},
|
|
||||||
|
|
||||||
_onClickMove: function( theEvent ) {
|
|
||||||
var clickedItemId = this._getClickedItemId( theEvent );
|
|
||||||
|
|
||||||
if( clickedItemId )
|
|
||||||
{
|
|
||||||
var clickedModel = this.collection.get( clickedItemId );
|
|
||||||
this.trigger('moveClicked', clickedModel);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -78,7 +78,7 @@ ul.qualities {
|
||||||
|
|
||||||
.drag-handle {
|
.drag-handle {
|
||||||
opacity: 1.0;
|
opacity: 1.0;
|
||||||
cursor: pointer;
|
cursor: move;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue