„Gefällt mir“ im SharePoint 2010 Blog

In diesem Beitrag wird gezeigt, wie man eine SharePoint 2010 Blogwebsite mit Facebook-ähnlicher Gefällt mir Funktionalität ausstatten kann. Die gezeigte Lösung ist mit JavaScript realisiert und kommt deshalb komplett ohne Postbacks aus. Das Ergebnis wird sich später so darstellen:

Wir beginnen, indem wir eine neue Website aus der Vorlage Blog erstellen.

Die Likes-Liste

Welcher Person welcher Beitrag gefällt, wird in einer SharePoint-Liste gespeichert. Wir legen also eine neue Liste an und geben ihr den Namen Likes. Man klickt dazu auf Websiteaktionen Weitere Optionen, markiert dann die Vorlage Benutzerdefinierte Liste und klickt rechts auf Weitere Optionen. Die Markierung bei Liste in der Schnellstartleiste anzeigen setzen wir auf Nein und klicken dann auf Erstellen.

Die Liste muß jetzt noch etwas verändert werden. Dazu klickt man im Reiter Liste auf Listeneinstellungen. Die Standardspalte Titel brauchen wir nicht. Die Spalte ist aber als Pflichtfeld gekennzeichnet und das müssen wir ändern. Dazu klickt man auf den Spaltennamen Titel und setzt die Markierung bei Diese Spalte muss Informationen enthalten auf Nein.

Um die einzelnen Likes einem Blogbeitrag zuzuordnen, brauchen wir jetzt noch eine Nachschlagespalte auf die Beiträge. Wir klicken dazu auf Spalte erstellen, geben der neuen Spalte den Namen Beitrag und wählen als Informationstyp Nachschlagen (in Informationen, die sich bereits auf dieser Website befinden). Nachdem wir geprüft haben, daß auch wirklich in der Liste Beiträge nachgeschlagen wird, klicken wir auf OK.

Weitere Anpassungen wie z.B. spezielle Ansichten sind nicht notwendig, da in dieser Liste niemand direkt Daten einträgt. Man könnte sie sogar komplett aus der Oberfläche ausblenden, indem man ihre Hidden-Eigenschaft auf true setzt (was nicht im Browser geht).

JavaScript

Den benötigten JavaScript-Code legt man am Besten in eine eigene .js-Datei und bindet diese dann ein. Es gibt viele Möglichkeiten, wo man diese Datei ablegen kann. Das kann irgendwo in der Website, z.B. in einer Assets-Bibliothek, aber auch im Dateisystem der Webfrontend-Server sein, z.B. in einem eigenen Unterordner von 14\TEMPLATE\LAYOUTS. Für die Demo hier erstellen wir eine einfache Dokumentbibliothek Assets, die nicht in der Schnellstartleiste angezeigt wird und bei der wir als Vorlage Keine wählen. Unser Script kommt in eine Datei Likes.js, die wir in diese Bibliothek hochladen.

Vorhandene Likes anzeigen

Wir fangen an mit einer Funktion, die alle derzeit vorhandenen Likes anzeigt. Der Funktion übergeben wir die ID des Blogbeitrags, für den die Likes angezeigt werden sollen:

function getAllPostLikes(postId) {
  // hier holen wir uns die Likes und stellen sie dar
}

In dieser Funktion holen wir uns zunächst den Kontext und die erforderlichen Objekte wie die Likes-Liste und den aktuellen Benutzer. Diesen brauchen wir um festzustellen, ob dem aktuellen Benutzer dieser Beitrag gefällt oder nicht:

var ctx = new SP.ClientContext();
var web = ctx.get_web();
var currentUser = web.get_currentUser();
ctx.load(currentUser);
var list = web.get_lists().getByTitle("Likes");

Die vorhandenen Likes zum Beitrag holen wir jetzt über eine kleine CAML-Abfrage aus der Liste:

var query = new SP.CamlQuery();
query.set_viewXml("<View><Query><Where><Eq><FieldRef Name=’Beitrag‘ LookupId=’True’/><Value Type=’Lookup‘>" + postId + "</Value></Eq></Where></Query></View>");
var items = list.getItems(query);
ctx.load(items);

Sämtliche Interaktionen mit dem Server müssen im SharePoint Client Object Model immer asynchron ausgeführt werden. Man gibt dabei jeweils eine Funktion an, die bei Erfolg und im Fehlerfall aufgerufen wird. Fehler ignorieren wir hier einfach und die Funktion für den Erfolg geben wir inline an. Das Gerüst dazu sieht also so aus:

ctx.executeQueryAsync(function () {
  // alle Likes stehen jetzt zur Verfügung
  }, function () { }
);

In dieser Funktion bauen wir uns den HTML-Quelltext zusammen, mit dem wir später die Anzahl der Likes darstellen. Auch den Button, mit dem der Benutzer später einen Beitrag "Liken" kann, bzw. einen "Like" zurücknehmen kann, erstellen wir dort als HTML.

Die Anzahl der Likes erstellen wir als einfachen Text und fügen davor und dahinter Leerraum ein, damit sich die Darstellung später besser in die Seite einpaßt. Man könnte hier z.B. noch eine Fallunterscheidung machen und für die Fälle, daß der Beitrag bisher niemandem oder nur einer Person gefällt, andere Texte anzeigen. Hier soll aber nur so einfach wie möglich das Prinzip gezeigt werden.

var html = "&nbsp;|&nbsp;" + items.get_count() + " Person(en) gef&auml;llt das&nbsp;&nbsp;";

Jetzt ermitteln wir, ob dem aktuellen Benutzer der Beitrag bereits gefallen hat. Dazu vergleichen wir einfach die ID desjenigen, der ein Like erstellt hat mit der ID des aktuellen Benutzers:

var userLikesThis = false;
for (var i = 0; i < items.get_count(); i++) {
  var item = items.get_item(i);
  var author = item.get_item("Author");
  if (author.get_lookupId() == currentUser.get_id()) {
    userLikesThis = true;
    break;
  }
}

Jetzt fehlt noch der Teil zur Darstellung der Like- bzw. Unlike-Buttons. Wir erzeugen hier einfache HTML-Buttons, die beim Klick entsprechende JavaScript-Funktionen aufrufen und dabei den Button selbst, die ID des Beitrags und die ID des aktuellen Benutzers übergeben. Diese Funktionen werden im Anschluß behandelt. Auch hier könnte man die Darstellung sicher noch aufhübschen, aber wie gesagt: es geht nur um das Prinzip:

if (userLikesThis) {
  html += "<input type=’button‘ value=’Gef&auml;llt mir nicht mehr‘ onclick=’unlikePost(this, " + postId + ", " + currentUser.get_id() + "); return false;’/>";
} else {
  html += "<input type=’button‘ value=’Gef&auml;llt mir‘ onclick=’likePost(this, " + postId + ", " + currentUser.get_id() + "); return false;’/>";
}

Wir haben jetzt das HTML zur Darstellung beieinander und fügen es jetzt in die Seite ein. Dazu setzen wir die innerHTML-Eigenschaft eines in der Seite platzierten <span>-Elements. Bei diesem Element wurde die id um die ID des Beitrags ergänzt, so daß wir jetzt gezielt darauf zugreifen können. Wie das Element erzeugt wurde, zeige ich weiter unten.

$get("PostLikesSpan" + postId).innerHTML = html;

Einen Beitrag "Liken"

Wenn ein Benutzer auf den Gefällt mir Button klickt, wird diese Funktion aufgerufen:

function likePost(btn, postId, userId) {
  btn.enabled = false;
}

In der Funktion wird zuerst der geklickte Button selbst deaktiviert, um zu verhindern, daß ein Benutzer für einen Beitrag mehrfach die Gefällt mir Funktion auslösen kann. Ähnlich wie oben holen wir uns jetzt ein paar Objekte und suchen dann nach einemeventuell bereits vorhandenen Like für den aktuellen Benutzer. Die CAML-Abfrage dazu ist ebenfalls ähnlich wie oben, aber weiter eingeschränkt auf den Benutzer:

query.set_viewXml("<View><Query><Where><And><Eq><FieldRef Name=’Beitrag‘ LookupId=’True’/><Value Type=’Lookup‘>" + postId + "</Value></Eq>" +
"<Eq><FieldRef Name=’Author‘ LookupId=’True’/><Value Type=’Lookup‘>" + userId + "</Value></Eq></And></Where></Query></View>");

Nach dem Ausführen der Abfrage prüfen wir, ob es bereits ein Like gibt und nur wenn nicht erzeugen wire in neues Element in der Likes-Liste. Danach rufen wir einfach die getAllPostLikes-Funktion von oben wieder auf, um die Anzeige zu aktualisieren:

if (items.get_count() == 0) {
  var itemCreateInfo = new SP.ListItemCreationInformation();
  var item = list.addItem(itemCreateInfo);
  item.set_item("Beitrag", postId);
  item.update();
  ctx.load(item);
  ctx.executeQueryAsync(function () {
    getAllPostLikes(postId);
  }, function () { }
  );
}

Einen Beitrag "Unliken"

Die Funktion zum Zurücknehmen eines Gefällt mir ist ähnlich aufgebaut. Der Unterschied besteht darin, daß ein gefundenes Element in der Likes-Liste gelöscht wird:

if (items.get_count() > 0) {
  var item = items.get_item(0);
  item.deleteObject();
  ctx.executeQueryAsync(function () {
    getAllPostLikes(postId);
  }, function () { }
  );
}

In die Seiten einbinden

In einer Blogwebsite werden die Beiträge auf verschiedenen Seiten dargestellt. Hier wird gezeigt, wie man die Gefällt mir Funktion in die Startseite default.aspx einbaut. Auf den anderen Seiten wie z.B. Category.aspx oder Date.aspx funktioniert das analog.

Die Darstellung der Blogbeiträge erfolgt immer durch ein XsltListViewWebPart und wir müssen dort eine Erweiterung im XSL einbauen und unsere Likes.js Datei referenzieren. Wir öffnen also die Website in SharePoint Designer, klicken links auf Alle Dateien und öffnen dann default.aspx im erweiterten Modus. Der erweiterte Modus ist notwendig, damit man Änderungen im Kopf der Seite machen kann.

Wir suchen den Platzhalter PlaceHolderAdditionalPageHead und fügen dort die Referenz auf unsere Scriptdatei ein:

<script type="text/javascript" src="/blog/Assets/Likes.js"></script>

Als nächstes müssen wir noch eine Ergänzung in die Ansicht der Beiträge einbauen. Damit man überhaupt an das XSL gelangt, markiert man das WebPart für die Beitragsanzeige, z.B. indem man einfach in der Entwurfsansicht draufklickt. Dann klickt man im Reiter Entwurf auf XSLT anpassen und dann auf Gesamte Ansicht anpassen. Dadurch wird das XSL in die aktuelle Seite kopiert und kann bearbeitet werden.

Man sucht sich jetzt eine geeignete Stelle für die Gefällt mir Funktion und markiert sie in der Entwurfsansicht. Wenn man jetzt in die Codeansicht umschaltet, ist der Teil im XSL markiert, der für die Darstellung des markierten Bereichs zuständig ist. Manchmal muß man das ein paar Mal machen, bis es wirklich klappt.

Wir wählen für die Demo die Stelle rechts neben der Anzahl der Kommentare. Man findet den Code dazu am einfachsten, wenn man das Wort Kommentar(e) markiert. Im Code sieht die Stelle so aus:

<xsl:value-of select="$thisNode/../@resource.wss.num_comments_blg_post"/>
</a>
</span>
</xsl:template>

Wir fügen unsere Erweiterung zwischen dem schließenden </span> und dem schließenden </xsl:template> ein:

<span id="PostLikesSpan{$thisNode/@ID}"> </span>
<script type="text/javascript">
  ExecuteOrDelayUntilScriptLoaded(getMyLikes<xsl:value-of select="$thisNode/@ID" />, &quot;sp.js&quot;);
  function getMyLikes<xsl:value-of select="$thisNode/@ID" /> () {
    getAllPostLikes(<xsl:value-of select="$thisNode/@ID" />);
  }
</script>

Damit wird zuerst das oben bereits erwähnte <span>-Element erzeugt, bei dem die id die eindeutige ID des Beitrags enthält. Anschließend wird eine JavaScript-Funktion erzeugt, die ebenfalls diese ID im Namen hat. Diese Funktion wird über ExecuteOrDelayUntilScriptLoaded aufgerufen. Dadurch wird dafür gesorgt, daß die für das Client Object Model notwendigen Scripte zur Verfügung stehen. Die aufgerufene Funktion ruft wiederum unsere getAllPostLikes-Funktion auf und übergibt die ID des Beitrags. Über ExecuteOrDelayUntilScriptLoaded kann man nur Funktionen ohne Parameter aufrufen, daher der Umweg.

Man muß jetzt noch den Beginn des <xsl:template> suchen und dort das ddwrt:ghost-Attribut entfernen. Zu diesem Thema habe ich hier etwas geschrieben.

Abschluß

Die hier ausschnittsweise gezeigte und erklärte JavaScript-Datei kann hier heruntergeladen werden. Der Download enthält auch eine deutsche Websitevorlage, aus der eine Blogwebsite mit eingebauter Gefällt mit Funktion erzeugt werden kann.

Die gezeigte Lösung bietet noch viel Raum für Erweiterungen. Man könnte z.B. auch die Kommentare mit der Gefällt mir Funktion versehen. Und man könnte nicht nur die Anzahl der Personen anzeigen, denen etwas gefällt, sondern auch wer diese Personen sind. Z.B. als Tooltip oder Popup, wenn man mit dem Mauszeiger darüber fährt. Das alles sollte sich durch erweitern der gezeigten Lösung relativ leicht machen lassen.

4 Gedanken zu “„Gefällt mir“ im SharePoint 2010 Blog

  1. Hallo Thomas,

    wie im Beitrag schon geschrieben, funktioniert das prinzipiell in jeder Seite, in der Beiträge angezeigt werden. Ich weiß gerade nicht, wie die Post.aspx aufgebaut ist und eventuell muß man sich die ID des angezeigten Beitrags aus der URL holen, aber im Prinzip geht es genauso.

    Viele Grüße
    Andi Fandrich

    Gefällt mir

  2. Hallo Andi,
    danke für die prompte Antwort. In meiner Umgebung werden die Like-It-Buttons immer nur sporadisch angezeigt. Nur bei mehrfachem Aktualisieren habe ich irgendwann alle auf dem Schirm. Schon mal gehört?

    Gefällt mir

Kommentar verfassen

Trage deine Daten unten ein oder klicke ein Icon um dich einzuloggen:

WordPress.com-Logo

Du kommentierst mit Deinem WordPress.com-Konto. Abmelden / Ändern )

Twitter-Bild

Du kommentierst mit Deinem Twitter-Konto. Abmelden / Ändern )

Facebook-Foto

Du kommentierst mit Deinem Facebook-Konto. Abmelden / Ändern )

Google+ Foto

Du kommentierst mit Deinem Google+-Konto. Abmelden / Ändern )

Verbinde mit %s