Customize list rendering for pagination - list

i'm trying to implement infinite scroll in Orchard doing minimal changes.
The script I use need to perfectly identify with a jquery selector the Next page link of pager.
Currently a standard orchard pager renders this way:
<li>></li>
the desiderable rendering is:
<li class="next">></li>
I tried many ways to override the Pager_Next template but no joy.
The pager is a list and list is done by code. No easy way to override.
A great article the should explain how to do miss some basic part (as to override the whole list for example):
http://weblogs.asp.net/bleroy/overriding-the-pager-rendering-in-orchard
Right now my workaround was to change the Orchard source CoreShapes.cs for list rendering adding these two lines:
if (itemTag != null) {
if (index == 0)
itemTag.AddCssClass("first");
if (index == count - 1)
itemTag.AddCssClass("last");
//new lines
if (index == 1 && count > 2)
itemTag.AddCssClass("previous");
if (index == count - 2 && count > 2)
itemTag.AddCssClass("next");
So far it works BUT I do not like it
1) It changes orchard source, this is bad
2) It changes all the lists (and not just pager)
So "How may I override the list for JUST my theme and for JUST pager in a way that a class is added automatically at the Page_Next li tag?"
Thanks

Try something like this in your Pager.Next.cshtml alternate view:
#using System.Web.Routing;
#{
string text = Model.Value.ToString();
string action = Model.RouteValues["action"].ToString();
RouteValueDictionary routeValues = (RouteValueDictionary)Model.RouteValues;
}
<span><a class="next" href="#Url.Action(action, routeValues)">#text</a></span>

I'm not sure if the answer by joshb is close enough for your needs.
Otherwise I would say almost the same thing.
Change the Pager.Next.cshtml and Pager.Previous.cshtml in your theme, and simply add a way for you to identify the link.
The use jQuery to add the class you need to the parent.
This is by no means an elegant solution, but it will accomplish what you're asking for without changing the core and without affecting other lists.
My test looks like this, just for testing and only for next, but you get the idea.
(Don't use id obviously as it would give you duplicate id's, this is just a quick and dirty example)
Pager.Next.cshtml :
#{
var RouteValues = (object)Model.RouteValues;
RouteValueDictionary rvd;
if (RouteValues == null) {
rvd = new RouteValueDictionary();
}
else {
rvd = RouteValues is RouteValueDictionary ? (RouteValueDictionary)RouteValues : new RouteValueDictionary(RouteValues);
}
}
<a id="pagination-pager-next" href="#Url.Action((string)rvd["action"], rvd)"><i class="fa fa-angle-right"></i></a>
And added this at the end of Pager.cshtml, but you may have a better place for it:
<script>
$(document).ready(function () {
$("#pagination-pager-next").parent().addClass("next");
});
</script>

Related

Color Status indicator in O365 SharePoint Online

I am working with O365 SharePoint Online platform with SharePoint lists around 300 items in All Items View. For the first 30 items Text to Html Javascript function successfully converts text code to Html and displays status in HTML color format, but when I am trying to select next 31 items and go ahead using the pagination the function does not able to convert Html and display only text codes. I also changed the calculated column value type to "Number" to get the HTML to render in the list view. But not being changed yet. Does anyone please who have the code handy to make this work easy? Below is the Text to HTML code used in O365 platform.
<script type="text/javascript">
function TextToHTML(NodeSet, HTMLregexp) {
var CellContent = "";
var i=0;
while (i < NodeSet.length){
try {
CellContent = NodeSet[i].innerText || NodeSet[i].textContent;
if (HTMLregexp.test(CellContent)) {NodeSet[i].innerHTML = CellContent;}
}
catch(err){}
i=i+1;
}
}
// Calendar views
var regexpA = new RegExp("\\s*<([a-zA-Z]*)(.|\\s)*/\\1?>\\s*");
TextToHTML(document.getElementsByTagName("a"),regexpA);
// List views
var regexpTD = new RegExp("^\\s*<([a-zA-Z]*)(.|\\s)*/\\1?>\\s*$");
TextToHTML(document.getElementsByTagName("TD"),regexpTD);
// This function is call continuesly every 100ms until the length of the main field changes
// after which the convert text to HTML is executed.
//
var postElemLength = 0;
function PostConvertToHtml()
{
if (postElemLength == document.getElementsByTagName("TD").length)
{
setTimeout(PostConvertToHtml,100);
}
else
{
var regexpTD = new RegExp("^\\s*<([a-zA-Z]*)(.|\\s)*/\\1?>\\s*$");
TextToHTML(document.getElementsByTagName("TD"),regexpTD);
}
}
// Grouped list views
ExpGroupRenderData = (function (old) {
return function (htmlToRender, groupName, isLoaded) {
var result = old(htmlToRender, groupName, isLoaded);
var regexpTD = new RegExp("^\\s*<([a-zA-Z]*)(.|\\s)*/\\1?>\\s*$");
TextToHTML(document.getElementsByTagName("TD"),regexpTD);
// start the periodic callback to check when the element has been changed
if(isLoaded == 'false')
{
postElemLength = document.getElementsByTagName("TD").length;
setTimeout(PostConvertToHtml,100);
}
};
})(ExpGroupRenderData);
// Preview pane views
if (typeof(showpreview1)=="function") {
showpreview1 = (function (old) {
return function (o) {
var result = old(o);
var regexpTD = new RegExp("^\\s*<([a-zA-Z]*)(.|\\s)*/\\1?>\\s*$");
TextToHTML(document.getElementsByTagName("TD"),regexpTD);
};
})(showpreview1);
}</script>
Below is the generated text code which needs to be converted to Html used in calculated columns. Thanks.
=IF([Trend]="Cancelled","DarkGray",IF([Trend]="Completed","DodgerBlue",IF([Trend]="Declining","DarkOrange",IF([Trend]="Improving","ForestGreen",IF([Trend]="No Change","ForestGreen",IF([Trend]="Not Started","White",IF([Trend]="On Hold","DarkGray","")))))))
And..
="<div style='position:relative;display:inline-block;width:100%;'>
<div style='width:100%;display:inline-block;text-align:center;border:1px solid "&[VPN provisioning_Clr]&";position:absolute;color:"&[VPN provisioning_Clr]&";'> "&[VPN provisioning]&"
</div>
<div style='display:inline-block;width: 100%;background-color:"&[VPN provisioning_Clr]&";text-align:center;border:1px solid;z-index:-1;filter:alpha(opacity=20);opacity:0.2;'>"&[VPN provisioning]&"
</div>
</div>"
Assuming you are using the Classic UI in SharePoint Online...
Two possible issues:
Check to see if the site has the Minimal Download Strategy enabled.
If so disable it and test your code. MDS often is the cause for JavaScript running only once. (The page is not reloaded, only the data area.)
The loading of the next page of the list is via a Web Service call and that may not be triggering your JavaScript. (Again, the page is not reloaded, only the data area.) You may need to intercept the paging link to insure your code is run. (Also check to see if the "Asynchronous Load" option has been enabled. Edit the page, edit the web part, and expand the "AJAX Options" section.)
You may want to take a look at a workflow plus a Calculated column solution to add the color coding. See: http://techtrainingnotes.blogspot.com/2018/01/adding-html-to-sharepoint-columns-color.html

Sharepoint 2013 - Open search result in new window/tab

Ok, so I've been struggling with this problem for a few hours now...
I need to modify the links in the search results, so that they open in a new window/tab.
Specifically it's the search results that links to a "off-site"-hit.
I've created a copy of Item_WebPage.html, but I just can't get it to work.
I guess that there are some kind of async loads that screws it all up.
My js-code is as follows:
var anchors = document.getElementsByClassName('ms-srch-item-link');
for (var i = 0; i < anchors.length; i++) {
anchors[i].setAttribute("target", "_blank");
}
}
However, "anchors" always is "0".
Is there a "sharepoint-document-ready-as-h*ll"-function I can use?
My guess is that my problem is that not all content is loaded into the DOM before I run my code...
A custom display template is a good way of changing the behavior of the search results. I've used JQuery code to make sure that external links always load in a new window :
<script type="text/javascript">
if (window.jQuery) {
$(window).load(function () {
// Open external links in a new tab
var url = '://' + window.location.hostname;
// get the current website name, and i add :// to make sure we're looking at the right name //
url = url.toLowerCase(); // lowercase everything to compare apples to apples
$("a").each(function () {
var link = this; // assign the link object to another variable for easier managability
var linkHref = link.href.toLowerCase(); // lower case it
if (linkHref.indexOf(url) < 0 && linkHref.indexOf('javascript:') < 0) { // check to see if this A object has this domain in it and make sure it's not a javascript call
link.target = '_blank'; // change the target to be in the new window
} if (linkHref.indexOf('.pdf') > 0) { // check to see if this is a PDF
link.target = '_blank'; // change the target to be in the new window
$(link).removeAttr("onclick"); //remove the SP click event
} if (linkHref.indexOf('/forms/') > 0 && linkHref.indexOf(').aspx') > 0) { //check for links in the forms library
link.target = '_blank'; // change the target to be in the new window
$(link).removeAttr("onclick"); //remove the SP click event
}
});
});
}
</script>
It's way too long and you may have resolved it.
I was looking for the same and added - target="_blank" to the anchor tag in a custom display template
In SharePoint online, this worked perfectly for me, applies to all results though.
Using SharePoint Designer, update the Item_CommonItem_Body.html Display Template from within _catalogs/masterpage/display templates/search.
Search for below line :
var titleHtml = String.format('<a clicktype="{0}" id="{1}" href="{2}" class="ms-srch-item-link" title="{3}" onfocus="{4}" {5} >{6}</a>',
and replace it with :
var titleHtml = String.format('<a clicktype="{0}" id="{1}" href="{2}" class="ms-srch-item-link" title="{3}" onfocus="{4}" {5} target="_blank">{6}</a>',
Save the change and, from the browser master page library, publish a major version. When you search now the results should open in new tabs although you may need to load the page cache again (CTRL+F5).
From https://social.technet.microsoft.com/Forums/ie/en-US/a7db8389-3740-4ff6-ac52-645776b29a56/search-results-in-new-tabwindow-in-sharepoint-2013

angularjs ui-router: find level of current state

So I'm using ui-router and stateparams to nest child states, and it works well. I'm now trying to find a way to dictate a css class what state level the app is at. main.route1.section1 would be 3 levels.
Here's some non-working code to help show:
<div ng-class="{findState().currentCount}"></div>
app.run(function($rootScope, $state, $stateParams) {
$rootScope.$state = $state;
$rootScope.$stateParams = $stateParams;
$rootScope.findState = function() {
var currentName = $state.current.name;
var currentMatch = currentName.match(/./g);
$rootScope.currentCount = currentMatch.length;
};
});
I'm basically looking for a way to take $state.current.name which say equals main.route1.section1 and split it at the dot and count how many are in the array and return that number to the mg-class. Unless you have a better idea... like a regex filter?
Take a look of the object $state.$current (instead of $state.current). In particular, the property path : it's an array representing the state hierarchy of the current state.
So what you are looking for is : $state.$current.path.length

Opencart: How to render a template only on a specific page?

In my catalog/controller/mycontroller.php, I have a script like this:
$this->data['settings'] = $this->config->get('my_module'); // retrieves data from "setting" table
foreach ($this->data['settings'] as $data) {
if ($data['pageurl'] == 'http://'.$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI']) {
$this->render();
}
}
In Extensions > Modules, I have my extension installed where I can set different page URLs to different Layouts and Positions like this:
Page URL Layout Position
================================================
http://...?product_id=10 Product Content Top
http://...?product_id=20 Product Content Top
http://... Home Content Top
My issue is - I'd like to render a template only ONCE on a specific page that meets the condition in the above script. What's currently happening is $this->render() is showing the template MULTIPLE times based on the Position and Layout in Extensions > Modules. For instance, when I visit http://...?product_id=10 page, it displays the template twice while it's only supposed to display it once because it only meets the condition for product_id=10 in the controller. How can I do this?
First of all, do this:
var_dump('http://'.$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI']);
I guess You may be missing also the $_SERVER['QUERY_STRING'] part...
to see, what URL are You building to compare to URLs You are setting in the backend...
Next, please, do not call $this->render() in a loop no matter why the condition succeed more times, instead of this do something like this:
$this->data['settings'] = $this->config->get('my_module'); // retrieves data from "setting" table
$render = false;
foreach ($this->data['settings'] as $data) {
if ($data['pageurl'] == HTTP_SERVER . $_SERVER['REQUEST_URI']) { // use defined constant HTTP_SERVER
$render = true;
}
}
if($render) {
$this->render();
}

Check if items exist in the current language?

I have a Sitecore solution where there are 3 different languages enabled. On top of the page, there is a link to each language. When you click this link, you get the current page you are standing on, in the selected language.
But not all pages are translated into all languages. So if I am standing on page x in English language, and this page is only available in English and German but not Chinese, then the Chinese link should not be shown.
So the question is - How do I check if the current item has a version of a specific language?
To see if there is a version of the current item you can do this: Sitecore.Context.Item.Versions.Count > 0
[updated for comment]
I don't claim that this is the most efficient way to determine if an item has a version in a language, but this will work:
bool hasVersion = HasLanguageVersion(Sitecore.Context.Item, "en");
private bool HasLanguageVersion(Sitecore.Data.Items.Item item, string languageName)
{
var language = item.Languages.FirstOrDefault(l => l.Name == languageName);
if (language != null)
{
var languageSpecificItem = global::Sitecore.Context.Database.GetItem(item.ID, language);
if (languageSpecificItem != null && languageSpecificItem.Versions.Count > 0)
{
return true;
}
}
return false;
}
You can retrieve a collection (LanguageCollection) of an items content languages (ie. the languages for which the item has content).
LanguageCollection collection = ItemManager.GetContentLanguages(Sitecore.Context.Item);
foreach (var lang in collection)
{
var itm = Sitecore.Context.Database.GetItem(Sitecore.Context.Item.ID,lang);
if(itm.Versions.Count > 0)
{
Response.Write("Found language " + lang + "<br />");
}
}
Hope this helps :)
NB: Add a comment dude.. please dont just make random edits to my answer. This is the height of rudeness.
Edit: Correcting .. Turns out the method doesn't take into account versions of that language existing.---
to clarify, ItemManager.GetContentLanguages does not get you the list of languages on a given item. It gives the list of all languages you have opted to include in your environment. Under the hood, it does 2 things (based on decompiled code for sitecore 7.2):
it calls LanguageManager.GetLanguages(item.Database));
it adds to this any languages not already added by step 1 by calling item.Database.DataManager.DataSource.GetLanguages(item.ID);
If you have the context items in a list, use a Linq expression:
List<Item> languageContentItems =
contentItems.Where(x=> x.Version != null && x.Versions.Count > 0).ToList();
I'm thoroughly confused as to why x.Version.Number wouldn't be the correct syntax vs. using x.Versions.Count because the x.Versions inline-documentation states that it returns all language versions of the item, which would mean that x.Versions.Count should return a count of all versions in all languages, when we really only want to see if the item has a version for the current context language.
This works like charm for me:
item.Versions.GetVersions(false).Any();
don't forget about Fallback option sometimes
if (item.Versions.Count > 0 && !item.IsFallback)
would work better
have a look at this post for a method which returns a list of languages an item has versions in: https://stackoverflow.com/a/31351810/551811
I use the following extension method on Item. This assumes you have an item to start from of course.
public static bool HasVersionInLanguage(this Item item, Sitecore.Globalization.Language lang)
{
return ItemManager.GetVersions(item, lang).Any();
}
If you don't have the item in memory you could change this to a 'normal' method and pass the ID of the item as a second parameter..
public bool HasVersionInLanguage(ID itemId, Sitecore.Globalization.Language lang)
{
return ItemManager.GetVersions(item, lang).Any();
}