Update: GitHub repository rjksolutions/CoresightCandy · GitHub

 

Good morning, good afternoon, good evening everybody!

 

Welcome to the second part of my series of blog posts talking about what I am calling project "Coresight Candy".

The purpose is to add a lightweight framework on top of PI Coresight so that we can add some extensibility to the functionality. I hit some issues that I could only resolve in this way whilst we wait for the next generation display builder.

 

A few people have been asking for more details on the solution so I have been trying to write this second blog post a bit quicker, which means there may well be some typos in here somewhere.

 

Right then, down to business. What I was able to achieve was perfect for what I needed and meant that I could continue to use PI Coresight for my visualisation needs - primarily for the ProcessBook hosted displays.

 

 

I need to suffix my existing links with the Current Element from the URL of the Element Relative Display being viewed, but only for links where I am linking to another Element Relative Display. The first task is simple, identify those links which are in fact using symbol PBButton. PBButtons are rendered ultimately as an anchor, or a <a> link.

I knew I was going to need to find those type of links easy enough so decide to prefix all my PBButtons that link to another ERD with the text "ERDLink_". Now the name of a Symbol in ProcessBook will become the "id" attribute of the rendered HTML object so I know I'll be able to find all of "my links" later on. I upload the display and check the rendered HMTL to make sure I can manually find the symbols, which I can. Yay, go me.

 

 

Next came the head scratching for how exactly I would find the symbols. Out comes Google (or Bing if you prefer) and I run through some JQuery refreshers. Perfect, I'm now a JQuery expert in a matter of minutes...obviously my previous background in web development re-surfaced somewhat.

 

I need to be able to have parental control over the rendered displays so that I can keep an eye on them, and to teach them new things. By keeping an eye on them I can see when navigation occurs and react to that. In order to do that I need to create a new Html page that I can embed the regular PI Coresight page within, and I'll simply just use an IFrame to do that...

 

CoresightCandy.html:

<!DOCTYPE html>
<html>
<head>
    <title>Coresight Candy - by Rhys Kirk</title>
</head>
<body style="margin:0px;padding:0px;overflow:hidden">
    <div style="height:100%; width:100%">
        <iframe id="mainframe" src="" frameborder="0" style="overflow:hidden" seamless />
    </div>
</body>
</html>

 

Simple, right? However, that is just the start as what it enables me to do now is keep an eye on that IFrame and whatever happens within it. Mostly I need this for when the user navigates within the IFrame so that I can react to that, you'll learn more about that later.

For now I have to make some adjustments because Internet Explorer will not render the document in the right mode for HTML5 when I use an IFrame, so I need a meta tag in the head and I want to use JQuery later so I need to reference a JQuery script file from a Content Delivery Network...

 

CoresightCandy.html:

<!DOCTYPE html>
<html>
<head>
    <title>Coresight Candy - by Rhys Kirk</title>
    <meta http-equiv="x-ua-compatible" content="IE=Edge">
    <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
</head>
<body style="margin:0px;padding:0px;overflow:hidden">
    <div style="height:100%; width:100%">
        <iframe id="mainframe" src="" frameborder="0" style="overflow:hidden" seamless />
    </div>
</body>
</html>

 

Currently I haven't set the source for the IFrame because I want to know when I first point it at my starting PI Coresight display to kick off some functions. That is going to be one of the first things I'll have to do.

 

Let me just jump in at this point and say that I need to put CoresightCandy.hmtl in the PI Coresight web application so that I don't hit any cross domain security issue, everything will essentially be part of the same application...let's call it a bolt on.

 

 

Back to the initial PI Coresight display task. I'm going to need my JQuery skills now, which means I need pull in my .js file in order to run some code. Also, I want to track the URL to check for changes so I'm using a hidden input field for that. For ease of explanation I'm just going to put everything in the PI Coresight root folder.

 

CoresightCandy.html:

<!DOCTYPE html>
<html>
<head>
    <title>Coresight Candy - by Rhys Kirk</title>
    <meta http-equiv="x-ua-compatible" content="IE=Edge">
    <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
    <script src="http://webserver/Coresight/CoresightCandy-1.0.0.0.js" type="text/javascript"></script>
</head>
<body style="margin:0px;padding:0px;overflow:hidden">
<input type="hidden" id="mainframeURL" name="mainframeURL" value="default">
    <div style="height:100%; width:100%">
        <iframe id="mainframe" src="" frameborder="0" style="overflow:hidden" seamless />
    </div>
</body>
</html>

 

Now I can add some code. Note, this code path will essentially be able to be applied to any of my displays! And yes it does mean that users need to go to the CoresightCandy.html page rather than the regular PI Coresight link. This is on purpose in order to get this extra functionality and so far everything works perfectly fine in the 'embedded PI Coresight' as it does by going to the regular link.

Think of it like the red pill / blue pill question Morpheus asks Neo in 'The Matrix'; your users either stay in PI Coresight, or they go down the rabbit hole to Coresight Candy. Well not as dramatic as that but you get the idea, if you don't take the red pill you won't see the candy.

 

Sorry, I'm waffling again, back to it...

 

Here is my first part of my code for CoresightCandy-1.0.0.0.js:

$(document).ready(function () {
    var iframe = $('#mainframe'); var iframeURL = $('#mainframeURL');


    iframe.attr('src', 'http://webserver/Coresight/#/PBDisplays/123');
    iframe.attr('height', window.innerHeight);
    iframe.attr('width', window.innerWidth);
    iframe.load(function () {
  // Add code for when the IFrame is loaded for the 1st time
    });
});
$(window).resize(function () {
    $('#mainframe').css('height', window.innerHeight);
    $('#mainframe').css('width', window.innerWidth);
});

 

As you can see all I am doing here is waiting for the document/page to be ready and then running some code. I have a couple of refrences to my IFrame and the hidden input where I'll store the URL.

I point the IFrame at my starting display hosted in PI Coresight, and also adjust the height & width of the IFrame to that of my window - this is because the IFrame doesn't always get rendered to 100% of the width & height so I'll just do it myself to be sure. This will ensure PI Coresight always fills the screen and you can't tell it is within an IFrame. Also, I make sure the IFrame resizes as the window is resized.

 

What I also have there is a bind to the load event of the IFrame that only gets set when the src attribute changes and because navigation will occur inside the Iframe itself via links on the display then I am going to need keep an eye on changes.

 

In order to keep an eye on changes I will just do some simple checking every second to see if the URL of the IFrame is different to that which I have in my hidden field. If it is different then I'm going to initiate some code that I want to run on each display that is navigated to. Now my CoresightCandy-1.0.0.0.js looks like this:

$(document).ready(function () {
    var iframe = $('#mainframe'); var iframeURL = $('#mainframeURL');


    iframe.attr('src', 'http://webserver/Coresight/#/PBDisplays/123');
    iframe.attr('height', window.innerHeight);
    iframe.attr('width', window.innerWidth);
    iframe.load(function () {
  // Add code for when the IFrame is loaded for the 1st time
  setInterval(function () {
            var currentLocation = iframe.get(0).contentWindow.location.toString().toLowerCase();
            var currentElement = currentLocation.split("?");

            if (iframeURL.val() !== currentLocation) {
                // Most likely user navigated within the IFrame
                // Inject the Coresight Candy Display specific js

                // Set the location so we don't continually Inject and overdose
                iframeURL.val(currentLocation);
            }
        }, 1000);
    });
});
$(window).resize(function () {
    $('#mainframe').css('height', window.innerHeight);
    $('#mainframe').css('width', window.innerWidth);
});

 

Now I have a 1 second timer to check if the user has navigated within the IFrame, and it will give me a code path that I can go down when they do. It is very simple, check if the URL has changed.

However, there is the ProcessBook side of PI Coresight and the Silverlight side. I'm only really interested in the ProcessBook displays...for now!

$(document).ready(function () {
    var iframe = $('#mainframe'); var iframeURL = $('#mainframeURL');

    iframe.attr('src', 'http://webserver/Coresight/#/PBDisplays/123');
    iframe.attr('height', window.innerHeight);
    iframe.attr('width', window.innerWidth);
    iframe.load(function () {
  // Add code for when the IFrame is loaded for the 1st time
  setInterval(function () {
            var currentLocation = iframe.get(0).contentWindow.location.toString().toLowerCase();
            var currentElement = currentLocation.split("?");


            if (iframeURL.val() !== currentLocation) {
                // Most likely user navigated within the IFrame
                // Inject the Coresight Candy Display specific js


                 // Only interested in ProcessBook displays (for now!)
                if (currentLocation.toLowerCase().indexOf('pbdisplays') >= 0) {
                    // Anything that you want to perform on each ProcessBook display
                    // ...
                }


                // Set the location so we don't continually Inject and overdose
                iframeURL.val(currentLocation);
            }
        }, 1000);
    });
});
$(window).resize(function () {
    $('#mainframe').css('height', window.innerHeight);
    $('#mainframe').css('width', window.innerWidth);
});

 

I know that when you navigate to a ProcessBook display that the URL has "PBDisplays" in it. So I check for that to make sure I am dealing with a ProcessBook display hosted in PI Coresight. Awesome.

 

Now I can start to think about solving my original problem of side-stepping from one ERD to another ERD in PI Coresight. Remember at the beginning of this post I said I prefixed the symbols with "ERDLink_", well..

$(document).ready(function () {
    var iframe = $('#mainframe'); var iframeURL = $('#mainframeURL');

    iframe.attr('src', 'http://webserver/Coresight/#/PBDisplays/123');
    iframe.attr('height', window.innerHeight);
    iframe.attr('width', window.innerWidth);
    iframe.load(function () {
  // Add code for when the IFrame is loaded for the 1st time
  setInterval(function () {
            var currentLocation = iframe.get(0).contentWindow.location.toString().toLowerCase();
            var currentElement = currentLocation.split("?");

            if (iframeURL.val() !== currentLocation) {
                // Most likely user navigated within the IFrame
                // Inject the Coresight Candy Display specific js

                 // Only interested in ProcessBook displays (for now!)
                if (currentLocation.toLowerCase().indexOf('pbdisplays') >= 0) {
                    // 1. Check for Element Relative Display
                    // 2. Find PBButtons with the prefix "erdlink_"
                    // 3. Add suffix of the current element from the querystring
                    if (currentLocation.indexOf('currentelement=') >= 0) {
                        // Find the anchors
                        var pbButtonLinks = iframe.contents().find('a[*|xlink]').toArray();
                        $.each(pbButtonLinks, function (index, element) { // I've already prefixed the names of the PBButtons with "ERDLINK_" so I know to append the CurrentElement
                            // Make sure it doesn't already have the CurrentElement= set
                        if ($(element).attr('id').indexOf('ERDLINK_') >= 0)
                        {
                            if ($(element).attr('xlink:href').indexOf(currentElement[1]) < 0) {
                                $(element).attr('xlink:href', $(element).attr('xlink:href') + '?' + currentElement[1]);
                            }
                        }
                        });
                    }
                }

                // Set the location so we don't continually Inject and overdose
                iframeURL.val(currentLocation);
            }
        }, 1000);
    });
});
$(window).resize(function () {
    $('#mainframe').css('height', window.innerHeight);
    $('#mainframe').css('width', window.innerWidth);
});

 

 

What I have done now is to check if the URL contains "CurrentElement=" to know if the display being viewed is an ERD with context already set. If it is then it means that I can use that context to update my side-step links.

To find PBButtons that are rendered as an anchor link I need to search the contents of the IFrame for all links in a specific format that they are rendered by the PI Coresight conversion. Once I have those links I can loop through them and check to see if they already have the CurrentElement part of the URL set, if not then append the CurrentElement from the current display URL to the link. It works! I've tested it on IE and Chrome and it works great - so long as I take the red pill!

 

Think about this for a minute. I can alter the rendered HTML output from my ProcessBook display conversion so that I can inject some value-added functionality without fundamentally changing PI Coresight. What's better is users don't have to use this functionality, they can still use PI Coresight as is.

 

Now think some more about this. I've only scratched the surface, I can add all sorts of value-added functionality to enrich the user experience with my hosted PI ProcessBook displays!

 

This is why I think we need project "Coresight Candy". As a community we can aggresively add new functionality. In fact I've already built a method for injecting application specific js files into the PI Coresight displays so that I have some modern old school ProcessBook events...

 

Sneak peak at Part 3 of my Coresight Candy blog posts:

$(document).ready(function () {
    // Bind click event
    $(document).on('click', 'body', function Display_Click(event) {
        // Check if a new object is selected
        if (event.target != null)
        {
            var xPos = event.pageX; var yPos = event.pageY;
            Display_SelectionChange(event.target);
        }
    });


    // Set up the 5 second timer for Display_DataUpdate()
    setInterval(Display_DataUpdate, 5000);


    // Trigger the Display Open event for initialising stuff
    Display_Open();
});

 

That means in part 3 I'll show you:

- How inject display specific js files

- How to make use of the Display_DataUpdate function

- How to play sounds and some other cool stuff

- How to parse the ProcessBook Symbols from the rendered HTML

 

 

Back in a few days with part 3. Please like & share this blog post if you want to see part 3.

 

 

Have you all seen enough to participate in such a project?