source: trunk/js/Utilities.js

Last change on this file was 679, checked in by anonymous, 5 years ago

Fix minor bugs. Detect http port and add to site_port, site_url, and page_url params of App.

File size: 9.1 KB
Line 
1/*
2* The Strangecode Codebase - a general application development framework for PHP
3* For details visit the project site: <http://trac.strangecode.com/codebase/>
4* Copyright © 2014 Strangecode, LLC
5*
6* This program is free software: you can redistribute it and/or modify
7* it under the terms of the GNU General Public License as published by
8* the Free Software Foundation, either version 3 of the License, or
9* (at your option) any later version.
10*
11* This program is distributed in the hope that it will be useful,
12* but WITHOUT ANY WARRANTY; without even the implied warranty of
13* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14* GNU General Public License for more details.
15*
16* You should have received a copy of the GNU General Public License
17* along with this program.  If not, see <http://www.gnu.org/licenses/>.
18*/
19
20// Codebase functions will be under the Strangecode namespace, unless they are added to the jQuery object for chaining.
21var Strangecode = Strangecode || {};
22
23/*
24Emulates a sprintf function. Placeholders are {1}
{N}.
25Some versions of this function were zero-indexed; this one is not.
26---------------------------------------------------------------------
27"{1} is dead, but {2} is alive! {1} {3}".format("ASP", "ASP.NET")
28
29outputs
30
31ASP is dead, but ASP.NET is alive! ASP {3}
32---------------------------------------------------------------------
33*
34* @access   public
35* @param    string multiple Strings to pass to the formatted string.
36* @author   http://stackoverflow.com/a/4673436/277303
37* @version  1.0
38* @since    30 May 2014 18:02:39
39*/
40if (!String.prototype.format) {
41    String.prototype.format = function () {
42        var args = arguments;
43        return this.replace(/{(\d+)}/g, function (match, number) {
44            return typeof args[number-1] != 'undefined' ? args[number-1] : match;
45        });
46    };
47}
48
49/*
50* Displays 'user at domain dot com' as 'user@domain.com'.
51---------------------------------------------------------------------
52<span class="sc-email">user at domain dot com</span>
53<a href="mailto:user at domain dot com" class="sc-email">Email me</a>
54<script>
55$('.sc-email').nospam();
56</script>
57---------------------------------------------------------------------
58*
59* @access   public
60* @version  2.0
61* @since    30 Jun 2008 12:32:19
62*/
63jQuery.fn.nospam = function () {
64    return this.each(function (){
65        $(this).text($(this).text().replace(' at ', '@').replace(' dot ', '.'));
66        if (this.href) {
67            this.href = decodeURIComponent(this.href).replace(' at ', '@').replace(' dot ', '.');
68        }
69    });
70};
71
72/*
73* Encode html entities by specific mapping table.
74* Decode HTML by proxying content via an in-memory div, setting its inner text which jQuery automatically encodes.
75Then we pull the encoded contents back out. The div never exists on the page.
76---------------------------------------------------------------------
77$('input').val(Strangecode.htmlEncode(string));
78---------------------------------------------------------------------
79
80@access   public
81@version  2.0
82@since    30 Jun 2013
83*/
84Strangecode.htmlEncode = function (str) {
85    var entityMap = {
86        '&': '&amp;',
87        '<': '&lt;',
88        '>': '&gt;',
89        '"': '&quot;',
90        "'": '&#39;',
91        '/': '&#x2F;',
92        '`': '&DiacriticalGrave;'
93    };
94    return String(str).replace(/[&<>"'\/`]/g, function (s) {
95        return entityMap[s];
96    });
97};
98Strangecode.htmlDecode = function (str) {
99    return $('<div>').html(str).text();
100};
101
102/*
103* Set the user's timezone in a cookie (which is used in Codebase's $app->start() method).
104---------------------------------------------------------------------
105Strangecode.setTimezoneCookie()
106---------------------------------------------------------------------
107* @access   public
108* @version  1.0
109* @since    24 Jan 2019
110*/
111Strangecode.setTimezoneCookie = function () {
112    try {
113        // use Intl API when available and returning valid time zone
114        var tz = Intl.DateTimeFormat().resolvedOptions().timeZone;
115    } catch (e) {
116        // Intl unavailable, fall back to manual guessing.
117        tz = (new Date().getTimezoneOffset()/-60);
118    }
119    if ('' != tz) {
120        document.cookie = 'tz=' + tz + ';path=/;max-age=86400';
121    }
122}
123
124/*
125Returns a string with URL-unsafe characters removed.
126---------------------------------------------------------------------
127var urlslug = $('.url').val().slug();
128---------------------------------------------------------------------
129* @access   public
130* @version  1.0
131* @since    30 Jun 2013
132*/
133$.fn.slug = function () {
134    str = this.text().trim().toLowerCase();
135    var from = 'áéíóúàÚìòùÀëïöÌÁÉÍÓÚÀÈÌÒÙÄËÏÖÜâêîÎûÂÊÎÔÛñçÇ@·/_,:;';
136    var to   = 'aeiouaeiouaeiouAEIOUAEIOUAEIOUaeiouAEIOUncCa------';
137    for (var i=0, l=from.length; i<l; i++) {
138        str = str.replace(new RegExp(from.charAt(i), 'g'), to.charAt(i));
139    }
140    return str.replace(/[^a-z0-9 -]/g, '').replace(/\s+/g, '-').replace(/-+/g, '-');
141};
142
143
144
145/*
146Remove rounding errors caused by representation of finite binary floating point numbers.
147---------------------------------------------------------------------
148> (.1*.2)
1490.020000000000000004
150> (.1*.2).trim()
1510.02
152---------------------------------------------------------------------
153* @access   public
154* @version  1.0
155* @since    24 Nov 2015
156*/
157if (!Number.prototype.trim) {
158    Number.prototype.trim = function (precision) {
159        var precision = precision || 11;
160        return Math.round(this * Math.pow(10, precision)) / Math.pow(10, precision);
161    };
162}
163
164/*
165Uppercase the first letter of string.
166---------------------------------------------------------------------
167> 'hello world'.ucfirst()
168Hello world
169---------------------------------------------------------------------
170* @access   public
171* @version  1.0
172* @since    24 Nov 2015
173*/
174if (!String.prototype.ucfirst) {
175    String.prototype.ucfirst = function () {
176        return this.charAt(0).toUpperCase() + this.slice(1);
177    };
178}
179
180
181/*
182Returns a human readable amount of time for the given amount of seconds.
183Months are calculated using the real number of days in a year: 365.2422 / 12.
184@param    int seconds Seconds of time.
185@param    string max_unit Key value from the units array.
186@return   string Value of units elapsed.
187---------------------------------------------------------------------
188> Strangecode.humanTime(3600)
1891 hour
190---------------------------------------------------------------------
191* @access   public
192* @version  1.0
193* @since    06 Mar 2019
194*/
195Strangecode.humanTime = function (seconds, max_unit) {
196    // Units: array of seconds in the unit, singular and plural unit names.
197    var units = {
198        'second': [1, 'second', 'seconds'],
199        'minute': [60, 'minute', 'minutes'],
200        'hour': [3600, 'hour', 'hours'],
201        'day': [86400, 'day', 'days'],
202        'week': [604800, 'week', 'weeks'],
203        'month': [2629743.84, 'month', 'months'],
204        'year': [31556926.08, 'year', 'years'],
205        'decade': [315569260.8, 'decade', 'decades'],
206        'century': [3155692608, 'century', 'centuries'],
207    };
208
209    // Max unit to calculate.
210    max_unit = typeof max_unit === 'string' && units[max_unit] ? max_unit : 'year';
211
212    var final_time = seconds;
213    var final_unit = 'second';
214    for (var k in units) {
215        if (seconds >= units[k][0]) {
216            final_time = seconds / units[k][0];
217            final_unit = k;
218        }
219        if (max_unit == final_unit) {
220            break;
221        }
222    }
223    final_time = Number(final_time).toFixed(0);
224    return '{1} {2}'.format(final_time, (1 == final_time ? units[final_unit][1] : units[final_unit][2]));
225}
226
227// https://github.com/benjamingr/RegExp.escape
228if(!RegExp.escape){
229    RegExp.escape = function (s){
230        return String(s).replace(/[\\^$*+?.()|[\]{}]/g, '\\$&');
231    };
232}
233
234// Throttle will ensure that a function is called at most once
235// in a specified time period (for instance, once per 10 seconds). This means
236// throttling will prevent a function from running if it has run “recently”.
237// Throttling also ensures a function is run regularly at a fixed rate.
238// https://blog.bitsrc.io/understanding-throttling-and-debouncing-973131c1ba07
239Strangecode.throttle = function (f, t) {
240    return function (args) {
241        let previousCall = this.lastCall;
242        this.lastCall = Date.now();
243        if (typeof previousCall === 'undefined' || (this.lastCall - previousCall) > t) {
244            // Throttle time has elapsed.
245            f(args);
246        }
247    }
248}
249
250// Debounce will ignore all calls to it until the calls have stopped for a
251// specified time period. Only then will it call the original function. For
252// instance, if we specify the time as two seconds, and the debounced function is
253// called 10 times with an interval of one second between each call, the function
254// will not call the original function until two seconds after the last (tenth)
255// call.
256// https://blog.bitsrc.io/understanding-throttling-and-debouncing-973131c1ba07
257Strangecode.debounce = function (f, t) {
258    return function (args) {
259        let previousCall = this.lastCall;
260        this.lastCall = Date.now();
261        if (previousCall && ((this.lastCall - previousCall) <= t)) {
262            clearTimeout(this.lastCallTimer);
263        }
264        this.lastCallTimer = setTimeout(() => f(args), t);
265    }
266}
Note: See TracBrowser for help on using the repository browser.