1
0
mirror of http://git.whoc.org.uk/git/password-manager.git synced 2025-10-28 18:07:35 +01:00

Implemented field manual ordering through drag&drop

This commit is contained in:
Giulio Cesare Solaroli
2014-09-04 18:58:56 +02:00
parent 3796182d77
commit 54b264b6a1
8 changed files with 707 additions and 25 deletions

View File

@@ -52,6 +52,7 @@ Clipperz.Base.extend(Clipperz.PM.DataModel.Record.Version, Clipperz.PM.DataModel
'hasPendingChanges': function () {
var deferredResult;
console.log("Record.Version.hasPendingChanges");
deferredResult = new Clipperz.Async.Deferred("Clipperz.PM.DataModel.Record.Version.hasPendingChanges", {trace:false});
deferredResult.addCallback(MochiKit.Base.bind(Clipperz.PM.DataModel.Record.Version.superclass.hasPendingChanges, this));
deferredResult.callback();
@@ -111,8 +112,6 @@ Clipperz.Base.extend(Clipperz.PM.DataModel.Record.Version, Clipperz.PM.DataModel
}
}
return result;
},

View File

@@ -769,13 +769,11 @@ Clipperz.Base.extend(Clipperz.PM.DataModel.Record, Clipperz.PM.DataModel.Encrypt
},
//=========================================================================
/*
'hasPendingChanges': function () {
var deferredResult;
/*if (this.isBrandNew()) {
deferredResult = MochiKit.Async.succeed(true);
} else*/ if (this.hasInitiatedObjectDataStore()) {
if (this.hasInitiatedObjectDataStore()) {
deferredResult = new Clipperz.Async.Deferred("Clipperz.PM.DataModel.Record.hasPendingChanges", {trace:false});
deferredResult.collectResults({
'super': MochiKit.Base.bind(Clipperz.PM.DataModel.Record.superclass.hasPendingChanges, this),
@@ -795,6 +793,7 @@ Clipperz.Base.extend(Clipperz.PM.DataModel.Record, Clipperz.PM.DataModel.Encrypt
// }
]
});
deferredResult.addCallback(function (aValue) { console.log("Record.hasPendingChanges", aValue); return aValue; });
deferredResult.addCallback(MochiKit.Base.values);
deferredResult.addCallback(MochiKit.Base.bind(function(someValues) {
var result;
@@ -823,6 +822,67 @@ Clipperz.Base.extend(Clipperz.PM.DataModel.Record, Clipperz.PM.DataModel.Encrypt
return deferredResult;
},
*/
'hasPendingChanges': function () {
var deferredResult;
// var recordReference = this.reference();
var self = this;
deferredResult = new Clipperz.Async.Deferred("Clipperz.PM.DataModel.Record.hasPendingChanges", {trace:false});
deferredResult.collectResults({
'super': [
MochiKit.Base.bind(Clipperz.PM.DataModel.Record.superclass.hasPendingChanges, this),
// MochiKit.Base.method(this, 'hasInitiatedObjectDataStore'),
// Clipperz.Async.deferredIf("Record.hasPendingChanges - hasInitiatedObjectDataStore", [
// MochiKit.Base.bind(Clipperz.PM.DataModel.Record.superclass.hasPendingChanges, this),
// ], [
// MochiKit.Base.partial(MochiKit.Async.succeed, false),
// ]),
],
'currentVersion': [
// MochiKit.Base.method(this, 'invokeCurrentRecordVersionMethod', 'hasPendingChanges')
MochiKit.Base.method(this, 'hasInitiatedObjectDataStore'),
Clipperz.Async.deferredIf("Record.hasPendingChanges - hasInitiatedObjectDataStore", [
MochiKit.Base.method(this, 'invokeCurrentRecordVersionMethod', 'hasPendingChanges')
], [
MochiKit.Base.partial(MochiKit.Async.succeed, false),
]),
],
'directLogins': [
MochiKit.Base.method(this, 'directLogins'),
MochiKit.Base.values,
MochiKit.Base.partial(MochiKit.Base.map, MochiKit.Base.methodcaller('hasPendingChanges')),
Clipperz.Async.collectAll,
Clipperz.Async.or
]
});
//deferredResult.addCallback(function (someValues) {
// if (recordReference == 'd620764a656bfd4e1d3758500d5db72e460a0cf729d56ed1a7755b5725c50045') {
// console.log("Record.hasPendingChanges VALUES", someValues);
// }
// return someValues;
//})
deferredResult.addCallback(MochiKit.Base.values);
deferredResult.addCallback(MochiKit.Base.bind(function(someValues) {
var result;
result = MochiKit.Iter.some(someValues, MochiKit.Base.operator.identity);
/*
if ((result == false) && (this.isBrandNew() == false)) {
console.log("TRANSIENT STATE", this.transientState());
console.log("TRANSIENT STATE - hasPendingChanges", this.transientState().getValue('hasPendingChanges.indexData'));
result = MochiKit.Iter.some(MochiKit.Base.values(this.transientState().getValue('hasPendingChanges.indexData')), MochiKit.Base.operator.identity);
}
console.log("Record.hasPendingChanges RESULT", result);
*/
return result;
}, this));
deferredResult.callback();
return deferredResult;
},
//-------------------------------------------------------------------------
@@ -872,15 +932,21 @@ Clipperz.Base.extend(Clipperz.PM.DataModel.Record, Clipperz.PM.DataModel.Encrypt
'revertChanges': function () {
var deferredResult;
var recordReference = this.reference();
if (this.isBrandNew() == false) {
/*
deferredResult = new Clipperz.Async.Deferred("Clipperz.PM.DataModel.Record.revertChanges", {trace:false});
deferredResult.addMethod(this, 'hasPendingChanges');
deferredResult.addCallback(function (aValue) {
if (recordReference == 'd620764a656bfd4e1d3758500d5db72e460a0cf729d56ed1a7755b5725c50045') {
console.log("Record.revertChanges - hasPendingChanges", aValue);
}
// return aValue;
return true;
});
deferredResult.addIf([
// MochiKit.Base.method(this, 'getCurrentRecordVersion'),
// MochiKit.Base.methodcaller('revertChanges'),
MochiKit.Base.method(this,'invokeCurrentRecordVersionMethod', 'revertChanges'),
MochiKit.Base.method(this, 'invokeCurrentRecordVersionMethod', 'revertChanges'),
MochiKit.Base.method(this, 'directLogins'),
MochiKit.Base.values,
MochiKit.Base.partial(MochiKit.Base.map, MochiKit.Base.methodcaller('revertChanges')),
@@ -890,6 +956,15 @@ Clipperz.Base.extend(Clipperz.PM.DataModel.Record, Clipperz.PM.DataModel.Encrypt
MochiKit.Async.succeed
]);
deferredResult.callback();
*/
deferredResult = Clipperz.Async.callbacks("Clipperz.PM.DataModel.Record.revertChanges", [
MochiKit.Base.method(this, 'invokeCurrentRecordVersionMethod', 'revertChanges'),
MochiKit.Base.method(this, 'directLogins'),
MochiKit.Base.values,
MochiKit.Base.partial(MochiKit.Base.map, MochiKit.Base.methodcaller('revertChanges')),
MochiKit.Base.bind(Clipperz.PM.DataModel.Record.superclass.revertChanges, this)
], {trace:false});
} else {
// this.deleteAllCleanTextData();
deferredResult = MochiKit.Async.succeed();
@@ -1005,6 +1080,45 @@ Clipperz.Base.extend(Clipperz.PM.DataModel.Record, Clipperz.PM.DataModel.Encrypt
])
},
//-------------------------------------------------------------------------
'moveFieldToPosition': function (aFieldReference, aPosition) {
var deferredResult;
var currentFieldValues;
var fromPosition;
deferredResult = new Clipperz.Async.Deferred("Clipperz.PM.DataModel.Record.moveFieldToPosition", {trace:false});
deferredResult.addMethod(this, 'getFieldsValues');
deferredResult.addCallback(function (someValues) {
fromPosition = MochiKit.Base.keys(someValues).indexOf(aFieldReference);
return ((fromPosition != -1) && (fromPosition!= aPosition));
});
deferredResult.addIf([
MochiKit.Base.method(this, 'getFieldsValues'),
function (someValues) { currentFieldValues = Clipperz.Base.deepClone(someValues); return currentFieldValues},
MochiKit.Base.method(this, 'fields'), MochiKit.Base.values,
MochiKit.Base.partial(MochiKit.Base.map, MochiKit.Base.method(this, 'removeField')),
Clipperz.Async.collectAll,
function () {
var currentFieldKeys = MochiKit.Base.keys(currentFieldValues);
currentFieldKeys.splice(aPosition, 0, currentFieldKeys.splice(fromPosition, 1)[0]);
return currentFieldKeys;
},
//function (aValue) { console.log("Sorted Keys", aValue); return aValue; },
MochiKit.Base.partial(MochiKit.Base.map, function (aReference) { return currentFieldValues[aReference]; }),
function (aValue) { console.log("Sorted Field values", aValue); return aValue; },
MochiKit.Base.partial(MochiKit.Base.map, MochiKit.Base.method(this, 'addField')),
Clipperz.Async.collectAll,
], [
MochiKit.Async.succeed
]);
deferredResult.callback();
return deferredResult;
},
//=========================================================================
'setUpWithRecord': function (aRecord) {
@@ -1025,9 +1139,10 @@ Clipperz.Base.extend(Clipperz.PM.DataModel.Record, Clipperz.PM.DataModel.Encrypt
MochiKit.Base.partial(MochiKit.Base.map, MochiKit.Base.method(this, 'addField')),
Clipperz.Async.collectAll,
// MochiKit.Base.method(aRecord, 'directLogins'), MochiKit.Base.values,
// function (aValue) { console.log("-> DirectLogin Values", aValue); return aValue; },
// MochiKit.Base.partial(MochiKit.Base.map, MochiKit.Base.method(this, 'addField')),
MochiKit.Base.method(aRecord, 'directLogins'), MochiKit.Base.values,
function (aValue) { console.log("-> DirectLogin Values", aValue); return aValue; },
MochiKit.Base.partial(MochiKit.Base.map, MochiKit.Base.method(this, 'addDirectLogin')),
//function (aValue) { console.log("-> DirectLogin Values", aValue); return aValue; },
// Clipperz.Async.collectAll,
MochiKit.Base.bind(function () { return this; }, this)

View File

@@ -33,12 +33,201 @@ Clipperz.PM.UI.Components.Cards.Edit = React.createClass({
// 'loading': React.PropTypes.bool,
},
getInitialState: function() {
return {
'draggedFieldReference': null,
'fromFieldPosition': -1,
'toFieldPosition': -1,
'dropPosition': -1,
};
},
//----------------------------------------------------------------------------
record: function () {
return this.props['_record'];
},
fields: function () {
return this.props['fields'];
},
/*
sortedFields: function () {
var result;
var from = this.state['fromFieldPosition'];
var to = this.state['toFieldPosition'];
// console.log("FIELDS", this.fields());
if ((from != -1) && (to != -1) && (from != to)) {
result = MochiKit.Base.clone(this.fields());
result.splice(to, 0, result.splice(from, 1)[0]);
} else {
result = this.fields();
}
return result;
},
*/
//============================================================================
positionOfField: function (aFieldReference) {
return MochiKit.Base.map(MochiKit.Base.itemgetter('_reference'), this.fields()).indexOf(aFieldReference);
},
//============================================================================
dragStart: function (anEvent) {
var fieldReference = anEvent.currentTarget.dataset['reference'];
var fieldPosition = this.positionOfField(fieldReference);
var x = anEvent.clientX - anEvent.currentTarget.getBoundingClientRect().left;
var y = anEvent.clientY - anEvent.currentTarget.getBoundingClientRect().top;
anEvent.dataTransfer.setDragImage(anEvent.currentTarget, x, y);
MochiKit.Async.callLater(0.1, MochiKit.Base.bind(this.setState, this, {
'draggedFieldReference': fieldReference,
'fromFieldPosition': fieldPosition,
'toFieldPosition': -1,
'dropPosition': -1
}));
// this.setState({
// 'draggedFieldReference': fieldReference,
// 'fromFieldPosition': fieldPosition
/// 'toFieldPosition': 0
// });
// anEvent.dataTransfer.effectAllowed = 'move';
// anEvent.dataTransfer.setData('text/html', this.innerHTML);
// anEvent.dropEffect
},
/*
drag: function (anEvent) {
//console.log("DRAG", anEvent);
},
drop: function (anEvent) {
console.log("DROP"); //, anEvent);
},
*/
dragEnd: function (anEvent) {
if (this.state['toFieldPosition'] != -1) {
var reference = this.props['_reference'];
//console.log("MOVE FIELD POSITION", this.state['toFieldPosition'], this.state['draggedFieldReference']);
Clipperz.Async.callbacks("Clipperz.PM.UI.Components.Cards.Edit.dragEnd-moveFieldToPosition", [
MochiKit.Base.method(this.record(), 'moveFieldToPosition', this.state['draggedFieldReference'], this.state['toFieldPosition']),
MochiKit.Base.partial(MochiKit.Signal.signal, Clipperz.Signal.NotificationCenter, 'refreshCardEditDetail', reference),
], {trace:false});
} else {
//console.log("CANCELLED FIELD MOVE");
}
this.setState({
'draggedFieldReference': null,
'fromFieldPosition': -1,
'toFieldPosition': -1,
'dropPosition': -1
})
},
//............................................................................
/*
dragEnter: function (anEvent) {
//console.log("DRAG ENTER", anEvent.currentTarget.dataset['reference'], this.positionOfField(anEvent.currentTarget.dataset['reference']));
// this.setState({'toFieldPosition': this.positionOfField(anEvent.currentTarget.dataset['reference'])});
},
*/
dragOver: function (anEvent) {
var toFieldPosition;
var dropPosition;
if (typeof(anEvent.currentTarget.dataset['index']) != 'undefined') {
var y = anEvent.clientY - anEvent.currentTarget.getBoundingClientRect().top;
var h = anEvent.currentTarget.getBoundingClientRect().height;
var hoveringIndex;
var draggingIndex;
var isHoveringTopPart;
hoveringIndex = +anEvent.currentTarget.dataset['index'];
draggingIndex = +this.state['fromFieldPosition'];
isHoveringTopPart = (y < h/2);
if (isHoveringTopPart) {
dropPosition = hoveringIndex;
} else {
dropPosition = hoveringIndex + 1;
}
if (hoveringIndex > draggingIndex) {
dropPosition = dropPosition - 1;
}
toFieldPosition = -1;
//console.log(hoveringIndex, draggingIndex, isHoveringTopPart, dropPosition);
//console.log("isHoveringTopPart", isHoveringTopPart);
} else {
dropPosition = anEvent.currentTarget.dataset['dropIndex'];
toFieldPosition = dropPosition;
}
if ((dropPosition != this.state['dropPosition']) || (toFieldPosition != this.state['toFieldPosition'])) {
this.setState({'dropPosition': dropPosition, 'toFieldPosition':toFieldPosition});
}
anEvent.stopPropagation();
},
/*
dragLeave: function (anEvent) {
//console.log("DRAG LEAVE", anEvent.currentTarget.dataset['reference'], this.positionOfField(anEvent.currentTarget.dataset['reference']));
// this.setState({'dropPosition': -1});
},
*/
//============================================================================
/*
dragStartDropTarget: function (anEvent) {
//console.log("TARGET: DRAG START");
},
dragDropTarget: function (anEvent) {
//console.log("TARGET: DRAG");
},
dropDropTarget: function (anEvent) {
//console.log("TARGET: DROP");
},
dragEndDropTarget: function (anEvent) {
//console.log("TARGET: DRAG END");
},
//............................................................................
dragEnterDropTarget: function (anEvent) {
//console.log("TARGET: DRAG ENTER");
},
*/
dragOverDropTarget: function (anEvent) {
var toFieldPosition = anEvent.currentTarget.dataset['dropIndex'];
if (toFieldPosition != this.state['toFieldPosition']) {
//console.log("TARGET: DRAG OVER - READY TO DROP", anEvent.currentTarget.dataset['dropIndex']);
this.setState({'toFieldPosition':toFieldPosition});
}
anEvent.stopPropagation();
},
dragLeaveDropTarget: function (anEvent) {
//console.log("TARGET: DRAG LEAVE");
if (-1 != this.state['toFieldPosition']) {
//console.log("READY TO DROP", anEvent.currentTarget.dataset['dropIndex']);
MochiKit.Async.callLater(0.5, MochiKit.Base.bind(function () {
//console.log("TARGET: DRAG LEAVE #####");
this.setState({'toFieldPosition':-1});
}, this))
}
},
//============================================================================
handleChange: function (anObject , aMethodName) {
@@ -104,12 +293,27 @@ Clipperz.PM.UI.Components.Cards.Edit = React.createClass({
cardFieldClasses['cardField'] = true;
cardFieldClasses[aField['actionType']] = true;
cardFieldClasses['hidden'] = aField['isHidden'];
if (this.state['draggedFieldReference'] == aField['_reference']) {
cardFieldClasses['dragged'] = true;
}
cardFieldValueClasses['fieldValue'] = true;
cardFieldValueClasses[aField['actionType']] = true;
cardFieldValueClasses['hidden'] = aField['isHidden'];
return React.DOM.div({'className':React.addons.classSet(cardFieldClasses), 'key':ref}, [
return React.DOM.div({'className':React.addons.classSet(cardFieldClasses), 'draggable':true, 'key':ref,
'data-reference':ref,
'data-document-id':ref,
'data-index':this.positionOfField(ref),
'onDragStart':this.dragStart,
// 'onDrag':this.drag,
// 'onDragEnter':this.dragEnter,
'onDragOver':this.dragOver,
// 'onDragLeave':this.dragLeave,
// 'onDrop':this.drop,
'onDragEnd':this.dragEnd
}, [
React.DOM.div({'className':'fieldValues'}, [
React.DOM.span({'className':'removeField', 'onClick':this.removeField(field)}, "delete"),
React.DOM.input({'className':'fieldLabel', 'onChange':this.handleChange(field, 'setLabel'), 'defaultValue':aField['label']}),
@@ -119,8 +323,40 @@ Clipperz.PM.UI.Components.Cards.Edit = React.createClass({
]);
},
updateRenderedFieldsWithDropArea: function (someRenderedFields) {
var dragFrom = this.state['fromFieldPosition']
var dropTo = this.state['dropPosition'];
var dropAreaPositionIndex = dropTo != -1 ? dropTo : dragFrom;
var dropArea = React.DOM.div({'className':'dropArea', 'key':'fieldDropArea',
'data-drop-index':dropAreaPositionIndex,
// 'onDragStart':this.dragStartDropTarget,
// 'onDrag':this.dragDropTarget,
// 'onDragEnter':this.dragEnterDropTarget,
'onDragOver': this.dragOverDropTarget,
'onDragLeave': this.dragLeaveDropTarget,
// 'onDrop': this.dropDropTarget,
// 'onDragEnd':this.dragEndDropTarget
});
var dropAreaNodeIndex = (dropAreaPositionIndex < dragFrom) ? dropAreaPositionIndex : dropAreaPositionIndex + 1;
//console.log("DROP", dropTo, dropAreaPositionIndex);
someRenderedFields.splice(dropAreaNodeIndex, 0, dropArea);
return someRenderedFields;
},
renderFields: function (someFields) {
return React.DOM.div({'className':'cardFields'}, MochiKit.Base.map(this.renderField, someFields));
var renderedFields;
renderedFields = MochiKit.Base.map(this.renderField, someFields);
if (this.state['draggedFieldReference'] != null) {
renderedFields = this.updateRenderedFieldsWithDropArea(renderedFields);
}
return React.DOM.div({'className':'cardFields' /*, 'dropzone':'move'*/}, renderedFields);
},
renderAddNewField: function () {
@@ -156,7 +392,7 @@ Clipperz.PM.UI.Components.Cards.Edit = React.createClass({
this.renderLabel(this.props['label']),
this.renderTags(this.props['tags']),
this.renderNotes(this.props['notes']),
this.renderFields(this.props['fields']),
this.renderFields(this.fields()),
this.renderAddNewField(),
this.renderDirectLogins(this.props['directLogins'])
])