Multiple category folders to same folder?
Is it possible to add multiple category folders? I have a schema that needs to have two relations to another same schema. Like a product has a list of products as up sell relation and another list as a cross sell relation.

cheers aruss
I found myself in a situation where this would also be useful for me but it seems it is not possible because you can only retrieve categories by foldername and there is no other way to make a distinction between the data, all items will appear to be selected in both controls
@aruss
Yes, that's possible. That's why here have "plus" button to add another category folder.
Ok but how do I distinguish them, if the product has a two lists of products, like up and cross sells, how do I get only the up selled products? I only can pass the folder for the category but not the name for the relation.
I have created a custom TextContent picker control maybe the code is useful for you:
1. In Kooboo.CMS.Form create a new file TextContentPicker.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Kooboo.CMS.Form.Html.Controls
{
public class TextContentPicker : Input
{
public override string Name
{
get { return "TextContentPicker"; }
}
public override string Type
{
get { return "hidden"; }
}
/// <summary>
/// false
/// </summary>
protected virtual bool AllowMultipleFiles
{
get
{
return false;
}
}
/// <summary>
/// /^.+\..+$/
/// </summary>
protected virtual string Validation
{
get
{
return @"/^.+\..+$/";
}
}
/// <summary>
/// Please select a valid file
/// </summary>
protected virtual string ValidationErrorMessage
{
get
{
return "Please select a valid file";
}
}
protected override string RenderInput(Kooboo.CMS.Form.IColumn column)
{
string input = base.RenderInput(column);
string foldername = "slike";
column.CustomSettings.TryGetValue("folderName", out foldername);
string SingleChoice = "false";
column.CustomSettings.TryGetValue("SingleChoice", out SingleChoice);
// <%:Url.Action("Selection", "MediaContent", ViewContext.RequestContext.AllRouteValues())%>
/*string mediaLibraryUrl = @"<%:Url.Action(""Selection"", ""MediaContent"", new {
repositoryName = Kooboo.CMS.Sites.Models.Site.Current.Repository,
siteName = Kooboo.CMS.Sites.Models.Site.Current.Name
})%>";*/
string mediaLibraryUrl = @"@Url.Action(""SelectCategories"", ""TextContent"", new {
repositoryName = Kooboo.CMS.Sites.Models.Site.Current.Repository,
siteName = Kooboo.CMS.Sites.Models.Site.Current.FullName,
folderName = ""#folderName#"",
SingleChoice = ""#singlechoice#"",
TextContentMode = ""true""
})";
mediaLibraryUrl = mediaLibraryUrl.Replace("#folderName#", foldername);
mediaLibraryUrl = mediaLibraryUrl.Replace("#singlechoice#", SingleChoice);
input = String.Format(@"
<div id='textcontentpicker_{0}' class='textcontentpicker category-list clearfix' data-folderName='{2}'>
<ul data-bind='foreach: data'>
<li class='category-item-data'>
<span class='text left' data-bind='{{text:Text}}'></span>
<a class='remove right' data-bind='{{click: $parent.removeItem}}'>@Html.IconImage(""minus small"")</a>
</li>
</ul>
<input type='hidden' id='{0}' name='{0}' data-bind='{{value:postValue}}' value='@(Model.{0} ?? """")'/>
<a columnName='{0}' id=""textcontentpicker_btn_{0}""
href='{1}' class='action textcontentpickerButton'>@Html.IconImage(""plus small"")</a>
</div>
<script>
$(function(){{
textcontentpicker('#textcontentpicker_{0}')
}})
</script>
", column.Name, mediaLibraryUrl, foldername, column.DefaultValue);
return input;
}
}
}
- Register the new control in ControlHelper.cs in the same lib
RegisterControl(new TextContentPicker());
- In Kooboo.CMS.Web in TextContentControler.cs add this function
[Kooboo.CMS.Web.Authorizations.Authorization(AreaName = "Contents", Group = "", Name = "Content", Order = 1)]
[HttpGet]
public JsonResult JSONForUUIDs(string folderName, string UUIDs)
{
string[] uuids = UUIDs.Split(',');
TextFolder textFolder = new TextFolder(Repository, folderName).AsActual();
var schema = textFolder.GetSchema().AsActual();
var content = schema.CreateQuery().WhereIn("UUID", uuids).Select(i => new { Text= i.GetSummary(), UUID=i.UUID });
return Json(content, JsonRequestBehavior.AllowGet);
}
- in the root View/shared folder in MasterScript.cshtml add these two js functions:
function CategoryViewModel(data) {
var self = this;
self.data = ko.observableArray(data);
self.removeItem = function () {
window.leaveConfirm.stop();
self.data.remove(this);
};
self.addItem = function (uuid, text) {
window.leaveConfirm.stop();
self.data.push({ UUID: uuid, Text: text });
};
self.postValue = ko.computed(function () {
var uuid = [];
_.each(this.data(), function (item) {
uuid.push(item.UUID);
});
return uuid.join(',');
}, this);
}
// initiate textcontent picker
function textcontentpicker(id) {
var data = []
var categoryViewModel = new CategoryViewModel(data);
var categoryTemplate = $(id);
// load text summary for existing uuids
var url = '@Html.Raw(Url.Action("JSONForUUIDs", "TextContent", new
{
repositoryName = Kooboo.CMS.Sites.Models.Site.Current.Repository,
siteName = Kooboo.CMS.Sites.Models.Site.Current.FullName,
folderName = "_folderName_",
uuids = "_uuids_"
}))'
// add route values from js model
url = url.replace('_folderName_', categoryTemplate.data("foldername")).replace('_uuids_', categoryTemplate.find('input').val())
// bind knockout js after we read the uuids becouse it will remove them
ko.applyBindings(categoryViewModel, categoryTemplate[0]);
//alert(categoryTemplate.find('input').val())
// get data
$.getJSON(url, function (data) {
_.each(data, function (i) {
categoryViewModel.addItem(i.UUID, i.Text);
});
//alert(data)
})
// init add new click event
categoryTemplate.find("a.textcontentpickerButton").click(function (e) {
e.preventDefault();
var $categoryLink = $(this);
$categoryLink.pop({
popupOnTop: true,
width: 700,
height: 500,
dialogClass: 'iframe-dialog',
onclose: function () {
setTimeout(function () {
if ($.popContext.getCurrent() != null) {
$.popContext.getCurrent().find('iframe').height('100%');
}
}, 16);
},
onload: function (currentHandle, pop, config) {
var iframe = pop.children('iframe'),
iframeSrc = iframe[0].contentWindow.document.location.href;
if (iframeSrc == 'about:blank') {
return false;
}
var contents = iframe.contents();
_.each(categoryViewModel.data(), function (item, index) {
var $tr = contents.find('tr#' + item.UUID);
$tr.addClass('active');
$tr.find('input.select').attr('checked', 'checked');
});
(function initButton() {
var saveBtn = contents.find('.save'),
cancelBtn = contents.find('.cancel');
cancelBtn.click(function () {
pop.close();
});
saveBtn.click(function () {
var $selectedTr = contents.find('tr.active');
//categoryViewModel.data.removeAll();
_.each($selectedTr, function (tr) {
var $tr = $(tr);
var text = $tr.find('td:eq(1)').text(),
uuid = $tr.attr('id');
categoryViewModel.addItem(uuid, text);
});
pop.close();
});
})();
}
});
}).click()
}
With this control you can get referenced uuids by the field name so you can have the same folder in two controls, the downside is it saves the uuids in as a coma seperated string in a field in stead of the contentcategory table so you can only use it one direction.