mirror of
https://github.com/the-djmaze/snappymail.git
synced 2026-07-13 03:27:39 +03:00
Merged from sub repository (filters - step 4)
This commit is contained in:
parent
67e45a6a6f
commit
e4b286e257
58 changed files with 1176 additions and 236 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
|
@ -1,6 +1,8 @@
|
|||
/.idea
|
||||
/nbproject
|
||||
/npm-debug.log
|
||||
/rainloop.sublime-project
|
||||
/rainloop.sublime-workspace
|
||||
/rainloop/v/0.0.0/static/css/*.css
|
||||
/rainloop/v/0.0.0/static/js/*.js
|
||||
/rainloop/v/0.0.0/static/js/**/*.js
|
||||
|
|
|
|||
|
|
@ -75,6 +75,20 @@
|
|||
Events.pub('interval.10m');
|
||||
}, 60000 * 10);
|
||||
|
||||
window.setInterval(function () {
|
||||
Events.pub('interval.15m');
|
||||
}, 60000 * 15);
|
||||
|
||||
window.setInterval(function () {
|
||||
Events.pub('interval.20m');
|
||||
}, 60000 * 15);
|
||||
|
||||
window.setTimeout(function () {
|
||||
window.setInterval(function () {
|
||||
Events.pub('interval.5m-after5m');
|
||||
}, 60000 * 5);
|
||||
}, 60000 * 5);
|
||||
|
||||
window.setTimeout(function () {
|
||||
window.setInterval(function () {
|
||||
Events.pub('interval.10m-after5m');
|
||||
|
|
@ -476,8 +490,32 @@
|
|||
}
|
||||
};
|
||||
|
||||
AppUser.prototype.accountsAndIdentities = function ()
|
||||
AppUser.prototype.accountsCounts = function ()
|
||||
{
|
||||
Remote.accountsCounts(function (sResult, oData) {
|
||||
if (Enums.StorageResultType.Success === sResult && oData.Result && oData.Result['Counts'])
|
||||
{
|
||||
var aAcounts = Data.accounts();
|
||||
|
||||
_.each(oData.Result['Counts'], function (oItem) {
|
||||
|
||||
var oAccount = _.find(aAcounts, function (oAccount) {
|
||||
return oAccount && oItem[0] === oAccount.email;
|
||||
});
|
||||
|
||||
if (oAccount)
|
||||
{
|
||||
oAccount.count(Utils.pInt(oItem[1]));
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
AppUser.prototype.accountsAndIdentities = function (bBoot)
|
||||
{
|
||||
var self = this;
|
||||
|
||||
Data.accountsLoading(true);
|
||||
Data.identitiesLoading(true);
|
||||
|
||||
|
|
@ -489,6 +527,7 @@
|
|||
if (Enums.StorageResultType.Success === sResult && oData.Result)
|
||||
{
|
||||
var
|
||||
aCounts = {},
|
||||
sParentEmail = Settings.settingsGet('ParentEmail'),
|
||||
sAccountEmail = Data.accountEmail()
|
||||
;
|
||||
|
|
@ -497,12 +536,22 @@
|
|||
|
||||
if (Utils.isArray(oData.Result['Accounts']))
|
||||
{
|
||||
_.each(Data.accounts(), function (oAccount) {
|
||||
aCounts[oAccount.email] = oAccount.count();
|
||||
});
|
||||
|
||||
Utils.delegateRunOnDestroy(Data.accounts());
|
||||
|
||||
Data.accounts(_.map(oData.Result['Accounts'], function (sValue) {
|
||||
return new AccountModel(sValue, sValue !== sParentEmail);
|
||||
return new AccountModel(sValue, sValue !== sParentEmail, aCounts[sValue] || 0);
|
||||
}));
|
||||
}
|
||||
|
||||
if (Utils.isUnd(bBoot) ? false : !!bBoot)
|
||||
{
|
||||
self.accountsCounts();
|
||||
}
|
||||
|
||||
if (Utils.isArray(oData.Result['Identities']))
|
||||
{
|
||||
Utils.delegateRunOnDestroy(Data.identities());
|
||||
|
|
@ -723,8 +772,9 @@
|
|||
});
|
||||
|
||||
if (bBoot)
|
||||
{
|
||||
self.folderInformationMultiply(true);
|
||||
{ _.delay(function () {
|
||||
self.folderInformationMultiply(true);
|
||||
}, 2000);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1342,7 +1392,7 @@
|
|||
self.folderInformation(Cache.getFolderInboxName());
|
||||
});
|
||||
|
||||
Events.sub('interval.2m', function () {
|
||||
Events.sub('interval.3m', function () {
|
||||
var sF = Data.currentFolderFullNameRaw();
|
||||
if (Cache.getFolderInboxName() !== sF)
|
||||
{
|
||||
|
|
@ -1350,15 +1400,15 @@
|
|||
}
|
||||
});
|
||||
|
||||
Events.sub('interval.3m', function () {
|
||||
Events.sub('interval.5m-after5m', function () {
|
||||
self.folderInformationMultiply();
|
||||
});
|
||||
|
||||
Events.sub('interval.5m', function () {
|
||||
Events.sub('interval.15m', function () {
|
||||
self.quota();
|
||||
});
|
||||
|
||||
Events.sub('interval.10m', function () {
|
||||
Events.sub('interval.20m', function () {
|
||||
self.folders();
|
||||
});
|
||||
|
||||
|
|
@ -1379,7 +1429,7 @@
|
|||
|
||||
if (Settings.capa(Enums.Capa.AdditionalAccounts) || Settings.capa(Enums.Capa.AdditionalIdentities))
|
||||
{
|
||||
self.accountsAndIdentities();
|
||||
self.accountsAndIdentities(true);
|
||||
}
|
||||
|
||||
_.delay(function () {
|
||||
|
|
|
|||
|
|
@ -1253,9 +1253,11 @@
|
|||
return sResult;
|
||||
};
|
||||
|
||||
Utils.draggeblePlace = function ()
|
||||
Utils.draggablePlace = function ()
|
||||
{
|
||||
return $('<div class="draggablePlace"><span class="text"></span> <i class="icon-copy icon-white visible-on-ctrl"></i><i class="icon-mail icon-white hidden-on-ctrl"></i></div>').appendTo('#rl-hidden');
|
||||
return $('<div class="draggablePlace">' +
|
||||
'<span class="text"></span> ' +
|
||||
'<i class="icon-copy icon-white visible-on-ctrl"></i><i class="icon-mail icon-white hidden-on-ctrl"></i></div>').appendTo('#rl-hidden');
|
||||
};
|
||||
|
||||
Utils.defautOptionsAfterRender = function (oDomOption, oItem)
|
||||
|
|
|
|||
24
dev/External/ko.js
vendored
24
dev/External/ko.js
vendored
|
|
@ -793,6 +793,30 @@
|
|||
return oTarget;
|
||||
};
|
||||
|
||||
ko.extenders.toggleSubscribeProperty = function (oTarget, oOptions)
|
||||
{
|
||||
var sProp = oOptions[1];
|
||||
|
||||
if (sProp)
|
||||
{
|
||||
oTarget.subscribe(function (oPrev) {
|
||||
if (oPrev && oPrev[sProp])
|
||||
{
|
||||
oPrev[sProp](false);
|
||||
}
|
||||
}, oOptions[0], 'beforeChange');
|
||||
|
||||
oTarget.subscribe(function (oNext) {
|
||||
if (oNext && oNext[sProp])
|
||||
{
|
||||
oNext[sProp](true);
|
||||
}
|
||||
}, oOptions[0]);
|
||||
}
|
||||
|
||||
return oTarget;
|
||||
};
|
||||
|
||||
ko.extenders.falseTimeout = function (oTarget, iOption)
|
||||
{
|
||||
var Utils = require('Common/Utils');
|
||||
|
|
|
|||
|
|
@ -17,13 +17,16 @@
|
|||
*
|
||||
* @param {string} sEmail
|
||||
* @param {boolean=} bCanBeDelete = true
|
||||
* @param {number=} iCount = 0
|
||||
*/
|
||||
function AccountModel(sEmail, bCanBeDelete)
|
||||
function AccountModel(sEmail, bCanBeDelete, iCount)
|
||||
{
|
||||
AbstractModel.call(this, 'AccountModel');
|
||||
|
||||
this.email = sEmail;
|
||||
|
||||
this.count = ko.observable(iCount || 0);
|
||||
|
||||
this.deleteAccess = ko.observable(false);
|
||||
this.canBeDalete = ko.observable(Utils.isUnd(bCanBeDelete) ? true : !!bCanBeDelete);
|
||||
this.canBeEdit = this.canBeDalete;
|
||||
|
|
|
|||
|
|
@ -21,42 +21,20 @@
|
|||
{
|
||||
AbstractModel.call(this, 'FilterModel');
|
||||
|
||||
this.isNew = ko.observable(true);
|
||||
this.enabled = ko.observable(true);
|
||||
|
||||
this.name = ko.observable('');
|
||||
|
||||
this.conditionsType = ko.observable(Enums.FilterRulesType.All);
|
||||
this.name.error = ko.observable(false);
|
||||
this.name.focused = ko.observable(false);
|
||||
|
||||
this.conditions = ko.observableArray([]);
|
||||
this.conditionsType = ko.observable(Enums.FilterRulesType.All);
|
||||
|
||||
// Actions
|
||||
this.actionMarkAsRead = ko.observable(false);
|
||||
this.actionSkipOtherFilters = ko.observable(true);
|
||||
this.actionValue = ko.observable('');
|
||||
this.actionMarkAsRead = ko.observable(false);
|
||||
|
||||
this.actionType = ko.observable(Enums.FiltersAction.Move);
|
||||
this.actionTypeOptions = [ // TODO i18n
|
||||
{'id': Enums.FiltersAction.None, 'name': 'None'},
|
||||
{'id': Enums.FiltersAction.Move, 'name': ' Move to'},
|
||||
// {'id': Enums.FiltersAction.Forward, 'name': 'Forward to'},
|
||||
{'id': Enums.FiltersAction.Discard, 'name': 'Discard'}
|
||||
];
|
||||
|
||||
this.enableSkipOtherFilters = ko.computed(function () {
|
||||
return -1 === Utils.inArray(this.actionType(), [
|
||||
Enums.FiltersAction.Move, Enums.FiltersAction.Forward, Enums.FiltersAction.Discard
|
||||
]);
|
||||
}, this);
|
||||
|
||||
this.actionSkipOtherFiltersResult = ko.computed({
|
||||
'read': function () {
|
||||
return this.actionSkipOtherFilters() ||
|
||||
!this.enableSkipOtherFilters();
|
||||
},
|
||||
'write': this.actionSkipOtherFilters,
|
||||
'owner': this
|
||||
});
|
||||
|
||||
this.actionTemplate = ko.computed(function () {
|
||||
|
||||
|
|
@ -84,14 +62,42 @@
|
|||
Utils.windowResize();
|
||||
}));
|
||||
|
||||
this.regDisposables([this.enableSkipOtherFilters, this.actionSkipOtherFiltersResult, this.actionTemplate]);
|
||||
this.regDisposables(this.name.subscribe(function (sValue) {
|
||||
this.name.error('' === sValue);
|
||||
}, this));
|
||||
|
||||
this.regDisposables([this.actionTemplate]);
|
||||
|
||||
this.deleteAccess = ko.observable(false);
|
||||
this.canBeDalete = ko.observable(true);
|
||||
}
|
||||
|
||||
_.extend(FilterModel.prototype, AbstractModel.prototype);
|
||||
|
||||
FilterModel.prototype.toJson = function ()
|
||||
{
|
||||
return {
|
||||
'Enabled': this.enabled(),
|
||||
'Name': this.name(),
|
||||
'ConditionsType': this.conditionsType(),
|
||||
'Conditions': _.map(this.conditions(), function (oItem) {
|
||||
return oItem.toJson();
|
||||
}),
|
||||
'ActionMarkAsRead': this.actionMarkAsRead(),
|
||||
'ActionValue': this.actionValue(),
|
||||
'ActionType': this.actionType()
|
||||
};
|
||||
};
|
||||
|
||||
FilterModel.prototype.addCondition = function ()
|
||||
{
|
||||
this.conditions.push(new FilterConditionModel(this.conditions));
|
||||
this.conditions.push(new FilterConditionModel());
|
||||
};
|
||||
|
||||
FilterModel.prototype.removeCondition = function (oConditionToDelete)
|
||||
{
|
||||
this.conditions.remove(oConditionToDelete);
|
||||
Utils.delegateRunOnDestroy(oConditionToDelete);
|
||||
};
|
||||
|
||||
FilterModel.prototype.parse = function (oItem)
|
||||
|
|
@ -107,6 +113,29 @@
|
|||
return bResult;
|
||||
};
|
||||
|
||||
FilterModel.prototype.cloneSelf = function ()
|
||||
{
|
||||
var oClone = new FilterModel();
|
||||
|
||||
oClone.enabled(this.enabled());
|
||||
|
||||
oClone.name(this.name());
|
||||
oClone.name.error(this.name.error());
|
||||
|
||||
oClone.conditionsType(this.conditionsType());
|
||||
|
||||
oClone.actionMarkAsRead(this.actionMarkAsRead());
|
||||
oClone.actionValue(this.actionValue());
|
||||
|
||||
oClone.actionType(this.actionType());
|
||||
|
||||
oClone.conditions(_.map(this.conditions(), function (oCondition) {
|
||||
return oCondition.cloneSelf();
|
||||
}));
|
||||
|
||||
return oClone;
|
||||
};
|
||||
|
||||
module.exports = FilterModel;
|
||||
|
||||
}());
|
||||
|
|
@ -16,29 +16,12 @@
|
|||
* @param {*} oKoList
|
||||
* @constructor
|
||||
*/
|
||||
function FilterConditionModel(oKoList)
|
||||
function FilterConditionModel()
|
||||
{
|
||||
AbstractModel.call(this, 'FilterConditionModel');
|
||||
|
||||
this.parentList = oKoList;
|
||||
|
||||
this.field = ko.observable(Enums.FilterConditionField.From);
|
||||
|
||||
this.fieldOptions = [ // TODO i18n
|
||||
{'id': Enums.FilterConditionField.From, 'name': 'From'},
|
||||
{'id': Enums.FilterConditionField.Recipient, 'name': 'Recipient (To or CC)'},
|
||||
{'id': Enums.FilterConditionField.Subject, 'name': 'Subject'}
|
||||
];
|
||||
|
||||
this.type = ko.observable(Enums.FilterConditionType.EqualTo);
|
||||
|
||||
this.typeOptions = [ // TODO i18n
|
||||
{'id': Enums.FilterConditionType.EqualTo, 'name': 'Equal To'},
|
||||
{'id': Enums.FilterConditionType.NotEqualTo, 'name': 'Not Equal To'},
|
||||
{'id': Enums.FilterConditionType.Contains, 'name': 'Contains'},
|
||||
{'id': Enums.FilterConditionType.NotContains, 'name': 'Not Contains'}
|
||||
];
|
||||
|
||||
this.value = ko.observable('');
|
||||
|
||||
this.template = ko.computed(function () {
|
||||
|
|
@ -60,9 +43,24 @@
|
|||
|
||||
_.extend(FilterConditionModel.prototype, AbstractModel.prototype);
|
||||
|
||||
FilterConditionModel.prototype.removeSelf = function ()
|
||||
FilterConditionModel.prototype.toJson = function ()
|
||||
{
|
||||
this.parentList.remove(this);
|
||||
return {
|
||||
'Field': this.field(),
|
||||
'Type': this.type(),
|
||||
'Value': this.value()
|
||||
};
|
||||
};
|
||||
|
||||
FilterConditionModel.prototype.cloneSelf = function ()
|
||||
{
|
||||
var oClone = new FilterConditionModel();
|
||||
|
||||
oClone.field(this.field());
|
||||
oClone.type(this.type());
|
||||
oClone.value(this.value());
|
||||
|
||||
return oClone;
|
||||
};
|
||||
|
||||
module.exports = FilterConditionModel;
|
||||
|
|
|
|||
|
|
@ -6,7 +6,10 @@
|
|||
var
|
||||
ko = require('ko'),
|
||||
|
||||
Utils = require('Common/Utils')
|
||||
Enums = require('Common/Enums'),
|
||||
Utils = require('Common/Utils'),
|
||||
|
||||
Remote = require('Storage/User/Remote')
|
||||
;
|
||||
|
||||
/**
|
||||
|
|
@ -14,14 +17,80 @@
|
|||
*/
|
||||
function FiltersUserSettings()
|
||||
{
|
||||
var self = this;
|
||||
|
||||
this.haveChanges = ko.observable(false);
|
||||
|
||||
this.processText = ko.observable('');
|
||||
this.visibility = ko.observable(false);
|
||||
|
||||
this.filters = ko.observableArray([]);
|
||||
this.filters.loading = ko.observable(false);
|
||||
this.filters.loading = ko.observable(false).extend({'throttle': 200});
|
||||
this.filters.saving = ko.observable(false).extend({'throttle': 200});
|
||||
|
||||
this.filters.subscribe(function () {
|
||||
Utils.windowResize();
|
||||
});
|
||||
|
||||
this.processText = ko.computed(function () {
|
||||
return this.filters.loading() ? Utils.i18n('SETTINGS_FILTERS/LOADING_PROCESS') : '';
|
||||
}, this);
|
||||
|
||||
this.visibility = ko.computed(function () {
|
||||
return '' === this.processText() ? 'hidden' : 'visible';
|
||||
}, this);
|
||||
|
||||
this.filterForDeletion = ko.observable(null).extend({'falseTimeout': 3000}).extend(
|
||||
{'toggleSubscribeProperty': [this, 'deleteAccess']});
|
||||
|
||||
this.saveChanges = Utils.createCommand(this, function () {
|
||||
|
||||
if (!this.filters.saving())
|
||||
{
|
||||
this.filters.saving(true);
|
||||
|
||||
Remote.filtersSave(function (sResult, oData) {
|
||||
|
||||
self.filters.saving(false);
|
||||
|
||||
if (Enums.StorageResultType.Success === sResult && oData && oData.Result)
|
||||
{
|
||||
|
||||
self.haveChanges(false);
|
||||
self.updateList();
|
||||
}
|
||||
|
||||
}, this.filters());
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
}, function () {
|
||||
return this.haveChanges();
|
||||
});
|
||||
|
||||
this.filters.subscribe(function () {
|
||||
this.haveChanges(true);
|
||||
}, this);
|
||||
}
|
||||
|
||||
FiltersUserSettings.prototype.scrollableOptions = function ()
|
||||
{
|
||||
return {
|
||||
// handle: '.drag-handle'
|
||||
};
|
||||
};
|
||||
|
||||
FiltersUserSettings.prototype.updateList = function ()
|
||||
{
|
||||
var self = this;
|
||||
|
||||
this.filters.loading(true);
|
||||
// Remote.filtersGet(function (sResult, oData) {
|
||||
self.filters.loading(false);
|
||||
// });
|
||||
};
|
||||
|
||||
FiltersUserSettings.prototype.deleteFilter = function (oFilter)
|
||||
{
|
||||
this.filters.remove(oFilter);
|
||||
|
|
@ -31,11 +100,60 @@
|
|||
FiltersUserSettings.prototype.addFilter = function ()
|
||||
{
|
||||
var
|
||||
FilterModel = require('Model/Filter')
|
||||
self = this,
|
||||
FilterModel = require('Model/Filter'),
|
||||
oNew = new FilterModel()
|
||||
;
|
||||
|
||||
require('Knoin/Knoin').showScreenPopup(
|
||||
require('View/Popup/Filter'), [new FilterModel()]);
|
||||
require('View/Popup/Filter'), [oNew, function () {
|
||||
self.filters.push(oNew);
|
||||
self.haveChanges(true);
|
||||
}, false]);
|
||||
};
|
||||
|
||||
FiltersUserSettings.prototype.editFilter = function (oEdit)
|
||||
{
|
||||
var
|
||||
self = this,
|
||||
oCloned = oEdit.cloneSelf()
|
||||
;
|
||||
|
||||
require('Knoin/Knoin').showScreenPopup(
|
||||
require('View/Popup/Filter'), [oCloned, function () {
|
||||
|
||||
var
|
||||
oFilters = self.filters(),
|
||||
iIndex = oFilters.indexOf(oEdit)
|
||||
;
|
||||
|
||||
if (-1 < iIndex && oFilters[iIndex])
|
||||
{
|
||||
Utils.delegateRunOnDestroy(oFilters[iIndex]);
|
||||
oFilters[iIndex] = oCloned;
|
||||
|
||||
self.filters(oFilters);
|
||||
self.haveChanges(true);
|
||||
}
|
||||
|
||||
}, false]);
|
||||
};
|
||||
|
||||
FiltersUserSettings.prototype.onBuild = function (oDom)
|
||||
{
|
||||
var self = this;
|
||||
|
||||
oDom
|
||||
.on('click', '.filter-item .e-action', function () {
|
||||
var oFilterItem = ko.dataFor(this);
|
||||
if (oFilterItem)
|
||||
{
|
||||
self.editFilter(oFilterItem);
|
||||
}
|
||||
})
|
||||
;
|
||||
|
||||
this.updateList();
|
||||
};
|
||||
|
||||
module.exports = FiltersUserSettings;
|
||||
|
|
|
|||
|
|
@ -129,15 +129,11 @@
|
|||
{
|
||||
this.identityForDeletion(null);
|
||||
|
||||
var
|
||||
fRemoveFolder = function (oIdentity) {
|
||||
return oIdentityToRemove === oIdentity;
|
||||
}
|
||||
;
|
||||
|
||||
if (oIdentityToRemove)
|
||||
{
|
||||
this.identities.remove(fRemoveFolder);
|
||||
this.identities.remove(function (oIdentity) {
|
||||
return oIdentityToRemove === oIdentity;
|
||||
});
|
||||
|
||||
Remote.identityDelete(function () {
|
||||
require('App/User').accountsAndIdentities();
|
||||
|
|
|
|||
|
|
@ -631,8 +631,8 @@
|
|||
iUtc = moment().unix(),
|
||||
iTimeout = iUtc - 60 * 5,
|
||||
aTimeouts = [],
|
||||
sInboxFolderName = Cache.getFolderInboxName(),
|
||||
fSearchFunction = function (aList) {
|
||||
var sInboxFolderName = Cache.getFolderInboxName();
|
||||
_.each(aList, function (oFolder) {
|
||||
if (oFolder && sInboxFolderName !== oFolder.fullNameRaw &&
|
||||
oFolder.selectable && oFolder.existen &&
|
||||
|
|
@ -653,12 +653,9 @@
|
|||
fSearchFunction(this.folderList());
|
||||
|
||||
aTimeouts.sort(function(a, b) {
|
||||
if (a[0] < b[0])
|
||||
{
|
||||
if (a[0] < b[0]) {
|
||||
return -1;
|
||||
}
|
||||
else if (a[0] > b[0])
|
||||
{
|
||||
} else if (a[0] > b[0]) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -221,6 +221,35 @@
|
|||
this.defaultRequest(fCallback, 'AccountsAndIdentities');
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {?Function} fCallback
|
||||
*/
|
||||
RemoteUserStorage.prototype.accountsCounts = function (fCallback)
|
||||
{
|
||||
this.defaultRequest(fCallback, 'AccountsCounts');
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {?Function} fCallback
|
||||
*/
|
||||
RemoteUserStorage.prototype.filtersSave = function (fCallback, aFilters)
|
||||
{
|
||||
this.defaultRequest(fCallback, 'FiltersSave', {
|
||||
'Filters': _.map(aFilters, function (oItem) {
|
||||
return oItem.toJson();
|
||||
})
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {?Function} fCallback
|
||||
*/
|
||||
RemoteUserStorage.prototype.filtersGet = function (fCallback)
|
||||
{
|
||||
this.defaultRequest(fCallback, 'Filters', {
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {?Function} fCallback
|
||||
* @param {string} sFolderFullNameRaw
|
||||
|
|
|
|||
|
|
@ -55,5 +55,11 @@
|
|||
cursor: pointer;
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
&.ui-sortable-helper {
|
||||
.delete-filter {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,34 +1,60 @@
|
|||
|
||||
.b-system-drop-down {
|
||||
|
||||
.b-toolbar {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
height: 30px;
|
||||
padding: 10px @rlLowMargin;
|
||||
z-index: 103;
|
||||
}
|
||||
|
||||
.e-facebook-name {
|
||||
display: inline-block;
|
||||
padding-top: 4px;
|
||||
}
|
||||
|
||||
.btn.system-dropdown {
|
||||
padding-left: 10px;
|
||||
padding-right: 10px;
|
||||
}
|
||||
|
||||
.button-fb-logout {
|
||||
margin: 5px;
|
||||
}
|
||||
|
||||
.email-title {
|
||||
display: inline-block;
|
||||
max-width: 200px;
|
||||
text-align: left;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.b-system-drop-down {
|
||||
|
||||
.b-toolbar {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
height: 30px;
|
||||
padding: 10px @rlLowMargin;
|
||||
z-index: 103;
|
||||
}
|
||||
|
||||
.e-facebook-name {
|
||||
display: inline-block;
|
||||
padding-top: 4px;
|
||||
}
|
||||
|
||||
.btn.system-dropdown {
|
||||
padding-left: 10px;
|
||||
padding-right: 10px;
|
||||
}
|
||||
|
||||
.button-fb-logout {
|
||||
margin: 5px;
|
||||
}
|
||||
|
||||
.email-title {
|
||||
display: inline-block;
|
||||
max-width: 200px;
|
||||
text-align: left;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
margin-right: 28px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.account-item {
|
||||
|
||||
.icon-ok {
|
||||
display: none;
|
||||
}
|
||||
|
||||
&.current {
|
||||
.icon-ok {
|
||||
display: inline-block;
|
||||
}
|
||||
.icon-user {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.counter {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.g-ui-menu .e-link.account-item {
|
||||
padding-right: 5px;
|
||||
}
|
||||
}
|
||||
|
|
@ -1180,14 +1180,13 @@
|
|||
if (window.google && window.google.picker)
|
||||
{
|
||||
var drivePicker = new window.google.picker.PickerBuilder()
|
||||
.addView(
|
||||
new window.google.picker.DocsView()
|
||||
.setIncludeFolders(true)
|
||||
)
|
||||
// .addView(window.google.picker.ViewId.FOLDERS)
|
||||
.addView(window.google.picker.ViewId.DOCS)
|
||||
.setAppId(Settings.settingsGet('GoogleClientID'))
|
||||
.setOAuthToken(oOauthToken.access_token)
|
||||
.setCallback(_.bind(self.driveCallback, self, oOauthToken.access_token))
|
||||
.enableFeature(window.google.picker.Feature.NAV_HIDDEN)
|
||||
// .setOrigin(window.location.protocol + '//' + window.location.host)
|
||||
.build()
|
||||
;
|
||||
|
||||
|
|
@ -1205,14 +1204,9 @@
|
|||
|
||||
window.gapi.load('auth', {'callback': function () {
|
||||
|
||||
var oAuthToken = window.gapi.auth.getToken();
|
||||
if (!oAuthToken)
|
||||
{
|
||||
window.gapi.auth.authorize({
|
||||
'client_id': Settings.settingsGet('GoogleClientID'),
|
||||
'scope': 'https://www.googleapis.com/auth/drive.readonly',
|
||||
'immediate': true
|
||||
}, function (oAuthResult) {
|
||||
var
|
||||
oAuthToken = window.gapi.auth.getToken(),
|
||||
fResult = function (oAuthResult) {
|
||||
if (oAuthResult && !oAuthResult.error)
|
||||
{
|
||||
var oAuthToken = window.gapi.auth.getToken();
|
||||
|
|
@ -1220,23 +1214,29 @@
|
|||
{
|
||||
self.driveCreatePiker(oAuthToken);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
|
||||
return false;
|
||||
}
|
||||
;
|
||||
|
||||
if (!oAuthToken)
|
||||
{
|
||||
window.gapi.auth.authorize({
|
||||
'client_id': Settings.settingsGet('GoogleClientID'),
|
||||
'scope': 'https://www.googleapis.com/auth/drive.readonly',
|
||||
'immediate': true
|
||||
}, function (oAuthResult) {
|
||||
|
||||
if (!fResult(oAuthResult))
|
||||
{
|
||||
window.gapi.auth.authorize({
|
||||
'client_id': Settings.settingsGet('GoogleClientID'),
|
||||
'scope': 'https://www.googleapis.com/auth/drive.readonly',
|
||||
'immediate': false
|
||||
}, function (oAuthResult) {
|
||||
if (oAuthResult && !oAuthResult.error)
|
||||
{
|
||||
var oAuthToken = window.gapi.auth.getToken();
|
||||
if (oAuthToken)
|
||||
{
|
||||
self.driveCreatePiker(oAuthToken);
|
||||
}
|
||||
}
|
||||
});
|
||||
}, fResult);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
ko = require('ko'),
|
||||
|
||||
Consts = require('Common/Consts'),
|
||||
Enums = require('Common/Enums'),
|
||||
Utils = require('Common/Utils'),
|
||||
|
||||
Data = require('Storage/User/Data'),
|
||||
|
|
@ -24,28 +25,102 @@
|
|||
{
|
||||
AbstractView.call(this, 'Popups', 'PopupsFilter');
|
||||
|
||||
this.isNew = ko.observable(true);
|
||||
|
||||
this.fTrueCallback = null;
|
||||
this.filter = ko.observable(null);
|
||||
|
||||
this.selectedFolderValue = ko.observable(Consts.Values.UnuseOptionValue);
|
||||
this.folderSelectList = Data.folderMenuForMove;
|
||||
this.defautOptionsAfterRender = Utils.defautOptionsAfterRender;
|
||||
|
||||
this.saveFilter = Utils.createCommand(this, function () {
|
||||
|
||||
if (this.filter())
|
||||
{
|
||||
if ('' === this.filter().name())
|
||||
{
|
||||
this.filter().name.error(true);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this.fTrueCallback)
|
||||
{
|
||||
this.fTrueCallback(this.filter());
|
||||
}
|
||||
|
||||
if (this.modalVisibility())
|
||||
{
|
||||
Utils.delegateRun(this, 'closeCommand');
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
|
||||
this.actionTypeOptions = [
|
||||
{'id': Enums.FiltersAction.None, 'name': 'None @i18n'},
|
||||
{'id': Enums.FiltersAction.Move, 'name': ' Move to @i18n'},
|
||||
// {'id': Enums.FiltersAction.Forward, 'name': 'Forward to @i18n'},
|
||||
{'id': Enums.FiltersAction.Discard, 'name': 'Discard @i18n'}
|
||||
];
|
||||
|
||||
this.fieldOptions = [
|
||||
{'id': Enums.FilterConditionField.From, 'name': 'From @i18n'},
|
||||
{'id': Enums.FilterConditionField.Recipient, 'name': 'Recipient (To or CC) @i18n'},
|
||||
{'id': Enums.FilterConditionField.Subject, 'name': 'Subject @i18n'}
|
||||
];
|
||||
|
||||
this.typeOptions = [
|
||||
{'id': Enums.FilterConditionType.EqualTo, 'name': 'Equal To @i18n'},
|
||||
{'id': Enums.FilterConditionType.NotEqualTo, 'name': 'Not Equal To @i18n'},
|
||||
{'id': Enums.FilterConditionType.Contains, 'name': 'Contains @i18n'},
|
||||
{'id': Enums.FilterConditionType.NotContains, 'name': 'Not Contains @i18n'}
|
||||
];
|
||||
|
||||
kn.constructorEnd(this);
|
||||
}
|
||||
|
||||
kn.extendAsViewModel(['View/Popup/Filter', 'PopupsFilterViewModel'], FilterPopupView);
|
||||
_.extend(FilterPopupView.prototype, AbstractView.prototype);
|
||||
|
||||
FilterPopupView.prototype.clearPopup = function ()
|
||||
FilterPopupView.prototype.removeCondition = function (oConditionToDelete)
|
||||
{
|
||||
// TODO
|
||||
if (this.filter())
|
||||
{
|
||||
this.filter().removeCondition(oConditionToDelete);
|
||||
}
|
||||
};
|
||||
|
||||
FilterPopupView.prototype.onShow = function (oFilter)
|
||||
FilterPopupView.prototype.clearPopup = function ()
|
||||
{
|
||||
this.isNew(true);
|
||||
|
||||
this.fTrueCallback = null;
|
||||
this.filter(null);
|
||||
};
|
||||
|
||||
FilterPopupView.prototype.onShow = function (oFilter, fTrueCallback, bEdit)
|
||||
{
|
||||
this.clearPopup();
|
||||
|
||||
this.fTrueCallback = fTrueCallback;
|
||||
this.filter(oFilter);
|
||||
|
||||
this.isNew(!bEdit);
|
||||
|
||||
if (!bEdit && oFilter)
|
||||
{
|
||||
oFilter.name.focused(true);
|
||||
}
|
||||
};
|
||||
|
||||
FilterPopupView.prototype.onFocus = function ()
|
||||
{
|
||||
if (this.isNew() && this.filter())
|
||||
{
|
||||
this.filter().name.focused(true);
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = FilterPopupView;
|
||||
|
|
|
|||
|
|
@ -319,7 +319,7 @@
|
|||
}
|
||||
|
||||
var
|
||||
oEl = Utils.draggeblePlace(),
|
||||
oEl = Utils.draggablePlace(),
|
||||
aUids = Data.messageListCheckedOrSelectedUidsWithSubMails()
|
||||
;
|
||||
|
||||
|
|
|
|||
|
|
@ -144,6 +144,7 @@ cfg.paths.js = {
|
|||
'vendors/underscore/1.6.0/underscore-min.js',
|
||||
'vendors/jquery/jquery-1.11.1.min.js',
|
||||
'vendors/jquery-ui/js/jquery-ui-1.10.3.custom.min.js',
|
||||
// 'vendors/jquery-ui.touch-punch/jquery.ui.touch-punch.min.js',
|
||||
'vendors/jquery-cookie/jquery.cookie-1.4.0.min.js',
|
||||
'vendors/jquery-finger/jquery.finger.min.js',
|
||||
'vendors/jquery-mousewheel/jquery.mousewheel-3.1.4.min.js',
|
||||
|
|
@ -161,6 +162,7 @@ cfg.paths.js = {
|
|||
'vendors/routes/crossroads.min.js',
|
||||
'vendors/knockout/knockout-3.2.0.js',
|
||||
'vendors/knockout-projections/knockout-projections-1.0.0.min.js',
|
||||
'vendors/knockout-sortable/knockout-sortable.min.js',
|
||||
'vendors/ssm/ssm.min.js',
|
||||
'vendors/jua/jua.min.js',
|
||||
'vendors/Autolinker/Autolinker.min.js',
|
||||
|
|
@ -169,7 +171,6 @@ cfg.paths.js = {
|
|||
'vendors/jsencrypt/jsencrypt.min.js',
|
||||
'vendors/keymaster/keymaster.min.js',
|
||||
'vendors/ifvisible/ifvisible.min.js',
|
||||
// 'vendors/jquery-magnific-popup/jquery.magnific-popup.min.js',
|
||||
'vendors/bootstrap/js/bootstrap.min.js'
|
||||
]
|
||||
},
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
"name": "RainLoop",
|
||||
"title": "RainLoop Webmail",
|
||||
"version": "1.7.0",
|
||||
"release": "210",
|
||||
"release": "211",
|
||||
"description": "Simple, modern & fast web-based email client",
|
||||
"homepage": "http://rainloop.net",
|
||||
"main": "gulpfile.js",
|
||||
|
|
|
|||
|
|
@ -2031,6 +2031,28 @@ class Actions
|
|||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*
|
||||
* @throws \MailSo\Base\Exceptions\Exception
|
||||
*/
|
||||
public function DoFilters()
|
||||
{
|
||||
return $this->TrueResponse(__FUNCTION__);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*
|
||||
* @throws \MailSo\Base\Exceptions\Exception
|
||||
*/
|
||||
public function DoFiltersSave()
|
||||
{
|
||||
sleep(2);
|
||||
return $this->TrueResponse(__FUNCTION__);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*
|
||||
|
|
@ -2246,6 +2268,35 @@ class Actions
|
|||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*
|
||||
* @throws \MailSo\Base\Exceptions\Exception
|
||||
*/
|
||||
public function DoAccountsCounts()
|
||||
{
|
||||
$oAccount = $this->getAccountFromToken();
|
||||
|
||||
$aCounts = array();
|
||||
if ($this->Config()->Get('webmail', 'allow_additional_accounts', true))
|
||||
{
|
||||
$mAccounts = $this->GetAccounts($oAccount);
|
||||
foreach ($mAccounts as $sEmail => $sHash)
|
||||
{
|
||||
$aCounts[] = array(\MailSo\Base\Utils::IdnToUtf8($sEmail), 0);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$aCounts[] = array(\MailSo\Base\Utils::IdnToUtf8($oAccount->Email()), 0);
|
||||
}
|
||||
|
||||
return $this->DefaultResponse(__FUNCTION__, array(
|
||||
'Complete' => true,
|
||||
'Counts' => $aCounts
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*
|
||||
|
|
|
|||
|
|
@ -65,8 +65,8 @@
|
|||
<div data-bind="visible: licensing()">
|
||||
<div class="alert alert-success span8" style="margin-left: 0; padding-top: 20px" data-bind="visible: licenseValid() && '' === licenseError()">
|
||||
<h4>
|
||||
<span data-bind="visible: licenseIsUnlim()">Lifetime (Premium)</span>
|
||||
<span data-bind="visible: !licenseIsUnlim()">Premium</span>
|
||||
Premium
|
||||
<span data-bind="visible: licenseIsUnlim()">(Lifetime)</span>
|
||||
</h4>
|
||||
<p data-bind="visible: 0 < licenseExpired()" style="padding-top: 10px">
|
||||
<b>Subscription expires:</b>
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@
|
|||
<div class="span5" data-bind="css: { 'testing-done': testingDone, 'testing-error': testingImapError }">
|
||||
<div class="legend imap-header">
|
||||
<span data-placement="bottom" data-bind="tooltipForTest: testingImapErrorDesc">
|
||||
<span data-bind="text: sieveSettings() ? 'SIEVE (Filters)' : 'IMAP'">IMAP</span>
|
||||
<span data-bind="text: sieveSettings() ? 'SIEVE' : 'IMAP'">IMAP</span>
|
||||
</span>
|
||||
</div>
|
||||
<div data-bind="visible: !sieveSettings()">
|
||||
|
|
@ -73,7 +73,7 @@
|
|||
<span data-bind="command: sieveCommand">
|
||||
<i class="icon-filter"></i>
|
||||
|
||||
<a href="#" class="g-ui-link">Sieve (Filetrs) configuration</a>
|
||||
<a href="#" class="g-ui-link">Sieve configuration</a>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -4,29 +4,34 @@
|
|||
<div class="modal-header">
|
||||
<button type="button" class="close" data-bind="command: cancelCommand">×</button>
|
||||
<h3>
|
||||
<span class="i18n" data-i18n-text="SETTINGS_FILTERS/TITLE_CREATE_FILTER"></span>
|
||||
<span class="i18n" data-i18n-text="SETTINGS_FILTERS/TITLE_CREATE_FILTER" data-bind="visible: isNew"></span>
|
||||
<span class="i18n" data-i18n-text="SETTINGS_FILTERS/TITLE_EDIT_FILTER" data-bind="visible: !isNew()"></span>
|
||||
</h3>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="row filter" data-bind="with: filter">
|
||||
<div class="span9">
|
||||
<br />
|
||||
<input type="text" class="span5" data-bind="value: name" placeholder="Name" />
|
||||
<br />
|
||||
<br />
|
||||
|
||||
<div class="control-group" data-bind="css: {'error': name.error}">
|
||||
<div class="controls">
|
||||
<input type="text" class="span5" data-bind="value: name, hasFocus: name.focused" placeholder="Name"
|
||||
autocorrect="off" autocapitalize="off" spellcheck="false" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="legend">
|
||||
<span>
|
||||
Conditions
|
||||
Conditions @i18n
|
||||
</span>
|
||||
</div>
|
||||
<div>
|
||||
<div data-bind="visible: 1 < conditions().length">
|
||||
<select class="span4" data-bind="value: conditionsType">
|
||||
<option value="All">
|
||||
Matching all of the following rules
|
||||
Matching all of the following rules @i18n
|
||||
</option>
|
||||
<option value="Any">
|
||||
Matching any of the following rules
|
||||
Matching any of the following rules @i18n
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
|
|
@ -34,7 +39,7 @@
|
|||
<div data-bind="template: {'name': template(), 'data': $data}"></div>
|
||||
</div>
|
||||
<div data-bind="visible: 0 === conditions().length">
|
||||
All incoming messages
|
||||
All incoming messages @i18n
|
||||
</div>
|
||||
<br />
|
||||
<a class="btn" data-bind="click: addCondition, i18nInit: true">
|
||||
|
|
@ -49,32 +54,23 @@
|
|||
Actions
|
||||
</span>
|
||||
</div>
|
||||
<div data-bind="template: {'name': actionTemplate()}"></div>
|
||||
<br />
|
||||
<div data-bind="component: {
|
||||
name: 'Checkbox',
|
||||
params: {
|
||||
label: 'Mark as read',
|
||||
label: 'Mark as read @i18n',
|
||||
value: actionMarkAsRead
|
||||
}
|
||||
}"></div>
|
||||
|
||||
<div data-bind="component: {
|
||||
name: 'Checkbox',
|
||||
params: {
|
||||
label: 'Skip other filters',
|
||||
enable: enableSkipOtherFilters,
|
||||
value: actionSkipOtherFiltersResult
|
||||
}
|
||||
}"></div>
|
||||
<br />
|
||||
<div data-bind="template: {'name': actionTemplate()}"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<a class="btn buttonSave">
|
||||
<i class="icon-folder-add"></i>
|
||||
<a class="btn buttonSave" data-bind="command: saveFilter">
|
||||
<i class="icon-ok"></i>
|
||||
|
||||
<span class="i18n" data-i18n-text="SETTINGS_FILTERS/BUTTON_CREATE"></span>
|
||||
<span class="i18n" data-i18n-text="SETTINGS_FILTERS/BUTTON_DONE"></span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -5,15 +5,57 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div data-bind="foreach: filters, i18nUpdate: filters">
|
||||
<span data-bind="text: name" ></span>
|
||||
<br />
|
||||
<div class="span8">
|
||||
<a class="btn" data-bind="click: addFilter">
|
||||
<i class="icon-plus"></i>
|
||||
|
||||
<span class="i18n" data-i18n-text="SETTINGS_FILTERS/BUTTON_ADD_FILTER"></span>
|
||||
</a>
|
||||
|
||||
<a class="btn" data-bind="command: saveChanges">
|
||||
<i data-bind="css: {'icon-floppy': !filters.saving(), 'icon-spinner animated': filters.saving()}"></i>
|
||||
|
||||
<span class="i18n" data-i18n-text="SETTINGS_FILTERS/BUTTON_SAVE"></span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="span8">
|
||||
<div class="process-place g-ui-user-select-none" data-bind="style: {'visibility': visibility }">
|
||||
<i class="icon-spinner animated"></i>
|
||||
|
||||
<span data-bind="text: processText"></span>
|
||||
</div>
|
||||
<table class="table table-hover list-table g-ui-user-select-none" data-bind="i18nUpdate: filters">
|
||||
<colgroup>
|
||||
<col style="width: 30px" />
|
||||
<col />
|
||||
<col style="width: 140px" />
|
||||
<col style="width: 1%" />
|
||||
</colgroup>
|
||||
<tbody data-bind="sortable: {data: filters, options: scrollableOptions()}">
|
||||
<tr class="filter-item">
|
||||
<td>
|
||||
<span class="disabled-filter" data-bind="click: function () { $root.haveChanges(true); enabled(!enabled()); }">
|
||||
<i data-bind="css: {'icon-checkbox-checked': enabled, 'icon-checkbox-unchecked': !enabled()}"></i>
|
||||
</span>
|
||||
</td>
|
||||
<td class="e-action">
|
||||
<span class="filter-name" data-bind="text: name()"></span>
|
||||
</td>
|
||||
<td>
|
||||
<a class="btn btn-small btn-small-small btn-danger pull-right button-delete button-delete-transitions" data-bind="css: {'delete-access': deleteAccess()}, click: function(oFilter) { $root.deleteFilter(oFilter); }">
|
||||
<span class="i18n" data-i18n-text="SETTINGS_FILTERS/DELETING_ASK"></span>
|
||||
</a>
|
||||
</td>
|
||||
<td>
|
||||
<span class="delete-filter" data-bind="visible: !deleteAccess() && canBeDalete(), click: function (oFilter) { $root.filterForDeletion(oFilter); }">
|
||||
<i class="icon-trash"></i>
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<br />
|
||||
<a class="btn" data-bind="click: addFilter">
|
||||
<i class="icon-filter"></i>
|
||||
|
||||
<span class="i18n" data-i18n-text="SETTINGS_FILTERS/BUTTON_ADD_FILTER"></span>
|
||||
</a>
|
||||
</div>
|
||||
|
|
@ -1 +1 @@
|
|||
<select data-bind="options: actionTypeOptions, value: actionType, optionsText: 'name', optionsValue: 'id'"></select>
|
||||
<select data-bind="options: $root.actionTypeOptions, value: actionType, optionsText: 'name', optionsValue: 'id'"></select>
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
<select data-bind="options: actionTypeOptions, value: actionType, optionsText: 'name', optionsValue: 'id'"></select>
|
||||
<select data-bind="options: $root.actionTypeOptions, value: actionType, optionsText: 'name', optionsValue: 'id'"></select>
|
||||
|
||||
<select data-bind="options: $root.folderSelectList, value: $root.selectedFolderValue,
|
||||
optionsText: 'name', optionsValue: 'id', optionsAfterRender: $root.defautOptionsAfterRender"></select>
|
||||
|
|
@ -1,3 +1,3 @@
|
|||
<select data-bind="options: actionTypeOptions, value: actionType, optionsText: 'name', optionsValue: 'id'"></select>
|
||||
<select data-bind="options: $root.actionTypeOptions, value: actionType, optionsText: 'name', optionsValue: 'id'"></select>
|
||||
|
||||
<input type="text" data-bind="value: actionValue" />
|
||||
|
|
@ -1,9 +1,9 @@
|
|||
<select class="span3" data-bind="options: fieldOptions, value: field, optionsText: 'name', optionsValue: 'id'"></select>
|
||||
<select class="span3" data-bind="options: $root.fieldOptions, value: field, optionsText: 'name', optionsValue: 'id'"></select>
|
||||
|
||||
<select class="span2" data-bind="options: typeOptions, value: type, optionsText: 'name', optionsValue: 'id'"></select>
|
||||
<select class="span2" data-bind="options: $root.typeOptions, value: type, optionsText: 'name', optionsValue: 'id'"></select>
|
||||
|
||||
<input class="span3" type="text" data-bind="value: value" />
|
||||
|
||||
<span class="delete-action button-delete pull-right" data-bind="click: removeSelf">
|
||||
<span class="delete-action button-delete pull-right" data-bind="click: function (oCondition) { $root.removeCondition(oCondition); }">
|
||||
<i class="icon-trash"></i>
|
||||
</span>
|
||||
|
|
@ -11,19 +11,26 @@
|
|||
<span class="caret"></span>
|
||||
</a>
|
||||
<ul class="dropdown-menu g-ui-menu" tabindex="-1" role="menu" aria-labelledby="top-system-dropdown-id">
|
||||
|
||||
<!-- ko if: accounts().length -->
|
||||
<!-- ko foreach: accounts -->
|
||||
<li class="e-item" role="presentation">
|
||||
<a class="e-link menuitem" href="#" data-bind="click: $root.accountClick, attr: {'href': changeAccountLink() }">
|
||||
<i class="icon-ok" data-bind="visible: $root.accountEmail() === email"></i>
|
||||
<i class="icon-user" data-bind="visible: $root.accountEmail() !== email"></i>
|
||||
|
||||
<span data-bind="text: email"></span>
|
||||
</a>
|
||||
</li>
|
||||
<!-- /ko -->
|
||||
<li class="divider" role="presentation"></li>
|
||||
<!-- ko foreach: accounts -->
|
||||
<li class="e-item" role="presentation">
|
||||
<a class="e-link menuitem account-item" href="#" data-bind="click: $root.accountClick,
|
||||
attr: {'href': changeAccountLink()}, css: {current: $root.accountEmail() === email}">
|
||||
<b class="pull-right counter" data-bind="visible: 0 < count()">
|
||||
<span data-bind="text: count, visible: 100 > count()"></span>
|
||||
<span data-bind="visible: 99 < count()">99+</span>
|
||||
</b>
|
||||
<i class="icon-ok"></i>
|
||||
<i class="icon-user"></i>
|
||||
|
||||
<span class="email-title" data-bind="text: email"></span>
|
||||
</a>
|
||||
</li>
|
||||
<!-- /ko -->
|
||||
<li class="divider" role="presentation"></li>
|
||||
<!-- /ko -->
|
||||
|
||||
<!-- ko if: capaAdditionalAccounts -->
|
||||
<li class="e-item" role="presentation">
|
||||
<a class="e-link menuitem" href="#" tabindex="-1" data-bind="click: addAccountClick">
|
||||
|
|
|
|||
|
|
@ -364,12 +364,6 @@ LABEL_CHANGE_PASSWORD_NAME = "Парола"
|
|||
LABEL_OPEN_PGP_NAME = "OpenPGP"
|
||||
BUTTON_BACK = "Назад"
|
||||
|
||||
[SETTINGS_FILTERS]
|
||||
LEGEND_FILTERS = "Филтри"
|
||||
BUTTON_ADD_FILTER = "Добавяне на филтър"
|
||||
BUTTON_DELETE_FILTER = "Изтриване на филтър"
|
||||
BUTTON_ADD_CONDITION = "Добавяне на условие"
|
||||
|
||||
[SETTINGS_IDENTITY]
|
||||
LEGEND_IDENTITY = "Идентичност"
|
||||
LABEL_DISPLAY_NAME = "Име"
|
||||
|
|
|
|||
|
|
@ -356,6 +356,7 @@ LABEL_FOLDERS_NAME = "Ordner"
|
|||
LABEL_ACCOUNTS_NAME = "Konten"
|
||||
LABEL_IDENTITY_NAME = "Identität"
|
||||
LABEL_IDENTITIES_NAME = "Identitäten"
|
||||
LABEL_FILTERS_NAME = "Filters"
|
||||
LABEL_SECURITY_NAME = "Sicherheit"
|
||||
LABEL_SOCIAL_NAME = "Sozial"
|
||||
LABEL_THEMES_NAME = "Vorlagen"
|
||||
|
|
|
|||
|
|
@ -366,11 +366,17 @@ BUTTON_BACK = "Back"
|
|||
|
||||
[SETTINGS_FILTERS]
|
||||
TITLE_CREATE_FILTER = "Create a filter?"
|
||||
BUTTON_CREATE = "Create"
|
||||
TITLE_EDIT_FILTER = "Update filter?"
|
||||
LEGEND_FILTERS = "Filters"
|
||||
BUTTON_SAVE = "Save"
|
||||
BUTTON_DONE = "Done"
|
||||
BUTTON_ADD_FILTER = "Add Filter"
|
||||
BUTTON_SAVE_FILTER = "Save Filter"
|
||||
BUTTON_DELETE_FILTER = "Delete Filter"
|
||||
BUTTON_ADD_CONDITION = "Add Condition"
|
||||
BUTTON_DELETE = "Delete"
|
||||
LOADING_PROCESS = "Updating filter list"
|
||||
DELETING_ASK = "Are you sure?"
|
||||
|
||||
[SETTINGS_IDENTITY]
|
||||
LEGEND_IDENTITY = "Identity"
|
||||
|
|
|
|||
|
|
@ -355,6 +355,7 @@ LABEL_FOLDERS_NAME = "Carpetas"
|
|||
LABEL_ACCOUNTS_NAME = "Cuentas"
|
||||
LABEL_IDENTITY_NAME = "Identidad"
|
||||
LABEL_IDENTITIES_NAME = "Identidades"
|
||||
LABEL_FILTERS_NAME = "Filters"
|
||||
LABEL_SECURITY_NAME = "Seguridad"
|
||||
LABEL_SOCIAL_NAME = "Social"
|
||||
LABEL_THEMES_NAME = "Temas"
|
||||
|
|
|
|||
|
|
@ -355,6 +355,7 @@ LABEL_FOLDERS_NAME = "Dossiers"
|
|||
LABEL_ACCOUNTS_NAME = "Comptes"
|
||||
LABEL_IDENTITY_NAME = "Identité"
|
||||
LABEL_IDENTITIES_NAME = "Identities"
|
||||
LABEL_FILTERS_NAME = "Filters"
|
||||
LABEL_SECURITY_NAME = "Securité"
|
||||
LABEL_SOCIAL_NAME = "Social"
|
||||
LABEL_THEMES_NAME = "Thèmes"
|
||||
|
|
|
|||
|
|
@ -355,6 +355,7 @@ LABEL_FOLDERS_NAME = "Könyvtárak"
|
|||
LABEL_ACCOUNTS_NAME = "Fiókok"
|
||||
LABEL_IDENTITY_NAME = "Identitás"
|
||||
LABEL_IDENTITIES_NAME = "Identitások"
|
||||
LABEL_FILTERS_NAME = "Filters"
|
||||
LABEL_SECURITY_NAME = "Security"
|
||||
LABEL_SOCIAL_NAME = "Közösség"
|
||||
LABEL_THEMES_NAME = "Sablonok"
|
||||
|
|
|
|||
|
|
@ -355,6 +355,7 @@ LABEL_FOLDERS_NAME = "Möppur"
|
|||
LABEL_ACCOUNTS_NAME = "Aðgangar"
|
||||
LABEL_IDENTITY_NAME = "Identity"
|
||||
LABEL_IDENTITIES_NAME = "Identities"
|
||||
LABEL_FILTERS_NAME = "Filters"
|
||||
LABEL_SECURITY_NAME = "Security"
|
||||
LABEL_SOCIAL_NAMELABEL_SOCIAL_NAME = "Félagsmiðlar"
|
||||
LABEL_THEMES_NAME = "Þemur"
|
||||
|
|
|
|||
|
|
@ -356,6 +356,7 @@ LABEL_FOLDERS_NAME = "Cartelle"
|
|||
LABEL_ACCOUNTS_NAME = "Account"
|
||||
LABEL_IDENTITY_NAME = "Identità"
|
||||
LABEL_IDENTITIES_NAME = "Identità"
|
||||
LABEL_FILTERS_NAME = "Filters"
|
||||
LABEL_SECURITY_NAME = "Sicurezza"
|
||||
LABEL_SOCIAL_NAME = "Social"
|
||||
LABEL_THEMES_NAME = "Temi"
|
||||
|
|
|
|||
|
|
@ -355,6 +355,7 @@ LABEL_FOLDERS_NAME = "フォルダ"
|
|||
LABEL_ACCOUNTS_NAME = "アカウント"
|
||||
LABEL_IDENTITY_NAME = "Identity"
|
||||
LABEL_IDENTITIES_NAME = "表示名"
|
||||
LABEL_FILTERS_NAME = "Filters"
|
||||
LABEL_SECURITY_NAME = "Security"
|
||||
LABEL_SOCIAL_NAME = "Social"
|
||||
LABEL_THEMES_NAME = "テーマ"
|
||||
|
|
|
|||
|
|
@ -352,6 +352,7 @@ LABEL_FOLDERS_NAME = "메일함"
|
|||
LABEL_ACCOUNTS_NAME = "계정"
|
||||
LABEL_IDENTITY_NAME = "신원"
|
||||
LABEL_IDENTITIES_NAME = "신원"
|
||||
LABEL_FILTERS_NAME = "Filters"
|
||||
LABEL_SECURITY_NAME = "Security"
|
||||
LABEL_SOCIAL_NAME = "소셜"
|
||||
LABEL_THEMES_NAME = "테마"
|
||||
|
|
|
|||
|
|
@ -364,12 +364,6 @@ LABEL_CHANGE_PASSWORD_NAME = "Slaptažodis"
|
|||
LABEL_OPEN_PGP_NAME = "OpenPGP"
|
||||
BUTTON_BACK = "Atgal"
|
||||
|
||||
[SETTINGS_FILTERS]
|
||||
LEGEND_FILTERS = "Filtrai"
|
||||
BUTTON_ADD_FILTER = "Sukurti filtrą"
|
||||
BUTTON_DELETE_FILTER = "Panaikinti filtrą"
|
||||
BUTTON_ADD_CONDITION = "Pridėti sąlygas"
|
||||
|
||||
[SETTINGS_IDENTITY]
|
||||
LEGEND_IDENTITY = "Tapatybė"
|
||||
LABEL_DISPLAY_NAME = "Vardas"
|
||||
|
|
|
|||
|
|
@ -355,6 +355,7 @@ LABEL_FOLDERS_NAME = "Mapes"
|
|||
LABEL_ACCOUNTS_NAME = "Konti"
|
||||
LABEL_IDENTITY_NAME = "Identity"
|
||||
LABEL_IDENTITIES_NAME = "Identities"
|
||||
LABEL_FILTERS_NAME = "Filters"
|
||||
LABEL_SECURITY_NAME = "Security"
|
||||
LABEL_SOCIAL_NAME = "Sociālie"
|
||||
LABEL_THEMES_NAME = "Tēmas"
|
||||
|
|
|
|||
|
|
@ -355,6 +355,7 @@ LABEL_FOLDERS_NAME = "Mappen"
|
|||
LABEL_ACCOUNTS_NAME = "Accounts"
|
||||
LABEL_IDENTITY_NAME = "Identiteit"
|
||||
LABEL_IDENTITIES_NAME = "Identiteiten"
|
||||
LABEL_FILTERS_NAME = "Filters"
|
||||
LABEL_SECURITY_NAME = "Beveiliging"
|
||||
LABEL_SOCIAL_NAME = "Social"
|
||||
LABEL_THEMES_NAME = "Thema's"
|
||||
|
|
|
|||
|
|
@ -354,6 +354,7 @@ LABEL_FOLDERS_NAME = "Mapper"
|
|||
LABEL_ACCOUNTS_NAME = "Kontoer"
|
||||
LABEL_IDENTITY_NAME = "Identitet"
|
||||
LABEL_IDENTITIES_NAME = "Identiteter"
|
||||
LABEL_FILTERS_NAME = "Filters"
|
||||
LABEL_SECURITY_NAME = "Sikkerhet"
|
||||
LABEL_SOCIAL_NAME = "Sosialt"
|
||||
LABEL_THEMES_NAME = "Tema"
|
||||
|
|
|
|||
|
|
@ -363,12 +363,6 @@ LABEL_CHANGE_PASSWORD_NAME = "Hasło"
|
|||
LABEL_OPEN_PGP_NAME = "OpenPGP"
|
||||
BUTTON_BACK = "Wstecz"
|
||||
|
||||
[SETTINGS_FILTERS]
|
||||
LEGEND_FILTERS = "Filtry"
|
||||
BUTTON_ADD_FILTER = "Dodaj filter"
|
||||
BUTTON_DELETE_FILTER = "Usuń filter"
|
||||
BUTTON_ADD_CONDITION = "Dodaj warunek"
|
||||
|
||||
[SETTINGS_IDENTITY]
|
||||
LEGEND_IDENTITY = "Tożsamość"
|
||||
LABEL_DISPLAY_NAME = "Imię i nazwisko"
|
||||
|
|
|
|||
|
|
@ -364,12 +364,6 @@ LABEL_CHANGE_PASSWORD_NAME = "Senha"
|
|||
LABEL_OPEN_PGP_NAME = "OpenPGP"
|
||||
BUTTON_BACK = "Voltar"
|
||||
|
||||
[SETTINGS_FILTERS]
|
||||
LEGEND_FILTERS = "Filtros"
|
||||
BUTTON_ADD_FILTER = "Adicionar Filtro"
|
||||
BUTTON_DELETE_FILTER = "Excluir Filtro"
|
||||
BUTTON_ADD_CONDITION = "Adicionar Condição"
|
||||
|
||||
[SETTINGS_IDENTITY]
|
||||
LEGEND_IDENTITY = "Identidade"
|
||||
LABEL_DISPLAY_NAME = "Nome"
|
||||
|
|
|
|||
|
|
@ -355,6 +355,7 @@ LABEL_FOLDERS_NAME = "Pastas"
|
|||
LABEL_ACCOUNTS_NAME = "Contas"
|
||||
LABEL_IDENTITY_NAME = "Identidade"
|
||||
LABEL_IDENTITIES_NAME = "Identidades"
|
||||
LABEL_FILTERS_NAME = "Filters"
|
||||
LABEL_SECURITY_NAME = "Security"
|
||||
LABEL_SOCIAL_NAME = "Social"
|
||||
LABEL_THEMES_NAME = "Temas"
|
||||
|
|
|
|||
|
|
@ -354,6 +354,7 @@ LABEL_FOLDERS_NAME = "Dosare"
|
|||
LABEL_ACCOUNTS_NAME = "Conturi"
|
||||
LABEL_IDENTITY_NAME = "Profil"
|
||||
LABEL_IDENTITIES_NAME = "Profiluri"
|
||||
LABEL_FILTERS_NAME = "Filters"
|
||||
LABEL_SECURITY_NAME = "Security"
|
||||
LABEL_SOCIAL_NAME = "Social"
|
||||
LABEL_THEMES_NAME = "Subiecte"
|
||||
|
|
|
|||
|
|
@ -355,6 +355,7 @@ LABEL_FOLDERS_NAME = "Папки"
|
|||
LABEL_ACCOUNTS_NAME = "Аккаунты"
|
||||
LABEL_IDENTITY_NAME = "Профиль"
|
||||
LABEL_IDENTITIES_NAME = "Профили"
|
||||
LABEL_FILTERS_NAME = "Фильтры"
|
||||
LABEL_SECURITY_NAME = "Безопасность"
|
||||
LABEL_SOCIAL_NAME = "Социальные"
|
||||
LABEL_THEMES_NAME = "Темы"
|
||||
|
|
|
|||
|
|
@ -355,6 +355,7 @@ LABEL_FOLDERS_NAME = "Priečinky"
|
|||
LABEL_ACCOUNTS_NAME = "Účty"
|
||||
LABEL_IDENTITY_NAME = "Identita"
|
||||
LABEL_IDENTITIES_NAME = "Identity"
|
||||
LABEL_FILTERS_NAME = "Filters"
|
||||
LABEL_SECURITY_NAME = "Security"
|
||||
LABEL_SOCIAL_NAME = "Social"
|
||||
LABEL_THEMES_NAME = "Motívy"
|
||||
|
|
|
|||
|
|
@ -364,12 +364,6 @@ LABEL_CHANGE_PASSWORD_NAME = "Lösenord"
|
|||
LABEL_OPEN_PGP_NAME = "OpenPGP"
|
||||
BUTTON_BACK = "Tillbaka"
|
||||
|
||||
[SETTINGS_FILTERS]
|
||||
LEGEND_FILTERS = "Filter"
|
||||
BUTTON_ADD_FILTER = "Lägg till Filter"
|
||||
BUTTON_DELETE_FILTER = "Ta bort Filter"
|
||||
BUTTON_ADD_CONDITION = "Lägg till villkor"
|
||||
|
||||
[SETTINGS_IDENTITY]
|
||||
LEGEND_IDENTITY = "Identitet"
|
||||
LABEL_DISPLAY_NAME = "Namn"
|
||||
|
|
|
|||
|
|
@ -362,12 +362,6 @@ LABEL_CHANGE_PASSWORD_NAME = "Şifre"
|
|||
LABEL_OPEN_PGP_NAME = "OpenPGP"
|
||||
BUTTON_BACK = "Geri"
|
||||
|
||||
[SETTINGS_FILTERS]
|
||||
LEGEND_FILTERS = "Filtreler"
|
||||
BUTTON_ADD_FILTER = "Filtre Ekle"
|
||||
BUTTON_DELETE_FILTER = "Delete Filter"
|
||||
BUTTON_ADD_CONDITION = "Durum Ekle"
|
||||
|
||||
[SETTINGS_IDENTITY]
|
||||
LEGEND_IDENTITY = "Kimlik"
|
||||
LABEL_DISPLAY_NAME = "İsim"
|
||||
|
|
|
|||
|
|
@ -355,6 +355,7 @@ LABEL_FOLDERS_NAME = "Теки"
|
|||
LABEL_ACCOUNTS_NAME = "Акаунти"
|
||||
LABEL_IDENTITY_NAME = "Профіль"
|
||||
LABEL_IDENTITIES_NAME = "Профілі"
|
||||
LABEL_FILTERS_NAME = "Фильтры"
|
||||
LABEL_SECURITY_NAME = "Безпека"
|
||||
LABEL_SOCIAL_NAME = "Соціальні"
|
||||
LABEL_THEMES_NAME = "Теми"
|
||||
|
|
|
|||
|
|
@ -355,6 +355,7 @@ LABEL_FOLDERS_NAME = "文件夹"
|
|||
LABEL_ACCOUNTS_NAME = "账户"
|
||||
LABEL_IDENTITY_NAME = "签名"
|
||||
LABEL_IDENTITIES_NAME = "签名"
|
||||
LABEL_FILTERS_NAME = "Filters"
|
||||
LABEL_SECURITY_NAME = "安全"
|
||||
LABEL_SOCIAL_NAME = "社交"
|
||||
LABEL_THEMES_NAME = "主题"
|
||||
|
|
|
|||
|
|
@ -364,12 +364,6 @@ LABEL_CHANGE_PASSWORD_NAME = "密碼"
|
|||
LABEL_OPEN_PGP_NAME = "OpenPGP"
|
||||
BUTTON_BACK = "返回"
|
||||
|
||||
[SETTINGS_FILTERS]
|
||||
LEGEND_FILTERS = "Filters"
|
||||
BUTTON_ADD_FILTER = "Add Filter"
|
||||
BUTTON_DELETE_FILTER = "Delete Filter"
|
||||
BUTTON_ADD_CONDITION = "Add Condition"
|
||||
|
||||
[SETTINGS_IDENTITY]
|
||||
LEGEND_IDENTITY = "簽名"
|
||||
LABEL_DISPLAY_NAME = "名稱"
|
||||
|
|
|
|||
11
vendors/jquery-ui.touch-punch/jquery.ui.touch-punch.min.js
vendored
Normal file
11
vendors/jquery-ui.touch-punch/jquery.ui.touch-punch.min.js
vendored
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
/*!
|
||||
* jQuery UI Touch Punch 0.2.3
|
||||
*
|
||||
* Copyright 2011–2014, Dave Furfero
|
||||
* Dual licensed under the MIT or GPL Version 2 licenses.
|
||||
*
|
||||
* Depends:
|
||||
* jquery.ui.widget.js
|
||||
* jquery.ui.mouse.js
|
||||
*/
|
||||
!function(a){function f(a,b){if(!(a.originalEvent.touches.length>1)){a.preventDefault();var c=a.originalEvent.changedTouches[0],d=document.createEvent("MouseEvents");d.initMouseEvent(b,!0,!0,window,1,c.screenX,c.screenY,c.clientX,c.clientY,!1,!1,!1,!1,0,null),a.target.dispatchEvent(d)}}if(a.support.touch="ontouchend"in document,a.support.touch){var e,b=a.ui.mouse.prototype,c=b._mouseInit,d=b._mouseDestroy;b._touchStart=function(a){var b=this;!e&&b._mouseCapture(a.originalEvent.changedTouches[0])&&(e=!0,b._touchMoved=!1,f(a,"mouseover"),f(a,"mousemove"),f(a,"mousedown"))},b._touchMove=function(a){e&&(this._touchMoved=!0,f(a,"mousemove"))},b._touchEnd=function(a){e&&(f(a,"mouseup"),f(a,"mouseout"),this._touchMoved||f(a,"click"),e=!1)},b._mouseInit=function(){var b=this;b.element.bind({touchstart:a.proxy(b,"_touchStart"),touchmove:a.proxy(b,"_touchMove"),touchend:a.proxy(b,"_touchEnd")}),c.call(b)},b._mouseDestroy=function(){var b=this;b.element.unbind({touchstart:a.proxy(b,"_touchStart"),touchmove:a.proxy(b,"_touchMove"),touchend:a.proxy(b,"_touchEnd")}),d.call(b)}}}(jQuery);
|
||||
129
vendors/knockout-sortable/README.md
vendored
Normal file
129
vendors/knockout-sortable/README.md
vendored
Normal file
|
|
@ -0,0 +1,129 @@
|
|||
**knockout-sortable** is a binding for [Knockout.js](http://knockoutjs.com/) designed to connect observableArrays with jQuery UI's sortable functionality. This allows a user to drag and drop items within a list or between lists and have the corresponding observableArrays updated appropriately.
|
||||
|
||||
**Basic Usage**
|
||||
|
||||
* using anonymous templates:
|
||||
|
||||
```html
|
||||
<ul data-bind="sortable: items">
|
||||
<li data-bind="text: name"></li>
|
||||
</ul>
|
||||
```
|
||||
|
||||
|
||||
* using named templates:
|
||||
|
||||
```html
|
||||
<ul data-bind="sortable: { template: 'itemTmpl', data: items }"></ul>
|
||||
<script id="itemTmpl" type="text/html"><li data-bind="text: name"></li></script>
|
||||
```
|
||||
|
||||
Note: The sortable binding assumes that the child "templates" have a single container element. You cannot use containerless bindings (comment-based) bindings at the top-level of your template, as the jQuery draggable/sortable functionality needs an element to operate on.
|
||||
|
||||
Note2: (*Update: 0.9.0 adds code to automatically strip leading/trailing whitespace*) When using named templates, you will have the best results across browsers, if you ensure that there is only a single top-level node inside your template with no surrounding text nodes. Inside of the top-level nodes, you can freely use whitespace/text nodes. So, you will want:
|
||||
|
||||
```html
|
||||
<!-- good - no text nodes surrounding template root node -->
|
||||
<script id="goodTmpl" type="text/html"><li data-bind="text: name">
|
||||
<span data-bind="text: name"></span>
|
||||
</li></script>
|
||||
|
||||
<!-- bad -->
|
||||
<script id="badTmpl" type="text/html">
|
||||
<li>
|
||||
<span data-bind="text: name"></span>
|
||||
</li>
|
||||
</script>
|
||||
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
**Additional Options**
|
||||
|
||||
* **connectClass** - specify the class that should be used to indicate a droppable target. The default class is "ko_container". This value can be passed in the binding or configured globally by setting `ko.bindingHandlers.sortable.connectClass`.
|
||||
|
||||
* **allowDrop** - specify whether this container should be a target for drops. This can be a static value, observable, or a function that is passed the observableArray as its first argument. If a function is specified, then it will be executed in a computed observable, so it will run again whenever any dependencies are updated. This option can be passed in the binding or configured globally by setting `ko.bindingHandlers.sortable.allowDrop`.
|
||||
|
||||
* **beforeMove** - specify a function to execute prior to an item being moved from its original position to its new position in the data. This function receives an object for its first argument that contains the following information:
|
||||
* `arg.item` - the actual item being moved
|
||||
* `arg.sourceIndex` - the position of the item in the original observableArray
|
||||
* `arg.sourceParent` - the original observableArray
|
||||
* `arg.sourceParentNode` - the container node of the original list
|
||||
* `arg.targetIndex` - the position of the item in the destination observableArray
|
||||
* `arg.targetParent` - the destination observableArray
|
||||
* `arg.cancelDrop` - this defaults to false and can be set to true to indicate that the drop should be cancelled.
|
||||
|
||||
This option can be passed in the binding or configured globally by setting `ko.bindingHandlers.sortable.beforeMove`. This callback also receives the `event` and `ui` objects as the second and third arguments.
|
||||
|
||||
* **afterMove** - specify a function to execute after an item has been moved to its new destination. This function receives an object for its first argument that contains the following information:
|
||||
* `arg.item` - the actual item being moved
|
||||
* `arg.sourceIndex` - the position of the item in the original observableArray
|
||||
* `arg.sourceParent` - the original observableArray
|
||||
* `arg.sourceParentNode` - the container node of the original list. Useful if moving items between lists, but within a single array. The value of `this` in the callback will be the target container node.
|
||||
* `arg.targetIndex` - the position of the item in the destination observableArray
|
||||
* `arg.targetParent` - the destination observableArray
|
||||
|
||||
This option can be passed in the binding or configured globally by setting `ko.bindingHandlers.sortable.afterMove`. This callback also receives the `event` and `ui` objects as the second and third arguments.
|
||||
|
||||
* **dragged** - specify a function to execute after a draggable item has been dropped into a sortable. This callback receives the drag item as the first argument, the `event` as the second argument, and the `ui` object as the third argument. If the function returns a value, then it will be used as item that is dropped into the sortable. This can be used as an alternative to the original item including a `clone` function.
|
||||
|
||||
* **isEnabled** - specify whether the sortable widget should be enabled. If this is an observable, then it will enable/disable the widget when the observable's value changes. This option can be passed in the binding or configured globally by setting `ko.bindingHandlers.sortable.isEnabled`.
|
||||
|
||||
* **options** - specify any additional options to pass on to the `.sortable` jQuery UI call. These options can be specified in the binding or specified globally by setting `ko.bindingHandlers.sortable.options`.
|
||||
|
||||
* **afterAdd, beforeRemove, afterRender, includeDestroyed, templateEngine, as** - this binding will pass these options on to the template binding.
|
||||
|
||||
**Draggable binding**
|
||||
|
||||
This library also includes a `draggable` binding that you can place on single items that can be moved into a `sortable` collection. When the item is dropped into a sortable, the plugin will attempt to call a `clone` function on the item to make a suitable copy of it, otherwise it will use the item directly. Additionally, the `dragged` callback can be used to provide a copy of the object, as described above.
|
||||
|
||||
* using anonymous templates:
|
||||
|
||||
```html
|
||||
<div data-bind="draggable: item">
|
||||
<span data-bind="text: name"></span>
|
||||
</div>
|
||||
```
|
||||
|
||||
* using named templates:
|
||||
|
||||
```html
|
||||
<div data-bind="draggable: { template: 'itemTmpl', data: item }"></div>
|
||||
<script id="itemTmpl" type="text/html"><span data-bind="text: name"></span></script>
|
||||
```
|
||||
|
||||
**Additional Options**
|
||||
|
||||
* **connectClass** - specify a class used to indicate which sortables that this draggable should be allowed to drop into. The default class is "ko_container". This value can be passed in the binding or configured globally by setting `ko.bindingHandlers.draggable.connectClass`.
|
||||
|
||||
* **isEnabled** - specify whether the draggable widget should be enabled. If this is an observable, then it will enable/disable the widget when the observable's value changes. This option can be passed in the binding or configured globally by setting `ko.bindingHandlers.draggable.isEnabled`.
|
||||
|
||||
* **options** - specify any additional options to pass on to the `.draggable` jQuery UI call. These options can be specified in the binding or specified globally by setting `ko.bindingHandlers.draggable.options`.
|
||||
|
||||
|
||||
**Dependencies**
|
||||
|
||||
* Knockout 2.0+
|
||||
* jQuery - no specific version identified yet as minimum
|
||||
* jQuery UI - no specific version identfied yet as minimum
|
||||
|
||||
**Touch Support** - for touch support take a look at: http://touchpunch.furf.com/
|
||||
|
||||
|
||||
**Build:** This project uses [grunt](http://gruntjs.com/) for building/minifying.
|
||||
|
||||
**Examples** The `examples` directory contains samples that include a simple sortable list, connected lists, and a seating chart that takes advantage of many of the additional options.
|
||||
|
||||
**Fiddles**
|
||||
|
||||
* simple: http://jsfiddle.net/rniemeyer/hw9B2/
|
||||
* connected: http://jsfiddle.net/rniemeyer/Jr2rE/
|
||||
* draggable: http://jsfiddle.net/rniemeyer/AC49j/
|
||||
* seating chart: http://jsfiddle.net/rniemeyer/UdXr4/
|
||||
|
||||
|
||||
|
||||
**License**: MIT [http://www.opensource.org/licenses/mit-license.php](http://www.opensource.org/licenses/mit-license.php)
|
||||
352
vendors/knockout-sortable/knockout-sortable.js
vendored
Normal file
352
vendors/knockout-sortable/knockout-sortable.js
vendored
Normal file
|
|
@ -0,0 +1,352 @@
|
|||
// knockout-sortable 0.9.2 | (c) 2014 Ryan Niemeyer | http://www.opensource.org/licenses/mit-license
|
||||
;(function(factory) {
|
||||
if (typeof define === "function" && define.amd) {
|
||||
// AMD anonymous module
|
||||
define(["knockout", "jquery", "jquery.ui.sortable"], factory);
|
||||
} else {
|
||||
// No module loader (plain <script> tag) - put directly in global namespace
|
||||
factory(window.ko, jQuery);
|
||||
}
|
||||
})(function(ko, $) {
|
||||
var ITEMKEY = "ko_sortItem",
|
||||
INDEXKEY = "ko_sourceIndex",
|
||||
LISTKEY = "ko_sortList",
|
||||
PARENTKEY = "ko_parentList",
|
||||
DRAGKEY = "ko_dragItem",
|
||||
unwrap = ko.utils.unwrapObservable,
|
||||
dataGet = ko.utils.domData.get,
|
||||
dataSet = ko.utils.domData.set,
|
||||
version = $.ui && $.ui.version,
|
||||
//1.8.24 included a fix for how events were triggered in nested sortables. indexOf checks will fail if version starts with that value (0 vs. -1)
|
||||
hasNestedSortableFix = version && version.indexOf("1.6.") && version.indexOf("1.7.") && (version.indexOf("1.8.") || version === "1.8.24");
|
||||
|
||||
//internal afterRender that adds meta-data to children
|
||||
var addMetaDataAfterRender = function(elements, data) {
|
||||
ko.utils.arrayForEach(elements, function(element) {
|
||||
if (element.nodeType === 1) {
|
||||
dataSet(element, ITEMKEY, data);
|
||||
dataSet(element, PARENTKEY, dataGet(element.parentNode, LISTKEY));
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
//prepare the proper options for the template binding
|
||||
var prepareTemplateOptions = function(valueAccessor, dataName) {
|
||||
var result = {},
|
||||
options = unwrap(valueAccessor()) || {},
|
||||
actualAfterRender;
|
||||
|
||||
//build our options to pass to the template engine
|
||||
if (options.data) {
|
||||
result[dataName] = options.data;
|
||||
result.name = options.template;
|
||||
} else {
|
||||
result[dataName] = valueAccessor();
|
||||
}
|
||||
|
||||
ko.utils.arrayForEach(["afterAdd", "afterRender", "as", "beforeRemove", "includeDestroyed", "templateEngine", "templateOptions"], function (option) {
|
||||
result[option] = options[option] || ko.bindingHandlers.sortable[option];
|
||||
});
|
||||
|
||||
//use an afterRender function to add meta-data
|
||||
if (dataName === "foreach") {
|
||||
if (result.afterRender) {
|
||||
//wrap the existing function, if it was passed
|
||||
actualAfterRender = result.afterRender;
|
||||
result.afterRender = function(element, data) {
|
||||
addMetaDataAfterRender.call(data, element, data);
|
||||
actualAfterRender.call(data, element, data);
|
||||
};
|
||||
} else {
|
||||
result.afterRender = addMetaDataAfterRender;
|
||||
}
|
||||
}
|
||||
|
||||
//return options to pass to the template binding
|
||||
return result;
|
||||
};
|
||||
|
||||
var updateIndexFromDestroyedItems = function(index, items) {
|
||||
var unwrapped = unwrap(items);
|
||||
|
||||
if (unwrapped) {
|
||||
for (var i = 0; i < index; i++) {
|
||||
//add one for every destroyed item we find before the targetIndex in the target array
|
||||
if (unwrapped[i] && unwrap(unwrapped[i]._destroy)) {
|
||||
index++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return index;
|
||||
};
|
||||
|
||||
//remove problematic leading/trailing whitespace from templates
|
||||
var stripTemplateWhitespace = function(element, name) {
|
||||
var templateSource,
|
||||
templateElement;
|
||||
|
||||
//process named templates
|
||||
if (name) {
|
||||
templateElement = document.getElementById(name);
|
||||
if (templateElement) {
|
||||
templateSource = new ko.templateSources.domElement(templateElement);
|
||||
templateSource.text($.trim(templateSource.text()));
|
||||
}
|
||||
}
|
||||
else {
|
||||
//remove leading/trailing non-elements from anonymous templates
|
||||
$(element).contents().each(function() {
|
||||
if (this && this.nodeType !== 1) {
|
||||
element.removeChild(this);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
//connect items with observableArrays
|
||||
ko.bindingHandlers.sortable = {
|
||||
init: function(element, valueAccessor, allBindingsAccessor, data, context) {
|
||||
var $element = $(element),
|
||||
value = unwrap(valueAccessor()) || {},
|
||||
templateOptions = prepareTemplateOptions(valueAccessor, "foreach"),
|
||||
sortable = {},
|
||||
startActual, updateActual;
|
||||
|
||||
stripTemplateWhitespace(element, templateOptions.name);
|
||||
|
||||
//build a new object that has the global options with overrides from the binding
|
||||
$.extend(true, sortable, ko.bindingHandlers.sortable);
|
||||
if (value.options && sortable.options) {
|
||||
ko.utils.extend(sortable.options, value.options);
|
||||
delete value.options;
|
||||
}
|
||||
ko.utils.extend(sortable, value);
|
||||
|
||||
//if allowDrop is an observable or a function, then execute it in a computed observable
|
||||
if (sortable.connectClass && (ko.isObservable(sortable.allowDrop) || typeof sortable.allowDrop == "function")) {
|
||||
ko.computed({
|
||||
read: function() {
|
||||
var value = unwrap(sortable.allowDrop),
|
||||
shouldAdd = typeof value == "function" ? value.call(this, templateOptions.foreach) : value;
|
||||
ko.utils.toggleDomNodeCssClass(element, sortable.connectClass, shouldAdd);
|
||||
},
|
||||
disposeWhenNodeIsRemoved: element
|
||||
}, this);
|
||||
} else {
|
||||
ko.utils.toggleDomNodeCssClass(element, sortable.connectClass, sortable.allowDrop);
|
||||
}
|
||||
|
||||
//wrap the template binding
|
||||
ko.bindingHandlers.template.init(element, function() { return templateOptions; }, allBindingsAccessor, data, context);
|
||||
|
||||
//keep a reference to start/update functions that might have been passed in
|
||||
startActual = sortable.options.start;
|
||||
updateActual = sortable.options.update;
|
||||
|
||||
//initialize sortable binding after template binding has rendered in update function
|
||||
var createTimeout = setTimeout(function() {
|
||||
var dragItem;
|
||||
$element.sortable(ko.utils.extend(sortable.options, {
|
||||
start: function(event, ui) {
|
||||
//track original index
|
||||
var el = ui.item[0];
|
||||
dataSet(el, INDEXKEY, ko.utils.arrayIndexOf(ui.item.parent().children(), el));
|
||||
|
||||
//make sure that fields have a chance to update model
|
||||
ui.item.find("input:focus").change();
|
||||
if (startActual) {
|
||||
startActual.apply(this, arguments);
|
||||
}
|
||||
},
|
||||
receive: function(event, ui) {
|
||||
dragItem = dataGet(ui.item[0], DRAGKEY);
|
||||
if (dragItem) {
|
||||
//copy the model item, if a clone option is provided
|
||||
if (dragItem.clone) {
|
||||
dragItem = dragItem.clone();
|
||||
}
|
||||
|
||||
//configure a handler to potentially manipulate item before drop
|
||||
if (sortable.dragged) {
|
||||
dragItem = sortable.dragged.call(this, dragItem, event, ui) || dragItem;
|
||||
}
|
||||
}
|
||||
},
|
||||
update: function(event, ui) {
|
||||
var sourceParent, targetParent, sourceIndex, targetIndex, arg,
|
||||
el = ui.item[0],
|
||||
parentEl = ui.item.parent()[0],
|
||||
item = dataGet(el, ITEMKEY) || dragItem;
|
||||
|
||||
dragItem = null;
|
||||
|
||||
//make sure that moves only run once, as update fires on multiple containers
|
||||
if (item && (this === parentEl) || (!hasNestedSortableFix && $.contains(this, parentEl))) {
|
||||
//identify parents
|
||||
sourceParent = dataGet(el, PARENTKEY);
|
||||
sourceIndex = dataGet(el, INDEXKEY);
|
||||
targetParent = dataGet(el.parentNode, LISTKEY);
|
||||
targetIndex = ko.utils.arrayIndexOf(ui.item.parent().children(), el);
|
||||
|
||||
//take destroyed items into consideration
|
||||
if (!templateOptions.includeDestroyed) {
|
||||
sourceIndex = updateIndexFromDestroyedItems(sourceIndex, sourceParent);
|
||||
targetIndex = updateIndexFromDestroyedItems(targetIndex, targetParent);
|
||||
}
|
||||
|
||||
//build up args for the callbacks
|
||||
if (sortable.beforeMove || sortable.afterMove) {
|
||||
arg = {
|
||||
item: item,
|
||||
sourceParent: sourceParent,
|
||||
sourceParentNode: sourceParent && ui.sender || el.parentNode,
|
||||
sourceIndex: sourceIndex,
|
||||
targetParent: targetParent,
|
||||
targetIndex: targetIndex,
|
||||
cancelDrop: false
|
||||
};
|
||||
|
||||
//execute the configured callback prior to actually moving items
|
||||
if (sortable.beforeMove) {
|
||||
sortable.beforeMove.call(this, arg, event, ui);
|
||||
}
|
||||
}
|
||||
|
||||
//call cancel on the correct list, so KO can take care of DOM manipulation
|
||||
if (sourceParent) {
|
||||
$(sourceParent === targetParent ? this : ui.sender || this).sortable("cancel");
|
||||
}
|
||||
//for a draggable item just remove the element
|
||||
else {
|
||||
$(el).remove();
|
||||
}
|
||||
|
||||
//if beforeMove told us to cancel, then we are done
|
||||
if (arg && arg.cancelDrop) {
|
||||
return;
|
||||
}
|
||||
|
||||
//do the actual move
|
||||
if (targetIndex >= 0) {
|
||||
if (sourceParent) {
|
||||
sourceParent.splice(sourceIndex, 1);
|
||||
|
||||
//if using deferred updates plugin, force updates
|
||||
if (ko.processAllDeferredBindingUpdates) {
|
||||
ko.processAllDeferredBindingUpdates();
|
||||
}
|
||||
}
|
||||
|
||||
targetParent.splice(targetIndex, 0, item);
|
||||
}
|
||||
|
||||
//rendering is handled by manipulating the observableArray; ignore dropped element
|
||||
dataSet(el, ITEMKEY, null);
|
||||
|
||||
//if using deferred updates plugin, force updates
|
||||
if (ko.processAllDeferredBindingUpdates) {
|
||||
ko.processAllDeferredBindingUpdates();
|
||||
}
|
||||
|
||||
//allow binding to accept a function to execute after moving the item
|
||||
if (sortable.afterMove) {
|
||||
sortable.afterMove.call(this, arg, event, ui);
|
||||
}
|
||||
}
|
||||
|
||||
if (updateActual) {
|
||||
updateActual.apply(this, arguments);
|
||||
}
|
||||
},
|
||||
connectWith: sortable.connectClass ? "." + sortable.connectClass : false
|
||||
}));
|
||||
|
||||
//handle enabling/disabling sorting
|
||||
if (sortable.isEnabled !== undefined) {
|
||||
ko.computed({
|
||||
read: function() {
|
||||
$element.sortable(unwrap(sortable.isEnabled) ? "enable" : "disable");
|
||||
},
|
||||
disposeWhenNodeIsRemoved: element
|
||||
});
|
||||
}
|
||||
}, 0);
|
||||
|
||||
//handle disposal
|
||||
ko.utils.domNodeDisposal.addDisposeCallback(element, function() {
|
||||
//only call destroy if sortable has been created
|
||||
if ($element.data("ui-sortable") || $element.data("sortable")) {
|
||||
$element.sortable("destroy");
|
||||
}
|
||||
|
||||
//do not create the sortable if the element has been removed from DOM
|
||||
clearTimeout(createTimeout);
|
||||
});
|
||||
|
||||
return { 'controlsDescendantBindings': true };
|
||||
},
|
||||
update: function(element, valueAccessor, allBindingsAccessor, data, context) {
|
||||
var templateOptions = prepareTemplateOptions(valueAccessor, "foreach");
|
||||
|
||||
//attach meta-data
|
||||
dataSet(element, LISTKEY, templateOptions.foreach);
|
||||
|
||||
//call template binding's update with correct options
|
||||
ko.bindingHandlers.template.update(element, function() { return templateOptions; }, allBindingsAccessor, data, context);
|
||||
},
|
||||
connectClass: 'ko_container',
|
||||
allowDrop: true,
|
||||
afterMove: null,
|
||||
beforeMove: null,
|
||||
options: {}
|
||||
};
|
||||
|
||||
//create a draggable that is appropriate for dropping into a sortable
|
||||
ko.bindingHandlers.draggable = {
|
||||
init: function(element, valueAccessor, allBindingsAccessor, data, context) {
|
||||
var value = unwrap(valueAccessor()) || {},
|
||||
options = value.options || {},
|
||||
draggableOptions = ko.utils.extend({}, ko.bindingHandlers.draggable.options),
|
||||
templateOptions = prepareTemplateOptions(valueAccessor, "data"),
|
||||
connectClass = value.connectClass || ko.bindingHandlers.draggable.connectClass,
|
||||
isEnabled = value.isEnabled !== undefined ? value.isEnabled : ko.bindingHandlers.draggable.isEnabled;
|
||||
|
||||
value = "data" in value ? value.data : value;
|
||||
|
||||
//set meta-data
|
||||
dataSet(element, DRAGKEY, value);
|
||||
|
||||
//override global options with override options passed in
|
||||
ko.utils.extend(draggableOptions, options);
|
||||
|
||||
//setup connection to a sortable
|
||||
draggableOptions.connectToSortable = connectClass ? "." + connectClass : false;
|
||||
|
||||
//initialize draggable
|
||||
$(element).draggable(draggableOptions);
|
||||
|
||||
//handle enabling/disabling sorting
|
||||
if (isEnabled !== undefined) {
|
||||
ko.computed({
|
||||
read: function() {
|
||||
$(element).draggable(unwrap(isEnabled) ? "enable" : "disable");
|
||||
},
|
||||
disposeWhenNodeIsRemoved: element
|
||||
});
|
||||
}
|
||||
|
||||
return ko.bindingHandlers.template.init(element, function() { return templateOptions; }, allBindingsAccessor, data, context);
|
||||
},
|
||||
update: function(element, valueAccessor, allBindingsAccessor, data, context) {
|
||||
var templateOptions = prepareTemplateOptions(valueAccessor, "data");
|
||||
|
||||
return ko.bindingHandlers.template.update(element, function() { return templateOptions; }, allBindingsAccessor, data, context);
|
||||
},
|
||||
connectClass: ko.bindingHandlers.sortable.connectClass,
|
||||
options: {
|
||||
helper: "clone"
|
||||
}
|
||||
};
|
||||
|
||||
});
|
||||
2
vendors/knockout-sortable/knockout-sortable.min.js
vendored
Normal file
2
vendors/knockout-sortable/knockout-sortable.min.js
vendored
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
// knockout-sortable 0.9.2 | (c) 2014 Ryan Niemeyer | http://www.opensource.org/licenses/mit-license
|
||||
!function(a){"function"==typeof define&&define.amd?define(["knockout","jquery","jquery.ui.sortable"],a):a(window.ko,jQuery)}(function(a,b){var c="ko_sortItem",d="ko_sourceIndex",e="ko_sortList",f="ko_parentList",g="ko_dragItem",h=a.utils.unwrapObservable,i=a.utils.domData.get,j=a.utils.domData.set,k=b.ui&&b.ui.version,l=k&&k.indexOf("1.6.")&&k.indexOf("1.7.")&&(k.indexOf("1.8.")||"1.8.24"===k),m=function(b,d){a.utils.arrayForEach(b,function(a){1===a.nodeType&&(j(a,c,d),j(a,f,i(a.parentNode,e)))})},n=function(b,c){var d,e={},f=h(b())||{};return f.data?(e[c]=f.data,e.name=f.template):e[c]=b(),a.utils.arrayForEach(["afterAdd","afterRender","as","beforeRemove","includeDestroyed","templateEngine","templateOptions"],function(b){e[b]=f[b]||a.bindingHandlers.sortable[b]}),"foreach"===c&&(e.afterRender?(d=e.afterRender,e.afterRender=function(a,b){m.call(b,a,b),d.call(b,a,b)}):e.afterRender=m),e},o=function(a,b){var c=h(b);if(c)for(var d=0;a>d;d++)c[d]&&h(c[d]._destroy)&&a++;return a},p=function(c,d){var e,f;d?(f=document.getElementById(d),f&&(e=new a.templateSources.domElement(f),e.text(b.trim(e.text())))):b(c).contents().each(function(){this&&1!==this.nodeType&&c.removeChild(this)})};a.bindingHandlers.sortable={init:function(k,m,q,r,s){var t,u,v=b(k),w=h(m())||{},x=n(m,"foreach"),y={};p(k,x.name),b.extend(!0,y,a.bindingHandlers.sortable),w.options&&y.options&&(a.utils.extend(y.options,w.options),delete w.options),a.utils.extend(y,w),y.connectClass&&(a.isObservable(y.allowDrop)||"function"==typeof y.allowDrop)?a.computed({read:function(){var b=h(y.allowDrop),c="function"==typeof b?b.call(this,x.foreach):b;a.utils.toggleDomNodeCssClass(k,y.connectClass,c)},disposeWhenNodeIsRemoved:k},this):a.utils.toggleDomNodeCssClass(k,y.connectClass,y.allowDrop),a.bindingHandlers.template.init(k,function(){return x},q,r,s),t=y.options.start,u=y.options.update;var z=setTimeout(function(){var m;v.sortable(a.utils.extend(y.options,{start:function(b,c){var e=c.item[0];j(e,d,a.utils.arrayIndexOf(c.item.parent().children(),e)),c.item.find("input:focus").change(),t&&t.apply(this,arguments)},receive:function(a,b){m=i(b.item[0],g),m&&(m.clone&&(m=m.clone()),y.dragged&&(m=y.dragged.call(this,m,a,b)||m))},update:function(g,h){var k,n,p,q,r,s=h.item[0],t=h.item.parent()[0],v=i(s,c)||m;if(m=null,v&&this===t||!l&&b.contains(this,t)){if(k=i(s,f),p=i(s,d),n=i(s.parentNode,e),q=a.utils.arrayIndexOf(h.item.parent().children(),s),x.includeDestroyed||(p=o(p,k),q=o(q,n)),(y.beforeMove||y.afterMove)&&(r={item:v,sourceParent:k,sourceParentNode:k&&h.sender||s.parentNode,sourceIndex:p,targetParent:n,targetIndex:q,cancelDrop:!1},y.beforeMove&&y.beforeMove.call(this,r,g,h)),k?b(k===n?this:h.sender||this).sortable("cancel"):b(s).remove(),r&&r.cancelDrop)return;q>=0&&(k&&(k.splice(p,1),a.processAllDeferredBindingUpdates&&a.processAllDeferredBindingUpdates()),n.splice(q,0,v)),j(s,c,null),a.processAllDeferredBindingUpdates&&a.processAllDeferredBindingUpdates(),y.afterMove&&y.afterMove.call(this,r,g,h)}u&&u.apply(this,arguments)},connectWith:y.connectClass?"."+y.connectClass:!1})),void 0!==y.isEnabled&&a.computed({read:function(){v.sortable(h(y.isEnabled)?"enable":"disable")},disposeWhenNodeIsRemoved:k})},0);return a.utils.domNodeDisposal.addDisposeCallback(k,function(){(v.data("ui-sortable")||v.data("sortable"))&&v.sortable("destroy"),clearTimeout(z)}),{controlsDescendantBindings:!0}},update:function(b,c,d,f,g){var h=n(c,"foreach");j(b,e,h.foreach),a.bindingHandlers.template.update(b,function(){return h},d,f,g)},connectClass:"ko_container",allowDrop:!0,afterMove:null,beforeMove:null,options:{}},a.bindingHandlers.draggable={init:function(c,d,e,f,i){var k=h(d())||{},l=k.options||{},m=a.utils.extend({},a.bindingHandlers.draggable.options),o=n(d,"data"),p=k.connectClass||a.bindingHandlers.draggable.connectClass,q=void 0!==k.isEnabled?k.isEnabled:a.bindingHandlers.draggable.isEnabled;return k="data"in k?k.data:k,j(c,g,k),a.utils.extend(m,l),m.connectToSortable=p?"."+p:!1,b(c).draggable(m),void 0!==q&&a.computed({read:function(){b(c).draggable(h(q)?"enable":"disable")},disposeWhenNodeIsRemoved:c}),a.bindingHandlers.template.init(c,function(){return o},e,f,i)},update:function(b,c,d,e,f){var g=n(c,"data");return a.bindingHandlers.template.update(b,function(){return g},d,e,f)},connectClass:a.bindingHandlers.sortable.connectClass,options:{helper:"clone"}}});
|
||||
13
vendors/knockout-sortable/package.json
vendored
Normal file
13
vendors/knockout-sortable/package.json
vendored
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
{
|
||||
"name": "knockout-sortable",
|
||||
"version": "0.9.2",
|
||||
"devDependencies": {
|
||||
"grunt": "~0.4.1",
|
||||
"grunt-contrib-uglify": "0.x.x",
|
||||
"grunt-contrib-jshint": "0.x.x",
|
||||
"grunt-contrib-watch": "0.x.x",
|
||||
"grunt-contrib-concat": "0.x.x",
|
||||
"grunt-contrib-jasmine": "0.x.x",
|
||||
"grunt-template-jasmine-istanbul": "0.x.x"
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue