Update for SMF 2.1, revamping into supporting alerts
Jeremy D

Jeremy D commited on 2022-03-06 17:23:36
Showing 13 changed files, with 183 additions and 75 deletions.

... ...
@@ -1,24 +1,29 @@
1
-Copyright (c) 2012, SleePy (smf [dash] mods [dash] license [dash] upc [at] sleepycode [dot]com)
1
+BSD 3-Clause License
2
+
3
+Copyright (c) 2022, SleePy
2 4
 All rights reserved.
3 5
 
4 6
 Redistribution and use in source and binary forms, with or without
5 7
 modification, are permitted provided that the following conditions are met:
6
-    * Redistributions of source code must retain the above copyright
7
-      notice, this list of conditions and the following disclaimer.
8
-    * Redistributions in binary form must reproduce the above copyright
9
-      notice, this list of conditions and the following disclaimer in the
10
-      documentation and/or other materials provided with the distribution.
11
-    * Neither the name of the <organization> nor the
12
-      names of its contributors may be used to endorse or promote products
13
-      derived from this software without specific prior written permission.
14 8
 
15
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
16
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18
-DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
19
-DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
21
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
22
-ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
9
+1. Redistributions of source code must retain the above copyright notice, this
10
+   list of conditions and the following disclaimer.
11
+
12
+2. Redistributions in binary form must reproduce the above copyright notice,
13
+   this list of conditions and the following disclaimer in the documentation
14
+   and/or other materials provided with the distribution.
15
+
16
+3. Neither the name of the copyright holder nor the names of its
17
+   contributors may be used to endorse or promote products derived from
18
+   this software without specific prior written permission.
19
+
20
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
... ...
@@ -2,7 +2,7 @@ SMF 2.0+ Modification.  I will not back support this mod to older versions.
2 2
 
3 3
 This modification adds a unread PM counter to the favicon.  In addition it continues to check for PMs at a specified interval.  Setting this variable to lower can result in server degration/performance issues.  Use with caution.  The default timeout is 1 minute (60 seconds).
4 4
 
5
-Prior to asking for support, check out the wiki: https://github.com/jdarwood007/smf-unreadPM_count/wiki
5
+Prior to asking for support, check out the wiki: https://github.com/jdarwood007/smfmod-faviconindicator/wiki
6 6
 
7 7
 Credits for this ability go to Tom Moor for creating Tinycon: https://github.com/tommoor/tinycon
8 8
 
... ...
@@ -14,3 +14,5 @@ Opera 11+
14 14
 The following browsers will fall back to changing the title due to lack of support for this:
15 15
 Internet Explorer 9
16 16
 Safari 5
17
+
18
+Websites with apple icons meta data may not function as iOS/Safari may overload the favicon
17 19
\ No newline at end of file
... ...
@@ -1,7 +1,7 @@
1 1
 <?php
2 2
 
3 3
 // This adds a hook to our action=.
4
-function uPMs_hook_actionArray(&$actionArray)
4
+function uPMs_hook_actionArray($actionArray)
5 5
 {
6 6
 	global $modSettings;
7 7
 
... ...
@@ -45,7 +45,7 @@ function uPMs_hook_load_theme()
45 45
 
46 46
 
47 47
 // Adds a hook to the general mod settings so we can manage the setting.
48
-function uPMs_hook_general_mod_settings(&$config_vars)
48
+function uPMs_hook_general_mod_settings($config_vars)
49 49
 {
50 50
 	global $txt;
51 51
 
... ...
@@ -0,0 +1,104 @@
1
+<?php
2
+
3
+/**
4
+ * The main class for Favicon Indicator customization
5
+ * @package AntiSpamLinks
6
+ * @author SleePy https://sleepycode.com
7
+ * @copyright 2022
8
+ * @license 3-Clause BSD https://opensource.org/licenses/BSD-3-Clause
9
+ * @version 2.0
10
+ */
11
+class FaviconIndicator
12
+{
13
+	/**
14
+	 * Creates the hook to the class for the xml sub actions.
15
+	 *
16
+	 * @param array $subActions A associate array of all the valid sub actions.
17
+	 *
18
+	 * @version 2.0
19
+	 * @since 1.0
20
+	 * @uses integrate_XMLhttpMain_subActions - Hook SMF2.1
21
+	 * @return void No return is generated
22
+	 */
23
+	public static function hook_XMLhttpMain_subActions(array &$subActions): void
24
+	{
25
+		$subActions['faviconnotify'] = 'FaviconIndicator::CheckNotifications';
26
+	}
27
+
28
+	/**
29
+	 * Prepares some XML data to send backt o the client.  This contains the unread pm and alerts counts.
30
+	 *
31
+	 * @version 2.0
32
+	 * @since 1.0
33
+	 * @return void No return is generated, it is sent to output
34
+	 */
35
+	public static function CheckNotifications(): void
36
+	{
37
+		global $user_info, $context;
38
+
39
+		header('Content-Type: text/xml; charset=UTF-8');
40
+
41
+		echo '<', '?xml version="1.0" encoding="UTF-8"?', '>
42
+	<smf>
43
+		<unreadpms>', $user_info['unread_messages'], '</unreadpms>
44
+		<alerts>', $user_info['alerts'], '</alerts>
45
+	</smf>';
46
+
47
+		obExit(false, false, false);
48
+	}
49
+
50
+	/**
51
+	 * Adds the javascript needed to make things work.
52
+	 *
53
+	 * @version 2.0
54
+	 * @since 1.0
55
+	 * @uses integrate_load_theme - Hook SMF2.1
56
+	 * @return void No return is generated
57
+	 */
58
+	public static function hook_load_theme(): void
59
+	{
60
+		global $context, $settings, $modSettings;
61
+
62
+		// Default the setting to 1 minute.
63
+		if (!isset($modSettings['faviconIndicatorTimeout']))
64
+			$modSettings['faviconIndicatorTimeout'] = 60;
65
+		elseif (empty($modSettings['faviconIndicatorTimeout']) || $context['user']['is_guest'])
66
+			return;
67
+
68
+		// Append the html headers.
69
+		loadJavaScriptFile('tinycon.min.js', [
70
+			'defer' => true,
71
+		]);
72
+
73
+		addInlineJavaScript('
74
+	fFaviconNotification = function ()
75
+	{
76
+		window.setTimeout(\'fFaviconNotification();\', ' . ((int) $modSettings['faviconIndicatorTimeout']) * 600 . ');
77
+
78
+		getXMLDocument(smf_prepareScriptUrl(smf_scripturl) + \'action=xmlhttp;sa=faviconnotify\', function(responseXML){
79
+			var unreadPMs = responseXML.getElementsByTagName(\'smf\')[0].getElementsByTagName(\'unreadpms\')[0].firstChild.nodeValue;
80
+			var alerts = responseXML.getElementsByTagName(\'smf\')[0].getElementsByTagName(\'alerts\')[0].firstChild.nodeValue;
81
+			Tinycon.setBubble(parseInt(unreadPMs) + parseInt(alerts));
82
+		});
83
+	}
84
+	addLoadEvent(fFaviconNotification);', true);
85
+	}
86
+
87
+	/**
88
+	 * Creates the hook to the class for the general mod settings.
89
+	 *
90
+	 * @param array $config_vars A associate array of all the valid configuration variables.
91
+	 *
92
+	 * @version 2.0
93
+	 * @since 1.0
94
+	 * @uses integrate_general_mod_settings - Hook SMF2.1
95
+	 * @return void No return is generated
96
+	 */
97
+	public static function hook_general_mod_settings(array &$config_vars): void
98
+	{
99
+		global $txt;
100
+
101
+		loadLanguage('FaviconIndicator');
102
+		$config_vars[] = array('int', 'faviconIndicatorTimeout', 'postinput' => $txt['faviconIndicatorTimeout_post']);
103
+	}
104
+}
0 105
\ No newline at end of file
... ...
@@ -0,0 +1,3 @@
1
+<?php
2
+$txt['faviconIndicatorTimeout'] = 'Favicon Indicator Timeout';
3
+$txt['faviconIndicatorTimeout_post'] = 'seconds between checks (setting this to low may cause performance issues)';
0 4
\ No newline at end of file
... ...
@@ -0,0 +1,13 @@
1
+<?php
2
+if (file_exists(dirname(__FILE__) . '/SSI.php') && !defined('SMF'))
3
+	require_once(dirname(__FILE__) . '/SSI.php');
4
+elseif (!defined('SMF'))
5
+	exit('<b>Error:</b> Cannot install - please verify you put this in the same place as SMF\'s index.php.');
6
+
7
+global $modSettings;
8
+
9
+if (isset($modSettings['unreadPMstimeout']) && !isset($modSettings['faviconIndicatorTimeout']))
10
+	updateSettings(array(
11
+		'faviconIndicatorTimeout' => (int) $modSettings['unreadPMstimeout'],
12
+		'unreadPMstimeout' => null
13
+	), true);
0 14
\ No newline at end of file
... ...
@@ -1,16 +0,0 @@
1
-<?xml version="1.0"?>
2
-<!DOCTYPE modification SYSTEM "http://www.simplemachines.org/xml/modification">
3
-<!-- This package was generated by SleePys Modification Maker at http://sleepycode.com -->
4
-<modification xmlns="http://www.simplemachines.org/xml/modification" xmlns:smf="http://www.simplemachines.org/">
5
-	<id>sleepy:unreadpmfav</id>
6
-	<version>1.0</version>
7
-
8
-	<file name="$languagedir/Modifications.russian-utf8.php" error="skip">
9
-		<operation>
10
-			<search position="end"/>
11
-			<add><![CDATA[// Unread PMs strings.
12
-$txt['unreadPMstimeout'] = 'Счетчик непрочитанных ЛС для фавикон';
13
-$txt['unreadPMstimeout_post'] = 'секунд между обновлениями (маленькое значение может повлиять на производительность форума)';]]></add>
14
-		</operation>
15
-	</file>
16
-</modification>
... ...
@@ -1,16 +0,0 @@
1
-<?xml version="1.0"?>
2
-<!DOCTYPE modification SYSTEM "http://www.simplemachines.org/xml/modification">
3
-<!-- This package was generated by SleePys Modification Maker at http://sleepycode.com -->
4
-<modification xmlns="http://www.simplemachines.org/xml/modification" xmlns:smf="http://www.simplemachines.org/">
5
-	<id>sleepy:unreadpmfav</id>
6
-	<version>1.0</version>
7
-
8
-	<file name="$languagedir/Modifications.russian.php" error="skip">
9
-		<operation>
10
-			<search position="end"/>
11
-			<add><![CDATA[// Unread PMs strings.
12
-$txt['unreadPMstimeout'] = '����� ���������� �� �� �������';
13
-$txt['unreadPMstimeout_post'] = '������ ����� ����������� (�������� ������� ����� ������ �� ���������������� ������)';]]></add>
14
-		</operation>
15
-	</file>
16
-</modification>
... ...
@@ -1,28 +1,43 @@
1 1
 <!DOCTYPE package-info SYSTEM "http://www.simplemachines.org/xml/package-info">
2
-<!-- This package was generated by SleePys Package Maker at http://sleepycode.com -->
3 2
 <package-info xmlns="http://www.simplemachines.org/xml/package-info" xmlns:smf="http://www.simplemachines.org/">
4 3
 	<id>sleepy:unreadpmfav</id>
5
-	<name>Unread PMs Favicon</name>
6
-	<version>1.0.2</version>
4
+	<name>Favicon Indictator</name>
5
+	<version>2.0</version>
7 6
 	<type>modification</type>
8 7
 
9
-	<install for="SMF 2.0-2.0.99">
10
-		<code>hooks_add.php</code>
11
-		<move-file name="UnreadPMs.php" destination="$sourcedir/" />
8
+	<install for="SMF 2.1.*">
9
+		<readme>README.txt</readme>
10
+		<hook hook="integrate_general_mod_settings" function="FaviconIndicator::hook_general_mod_settings" file="$sourcedir/FaviconIndicator.php" />
11
+		<hook hook="integrate_XMLhttpMain_subActions" function="FaviconIndicator::hook_XMLhttpMain_subActions" file="$sourcedir/FaviconIndicator.php" />
12
+		<hook hook="integrate_load_theme" function="FaviconIndicator::hook_load_theme" file="$sourcedir/FaviconIndicator.php" />
13
+
14
+		<require-file name="SMF2.1/language/FaviconIndicator.english.php" destination="$themes_dir/default/languages" />
15
+		<require-file name="tinycon.min.js" destination="$themes_dir/default/scripts" />
16
+		<require-file name="SMF2.1/FaviconIndicator.php" destination="$sourcedir" />
17
+	</install>
18
+	
19
+	<uninstall for="SMF 2.1.*">
20
+		<hook reverse="true" hook="integrate_general_mod_settings" function="FaviconIndicator::hook_general_mod_settings" file="$sourcedir/FaviconIndicator.php" />
21
+		<hook reverse="true" hook="integrate_XMLhttpMain_subActions" function="FaviconIndicator::hook_XMLhttpMain_subActions" file="$sourcedir/FaviconIndicator.php" />
22
+		<hook reverse="true" hook="integrate_load_theme" function="FaviconIndicator::hook_load_theme" file="$sourcedir/FaviconIndicator.php" />
23
+
24
+		<remove-file name="$themes_dir/default/languages/FaviconIndicator.english.php" />
25
+		<remove-file name="$themes_dir/default/scripts/tinycon.min.js" />
26
+		<remove-file name="$sourcedir/FaviconIndicator.php" />
27
+	</uninstall>
28
+
29
+	<install for="SMF 2.0.*">
30
+		<code>SMF2.0/hooks_add.php</code>
31
+		<move-file name="SMF2.0/UnreadPMs.php" destination="$sourcedir/" />
12 32
 		<move-file name="tinycon.min.js" destination="$themedir/scripts/" />
13
-		<modification>language.xml</modification>
14
-		<modification>language.russian.xml</modification>
15
-		<modification>language.russian-utf8.xml</modification>
16
-		<redirect url="?action=admin;area=modsettings;" timeout="1000" />
33
+		<modification>SMF2.0/language.xml</modification>
17 34
 	</install>
18 35
 
19
-	<uninstall for="SMF 2.0-2.0.99">
20
-		<code>hooks_remove.php</code>
36
+	<uninstall for="SMF 2.0.*">
37
+		<code>SMF2.0/hooks_remove.php</code>
21 38
 		<remove-file name="$themedir/scripts/tinycon.min.js" />
22 39
 		<remove-file name="$sourcedir/UnreadPMs.php" />
23
-		<modification reverse="true">language.xml</modification>
24
-		<modification reverse="true">language.russian.xml</modification>
25
-		<modification reverse="true">language.russian-utf8.xml</modification>
40
+		<modification reverse="true">SMF2.0/language.xml</modification>
26 41
 	</uninstall>
27 42
 
28 43
 </package-info>
29 44
\ No newline at end of file
... ...
@@ -1,9 +1,7 @@
1
-/*
1
+/*!
2 2
  * Tinycon - A small library for manipulating the Favicon
3 3
  * Tom Moor, http://tommoor.com
4
- * Copyright (c) 2012 Tom Moor
5
- * MIT Licensed
6
- * @version 0.2.6
4
+ * Copyright (c) 2015 Tom Moor
5
+ * @license MIT Licensed
7 6
  */
8
-
9
-(function(){var Tinycon={};var currentFavicon=null;var originalFavicon=null;var originalTitle=document.title;var faviconImage=null;var canvas=null;var options={};var defaults={width:7,height:9,font:'10px arial',colour:'#ffffff',background:'#F03D25',fallback:true};var ua=(function(){var agent=navigator.userAgent.toLowerCase();return function(browser){return agent.indexOf(browser)!==-1}}());var browser={chrome:ua('chrome'),webkit:ua('chrome')||ua('safari'),safari:ua('safari')&&!ua('chrome'),mozilla:ua('mozilla')&&!ua('chrome')&&!ua('safari')};var getFaviconTag=function(){var links=document.getElementsByTagName('link');for(var i=0,len=links.length;i<len;i++){if((links[i].getAttribute('rel')||'').match(/\bicon\b/)){return links[i]}}return false};var removeFaviconTag=function(){var links=document.getElementsByTagName('link');var head=document.getElementsByTagName('head')[0];for(var i=0,len=links.length;i<len;i++){var exists=(typeof(links[i])!=='undefined');if(exists&&links[i].getAttribute('rel')==='icon'){head.removeChild(links[i])}}};var getCurrentFavicon=function(){if(!originalFavicon||!currentFavicon){var tag=getFaviconTag();originalFavicon=currentFavicon=tag?tag.getAttribute('href'):'/favicon.ico'}return currentFavicon};var getCanvas=function(){if(!canvas){canvas=document.createElement("canvas");canvas.width=16;canvas.height=16}return canvas};var setFaviconTag=function(url){removeFaviconTag();var link=document.createElement('link');link.type='image/x-icon';link.rel='icon';link.href=url;document.getElementsByTagName('head')[0].appendChild(link)};var log=function(message){if(window.console)window.console.log(message)};var drawFavicon=function(num,colour){if(!getCanvas().getContext||browser.safari||options.fallback==='force'){return updateTitle(num)}var context=getCanvas().getContext("2d");var colour=colour||'#000000';var num=num||0;var src=getCurrentFavicon();faviconImage=new Image();faviconImage.onload=function(){context.clearRect(0,0,16,16);context.drawImage(faviconImage,0,0,faviconImage.width,faviconImage.height,0,0,16,16);if(num>0)drawBubble(context,num,colour);refreshFavicon()};if(!src.match(/^data/)){faviconImage.crossOrigin='anonymous'}faviconImage.src=src};var updateTitle=function(num){if(options.fallback){if(num>0){document.title='('+num+') '+originalTitle}else{document.title=originalTitle}}};var drawBubble=function(context,num,colour){var len=(num+"").length-1;var width=options.width+(6*len);var w=16-width;var h=16-options.height;context.font=(browser.webkit?'bold ':'')+options.font;context.fillStyle=options.background;context.strokeStyle=options.background;context.lineWidth=1;context.fillRect(w,h,width-1,options.height);context.beginPath();context.moveTo(w-0.5,h+1);context.lineTo(w-0.5,15);context.stroke();context.beginPath();context.moveTo(15.5,h+1);context.lineTo(15.5,15);context.stroke();context.beginPath();context.strokeStyle="rgba(0,0,0,0.3)";context.moveTo(w,16);context.lineTo(15,16);context.stroke();context.fillStyle=options.colour;context.textAlign="right";context.textBaseline="top";context.fillText(num,15,browser.mozilla?7:6)};var refreshFavicon=function(){if(!getCanvas().getContext)return;setFaviconTag(getCanvas().toDataURL())};Tinycon.setOptions=function(custom){options={};for(var key in defaults){options[key]=custom.hasOwnProperty(key)?custom[key]:defaults[key]}return this};Tinycon.setImage=function(url){currentFavicon=url;refreshFavicon();return this};Tinycon.setBubble=function(num,colour){if(isNaN(parseFloat(num))||!isFinite(num))return log('Bubble must be a number');drawFavicon(num,colour);return this};Tinycon.reset=function(){Tinycon.setImage(originalFavicon)};Tinycon.setOptions(defaults);window.Tinycon=Tinycon})();
10 7
\ No newline at end of file
8
+!function(){var a={},b=null,c=null,d=null,e=null,f={},g=Math.ceil(window.devicePixelRatio)||1,h=16*g,i={width:7,height:9,font:10*g+"px arial",color:"#ffffff",background:"#F03D25",fallback:!0,crossOrigin:!0,abbreviate:!0},j=function(){var a=navigator.userAgent.toLowerCase();return function(b){return a.indexOf(b)!==-1}}(),k={ie:j("trident"),chrome:j("chrome"),webkit:j("chrome")||j("safari"),safari:j("safari")&&!j("chrome"),mozilla:j("mozilla")&&!j("chrome")&&!j("safari")},l=function(){for(var a=document.getElementsByTagName("link"),b=0,c=a.length;b<c;b++)if((a[b].getAttribute("rel")||"").match(/\bicon\b/i))return a[b];return!1},m=function(){for(var a=document.getElementsByTagName("link"),b=0,c=a.length;b<c;b++){void 0!==a[b]&&(a[b].getAttribute("rel")||"").match(/\bicon\b/i)&&a[b].parentNode.removeChild(a[b])}},n=function(){if(!c||!b){var a=l();b=a?a.getAttribute("href"):"/favicon.ico",c||(c=b)}return b},o=function(){return e||(e=document.createElement("canvas"),e.width=h,e.height=h),e},p=function(a){if(a){m();var b=document.createElement("link");b.type="image/x-icon",b.rel="icon",b.href=a,document.getElementsByTagName("head")[0].appendChild(b)}},q=function(a,b){if(!o().getContext||k.ie||k.safari||"force"===f.fallback)return r(a);var c=o().getContext("2d"),b=b||"#000000",e=n();d=document.createElement("img"),d.onload=function(){c.clearRect(0,0,h,h),c.drawImage(d,0,0,d.width,d.height,0,0,h,h),(a+"").length>0&&s(c,a,b),t()},!e.match(/^data/)&&f.crossOrigin&&(d.crossOrigin="anonymous"),d.src=e},r=function(a){if(f.fallback){var b=document.title;"("===b[0]&&(b=b.slice(b.indexOf(" "))),(a+"").length>0?document.title="("+a+") "+b:document.title=b}},s=function(a,b,c){"number"==typeof b&&b>99&&f.abbreviate&&(b=u(b));var d=(b+"").length-1,e=f.width*g+6*g*d,i=f.height*g,j=h-i,l=h-e-g,m=16*g,n=16*g,o=2*g;a.font=(k.webkit?"bold ":"")+f.font,a.fillStyle=f.background,a.strokeStyle=f.background,a.lineWidth=g,a.beginPath(),a.moveTo(l+o,j),a.quadraticCurveTo(l,j,l,j+o),a.lineTo(l,m-o),a.quadraticCurveTo(l,m,l+o,m),a.lineTo(n-o,m),a.quadraticCurveTo(n,m,n,m-o),a.lineTo(n,j+o),a.quadraticCurveTo(n,j,n-o,j),a.closePath(),a.fill(),a.beginPath(),a.strokeStyle="rgba(0,0,0,0.3)",a.moveTo(l+o/2,m),a.lineTo(n-o/2,m),a.stroke(),a.fillStyle=f.color,a.textAlign="right",a.textBaseline="top",a.fillText(b,2===g?29:15,k.mozilla?7*g:6*g)},t=function(){o().getContext&&p(o().toDataURL())},u=function(a){for(var b=[["G",1e9],["M",1e6],["k",1e3]],c=0;c<b.length;++c)if(a>=b[c][1]){a=v(a/b[c][1])+b[c][0];break}return a},v=function(a,b){return new Number(a).toFixed(b)};a.setOptions=function(a){f={},a.colour&&(a.color=a.colour);for(var b in i)f[b]=a.hasOwnProperty(b)?a[b]:i[b];return this},a.setImage=function(a){return b=a,t(),this},a.setBubble=function(a,b){return a=a||"",q(a,b),this},a.reset=function(){b=c,p(c)},a.setOptions(i),"function"==typeof define&&define.amd?define(a):"undefined"!=typeof module?module.exports=a:window.Tinycon=a}();
11 9
\ No newline at end of file
12 10