streamlines and simplifies contentpicker.controller.js, ensures that filtering is performed properly even based on search results and differently based on members
This commit is contained in:
@@ -1,137 +1,189 @@
|
||||
//this controller simply tells the dialogs service to open a mediaPicker window
|
||||
//with a specified callback, this callback will receive an object with a selection on it
|
||||
angular.module('umbraco')
|
||||
.controller("Umbraco.PropertyEditors.ContentPickerController",
|
||||
|
||||
function ($scope, dialogService, entityResource, editorState, $log, iconHelper, $routeParams, fileManager, contentEditingHelper) {
|
||||
function contentPickerController($scope, dialogService, entityResource, editorState, $log, iconHelper, $routeParams, fileManager, contentEditingHelper) {
|
||||
|
||||
$scope.renderModel = [];
|
||||
$scope.ids = $scope.model.value ? $scope.model.value.split(',') : [];
|
||||
function trim(str, chr) {
|
||||
var rgxtrim = (!chr) ? new RegExp('^\\s+|\\s+$', 'g') : new RegExp('^' + chr + '+|' + chr + '+$', 'g');
|
||||
return str.replace(rgxtrim, '');
|
||||
}
|
||||
|
||||
$scope.dialogEditor = editorState && editorState.current && editorState.current.isDialogEditor === true;
|
||||
function startWatch() {
|
||||
//We need to watch our renderModel so that we can update the underlying $scope.model.value properly, this is required
|
||||
// because the ui-sortable doesn't dispatch an event after the digest of the sort operation. Any of the events for UI sortable
|
||||
// occur after the DOM has updated but BEFORE the digest has occured so the model has NOT changed yet - it even states so in the docs.
|
||||
// In their source code there is no event so we need to just subscribe to our model changes here.
|
||||
//This also makes it easier to manage models, we update one and the rest will just work.
|
||||
$scope.$watch(function () {
|
||||
//return the joined Ids as a string to watch
|
||||
return _.map($scope.renderModel, function (i) {
|
||||
return i.id;
|
||||
}).join();
|
||||
}, function (newVal) {
|
||||
var currIds = _.map($scope.renderModel, function (i) {
|
||||
return i.id;
|
||||
});
|
||||
$scope.model.value = trim(currIds.join(), ",");
|
||||
|
||||
//configuration
|
||||
$scope.cfg = {
|
||||
multiPicker: "0",
|
||||
showEditButton: "0",
|
||||
entityType: "Document",
|
||||
filterCssClass: "not-allowed not-published",
|
||||
//Validate!
|
||||
if ($scope.model.config && $scope.model.config.minNumber && parseInt($scope.model.config.minNumber) > $scope.renderModel.length) {
|
||||
$scope.contentPickerForm.minCount.$setValidity("minCount", false);
|
||||
}
|
||||
else {
|
||||
$scope.contentPickerForm.minCount.$setValidity("minCount", true);
|
||||
}
|
||||
|
||||
startNode: {
|
||||
query: "",
|
||||
type: "content",
|
||||
id: -1
|
||||
}
|
||||
};
|
||||
if ($scope.model.config && $scope.model.config.maxNumber && parseInt($scope.model.config.maxNumber) < $scope.renderModel.length) {
|
||||
$scope.contentPickerForm.maxCount.$setValidity("maxCount", false);
|
||||
}
|
||||
else {
|
||||
$scope.contentPickerForm.maxCount.$setValidity("maxCount", true);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if ($scope.model.config) {
|
||||
$scope.cfg = angular.extend($scope.cfg, $scope.model.config);
|
||||
}
|
||||
$scope.renderModel = [];
|
||||
|
||||
$scope.dialogEditor = editorState && editorState.current && editorState.current.isDialogEditor === true;
|
||||
|
||||
//Umbraco persists boolean for prevalues as "0" or "1" so we need to convert that!
|
||||
$scope.cfg.multiPicker = ($scope.cfg.multiPicker === "0" ? false : true);
|
||||
$scope.cfg.showEditButton = ($scope.cfg.showEditButton === "0" ? false : true);
|
||||
//the default pre-values
|
||||
var defaultConfig = {
|
||||
multiPicker: false,
|
||||
showEditButton: false,
|
||||
startNode: {
|
||||
query: "",
|
||||
type: "content",
|
||||
id: -1
|
||||
}
|
||||
};
|
||||
|
||||
if ($scope.cfg.startNode.type === "member") {
|
||||
$scope.cfg.entityType = "Member";
|
||||
}
|
||||
else if ($scope.cfg.startNode.type === "media") {
|
||||
$scope.cfg.entityType = "Media";
|
||||
}
|
||||
if ($scope.model.config) {
|
||||
//merge the server config on top of the default config, then set the server config to use the result
|
||||
$scope.model.config = angular.extend(defaultConfig, $scope.model.config);
|
||||
}
|
||||
|
||||
//if we have a query for the startnode, we will use that.
|
||||
if ($scope.cfg.startNode.query) {
|
||||
var rootId = $routeParams.id;
|
||||
entityResource.getByQuery($scope.cfg.startNode.query, rootId, "Document").then(function (ent) {
|
||||
$scope.cfg.startNodeId = ent.id;
|
||||
});
|
||||
} else {
|
||||
$scope.cfg.startNodeId = $scope.cfg.startNode.id;
|
||||
}
|
||||
//Umbraco persists boolean for prevalues as "0" or "1" so we need to convert that!
|
||||
$scope.model.config.multiPicker = ($scope.model.config.multiPicker === "0" ? false : true);
|
||||
$scope.model.config.showEditButton = ($scope.model.config.showEditButton === "0" ? false : true);
|
||||
|
||||
$scope.cfg.callback = populate;
|
||||
$scope.cfg.treeAlias = $scope.cfg.startNode.type;
|
||||
$scope.cfg.section = $scope.cfg.startNode.type;
|
||||
var entityType = $scope.model.config.startNode.type === "member"
|
||||
? "Member"
|
||||
: $scope.model.config.startNode.type === "media"
|
||||
? "Media"
|
||||
: "Document";
|
||||
|
||||
//load current data
|
||||
entityResource.getByIds($scope.ids, $scope.cfg.entityType).then(function (data) {
|
||||
_.each(data, function (item, i) {
|
||||
item.icon = iconHelper.convertFromLegacyIcon(item.icon);
|
||||
$scope.renderModel.push({ name: item.name, id: item.id, icon: item.icon });
|
||||
});
|
||||
});
|
||||
//the dialog options for the picker
|
||||
var dialogOptions = {
|
||||
multiPicker: $scope.model.config.multiPicker,
|
||||
entityType: entityType,
|
||||
filterCssClass: "not-allowed not-published",
|
||||
startNodeId: null,
|
||||
callback: function (data) {
|
||||
if (angular.isArray(data)) {
|
||||
_.each(data, function (item, i) {
|
||||
$scope.add(item);
|
||||
});
|
||||
} else {
|
||||
$scope.clear();
|
||||
$scope.add(data);
|
||||
}
|
||||
},
|
||||
treeAlias: $scope.model.config.startNode.type,
|
||||
section: $scope.model.config.startNode.type
|
||||
};
|
||||
|
||||
//since most of the pre-value config's are used in the dialog options (i.e. maxNumber, minNumber, etc...) we'll merge the
|
||||
// pre-value config on to the dialog options
|
||||
angular.extend(dialogOptions, $scope.model.config);
|
||||
|
||||
//We need to manually handle the filter for members here since the tree displayed is different and only contains
|
||||
// searchable list views
|
||||
if (entityType === "Member") {
|
||||
//first change the not allowed filter css class
|
||||
dialogOptions.filterCssClass = "not-allowed";
|
||||
var currFilter = dialogOptions.filter;
|
||||
//now change the filter to be a method
|
||||
dialogOptions.filter = function(i) {
|
||||
//filter out the list view nodes
|
||||
if (i.metaData.isContainer) {
|
||||
return true;
|
||||
}
|
||||
if (!currFilter) {
|
||||
return false;
|
||||
}
|
||||
//now we need to filter based on what is stored in the pre-vals, this logic duplicates what is in the treepicker.controller,
|
||||
// but not much we can do about that since members require special filtering.
|
||||
var filterItem = currFilter.toLowerCase().split(',');
|
||||
var found = filterItem.indexOf(i.metaData.contentType.toLowerCase()) >= 0;
|
||||
if (!currFilter.startsWith("!") && !found || currFilter.startsWith("!") && found) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//dialog
|
||||
$scope.openContentPicker = function () {
|
||||
var d = dialogService.treePicker($scope.cfg);
|
||||
};
|
||||
//if we have a query for the startnode, we will use that.
|
||||
if ($scope.model.config.startNode.query) {
|
||||
var rootId = $routeParams.id;
|
||||
entityResource.getByQuery($scope.model.config.startNode.query, rootId, "Document").then(function (ent) {
|
||||
dialogOptions.startNodeId = ent.id;
|
||||
});
|
||||
} else {
|
||||
dialogOptions.startNodeId = $scope.model.config.startNode.id;
|
||||
}
|
||||
|
||||
//dialog
|
||||
$scope.openContentPicker = function () {
|
||||
var d = dialogService.treePicker(dialogOptions);
|
||||
};
|
||||
|
||||
|
||||
$scope.remove = function (index) {
|
||||
$scope.renderModel.splice(index, 1);
|
||||
};
|
||||
$scope.remove = function (index) {
|
||||
$scope.renderModel.splice(index, 1);
|
||||
};
|
||||
|
||||
$scope.add = function (item) {
|
||||
if ($scope.ids.indexOf(item.id) < 0) {
|
||||
item.icon = iconHelper.convertFromLegacyIcon(item.icon);
|
||||
$scope.renderModel.push({ name: item.name, id: item.id, icon: item.icon });
|
||||
}
|
||||
};
|
||||
$scope.add = function (item) {
|
||||
var currIds = _.map($scope.renderModel, function (i) {
|
||||
return i.id;
|
||||
});
|
||||
|
||||
$scope.clear = function () {
|
||||
$scope.renderModel = [];
|
||||
};
|
||||
if (currIds.indexOf(item.id) < 0) {
|
||||
item.icon = iconHelper.convertFromLegacyIcon(item.icon);
|
||||
$scope.renderModel.push({ name: item.name, id: item.id, icon: item.icon });
|
||||
}
|
||||
};
|
||||
|
||||
//We need to watch our renderModel so that we can update the underlying $scope.model.value properly, this is required
|
||||
// because the ui-sortable doesn't dispatch an event after the digest of the sort operation. Any of the events for UI sortable
|
||||
// occur after the DOM has updated but BEFORE the digest has occured so the model has NOT changed yet - it even states so in the docs.
|
||||
// In their source code there is no event so we need to just subscribe to our model changes here.
|
||||
//This also makes it easier to manage models, we update one and the rest will just work.
|
||||
$scope.$watch(function () {
|
||||
//return the joined Ids as a string to watch
|
||||
return _.map($scope.renderModel, function (i) {
|
||||
return i.id;
|
||||
}).join();
|
||||
}, function (newVal) {
|
||||
$scope.ids = _.map($scope.renderModel, function (i) {
|
||||
return i.id;
|
||||
});
|
||||
$scope.model.value = trim($scope.ids.join(), ",");
|
||||
$scope.clear = function () {
|
||||
$scope.renderModel = [];
|
||||
};
|
||||
|
||||
$scope.$on("formSubmitting", function (ev, args) {
|
||||
var currIds = _.map($scope.renderModel, function (i) {
|
||||
return i.id;
|
||||
});
|
||||
$scope.model.value = trim(currIds.join(), ",");
|
||||
});
|
||||
|
||||
//Validate!
|
||||
if ($scope.model.config && $scope.model.config.minNumber && parseInt($scope.model.config.minNumber) > $scope.renderModel.length) {
|
||||
$scope.contentPickerForm.minCount.$setValidity("minCount", false);
|
||||
}
|
||||
else {
|
||||
$scope.contentPickerForm.minCount.$setValidity("minCount", true);
|
||||
}
|
||||
//load current data
|
||||
var modelIds = $scope.model.value ? $scope.model.value.split(',') : [];
|
||||
entityResource.getByIds(modelIds, entityType).then(function (data) {
|
||||
|
||||
if ($scope.model.config && $scope.model.config.maxNumber && parseInt($scope.model.config.maxNumber) < $scope.renderModel.length) {
|
||||
$scope.contentPickerForm.maxCount.$setValidity("maxCount", false);
|
||||
}
|
||||
else {
|
||||
$scope.contentPickerForm.maxCount.$setValidity("maxCount", true);
|
||||
}
|
||||
});
|
||||
//Ensure we populate the render model in the same order that the ids were stored!
|
||||
_.each(modelIds, function (id, i) {
|
||||
var entity = _.find(data, function (d) {
|
||||
return d.id == id;
|
||||
});
|
||||
|
||||
entity.icon = iconHelper.convertFromLegacyIcon(entity.icon);
|
||||
$scope.renderModel.push({ name: entity.name, id: entity.id, icon: entity.icon });
|
||||
|
||||
});
|
||||
|
||||
$scope.$on("formSubmitting", function (ev, args) {
|
||||
$scope.model.value = trim($scope.ids.join(), ",");
|
||||
});
|
||||
//everything is loaded, start the watch on the model
|
||||
startWatch();
|
||||
|
||||
function trim(str, chr) {
|
||||
var rgxtrim = (!chr) ? new RegExp('^\\s+|\\s+$', 'g') : new RegExp('^' + chr + '+|' + chr + '+$', 'g');
|
||||
return str.replace(rgxtrim, '');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function populate(data) {
|
||||
if (angular.isArray(data)) {
|
||||
_.each(data, function (item, i) {
|
||||
$scope.add(item);
|
||||
});
|
||||
} else {
|
||||
$scope.clear();
|
||||
$scope.add(data);
|
||||
}
|
||||
}
|
||||
});
|
||||
angular.module('umbraco').controller("Umbraco.PropertyEditors.ContentPickerController", contentPickerController);
|
||||
Reference in New Issue
Block a user