Adds GetPagedDescendants to EntityController
Implements GetPagedDescendants in the mediapicker Search Removes duplicate ExamineSearch and Search endpoint code from MediaController
This commit is contained in:
@@ -395,6 +395,76 @@ function entityResource($q, $http, umbRequestHelper) {
|
||||
)),
|
||||
'Failed to retrieve child data for id ' + parentId);
|
||||
},
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name umbraco.resources.entityResource#getPagedDescendants
|
||||
* @methodOf umbraco.resources.entityResource
|
||||
*
|
||||
* @description
|
||||
* Gets paged descendants of a content item with a given id
|
||||
*
|
||||
* ##usage
|
||||
* <pre>
|
||||
* entityResource.getPagedDescendants(1234, "Content", {pageSize: 10, pageNumber: 2})
|
||||
* .then(function(contentArray) {
|
||||
* var children = contentArray;
|
||||
* alert('they are here!');
|
||||
* });
|
||||
* </pre>
|
||||
*
|
||||
* @param {Int} parentid id of content item to return descendants of
|
||||
* @param {string} type Object type name
|
||||
* @param {Object} options optional options object
|
||||
* @param {Int} options.pageSize if paging data, number of nodes per page, default = 0
|
||||
* @param {Int} options.pageNumber if paging data, current page index, default = 0
|
||||
* @param {String} options.filter if provided, query will only return those with names matching the filter
|
||||
* @param {String} options.orderDirection can be `Ascending` or `Descending` - Default: `Ascending`
|
||||
* @param {String} options.orderBy property to order items by, default: `SortOrder`
|
||||
* @returns {Promise} resourcePromise object containing an array of content items.
|
||||
*
|
||||
*/
|
||||
getPagedDescendants: function (parentId, type, options) {
|
||||
|
||||
var defaults = {
|
||||
pageSize: 0,
|
||||
pageNumber: 0,
|
||||
filter: '',
|
||||
orderDirection: "Ascending",
|
||||
orderBy: "SortOrder"
|
||||
};
|
||||
if (options === undefined) {
|
||||
options = {};
|
||||
}
|
||||
//overwrite the defaults if there are any specified
|
||||
angular.extend(defaults, options);
|
||||
//now copy back to the options we will use
|
||||
options = defaults;
|
||||
//change asc/desct
|
||||
if (options.orderDirection === "asc") {
|
||||
options.orderDirection = "Ascending";
|
||||
}
|
||||
else if (options.orderDirection === "desc") {
|
||||
options.orderDirection = "Descending";
|
||||
}
|
||||
|
||||
return umbRequestHelper.resourcePromise(
|
||||
$http.get(
|
||||
umbRequestHelper.getApiUrl(
|
||||
"entityApiBaseUrl",
|
||||
"GetPagedDescendants",
|
||||
{
|
||||
id: parentId,
|
||||
type: type,
|
||||
pageNumber: options.pageNumber,
|
||||
pageSize: options.pageSize,
|
||||
orderBy: options.orderBy,
|
||||
orderDirection: options.orderDirection,
|
||||
filter: options.filter
|
||||
}
|
||||
)),
|
||||
'Failed to retrieve child data for id ' + parentId);
|
||||
},
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
|
||||
@@ -37,7 +37,8 @@ angular.module("umbraco")
|
||||
pageNumber: 1,
|
||||
pageSize: 100,
|
||||
totalItems: 0,
|
||||
totalPages: 0
|
||||
totalPages: 0,
|
||||
filter: '',
|
||||
};
|
||||
|
||||
//preload selected item
|
||||
@@ -233,7 +234,7 @@ angular.module("umbraco")
|
||||
|
||||
var debounceSearchMedia = _.debounce(function () {
|
||||
$scope.$apply(function () {
|
||||
if ($scope.searchTerm) {
|
||||
if ($scope.searchOptions.filter) {
|
||||
searchMedia();
|
||||
} else {
|
||||
// reset pagination
|
||||
@@ -241,7 +242,8 @@ angular.module("umbraco")
|
||||
pageNumber: 1,
|
||||
pageSize: 100,
|
||||
totalItems: 0,
|
||||
totalPages: 0
|
||||
totalPages: 0,
|
||||
filter: ''
|
||||
};
|
||||
getChildren($scope.currentFolder.id);
|
||||
}
|
||||
@@ -250,7 +252,7 @@ angular.module("umbraco")
|
||||
|
||||
function searchMedia() {
|
||||
$scope.loading = true;
|
||||
mediaResource.search($scope.searchTerm, $scope.searchOptions.pageNumber, $scope.searchOptions.pageSize, $scope.startNodeId)
|
||||
entityResource.getPagedDescendants($scope.startNodeId, "Media", $scope.searchOptions)
|
||||
.then(function (data) {
|
||||
// update images
|
||||
$scope.images = data.items ? data.items : [];
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
<i class="icon-search"></i>
|
||||
<input
|
||||
class="umb-search-field search-query"
|
||||
ng-model="searchTerm"
|
||||
ng-model="searchOptions.filter"
|
||||
localize="placeholder"
|
||||
placeholder="@placeholders_search"
|
||||
ng-change="changeSearch()"
|
||||
|
||||
@@ -430,6 +430,53 @@ namespace Umbraco.Web.Editors
|
||||
}
|
||||
}
|
||||
|
||||
public PagedResult<EntityBasic> GetPagedDescendants(
|
||||
int id,
|
||||
UmbracoEntityTypes type,
|
||||
int pageNumber,
|
||||
int pageSize,
|
||||
string orderBy = "SortOrder",
|
||||
Direction orderDirection = Direction.Ascending,
|
||||
string filter = "")
|
||||
{
|
||||
if (pageNumber <= 0)
|
||||
throw new HttpResponseException(HttpStatusCode.NotFound);
|
||||
if (pageSize <= 0)
|
||||
throw new HttpResponseException(HttpStatusCode.NotFound);
|
||||
|
||||
var objectType = ConvertToObjectType(type);
|
||||
if (objectType.HasValue)
|
||||
{
|
||||
long totalRecords;
|
||||
var entities = Services.EntityService.GetPagedDescendants(id, objectType.Value, pageNumber - 1, pageSize, out totalRecords, orderBy, orderDirection, filter);
|
||||
|
||||
if (totalRecords == 0)
|
||||
{
|
||||
return new PagedResult<EntityBasic>(0, 0, 0);
|
||||
}
|
||||
|
||||
var pagedResult = new PagedResult<EntityBasic>(totalRecords, pageNumber, pageSize)
|
||||
{
|
||||
Items = entities.Select(Mapper.Map<EntityBasic>)
|
||||
};
|
||||
|
||||
return pagedResult;
|
||||
}
|
||||
|
||||
//now we need to convert the unknown ones
|
||||
switch (type)
|
||||
{
|
||||
case UmbracoEntityTypes.PropertyType:
|
||||
case UmbracoEntityTypes.PropertyGroup:
|
||||
case UmbracoEntityTypes.Domain:
|
||||
case UmbracoEntityTypes.Language:
|
||||
case UmbracoEntityTypes.User:
|
||||
case UmbracoEntityTypes.Macro:
|
||||
default:
|
||||
throw new NotSupportedException("The " + typeof(EntityController) + " does not currently support data for the type " + type);
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<EntityBasic> GetAncestors(int id, UmbracoEntityTypes type)
|
||||
{
|
||||
return GetResultForAncestors(id, type);
|
||||
|
||||
@@ -315,31 +315,6 @@ namespace Umbraco.Web.Editors
|
||||
}
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Searches media and returns a paged result
|
||||
/// </summary>
|
||||
/// <param name="query"></param>
|
||||
/// <param name="pageNumber"></param>
|
||||
/// <param name="pageSize"></param>
|
||||
/// <param name="searchFrom"></param>
|
||||
/// <returns></returns>
|
||||
[HttpGet]
|
||||
[FilterAllowedOutgoingMedia(typeof(IEnumerable<ContentItemBasic<ContentPropertyBasic, IMedia>>), "Items")]
|
||||
public PagedResult<ContentItemBasic<ContentPropertyBasic, IMedia>> Search(string query, int pageNumber = 0,
|
||||
int pageSize = 0, string searchFrom = null)
|
||||
{
|
||||
if (string.IsNullOrEmpty(query))
|
||||
return new PagedResult<ContentItemBasic<ContentPropertyBasic, IMedia>>(0, 0, 0);
|
||||
|
||||
var searchResult = ExamineSearch(query, searchFrom).ToArray();
|
||||
var items = searchResult.Skip(pageSize * (pageNumber - 1)).Take(pageSize);
|
||||
var pagedResult = new PagedResult<ContentItemBasic<ContentPropertyBasic, IMedia>>(searchResult.Length, pageNumber, pageSize);
|
||||
pagedResult.Items = Services.MediaService.GetByIds(items.Select(x => Convert.ToInt32(x.Id)))
|
||||
.Select(Mapper.Map<IMedia, ContentItemBasic<ContentPropertyBasic, IMedia>>);
|
||||
|
||||
return pagedResult;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Moves an item to the recycle bin, if it is already there then it will permanently delete it
|
||||
/// </summary>
|
||||
@@ -858,144 +833,5 @@ namespace Umbraco.Web.Editors
|
||||
|
||||
return hasPathAccess;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Searches for results based on the entity type
|
||||
/// </summary>
|
||||
/// <param name="query"></param>
|
||||
/// <param name="searchFrom">
|
||||
/// A starting point for the search, generally a node id, but for members this is a member type alias
|
||||
/// </param>
|
||||
/// <returns></returns>
|
||||
private IEnumerable<EntityBasic> ExamineSearch(string query, string searchFrom = null)
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
|
||||
string type;
|
||||
var searcher = Constants.Examine.InternalSearcher;
|
||||
var fields = new[] { "id", "__NodeId" };
|
||||
|
||||
type = "media";
|
||||
|
||||
var mediaSearchFrom = int.MinValue;
|
||||
|
||||
if (Security.CurrentUser.StartMediaId > 0 ||
|
||||
//if searchFrom is specified and it is greater than 0
|
||||
(searchFrom != null && int.TryParse(searchFrom, out mediaSearchFrom) && mediaSearchFrom > 0))
|
||||
{
|
||||
sb.Append("+__Path: \\-1*\\,");
|
||||
sb.Append(mediaSearchFrom > 0
|
||||
? mediaSearchFrom.ToString(CultureInfo.InvariantCulture)
|
||||
: Security.CurrentUser.StartMediaId.ToString(CultureInfo.InvariantCulture));
|
||||
sb.Append("\\,* ");
|
||||
}
|
||||
|
||||
var internalSearcher = ExamineManager.Instance.SearchProviderCollection[searcher];
|
||||
|
||||
//build a lucene query:
|
||||
// the __nodeName will be boosted 10x without wildcards
|
||||
// then __nodeName will be matched normally with wildcards
|
||||
// the rest will be normal without wildcards
|
||||
|
||||
|
||||
//check if text is surrounded by single or double quotes, if so, then exact match
|
||||
var surroundedByQuotes = Regex.IsMatch(query, "^\".*?\"$")
|
||||
|| Regex.IsMatch(query, "^\'.*?\'$");
|
||||
|
||||
if (surroundedByQuotes)
|
||||
{
|
||||
//strip quotes, escape string, the replace again
|
||||
query = query.Trim(new[] { '\"', '\'' });
|
||||
|
||||
query = Lucene.Net.QueryParsers.QueryParser.Escape(query);
|
||||
|
||||
if (query.IsNullOrWhiteSpace())
|
||||
{
|
||||
return new List<EntityBasic>();
|
||||
}
|
||||
|
||||
//add back the surrounding quotes
|
||||
query = string.Format("{0}{1}{0}", "\"", query);
|
||||
|
||||
//node name exactly boost x 10
|
||||
sb.Append("+(__nodeName: (");
|
||||
sb.Append(query.ToLower());
|
||||
sb.Append(")^10.0 ");
|
||||
|
||||
foreach (var f in fields)
|
||||
{
|
||||
//additional fields normally
|
||||
sb.Append(f);
|
||||
sb.Append(": (");
|
||||
sb.Append(query);
|
||||
sb.Append(") ");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (query.Trim(new[] { '\"', '\'' }).IsNullOrWhiteSpace())
|
||||
{
|
||||
return new List<EntityBasic>();
|
||||
}
|
||||
|
||||
query = Lucene.Net.QueryParsers.QueryParser.Escape(query);
|
||||
|
||||
var querywords = query.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
|
||||
//node name exactly boost x 10
|
||||
sb.Append("+(__nodeName:");
|
||||
sb.Append("\"");
|
||||
sb.Append(query.ToLower());
|
||||
sb.Append("\"");
|
||||
sb.Append("^10.0 ");
|
||||
|
||||
//node name normally with wildcards
|
||||
sb.Append(" __nodeName:");
|
||||
sb.Append("(");
|
||||
foreach (var w in querywords)
|
||||
{
|
||||
sb.Append(w.ToLower());
|
||||
sb.Append("* ");
|
||||
}
|
||||
sb.Append(") ");
|
||||
|
||||
|
||||
foreach (var f in fields)
|
||||
{
|
||||
//additional fields normally
|
||||
sb.Append(f);
|
||||
sb.Append(":");
|
||||
sb.Append("(");
|
||||
foreach (var w in querywords)
|
||||
{
|
||||
sb.Append(w.ToLower());
|
||||
sb.Append("* ");
|
||||
}
|
||||
sb.Append(")");
|
||||
sb.Append(" ");
|
||||
}
|
||||
}
|
||||
|
||||
//must match index type
|
||||
sb.Append(") +__IndexType:");
|
||||
sb.Append(type);
|
||||
|
||||
var raw = internalSearcher.CreateSearchCriteria().RawQuery(sb.ToString());
|
||||
|
||||
//limit results to 200 to avoid huge over processing (CPU)
|
||||
var result = internalSearcher.Search(raw, 200);
|
||||
|
||||
var mapped = Mapper.Map<IEnumerable<EntityBasic>>(result).ToArray();
|
||||
//add additional data
|
||||
foreach (var m in mapped)
|
||||
{
|
||||
//if no icon could be mapped, it will be set to document, so change it to picture
|
||||
if (m.Icon == "icon-document")
|
||||
{
|
||||
m.Icon = "icon-picture";
|
||||
}
|
||||
}
|
||||
return mapped;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user