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:
Shannon
2014-10-28 15:37:47 +10:00
parent cc8f07c0d8
commit 7a42b5dae3
3 changed files with 167 additions and 114 deletions

View File

@@ -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);