Skip to content
Extraits de code Groupes Projets
broadcast.js 17,9 ko
Newer Older
  • Learn to ignore specific revisions
  • robocoder's avatar
    robocoder a validé
    /*!
    
    robocoder's avatar
    robocoder a validé
     * Piwik - Web Analytics
     *
     * @link http://piwik.org
     * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
     */
    
    
    /**
     *  broadcast object is to help maintain a hash for link clicks and ajax calls
     *  so we can have back button and refresh button working.
    
     *
     *   Other file that currently depending on this are:
     *     calendar.js
     *     period_select.tpl
     *     sites_selections.tpl
     *     menu.js, ...etc
     *
    
     * !! Load this once and only once. !!
    
     * @type {object}
    
    var broadcast = {
    
        /**
         * Initialisation state
         * @type {Boolean}
         */
        _isInit: false,
    
    
    	 * Last known hash url without popover parameter
    
    	currentHashUrl: false,
    
    	 * Last known popover parameter
    
    	currentPopoverParameter: false,
    	
    	/**
    	 * Callbacks for popover parameter change
    	 */
    	popoverHandlers: [],
    
    BeezyT's avatar
    BeezyT a validé
    	/**
    	 * Force reload once
    	 */
    
    BeezyT's avatar
    BeezyT a validé
    	forceReload: false,
    
    
        /**
         * Suppress content update on hash changing
         */
        updateHashOnly: false,
    
    
        /**
         * Initializes broadcast object
         * @return {void}
         */
        init: function() {
    
    sgiehl's avatar
    sgiehl a validé
            if(broadcast._isInit) {
    
    sgiehl's avatar
    sgiehl a validé
            broadcast._isInit = true;
    
    
            // Initialize history plugin.
            // The callback is called at once by present location.hash
    
    sgiehl's avatar
    sgiehl a validé
            $.history.init(broadcast.pageload, {unescape: true});
    
    
            piwikHelper.showAjaxLoading();
        },
    
        /**
         * ========== PageLoad function =================
         * This function is called when:
         * 1. after calling $.history.init();
         * 2. after calling $.history.load();  //look at broadcast.changeParameter();
         * 3. after pushing "Go Back" button of a browser
    
    BeezyT's avatar
    BeezyT a validé
    	 * 
    	 * * Note: the method is manipulated in Overlay/templates/index.js - keep this in mind when making changes.
    
         *
         * @param {string}  hash to load page with
         * @return {void}
         */
        pageload: function( hash )
    
    mattpiwik's avatar
    mattpiwik a validé
        {
    
    
            // Unbind any previously attached resize handlers
            $(window).off('resize');
    
    
            // do not update content if it should be suppressed
            if (broadcast.updateHashOnly) {
                broadcast.updateHashOnly = false;
                return;
            }
    
    			
    		// hash doesn't contain the first # character.
    		if( hash ) {
    			
    
    			var hashParts = hash.split('&popover=');
    			var hashUrl = hashParts[0];
    			var popoverParam = '';
    			if (hashParts.length > 1) {
    				popoverParam = hashParts[1];
    				// in case the $ was encoded (e.g. when using copy&paste on urls in some browsers) 
    				popoverParam = decodeURIComponent(popoverParam);
    				// revert special encoding from broadcast.propagateNewPopoverParameter()
    				popoverParam = popoverParam.replace(/\$/g, '%');
    				popoverParam = decodeURIComponent(popoverParam);
    			}
    			
    			var pageUrlUpdated = (popoverParam == '' ||
    				(broadcast.currentHashUrl !== false && broadcast.currentHashUrl != hashUrl));
    			
    			var popoverParamUpdated = (popoverParam != '' && hashUrl == broadcast.currentHashUrl);
    			
    			if (broadcast.currentHashUrl === false) {
    
    				pageUrlUpdated = true;
    				popoverParamUpdated = (popoverParam != '');
    
    			if (pageUrlUpdated || broadcast.forceReload) {
    
    				if (hashUrl != broadcast.currentHashUrl || broadcast.forceReload) {
    
    					broadcast.loadAjaxContent(hashUrl);
    
    		
    					// make sure the "Widgets & Dashboard" is deleted on reload
    					$('#dashboardSettings').remove();
    					$('#dashboardWidgetsArea').dashboard('destroy');
    				}
    			}
    
    BeezyT's avatar
    BeezyT a validé
    			
    
    BeezyT's avatar
    BeezyT a validé
    			broadcast.forceReload = false;
    
    			broadcast.currentHashUrl = hashUrl;
    			broadcast.currentPopoverParameter = popoverParam;
    
    			if (popoverParamUpdated && popoverParam == '') {
    
    			} else if (popoverParamUpdated) {
    				var popoverParamParts = popoverParam.split(':');
    				var handlerName = popoverParamParts[0];
    				popoverParamParts.shift();
    				var param = popoverParamParts.join(':');
    				if (typeof broadcast.popoverHandlers[handlerName] != 'undefined') {
    					broadcast.popoverHandlers[handlerName](param);
    
        },
    
        /**
         * propagateAjax -- update hash values then make ajax calls.
         *    example :
         *       1) <a href="javascript:broadcast.propagateAjax('module=Referers&action=getKeywords')">View keywords report</a>
         *       2) Main menu li also goes through this function.
         *
         * Will propagate your new value into the current hash string and make ajax calls.
         *
         * NOTE: this method will only make ajax call and replacing main content.
         *
         * @param {string} ajaxUrl  querystring with parameters to be updated
    
    BeezyT's avatar
    BeezyT a validé
    	 * @param {boolean} disableHistory  the hash change won't be available in the browser history
    
         * @return {void}
         */
    
    BeezyT's avatar
    BeezyT a validé
        propagateAjax: function (ajaxUrl, disableHistory)
    
    sgiehl's avatar
    sgiehl a validé
            broadcast.init();
    
            // abort all existing ajax requests
    
            // available in global scope
    
    sgiehl's avatar
    sgiehl a validé
            var currentHashStr = broadcast.getHash();
    
    BeezyT's avatar
    BeezyT a validé
    		ajaxUrl = ajaxUrl.replace(/^\?|&#/,'');
    
            var params_vals = ajaxUrl.split("&");
            for( var i=0; i<params_vals.length; i++ )
            {
    
    sgiehl's avatar
    sgiehl a validé
                currentHashStr = broadcast.updateParamValue(params_vals[i],currentHashStr);
    
            // if the module is not 'Goals', we specifically unset the 'idGoal' parameter
            // this is to ensure that the URLs are clean (and that clicks on graphs work as expected - they are broken with the extra parameter)
    
    sgiehl's avatar
    sgiehl a validé
            var action = broadcast.getParamValue('action', currentHashStr);
    
            if( action != 'goalReport' && action != 'ecommerceReport')
            {
    
    sgiehl's avatar
    sgiehl a validé
                currentHashStr = broadcast.updateParamValue('idGoal=', currentHashStr);
    
            // unset idDashboard if use doesn't display a dashboard
    
    sgiehl's avatar
    sgiehl a validé
            var module = broadcast.getParamValue('module', currentHashStr);
    
            if( module != 'Dashboard')
            {
    
    sgiehl's avatar
    sgiehl a validé
                currentHashStr = broadcast.updateParamValue('idDashboard=', currentHashStr);
    
    BeezyT's avatar
    BeezyT a validé
    		
    
    BeezyT's avatar
    BeezyT a validé
    		if (disableHistory)
    		{
    			var newLocation = window.location.href.split('#')[0] + '#' + currentHashStr;
    			// window.location.replace changes the current url without pushing it on the browser's history stack
    			window.location.replace(newLocation);
    		}
    		else
    		{
    			// Let history know about this new Hash and load it.
    			broadcast.forceReload = true;
    			$.history.load(currentHashStr);
    		}
    
        },
    
        /**
         * propagateNewPage() -- update url value and load new page,
         * Example:
         *         1) We want to update idSite to both search query and hash then reload the page,
         *         2) update period to both search query and hash then reload page.
         *
         * ** If you'd like to make ajax call with new values then use propagateAjax ** *
         *
         * Expecting:
         *         str = "param1=newVal1&param2=newVal2";
         *
         * Currently being use by:
         *
         *  handlePeriodClick,
         *  calendar.js,
         *  sites_selection.tpl
         *
         * NOTE: This method will refresh the page with new values.
         *
         * @param {string} str  url with parameters to be updated
    
         * @param {bool} showAjaxLoading whether to show the ajax loading gif or not.
    
         * @return {void}
         */
    
        propagateNewPage: function (str, showAjaxLoading)
    
        {
            // abort all existing ajax requests
    
    		
    		if (typeof showAjaxLoading === 'undefined' || showAjaxLoading)
    		{
    	        piwikHelper.showAjaxLoading();
            }
    
            var params_vals = str.split("&");
    
            // available in global scope
            var currentSearchStr = window.location.search;
    
    sgiehl's avatar
    sgiehl a validé
            var currentHashStr = broadcast.getHashFromUrl();
    
            var oldUrl = currentSearchStr + currentHashStr;
    
            for( var i=0; i<params_vals.length; i++ ) {
                // update both the current search query and hash string
    
    sgiehl's avatar
    sgiehl a validé
                currentSearchStr = broadcast.updateParamValue(params_vals[i],currentSearchStr);
    
                if(currentHashStr.length != 0 ) {
    
    sgiehl's avatar
    sgiehl a validé
                    currentHashStr   = broadcast.updateParamValue(params_vals[i],currentHashStr);
    
            // Now load the new page.
            var newUrl = currentSearchStr + currentHashStr;
    
            if(oldUrl == newUrl) {
                window.location.reload();
            } else {
    
    BeezyT's avatar
    BeezyT a validé
    			this.forceReload = true;
    
                window.location.href = newUrl;
            }
    
        },
    
        /*************************************************
         *
         *      Broadcast Supporter Methods:
         *
         *************************************************/
    
        /**
         * updateParamValue(newParamValue,urlStr) -- Helping propagate functions to update value to url string.
         * eg. I want to update date value to search query or hash query
         *
         * Expecting:
         *        urlStr : A Hash or search query string. e.g: module=whatever&action=index=date=yesterday
         *        newParamValue : A param value pair: e.g: date=2009-05-02
         *
         * Return module=whatever&action=index&date=2009-05-02
         *
         * @param {string} newParamValue   param to be updated
         * @param {string} urlStr          url to be updated
         * @return {string}  urlStr with updated param
         */
        updateParamValue: function(newParamValue, urlStr)
        {
            var p_v = newParamValue.split("=");
    
            var paramName = p_v[0];
    
    sgiehl's avatar
    sgiehl a validé
            var valFromUrl = broadcast.getParamValue(paramName,urlStr);
    
            // if set 'idGoal=' then we remove the parameter from the URL automatically (rather than passing an empty value)
            var paramValue = p_v[1];
            if(paramValue == '')
            {
                newParamValue = '';
            }
            if( valFromUrl != '') {
                // replacing current param=value to newParamValue;
    
    BeezyT's avatar
    BeezyT a validé
    			valFromUrl = valFromUrl.replace(/\$/g, '\\$');
    			valFromUrl = valFromUrl.replace(/\./g, '\\.');
    
                var regToBeReplace = new RegExp(paramName + '=' + valFromUrl, 'ig');
    
                if(newParamValue == '') {
                    // if new value is empty remove leading &, aswell
                    regToBeReplace = new RegExp('[\&]?' + paramName + '=' + valFromUrl, 'ig');
                }
    
                urlStr = urlStr.replace( regToBeReplace, newParamValue );
            } else if(newParamValue != '') {
                urlStr += (urlStr == '') ? newParamValue : '&' + newParamValue;
            }
    
            return urlStr;
        },
    
    	/**
    	 * Update the part after the second hash
    	 */
    
    	propagateNewPopoverParameter: function(handlerName, value)
    
    		var hash = broadcast.getHashFromUrl(window.location.href);
    		var hashParts = hash.split('&popover=');
    		
    		var newHash = hashParts[0];
    		if (handlerName) {
    			var popover = handlerName + ':' + value;
    			
    			// between jquery.history and different browser bugs, it's impossible to ensure
    			// that the parameter is en- and decoded the same number of times. in order to
    			// make sure it doesn't change, we have to manipulate the url encoding a bit.
    			popover = encodeURIComponent(popover);
    			popover = popover.replace(/%/g, '\$');
    			newHash = hashParts[0] + '&popover=' + popover;
    		}
    		
    		window.location.href = 'index.php' + window.location.search + newHash;
    
    	 * Add a handler for the popover parameter
    
    	addPopoverHandler: function(handlerName, callback) {
    		this.popoverHandlers[handlerName] = callback;
    
        /**
         * Loads the given url with ajax and replaces the content
    
    BeezyT's avatar
    BeezyT a validé
    	 * 
    	 * Note: the method is replaced in Overlay/templates/index.js - keep this in mind when making changes. 
    
         *
         * @param {string} urlAjax  url to load
         * @return {Boolean}
         */
        loadAjaxContent: function(urlAjax)
        {
            piwikMenu.activateMenu(
    
    sgiehl's avatar
    sgiehl a validé
                    broadcast.getParamValue('module', urlAjax),
                    broadcast.getParamValue('action', urlAjax),
                    broadcast.getParamValue('idGoal', urlAjax) || broadcast.getParamValue('idDashboard', urlAjax)
    
            );
    
            piwikHelper.hideAjaxError('loadingError');
            piwikHelper.showAjaxLoading();
            $('#content').hide();
            $("object").remove();
    
            urlAjax = urlAjax.match(/^\?/) ? urlAjax : "?" + urlAjax;
    
    sgiehl's avatar
    sgiehl a validé
            broadcast.lastUrlRequested = urlAjax;
    
            function sectionLoaded(content)
            {
    
    			// if content is whole HTML document, do not show it, otherwise recursive page load could occur
    			var htmlDocType = '<!DOCTYPE';
    			if (content.substring(0, htmlDocType.length) == htmlDocType)
    			{
    				return;
    			}
    			
    
    sgiehl's avatar
    sgiehl a validé
                if(urlAjax == broadcast.lastUrlRequested) {
    
                    $('#content').html( content ).show();
                    piwikHelper.hideAjaxLoading();
    
    sgiehl's avatar
    sgiehl a validé
                    broadcast.lastUrlRequested = null;
    
                }
            }
            var ajaxRequest = {
    
                url: urlAjax,
                dataType: 'html',
                async: true,
    
    sgiehl's avatar
    sgiehl a validé
                error: broadcast.customAjaxHandleError,	// Callback when the request fails
    
                success: sectionLoaded, // Callback when the request succeeds
                data: new Object
            };
    
            return false;
        },
    
        /**
         * Method to handle ajax errors
         * @param {XMLHttpRequest} deferred
         * @param {string} status
         * @return {void}
         */
        customAjaxHandleError: function (deferred, status)
        {
    
    sgiehl's avatar
    sgiehl a validé
            broadcast.lastUrlRequested = null;
    
            piwikHelper.ajaxHandleError(deferred, status);
        },
    
        /**
         * Return hash string if hash exists on address bar.
         * else return false;
         *
         * @return {string|false}
         */
        isHashExists: function()
        {
    
    sgiehl's avatar
    sgiehl a validé
            var hashStr = broadcast.getHashFromUrl();
    
            if ( hashStr != "" ) {
                return hashStr;
            } else {
                return false;
            }
        },
    
        /**
         * Get Hash from given url or from current location.
         * return empty string if no hash present.
         *
         * @param {string}  url
         * @return {string} the hash part of the given url
         */
        getHashFromUrl: function(url)
        {
            var hashStr = "";
            // If url provided, give back the hash from url, else get hash from current address.
            if( url && url.match('#') ) {
                hashStr = url.substring(url.indexOf("#"),url.length);
            }
            else {
                hashStr = decodeURIComponent(location.hash);
            }
    
            return hashStr;
        },
    
        /**
         * Get search query from given url or from current location.
         * return empty string if no search query present.
         *
         * @param {string} url
         * @return {string}  the query part of the given url
         */
        getSearchFromUrl: function(url)
        {
            var searchStr = "";
            // If url provided, give back the query string from url, else get query string from current address.
            if( url && url.match(/\?/) ) {
                searchStr = url.substring(url.indexOf("?"),url.length);
            } else {
                searchStr = location.search;
            }
    
            return searchStr;
        },
    
        
        /**
         * Returns all key-value pairs in query string of url.
         * 
         * @param {string} url url to check. if undefined, null or empty, current url is used.
         * @return {object} key value pair describing query string parameters
         */
        getValuesFromUrl: function(url)
        {
        	var searchString = this._removeHashFromUrl(url).split('?')[1] || '',
        		pairs = searchString.split('&');
        	
        	var result = {};
        	for (var i = 0; i != pairs.length; ++i)
        	{
        		var pair = pairs[i].split('=');
        		result[pair[0]] = pair[1];
        	}
        	return result;
        },
    
    
        /**
         * help to get param value for any given url string with provided param name
         * if no url is provided, it will get param from current address.
         * return:
         *   Empty String if param is not found.
         *
         * @param {string} param   parameter to search for
         * @param {string} url     url to check
         * @return {string} value of the given param within the given url
         */
        getValueFromUrl: function (param, url)
        {
    
            var searchString = this._removeHashFromUrl(url);
    
    sgiehl's avatar
    sgiehl a validé
            return broadcast.getParamValue(param,searchString);
    
        },
    
        /**
         * NOTE: you should probably be using broadcast.getValueFromUrl instead!
         *
         * @param {string} param   parameter to search for
         * @param {string} url     url to check
         * @return {string} value of the given param within the hash part of the given url
         */
        getValueFromHash: function(param, url)
        {
    
    sgiehl's avatar
    sgiehl a validé
            var hashStr = broadcast.getHashFromUrl(url);
    
    BeezyT's avatar
    BeezyT a validé
    		if (hashStr.substr(0, 1) == '#') {
    			hashStr = hashStr.substr(1);
    		}
    		hashStr = hashStr.split('#')[0];
    		return broadcast.getParamValue(param,hashStr);
    
        },
    
    
        /**
         * return value for the requested param, will return the first match.
         * out side of this class should use getValueFromHash() or getValueFromUrl() instead.
         * return:
         *   Empty String if param is not found.
         *
         * @param {string} param   parameter to search for
         * @param {string} url     url to check
         * @return {string} value of the given param within the given url
         */
        getParamValue: function (param, url)
        {
            var startStr = url.indexOf(param);
    
            if( startStr  >= 0 ) {
                var endStr = url.indexOf("&", startStr);
                if( endStr == -1 ) {
                    endStr = url.length;
                }
                var value = url.substring(startStr + param.length +1,endStr);
                // sanitize values
    
    BeezyT's avatar
    BeezyT a validé
                value = value.replace(/[^_%\-\<\>!@\$\.=,;0-9a-zA-Z]/gi, '');
    
    
                return value;
            } else {
                return '';
    
        },
    
        /**
         * Returns the hash without the starting #
         * @return {string} hash part of the current url
         */
        getHash: function ()
        {
    
            return broadcast.getHashFromUrl().replace(/^#/, '').split('#')[0];
    
        },
    	
    	/**
    	 * Removes the hash portion of a URL and returns the rest.
    	 * 
    	 * @param {string} url
    	 * @return {string} url w/o hash
    	 */
    	_removeHashFromUrl: function(url)
    	{
            var searchString = '';
            if( url ) {
                var urlParts = url.split('#');
                searchString = urlParts[0];
            } else {
                searchString = location.search;
            }
            return searchString;
    	}
    };