Does anyone know how to get a list of all the items protected (and unprotected them after) in sitecore?
I've googled around but I didn't find any relevant results.
Thanks in advance
This is what I have so far...
var homeItem = Sitecore.Context.Database.GetItem(Sitecore.Context.Site.StartPath);
foreach (Item item in homeItem.Children)
{
if (item.Locking.IsLocked())
{
//to do
}
}
Unfortunately the item.Locking.IsLocked is not returning if the item is protected or not.
When you press protect or unprotect item this command is called:
item:togglereadonly
This is the part of the method who protect or unprotect item:
public override void Execute(CommandContext context)
{
if (context.Items.Length != 1)
return;
Item obj = context.Items[0];
obj.Editing.BeginEdit();
obj.Appearance.ReadOnly = !obj.Appearance.ReadOnly;
obj.Editing.EndEdit();
Log.Audit((object) this, "Toggle read only: {0}, value: {1}", AuditFormatter.FormatItem(obj), MainUtil.BoolToString(obj.Appearance.ReadOnly));
}
Found the solution
var homeItem = Sitecore.Context.Database.GetItem(Sitecore.Context.Site.StartPath);
foreach (Item item in homeItem.Children)
{
if (item.Appearance.ReadOnly)
{
//stuff here
}
}
Cheers
Related
Please see the code below. Pressing the button once (or twice at most) is almost certain to crash the app. The app shows a list containing two sections, each of which have four items. When button is pressed, it inserts a new item into each section and also changes the section order.
I have just submitted FB9952691 to Apple. But I wonder if anyone on SO happens to know 1) Does UIKit has the same issue? I'm just curious (the last time I used UIkit was two years ago). 2) Is it possible to work around the issue in SwiftUI? Thanks.
import SwiftUI
let groupNames = (1...2).map { "\($0)" }
let groupNumber = groupNames.count
let itemValues = (1...4)
let itemNumber = itemValues.count
struct Item: Identifiable {
var value: Int
var id = UUID()
}
struct Group: Identifiable {
var name: String
var items: [Item]
var id = UUID()
// insert a random item to the group
mutating func insertItem() {
let index = (0...itemNumber).randomElement()!
items.insert(Item(value: 100), at: index)
}
}
struct Data {
var groups: [Group]
// initial data: 2 sections, each having 4 items.
init() {
groups = groupNames.map { name in
let items = itemValues.map{ Item(value: $0) }
return Group(name: name, items: items)
}
}
// multiple changes: 1) reverse group order 2) insert a random item to each group
mutating func change() {
groups.reverse()
for index in groups.indices {
groups[index].insertItem()
}
}
}
struct ContentView: View {
#State var data = Data()
var body: some View {
VStack {
List {
ForEach(data.groups) { group in
Section {
ForEach(group.items) { item in
Text("\(group.name): \(item.value)")
}
}
header: {
Text("Section \(group.name)")
}
}
}
Button("Press to crash the app!") {
withAnimation {
data.change()
}
}
.padding()
}
}
}
More information:
The error message:
Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'UITableView internal inconsistency: encountered out of bounds global row index while preparing batch updates (oldRow=8, oldGlobalRowCount=8)'
The issue isn't caused by animation. Removing withAnimation still has the same issue. I believe the issue is caused by the section order change (though it works fine occasionally).
Update: Thank #Yrb for pointing out an out-of-index bug in insertItem(). That function is a setup utility in the example code and is irrelevant to the issue with change(). So please ignore it.
The problem is here:
// multiple changes: 1) reverse group order 2) insert a random item to each group
mutating func change() {
groups.reverse()
for index in groups.indices {
groups[index].insertItem()
}
}
You are attempting to do too much to the array at once, so in the middle of reversing the order, the array counts are suddenly off, and the List (and it's underlying UITableView) can't handle it. So, you can either reverse the rows, or add an item to the rows, but not both at the same time.
As a bonus, this will be your next crash:
// insert a random item to the group
mutating func insertItem() {
let index = (0...itemNumber).randomElement()!
items.insert(Item(value: 100), at: index)
}
though it is not causing the above as I fixed this first. You have set a fixed Int for itemNumber which is the count of the items in the first place. Arrays are 0 indexed, which means the initial array indices will be (0...3). This line let index = (0...itemNumber).randomElement()! gives you an index that is in the range of (0...4), so you have a 20% chance of crashing your app each time this runs. In this sort of situation, always use an index of (0..<Array.count) and make sure the array is not empty.
I got Apple's reply regarding FB9952691. The issue has been fixed in iOS16 (I verified it).
I got an issue when I tried to remove an item in a list. when I tried to remove a list it disappeared, but they show a new list. the case looks like this.
below I provided my code also
adapter.setOnItemClickedCallback(object : ListOrderAdapter.OnItemClickCallback {
override fun onDecrementButtonClicked(orderMenu: OrderMenu, itemView: View, position: Int) {
var quantityChanged = (orderMenu.quantity)!!.minus(1)
itemView.tv_order_number.text = quantityChanged.toString()
Log.e("Position", position.toString())
if (quantityChanged > 0) {
updateData(quantityChanged, orderMenu)
} else {
listItem.remove(orderMenu)
recyclerView.removeViewAt(position)
adapter.notifyItemRemoved(position)
adapter.notifyItemRangeRemoved(position, listItem.size)
Toast.makeText(applicationContext, "Pesanan telah di hapus dari orderan", Toast.LENGTH_SHORT).show()
}
}
})
}
private fun updateData(quantityChanged: Long, orderMenu: OrderMenu) {
for (item in listItem){
if (item.name.equals(orderMenu.name)){
item.quantity = quantityChanged
}
}
}
Is it possible to get __Rendering control's template field value on content item?
Especially, I'd like to get "Data Source" field value defined in control on page item, like below screenshot.
As shown in screenshot, I have some controls in page item and I'd like to get control's "Data Source" field value.
I used this code and I could list all controls using on the page item. But, I don't know how to get the control's browsed data-source information on the page.
public RenderingReference[] GetListOfSublayouts(string itemId, Item targetItem)
{
RenderingReference[] renderings = null;
if (Sitecore.Data.ID.IsID(itemId))
{
renderings = targetItem.Visualization.GetRenderings(Sitecore.Context.Device, true);
}
return renderings;
}
public List<RenderingItem> GetListOfDataSource(RenderingReference[] renderings)
{
List<RenderingItem> ListOfDataSource = new List<RenderingItem>();
foreach (RenderingReference rendering in renderings)
{
if (!String.IsNullOrEmpty(rendering.Settings.DataSource))
{
ListOfDataSource.Add(rendering.RenderingItem);
}
}
return ListOfDataSource;
}
RenderingReference[] renderings = GetListOfSublayouts(targetItem.ID.ToString(), targetItem);
List<RenderingItem> ListOfDataSource = GetListOfDataSource(renderings);
This is exactly what I wanted.
Perfectly working!!!!!!
public IEnumerable<string> GetDatasourceValue(Item targetItem)
{
List<string> uniqueDatasourceValues = new List<string>();
Sitecore.Layouts.RenderingReference[] renderings = GetListOfSublayouts(targetItem.ID.ToString(), targetItem);
foreach (var rendering in renderings)
{
if (!uniqueDatasourceValues.Contains(rendering.Settings.DataSource))
uniqueDatasourceValues.Add(rendering.Settings.DataSource);
}
return uniqueDatasourceValues;
}
}
Here is a blog post that can help: Using the Data Source Field with Sitecore Sublayouts
Here's the relevant code you can call from within a single control:
private Item _dataSource = null;
public Item DataSource
{
get
{
if (_dataSource == null)
if(Parent is Sublayout)
_dataSource = Sitecore.Context.Database.GetItem(((Sublayout)Parent).DataSource);
return _dataSource;
}
}
Accesing the DataSource property defined above will give you the item that is assigned as the Data Source from the CMS.
How do i create a Field value for a Particular Item in a Particular Language? I have an Excel that has all the item Names inside the RootItem .These Items exist in a en-US language Already. i need add values for a particular field for other languages.. Like en-GB, nl-NL, it-IT.
I have a List like
ItemName Language Translation
TestItem en-GB Hello
TestItem nl-NL Hallo
and so on..
The only problem is, when i do item.Add, it creates a new item rather than adding the value to the existing item. How can i handle this?
My code is as follows:
foreach (DataRow row in dt.Rows)
{
Language language = Language.Parse(languageId);
var rootItem = currentDatabase.GetItem(RootItemPath, language);
var item = rootItem.Add(itemName, templateItem);
if (item != null)
{
item.Fields.ReadAll();
item.Editing.BeginEdit();
try
{
//Add values for the fields
item.Fields["Translation"].Value = strTranslationValue;
}
catch (Exception)
{
item.Editing.EndEdit();
}
}
}
Try This:
var rootItem = currentDatabase.GetItem(RootItemPath);
foreach (DataRow row in dt.Rows)
{
Language language = Language.Parse(languageId);
var itemInCurrentLanguage = rootItem.Children.Where(i=>i.Name == itemName).FirstOrDefault();
if(itemInCurrentLanguage == null){
itemInCurrentLanguage = rootItem.Add(itemName, templateItem);
}
var itemInDestinationLanguage = currentDatabase.GetItem(itemInCurrentLanguage.ID, language );
if (itemInDestinationLanguage != null)
{
itemInDestinationLanguage.Fields.ReadAll();
itemInDestinationLanguage.Editing.BeginEdit();
try
{
//Add values for the fields
itemInDestinationLanguage.Fields["Translation"].Value = strTranslationValue;
}
catch (Exception)
{
//Log any error
}
finally
{
itemInDestinationLanguage.Editing.EndEdit();
}
}
}
You need to switch the language before you get the root item:
using (new LanguageSwitcher(language))
{
var rootItem = currentDatabase.GetItem(RootItemPath);
var item = rootItem.Add(selectedItem.Name, CommunityProjectTemplateId);
// Add new item here...
}
Normally, when I want to access the current Item in Sitecore, I go through Sitecore.Context.Item. This works well when creating a tool which will be used by the end user, but not for a tool which is consumed by the Sitecore admins. If I want something to show up as a custom field in the Content Editor itself, the Context.Item is a reference to the Content Editor and not to the node which is selected in the editor.
For the most part I can get around this by using the ItemID property, but if I have event dispatchers on the field, those will no longer have access to the ItemID. Eg:
protected override void OnPreRender(EventArgs e)
{
if (IsEvent)
{
// ItemID is defined here!
Button live = FindControl(GetID(LiveButton)) as Button;
if (live != null)
{
live.ServerProperties["Click"] = string.Format("{0}.LiveClicked", ID);
}
}
}
public void LiveClicked()
{
// ItemID is blank here!
DoSomething();
}
How do I gain access to ItemID in my listener (like LiveClicked above)?
The way I solved it was through something called ServerProperties and I called the equivalent to this function in every listener.
private void SyncID()
{
var live = FindControl(GetID(LiveButton)) as Button;
if (live != null)
{
if(string.IsNullOrEmpty(ItemID))
{
ItemID = live.ServerProperties["owner_id"].ToString();
}
live.ServerProperties["owner_id"] = ItemID;
}
}