Programmatically Set the Title of a SharePoint Page? - sharepoint

I need to set the page title (Page Title) of a SharePoint page in code. I have already tested
this.Page.Title = "My Page Title";
But this does not change the title when the page loads. Can anyone offer any advise on how to do this?
Thanks, MagicAndi

This blog post by Michael Becker gives a method of modifying the SharePoint Page title using the code below:
ContentPlaceHolder contentPlaceHolder = (ContentPlaceHolder) Page.Master.FindControl("PlaceHolderPageTitle");
contentPlaceHolder.Controls.Clear();
LiteralControl literalControl = new LiteralControl();
literalControl.Text = "My Page Title";
contentPlaceHolder.Controls.Add(literalControl);

If you want to change the page title from a webpart on the page for example, you could use this:
private void ChangeTitle(string newTitle)
{
SPListItem item = SPContext.Current.ListItem;
if (item != null)
{
item[SPBuiltInFieldId.Title] = newTitle;
item.SystemUpdate(false);
}
}
This will only work for a page in the pages library, because the default.aspx page in the root of your site doesn't have an associated listitem. Also don't forget to refresh your page after changing the title.
The SystemUpdate makes sure that 'modified/modified by' information is not updated and that the version number doesn't increase. If you want this information updated, replace it by item.Update();

Related

Highlight links in a Quick Links web part on SharePoint modern page

We have added 4 "Quick Links" web/app part in one section on a SharePoint modern page. We would like to highlight links under "Quick Links web part 2" and "Quick Links web part 4" only. I have added React modern script editor. How do we archive the above requirement using CSS ? If it is not possible in CSS then we would like to introduce JS. I couldn't find a fixed tag name that I can grab and apply CSS except GUID.
You could try to inject CSS by SPFX.
Check the demo shared by hugoabernier.
Main code:
export default class InjectCssApplicationCustomizer
extends BaseApplicationCustomizer<IInjectCssApplicationCustomizerProperties> {
#override
public onInit(): Promise<void> {
Log.info(LOG_SOURCE, `Initialized ${strings.Title}`);
const cssUrl: string = this.properties.cssurl;
if (cssUrl) {
// inject the style sheet
const head: any = document.getElementsByTagName("head")[0] || document.documentElement;
let customStyle: HTMLLinkElement = document.createElement("link");
customStyle.href = cssUrl;
customStyle.rel = "stylesheet";
customStyle.type = "text/css";
head.insertAdjacentElement("beforeEnd", customStyle);
}
return Promise.resolve();
}
}

Is this a bug in the Tab Container?

I think this is a bug in the Tab Container...
Opening a new tab using Java or the Server Side JavaScript createTab method when the new tab contains a panel that is set to be an iframe pointing to another XPage in the same database will always cause the XPage to get reloaded after loading about five or six tabs (in Chrome, IE does the same but it takes more tabs...)
If the tab contains an iframe that points to another database that holds the XPage it works fine.
The SSJS code is:
getComponent("djTabContainer1").createTab({title:"New tab"});;
The Java code is
public static boolean createTab(UIDojoTabContainer tabContainer) {
try {
if (tabContainer == null) {
tabContainer = (UIDojoTabContainer) Utils.findComponent("TabContainer");
if (tabContainer == null) {
return false;
}
}
String tabTitle = null;
String url = null;
String unid = null;
UIDojoTabPane newTab = null;
// get default number from current project preferences
tabTitle = "My Tabpage";
url = Utils.GetXpageURL("tabpage.xsp");
// create a new Tab
newTab = new UIDojoTabPane();
newTab.setTitle(tabTitle);
newTab.setTabUniqueKey(new Random().toString());
newTab.setClosable(true);
newTab.setId("TabContainer_" + unid);
newTab.setStyleClass("myTabContainer");
Utils.WriteToConsole("setting style class on " + newTab.getTitle());
// newTab.setStyle("height:auto;width:auto; overflow-y: auto;border: 0px;");
// create new Panel
UIPanelEx newPanel = new UIPanelEx();
newPanel.setId("IFrame" + unid);
newPanel.setStyleClass("iframeClass");
// make an iFrame of this panel with our URL as src
newPanel.setTagName("iframe");
Attr property = new Attr();
property.setName("src");
property.setValue(url);
newPanel.addAttr(property);
// add Panel to our new Tab
newTab.getChildren().add(newPanel);
// add the new tab to our tab container
tabContainer.getChildren().add(newTab);
tabContainer.setSelectedTab(unid);
return true;
} catch (Exception ex) {
Utils.WriteToConsole("Unable to add a new Tab Page to the Tab Container (com.tlcc.Main.createTab)", ex);
return false;
}
}
The XPage that is referenced in the src property of the iframe is very basic...
<?xml version="1.0" encoding="UTF-8"?>
<xp:view xmlns:xp="http://www.ibm.com/xsp/core">
<xp:button
value="Label"
id="button1">
</xp:button>
<xp:inputText id="inputText1"></xp:inputText></xp:view>
When the XPage reloads it has no more tabs (except the first tab that was created in the XPage at the start) and is not responsive.
Howard
It could be a server page persistence/component tree limit problem. If you use the default server page persistence, the server only stores 4 pages in memory (per user).
When you create new tabs on the page that loads another XPage, the server is filling up the server page persistence queue and when you hit the 5th tab, the current page is no longer part of the server page persistence (the component tree is no longer in memory) leading to a reload of the current page.
You can increase the number of pages stored (and also move the disk persistence instead of memory persistence). You can also set viewState to "nostate" on the XPage that you load in the iframe (at least to test out my theory).
See Toby Samples blog post on state and this answer on a similar state issue: https://stackoverflow.com/a/31431917/785061
So, to finalize this... the setting for viewstate=nostate allows more tabs but then does not keep the components in memory. So, it works well for readonly XPages but not when the document on the XPage is in edit mode. The setting Maximum Pages on disk in the Xsp properties on the persistence tab will allow more tabs with iframes that have XPages but still will crash at some point.
Net is, don't use multiple iframes that pull in XPages from the same nsf...

How to extend Orchard navigation module to add images to menu items

UPDATE: I've changed the original question drastically based on Bertrand's suggestions and my own findings. Now it provides an incomplete solution in its text instead of my own blind meanderings and commentary on Orchard, which were completely WRONG!
I need to display a menu using images instead of text, one standard, and another for when hovered/selected. The requirements for the site states that the end-user should be able to manage the menu item images. The standard navigation module now provides an HTML menu item, which is not what the end user wants. The customer wants a very simple, intuitive interface for configuring the sites many menus, and all menus are image-based.
Based on Bertrand's advice, and after realizing that Content Menu Item IS A CONTENT TYPE, I've created a new Content Part in the Admin Interface (not by code, I only want to write code for parts and content types when ultimately needed... I really want to see how far I can go with Orchard just by using the admin interface and templating/CSSing).
So, I've created a Menu Image Part, with two Content Picker fields added to it: Image and Hover Image. Then I've added this part to the Content Menu Item in the Manage Content Items admin interface.
Since I didn't write a Driver for it, the Model passed to the menu item template does not have an easily accessible property like #Model.Href... I've overriden the MenuItemLink-ContentMenuItem.cshtml with the following code so far:
#using Orchard.Core.Common.Models
#using Orchard.ContentManagement
#{
var contentManager = WorkContext.Resolve<IContentManager>();
var itemId = Model.Content.ContentItem.ContentMenuItemPart.Id;
ContentItem contentItem = contentManager.Get(itemId);
ContentField temp = null;
var menuImagePart = contentItem.Parts.FirstOrDefault(p => p.PartDefinition.Name == "MenuImagePart");
if (menuImagePart != null)
{
temp = menuImagePart.Fields.First();
}
}
<span>#temp</span>
#Model.Text
This yields the expected title for the Menu in a link, with a span before it with the following text:
Orchard.Fields.Fields.MediaPickerField
So all the above code (get the current content manager and the id of the ContentItem representing the ContentMenuItemPart, then use the content manager to get ContentItem itself, then linqing over its Parts to find the MenuImagePart (I can't use Get to get it because it requires a type and the MenuImagePart is not a type, it was created in the admin interface), then finally getting the first field for debugging purposes (this should be the Image field of the MenuImagePart I've created...)... all the above code actually got me to the Media Picker Field on my Meny Image Part...
What I'm not being able to do, and what makes me certainly a lot obtuse and stupid, is to find a way to read the MediaPickerField URL property! I've tried casting it to MediaPickerField, but I can't access its namespace from inside my template code above. I don't even know which reference to add to my theme to be able to add the following directive to it:
#using Orchard.Fields.Fields
I've finally succeeded in this task (thanks to Bertrand's direction).
UPDATE: And thanks again to Bertrand I've polished the solution which was running in circles, querying content items from the content manager when they were already available on the Model... now I'm leveraging the dynamic nature of content item, etc. And I'm finally satisfied with this solution.
It was necessary to create a new Content Part called Menu Image, then add this to the Content Type named Content Item Menu, and finally overriding the Content Item Menu template. This last part was the really tricky one. If it was not for Bertrand's directions the code bellow would have been smelly and daunting. The template ended up as follow:
#using Orchard.Utility.Extensions;
#using System.Dynamic
#{
/* Getting the menu content item
***************************************************************/
var menu = Model.Content.ContentItem;
/* Creating a unique CSS class name based on the menu item
***************************************************************/
// !!! for some reason the following code throws: 'string' does not contain a definition for 'HtmlClassify'
//string test = menu.ContentType.HtmlClassify();
string cssPrefix = Orchard.Utility.Extensions.StringExtensions.HtmlClassify(menu.ContentType);
var uniqueCSSClassName = cssPrefix + '-' + Model.Menu.MenuName;
/* Adds the normal and hovered styles to the html if any
***************************************************************/
if (menu.MenuImagePart != null)
{
if (!string.IsNullOrWhiteSpace(menu.MenuImagePart.Image.Url))
{
using(Script.Head()){
<style>
.#uniqueCSSClassName {
background-image: url('#Href(menu.MenuImagePart.Image.Url)');
width: #{#menu.MenuImagePart.Image.Width}px;
height: #{#menu.MenuImagePart.Image.Height}px;
display: block;
}
</style>
}
}
if (!string.IsNullOrWhiteSpace(menu.MenuImagePart.HoverImage.Url))
{
using(Script.Head()){
<style>
.#uniqueCSSClassName:hover {
background-image: url('#Href(menu.MenuImagePart.HoverImage.Url)');
width: #{#menu.MenuImagePart.HoverImage.Width}px;
height: #{#menu.MenuImagePart.HoverImage.Height}px;
}
</style>
}
}
}
}
<a class="#uniqueCSSClassName" href="#Model.Href">#Model.Text</a>
The only thing that I didn't understand is why I can't use HtmlClassify as an extension method with menu.ContentItem.HtmlClassify() and have to resort to calling the method as a standard static method (see the line with the comment `// !!! for some reason the following code throws´...)
Thanks again Bertrand!

How do you add custom menu actions programmatically in SharePoint?

I need to add a custom menu action to a custom content type programmatically in c#. This is because I will not know the URL I need to link to beforehand. The URL to link to will be pulled from configuration when the feature is activated.
I have tried the following:
Added the CustomAction in my Element.xml file as:
<CustomAction
Id="MyID"
RegistrationType="ContentType"
RegistrationId="0x010100ef19b15f43e64355b39431399657766e"
Location="EditControlBlock"
Sequence="1000"
Title="My Menu Item">
<UrlAction Url="" />
</CustomAction>
In my feature receiver FeatureActivated method, I have:
SPElementDefinitionCollection eleCollection =
properties.Feature.Definition.GetElementDefinitions(
new System.Globalization.CultureInfo(1));
foreach (SPElementDefinition ele in eleCollection)
{
if (ele.Id == "MyID")
{
System.Xml.XmlNode node = ele.XmlDefinition.FirstChild;
node.Attributes[0].Value = "MY URL";
ele.FeatureDefinition.Update(true);
}
}
I would expect this code to update the UrlAction Url with "MY URL" but it does not. If I hard code a URL in the XML it works but I must be able to do it programmatically.
You can use the SPUserCustomActionCollection on the SPWeb object:
using (SPSite site = new SPSite("http://moss.dev.com"))
using (SPWeb web = site.OpenWeb())
{
SPContentType contentType = web.ContentTypes["Curriculum Vitae"];
SPUserCustomAction action = web.UserCustomActions.Add();
action.RegistrationType = SPUserCustomActionRegistrationType.ContentType;
action.RegistrationId = contentType.Id.ToString();
action.Location = "EditControlBlock";
action.Sequence = 450;
action.Title = "Test";
action.Rights = SPBasePermissions.EditListItems;
action.Url = "http://www.google.com";
action.Update();
}
This way, you can set the URL to whatever you want. If you are updating an existing custom action, you can iterate through the collection and update the one you are looking for. Updating the element XML definition after you've installed the custom action doesn't do anything.
Depending on what you want to achieve, you can use some javascript;
<UrlAction Url="JavaScript:window.location='{SiteUrl}/_layouts/CustomListAction.aspx?ID={ListId}'"/>
the ~site and ~siteCollection also works:
<UrlAction Url="~site/_layouts/Page.aspx?ID={ListId}"/>
I don't think the WSS schema definition allows for an empty Url attribute in the UrlAction element. Maybe try putting a "default" url in the xml that you overwrite later?

specific format for a title in a Sharepoint Website?

I need to show in every webpage, the following structure of title:
"title of the WebSite/Project" +","+ "title of the 1º site" +","+ "title of the 2º site" +","+ "title of the page"
For example, i have a webpage with the title "Last news webpage" and I am in a site with the following path: /news/international/new1.aspx. The site "news" has the title: "News", the site "international" has the title "International News" and the page has the title "New planet discovered". The result should be:
Last news webpage, news, international news, New Planet discovered
How can i do this using the ProjectProperty tag of Sharepoint?
If it can't be done, how can i do it with at least one level of site? ("Last news webpage, news, new planet discovered")
You may want to investigate building your own server control that creates the appropriate title and add it to the site's masterpage.
here's a tutorial for creating a custom server control.
the code to get the custom server control to render the appropriate site information would be something like the following:
protected override void RenderContents(HtmlTextWriter writer)
{
if (Context != null)
{
SPWeb l_web = SPContext.Current.Web;
StringBuilder l_titleBuilder = new StringBuilder();
l_titleBuilder.AppendFormat("{0}, ", l_web.Title);
char[] l_delim = new char { '/' };
foreach ( string l_pathComponent in
l_web.ServerRelativeUrl.Split(l_delim) )
l_titleBuilder.AppendFormat("{0}, ", l_pathComponent);
l_titleBuilder.Remove(l_titleBuilder.Length - 2, 2);
writer.Write(l_titleBuilder.ToString());
}
}

Resources