Sharepoint 2013 Hosted App execute javascript on all pages load - javascript

I would like to know if it's possible to have a SP 2013 Hosted app that injects a piece of Javascript that gets executed on every page load.
For the sake of simplicity, imagine that I want to create an App that on every page load of the SP Site displays a alert('Hello world!');
I don't want to have a Remote Web, pure and simple Hosted App that can be added by anyone simply by picking it from the SP Store.
Is this possible?
Thanks!

You can inject the javascript using a custom action script link as #AlexCode suggests but the app will require web - full control permissions. I can't remember where I adapted this code from while I was looking into add-in development. Also this is for POC only you should probably look to make it more robust before using it in a live environment.
App.js contents
(function(undefined) {
"use strict";
var actions, web, context, hostContext, actionDescription;
console.log('running function');
// getQueryStringParameter: method to retrieve query string parameter values
var getQueryStringParameter = function(param) {
var params = document.URL.split('?')[1].split('&');
var length = params.length;
for (var i = 0; i < length; i = i + 1) {
var singleParam = params[i].split('=');
if (singleParam[0] == param) {
return singleParam[1];
}
}
};
// inject: method to return as a string the js that will be ran by the custom action
var inject = function() {
debugger;
var scriptToRun;
scriptToRun += '(function (){' +
'var elem = document.getElementsByTagName("head")[0];' +
'var script = document.createElement("script");' +
'script.appendChild(document.createTextNode(alert("hello world")));' +
'elem.appendChild(script);' +
'}());';
return scriptToRun;
};
var success = function() {
alert('Done');
}
var fail = function() {
alert('Failed');
}
// unprovision: removes the custom action and the JavaScript file
var unprovision = function() {
context = SP.ClientContext.get_current();
hostContext = new SP.AppContextSite(context, decodeURIComponent(getQueryStringParameter('SPHostUrl')));
// load the custom actions from the host web
actions = hostContext.get_web().get_userCustomActions();
context.load(actions);
web = hostContext.get_web();
context.load(web);
context.executeQueryAsync(unprovisionEx, fail);
};
// unprovisionEx: method to remove the custom action
var unprovisionEx = function() {
var enumerator = actions.getEnumerator();
var removeThese = [];
// find the custom action
while (enumerator.moveNext()) {
var action = enumerator.get_current();
if (action.get_description() == actionDescription && action.get_location() == 'ScriptLink') {
// add it to a temporary array (we cannot modify an enumerator while enumerating)
removeThese.push(action);
}
}
// do the actual removal of the custom action
var length = removeThese.length;
for (var i = 0; i < length; i++) {
removeThese[i].deleteObject();
delete removeThese[i];
}
context.executeQueryAsync(success, fail);
};
// provisionScriptLink: method that adds the custom action
var provisionScriptLink = function() {
var enumerator = actions.getEnumerator();
var removeThese = [];
// check if the custom action already exists, if it does then remove it before adding the new one
while (enumerator.moveNext()) {
var action = enumerator.get_current();
if (action.get_description() == actionDescription && action.get_location() == 'ScriptLink') {
removeThese.push(action);
}
}
var length = removeThese.length;
for (var i = 0; i < length; i++) {
removeThese[i].deleteObject();
delete removeThese[i];
}
// create the custom action
var newAction = actions.add();
// the 'description' is what we'll use to uniquely identify our custom action
newAction.set_description(actionDescription);
newAction.set_location('ScriptLink');
newAction.set_scriptBlock(inject());
newAction.update();
context.executeQueryAsync(success, fail);
};
// provision: starts with uploading the JavaScript file to the host we, once done it will continue with the provisionScriptLink() method
var provision = function() {
context = SP.ClientContext.get_current();
hostContext = new SP.AppContextSite(context, decodeURIComponent(getQueryStringParameter('SPHostUrl')));
// load the custom actions from the host web
actions = hostContext.get_web().get_userCustomActions();
context.load(actions);
web = hostContext.get_web();
context.load(web);
context.executeQueryAsync(provisionScriptLink, fail);
};
document.getElementById("add").onclick = provision;
}());
Default.apsx content
<%-- The following 4 lines are ASP.NET directives needed when using SharePoint components --%>
<%# Page Inherits="Microsoft.SharePoint.WebPartPages.WebPartPage, Microsoft.SharePoint, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" MasterPageFile="~masterurl/default.master" Language="C#" %>
<%# Register TagPrefix="SharePoint" Namespace="Microsoft.SharePoint.WebControls" Assembly="Microsoft.SharePoint, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%# Register TagPrefix="Utilities" Namespace="Microsoft.SharePoint.Utilities" Assembly="Microsoft.SharePoint, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%# Register TagPrefix="WebPartPages" Namespace="Microsoft.SharePoint.WebPartPages" Assembly="Microsoft.SharePoint, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%-- The markup and script in the following Content element will be placed in the <head> of the page --%>
<asp:Content ContentPlaceHolderID="PlaceHolderAdditionalPageHead" runat="server">
<script type="text/javascript" src="/_layouts/15/sp.runtime.js"></script>
<script type="text/javascript" src="/_layouts/15/sp.js"></script>
<!-- Add your CSS styles to the following file -->
<link rel="Stylesheet" type="text/css" href="../Content/App.css" />
</asp:Content>
<%-- The markup in the following Content element will be placed in the TitleArea of the page --%>
<asp:Content ContentPlaceHolderID="PlaceHolderPageTitleInTitleArea" runat="server">
Page Title
</asp:Content>
<%-- The markup and script in the following Content element will be placed in the <body> of the page --%>
<asp:Content ContentPlaceHolderID="PlaceHolderMain" runat="server">
<div>
<button type="button" value="add" name="add" id="add">Add</button>
</div>
</asp:Content>
<asp:Content ContentPlaceHolderID="PlaceHolderUtilityContent" runat="server">
<!-- Add your JavaScript to the following file -->
<script type="text/javascript" src="../Scripts/App.js"></script>
</asp:Content>

You can provide a custom master page to the host site from app site via javascript. Anyway the host site must use the new master page.
You can see this article for more info

Related

SharePoint JavaScript update choices field.set_choice does not exist

I am working with a SharePoint hosted add on that has a JavaScript component that I would like to use to update some of the choice values for one of the Site Columns I created. Everything I see indicates I should have access to a spChoiceField.Choices.Add(value), or spChoiceField.AddChoice(value), or spChoiceField.set_choices(value) but none of these are valid for me.
I am working with code that looks like:
if (clientContext != undefined && clientContext != null) {
var web = clientContext.get_web();
fieldTitle = "TQM Requesting:";
fieldChoice = clientContext.castTo(web.get_availableFields().getByTitle(fieldTitle), SP.FieldChoice);
TQMtoAdd = TQMToInsert.value;
clientContext.load(fieldChoice);
I expect fieldChoice to provide one of the add functions but it does not.
I checked the following articles:
How to update Choice column in SharePoint
Update multiple choice field in sharepoint using rest api
Sharepoint choice field
Thank you,
Duncan
Tested script in my local to update choice field of host web in SharePoint hosted add-in.
<%-- The following 4 lines are ASP.NET directives needed when using SharePoint components --%>
<%# Page Inherits="Microsoft.SharePoint.WebPartPages.WebPartPage, Microsoft.SharePoint, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" MasterPageFile="~masterurl/default.master" Language="C#" %>
<%# Register TagPrefix="Utilities" Namespace="Microsoft.SharePoint.Utilities" Assembly="Microsoft.SharePoint, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%# Register TagPrefix="WebPartPages" Namespace="Microsoft.SharePoint.WebPartPages" Assembly="Microsoft.SharePoint, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%# Register TagPrefix="SharePoint" Namespace="Microsoft.SharePoint.WebControls" Assembly="Microsoft.SharePoint, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%-- The markup and script in the following Content element will be placed in the <head> of the page --%>
<asp:Content ContentPlaceHolderID="PlaceHolderAdditionalPageHead" runat="server">
<script type="text/javascript" src="../Scripts/jquery-1.9.1.min.js"></script>
<SharePoint:ScriptLink Name="sp.js" runat="server" OnDemand="true" LoadAfterUI="true" Localizable="false" />
<meta name="WebPartPageExpansion" content="full" />
<!-- Add your CSS styles to the following file -->
<link rel="Stylesheet" type="text/css" href="../Content/App.css" />
<!-- Add your JavaScript to the following file -->
<script type="text/javascript" src="/_layouts/15/sp.runtime.js"></script>
<script type="text/javascript" src="/_layouts/15/sp.js"></script>
<script type="text/javascript" src="../Scripts/App.js"></script>
<script type="text/javascript">
var appWebContext;
var listResult;
var hostweburl;
$(document).ready(function () {
UpdateChoice();
});
function UpdateChoice() {
appWebContext = new SP.ClientContext.get_current();
hostweburl = decodeURIComponent($.getUrlVar("SPHostUrl"));
var hostwebContext = new SP.AppContextSite(appWebContext, hostweburl);
var web = hostwebContext.get_web();
var fieldTitle = "MyChoice";
var fieldChoice = appWebContext.castTo(web.get_availableFields().getByTitle(fieldTitle), SP.FieldChoice);
appWebContext.load(fieldChoice);
appWebContext.executeQueryAsync(function () {
var newValues = "NewOption";//strStatusValues.split(",");
var currentChoices = fieldChoice.get_choices();
//for (var i = 0; i < newValues.length; i++) {
// currentChoices.push(newValues[i]);
//}
currentChoices.push(newValues);
fieldChoice.set_choices(currentChoices);
fieldChoice.updateAndPushChanges();
debugger;
appWebContext.executeQueryAsync(function () {
console.log("Added new choice values to the column");
}, function (sender, args) {
deferred.reject(args.get_message());
});
},
function (sender, args) {
deferred.reject(args.get_message());
});
}
// jQuery plugin for fetching querystring parameters
jQuery.extend({
getUrlVars: function () {
var vars = [], hash;
var hashes = window.location.href.slice(window.location.href.indexOf('?') + 1).split('&');
for (var i = 0; i < hashes.length; i++) {
hash = hashes[i].split('=');
vars.push(hash[0]);
vars[hash[0]] = hash[1];
}
return vars;
},
getUrlVar: function (name) {
return jQuery.getUrlVars()[name];
}
});
</script>
</asp:Content>
<%-- The markup in the following Content element will be placed in the TitleArea of the page --%>
<asp:Content ContentPlaceHolderID="PlaceHolderPageTitleInTitleArea" runat="server">
Page Title
</asp:Content>
<%-- The markup and script in the following Content element will be placed in the <body> of the page --%>
<asp:Content ContentPlaceHolderID="PlaceHolderMain" runat="server">
<div>
<p id="message">
<!-- The following content will be replaced with the user name when you run the app - see App.js -->
initializing...
</p>
</div>
</asp:Content>

Access list of data in the Master Page code behind to front end of the same master page using Javascript

I'm loading some of data to a list called "TransactionNames" in the code behind of the master page (TestMaster.Master).
Now I need to pass that list of data to front-end of the master page(TestMaster.Master) using java script.
I tried like above,
If you have a List in code behind that is declared outside a method:
public List<string> TransactionNames = new List<string>();
Then you need to create an array in javascript:
<script type="text/javascript">
var TransactionNames = ["<%= string.Join("\",\"", TransactionNames) %>"];
//or
var TransactionNames = <%= "['" + string.Join("','", TransactionNames) + "']" %>;
for (var i = 0; i < TransactionNames.length; i++) {
alert(TransactionNames[i]);
}
</script>
Or it becomes even easier when you use Newtonsoft.Json to serialize objects:
var TransactionNames = <%= Newtonsoft.Json.JsonConvert.SerializeObject(TransactionNames) %>;
You didn't mention exactly what do you want to do with the transaction names on the front-end of master page e.g. adding them to a menu, concatenating them to a label etc or creating a structure from the names;
Suppose you want to create a structure; here is the code
for(i =0;i< TransactionNames.length;i++)
{
$("#ul").append("<li>" + TransactionNames[i] + "</li>");
}
You can do using declare global public variable:
Code Behind:
public string[] TransactionNames=new string[]
{
"schnauzer",
"shih tzu",
"shar pei",
"russian spaniel"
};
Source File:
<script type="text/javascript">
var TransactionNames= <%= TransactionNames %>;
for(var i=0; i < TransactionNames.length;i++){
var tx=TransactionNames[i];
}
</script>

Javascript/Ajax Request very erratic and random

I have been working on the following code and with help from #squint, I have got to a point where it appears to work, but very erratic and randomly.
Code Edited with #TomasZato suggestions
<%#LANGUAGE="VBSCRIPT" CODEPAGE="65001"%>
<!--#include file="../Connections/DVerto.asp" -->
<%
Dim Recordset1
Dim Recordset1_cmd
Dim Recordset1_numRows
Set Recordset1_cmd = Server.CreateObject ("ADODB.Command")
Recordset1_cmd.ActiveConnection = MM_DVerto_STRING
Recordset1_cmd.CommandText = "SELECT Part_Number FROM dbo.Stock_Header WHERE Part_Number like '84%'"
Recordset1_cmd.Prepared = true
Set Recordset1 = Recordset1_cmd.Execute
Recordset1_numRows = 0
%>
<%
Dim Repeat1__numRows
Dim Repeat1__index
Repeat1__numRows = 10
Repeat1__index = 0
Recordset1_numRows = Recordset1_numRows + Repeat1__numRows
%>
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>Untitled Document</title>
</head>
<body onLoad="loadDoc()">
<table width="50%" border="0" cellspacing="2" cellpadding="2">
<%
While ((Repeat1__numRows <> 0) AND (NOT Recordset1.EOF))
%>
<tr>
<td class="prodref"><%=(Recordset1.Fields.Item("Part_Number").Value)%></td>
<td class="demo"> </td>
</tr>
<%
Repeat1__index=Repeat1__index+1
Repeat1__numRows=Repeat1__numRows-1
Recordset1.MoveNext()
Wend
%>
</table>
<script>
// This creates array of elements with requested class name - eg. [HTMLElement, HTMLElement ...]
var elements = document.getElementsByClassName("prodref");
var outputElements = document.getElementsByClassName("demo");
// Allways check if there is correct number of demo elements to print loaded data in
if(elements.length != outputElements.length) {
console.error("The number of prodref and demo elements is not the same!");
}
// Loop through both arrays of elements and make AJAX request for every one of them
for (var i=0, length=elements.length; i < length; i++) {
loadDoc(elements[i], outputElements[i]);
}
function loadDoc(element, demoElement) {
console.log("creating loadDoc() call for element", element);
var xhttp = new XMLHttpRequest();
var url = "data.asp?prodref="+element.innerHTML;
// Onload calls if request was successful
xhttp.onload = function() {
console.log("loadDoc() call for element", element, "succeeded");
demoElement.innerHTML = xhttp.responseText;
};
// Error calls if there is an error
xhttp.onerror = function() {
console.error("There was some problem with the request for element",element," with url '", url, "', check the Net debug panel.");
}
// Do not make sync requests, that makes page lag. Just DON'T!!!
xhttp.open("GET", url, false);
xhttp.send();
}
</script>
</body>
</html>
<%
Recordset1.Close()
Set Recordset1 = Nothing
%>
Code (Data.asp)
<%#LANGUAGE="VBSCRIPT" CODEPAGE="65001"%>
<!--#include file="../Connections/PSCRM.asp" -->
<%
Dim rs_proditem__MMColParam
rs_proditem__MMColParam = "1"
If (Request.QueryString("prodref") <> "") Then
rs_proditem__MMColParam = Request.QueryString("prodref")
End If
%>
<%
Dim rs_proditem
Dim rs_proditem_cmd
Dim rs_proditem_numRows
Set rs_proditem_cmd = Server.CreateObject ("ADODB.Command")
rs_proditem_cmd.ActiveConnection = MM_PSCRM_STRING
rs_proditem_cmd.CommandText = "SELECT * FROM dba.proditem as t1 LEFT JOIN dba.proditem_xtra as t2 ON t1.prodref=t2.prodref WHERE t1.prodref = ? and rber_mi_source = 'M'"
rs_proditem_cmd.Prepared = true
rs_proditem_cmd.Parameters.Append rs_proditem_cmd.CreateParameter("param1", 200, 1, 25, rs_proditem__MMColParam) ' adVarChar
Set rs_proditem = rs_proditem_cmd.Execute
rs_proditem_numRows = 0
%>
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>Untitled Document</title>
</head>
<div class="demo"><%=(rs_proditem.Fields.Item("proddesc").Value)%></div>
<body>
</body>
</html>
<%
rs_proditem.Close()
Set rs_proditem = Nothing
%>
When the page loads, some results are seen, sometimes returns 2 results, then more. Sometimes it misses a row out.
I have also noticed that on load the data in the third column <td class='demo'></td> which is being pulled from data.asp seems to change while the page is still loading?
Any help would be greatly accepted.
The problem is that you produced totally obscure code and you forgot what it's doing. First to the cause - I actually don't understand how come it ever works. First you do this:
a[i] = document.getElementsByClassName("prodref").innerHTML;
This is wrong because
a is HTMLElementCollection and is not supposed to be changed
document.getElementsByClassName("prodref") is an also HTMLElementCollection and has no property innerHTML
a[i] should now contain undefined, but since HTMLElementCollection array is immutable this code just doesn't do anything.
After this, you try to do this - technically it should work, because your wrong code above didn't do anything:
xhttp.open("GET", "data.asp?prodref="+a[i].innerHTML, true);
But it fails, which indicates there's an error you're hiding from me (eg. problem in the VBS script).
Fixed code with remarks
I decided to clean up and comment your code:
// This creates array of elements with requested class name - eg. [HTMLElement, HTMLElement ...]
var elements = document.getElementsByClassName("prodref");
var outputElements = document.getElementsByClassName("demo");
// Allways check if there is correct number of demo elements to print loaded data in
if(elements.length != outputElements.length) {
console.error("The number of prodref and demo elements is not the same!");
}
// Loop through both arrays of elements and make AJAX request for every one of them
for (var i=0, length=elements.length; i < length; i++) {
loadDoc(elements[i], outputElements[i]);
}
function loadDoc(element, demoElement) {
console.log("creating loadDoc() call for element", element);
var xhttp = new XMLHttpRequest();
var url = "data.asp?prodref="+element.innerHTML;
// Onload calls if request was successful
xhttp.onload = function() {
console.log("loadDoc() call for element", element, "succeeded");
demoElement.innerHTML = xhttp.responseText;
};
// Error calls if there is an error
xhttp.onerror = function() {
console.error("There was some problem with the request for element",element," with url '", url, "', check the Net debug panel.");
}
// Do not make sync requests, that makes page lag. Just DON'T!!!
xhttp.open("GET", url, false);
xhttp.send();
}
Of course, since you decided not to provide a good test page, I couldn't test this code.

jQuery append() under an element ID?

I am building a navigation bar that is driven based off of values retrieved from a SharePoint List. Right now, I am using an <ul> for my column headers and <li> for my contents. I can get the headers to display correctly and can also get the contents of that column to display correctly. What I'm having troubles with is that the <li> seems be appended to the <ul> which is great, but it's also putting it inside of it. My <ul> has a border around it and I want the content to be appended directly under that border but instead, it's putting everything inside of it.
Here is the specific block of code I believe is wrong:
$('#TableElement').hover(function () {
$('[id^=Header]').hover(function () {
$("#" + this.id).append("<li>" + this.id + "</li>");
});
});
Here is all of my code:
/////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////
////////////////////////////////////////EVERYTHING BELOW THIS LINE IS GOOD TO GO/////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////
//Print Headers to Screen. This will drive the core functionalty of the navpart
var siteUrl = '/sites/dev';
ExecuteOrDelayUntilScriptLoaded(retrieveListItems, "sp.js");
theCounter = 0;
var Headers = new Array();
var getCurrentElementId = null;
function retrieveListItems() {
var clientContext = new SP.ClientContext(siteUrl);
var oList = clientContext.get_web().get_lists().getByTitle('myList');
var camlQuery = new SP.CamlQuery();
camlQuery.set_viewXml("<Where><IsNotNull><FieldRef Name='Title' /></IsNotNull></Where>");
this.collListItem = oList.getItems(camlQuery);
clientContext.load(collListItem);
clientContext.executeQueryAsync(Function.createDelegate(this, this.onQuerySucceeded), Function.createDelegate(this, this.onQueryFailed));
}
function onQuerySucceeded(sender, args) {
var listItemInfo = '';
var listItemEnumerator = collListItem.getEnumerator();
while (listItemEnumerator.moveNext()) {
var oListItem = listItemEnumerator.get_current();
theCounter += 1;
Headers[theCounter - 1] = oListItem.get_item('Title');
}
var HeaderDisplay = _.uniq(Headers);
for (var i = 0; i <= HeaderDisplay.length - 1; i++) {
$('#TableElement').append("<th id=Header" + i + ">" + HeaderDisplay[i] + "::::::" + "</th>");
}
}
function onQueryFailed(sender, args) {
alert('Request failed. ' + args.get_message() + '\n' + args.get_stackTrace());
}
/////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////
////////////////////////////////////////EVERYTHING ABOVE THIS LINE IS GOOD TO GO/////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////
// You got the headers to print as expected. Right now you need to figure out how to get the current ID
// that the mouse is over. Try looking at another project you did where the mouse goes into the table header
// and the outline expands.
$('#TableElement').hover(function () {
$('[id^=Header]').hover(function () {
// Come back to this::::::: var content = $(this).html();
$("#" + this.id).append("<li>" + this.id + "</li>");
});
});
//This should be the universal onmouseover event that will expose only links
//and values relavent to the selected header.
//$(document).ready(function onPageLoad() {
// $().SPServices({
// operation: "GetListItems",
// async: false,
// listName: "myList",
// CAMLQuery: "<Query><Where><IsNotNull><FieldRef Name='Title' /></IsNotNull></Where></Query>",
// completefunc: function completeFunction(xData, Status) {
// $(xData.responseXML).SPFilterNode("z:row").each(function () {
// var Headers = "<th>" + $(this).attr("ows_Title") + "</th>";
// $("#TableElement").append(Headers);
// });
// }
// });
//});
HTML Code:
<%# Assembly Name="$SharePoint.Project.AssemblyFullName$" %>
<%# Assembly Name="Microsoft.Web.CommandUI, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%# Register Tagprefix="SharePoint" Namespace="Microsoft.SharePoint.WebControls" Assembly="Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%# Register Tagprefix="Utilities" Namespace="Microsoft.SharePoint.Utilities" Assembly="Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%# Register Tagprefix="asp" Namespace="System.Web.UI" Assembly="System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" %>
<%# Import Namespace="Microsoft.SharePoint" %>
<%# Register Tagprefix="WebPartPages" Namespace="Microsoft.SharePoint.WebPartPages" Assembly="Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%# Control Language="C#" AutoEventWireup="true" CodeBehind="VisualWebPart1UserControl.ascx.cs" Inherits="AnotherMarcPart.VisualWebPart1.VisualWebPart1UserControl" %>
<!DOCTYPE Html />
<html>
<head>
<link rel="Stylesheet" type="text/css" href="c:\users\administrator\documents\visual studio 2010\Projects\AnotherMarcPart\AnotherMarcPart\VisualWebPart1\Stylesheet1.css" />
<title></title>
</head>
<body>
<ul id="TableElement"></ul>
<script type="text/javascript" src="c:\users\administrator\documents\visual studio 2010\Projects\AnotherMarcPart\AnotherMarcPart\VisualWebPart1\jQuery_v1.10.2.js"></script>
<script type="text/javascript" src="c:\users\administrator\documents\visual studio 2010\Projects\AnotherMarcPart\AnotherMarcPart\VisualWebPart1\jquery.SPServices-2013.01.js"></script>
<script type="text/javascript" src="c:\users\administrator\documents\visual studio 2010\Projects\AnotherMarcPart\AnotherMarcPart\VisualWebPart1\Underscore.js 1.5.2.js"> </script>
<script type="text/javascript" src="c:\users\administrator\documents\visual studio 2010\Projects\AnotherMarcPart\AnotherMarcPart\VisualWebPart1\JScript1.js"></script>
</body>
</html>
<li> tags must go inside a <ul>. If you want your content after the <ul>, then don't put it in an <li> (perhaps put it in a <div> instead) and use jQuery's .after() or .insertAfter() to put it after the <ul>.
Also, this code is likely wrong:
$('#TableElement').hover(function () {
$('[id^=Header]').hover(function () {
$("#" + this.id).append("<li>" + this.id + "</li>");
});
});
You don't want two .hover() handlers inside of one another. You will be installing the second .hover() over and over every time you hover over the first one. That will give you lots of duplicate event handlers and the function inside will get executed multiple times.
If .insertAfter() isn't exactly what you want, then show us your HTML and show us exactly where you want the new content inserted. You said you wanted it after the <ul> tag's border so that's what .insertAfter() will do.
Based on how you've edited your question, you would append to that other UL like this:
$("#TableElement").append("<li>" + this.id + "</li>");
That will make the <li> be the last <li> inside of the TableElement <ul> which will be inside it's border. There is no way to put an <li> inside a <ul> and have the <li> be outside the border around the <ul>. To do that, you would have to create a container object AFTER the <ul> and put the content into that container instead.

SharePoint 2010: Create a bookmark button that adds a page to your My Links

I am trying to create a link/button on my masterpage which when clicked, adds the current page to the user's My Links list. This is merely a shortcut to save the user from having to navigate to their My Site and add the link manually.
[This blog post] gives a solution to this problem, but I get a JavaScript error on the second line of the "Add Link" dialog (QuickLinksDialog2.aspx) because the frameElement property is null:
<script language="Javascript">
var form = document.forms[0];
var args = window.parent.frameElement.dialogArgs;
Regardless, Portal.js appears to contain all the functions that the My Links page (_layouts/MyQuickLinks.aspx) uses to add links to this list.
Can anyone suggest how I might go about calling one/some of these functions from my masterpage so that the "Add Link" dialog is opened with the title and URL fields pre-poulated?
I ended up using the object model to create the My Links (as apposed to the popup dialog).
The upside to this is that adding a link is now only a 1-click process, the downside is that the user does not have the opportunity to rename the link or assign it to a group (personally, I've hidden the groups from the UI anyway as we didnt need them so this was a non-issue for me).
For those interested, I created a little usercontrol which just houses an ajaxified button which you can drop onto your masterpage / page layout. My code for this is as follows:
HTML
<script type="text/javascript">
function FavouriteImageButton_AddMyLink_Clicked() {
SP.UI.Notify.addNotification("Bookmark generated successfully.");
}
function FavouriteImageButton_RemoveMyLink_Clicked() {
SP.UI.Notify.addNotification("Bookmark deleted successfully.");
}
</script>
<asp:UpdatePanel ID="UpdatePanel" runat="server" ChildrenAsTriggers="true" UpdateMode="Conditional">
<ContentTemplate>
<asp:ImageButton ID="FavouriteImageButon" runat="server" OnCommand="FavouriteImageButton_Command" />
</ContentTemplate>
</asp:UpdatePanel>
C#
private struct FavouriteButtonCommandNames
{
public const string AddMyLink = "AddMyLink";
public const string RemoveMyLink = "RemoveMyLink";
}
protected void Page_PreRender(object sender, EventArgs e)
{
// Initialise the favourites button according to whether or not the page already exists in the My Links list.
this.FavouriteImageButon.ImageUrl = "/_layouts/images/favourite_add.png";
this.FavouriteImageButon.AlternateText = "Add to My Links";
this.FavouriteImageButon.CommandName = FavouriteButtonCommandNames.AddMyLink;
this.FavouriteImageButon.CommandArgument = null;
UserProfileManager userProfileManager = new UserProfileManager(SPServiceContext.Current);
UserProfile currentUser = userProfileManager.GetUserProfile(false);
foreach (QuickLink quickLink in currentUser.QuickLinks.GetItems())
{
if (quickLink.Url.ToLower() == this.Page.Request.Url.ToString().ToLower())
{
this.FavouriteImageButon.ImageUrl = "/_layouts/images/favourite_delete.png";
this.FavouriteImageButon.AlternateText = "Remove from My Links";
this.FavouriteImageButon.CommandName = FavouriteButtonCommandNames.RemoveMyLink;
this.FavouriteImageButon.CommandArgument = quickLink.ID.ToString();
break;
}
}
}
protected void FavouriteImageButton_Command(object sender, CommandEventArgs e)
{
UserProfileManager userProfileManager = new UserProfileManager(SPServiceContext.Current);
UserProfile currentUser = userProfileManager.GetUserProfile(false);
switch (e.CommandName)
{
case FavouriteButtonCommandNames.AddMyLink:
// Create the link.
currentUser.QuickLinks.Create(
SPContext.Current.File.Title,
this.Page.Request.Url.ToString(),
QuickLinkGroupType.General,
null,
Privacy.Private);
// Display a notification message.
ScriptManager.RegisterStartupScript(this.UpdatePanel, this.UpdatePanel.GetType(), e.CommandName, "ExecuteOrDelayUntilScriptLoaded(FavouriteImageButton_AddMyLink_Clicked, \"sp.js\");", true);
break;
case FavouriteButtonCommandNames.RemoveMyLink:
long id;
if (long.TryParse((string)e.CommandArgument, out id))
{
// Delete the link.
QuickLink quickLink = currentUser.QuickLinks[long.Parse((string)e.CommandArgument)];
quickLink.Delete();
// Display a notification message.
ScriptManager.RegisterStartupScript(this.UpdatePanel, this.UpdatePanel.GetType(), e.CommandName, "ExecuteOrDelayUntilScriptLoaded(FavouriteImageButton_RemoveMyLink_Clicked, \"sp.js\");", true);
}
else
{
throw new ArgumentNullException("e.CommandArgument", "\"{0}\" is not a valid QuickLink ID. The QuickLink could not be removed from the list.");
}
break;
}
}
Add the following function to your master page:
function addlink(){
t=document.title;
u=escape(location.href);
var q = window.location.protocol + "//" + window.location.host + "/_vti_bin/portalapi.aspx?cmd=PinToMyPage&ListViewURL=" + u + "&ListTitle=" + t + "&IsDlg-1"; // + "&ReturnUrl=" + u;
location.href = q;
}
Then add your anchor tag:
<a href='javascript:addlink()'>Add this Page</a>

Categories

Resources