Pages

Friday, November 27, 2015

View PDF files in a ShadowBox pop-up window in the Essential Theme on your Moodle 3.0 site (works on all other themes as well!)

Source: Jens Peter Olesen,
Pixabay, CC0 Public Domain
Design. It's all about design. Today's post is  a sequel to my earlier post on the same subject. In that post, I enabled my PDF and ODF files to open in a Lightbox-like window, when clicked upon, in three themes: Evolve-D, Academi and BCU. I had used FancyBox and ViewerJS to achieve this. I couldn't get Fancybox to work with other themes.

The great news is that I have since discovered that ShadowBox (in place of FancyBox) works on Essential and Moodle 3.2's Boost theme. The installation is much easier, and I managed to optimise the look and feel of ShadowBox by tweaking its original CSS file.

Important Disclaimer and warning:
If you find that your Moodle version and Moodle theme causes your PDF file to load v-e-r-y slowly, or if your Google Chrome displays the "Out of memory" or "Aw snap" message,  then try using the FancyBox method that I blogged here instead.

Learning Outcome
At the end of this post, you will be able to hack your beloved and sacred Moodle site so that PDF files will open as pop-ups. That's all. Nothing earth-shattering. However, I strongly believe that my post today is going to touch lives and make a difference in your Moodle experience (XP). As well as your teachers' and students' Moodle XP. Read on!




The course page
before I left-click a PDF file

Notice the PDF file resources that I drag and dropped into the Moodle 3.0 coursepage? Well, their display settings are the default "Automatic". How to use? With Google Chrome, click on the red PDF icon to download a file. Click on the file name link, e.g. "Lady Liberty (95 Kb)", to open the PDF contents inside a pop-up. That's a Frankie Kam innovation and a Moodle First.

The intermediate smaller window
opens seconds after a PDF file is clicked

The end result.
IMHO, very nice.

Coursepage link Site: http://cefl4u.org/m30/course/view.php?id=2
Username: sippycup
Password:  Happy_go_lucky123
You may change the user's theme at any time.

The best thing about this is it works on multiple platforms - iPad, iPhone, Android, PC, Linux, etc. I think this is ART. I'm lovin' it.


Besides Essential theme, it also works with ALL other themes I have tested. Here is a long list of Moodle.org themes that I have installed and tested ShadowBox on:

Aardvark
Academi
Archaius
BCU
Campus
Clean
Contemporary
Crisp
Dynamic
Educacionbe
Eguru
Elegance
Essential
Evolve-D
More
Pioneer
Rocket
Roshnilite
Simple
Shoehorn
Squared


How to install In 11 Steps:

STEP 1. Download this zip file.
STEP 2. Extract the zip file. This is the structure of subfolders when the zip file is extracted.


The pdf.js-gh-pages subfolder stores the PDF.js library. This library is responsible for the PDF viewer that will open your PDF files in all their glory. That should go into your web server's Moodle folder.

The theme folder mirrors your Moodle theme folder. The three subfolders  javascript, shadowboxpix and style need to be uploaded to your theme name's folder. For example, if your theme's name is Essential, then the subfolder javascript is to be uploaded to /public_html/Moodle/theme/essential.

The ViewerJS subfolder stores the ViewerJS library. That should go into your web server's Moodle folder. The ViewerJS library is used to open Open Document Format files.


STEP 3. Upload the pdf.js-gh-pages subfolder to your Moodle folder. My Moodle folder is m30. Yours will differ. This step is necessary if you want to open PDF files in a ShadowBox window.



STEP 4. Upload the ViewerJS subfolder to your Moodle folder. My Moodle folder is m30. Yours will differ. This step is necessary if you want to open Open Document Format files in a ShadowBox window. If you are going to deal solely with PDF files, then Step 4 is not necessary.




STEP 5
. Upload the style folder into your theme's folder. The file is:



STEP 6. Upload the javascript folder into your theme's folder. The files are:


STEP 7. Upload the shadowboxpix folder into your theme's folder. The files are:



So, here's what my Essential theme folder looks like after Steps 5,6 and 7:




STEP 8
Edit line 86 of shadowbox.css


Change the URL to your website's Moodle. For example, if your website is at http://www.mysparky.com, and your Moodle files are in the folder /public_html/moodle, then line 86 should read as:

background: url("http://www.mysparky.com/moodle/theme/essential/shadowboxpix/shadowbox-icons.png") no-repeat;


STEP 9
Edit config.php so that it will access the Shadowbox CSS and JS files.

For the Essential theme, add these line of code:
$THEME->sheets[] = 'shadowbox';
and insert the code 'shadowbox', 'myShadowbox' inside this line:
$THEME->javascripts_footer = array('essential', 'coloursswitcher', 'shadowbox', 'myShadowbox');

For other themes, do it this way:

If the $THEME->sheets or $THEME->javascripts or $THEME->javascripts_footer code already exist inside the config.php file, then insert the code in blue:
$THEME->sheets = array('shadowbox');
$THEME->javascripts = array('shadowbox','myShadowbox');
-or-
$THEME->javascripts_footer = array('shadowbox','myShadowbox');


STEP 10
Edit course_section_cm_name function inside course/renderer.php file. Here's what my MODIFIED course/renderer.php file looks like. Sorry for the code headache. It's all GREEK to me. To help you out a bit, the pink background colored code is my secret brew. Not-so secret now. The function is long and windy because there is code to specifically handle Google Chrome, Firefox, and Safari iOS browser usage.

public function course_section_cm_name(cm_info $mod, $displayoptions = array())
{
$output = '';
if (!$mod->uservisible && empty($mod->availableinfo))
{

// nothing to be displayed to the user

return $output;
}

$url = $mod->url;
if (!$url)
{
return $output;
}

// Accessibility: for files get description via icon, this is very ugly hack!

$instancename = $mod->get_formatted_name();
$altname = $mod->modfullname;

// Avoid unnecessary duplication: if e.g. a forum name already
// includes the word forum (or Forum, etc) then it is unhelpful
// to include that in the accessible description that is added.

if (false !== strpos(core_text::strtolower($instancename) , core_text::strtolower($altname)))
{
$altname = '';
}

// File type after name, for alphabetic lists (screen reader).

if ($altname)
{
$altname = get_accesshide(' ' . $altname);
}

// For items which are hidden but available to current user
// ($mod->uservisible), we show those as dimmed only if the user has
// viewhiddenactivities, so that teachers see 'items which might not
// be available to some students' dimmed but students do not see 'item
// which is actually available to current student' dimmed.

$linkclasses = '';
$accesstext = '';
$textclasses = '';
if ($mod->uservisible)
{
$conditionalhidden = $this->is_cm_conditionally_hidden($mod);
$accessiblebutdim = (!$mod->visible || $conditionalhidden) && has_capability('moodle/course:viewhiddenactivities', $mod->context);
if ($accessiblebutdim)
{
$linkclasses.= ' dimmed';
$textclasses.= ' dimmed_text';
if ($conditionalhidden)
{
$linkclasses.= ' conditionalhidden';
$textclasses.= ' conditionalhidden';
}

// Show accessibility note only if user can access the module himself.

$accesstext = get_accesshide(get_string('hiddenfromstudents') . ':' . $mod->modfullname);
}
}
else
{
$linkclasses.= ' dimmed';
$textclasses.= ' dimmed_text';
}

// Get on-click attribute value if specified and decode the onclick - it
// has already been encoded for display (puke).

$onclick = htmlspecialchars_decode($mod->onclick, ENT_QUOTES);
$groupinglabel = $mod->get_grouping_label($textclasses);

// Display link itself.

$activitylink = html_writer::empty_tag('img', array(
'src' => $mod->get_icon_url() ,
'class' => 'iconlarge activityicon',
'alt' => ' ',
'role' => 'presentation'
)) . $accesstext . html_writer::tag('span', $instancename . $altname, array(
'class' => 'instancename'
));
$filename = $url;
if ($mod->uservisible)
{
/* Start of Frankie code */

// print_object($activitylink);

if ((strpos($activitylink, 'writer-24') !== false) || (strpos($activitylink, 'calc-24') !== false) || (strpos($activitylink, 'impress-24') !== false))
{
$url = str_replace("/m30/", "/m30/ViewerJS/#../", $url);
$output.= html_writer::link($url, $activitylink, array( /*'title'=>'Click text to pop-up PDF',*/
'rel' => 'shadowbox[Mixed]' /*,'onclick' => $onclick*/
)) . $groupinglabel;
/*
$output .= html_writer::link($url, $activitylink,
array('data-fancybox-type' => 'iframe',  'class' => 'fancybox', 'onclick' => $onclick)) .
$groupinglabel;
*/
}
else
if (strpos($activitylink, 'pdf-24') !== false)
{
/*$browser = $_SERVER['HTTP_USER_AGENT'];
$chrome = '/Chrome/';
$firefox = '/Firefox/';
$ie = '/MSIE/';
if (preg_match($firefox, $browser))
*/
if (core_useragent::is_chrome())
{
/*This code replaces this: http://cefl4u.org/teach/pdf.js-gh-pages/web/viewer.html?file=http://cefl4u.org/teach/mod/resource/view.php%3Fid=44
with this: http://cefl4u.org/teach/pdf.js-gh-pages/web/viewer.html?file=http%3A%2F%2Fcefl4u%2Eorg%2Fteach%2Fmod%2Fresource%2Fview%2Ephp%3Fid%3D44
%3A     :     Colon
%2F     /     Solidus (slash)
%2E     .     Period (fullstop)
%3D     =     Equals sign
%3F     ?     Question mark
*/
global $CFG;
$newurl = str_replace(':', '%3A', $url);
$newurl = str_replace('/', '%2F', $newurl);
$newurl = str_replace('.', '%2E', $newurl);
$newurl = str_replace('?', '%3F', $newurl);
$newurl = str_replace('=', '%3D', $newurl);
$newurl = $CFG->wwwroot . '/pdf.js-gh-pages/web/viewer.html?file=' . $newurl;
$activitylink = html_writer::empty_tag('img', array(
'src' => $mod->get_icon_url() ,
'class' => 'iconlarge activityicon',
'alt' => ' ',
'role' => 'presentation'
));

// So hard to just add the word download but here it is!
// $output .=  str_replace('=""','',html_writer::link($url, $activitylink, str_replace('=""','',array('download'=>'','title'=>'Click icon to download'))));

$output.= str_replace('=""', '', html_writer::link($url, $activitylink, array(
'download' => '',
'title' => 'Click icon to download'
)));
$instancename = html_writer::start_span('instancename') . $instancename . html_writer::start_span('accesshide ') . 'File' . html_writer::end_span() . html_writer::end_span();

// ShadowBox

$output.= html_writer::link($newurl, $instancename, array(
'title' => 'Click text to pop-up PDF',
'rel' => 'shadowbox[Mixed]',
'onclick' => $onclick
)) . $groupinglabel;
}
else
if (core_useragent::is_firefox())
{
global $CFG;
$newurl = str_replace(':', '%3A', $url);
$newurl = str_replace('/', '%2F', $newurl);
$newurl = str_replace('.', '%2E', $newurl);
$newurl = str_replace('?', '%3F', $newurl);
$newurl = str_replace('=', '%3D', $newurl);
$newurl = $CFG->wwwroot . '/pdf.js-gh-pages/web/viewer.html?file=' . $newurl;
$activitylink = html_writer::empty_tag('img', array(
'src' => $mod->get_icon_url() ,
'class' => 'iconlarge activityicon',
'alt' => ' ',
'role' => 'presentation'
));

// So hard to just add the word download but here it is!
// $output .=  str_replace('=""','',html_writer::link($url, $activitylink, str_replace('=""','',array('download'=>'','title'=>'Click icon to download'))));

$output.= str_replace('=""', '', html_writer::link($url, $activitylink, array(
'download' => '',
'title' => 'Right-click icon to download'
)));
$instancename = html_writer::start_span('instancename') . $instancename . html_writer::start_span('accesshide ') . 'File' . html_writer::end_span() . html_writer::end_span();

// ShadowBox

$output.= html_writer::link($newurl, $instancename, array(
'title' => 'Click text to pop-up PDF',
'rel' => 'shadowbox[Mixed]' /*,'onclick' => $onclick*/
)) . $groupinglabel;
}
else
if (core_useragent::is_safari_ios())
{
global $CFG;
$newurl = str_replace(':', '%3A', $url);
$newurl = str_replace('/', '%2F', $newurl);
$newurl = str_replace('.', '%2E', $newurl);
$newurl = str_replace('?', '%3F', $newurl);
$newurl = str_replace('=', '%3D', $newurl);
$newurl = $CFG->wwwroot . '/pdf.js-gh-pages/web/viewer.html?file=' . $newurl;

// ShadowBox

$output.= html_writer::link($newurl, $activitylink, array(
'title' => 'Click text to  
       pop-up PDF',
'rel' => 'shadowbox[Mixed]',
'onclick' => $onclick
)) . $groupinglabel;
}
else
if (core_useragent::is_ie())
{ /* Opera, and ALL others!!! */
global $CFG;
$newurl = str_replace(':', '%3A', $url);
$newurl = str_replace('/', '%2F', $newurl);
$newurl = str_replace('.', '%2E', $newurl);
$newurl = str_replace('?', '%3F', $newurl);
$newurl = str_replace('=', '%3D', $newurl);
$newurl = $CFG->wwwroot . '/pdf.js-gh-pages/web/viewer.html?file=' . $newurl;

// ShadowBox

$output.= html_writer::link($newurl, $activitylink, array(
'title' => 'Click text to pop-up PDF',
'rel' => 'shadowbox[Mixed]',
'onclick' => $onclick
)) . $groupinglabel;
}
else
{ /* Opera, and ALL others!!! */
global $CFG;
$newurl = str_replace(':', '%3A', $url);
$newurl = str_replace('/', '%2F', $newurl);
$newurl = str_replace('.', '%2E', $newurl);
$newurl = str_replace('?', '%3F', $newurl);
$newurl = str_replace('=', '%3D', $newurl);
$newurl = $CFG->wwwroot . '/pdf.js-gh-pages/web/viewer.html?file=' . $newurl;

// ShadowBox

$output.= html_writer::link($newurl, $activitylink, array(
'title' => 'Click text to pop-up PDF',
'rel' => 'shadowbox[Mixed]',
'onclick' => $onclick
)) . $groupinglabel;
}
}
else
{
$output.= html_writer::link($url, $activitylink, array(
'class' => $linkclasses,
'onclick' => $onclick
)) . $groupinglabel;
}

/* End of Frankie code */
}
else
{

// We may be displaying this just in order to show information
// about visibility, without the actual link ($mod->uservisible)

$output.= html_writer::tag('div', $activitylink, array(
'class' => $textclasses
)) . $groupinglabel;
}

return $output;
}



Please refer to the files modified_course_renderer.php and original_m30_course_renderer.php inside the zip file. Both are Moodle 3.0 files. You can see the diffchecker.com difference by clicking here.

If you are using Moodle 3.0, then rename modified_course_renderer.php to  renderer.php and upload it to your /moodle/course/ folder. E.g., /public_html/moodle/course



STEP 11
If you are going to drag and drop Open Document Fornat (ODF) files to your coursepage, then please edit line 810 where it says:
$url = str_replace("/m30/","/m30/ViewerJS/#../", $url);
Change the m30 to whatever is accurate, reflecting your website URL. For my case, my Moodle files are stored at /public_html/m30 (LAMPP system).

One final screenshot. Here's an OpenOffice / LibreOffice / ODF file opening inside a ShadowBox window on my Moodle site.



Cor...isn't that a sight for sore eyes?

In summary, what have I achieved? I have created a work of art. It allows you to open and view PDF and ODF files without leaving your beloved Moodle course page. This is a step UP in Moodle usability. If your teacher is using Moodle as a glorified PDF file repository, he or she is going to thank you for it (I think). I have managed to get PDF files to open consistently on ALL major platforms. Now iPad and smartphone users can rejoice. And this solution is FREE for you to use.

I hope this helps. If you managed to get it to work and you are happy with this HACK, please drop me a comment below. Oh yeah, and please click the Like link. I'd like to achieve a target of at least 15 Likes. We shall see...

For future enhancement. I personally don't like hacking core code. It gives me a maintenance headache. However for now this is what I have to offer the Moodle community. If I ever get around to overriding the course renderer, then I will make the change and my life will be so much happier. If you can overriding the course renderer then please share with me and the Moodle community. After all, I'm just a poor, starving programmer in a still-developing country in South East Asia.



The inspiration for this blog post, where I integrate ShadowBox with Moodle Moodle, came from the book entitled "JavaScript Cookbook". Specifically pages 147 to 160, from "Chapter 9: Integrating External Libraries".



This excellent 2011 book is written by Alistair Hole. You can buy it from Packt Publishing or from Amazon.com. I hope that Alistair will update it for 2016. For me, some of the best inspirational ideas comes from the printed page. All hail the Book!



Finally, I want to give a shoutout and thanks to David Choi and Mary Evans for this Moodle.org post which helped me very much to understand how to use Shadowbox in Moodle.

Regards
Frankie Kam
Malaysia
Saturday 28th November 2015, 1:12pm.



UPDATE: 14TH APRIL 2017

Great news. I managed to get it to work on my Moodle 3.2 site running on the Boost theme. ;-)

In your /theme/boost/config.php, instead of using the code which I blogged about,
$THEME->sheets = []; /* Don't use this! */
use this code:
$THEME->sheets = ['shadowbox']; /* Use THIS code instead! */

Here's a video of me setting up ShadowBox pop-up window on my Moodle 3.2 server, using Boost theme.



Click here https://goo.gl/U4pfDw to download my Boost theme's config.php and my site's /course/renderer.php to see my code. The Google Drive link contains:
(1) The php file /theme/boost/config.php
(2) The php file /course/renderer.php (my modified file)
(3) The php file /course/renderer.bak.php (my original stock file)
(4) The zip file boost.zip (I zipped up my entire /theme/boost folder for you)


APPENDIX 

ShadowBox/Moodle related links:
http://sites.middlebury.edu/moodle/2009/10/30/shadowbox-for-moodle/
https://moodle.org/mod/forum/discuss.php?d=322120
https://moodle.org/mod/forum/discuss.php?d=258455
https://moodle.org/mod/forum/discuss.php?d=217185
https://moodle.org/mod/forum/discuss.php?d=203583
https://moodle.org/mod/forum/discuss.php?d=227866
https://moodle.org/mod/forum/discuss.php?d=194263
https://moodle.org/mod/forum/discuss.php?d=181320
https://moodle.org/mod/forum/discuss.php?d=123065
https://www.youtube.com/watch?v=ZmLjp6onLGQ

Lightbox/Moodle related links:
https://moodle.org/mod/forum/discuss.php?d=205810
http://cogpsy.info/courses/mod/forum/discuss.php?d=3
https://elearningshow.wordpress.com/2010/10/30/improved-moodle-navigation/


If you like this post or site
a small donation would be nice but would last only a day,
otherwise leaving a comment (or a compliment) below will last me a month!

Ratings and Recommendations by outbrain