How to access back-forward list of UIWebView - list

How can we get the no of list items in bad-forward list of UIWebView? What I wanted to do is when back list is empty (ie. when there is no link to go back) navigate to previous controller. So wanted to know the count in the list.
Thanks in advance
Sayali

you dont want to access backforward list just for that, simply use .canGoBack property.
Here is the way to do it anyways (be carefull, private API here) :
id webview111 = [self _documentView]; /// self - uiwebview subclass
coreWebV = [webview111 webView];
backForwardList = [coreWebV backForwardList];

Related

Identifying targetList in ember-drag-sort

I am currently trying to implement an ember-drag-sort nested list into my Ember.js app.
Is there a way to determine in the dragEnd action which "sub-list" the item has been dropped into? (e.g. a class name, id etc)
In my scenario, I am sorting ember data records that can belong to each other (i.e. a nested, 'tree' structure). When I drag one nested record "into" another (making the dragged record a child of the second record), I need to update the parent attribute in ember-data. My question is, how do you pass some id of the second record (the new parent) to the dragEnd action?
Is this even possible?
EDIT:
To put it another way, I want to be able to identify which list I have dropped the item into.
targetList refers to the array on the dragged side of the component. For pushing the parent to the target list alongside the child, you can take a look at this twiddle.
To simplify identification of lists, the additional arguments feature has been implemented by #rwwagner90 (SO, GitHub).
You can pass some kind of list identifier into the additionalArgs argument to your lists. In this example I'm passing parent records which own the lists:
{{#each parents as |parent|}}
{{#drag-sort-list
items = parent.children
additionalArgs = (hash parent=parent)
dragEndAction = (action 'dragEnd')
as |child|
}}
{{child.name}}
{{/drag-sort-list}}
{{/each}}
In the dragEnd action you can access the parent records that own the source list and the target list:
dragEndAction({ sourceList, sourceIndex, sourceArgs, targetList, targetIndex, targetArgs }) {
if (sourceModel === targetModel && sourceIndex === targetIndex) return;
const item = sourceList.objectAt(sourceIndex);
sourceList.removeAt(sourceIndex);
targetList.insertAt(targetIndex, item);
// Access the parent via `sourceArgs` and `targetArgs`
sourceArgs.parent.save();
targetArgs.parent.save();
}

How do we retrieve values of Custom Lists(dropdown) in Netsuite

I have record type "XYZ" which has field called "award area" which is of type list/record. "award area" is of type custom list and is a drop down control.
Using Suitetalk how can I retrieve those values from that drop down?
Thank you
I think something like this should work. It's for translating the results from the internalId's returned into the actual text type, you maybe be able to leverage it in another way. Maybe you could create a lookup list with something like this(C#):
public Dictionary<string, Dictionary<long, string>> getCustomFieldLists()
{
return
nsService.search(new CustomListSearch())
.recordList.Select(a => (CustomList) a)
.ToDictionary(a => a.name,
a => a.customValueList.customValue
.ToDictionary(b => b.valueId, c => c.value));
}
var valueLookup = getCustomFieldLists()["award area"];
Here's how I did it for myself, because I was irritated with the fact the NetSuite doesn't just provide us an easy way to access these. And I wanted the following data for reference:
The Internal ID of the Custom List
The Name of the Custom List
The Internal ID of the Custom List Item
The name Value of the Custom List Item
I wanted/needed access to all of those things, and I wanted to be able to obtain the name Value of the Custom List Item by just providing the Internal ID of the Custom List and the Internal ID of the Custom List Item. So, in my homemade integration client, similar to David Rogers' answer, but without all the fancy Linq, I figured out that the best solution was a Dictionary>>.
This way, for the outer Dictionary, I could set the key to the internal IDs of the Custom Lists, and for the inner Dictionary I could set the key to the internal IDs of the Custom List Items themselves. Then, I would get the name of the Custom List for "free" as the beginning part of the Tuple, and the actual name Value for "free" as the value of the internal Dictionary.
Below is my method code to generate this object:
/// <summary>
/// Gets the collection of all custom lists, and places it in the public CustomListEntries object
/// </summary>
/// <returns></returns>
private Dictionary<string, Tuple<string, Dictionary<long, string>>> GetCustomLists()
{
Dictionary<string, Tuple<string, Dictionary<long, string>>> customListEntries = new Dictionary<string, Tuple<string, Dictionary<long, string>>>();
SearchPreferences sp = SuiteTalkService.searchPreferences; //Store search preferences to reset back later, just need body fields this one time
SuiteTalkService.searchPreferences = new SearchPreferences() { bodyFieldsOnly = false };
SearchResult sr = SuiteTalkService.search(new CustomListSearch());
SuiteTalkService.searchPreferences = sp; //Restore search preferences
foreach (CustomList cl in sr.recordList)
{
Dictionary<long, string> customListItems = new Dictionary<long, string>();
if (cl.customValueList == null) continue;
foreach (CustomListCustomValue clcv in cl.customValueList.customValue)
{
customListItems.Add(clcv.valueId, clcv.value);
}
customListEntries.Add(cl.internalId, new Tuple<string, Dictionary<long, string>>(cl.name, customListItems));
}
return customListEntries;
}
Then, in the constructors of my Integration class, I can set my object to the return result:
public Dictionary<string, Tuple<string, Dictionary<long, string>>> CustomListEntries = GetCustomLists();
And finally, whenever I need access TO those values, since I set all of this up ahead of time, I can do the following:
dr[Class] = SuiteTalkIntegrator.CustomListEntries[lorr.typeId].Item2[long.Parse(lorr.internalId)];
In this case above, my "lorr" object is a ListOrRecordRef object that I obtained from the SearchColumnSelectCustomField.searchValue from the search results of a SavedSearch. I don't know if this will work for anyone else that finds this code, but since I was frustrated in finding an easy answer to this problem, I thought I'd share my solution with everyone.
Frankly, I'm most frustrated that this functionality isn't just given to us out of the box, but I've noticed that NetSuite has made a lot of bad design choices in their SuiteTalk API, like not making a custom class of "RecordField" for their record fields and not placing their record fields under an IEnumerable of RecordField so that programmers can loop through all values in a record in a generic way without having to EXPLICITLY name them and re-construct the same code logic over and over again... ugh...

Sitecore Multisite Manager and 'source' field in template builder

Is there any way to parametise the Datasource for the 'source' field in the Template Builder?
We have a multisite setup. As part of this it would save a lot of time and irritation if we could point our Droptrees and Treelists point at the appropriate locations rather than common parents.
For instance:
Content
--Site1
--Data
--Site2
--Data
Instead of having to point our site at the root Content folder I want to point it at the individual data folders, so I want to do something like:
DataSource=/sitecore/content/$sitename/Data
I can't find any articles on this. Is it something that's possible?
Not by default, but you can use this technique to code your datasources:
http://newguid.net/sitecore/2013/coded-field-datasources-in-sitecore/
You could possibly use relative paths if it fits with the rest of your site structure. It could be as simple as:
./Data
But if the fields are on random items all over the tree, that might not be helpul.
Otherwise try looking at:
How to use sitecore query in datasource location? (dynamic datasouce)
You might want to look at using a Querable Datasource Location and plugging into the getRenderingDatasource pipeline.
It's really going to depend on your use cases. The thing I like about this solution is there is no need to create a whole bunch of controls which effectively do he same thing as the default Sitecore ones, and you don't have to individually code up each datasource you require - just set the query you need to get the data. You can also just set the datasource query in the __standard values for the templates.
This is very similar to Holger's suggestion, I just think this code is neater :)
Since Sitecore 7 requires VS 2012 and our company isn't going to upgrade any time soon I was forced to find a Sitecore 6 solution to this.
Drawing on this article and this one I came up with this solution.
public class SCWTreeList : TreeList
{
protected override void OnLoad(EventArgs e)
{
if (!String.IsNullOrEmpty(Source))
this.Source = SourceQuery.Resolve(SContext.ContentDatabase.Items[ItemID], Source);
base.OnLoad(e);
}
}
This creates a custom TreeList control and passes it's Source field through to a class to handle it. All that class needs to do is resolve anything you have in the Source field into a sitecore query path which can then be reassigned to the source field. This will then go on to be handled by Sitecore's own query engine.
So for our multi-site solution it enabled paths such as this:
{A588F1CE-3BB7-46FA-AFF1-3918E8925E09}/$sitename
To resolve to paths such as this:
/sitecore/medialibrary/Product Images/Site2
Our controls will then only show items for the correct site.
This is the method that handles resolving the GUIDs and tokens:
public static string Resolve(Item item, string query)
{
// Resolve tokens
if (query.Contains("$"))
{
MatchCollection matches = Regex.Matches(query, "\\$[a-z]+");
foreach (Match match in matches)
query = query.Replace(match.Value, ResolveToken(item, match.Value));
}
// Resolve GUIDs.
MatchCollection guidMatches = Regex.Matches(query, "^{[a-zA-Z0-9-]+}");
foreach (Match match in guidMatches)
{
Guid guid = Guid.Parse(match.Value);
Item queryItem = SContext.ContentDatabase.GetItem(new ID(guid));
if (item != null)
query = query.Replace(match.Value, queryItem.Paths.FullPath);
}
return query;
}
Token handling below, as you can see it requires that any item using the $siteref token is inside an Site Folder item that we created. That allows us to use a field which contains the name that all of our multi-site content folders must follow - Site Reference. As long at that naming convention is obeyed it allows us to reference folders within the media library or any other shared content within Sitecore.
static string ResolveToken(Item root, string token)
{
switch (token)
{
case "$siteref":
string sRef = string.Empty;
Item siteFolder = root.Axes.GetAncestors().First(x => x.TemplateID.Guid == TemplateKeys.CMS.SiteFolder);
if (siteFolder != null)
sRef = siteFolder.Fields["Site Reference"].Value;
return sRef;
}
throw new Exception("Token '" + token + "' is not recognised. Please disable wishful thinking and try again.");
}
So far this works for TreeLists, DropTrees and DropLists. It would be nice to get it working with DropLinks but this method does not seem to work.
This feels like scratching the surface, I'm sure there's a lot more you could do with this approach.

How to generate media item link with id instead of path in Sitecore

Anyone knows how to generate links in sitecore with ID instead of item path?
If you use GetMediaUrl method from the API, I can get this URL:
/~/media/Images/Archive/content/News and Events/News_and_Events_Level2/20070419162739/iwhiz3.jpg
The problem with this approach is that if someone changes the media item name, removes it somewhere or deletes it, the above link will break.
I notice if I insert a media link from rich text editor, I get the link as below:
/~/media/14BDED00E4D64DFD8F74019AED4D74EB.ashx
The second link is better because it's using the item id, so if the actual media item is renamed, removed, or deleted, all related links will be updated too. On top of that, when Sitecore renders the page, it will actually convert the above link and display the item path so it's readable.
I'm using Sitecore 6.5 and currently doing content migration so I need to make sure all internal links are updated properly.
May I know if there is a method to generate the second link by using sitecore API?
Thanks!
The GetMediaItemUrl extension method seems to give you what you want.
public static class ItemExtensions
{
public static string GetMediaItemUrl(this Item item)
{
var mediaUrlOptions = new MediaUrlOptions() { UseItemPath = false, AbsolutePath = true };
return Sitecore.Resources.Media.MediaManager.GetMediaUrl(item, mediaUrlOptions);
}
}
[TestFixture]
public class when_using_items_extensions
{
[Test]
public void a_url_based_on_media_item_id_can_be_generated()
{
// Arrange
Database db = global::Sitecore.Configuration.Factory.GetDatabase("master");
Item item = db.GetItem("/sitecore/media library/Images/MyImage");
// Act
var mediaUrl = item.GetMediaItemUrl();
// Assert
Assert.That(mediaUrl, Is.EqualTo("/~/media/17A1341ABEEC46788F2159843DCEAB03.ashx"));
}
}
These are called dynamic links and you can normally generate them using the LinkManager e.g:
Sitecore.Links.LinkManager.GetDynamicUrl(item)
.. but I'm not sure of the method to do this with Media links (there probably is one but I cant seem to find it and its not on MediaManager) but the basic syntax is:
"/~/media/" + item.ID.ToShortID() + ".ashx"
If you always want to use ID's instead of paths, you can change this setting in webconfig to false (like this):
<setting name="Media.UseItemPaths" value="false"/>`
Here is what the webconfig describes about it:
MEDIA - USE ITEM PATHS FOR URLS
This setting controls if item paths are used for constructing media URLs.
If false, short ids will be used.
Default value: true
Then you can use the default implementation (without additional parameters):
Sitecore.Resources.Media.MediaManager.GetMediaUrl(item);
This is what I use:
var imgField = ((Sitecore.Data.Fields.ImageField)currentItem.Fields["Icon"]);
MediaUrlOptions opt = new MediaUrlOptions();
opt.AlwaysIncludeServerUrl = true;
// Absolute Path works as well. So either use AbsolutePath or AlwaysIncludeServerUrl
opt.AbsolutePath = true;
string mediaUrl = MediaManager.GetMediaUrl(imgField.MediaItem, opt);

sitecore query items by client url

I am looking for a quick and dirty way to query the layouts files of a particular page by its friendly url. This is probably easy, but I can't find the solution.
Basically I want to say something like the following. Pseudo-code:
var mainpage = Sitecore.EasyQueryUtility.GetItemByFriendlyUrl(requestedUrl);
or
var mainpage = Sitecore.EasyQueryUtility.GetOppositeOfFriendlyUrl(friendlyurl);
It sounds like you want to do two things here:
Determine an item based on its rendered URL in the address bar (i.e. friendly URL)
Determine the layout being used by the item once you determine the item.
If those are correct, hopefully this can help you out:
Note: untested code I did on-the-fly
// if you have the full URL with protocol and host
public static Item GetItemFromUrl(string url)
{
string path = new Uri(url).PathAndQuery;
return GetItemFromPath(path);
}
// if you have just the path after the hostname
public static Item GetItemFromPath(string path)
{
// remove query string
if(path.Contains("?"))
path = path.split('?')[0];
path = path.Replace(".aspx", "");
return Sitecore.Context.Database.GetItem(path);
}
Once you have the item you can get the layout's name like so:
item.Visualization.GetLayout(Sitecore.Context.Device).Name;
Or the layout's physical file path to the ASPX:
item.Visualization.GetLayout(Sitecore.Context.Device).FilePath;
If you want to get the path of the aspx file which is used for the layout of your page, you can use:
Sitecore.Context.Item.Visualization.Layout.FilePath
I may have misunderstood you but if you want to control the format of friendly URLs you can set several attributes via the Sitecore.Links.UrlOptions class and pass an instance of this in to the link manager. See here for more details. (Note - the LinkManager class is only available from SiteCore 6 I beleive).
The code you would end up with looks like this:
Sitecore.Links.UrlOptions urlOptions = (Sitecore.Links.UrlOptions)Sitecore.Links.UrlOptions.DefaultOptions.Clone();
urlOptions.SiteResolving = Sitecore.Configuration.Settings.Rendering.SiteResolving;
string url = Sitecore.Links.LinkManager.GetItemUrl(item, urlOptions);
You can then set fields like AddAspxExtension on the urlOptions you pass in.
As you can see, the process is reliant on you passing in an item - whether it be obtained via the current context or retrieved from the URL you start off with.
If you were asking about obtaining the layout definition item, take a look at this which shows you how.