This was a triumph.
I'm making a note here: HUGE SUCCESS.

Search This Blog

Wednesday, February 12, 2014

How to have a discussion board web part with modal dialogs and auto-refreshing content in SharePoint 2013

Imagine you added a discussion board as a web part to a page. Whenever you want to add a new discussion, by default it will always open in a new page rather than in a modal dialog (even if you ticked the "Display forms in a modal dialog" option under "Advanced settings" of the discussion board). As a matter of fact, existing discussions also open in new pages.

For my end users, this is annoying since they will lose track of the page they were originally on. I made it so that they will always know on what page they are, by highlighting the link of the current page in the term-driven subsite navigation. And when they want to create a new discussion or want to look at an existing one, that term-driven subsite navigation can't tell you the path of the "AllItems.aspx" page your user has ended on.

So! In order to stick to the page that has the discussion board web part, I had to write a small script.

How do we create a new discussion or open an existing discussion in a dialog rather than on a new page?

You'll need two scripts for this: one that runs only on the page that has the discussion board web part, and one that is referenced on the master page (so that it will always run, on any page, regardless whether it has a discussion board or not).

I named the first script "discussion-board.js" and gave it the following code. Comments have been added to the code to further explain it.
// When called, this function opens the dialog.
function openDialog(pUrl) { 
   var options = {
      url : pUrl,
      dialogReturnValueCallback: OnDialogClose
   };
   SP.SOD.execute('sp.ui.dialog.js', 'SP.UI.ModalDialog.showModalDialog', 
    options);
}

// When the user closes the dialog by either pressing OK when adding a new 
// item, by clicking the cancel button or by closing it with the X on the 
// top right corner, this function will run.
function OnDialogClose(dialogResult, returnValue) {
   // The line below will refresh the content of the web part, by acting as 
   // if the refresh button was clicked. 
   $('.ms-comm-refreshIcon').trigger('click');
   // The line below will run the clickMe() function, I also added a timeout
   // because I noticed that it sometimes doesn't run properly. This timeout 
   // should make sure that the function will always run. 
   clickMe();
   setTimeout(function() { 
      clickMe();
   }, 500);
}

// When called, this function makes sure that a new discussion or an existing
// discussion is opened in a modal dialog instead of on a new page.
function clickMe() {
   // The lines below replaces the value of the default onclick and href
   // attributes so that it won't open on a new page, but in a dialog. 
   $('a[href*="NewForm.aspx"]').each(function() {
      $(this).attr('onclick', 'openDialog("' +  $(this).attr('href') + '")');
      $(this).attr('href','javascript:void(0)');
   });
   // Same for the following lines, when the user is on the page that 
   // contains the discussion board web part, we want the existing 
   // discussions to be displayed in a dialog as well rather than on a new 
   // page. 
   $('a[href*="Forum.aspx"]').each(function() {
      $(this).attr('onclick', 'openDialog("' +  $(this).attr('href') + '")');
      $(this).attr('href','javascript:void(0)');
   });
}

// When the window first loads, we want to be sure that the discussions are 
// already set to open in a dialog. So we will run the clickMe() function on
// load, and set the timeout again just to be sure (in my case, it doesn't 
// work without the timeout).
window.onload = function () {
   clickMe();
   setTimeout(function() { 
      clickMe();
   }, 500);
}; 

// The lines below are needed as well, because when a user changes the view 
// of the web part (to for example "Recent" or "My discussions"), then the
// values of the attributes  href and onclick get back their original value.
// We don't want a user to see the discussions on a new page, so we once 
// again set it so that the clickMe() function runs as soon as the user 
// clicks anywhere inside the content div (which in my case, has "content" 
// for its ID. 
$("#content").click(function() {
   clickMe();
   setTimeout(function() {
      clickMe();
   }, 500);
});

So that's the first script that you'll need. Include this script to the page that contains the discussion board web part. Do so by adding a script editor web part at the bottom of the page and add the following code tot it:
<script src="/Style%20Library/Scripts/discussion-board.js" 
 type="text/javascript"></script>

Please do note that your path may be different, so change it if necessary.

And now for the script that has to have a reference on the master page. I already have a file called "scripts.js" which runs on every page, so I just added the following code to that script:
var ref = document.referrer; 
var url = window.location.pathname; 
$(document).ready(function(){
   // If the current url ends with "AllItems.aspx" and the previous url 
   // contained "IsDlg=", stating that it was a dialog, then run the 
   // following code. 
   if ( (url.indexOf('AllItems.aspx') > -1 && ref.indexOf('IsDlg=') > -1) ) {
      // The line below will close the dialog. 
   SP.UI.ModalDialog.commonModalDialogClose(SP.UI.DialogResult.Cancel);
   }
   else {
      // Do nothing.
   }
});

The reason why we have to state that the dialog has be closed, is because when you delete a discussion through a modal dialog, it will show you the AllItems.aspx page inside the dialog instead of returning to the original page (in my case, Forum.aspx). So to fix this, I check if the dialog came from a page that had "IsDlg=" in the url, and if the url of the dialog is currently "AllItems.aspx" then that must mean that a discussion was deleted. So then we can close the dialog.

Check if your second script is added to your master page. I use a HTML master page so my reference looks like this:
<!--SPM:<SharePoint:ScriptLink language="javascript" OnDemand="false"
  name="~sitecollection/Style Library/Scripts/scripts.js"
  ID="scriptLink4" runat="server" Localizable="false"/>-->

Again, do note that your path may be different, so change it where necessary.

If you did everything as I explained it here, you will now have a discussion board web app on a page that will:
  • open all existing discussions in a modal dialog;
  • open all new discussions in a modal dialog;
  • automatically refresh the content of the web part whenever a new discussion is adde;
  • automatically refresh the content of the web part whenever an existing discussion has been edited or deleted;
  • returns to the page with the web part and closes the dialog after deleting a discussion.

As always, if you have any questions or need any help do let me know by placing a comment!
This post can also be found as an answer on SharePoint StackExchange.

Tuesday, January 28, 2014

IT'S OVER ONE THOUSAAAAAAAAAAND!!!!

My blog just got over one thousand views!!! 

 

Hurray!!! 

 

Confetti for everyone!!!

 

I probably just viewed my own blog so many times that I'm now up to one thousand. Although I did set it so that my own views wouldn't count. But meh, /care, one thousand views!

Also, someone actually clicked on the advertisement box on the right. Which gave me a very tiny small amount of eurocents, but still money nonetheless!
So if you happen to stumble upon this post, could you like... Just... Do a tiny click on that advertisement box on your right? Yeah. That one, right underneath the "Subscribe to" thingy. It won't cost you a thing, it won't do any harm either, but it will give me a (once again) very tiny small amount of money, which in return makes me a very tiny bit more happier each time someone clicks it.

And who knows, it might even be interesting! I have no idea what the advertisement box tells you, it is supposed to show you advertisements that are relevant to whatever business you searched for on Google. In my case it shows me something in French about becoming a florist, although I have absolutely no idea why it would show something like that since I never even searched for flowers online. Peculiar.


I think I'll keep making posts like these every time my views increase by a thousand. Eventually, I'll get to 9000. And you should know what that means. Oh boy, do I look forward to that moment... That will be one heck of a post.

Friday, January 24, 2014

My new favourite syntax highlighter: Prism!

The past few days, I noticed some parts of my code were missing in the Syntax Highlighter and that sometimes, the code wasn't shown in the highlighter at all (it was just dull text). When I edited the affected blog posts however, the missing pieces of code were there and so were the elements for the highlighter. So I figured it might have had to do something with the Syntax Highlighter.

I decided to search for a new highlighter, and came across Prism. This is a very neat highlighter, it is lightweight and extensible, offers six different styles, has various plugins and is supported by most browsers.
For my blog, I'm using the Prism highlighter with the Okaidia theme and I also included the Line Numbers plugin. 

How to use Prism on Blogger/Blogspot

First of all, I discovered that I couldn't host JavaScript files on Blogger/Blogspot. Secondly, I didn't like the idea of hosting scripts elsewhere. I tried hosting it on Google Drive and that sort of worked, but still I wanted to find an easier way.
So I checked the source of prismjs.com and its pages, searched for the scripts and found them there. Not quite sure if I'm allowed to do that... But it was easier for me and I think those will always be the most up-to-date scripts. 
This is the core JavaScript code of Prism. 
This is the JavaScript code for the line numbers plugin.
This is the CSS code for the line numbers plugin.
And this is the CSS code for the Okaidia theme.

I'm not going to provide the link to all the scripts, plugins and themes for Prism since you can probably find most of them yourself by changing the URLs a bit or by doing a search through the source code of the site. 

Now that we have the necessary files, we need to include them to the template. 
To add them, you need to edit the HTML of your template. You can do so by going to the settings of your blog, select "Template" from the left hand side navigation, and then choose "Edit HTML". 

Right before the </head> tag, you paste the following code (source of the scripts may be different depending on which plugins or styles you use):
<script src='http://prismjs.com/prism.js' type='text/javascript'/>
<script src='http://prismjs.com/plugins/line-numbers/prism-line-numbers.js' 
type='text/javascript'/>
<link 
href='http://prismjs.com/themes/prism-okaidia.css' rel='stylesheet'/>
<link 
href='http://prismjs.com/plugins/line-numbers/prism-line-numbers.css' 
rel='stylesheet'/>

Now, when you create a new blog post and you wish to add code to it, you can use the following to highlight your code:
<pre class="line-numbers"><code class="language-javascript">
// Your code here.
</code></pre>

Do note that depending on which plugins you have, you can change the class in the pre tag. You can read more about the different plugins and how to use them here. Also, depending on what kind of code you will be highlighting, you can change the class in the code tag.
To highlight CSS, use language-css class for the code tag.
To highlight HTML, use language-markup class for the code tag.
To highlight JavaScript, use language-javascript class for the code tag.

Got code that's not showing up? No problem. We can fix this. 

I noticed that if you want to use HTML code inside JavaScript (or even script tags in JavaScript), the code will likely not show. I think this might be related to HTML being stripped off. For example, see the following code:
var site = "www.prismjs.com";
var title = "PrismJS";
var text = "" + title + "";

Noticed anything strange? I surely did. I added an anchor tag to that code, yet it is not showing.
Let me show you the same code, but now I changed the "less than" character ("<") with "&lt;" and this is the result:
var site = "www.prismjs.com";
var title = "PrismJS";
var text = "<a href='" + site + "'>" + title + "</a>";

Bam! Suddenly the code works. Just to give you an idea, this is how it looks like (and how I write it in order for it to show up properly) when I edit the blog post with the code:
var site = "www.prismjs.com";
var title = "PrismJS";
var text = "&lt;a href='" + site + "'>" + title + "&lt;/a>";

So when you use HTML inside JavaScript, or even when you use "<script></script>" tags or regular expressions, always make sure to replace the "less than" character with "<". That way, no code will be missing from the highlighter and visitors will be able to correctly copy and use your code.

All done! Let's start making more blog posts now!

Now that I finally have a syntax highlighter that does what I want it to do, I can continue writing blog posts about my SharePoint experiences without having to worry about visitors not seeing my code. ^_^

I would like to thank Lea Verou and all these people who created Prism, without them I would probably still struggle with highlighting stuff. Please do check out Prism, I highly recommend it for Blogger/Blogspot or any other site.