Browse Source

+ CSS/JS loading functions in the source

Modders should love me, adding CSS and JS is dead simple now!
Also started making use of loadJavascriptFile() in index.template.php to load all the default JS stuff (script.js, JQuery, plugins, etc).

Signed-off-by: marcusforsberg <[email protected]>
marcusforsberg 12 years ago
parent
commit
be21090480
6 changed files with 206 additions and 107 deletions
  1. 1 1
      Sources/Admin.php
  2. 128 30
      Sources/Load.php
  3. 1 1
      Sources/ModerationCenter.php
  4. 63 12
      Sources/Subs.php
  5. 2 63
      Themes/default/index.template.php
  6. 11 0
      Themes/default/scripts/theme.js

+ 1 - 1
Sources/Admin.php

@@ -30,7 +30,7 @@ function AdminMain()
 	// Load the language and templates....
 	loadLanguage('Admin');
 	loadTemplate('Admin', 'admin');
-	loadJavascriptFile('scripts/admin.js?alp21', array('default_theme' => true));
+	loadJavascriptFile('admin.js?alp21', array('default_theme' => true));
 
 	// No indexing evil stuff.
 	$context['robot_no_index'] = true;

+ 128 - 30
Sources/Load.php

@@ -1517,6 +1517,14 @@ function loadTheme($id_theme = 0, $initialize = true)
 	// Some basic information...
 	if (!isset($context['html_headers']))
 		$context['html_headers'] = '';
+	if(!isset($context['javascript_files']))
+		$context['javascript_files'] = array();
+	if(!isset($context['css_files']))
+		$context['css_files'] = array();
+	if(!isset($context['javascript_inline']))
+		$context['javascript_inline'] = array('standard' => array(), 'defer' => array());
+	if(!isset($context['javascript_vars']))
+		$context['javascript_vars'] = array();
 
 	$context['menu_separator'] = !empty($settings['use_image_buttons']) ? ' ' : ' | ';
 	$context['session_var'] = $_SESSION['session_var'];
@@ -1569,9 +1577,6 @@ function loadTheme($id_theme = 0, $initialize = true)
 		'spellcheck',
 	);
 
-	$context['javascript_files'] = array();
-	$context['css_files'] = array();
-
 	// Wireless mode?  Load up the wireless stuff.
 	if (WIRELESS)
 	{
@@ -1682,6 +1687,40 @@ function loadTheme($id_theme = 0, $initialize = true)
 	// This allows us to change the way things look for the admin.
 	$context['admin_features'] = isset($modSettings['admin_features']) ? explode(',', $modSettings['admin_features']) : array('cd,cp,k,w,rg,ml,pm');
 
+	// Default JS variables for use in every theme
+	loadLanguage('index');
+	$context['javascript_vars'] = array(
+		'smf_theme_url' => '"' . $settings['theme_url'] . '"',
+		'smf_default_theme_url' => '"' . $settings['default_theme_url'] . '"',
+		'smf_images_url' => '"' . $settings['images_url'] . '"',
+		'smf_scripturl' => '"' . $scripturl . '"',
+		'smf_default_theme_url' => '"' . $settings['default_theme_url'] . '"',
+		'smf_iso_case_folding' => $context['server']['iso_case_folding'] ? 'true' : 'false',
+		'smf_charset' => '"' . $context['character_set'] . '"',
+		'smf_session_id' => '"' . $context['session_id'] . '"',
+		'smf_session_var' => '"' . $context['session_var'] . '"',
+		'smf_member_id' => $context['user']['id'],
+		'ajax_notification_text' => JavaScriptEscape($txt['ajax_in_progress']),
+		'ajax_notification_cancel_text' => JavaScriptEscape($txt['modify_cancel']),
+		'help_popup_heading_text' => JavaScriptEscape($txt['help_popup']),
+	);
+	
+	// Add the JQuery library to the list of files to load.
+	if (isset($modSettings['jquery_source']) && $modSettings['jquery_source'] == 'cdn')
+		loadJavascriptFile('https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js', array(), 'jquery');
+	elseif (isset($modSettings['jquery_source']) && $modSettings['jquery_source'] == 'local')
+		loadJavascriptFile('jquery-1.7.1.min.js', array('default_theme' => true), 'jquery');
+	// Auto load, eh? template_javascript() will take care of the inline half of this.
+	else
+		loadJavascriptFile('https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js', array(), 'jquery');
+	
+	// Queue our JQuery plugins!
+	loadJavascriptFile('smf_jquery_plugins.js', array('default_theme' => true), 'jquery_plugins');
+	
+	// script.js and theme.js, always required, so always add them! Makes index.template.php cleaner and all.
+	loadJavascriptFile('script.js', array('default_theme' => true), 'smf_scripts');
+	loadJavascriptFile('theme.js', array(), 'theme_scripts');
+	
 	// If we think we have mail to send, let's offer up some possibilities... robots get pain (Now with scheduled task support!)
 	if ((!empty($modSettings['mail_next_send']) && $modSettings['mail_next_send'] < time() && empty($modSettings['mail_queue_use_cron'])) || empty($modSettings['next_task_time']) || $modSettings['next_task_time'] < time())
 	{
@@ -1701,15 +1740,14 @@ function loadTheme($id_theme = 0, $initialize = true)
 			$type = empty($modSettings['next_task_time']) || $modSettings['next_task_time'] < time() ? 'task' : 'mailq';
 			$ts = $type == 'mailq' ? $modSettings['mail_next_send'] : $modSettings['next_task_time'];
 
-			$context['html_headers'] .= '
-	<script type="text/javascript">
+			addInlineJavascript('
 		function smfAutoTask()
 		{
 			var tempImage = new Image();
 			tempImage.src = smf_scripturl + "?scheduled=' . $type . ';ts=' . $ts . '";
 		}
-		window.setTimeout("smfAutoTask();", 1);
-	</script>';
+		window.setTimeout("smfAutoTask();", 1);');
+
 		}
 	}
 
@@ -1748,26 +1786,14 @@ function loadTemplate($template_name, $style_sheets = array(), $fatal = true)
 {
 	global $context, $settings, $txt, $scripturl, $boarddir, $db_show_debug;
 
-	// Do any style sheets first, cause we're easy with those.
+	// Do any style sheets first (reroute to the new function to do this!)
 	if (!empty($style_sheets))
 	{
 		if (!is_array($style_sheets))
 			$style_sheets = array($style_sheets);
 
 		foreach ($style_sheets as $sheet)
-		{
-			// Prevent the style sheet from being included twice.
-			if (strpos($context['html_headers'], 'id="' . $sheet . '_css"') !== false)
-				continue;
-
-			$sheet_path = file_exists($settings['theme_dir']. '/css/' . $sheet . '.css') ? 'theme_url' : (file_exists($settings['default_theme_dir']. '/css/' . $sheet . '.css') ? 'default_theme_url' : '');
-			if ($sheet_path)
-			{
-				$context['html_headers'] .= "\n\t" . '<link rel="stylesheet" type="text/css" id="' . $sheet . '_css" href="' . $settings[$sheet_path] . '/css/' . $sheet . '.css?alp21" />';
-				if ($db_show_debug === true)
-					$context['debug']['sheets'][] = $sheet . ' (' . basename($settings[$sheet_path]) . ')';
-			}
-		}
+			loadCSSFile($sheet . '.css', array(), $sheet);
 	}
 
 	// No template to load?
@@ -1866,15 +1892,36 @@ function loadSubTemplate($sub_template_name, $fatal = false)
  *
  * @param string $filename
  * @param array $options
+ * 	- local (true/false): define if the file is local
+ * 	- default_theme (true/false): force use of default theme url
+ * 	- force_current (true/false): if this is false, we will attempt to load the file from the default theme if not found in the current theme
+ * @param string $id
  */
-function loadCSSFile($filename, $options = array())
+function loadCSSFile($filename, $options = array(), $id = '')
 {
 	global $settings, $context;
 
-	if (strpos($filename, 'http://') === false || !empty($options['local']))
-		$filename = $settings['theme_url'] . '/' . $filename;
+	$theme = !empty($options['default_theme']) ? 'default_theme' : 'theme';
+	$options['force_current'] = !empty($options['force_current']) ? $options['force_current'] : false;
+
+	// Is this a local file?
+	if (strpos($filename, 'http') === false || !empty($options['local']))
+	{
+		// Make sure it exists, too!
+		if(!file_exists($settings[$theme . '_dir'] . '/css/' . $filename))
+		{
+			// Maybe the default theme has it?
+			if($theme == 'theme' && file_exists($settings['default_theme_dir'] . '/' . $filename) && !$options['force_current'])
+				$filename = $settings['default_theme_url'] . '/css/' . $filename;
+			else
+				$filename = false;
+		}
+		else
+			$filename = $settings[$theme . '_url'] . '/css/' . $filename;
+	}
 
-	$context['css_files'][$filename] = $options;
+	if(!empty($filename))
+		$context['css_files'][(empty($id) ? basename($filename) : $id)] = array('filename' => $filename, 'options' => $options);
 }
 
 /**
@@ -1884,18 +1931,69 @@ function loadCSSFile($filename, $options = array())
  * @param array $options, possible parameters:
  * 	- local (true/false): define if the file is local
  * 	- default_theme (true/false): force use of default theme url
- * 	- defer (true/false): define if the file should be load in head or before the closing <html> tag
+ * 	- force_current (true/false): if this is false, we will attempt to load the file from the default theme if not found in the current theme
+ * 	- defer (true/false): define if the file should load in <head> or before the closing <html> tag
+ *	- async (true/false): if the script should be loaded asynchronously (HTML5)
+ * @param string $id
  */
-function loadJavascriptFile($filename, $options = array())
+function loadJavascriptFile($filename, $options = array(), $id = '')
 {
 	global $settings, $context;
 
-	$theme = !empty($options['default_theme']) ? 'default_theme_url' : 'theme_url';
+	$theme = !empty($options['default_theme']) ? 'default_theme' : 'theme';
+	$options['force_current'] = !empty($options['force_current']) ? $options['force_current'] : false;
 
+	// Is this a local file?
 	if (strpos($filename, 'http') === false || !empty($options['local']))
-		$filename = $settings[$theme] . '/' . $filename;
+	{
+		// Make sure it exists, too!
+		if(!file_exists($settings[$theme . '_dir'] . '/scripts/' . $filename))
+		{
+			// Maybe the default theme has it?
+			if($theme == 'theme' && file_exists($settings['default_theme_dir'] . '/' . $filename) && !$options['force_current'])
+				$filename = $settings['default_theme_url'] . '/scripts/' . $filename;
+			else
+				$filename = false;
+		}
+		else
+			$filename = $settings[$theme . '_url'] . '/scripts/' . $filename;
+	}
+
+	if(!empty($filename))
+		$context['javascript_files'][(empty($id) ? basename($filename) : $id)] = array('filename' => $filename, 'options' => $options);
+}
+
+/**
+ * Add a Javascript variable for output later (for feeding text strings and similar to JS)
+ * Cleaner and easier (for modders) than to use the function below.
+ *
+ * @param string $key
+ * @param string $value
+ * @param bool $escape = false, whether or not to escape the value
+ */
+function addJavascriptVar($key, $value, $escape = false)
+{
+	global $context;
+
+	if(!empty($key) && !empty($value))
+		$context['javascript_vars'][$key] = $escape ? JavaScriptEscape($value) : $value;
+}
+
+/**
+ * Add a block of inline Javascript code to be executed later
+ * Only use this if you have to, generally external JS files are better, but for very small scripts
+ * or for scripts that require help from PHP/whatever, this can be useful.
+ * Do note that all code added with this function is added to the same <script> tag so do make sure your JS is clean!
+ *
+ * @param string $javascript
+ * @param bool $defer = false, define if the script should load in <head> or before the closing <html> tag
+ */
+function addInlineJavascript($javascript, $defer = false)
+{
+	global $context;
 
-	$context['javascript_files'][$filename] = $options;
+	if(!empty($javascript))
+		$context['javascript_inline'][$defer ? 'defer' : 'standard'][] = $javascript;
 }
 
 /**

+ 1 - 1
Sources/ModerationCenter.php

@@ -225,7 +225,7 @@ function ModerationHome()
 	global $txt, $context, $scripturl, $modSettings, $user_info, $user_settings;
 
 	loadTemplate('ModerationCenter');
-	loadJavascriptFile('scripts/admin.js?alp21', array('default_theme' => true));
+	loadJavascriptFile('admin.js?alp21', array('default_theme' => true));
 
 	$context['page_title'] = $txt['moderation_center'];
 	$context['sub_template'] = 'moderation_center';

+ 63 - 12
Sources/Subs.php

@@ -2934,6 +2934,17 @@ function setupThemeContext($forceload = false)
 	// This is done to allow theme authors to customize it as they want.
 	$context['show_pm_popup'] = $context['user']['popup_messages'] && !empty($options['popup_messages']) && (!isset($_REQUEST['action']) || $_REQUEST['action'] != 'pm');
 
+	// 2.1+: Add the PM popup here instead. Theme authors can still override it simply by editing/removing the 'fPmPopup' in the array.
+	if($context['show_pm_popup'])
+		addInlineJavascript('
+		$(document).ready(function(){
+			new smc_Popup({
+				heading: ' . JavaScriptEscape($txt['show_personal_messages_heading']) . ',
+				content: ' . JavaScriptEscape(sprintf($txt['show_personal_messages'], $context['user']['unread_messages'], $scripturl . '?action=pm')) . ',
+				icon: smf_images_url + \'/im_sm_newmsg.png\'
+			});
+		});');
+
 	// Resize avatars the fancy, but non-GD requiring way.
 	if ($modSettings['avatar_action_too_large'] == 'option_js_resize' && (!empty($modSettings['avatar_max_width_external']) || !empty($modSettings['avatar_max_height_external'])))
 	{
@@ -3224,32 +3235,72 @@ function template_footer()
 }
 
 /**
- * Output the Javascript files
+ * Output the Javascript files (messed up tabbing in this function is to make the HTML source look good)
  */
 function template_javascript($do_defered = false)
 {
-	global $context;
+	global $context, $modSettings, $settings;
 
-	// Use this hook to minify/optimize Javascript files
+	// Use this hook to minify/optimize Javascript files and vars
 	call_integration_hook('pre_javascript_output');
 
-	foreach ($context['javascript_files'] as $filename => $options)
-		if ((!$do_defered && empty($options['defer'])) || ($do_defered && !empty($options['defer'])))
+	foreach ($context['javascript_files'] as $id => $file)
+	{
+		if ((!$do_defered && empty($file['options']['defer'])) || ($do_defered && !empty($file['options']['defer'])))
 			echo '
-		<script type="text/javascript" src="', $filename, '"></script>';
+	<script type="text/javascript" src="', $file['filename'], '" id="', $id,'"' , !empty($file['options']['async']) ? ' async="async"' : '' ,'></script>';
+	
+		// If this was JQuery being loaded and we are set to 'auto' load it, add the inline JS stuff here
+		if($id == 'jquery' && (!isset($modSettings['jquery_source']) || !in_array($modSettings['jquery_source'],array('local', 'cdn'))))
+		echo '
+	<script type="text/javascript"><!-- // --><![CDATA[
+		window.jQuery || document.write(\'<script src="' . $settings['default_theme_url'] . '/scripts/jquery-1.7.1.min.js"><\/script>\');
+	// ]]></script>';
+
+	}
 
-	if (!empty($context['javascript_vars']))
+	// Javascript variables.
+	if (!empty($context['javascript_vars']) && !$do_defered)
 	{
 		echo '
-		<script type="text/javascript"><!-- // --><![CDATA[';
+	<script type="text/javascript"><!-- // --><![CDATA[';
 
 		foreach ($context['javascript_vars'] as $key => $value)
 			echo '
-			var ', $key, ' = ', $value;
+		var ', $key, ' = ', $value, ';';
 
 		echo '
-		// ]]></script>';
+	// ]]></script>';
+	}
+	
+	// Inline JavaScript - Actually useful some times!
+	if (!empty($context['javascript_inline']))
+	{
+		if(!empty($context['javascript_inline']['defer']) && $do_defered)
+		{
+			echo '
+<script type="text/javascript"><!-- // --><![CDATA[
+	';
+
+			foreach ($context['javascript_inline']['defer'] as $code)
+				echo $code;
+					
+			echo'
+// ]]></script>';
+		}
 
+		if(!empty($context['javascript_inline']['standard']) && !$do_defered)
+		{
+			echo '
+	<script type="text/javascript"><!-- // --><![CDATA[
+		';
+
+			foreach ($context['javascript_inline']['standard'] as $code)
+				echo $code;
+					
+			echo'
+	// ]]></script>';
+		}
 	}
 }
 
@@ -3263,9 +3314,9 @@ function template_css()
 	// Use this hook to minify/optimize CSS files
 	call_integration_hook('pre_css_output');
 
-	foreach ($context['css_files'] as $filename => $options)
+	foreach ($context['css_files'] as $id => $file)
 		echo '
-	<link rel="stylesheet" type="text/css" href="', $filename, '" />';
+	<link rel="stylesheet" type="text/css" href="', $file['filename'], '" id="', $id,'" />';
 }
 
 /**

+ 2 - 63
Themes/default/index.template.php

@@ -99,71 +99,10 @@ function template_html_above()
 		echo '
 	<link rel="stylesheet" type="text/css" href="', $settings['theme_url'], '/css/rtl.css" />';
 
-	// load in any css from mods or themes so they can overwrite if wanted
+	// Load in any css from mods
 	template_css();
-
-	// Jquery Librarys
-	if (isset($modSettings['jquery_source']) && $modSettings['jquery_source'] == 'cdn')
-		echo '
-	<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>';
-	elseif (isset($modSettings['jquery_source']) && $modSettings['jquery_source'] == 'local')
-		echo '
-	<script type="text/javascript" src="', $settings['theme_url'], '/scripts/jquery-1.7.1.min.js"></script>';
-	else
-		echo '
-	<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
-	<script type="text/javascript"><!-- // --><![CDATA[
-		window.jQuery || document.write(\'<script src="', $settings['theme_url'], '/scripts/jquery-1.7.1.min.js"><\/script>\');
-	// ]]></script>';
-
-	// Note that the Superfish function seems to like being called by the full syntax.
-	// It doesn't appear to like being called by short syntax. Please test if contemplating changes.
-	echo '
-	<script type="text/javascript" src="', $settings['theme_url'], '/scripts/smf_jquery_plugins.js"></script>';
 	
-	// Here comes the JavaScript bits!
-	echo '
-	<script type="text/javascript" src="', $settings['default_theme_url'], '/scripts/script.js?alp21"></script>
-	<script type="text/javascript" src="', $settings['theme_url'], '/scripts/theme.js?alp21"></script>
-	<script type="text/javascript"><!-- // --><![CDATA[
-		var smf_theme_url = "', $settings['theme_url'], '";
-		var smf_default_theme_url = "', $settings['default_theme_url'], '";
-		var smf_images_url = "', $settings['images_url'], '";
-		var smf_scripturl = "', $scripturl, '";
-		var smf_iso_case_folding = ', $context['server']['iso_case_folding'] ? 'true' : 'false', ';
-		var smf_charset = "', $context['character_set'], '";
-		var smf_session_id = "', $context['session_id'], '";
-		var smf_session_var = "', $context['session_var'], '";
-		var smf_member_id = "', $context['user']['id'], '";', $context['show_pm_popup'] ? '
-		var fPmPopup = function ()
-		{
-			new smc_Popup({
-				heading: ' . JavaScriptEscape($txt['show_personal_messages_heading']) . ',
-				content: ' . JavaScriptEscape(sprintf($txt['show_personal_messages'], $context['user']['unread_messages'], $scripturl . '?action=pm')) . ',
-				icon: smf_images_url + \'/im_sm_newmsg.png\'
-			});
-		}
-		addLoadEvent(fPmPopup);' : '', '
-		var ajax_notification_text = "', $txt['ajax_in_progress'], '";
-		var ajax_notification_cancel_text = "', $txt['modify_cancel'], '";
-		var help_popup_heading_text = "', $txt['help_popup'], '";
-	// ]]></script>';
-
-	echo '
-	<script type="text/javascript"><!-- // --><![CDATA[
-		$(document).ready(function() {
-			// menu drop downs
-			$("ul.dropmenu").superfish();
-			
-			// tooltips
-			$(".preview").SMFtooltip();
-
-			// find all nested linked images and turn off the border
-			$("a.bbc_link img.bbc_img").parent().css("border", "0");
-		});
-	// ]]></script>';
-
-	// load in any javascript files from mods and themes
+	// Load in default Javascript variables as well as stuff added by mods (new in 2.1, so themers won't have to bother with it)
 	template_javascript();
 		
 	echo '

+ 11 - 0
Themes/default/scripts/theme.js

@@ -1,3 +1,14 @@
+$(document).ready(function() {
+	// menu drop downs
+	$('ul.dropmenu').superfish();
+	
+	// tooltips
+	$('.preview').SMFtooltip();
+
+	// find all nested linked images and turn off the border
+	$('a.bbc_link img.bbc_img').parent().css('border', '0');
+});
+
 // The purpose of this code is to fix the height of overflow: auto blocks, because some browsers can't figure it out for themselves.
 function smf_codeBoxFix()
 {