SharePoint show Ribbon with multiple webparts on page - sharepoint

I've created a sharepoint page that has an xslt webpart and a 2nd webpart that is unrelated to the question
When we add this second webpart the ribbon bar is hidden and you have to click the webpart to get the ribbon bar shown again.
Clicking the webpart isn’t something we can ask from our users so I’m trying to get the ribbon bar visible at all times with the context of our xslt listview webpart.
When searching for this problem I found out that when you search for this hidden ribbon behavior with reflector in the SharePoint source code it seems this is behavior that is designed by Microsoft as the example below shows:
public override bool Visible {
get {
if (!this.SingleWebPartPresentOnPage)
return false;
else
return base.Visible;
}
}
Someone with same problem but no solution: http://www.glynblogs.com/2011/02/list-view-selector-missing-with-multiple-web-parts-in-sharepoint-2010.html
Is it possible to force the ribbon bar to visible with server side code or can I call the javascript code that is being used when I click the webpart to show the ribbon bar?
I think it should be possible with javascript because if you click the xslt webpart the ribbon is visible but i can't reproduce the code thats being executed.

you can use JavaScript to reselect the XSLTListViewWebPart, that the ribbon appears again.
$(document).ready(function() {
var target = document.getElementById("MSOZoneCell_WebPartWPQ2");
if(target != null) {
var fakeEvent = new Array();
fakeEvent["target"] = target;
fakeEvent["srcElement"] = target;
WpClick(fakeEvent);
}
});

Below Javascript worked for me!!
<script>
setTimeout(function() {
var elem = document.getElementById("MSOZoneCell_WebPartWPQ4");
if(elem != null) {
var dummyevent = new Array();
dummyevent["target"] = elem;
dummyevent["srcElement"] = elem;
WpClick(dummyevent);
}
}, 100);
</script>
In the above script the MSOZoneCell_WebPartWPQ4 being my list view web part

A great solution is to grab the contextualInfo for the main webpart on your view page.
public class MyView : WebPart, IWebPartPageComponentProvider
{
protected override void CreateChildControls(){.............}
public WebPartContextualInfo WebPartContextualInfo
{
get
{
// get default current view webart (WebPartWPQ2)
ListViewWebPart listView = this.WebPartManager.WebParts
.OfType<ListViewWebPart>().FirstOrDefault();
// use reflection to get non-public member containing contextualinfo
var t = listView.GetType();
WebPartContextualInfo oViewInfo = (WebPartContextualInfo)t.InvokeMember("Microsoft.SharePoint.WebControls.IWebPartPageComponentProvider.WebPartContextualInfo", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.FlattenHierarchy | BindingFlags.GetProperty, null, listView, new object[] { });
return oViewInfo;
}
}
protected override void OnPreRender(EventArgs e)
{
SPRibbon ribbon = SPRibbon.GetCurrent(this.Page);
// Ensure ribbon exists.
if (ribbon != null)
{
// Load dependencies if not already on the page.
ScriptLink.RegisterScriptAfterUI(this.Page, "SP.Ribbon.js", false, true);
}
base.OnPreRender(e);
}
}

Below a version using SharePoint's Script On Demand instead of 100ms timeout or jquery. I think thats more solid, cuz it is exactly executed after the ribbon is initialized.
SP.SOD.executeOrDelayUntilScriptLoaded(function () {
//using setTimeout to ensure it will be executed after the code of sp.ribbon.js has done its initialization
setTimeout(function () {
//try to focus the default webpart so the ribbon will show
var elem = document.getElementById("MSOZoneCell_WebPartWPQ2");
if (elem != null) {
var dummyevent = new Array();
dummyevent["target"] = elem;
dummyevent["srcElement"] = elem;
WpClick(dummyevent);
}
}, 0);
}, "sp.ribbon.js");

Similar to Thorstens solution, I use jQuery to fire the WpClick function on the mouseenter event. This approach also handles the issue where the Full Toolbar freaks out when a user first enters a page and tries to use one of the menus. You can trap the event bubble for any number of web parts on the page if desired. For example:
$("body").on("mouseenter","#MSOZoneCell_WebPartWPQ2,#MSOzoneCell_WebPartWPQ3, . . . etc.",function() {
WpClick(event);
});
Where "body" could be any parent element you want that contains the web parts to auto select when hovering.
When only one web part is of concern, or for optimal performance on large pages you could also set the event directly on the zone.
$("#MSOZoneCell_WebPartWPQ2").attr("onmouseenter","WpClick(event)");
or if jQuery is not available
var el = document.getElementById("MSOZoneCell_WebPartWPQ2");
if(el != null) {
el.setAttribute('onmouseenter','WpClick(event);');
}
Optionally, you can still force the Ribbon to appear after the page loads and before a user hovers by triggering the event manually. Just include the appropriate code after attaching the event above. e.g. using jQuery
$("#MSOZoneCell_WebPartWPQ2").mouseenter();

Related

Open custom Acumatica screen as popup from button on Bills and Adjustments screen

I have a completely custom screen with its own BLC and DACs, and I want to open it as a popup from a button placed on the Bills and Adjustments screen. I have coded it as follows:
public class APInvoiceEntryExt : PXGraphExtension<APInvoiceEntry>
{
public PXAction<APInvoice> LaunchOpenSource;
[PXButton(CommitChanges = true)]
[PXUIField(DisplayName = "Open Source")]
protected void launchOpenSource()
{
APInvoice apinvoice = (APInvoice)Base.Document.Current;
if (apinvoice != null)
{
//var url = "http://localhost/AcumaticaDB2562/?ScreenId=AC302000&OpenSourceName=Bills+and+Adjustments&DataID=" + apinvoice.RefNbr;
OpenSourceDataMaint graph = PXGraph.CreateInstance<OpenSourceDataMaint>();
graph.OpenSourceDataHeader.Current = graph.OpenSourceDataHeader.Search<xTACOpenSourceHeader.openSourceName, xTACOpenSourceHeader.dataID>("Bills and Adjustments", apinvoice.RefNbr);
if (graph.OpenSourceDataHeader.Current != null)
{
throw new PXRedirectRequiredException(graph, "Open Source")
{
Mode = PXBaseRedirectException.WindowMode.NewWindow
};
}
}
}
}
I've included all the relevant DACs and BLC for my custom screen in the Class Library project I'm using to customize the 'Bills and Adjustments' screen where I'm adding the button.
The problem I'm having is that I get the following error message when launching the button:
I've set all the relevant permissions for the screen that uses the OpenSourceDataMaint BLC to 'Delete' in 'Access Right By Role', 'Access Rights By User', and 'Access Rights By Screen'. Nothing makes any difference.
Looks like DataSource is trying to find a node in SiteMap with GraphType equal to full name off your OpenSourceDataMaint class and fails:
public class PXBaseDataSource : DataSourceControl, IAttributeAccessor, INamingContainer, ICompositeControlDesignerAccessor, ICommandSource, IPXCallbackHandler, IPXScriptControl, IPXCallbackUpdatable, IPostBackDataHandler
{
...
private static string getFormUrl(Type graphType)
{
PXSiteMapNode node = getSiteMapNode(graphType);
if (node == null)
{
throw new PXException(string.Format(ErrorMessages.GetLocal(ErrorMessages.NotEnoughRightsToAccessObject), graphType.Name));
}
String url = node.Url;
//if (url.Contains("unum=")) url = PXUrl.IgnoreQueryParameter(url, "unum");
return PXUrl.TrimUrl(url);
}
...
}
Could you please check if TypeName is properly defined for PXDataSource inside your custom Aspx page? Also could you please check if your custom Aspx page also exists in Cst_Published folder and if values set for PXDataSource.TypeName property are identical inside Pages and Cst_Published folders?
One more thing to check, does the Site Map screen show the right GraphName for your custom screen? - would be beneficial if you can provide a screenshot for verification.
If possible, please provide your customization package, that can be published locally (even with compiled assembly) - this would greatly speed up the investigation process.
The solution, for me, was to put the code (shown below) in a customization window instead of a class library project in Visual Studio. Since the code needs to have a reference to another published customization, putting it inside an Acumatica code window takes care of this. There is no reference to the published custom screen customization in my class library project, and this obviously causes issues - and I'm not sure how to handle that.
public class APInvoiceEntryExt:PXGraphExtension<APInvoiceEntry>
{
public PXAction<APInvoice> LaunchOpenSource;
[PXButton(CommitChanges = true)]
[PXUIField(DisplayName = "Open Source")]
protected void launchOpenSource()
{
APInvoice apinvoice = (APInvoice)Base.Document.Current;
if (apinvoice != null)
{
AssistantController.OpenSourceDataMaint graph = PXGraph.CreateInstance<AssistantController.OpenSourceDataMaint>();
graph.OpenSourceDataHeader.Current = graph.OpenSourceDataHeader.Search<AssistantController.xTACOpenSourceHeader.openSourceName
,AssistantController.xTACOpenSourceHeader.dataID>("Bills and Adjustments", apinvoice.RefNbr);
throw new PXRedirectRequiredException(graph, "Open Source")
{
Mode = PXBaseRedirectException.WindowMode.NewWindow
};
}
}
}

Page refresh does not load the search results on customized coreresultswebpart sharepoint 2010

I have inherited the coreresultswebpart in a custom webpart that I am building in sharepoint 2010.
The reason for this is because there are some properties that I want to set by default, without any manual entry.
The webpart is working fine except, when the webpart is loaded in the page, it does not immediately show the results (search result exists for the default configurations). But when I hit the enter key on the adress bar, the results are loaded. The results are also loaded when I am in edit mode. However, when I click OK in the editorpart, the results vanish and the webpart tells me to refresh page, at which point, the same cycle repeats.
What am I missing?
Here is a code snippet of where I am making the change:
protected override void OnLoad(EventArgs e)
{
CssRegistration.Register("/_layouts/WPLatestBlogFeed/LatestBlogFeed_CustomStyle.css");
base.OnLoad(e);
if (firstLoad)
{
firstLoad = false;
CustomizeWebPart();
}
}
try to override ConfigureDataSourceProperties Method.
protected override void ConfigureDataSourceProperties()
{
// run the base code
base.ConfigureDataSourceProperties();
CssRegistration.Register("/_layouts/WPLatestBlogFeed/LatestBlogFeed_CustomStyle.css");
base.OnLoad(e);
if (firstLoad)
{
firstLoad = false;
CustomizeWebPart();
}
}

Loss of properties webpart toolpart moss 2007

I've got the following problem:
I created a WebPart with a ToolPart,
this toolpart has multiple controls (textbox, dropdownlist, ...)
when I fill in everything and apply, it all goes ok,
even when i press ok. But when i go back to
edit -> modify webpart, all my data i've entered is gone.
How can i solve this?
Thanks
You'll need to save the values from the Toolpart in the webpart's properties. For example, lets say I want to save a string for "Title"... in the webpart define a property:
private const string DEFAULT_WPPColumnTitle = "Title";
private string _WPPColumnTitle = DEFAULT_WPPColumnTitle;
[Browsable(false)]
[WebPartStorage(Storage.Shared)]
public string WPPColumnTitle
{
get { return this._WPPColumnTitle; }
set { this._WPPColumnTitle = value; }
}
I always use the prefix "WPP" to keep all the web part properties together.
Then, in the Toolpart's ApplyChanges override, save the control's value (_ddlColumnsTitle) to the webpart (WPPColumnTitle):
/// <summary>
/// Called by the tool pane to apply property changes to
/// the selected Web Part.
/// </summary>
public override void ApplyChanges()
{
// get our webpart and set it's properties
MyCustomWebPart et = (MyCustomWebPart)ParentToolPane.SelectedWebPart;
et.WPPColumnTitle = _ddlColumnsTitle.SelectedValue;
}
Lastly, if the user edited the properties already, we want the Toolpart to be pre-populated with the user's configuration. In the CreateChildControls() method of your Toolpart, initialize the controls:
protected override void CreateChildControls()
{
try
{
MyCustomWebPart et = (MyCustomWebPart)ParentToolPane.SelectedWebPart;
// ... code to create _ddlColumnsTitle and add it to the Controls
// default our dropdown to the user's selection
ListItem currentItem = _ddlColumnsTitle.Items.FindByValue(et.WPPColumnTitle);
if (null != currentItem)
{
_ddlColumnsTitle.SelectedValue = currentItem.Value;
}
}
catch (Exception ex)
{
_errorMessage = "Error adding edit controls. " + ex.ToString();
}
}
Open up the debugger and double check that the values are getting applied to your propertries on Apply (i.e. WPPColumnTitle is set).
If so then problem is that SharePoint is not serializing/deserializing the value from the property (WPPColumnTitle) to the database and back - verify by writing out this property on the web part - as soon as you leave the page and come back it will be empty.
If so then check things like this on class
[XmlRoot(Namespace = "YourNamespace")]
and this (not strictly necessary) on properties
[XmlElement(ElementName = "ColumnTitle")]
I've also seen problems if you name your web part class "WebPart" so call it MyWebPart
I've solved it with adding a property in my webpart "IsNeverSet" (bool)
and when i go to the "CreateControls()" of my toolpart, I get this property
and if it's false, I load all the properties from my webpart and fill them in the toolpart.
So I found it with the help of Kit Menke

Outlook add in , text box , delete\backspace not working

I developed an outlook add in (custom task pane), with web browser in the user control.
All the things working well beside the backspace or the delete button when I am writing something in text box in the web browser, I can't use those keys, am I missing something?
I am a few years late to the party but I managed to fix this. The easiest way to fix this is to ensure proper focus is given to the input fields, so you will need to be able to run your own javascript on whatever page is being loaded.
The javascript I run on the page is as follows (using jQuery):
$(document).on("click", function (e) {
// first let the add-in give focus to our CustomTaskPane
window.external.focus();
// then in our web browser give focus to whatever element was clicked on
$(e.target).focus();
});
the window.external variable contains code run from the plugin (c# or VB I assume) which is exposed so we can interact from web page back to the add-in.
In the add-in code for the custom taskpane set the context of window.external:
// event when webBrowser is finished loading document
private void webBrowser1_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
// sets context of window.external to functions defined on this context
webBrowser1.ObjectForScripting = this;
}
And a public method for focusing:
// can be called by the web browser as window.external.focus()
public void focus()
{
this.Focus();
}
This worked for me, and I hope it helps others. Although do note that this probably doesn't work if the user keyboard navigates using tab, but you can either extend this code for that use case, or safely assume that the average outlook user will have his hand glued to the mouse.
Ok I solved the problem ,
The problem is that the custom task pane in not always gets fucos from the outlook.
So, I raised an event every time that there is "onclick" for all the pane, and then forced the pane to be in focus.
spent a lot of time trying to get this working in Outlook v16.0.13801.20288 the above did not work for me. I ended up with this working code.
Create a user control and add your webbrowser control to it then customize the .cs as below
private void CreateTaskPane() {
MyWinFormUserControl webBrowser = new MyWinFormUserControl();
webBrowser.webBrowser3.Url = new Uri("https://google.com");
webBrowser.webBrowser3.Width = 500;
webBrowser.webBrowser3.Dock = DockStyle.Fill;
webBrowser.webBrowser3.Visible = true;
webBrowser.Width = 500;
webBrowser.Dock = DockStyle.Fill;
webBrowser.Visible = true;
this.CRMTaskPaneControl = CustomTaskPanes.Add(webBrowser, "My App");
//Components.WebViewContainerWPFUserControl webView = (Components.WebViewContainerWPFUserControl)_eh.Child;
//webView.webview.Source = new Uri("https://localhost:3000");
this.CRMTaskPaneControl.Width = 500;
System.Windows.Forms.Application.DoEvents();
this.CRMTaskPaneControl.Control.Focus();
this.CRMTaskPane.Visible = true;
}
public partial class MyWinFormUserControl : UserControl
{
public WebBrowser webBrowser3;
public System.Windows.Forms.WebBrowser webBrowser1;
public MyWinFormUserControl()
{
InitializeComponent();
}
private void InitializeComponent()
{
this.webBrowser3 = new System.Windows.Forms.WebBrowser();
this.SuspendLayout();
//
// webBrowser3
//
this.webBrowser3.Dock = System.Windows.Forms.DockStyle.Fill;
this.webBrowser3.Location = new System.Drawing.Point(0, 0);
this.webBrowser3.MinimumSize = new System.Drawing.Size(20, 20);
this.webBrowser3.Name = "webBrowser3";
this.webBrowser3.Size = new System.Drawing.Size(500, 749);
this.webBrowser3.TabIndex = 0;
this.webBrowser3.DocumentCompleted += new System.Windows.Forms.WebBrowserDocumentCompletedEventHandler(this.webBrowser3_DocumentCompleted);
//
// MyWinFormUserControl
//
this.Controls.Add(this.webBrowser3);
this.Name = "MyWinFormUserControl";
this.Size = new System.Drawing.Size(500, 749);
this.Load += new System.EventHandler(this.MyWinFormUserControl_Load);
this.ResumeLayout(false);
}
void webBrowser3_DocumentCompleted(object sender, System.Windows.Forms.WebBrowserDocumentCompletedEventArgs e)
{
HtmlDocument doc;
doc = webBrowser3.Document;
doc.Click += doc_Click;
}
void doc_Click(object sender, HtmlElementEventArgs e)
{
this.Focus(); // force user control to have the focus
HtmlElement elem = webBrowser3.Document.GetElementFromPoint(e.ClientMousePosition);
elem.Focus(); // then let the clicked control to have focus
}
private void MyWinFormUserControl_Load(object sender, EventArgs e)
{
//Control loaded
}
Turns out this is an easy issue to fix.
Just write
class MyBrowser : WebBrowser {}
Then use MyBrowser instead of the .NET one.

How to access the Sharepoint SPNavigationNode.QuickLaunch Property?

I have a site as follows:
--SiteA
----Subsite1
----Subsite2
Now whenever i try to access the QuickLaunch Property its always empty e.g
SPNavigation nav = spWeb.Navigation;
if (nav.QuickLaunch.Count == 0)
{
// ALWAYS TRUE
}
However if i go into the Naviation Settings (Through the UI) of SiteA and reorder any site in the list, only then will the QuickLanuch become available. (Other settings are left as default)
Can anyone explain this behaviour? I really need access to the QuickLaunch items.
Thanks
This error occurs if you access quicklaunch while site is being created.Below code causes the feature activated code to wait until the site collection has been created before executing.
using System.Threading;
public override void FeatureActivated(SPFeatureReceiverProperties properties)
{
//Queues changes until after site exists. For use in provisioning.
SPWeb web = properties.Feature.Parent as SPWeb;
ThreadPool.QueueUserWorkItem(ApplyYourChanges, web.Url);
}
private void ApplyYourChanges(object state)
{
string webUrl = state as string;
Uri uri = new Uri(webUrl);
// additional conditions here -- perhaps check if a feature was activated
while (!SPSite.Exists(uri))
{
Thread.Sleep(5000);
}
using (SPSite site = new SPSite(webUrl))
{
using (SPWeb web = site.OpenWeb())
{
//configure the quicklaunch menu
configureQuickLaunch(web);
}
}
}
public static void configureQuickLaunch(SPWeb spWeb)
{
SPNavigationNodeCollection nodeCollection = spWeb.Navigation.QuickLaunch;
SPNavigationNode heading = nodeCollection.Cast<SPNavigationNode>().FirstOrDefault(n => n.Title == headingNode);
SPNavigationNode item = heading.Children.Cast<SPNavigationNode>().FirstOrDefault(n => n.Url == url);
if(item == null)
{
item = new SPNavigationNode(nodeName, url);
item = heading.Children.AddAsLast(item);
}
}
I think, by default, the QuickLaunch uses shared navigation. In other words, the QuickLaunch for a subsite doesn't have its own collection of nodes until you do something with it. If you reorder a site, that gives it its own unique set of nodes.
If you wanted to programmatically set your QuickLaunch to have its own set of nodes programmatically, you should be able to do so this way:
SPNavigation nav = spWeb.Navigation;
nav.UseShared = false;
spWeb.Update();
I think your count should be something other than zero at that point.
I seem to remember reading somewhere that the QuickLaunch collection only stored customisations to the default ordering. Looking around, I can't find that documentation to show you, but it would explain the behavior you see if true.
So your QuickLaunch.Count == 0 is just confirming that default ordering of items is in place.
You can still add nodes, if that's at all helpful;
SPNavigationNodeCollection nodes = web.Navigation.QuickLaunch;
SPNavigationNode node = new SPNavigationNode("Node Name", "Node URL", true);
nodes.AddAsFirst(node);

Resources