Skip to content

Instantly share code, notes, and snippets.

@gregwiechec
Last active September 16, 2016 19:54
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save gregwiechec/38188931a443bf913eea to your computer and use it in GitHub Desktop.
Save gregwiechec/38188931a443bf913eea to your computer and use it in GitHub Desktop.
Editor Favourite Content
define([
"dojo/_base/declare",
"dojo/_base/lang",
"dojo/when",
"epi/shell/command/_Command",
"epi/dependency",
"epi-cms/_ContentContextMixin",
"./favouriteContextMixin"
],
function(
declare,
lang,
when,
_Command,
dependency,
_ContentContextMixin,
FavouriteContextMixin
) {
return declare([_Command, _ContentContextMixin, FavouriteContextMixin], {
name: "ContentReferences",
label: "Favourite content",
tooltip: "Favourite content",
iconClass: 'epi-icon--medium epi-iconStar',
canExecute: true,
addedToFavourite: false,
constructor: function() {
var registry = dependency.resolve("epi.storeregistry");
this.favouriteContentStore = registry.get("alloy.favouriteContentStore");
var contentId = this.getCurrentContext().id;
this.favouriteContentStore.get(contentId).then(lang.hitch(this, function (result) {
this.favouriteContentChanged(contentId, result); //this._updateFavouriteStatus(result);
}));
},
_execute: function() {
this.addedToFavourite = !this.addedToFavourite;
when(this.getCurrentContext(), lang.hitch(this, function(currentContext) {
var postParams = { contentReference: currentContext.id, addToFavourite: this.addedToFavourite };
this.favouriteContentStore.add(postParams).then(lang.hitch(this, function (result) {
this.favouriteContentChanged(currentContext.id, result.addToFavourite);
}));
}));
},
contentContextChanged: function(content) {
this.favouriteContentStore.get(content.id).then(lang.hitch(this, function (result) {
this._updateFavouriteStatus(result);
}));
},
_updateFavouriteStatus: function(result) {
this.set("active", result);
this.set('label', result ? "Remove from favourites" : "Add to your favourites");
this.addedToFavourite = result;
},
onFavouriteContentRemoveAll: function() {
this._updateFavouriteStatus(false);
},
onFavouriteContentChanged: function (contentId, adToFavourite) {
this._updateFavouriteStatus(adToFavourite);
}
});
});
define([
"dojo",
"dojo/_base/declare",
"epi/_Module",
"epi/dependency",
"epi/routes",
"favourites/commandsProvider",
"epi/shell/store/Throttle",
"epi/shell/store/JsonRest"
], function (
dojo,
declare,
_Module,
dependency,
routes,
CommandsProvider,
Throttle,
JsonRest
) {
return declare([_Module], {
initialize: function () {
this.inherited(arguments);
var registry = this.resolveDependency("epi.storeregistry");
//Register store
registry.add("alloy.favouriteContentStore",
new Throttle(
new JsonRest({
target: this._getRestPath("favouriteContentStore"),
idProperty: "contentLink"
})
)
);
var commandsProvider = new CommandsProvider();
var commandregistry = dependency.resolve("epi.globalcommandregistry");
var area = "epi.cms.globalToolbar";
commandregistry.registerProvider(area, commandsProvider);
},
_getRestPath: function (name) {
return routes.getRestPath({ moduleArea: "App", storeName: name });
}
});
});
define([
"dojo",
"dojo/_base/declare",
"dijit/form/ToggleButton",
"epi-cms/component/command/_GlobalToolbarCommandProvider",
"favourites/addToFavouritesCommand"
], function (dojo, declare, ToggleButton, _GlobalToolbarCommandProvider, AddToFavouritesCommand) {
return declare([_GlobalToolbarCommandProvider], {
constructor: function () {
this.inherited(arguments);
var addToFavouritesCommand = new AddToFavouritesCommand({
//label: "First command"
});
this.addToLeading(addToFavouritesCommand,
{
showLabel: false,
widget: ToggleButton,
'class': 'favourite-button'
//'epi-disabledDropdownArrow epi-groupedButtonContainer'//'epi-leadingToggleButton epi-disabledDropdownArrow dijitDropDownButton' // dijitChecked
});
}
});
});
define([
"dojo",
"dojo/when",
"dojo/_base/lang",
"dojo/_base/declare",
"epi/dependency",
"epi/shell/command/_CommandProviderMixin",
"epi/shell/command/DelegateCommand",
"epi-cms/component/command/ChangeContext",
"epi-cms/_ContentContextMixin",
"./favouriteContextMixin"
], function (
dojo,
when,
lang,
declare,
dependency,
_CommandProviderMixin,
DelegateCommand,
ChangeContext,
_ContentContextMixin,
FavouriteContextMixin
) {
return declare([_CommandProviderMixin, _ContentContextMixin, FavouriteContextMixin], {
category: "context",
constructor: function() {
this.inherited(arguments);
var registry = dependency.resolve("epi.storeregistry");
var favouriteContentStore = registry.get("alloy.favouriteContentStore");
this.add("commands", new ChangeContext({
category: "context"
}));
this.add("commands", new DelegateCommand({
name: "remove",
category: "context",
label: 'Remove',
iconClass: "epi-iconTrash",
canExecute: true,
isAvailable: true,
delegate: lang.hitch(this, function() {
when(this.getCurrentContext(), lang.hitch(this, function(currentContext) {
var contentId = currentContext.id;
favouriteContentStore.add({ contentReference: contentId, addToFavourite: false }).then(lang.hitch(this, function (result) {
this.favouriteContentChanged(contentId, false);
}));
}));
})
}));
}
});
});
.favourite-content-list {
padding: 10px;
margin: 0;
}
.favourite-content-list ul {
height: 100%;
overflow-y: scroll;
}
.favourite-content-list li {
padding-bottom: 10px;
}
.favourite-content-list li a:hover {
color: #aaa;
}
<div class="favourite-content-list" tabindex="-1" role="presentation">
<ul v data-dojo-attach-point="linkList"></ul>
</div>
.Sleek .dijitToggleButton.favourite-button .dijitButtonNode {
background: #555b62;
background-image: none;
border: 1px solid #555b62;
background-position-x: -24px;
padding: 0;
margin-right: 5px;
}
.Sleek .dijitToggleButton.favourite-button .dijitButtonNode:hover {
background: #A3A9B0;
}
.Sleek .dijitToggleButton.favourite-button .dijitButtonNode .dijitButtonContents {
padding: 0 5px 0 5px;
}
.Sleek .dijitToggleButton.favourite-button .dijitButtonNode .dijitIcon {
background-position-x: -24px;
padding: 0;
margin: 0;
}
.Sleek .dijitToggleButton.favourite-button.dijitChecked .dijitButtonNode .dijitIcon {
background-position-x: -120px;
}
using EPiServer.Shell.ViewComposition;
namespace FavouriteContentList.Business.FavouriteContent
{
[Component]
public class FavouriteContent : ComponentDefinitionBase
{
public FavouriteContent()
: base("favourites.favouriteContentComponent")
{
Description = "Shows user favourite content";
Title = "My Favourite Content";
this.Categories = new string[] {"content"};
this.SortOrder = 120;
this.PlugInAreas = new string[]
{
"/episerver/cms/mainnavigation"
};
this.Settings.Add(new Setting("open", (object) false, true));
this.Settings.Add(new Setting("dndFormatSuffix", (object) "fragment"));
}
}
}
define([
"dojo/_base/declare",
"dojo/_base/lang",
"dojo/when",
"epi",
"epi/dependency",
"epi/shell/command/_WidgetCommandProviderMixin",
"epi/shell/command/_Command",
"epi/shell/widget/_FocusableMixin",
"epi-cms/contentediting/ContentActionSupport",
"epi-cms/core/ContentReference",
"epi-cms/widget/_GridWidgetBase",
"epi-cms/_ContentContextMixin",
"./componentCommandsProvider",
"./favouriteContextMixin",
"epi/i18n!epi/cms/nls/episerver.cms.components.recentlychanged"
],
function (
declare,
lang,
when,
epi,
dependency,
_WidgetCommandProviderMixin,
_Command,
_FocusableMixin,
ContentActionSupport,
ContentReference,
_GridWidgetBase,
_ContentContextMixin,
ComponentCommandsProvider,
FavouriteContextMixin,
resources
) {
return declare([_GridWidgetBase, _WidgetCommandProviderMixin, _FocusableMixin, _ContentContextMixin, FavouriteContextMixin], {
_componentsController: null,
contextChangeEvent: "dblclick",
menuProvider: new ComponentCommandsProvider(),
constructor: function () {
var registry = dependency.resolve("epi.storeregistry");
this.favouriteContentStore = registry.get("alloy.favouriteContentStore");
},
postMixInProperties: function () {
this.storeKeyName = "alloy.favouriteContentStore";
this._componentsController = dependency.resolve("epi.shell.controller.Components");
this.ignoreVersionWhenComparingLinks = false;
this.inherited(arguments);
},
buildRendering: function () {
this.inherited(arguments);
var gridSettings = lang.mixin({
columns: this._createGridColumns(),
store: this.store,
selectionMode: "single"
}, this.defaultGridMixin);
this.grid = new this._gridClass(gridSettings, this.domNode);
this.grid.contextMenu.addProvider(this.menuProvider);
},
startup: function () {
if (this._started) {
return;
}
this.inherited(arguments);
this.addToFavouriteCommand = new _Command({
iconClass: "epi-iconPlus",
label: epi.resources.action.add,
canExecute: false,
_execute: lang.hitch(this, function () {
when(this.getCurrentContext(), lang.hitch(this, function (currentContext) {
var contentId = currentContext.id;
this.favouriteContentStore.add({ contentReference: contentId, addToFavourite: true }).then(lang.hitch(this, function (result) {
this.grid.refresh();
this.favouriteContentChanged(contentId, true);
}));
}));
})
});
var commands = [
new _Command({
label: "Remove all",
iconClass: "epi-iconTrash",
category: "setting",
canExecute: true,
_execute: lang.hitch(this, function () {
when(this.store.executeMethod("RemoveAll", 'removeAll')).then(lang.hitch(this, function() {
this.grid.refresh();
this._updateAddToFavouriteCommandStatus(true);
this.favouriteContentRemoveAll();
}));
})
}),
new _Command({
iconClass: "epi-iconReload",
label: epi.resources.action.refresh,
canExecute: true,
_execute: lang.hitch(this, function () {
this.grid.refresh();
})
}),
this.addToFavouriteCommand];
this.add("commands", commands);
this.fetchData();
when(this.getCurrentContent(), lang.hitch(this, function(content) {
this._refreshAddFavouriteActionState(content.contentLink);
}));
},
fetchData: function () {
var query = this._getQuery();
this.grid.set("query", query.query, query.options);
},
_getQuery: function () {
return {
query: { query: 'recentlychanged', onlyShowMyChanges: this.onlyShowMyChanges, keepversion: true },
options: { ignore: ["query"], sort: [{ attribute: "saved", descending: true }] }
};
},
_createGridColumns: function () {
var columns = {
name: {
label: epi.resources.header.name,
className: "epi-width50",
renderCell: lang.hitch(this, this._renderContentItem)
},
status: {
label: epi.resources.header.status,
renderCell: function (item, value, node, options) {
node.innerHTML = ContentActionSupport.getVersionStatus(value);
},
className: "epi-width15"
},
action: {
label: " ",
className: "epi-width10",
renderCell: function (item, value, node, options) {
node.innerHTML = '<span class="dijitInline dijitIcon epi-iconContextMenu epi-floatRight" title="Options">&nbsp;</span>';
},
sortable: false
}
};
return columns;
},
onContextChanged: function (context) {
// summary:
// Selects the current context item if it exists in the grid.
this.grid.clearSelection();
var versionAgnosticLink = new ContentReference(context.id).createVersionUnspecificReference().toString();
var row = this.grid.row(versionAgnosticLink);
if (row) {
this.grid.select(row);
}
},
contentContextChanged: function (content) {
this._refreshAddFavouriteActionState(content.id);
},
_refreshAddFavouriteActionState: function (content) {
this.favouriteContentStore.get(content).then(lang.hitch(this, function (result) {
this._updateAddToFavouriteCommandStatus(!result);
}));
},
_onSelect: function (e) {
for (var i = 0; i < this.menuProvider.commands.length; i++) {
this.menuProvider.commands[i].set('model', e.rows[0].data);
}
},
onFavouriteContentChanged: function (contentId, addToFavourite) {
this.grid.refresh();
this._updateAddToFavouriteCommandStatus(!addToFavourite);
},
_updateAddToFavouriteCommandStatus(canExecute) {
this.addToFavouriteCommand.set('canExecute', canExecute);
}
});
});
using EPiServer.Framework;
using EPiServer.Framework.Initialization;
using EPiServer.ServiceLocation;
namespace FavouriteContentList.Business.FavouriteContent
{
[InitializableModule]
[ModuleDependency(typeof(EPiServer.Web.InitializationModule))]
public class FavouriteContentInitializableModule: IConfigurableModule
{
public void ConfigureContainer(ServiceConfigurationContext context)
{
context.Services.AddSingleton<IFavouriteContentStorage, FavouriteContentStorage>();
}
public void Initialize(InitializationEngine context)
{
}
public void Uninitialize(InitializationEngine context)
{
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Principal;
using EPiServer.Core;
using EPiServer.Data.Dynamic;
namespace FavouriteContentList.Business.FavouriteContent
{
public class FavouriteContentStorage: IFavouriteContentStorage
{
public static DynamicDataStore GetDataStore()
{
var store = typeof(UserFavouriteContnet).GetOrCreateStore();
store.KeepObjectsInContext = false;
return store;
}
public bool Add(IPrincipal principal, ContentReference contentReference)
{
using (var dataStore = GetDataStore())
{
if (dataStore == null)
{
return false;
}
var userFavouriteContent = GetUserFavouriteContent(principal, dataStore) ?? new UserFavouriteContnet() { UserId = GetUserId(principal)};
var contentReferences = ConvertContentList(userFavouriteContent).ToList();
contentReferences.Add(contentReference.ToReferenceWithoutVersion());
contentReferences = contentReferences.Distinct().ToList();
userFavouriteContent.FavouriteList = ConvertFromContentList(contentReferences);
dataStore.Save(userFavouriteContent);
return true;
}
}
public bool Remove(IPrincipal principal, ContentReference contentReference)
{
using (var dataStore = GetDataStore())
{
if (dataStore == null)
{
return false;
}
var userFavouriteContent = GetUserFavouriteContent(principal, dataStore) ?? new UserFavouriteContnet() { UserId = GetUserId(principal) };
var contentReferences = ConvertContentList(userFavouriteContent).ToList();
contentReferences.Remove(contentReference.ToReferenceWithoutVersion());
contentReferences = contentReferences.Distinct().ToList();
userFavouriteContent.FavouriteList = ConvertFromContentList(contentReferences);
dataStore.Save(userFavouriteContent);
return false;
}
}
public IEnumerable<ContentReference> GetByUser(IPrincipal principal)
{
using (var dataStore = GetDataStore())
{
if (dataStore == null)
{
return Enumerable.Empty<ContentReference>();
}
var userFavouriteContent = GetUserFavouriteContent(principal, dataStore);
var favouriteContentList = ConvertContentList(userFavouriteContent);
return favouriteContentList;
}
}
public bool RemoveAll(IPrincipal principal)
{
using (var dataStore = GetDataStore())
{
if (dataStore == null)
{
return false;
}
var userFavouriteContent = GetUserFavouriteContent(principal, dataStore);
if (userFavouriteContent == null)
{
return true;
}
userFavouriteContent.FavouriteList = ConvertFromContentList(Enumerable.Empty<ContentReference>());
dataStore.Save(userFavouriteContent);
}
return true;
}
private static IEnumerable<ContentReference> ConvertContentList(UserFavouriteContnet userFavouriteContent)
{
return userFavouriteContent
?.FavouriteList
?.Split(new string[] {","}, StringSplitOptions.RemoveEmptyEntries)
.Select(ContentReference.Parse) ?? Enumerable.Empty<ContentReference>();
}
private static string ConvertFromContentList(IEnumerable<ContentReference> contentReferences)
{
var result = string.Join(",", contentReferences.Select(cr => cr.ToReferenceWithoutVersion().ToString()));
return result;
}
private static UserFavouriteContnet GetUserFavouriteContent(IPrincipal principal, DynamicDataStore dataStore)
{
return dataStore.Items<UserFavouriteContnet>().FirstOrDefault(u => u.UserId == GetUserId(principal));
}
private static string GetUserId(IPrincipal principal)
{
return principal.Identity.Name;
}
}
public interface IFavouriteContentStorage
{
bool Add(IPrincipal principal, ContentReference contentReference);
bool Remove(IPrincipal principal, ContentReference contentReference);
IEnumerable<ContentReference> GetByUser(IPrincipal principal);
bool RemoveAll(IPrincipal principal);
}
[EPiServerDataStore(AutomaticallyRemapStore = true, AutomaticallyCreateStore = true)]
public class UserFavouriteContnet
{
public Guid Id { get; set; }
public string UserId { get; set; }
public string FavouriteList { get; set; }
}
}
using EPiServer.Cms.Shell.UI.Rest.Models;
using EPiServer.Core;
using EPiServer.Globalization;
using EPiServer.Security;
using EPiServer.Shell.Rest;
using EPiServer.Shell.Services.Rest;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Web.Mvc;
using EPiServer;
using EPiServer.Cms.Shell.UI.Rest;
using EPiServer.Cms.Shell.UI.Rest.ContentQuery;
using EPiServer.ServiceLocation;
namespace FavouriteContentList.Business.FavouriteContent
{
[RestStore("favouriteContentStore")]
public class FavouriteContentStore : RestControllerBase
{
private readonly IFavouriteContentStorage _favouriteContentStorage;
private readonly IContentQueryProvider _queryProvider;
private readonly IContentRepository _contentRepository;
private readonly IContentStoreModelCreator _contentStoreModelCreator;
public FavouriteContentStore(IContentRepository contentRepository,
IContentStoreModelCreator contentStoreModelCreator,
IContentQueryProvider queryProvider,
IFavouriteContentStorage favouriteContentStorage
)
{
this._contentRepository = contentRepository;
this._contentStoreModelCreator = contentStoreModelCreator;
this._queryProvider = queryProvider;
this._favouriteContentStorage = favouriteContentStorage;
}
[HttpGet]
public RestResult Get(ContentReference id, string query, ContentReference referenceId, string[] typeIdentifiers,
bool? allLanguages, IEnumerable<SortColumn> sortColumns, ItemRange range)
{
var contentReferences = this._favouriteContentStorage.GetByUser(HttpContext.User);
if (id != null && id != ContentReference.EmptyReference)
{
var result = contentReferences
.FirstOrDefault(cr => cr.CompareToIgnoreWorkID(id));
return this.Rest(result != null);
}
var contentQueryParameters = new ContentQueryParameters
{
ReferenceId = referenceId,
AllLanguages = allLanguages.GetValueOrDefault(),
TypeIdentifiers = (IEnumerable<string>) typeIdentifiers,
SortColumns = sortColumns,
Range = range,
AllParameters = this.ControllerContext.HttpContext.Request.QueryString,
CurrentPrincipal = PrincipalInfo.CurrentPrincipal,
PreferredCulture =
allLanguages.GetValueOrDefault() ? (CultureInfo) null : ContentLanguage.PreferredCulture
};
var parameters = contentQueryParameters;
var contentVersionRepository = ServiceLocator.Current.GetInstance<IContentVersionRepository>();
var resultList = contentReferences
.Select(cr => contentVersionRepository.LoadCommonDraft(cr, ContentLanguage.PreferredCulture.Name))
.Select(cr => this._contentRepository.Get<IContent>(cr.ContentLink))
.Where(c => c != null);
var structureStoreContentDataModels = this.CreateStoreModels(resultList, parameters);
if (sortColumns != null)
{
structureStoreContentDataModels = structureStoreContentDataModels.AsQueryable().OrderBy(sortColumns);
}
var restResult = this.Rest(structureStoreContentDataModels);
var queryRange = this.GetQuery(query ?? "", parameters).ExecuteQuery(parameters);
restResult.Range = queryRange.Range;
return restResult;
}
private IRestQuery<IContent> GetQuery(string queryName, ContentQueryParameters parameters)
{
queryName = "searchcontent";
IRestQuery<IContent> query = this._queryProvider.GetQuery(queryName, (IQueryParameters) parameters);
if (query == null)
throw new ArgumentException("There is no content query registered with the name " + queryName +
" or none that accepts the query parameters.");
return query;
}
private IEnumerable<StructureStoreContentDataModel> CreateStoreModels(IEnumerable<IContent> content,
DefaultQueryParameters queryParameters)
{
return this._contentStoreModelCreator.CreateContentDataStoreModels<StructureStoreContentDataModel>(content,
queryParameters);
}
public RestResult RemoveAll()
{
var result = this._favouriteContentStorage.RemoveAll(HttpContext.User);
return this.Rest(result);
}
[HttpPost]
public ActionResult Post(PostFavouriteContent postFavouriteContent)
{
if (postFavouriteContent.AddToFavourite)
{
postFavouriteContent.AddToFavourite = this._favouriteContentStorage.Add(HttpContext.User,
postFavouriteContent.ContentReference);
}
else
{
postFavouriteContent.AddToFavourite = this._favouriteContentStorage.Remove(HttpContext.User,
postFavouriteContent.ContentReference);
}
return this.Rest((object) postFavouriteContent);
}
}
public class PostFavouriteContent
{
public ContentReference ContentReference { get; set; }
public bool AddToFavourite { get; set; }
}
}
define([
"dojo/_base/declare",
"dojo/_base/lang",
"dojo/topic",
"dijit/Destroyable"
],
function (
declare,
lang,
topic,
Destroyable
) {
return declare([Destroyable], {
constructor: function (options) {
this.own(
topic.subscribe("/favouriteContent/changed", lang.hitch(this, this._favouriteContentChanged)),
topic.subscribe("/favouriteContent/removeAll", lang.hitch(this, this._favouriteContentRemoveAll))
);
},
favouriteContentChanged: function(contentId, adToFavourite) {
topic.publish("/favouriteContent/changed", { sender: this, contentId: contentId, adToFavourite: adToFavourite });
},
favouriteContentRemoveAll: function () {
topic.publish("/favouriteContent/removeAll", { sender: this });
},
_favouriteContentChanged: function(data) {
this.onFavouriteContentChanged(data.contentId, data.adToFavourite);
},
_favouriteContentRemoveAll: function() {
this.onFavouriteContentRemoveAll();
},
onFavouriteContentChanged: function(contentId, adToFavourite) {
},
onFavouriteContentRemoveAll: function() {
}
});
});
<?xml version="1.0" encoding="utf-8" ?>
<module>
<clientResources>
<add dependency="epi-cms.widgets.base" path="scripts/commandsInitializer.js" resourceType="Script" />
</clientResources>
<clientModule initializer="favourites.commandsInitializer">
<moduleDependencies>
<add dependency="CMS" type="RunAfter" />
</moduleDependencies>
</clientModule>
<dojo>
<paths>
<add name="favourites" path="scripts" />
</paths>
</dojo>
<clientResources>
<add name="epi-cms.widgets.base" path="scripts/content/favourite.css" resourceType="Style">
</add>
</clientResources>
</module>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment