wp/wp-admin/js/dashboard.js
changeset 9 177826044cd9
parent 7 cf61fcea0001
child 16 a86126ab1dd4
equal deleted inserted replaced
8:c7c34916027a 9:177826044cd9
     1 /* global pagenow, ajaxurl, postboxes, wpActiveEditor:true */
     1 /**
     2 var ajaxWidgets, ajaxPopulateWidgets, quickPressLoad;
     2  * @output wp-admin/js/dashboard.js
       
     3  */
       
     4 
       
     5 /* global pagenow, ajaxurl, postboxes, wpActiveEditor:true, ajaxWidgets */
       
     6 /* global ajaxPopulateWidgets, quickPressLoad,  */
     3 window.wp = window.wp || {};
     7 window.wp = window.wp || {};
     4 
     8 
       
     9 /**
       
    10  * Initializes the dashboard widget functionality.
       
    11  *
       
    12  * @since 2.7.0
       
    13  */
     5 jQuery(document).ready( function($) {
    14 jQuery(document).ready( function($) {
     6 	var welcomePanel = $( '#welcome-panel' ),
    15 	var welcomePanel = $( '#welcome-panel' ),
     7 		welcomePanelHide = $('#wp_welcome_panel-hide'),
    16 		welcomePanelHide = $('#wp_welcome_panel-hide'),
     8 		updateWelcomePanel;
    17 		updateWelcomePanel;
     9 
    18 
       
    19 	/**
       
    20 	 * Saves the visibility of the welcome panel.
       
    21 	 *
       
    22 	 * @since 3.3.0
       
    23 	 *
       
    24 	 * @param {boolean} visible Should it be visible or not.
       
    25 	 *
       
    26 	 * @returns {void}
       
    27 	 */
    10 	updateWelcomePanel = function( visible ) {
    28 	updateWelcomePanel = function( visible ) {
    11 		$.post( ajaxurl, {
    29 		$.post( ajaxurl, {
    12 			action: 'update-welcome-panel',
    30 			action: 'update-welcome-panel',
    13 			visible: visible,
    31 			visible: visible,
    14 			welcomepanelnonce: $( '#welcomepanelnonce' ).val()
    32 			welcomepanelnonce: $( '#welcomepanelnonce' ).val()
    15 		});
    33 		});
    16 	};
    34 	};
    17 
    35 
       
    36 	// Unhide the welcome panel if the Welcome Option checkbox is checked.
    18 	if ( welcomePanel.hasClass('hidden') && welcomePanelHide.prop('checked') ) {
    37 	if ( welcomePanel.hasClass('hidden') && welcomePanelHide.prop('checked') ) {
    19 		welcomePanel.removeClass('hidden');
    38 		welcomePanel.removeClass('hidden');
    20 	}
    39 	}
    21 
    40 
       
    41 	// Hide the welcome panel when the dismiss button or close button is clicked.
    22 	$('.welcome-panel-close, .welcome-panel-dismiss a', welcomePanel).click( function(e) {
    42 	$('.welcome-panel-close, .welcome-panel-dismiss a', welcomePanel).click( function(e) {
    23 		e.preventDefault();
    43 		e.preventDefault();
    24 		welcomePanel.addClass('hidden');
    44 		welcomePanel.addClass('hidden');
    25 		updateWelcomePanel( 0 );
    45 		updateWelcomePanel( 0 );
    26 		$('#wp_welcome_panel-hide').prop('checked', false);
    46 		$('#wp_welcome_panel-hide').prop('checked', false);
    27 	});
    47 	});
    28 
    48 
       
    49 	// Set welcome panel visibility based on Welcome Option checkbox value.
    29 	welcomePanelHide.click( function() {
    50 	welcomePanelHide.click( function() {
    30 		welcomePanel.toggleClass('hidden', ! this.checked );
    51 		welcomePanel.toggleClass('hidden', ! this.checked );
    31 		updateWelcomePanel( this.checked ? 1 : 0 );
    52 		updateWelcomePanel( this.checked ? 1 : 0 );
    32 	});
    53 	});
    33 
    54 
    34 	var tryGutenbergPanel = $( '#try-gutenberg-panel' ),
    55 	/**
    35 		tryGutenbergPanelHide = $('#wp_try_gutenberg_panel-hide'),
    56 	 * These widgets can be populated via ajax.
    36 		updateTryGutenbergPanel, installGutenbergSuccess;
    57 	 *
    37 
    58 	 * @since 2.7.0
    38 	updateTryGutenbergPanel = function( visible ) {
    59 	 *
    39 		$.post( ajaxurl, {
    60 	 * @type {string[]}
    40 			action: 'update-try-gutenberg-panel',
    61 	 *
    41 			visible: visible,
    62 	 * @global
    42 			trygutenbergpanelnonce: $( '#trygutenbergpanelnonce' ).val()
    63  	 */
    43 		});
    64 	window.ajaxWidgets = ['dashboard_primary'];
    44 	};
    65 
    45 
    66 	/**
    46 	installGutenbergSuccess = function( response ) {
    67 	 * Triggers widget updates via AJAX.
    47 		response.activateUrl += '&from=try-gutenberg';
    68 	 *
    48 		response.activateLabel = wp.updates.l10n.activatePluginLabel.replace( '%s', response.pluginName );
    69 	 * @since 2.7.0
    49 		wp.updates.installPluginSuccess( response );
    70 	 *
    50 	};
    71 	 * @global
    51 
    72 	 *
    52 	if ( tryGutenbergPanel.hasClass( 'hidden' ) && tryGutenbergPanelHide.prop( 'checked' ) ) {
    73 	 * @param {string} el Optional. Widget to fetch or none to update all.
    53 		tryGutenbergPanel.removeClass( 'hidden' );
    74 	 *
    54 	}
    75 	 * @returns {void}
    55 
    76 	 */
    56 	$( '.try-gutenberg-panel-close, .try-gutenberg-panel-dismiss a', tryGutenbergPanel ).click( function( e ) {
    77 	window.ajaxPopulateWidgets = function(el) {
    57 		e.preventDefault();
    78 		/**
    58 		tryGutenbergPanel.addClass( 'hidden' );
    79 		 * Fetch the latest representation of the widget via Ajax and show it.
    59 		updateTryGutenbergPanel( 0 );
    80 		 *
    60 		$('#wp_try_gutenberg_panel-hide').prop( 'checked', false );
    81 		 * @param {number} i Number of half-seconds to use as the timeout.
    61 	});
    82 		 * @param {string} id ID of the element which is going to be checked for changes.
    62 
    83 		 *
    63 	tryGutenbergPanelHide.click( function() {
    84 		 * @returns {void}
    64 		tryGutenbergPanel.toggleClass( 'hidden', ! this.checked );
    85 		 */
    65 		updateTryGutenbergPanel( this.checked ? 1 : 0 );
       
    66 	});
       
    67 
       
    68 	tryGutenbergPanel.on( 'click', '.install-now', function( e ) {
       
    69 		e.preventDefault();
       
    70 		var args = {
       
    71 			slug: $( e.target ).data( 'slug' ),
       
    72 			success: installGutenbergSuccess
       
    73 		};
       
    74 		wp.updates.installPlugin( args );
       
    75 	} );
       
    76 
       
    77 	// These widgets are sometimes populated via ajax
       
    78 	ajaxWidgets = ['dashboard_primary'];
       
    79 
       
    80 	ajaxPopulateWidgets = function(el) {
       
    81 		function show(i, id) {
    86 		function show(i, id) {
    82 			var p, e = $('#' + id + ' div.inside:visible').find('.widget-loading');
    87 			var p, e = $('#' + id + ' div.inside:visible').find('.widget-loading');
       
    88 			// If the element is found in the dom, queue to load latest representation.
    83 			if ( e.length ) {
    89 			if ( e.length ) {
    84 				p = e.parent();
    90 				p = e.parent();
    85 				setTimeout( function(){
    91 				setTimeout( function(){
       
    92 					// Request the widget content.
    86 					p.load( ajaxurl + '?action=dashboard-widgets&widget=' + id + '&pagenow=' + pagenow, '', function() {
    93 					p.load( ajaxurl + '?action=dashboard-widgets&widget=' + id + '&pagenow=' + pagenow, '', function() {
       
    94 						// Hide the parent and slide it out for visual fancyness.
    87 						p.hide().slideDown('normal', function(){
    95 						p.hide().slideDown('normal', function(){
    88 							$(this).css('display', '');
    96 							$(this).css('display', '');
    89 						});
    97 						});
    90 					});
    98 					});
    91 				}, i * 500 );
    99 				}, i * 500 );
    92 			}
   100 			}
    93 		}
   101 		}
    94 
   102 
       
   103 		// If we have received a specific element to fetch, check if it is valid.
    95 		if ( el ) {
   104 		if ( el ) {
    96 			el = el.toString();
   105 			el = el.toString();
       
   106 			// If the element is available as AJAX widget, show it.
    97 			if ( $.inArray(el, ajaxWidgets) !== -1 ) {
   107 			if ( $.inArray(el, ajaxWidgets) !== -1 ) {
       
   108 				// Show element without any delay.
    98 				show(0, el);
   109 				show(0, el);
    99 			}
   110 			}
   100 		} else {
   111 		} else {
       
   112 			// Walk through all ajaxWidgets, loading them after each other.
   101 			$.each( ajaxWidgets, show );
   113 			$.each( ajaxWidgets, show );
   102 		}
   114 		}
   103 	};
   115 	};
       
   116 
       
   117 	// Initially populate ajax widgets.
   104 	ajaxPopulateWidgets();
   118 	ajaxPopulateWidgets();
   105 
   119 
       
   120 	// Register ajax widgets as postbox toggles.
   106 	postboxes.add_postbox_toggles(pagenow, { pbshow: ajaxPopulateWidgets } );
   121 	postboxes.add_postbox_toggles(pagenow, { pbshow: ajaxPopulateWidgets } );
   107 
   122 
   108 	/* QuickPress */
   123 	/**
   109 	quickPressLoad = function() {
   124 	 * Control the Quick Press (Quick Draft) widget.
       
   125 	 *
       
   126 	 * @since 2.7.0
       
   127 	 *
       
   128 	 * @global
       
   129 	 *
       
   130 	 * @returns {void}
       
   131 	 */
       
   132 	window.quickPressLoad = function() {
   110 		var act = $('#quickpost-action'), t;
   133 		var act = $('#quickpost-action'), t;
   111 
   134 
       
   135 		// Enable the submit buttons.
   112 		$( '#quick-press .submit input[type="submit"], #quick-press .submit input[type="reset"]' ).prop( 'disabled' , false );
   136 		$( '#quick-press .submit input[type="submit"], #quick-press .submit input[type="reset"]' ).prop( 'disabled' , false );
   113 
   137 
   114 		t = $('#quick-press').submit( function( e ) {
   138 		t = $('#quick-press').submit( function( e ) {
   115 			e.preventDefault();
   139 			e.preventDefault();
       
   140 
       
   141 			// Show a spinner.
   116 			$('#dashboard_quick_press #publishing-action .spinner').show();
   142 			$('#dashboard_quick_press #publishing-action .spinner').show();
       
   143 
       
   144 			// Disable the submit button to prevent duplicate submissions.
   117 			$('#quick-press .submit input[type="submit"], #quick-press .submit input[type="reset"]').prop('disabled', true);
   145 			$('#quick-press .submit input[type="submit"], #quick-press .submit input[type="reset"]').prop('disabled', true);
   118 
   146 
       
   147 			// Post the entered data to save it.
   119 			$.post( t.attr( 'action' ), t.serializeArray(), function( data ) {
   148 			$.post( t.attr( 'action' ), t.serializeArray(), function( data ) {
   120 				// Replace the form, and prepend the published post.
   149 				// Replace the form, and prepend the published post.
   121 				$('#dashboard_quick_press .inside').html( data );
   150 				$('#dashboard_quick_press .inside').html( data );
   122 				$('#quick-press').removeClass('initial-form');
   151 				$('#quick-press').removeClass('initial-form');
   123 				quickPressLoad();
   152 				quickPressLoad();
   124 				highlightLatestPost();
   153 				highlightLatestPost();
       
   154 
       
   155 				// Focus the title to allow for quickly drafting another post.
   125 				$('#title').focus();
   156 				$('#title').focus();
   126 			});
   157 			});
   127 
   158 
       
   159 			/**
       
   160 			 * Highlights the latest post for one second.
       
   161 			 *
       
   162 			 * @returns {void}
       
   163  			 */
   128 			function highlightLatestPost () {
   164 			function highlightLatestPost () {
   129 				var latestPost = $('.drafts ul li').first();
   165 				var latestPost = $('.drafts ul li').first();
   130 				latestPost.css('background', '#fffbe5');
   166 				latestPost.css('background', '#fffbe5');
   131 				setTimeout(function () {
   167 				setTimeout(function () {
   132 					latestPost.css('background', 'none');
   168 					latestPost.css('background', 'none');
   133 				}, 1000);
   169 				}, 1000);
   134 			}
   170 			}
   135 		} );
   171 		} );
   136 
   172 
       
   173 		// Change the QuickPost action to the publish value.
   137 		$('#publish').click( function() { act.val( 'post-quickpress-publish' ); } );
   174 		$('#publish').click( function() { act.val( 'post-quickpress-publish' ); } );
   138 
       
   139 		$('#title, #tags-input, #content').each( function() {
       
   140 			var input = $(this), prompt = $('#' + this.id + '-prompt-text');
       
   141 
       
   142 			if ( '' === this.value ) {
       
   143 				prompt.removeClass('screen-reader-text');
       
   144 			}
       
   145 
       
   146 			prompt.click( function() {
       
   147 				$(this).addClass('screen-reader-text');
       
   148 				input.focus();
       
   149 			});
       
   150 
       
   151 			input.blur( function() {
       
   152 				if ( '' === this.value ) {
       
   153 					prompt.removeClass('screen-reader-text');
       
   154 				}
       
   155 			});
       
   156 
       
   157 			input.focus( function() {
       
   158 				prompt.addClass('screen-reader-text');
       
   159 			});
       
   160 		});
       
   161 
   175 
   162 		$('#quick-press').on( 'click focusin', function() {
   176 		$('#quick-press').on( 'click focusin', function() {
   163 			wpActiveEditor = 'content';
   177 			wpActiveEditor = 'content';
   164 		});
   178 		});
   165 
   179 
   166 		autoResizeTextarea();
   180 		autoResizeTextarea();
   167 	};
   181 	};
   168 	quickPressLoad();
   182 	window.quickPressLoad();
   169 
   183 
       
   184 	// Enable the dragging functionality of the widgets.
   170 	$( '.meta-box-sortables' ).sortable( 'option', 'containment', '#wpwrap' );
   185 	$( '.meta-box-sortables' ).sortable( 'option', 'containment', '#wpwrap' );
   171 
   186 
       
   187 	/**
       
   188 	 * Adjust the height of the textarea based on the content.
       
   189 	 *
       
   190 	 * @since 3.6.0
       
   191 	 *
       
   192 	 * @returns {void}
       
   193 	 */
   172 	function autoResizeTextarea() {
   194 	function autoResizeTextarea() {
       
   195 		// When IE8 or older is used to render this document, exit.
   173 		if ( document.documentMode && document.documentMode < 9 ) {
   196 		if ( document.documentMode && document.documentMode < 9 ) {
   174 			return;
   197 			return;
   175 		}
   198 		}
   176 
   199 
   177 		// Add a hidden div. We'll copy over the text from the textarea to measure its height.
   200 		// Add a hidden div. We'll copy over the text from the textarea to measure its height.
   178 		$('body').append( '<div class="quick-draft-textarea-clone" style="display: none;"></div>' );
   201 		$('body').append( '<div class="quick-draft-textarea-clone" style="display: none;"></div>' );
   179 
   202 
   180 		var clone = $('.quick-draft-textarea-clone'),
   203 		var clone = $('.quick-draft-textarea-clone'),
   181 			editor = $('#content'),
   204 			editor = $('#content'),
   182 			editorHeight = editor.height(),
   205 			editorHeight = editor.height(),
   183 			// 100px roughly accounts for browser chrome and allows the
   206 			/*
   184 			// save draft button to show on-screen at the same time.
   207 			 * 100px roughly accounts for browser chrome and allows the
       
   208 			 * save draft button to show on-screen at the same time.
       
   209 			 */
   185 			editorMaxHeight = $(window).height() - 100;
   210 			editorMaxHeight = $(window).height() - 100;
   186 
   211 
   187 		// Match up textarea and clone div as much as possible.
   212 		/*
   188 		// Padding cannot be reliably retrieved using shorthand in all browsers.
   213 		 * Match up textarea and clone div as much as possible.
       
   214 		 * Padding cannot be reliably retrieved using shorthand in all browsers.
       
   215 		 */
   189 		clone.css({
   216 		clone.css({
   190 			'font-family': editor.css('font-family'),
   217 			'font-family': editor.css('font-family'),
   191 			'font-size':   editor.css('font-size'),
   218 			'font-size':   editor.css('font-size'),
   192 			'line-height': editor.css('line-height'),
   219 			'line-height': editor.css('line-height'),
   193 			'padding-bottom': editor.css('paddingBottom'),
   220 			'padding-bottom': editor.css('paddingBottom'),
   197 			'white-space': 'pre-wrap',
   224 			'white-space': 'pre-wrap',
   198 			'word-wrap': 'break-word',
   225 			'word-wrap': 'break-word',
   199 			'display': 'none'
   226 			'display': 'none'
   200 		});
   227 		});
   201 
   228 
   202 		// propertychange is for IE < 9
   229 		// The 'propertychange' is used in IE < 9.
   203 		editor.on('focus input propertychange', function() {
   230 		editor.on('focus input propertychange', function() {
   204 			var $this = $(this),
   231 			var $this = $(this),
   205 				// &nbsp; is to ensure that the height of a final trailing newline is included.
   232 				// Add a non-breaking space to ensure that the height of a trailing newline is
       
   233 				// included.
   206 				textareaContent = $this.val() + '&nbsp;',
   234 				textareaContent = $this.val() + '&nbsp;',
   207 				// 2px is for border-top & border-bottom
   235 				// Add 2px to compensate for border-top & border-bottom.
   208 				cloneHeight = clone.css('width', $this.css('width')).text(textareaContent).outerHeight() + 2;
   236 				cloneHeight = clone.css('width', $this.css('width')).text(textareaContent).outerHeight() + 2;
   209 
   237 
   210 			// Default to having scrollbars
   238 			// Default to show a vertical scrollbar, if needed.
   211 			editor.css('overflow-y', 'auto');
   239 			editor.css('overflow-y', 'auto');
   212 
   240 
   213 			// Only change the height if it has indeed changed and both heights are below the max.
   241 			// Only change the height if it has changed and both heights are below the max.
   214 			if ( cloneHeight === editorHeight || ( cloneHeight >= editorMaxHeight && editorHeight >= editorMaxHeight ) ) {
   242 			if ( cloneHeight === editorHeight || ( cloneHeight >= editorMaxHeight && editorHeight >= editorMaxHeight ) ) {
   215 				return;
   243 				return;
   216 			}
   244 			}
   217 
   245 
   218 			// Don't allow editor to exceed height of window.
   246 			/*
   219 			// This is also bound in CSS to a max-height of 1300px to be extra safe.
   247 			 * Don't allow editor to exceed the height of the window.
       
   248 			 * This is also bound in CSS to a max-height of 1300px to be extra safe.
       
   249 			 */
   220 			if ( cloneHeight > editorMaxHeight ) {
   250 			if ( cloneHeight > editorMaxHeight ) {
   221 				editorHeight = editorMaxHeight;
   251 				editorHeight = editorMaxHeight;
   222 			} else {
   252 			} else {
   223 				editorHeight = cloneHeight;
   253 				editorHeight = cloneHeight;
   224 			}
   254 			}
   225 
   255 
   226 			// No scrollbars as we change height, not for IE < 9
   256 			// Disable scrollbars because we adjust the height to the content.
   227 			editor.css('overflow', 'hidden');
   257 			editor.css('overflow', 'hidden');
   228 
   258 
   229 			$this.css('height', editorHeight + 'px');
   259 			$this.css('height', editorHeight + 'px');
   230 		});
   260 		});
   231 	}
   261 	}
   236 	'use strict';
   266 	'use strict';
   237 
   267 
   238 	var communityEventsData = window.communityEventsData || {},
   268 	var communityEventsData = window.communityEventsData || {},
   239 		app;
   269 		app;
   240 
   270 
   241 	app = window.wp.communityEvents = {
   271 	/**
       
   272 	 * Global Community Events namespace.
       
   273 	 *
       
   274 	 * @since 4.8.0
       
   275 	 *
       
   276 	 * @memberOf wp
       
   277 	 * @namespace wp.communityEvents
       
   278 	 */
       
   279 	app = window.wp.communityEvents = /** @lends wp.communityEvents */{
   242 		initialized: false,
   280 		initialized: false,
   243 		model: null,
   281 		model: null,
   244 
   282 
   245 		/**
   283 		/**
   246 		 * Initializes the wp.communityEvents object.
   284 		 * Initializes the wp.communityEvents object.
   247 		 *
   285 		 *
   248 		 * @since 4.8.0
   286 		 * @since 4.8.0
       
   287 		 *
       
   288 		 * @returns {void}
   249 		 */
   289 		 */
   250 		init: function() {
   290 		init: function() {
   251 			if ( app.initialized ) {
   291 			if ( app.initialized ) {
   252 				return;
   292 				return;
   253 			}
   293 			}
   274 				.attr( 'aria-hidden', 'true' )
   314 				.attr( 'aria-hidden', 'true' )
   275 				.removeClass( 'hide-if-js' );
   315 				.removeClass( 'hide-if-js' );
   276 
   316 
   277 			$container.on( 'click', '.community-events-toggle-location, .community-events-cancel', app.toggleLocationForm );
   317 			$container.on( 'click', '.community-events-toggle-location, .community-events-cancel', app.toggleLocationForm );
   278 
   318 
       
   319 			/**
       
   320 			 * Filters events based on entered location.
       
   321 			 *
       
   322 			 * @returns {void}
       
   323 			 */
   279 			$container.on( 'submit', '.community-events-form', function( event ) {
   324 			$container.on( 'submit', '.community-events-form', function( event ) {
   280 				var location = $.trim( $( '#community-events-location' ).val() );
   325 				var location = $.trim( $( '#community-events-location' ).val() );
   281 
   326 
   282 				event.preventDefault();
   327 				event.preventDefault();
   283 
   328 
   308 		 *
   353 		 *
   309 		 * @since 4.8.0
   354 		 * @since 4.8.0
   310 		 *
   355 		 *
   311 		 * @param {event|string} action 'show' or 'hide' to specify a state;
   356 		 * @param {event|string} action 'show' or 'hide' to specify a state;
   312 		 *                              or an event object to flip between states.
   357 		 *                              or an event object to flip between states.
       
   358 		 *
       
   359 		 * @returns {void}
   313 		 */
   360 		 */
   314 		toggleLocationForm: function( action ) {
   361 		toggleLocationForm: function( action ) {
   315 			var $toggleButton = $( '.community-events-toggle-location' ),
   362 			var $toggleButton = $( '.community-events-toggle-location' ),
   316 				$cancelButton = $( '.community-events-cancel' ),
   363 				$cancelButton = $( '.community-events-cancel' ),
   317 				$form         = $( '.community-events-form' ),
   364 				$form         = $( '.community-events-form' ),
   350 		/**
   397 		/**
   351 		 * Sends REST API requests to fetch events for the widget.
   398 		 * Sends REST API requests to fetch events for the widget.
   352 		 *
   399 		 *
   353 		 * @since 4.8.0
   400 		 * @since 4.8.0
   354 		 *
   401 		 *
   355 		 * @param {object} requestParams
   402 		 * @param {Object} requestParams REST API Request parameters object.
       
   403 		 *
       
   404 		 * @returns {void}
   356 		 */
   405 		 */
   357 		getEvents: function( requestParams ) {
   406 		getEvents: function( requestParams ) {
   358 			var initiatedBy,
   407 			var initiatedBy,
   359 				app = this,
   408 				app = this,
   360 				$spinner = $( '.community-events-form' ).children( '.spinner' );
   409 				$spinner = $( '.community-events-form' ).children( '.spinner' );
   403 		 * @since 4.8.0
   452 		 * @since 4.8.0
   404 		 *
   453 		 *
   405 		 * @param {Object} templateParams The various parameters that will get passed to wp.template.
   454 		 * @param {Object} templateParams The various parameters that will get passed to wp.template.
   406 		 * @param {string} initiatedBy    'user' to indicate that this was triggered manually by the user;
   455 		 * @param {string} initiatedBy    'user' to indicate that this was triggered manually by the user;
   407 		 *                                'app' to indicate it was triggered automatically by the app itself.
   456 		 *                                'app' to indicate it was triggered automatically by the app itself.
       
   457 		 *
       
   458 		 * @returns {void}
   408 		 */
   459 		 */
   409 		renderEventsTemplate: function( templateParams, initiatedBy ) {
   460 		renderEventsTemplate: function( templateParams, initiatedBy ) {
   410 			var template,
   461 			var template,
   411 				elementVisibility,
   462 				elementVisibility,
   412 				l10nPlaceholder  = /%(?:\d\$)?s/g, // Match `%s`, `%1$s`, `%2$s`, etc.
   463 				l10nPlaceholder  = /%(?:\d\$)?s/g, // Match `%s`, `%1$s`, `%2$s`, etc.