Posted in: Javascript

How to get Angular controller and scope from an element using a jQuery selector

Posted on June 22, 2015 by Michael Roma

The following shows how to get an Angular controller and it's scope from an element using a jQuery selector.

Here is an example Angular controller:

<div ng-controller="ProfileSignupController">
...
</div>

To get the controller, use the following:

// get the controller by controller name
var controller = angular.element("[ng-controller='" + name + "']");

Now since you have the controller, you now have access to the scope:

var scope = controller.scope();

Track YouTube Video Events and Checkpoints in Google Analytics using jQuery

Posted on March 9, 2014 by Michael Roma

This post shows how to track user's activity when viewing YouTube videos on your site. It can track when a user starts/stops/pauses a video, watches a video all the way through, and also tracks at different points 25%/50%/75%. I used example code from lunametrics that creates YouTube objects from any existing iframe plugins on the site. Reference: http://www.lunametrics.com @lunametrics.

First, first this to work - all iframe src value needs to contain the following:&enablejsapi=1&origin=http%3a%2f%2fwww.mroma.net. Where www.mroma.net would be the domain you are running your site on.

var tag = document.createElement('script');
tag.src = "//www.youtube.com/iframe_api";
var firstScriptTag = document.getElementsByTagName('script')[0];
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);

var videoArray = new Array();
var playerArray = new Array();

// find all existing iframes, convert to youtube objects
(function ($) {
    function trackYouTube() {
        var i = 0;

        jQuery('iframe').each(function () {
            var video = $(this);

            if (video.attr('src') === undefined) {
                var vidSrc = "";
            } else {
                var vidSrc = video.attr('src');
            }

            var regex = /h?t?t?p?s?\:?\/\/www\.youtube\.com\/embed\/([\w-]{11})(?:\?.*)?/;
            var matches = vidSrc.match(regex);

            if (matches && matches.length > 1) {
                videoArray[i] = matches[1];
                $(this).attr('id', matches[1]);
                i++;
            }            
        });
        onYouTubeIframeAPIReady();
    }

    $(document).ready(function () {
        trackYouTube();
    });
})(jQuery);

// handle when iframe api is ready
function onYouTubeIframeAPIReady() {

    // check if already executed
    if (videoArray.length == 0 || playerArray.length > 0) {
        return;
    }
    
    // go through each video, get the player object
    for (var i = 0; i < videoArray.length; i++) {
        playerArray[i] = new YT.Player(videoArray[i], {
            events: {
                'onReady': onPlayerReady,
                'onStateChange': onPlayerStateChange
            }
        });
    }    
}

// youtube player ready
function onPlayerReady(event) { }

// youtube player state change
function onPlayerStateChange(event) {

    // track state change
    YouTubeTracking.checkStateChange(event);
}

Now that we have a player object for each YouTube video on the page, here is the code that tracks each event and tracks have checkpoints met. The checkpoints array contains which percents to check.

// define youtube tracking api
var YouTubeTracking = {

    // define checkpoints to track
    checkpointsToTrack: [25, 50, 75],

    // define player array
    players: [],

    // define pause flag
    _pauseFlag: false,


    // define interval id 
    intervalId: 0,

    // function that gets the player info, creates new if not exists
    get: function (id) {
        if (YouTubeTracking.players[id] == undefined) {
            YouTubeTracking.players[id] = { timePercent: 0 };
        }
        return YouTubeTracking.players[id];
    },

    // function that start the interval, if not already started
    startChecking: function () {

        // check if not already started
        if (YouTubeTracking.intervalId == 0) {
            YouTubeTracking.intervalId = setInterval(YouTubeTracking.checkPlayers, 500);
        }
    },

    // function that checks players on an interval
    checkPlayers: function () {

        // go through each player make sure atleast one playing
        var anyPlaying = false;
        $.each(playerArray, function (i, p) {

            // check if playing
            if (p.getPlayerState() == YT.PlayerState.PLAYING) {
                anyPlaying = true;

                // get the video info
                var duration = p.getDuration();
                var timeSoFar = p.getCurrentTime();
                var id = p.getVideoData().video_id;

                // get what we tracked so far on this video
                var playerPerc = YouTubeTracking.get(id).timePercent;

                // check if any duraction
                if (duration > 0) {

                    // get the percentage played
                    var thisPerc = timeSoFar / duration * 100;

                    // check each checkpoint
                    $.each(YouTubeTracking.checkpointsToTrack, function (j, checkpoint) {

                        // check if we reached a checkpoint milestone
                        if (playerPerc < checkpoint && thisPerc > checkpoint) {
                            YouTubeTracking.players[id].timePercent = checkpoint;
                            YouTubeTracking.pushEvent(id, "Watched " + checkpoint + "%");
                        }
                    });
                }
            }
        });

        // check if none player, stop intveral
        if (!anyPlaying) {
            clearInterval(YouTubeTracking.intervalId);
            YouTubeTracking.intervalId = 0;
        }
    },

    // track state check
    checkStateChange: function (event) {

        // get the id
        var id = event.target.a.id;

        // video playing
        if (event.data == YT.PlayerState.PLAYING) {
            YouTubeTracking.pushEvent(id, "Play");
            YouTubeTracking.pauseFlag = false;

            // start checkpoint checking
            YouTubeTracking.startChecking();
        }

        // video end
        if (event.data == YT.PlayerState.ENDED) {
            YouTubeTracking.pushEvent(id, "Watch to End");
        }

        // video paused
        if (event.data == YT.PlayerState.PAUSED && YouTubeTracking.pauseFlag == false) {
            YouTubeTracking.pushEvent(id, "Pause");
            YouTubeTracking.pauseFlag = true;
        }

        // buffering
        if (event.data == YT.PlayerState.BUFFERING) {
            YouTubeTracking.pushEvent(id, "Buffering");
        }

        // cued
        if (event.data == YT.PlayerState.CUED) {
            YouTubeTracking.pushEvent(id, "Cueing");
        }
    },

    // track in GA
    pushEvent: function (id, catg) {

        // get the title, then trach
        $.get("https://gdata.youtube.com/feeds/api/videos/" + id + "?v=2&alt=json", function (d) {
            _gaq.push(['_trackEvent', 'Videos', catg, d.entry.title.$t]);
        });
    }
};

The full source file can be downloaded here: mroma-youtube-tracking.js

GNOME Shell 3.4 Extension that will add remmina configurations to the search results

Posted on June 27, 2012 by Michael Roma

Below is javascript code for a gnome shell 3.4 extension that will add remmina configurations that are stored in a text file to the shell search results. I plan to update this extension in the future to read the contents .remmina directory instead of a text file. The text file is assumed to be ~/src/rdp and contain an rdp per line in the format: Server 1{tab}12312323.remmina Server 2{tab}23444324.remmina etc.

const St = imports.gi.St;
const Main = imports.ui.main;
const Search = imports.ui.search;
const Gio = imports.gi.Gio;
const GLib = imports.gi.GLib;
const Lang = imports.lang;
const Shell = imports.gi.Shell;
const Util = imports.misc.util;

// define search provider object
var rdpSearchProvider = null;

// define file watch to detect changes in the source text file
var rdpConfigFileWatcher = null;

// define class
const RemminaSearchProvider = new Lang.Class({
    Name: 'RemminaSearchProvider',
    Extends: Search.SearchProvider,

    // init
    _init: function(name) {
        global.log('init remmina-search');
        Search.SearchProvider.prototype._init.call(this, "Remote Desktops");


        // define remmina path 
        this.remminaPath = GLib.build_filenamev([GLib.get_home_dir(), ".remmina"]);
        
        // define config path for remmina definitions
        this.remminaConfigPath = GLib.build_filenamev([GLib.get_home_dir(), "src/rdp"]);
                                     
      
        // define the remmina config list and read
        this._remminaConfigs = [];
        this._readRemminaConfigs();

        // setup file monitor to detect changes
        let fileWatch = Gio.file_new_for_path(this.remminaConfigPath);
        rdpConfigFileWatcher = fileWatch.monitor(Gio.FileMonitorFlags.NONE, null);
        rdpConfigFileWatcher.connect('changed', Lang.bind(this, this._readRemminaConfigs));       

        return true;
    },
    

    // function that reads the configurations from the file
    _readRemminaConfigs : function () {

        // init list
        this._remminaConfigs = [];
        
        // get the file data
        let filedata;
        try {
            filedata = GLib.file_get_contents(this.remminaConfigPath, null, 0);
        } catch (e) {
            Main.notifyError("Error reading file", e.message);
            return false;
        }


        // attempt to parse the data        
        if ( (filedata[1].length != 0) && (filedata[1] != null) ) {
            try {
                
                // get each line
                let rdpInfoLines = String(filedata[1]).trim().split('\n');                
                for (var i=0; i<rdpInfoLines.length; i++) {                

                    // parse rdp info: 0 = name, 1 = remmina config file
                    let rdpInfo = String(rdpInfoLines[i]).trim().split('\t');
                    
                    // push rdp info to the list
                    this._remminaConfigs.push([rdpInfo[0], this.remminaPath + "/" + rdpInfo[1]]);                    
                }                
                
            } catch (e) {
                Main.notifyError("Error parsing file - "+ filedata, e.message);
                return false;
            }
        } else {
            Main.notifyError("Error parsing file - Empty data");
            return false;
        }
        
        // ok
        return true;
    },
    
    
    // return results back to search
    getResultMetas: function(resultIds, callback) {

        // define results
        let metas = [];

        // go through each result
        for (let i = 0; i < resultIds.length; i++) {            
            let resultId = resultIds[i];

            // get the rdp name, fallback to url if no name
            let rdpInfoName = "";
            if (resultId.name)
                rdpInfoName = resultId.name;
            else
                rdpInfoName = resultId.url;

            // add the result to the list
            metas.push({ 'id': resultId,
                     'name': rdpInfoName,
                     'createIcon': function(size) {
                            let xicon = new Gio.ThemedIcon({name: 'remmina'});
                            return new St.Icon({icon_size: size, gicon: xicon});
                    }
            });
        }
        
        // call back with results
        callback(metas);
    },

    // define method to open fetched result
    activateResult: function(id) {
        Util.spawn(['/usr/bin/remmina', '-c', id.url]);
    },

    // function that searches the rdp configs using terms passed 
    _checkRemminaConfigs: function(configs, terms) {

        // define results
        let searchResults = [];

        // go through each rdp and term
        for (var i=0; i<configs.length; i++) {
            for (var j=0; j<terms.length; j++) {

                try {
                    // get the name and url and build the string to search
                    let name = configs[i][0];
                    let url = configs[i][1];
                    let searchStr = name+url;

                    // search the string
                    let pattern = new RegExp(terms[j],"gi");
                    if (searchStr.match(pattern)) {

                        // add to the list if matched
                        searchResults.push({
                                'name': name,
                                'url': url
                        });
                    }
                }
                catch(ex) {
                    continue;
                }
            }
        }

        // return results
        return searchResults;
    },

    // function that returns the initial results
    getInitialResultSet: function(terms) {
        this.searchSystem.pushResults(this, this._checkRemminaConfigs(this._remminaConfigs, terms));    
    },

    // call same initial search on subsearch
    getSubsearchResultSet: function(previousResults, terms) {
        this.getInitialResultSet(terms);
    }
});


// init event
function init(meta) {
}

// enable event
function enable() {

    // check if search provider already initialized, create new
    if (rdpSearchProvider==null) {
        rdpSearchProvider = new RemminaSearchProvider();
        Main.overview.addSearchProvider(rdpSearchProvider);
    }
}

// disable event
function disable() {

    // if search provider exists, disable it
    if  (rdpSearchProvider!=null) {
        Main.overview.removeSearchProvider(rdpSearchProvider);
        rdpSearchProvider.rdpConfigFileWatcher.cancel(); 
        rdpSearchProvider = null;
    }
}

JQuery Background Image Fade In and Out

Posted on December 9, 2011 by Michael Roma


	
	Cycle Background Image