Sugar | Javascript, sweetened.

January 25, 2013

Changelog | Cautionlog

jQuery 1.9 Fix

The most major point of this release was fixing jQuery 1.9, which broke in one area when Sugar was included in the page. The cause was complex, on jQuery’s side there was an issue that I submitted a pull request for, however the most direct culprit was String#namespace which is a method that never really fit into the library anyway. As a result I have removed this method from String entirely. At the moment I’m not sure if it will be re-added as it feels better for another lib.

Object.toQueryString

The inverse to Object.fromQueryString, this method will take an object and turn it into a query string for use in a url. In addition to the main method it is also mapped onto extended objects, making it even easier. Finally, a namespace can be added to scope all parameters by the given namespace.

var o1 = { foo: 'bar' };
var o2 = { foo: [1,2,3] };
Object.toQueryString(o1)        // 'foo=bar'
Object.toQueryString(o2)        // 'foo[0]=1&foo[1]=2&foo[2]=3'
Object.toQueryString(o2, 'bar') // 'bar[foo][0]=1&bar[foo][1]=2&foo[2]=3'

var o1 = Object.extended({ foo: 'bar' });
var o2 = Object.extended({ foo: [1,2,3] });

o1.toQueryString()      // 'foo=bar'
o2.toQueryString()      // 'foo[0]=1&foo[1]=2&foo[2]=3'
o2.toQueryString('bar') // 'bar[foo][0]=1&bar[foo][1]=2&foo[2]=3'

Other Minor Fixes

  • Fixed issue with timezone offsets like “-0330”.
  • Fixed issue with date comparison methods like isToday not working when another locale is set.

January 13, 2013

Changelog | Cautionlog

New caching mechanism

The Function#throttle method was intended as a way to rate limit heavy operations, however not much thought was given to the returned value. v1.3.8 adds a mechanism that memoizes the result of a throttled function so that it will always return the last calculated value. This means that it can now be used as a way to cache a value for a specific period of time:

var cachedOperation = heavyOperation.throttle(5000);
cachedOperation(); // Runs the operation
cachedOperation(); // Returns the result of the last operation
setTimeout(function() {
  cachedOperation(); // Runs the operation again
}, 6000);

Function#once now makes use of this mechanism internally. It is now equivalent to .throttle(Infinity), or in other words a cached function that never expires.

Bugfixes

  • Updating Date#setWeek (now Date#setISOWeek) to follow ISO-8601 standard.
  • Renamed Date#getWeek and Date#setWeek to Date#getISOWeek and Date#setISOWeek.
  • Performance improvement to return early using typeof for type checks.
  • Performance improvement for loops.
  • Fix for Array#sample sometimes returning undefined.
  • Fix for French locales.
  • Fix for conflict with Coffeescript.
  • Fix for Object.clone not preserving date _utc flag.

November 29, 2012

Changelog | Cautionlog

select/reject

Analogous to Underscore’s Object.pick and Object.omit, Sugar now has Object.select and Object.reject. These methods do pretty much what you would expect from the names — returning a new object that contains properties that match/do not match the keys passed — but have some special hidden features. Multiple keys may be specified through enumerated arguments, or also by passing an array of keys. Additionally, regexes will match against the key. And finally, passing another object will result in a match if that object also has the given key. This in effect will produce something like an “intersect” operation in the case of select, and a “subtract” operation in the case of reject. Some examples:

// Returns an object with the single member "user"
Object.select(obj, 'user');

// Returns an object with all members except "user"
Object.reject(obj, 'user');

// Returns an object with the members "user" or "count"
Object.select(obj, 'user','count');

// Returns an object with all members except "user" and "count"
Object.reject(obj, 'user','count');

// Returns an object with the members "user" or "count"
Object.select(obj, ['user','count']);

// Returns an object with any members that match /^user/
Object.select(obj, /^user/);

// Returns an object with any members that do not match /^user/
Object.reject(obj, /^user/);

// Returns an object with members whose keys match those in obj2
Object.select(obj, obj2);

// Returns an object with all members except those in obj2
Object.reject(obj, obj2);

As “hash” methods, select and reject are most powerful when used in extended objects (Sugar’s answer to hashes):

var obj = Object.extended(obj);
obj.select('user');
obj.select('user', 'count');
obj.select(['user', 'count']);

Other changes

String#startsWith and String#endsWith were modified to allow a second argument that is the position from which startsWith or to which endsWith the operation will be performed on. This is to bring in line these methods with those of the Harmony proposals of the same name. The “case sensitivity” flag that was previously the second argument is now the third, and as always Sugar will detect when/if to defer to the native method if available.

Fixes

  • Fix for Date.create not preserving the UTC flag when the source is also a date.
  • Object.clone on arrays with the “deep” flag set to true should create a deep clone of the array.
  • Array#min/max should throw an error when comparing to undefined.
  • Fix for dates that fallback to native parsing when forcing UTC flag.
  • Date#since/fromNow aliases will now count “past” integers instead of rounding.

November 2, 2012

Changelog | Cautionlog

Basic bugfixes for this release. Skipped 1.3.5 (more simple fixes).

  • Faster String#repeat
  • Fixed issue with Array#sample skewing randomization.
  • Limiting minute/second parsing to 0-59.
  • Fixed issue with addMonths traversing into other months.
  • Fixed issue with NaN being true for isOdd.
  • Fixed issue with HTML escaping.
  • Fixed issue with float values parsing in Object.fromQueryString.
  • Internal refactoring of Object.each.
  • Fixed issue with 7 July date format.
  • Added “‘yy” as a valid year format.
  • Allowing empty strings for thousands separator and decimal in Number#format.

September 13, 2012

Changelog | Cautionlog

UTC Dates

These days, nearly all web apps have both a client-side and server-side component. Commonly the server stores dates coordinated in UTC (Universal Time). Javascript dates, on the other hand, are always localized to the the local machine, making handling this discrepancy tricky, or at least a bit of a pain.

Previous versions of Sugar had a toUTC method that performed a very naive operation of subtracting the local timezone’s offset to produce a date that would be “pseudo-UTC”, that is, still appearing to be a local time (timezones can’t be changed in JS) but with the timezone offset subtracted so that the timestamp would match that of a UTC date. The method also set a flag that format would check to output a string format with a zero timezone offset. This system had very limited functionality, as any further manipulation of the date would once again yield a local non-UTC result.

This has now been redesigned. toUTC is deprecated and two different but related methods take its place. First, when parsing utc dates, using Date.utc.create instead of Date.create will now tell Sugar to parse the date as utc based. Date.utc.past and Date.utc.future are likewise available here. This handles the case of parsing a date from utc and returning a localized date.

It is also possible to manipulate dates in Sugar as utc, similar to the way they would be manipulated on the server. To achieve this the instance method utc sets a simple internal flag on the date. From that point forward manipulations to the date will call Javascript native utc method equivalents, and formatting will have a zero timezone offset. Note that the utc method will not modify the date.

The difference between these two methods is important. The most common case is parsing utc dates from the server but using a localized date in the client (displaying to the user, etc). However, there may be more uncommon cases when you want to manipulate the date as UTC as well:

Date.create('October 1st')     // October 1st in local time
Date.utc.create('October 1st') // October 1st in GMT (UTC) time
date.set({ date: 15 })         // Calls .setDate(15) internally
date.utc().set({ date: 15 })   // Calls .setUTCDate(15) internally
date.format()                  // Outputs the date as a localized string
date.utc().format()            // Outputs the date as a string in utc
date.utc(false)                // turns off the utc flag on the date

Array Matching

Another semi-big refactoring deals with the matching of elements inside an array. Previously Sugar would attempt to recursively match any object in an array by value. This included arrays, primitives, etc, and was opt-out, ensuring that only functions are matched by reference. This has been refactored to effectively opt-in nearly all Javascript native types (except functions) to be matched by value. However it will not opt in any “objects” that are not of class [object Object] and do not have hasOwnProperty.

For user created objects and other JS internals, this has little effect. However it effectively opts-out host objects like dom elements, meaning they will be matched by reference only. This closes a major hole in matching host objects in arrays in Sugar. Previously any div element would be matched by any other div element when attempting to find it in an array, as the stringified value [object HTMLDivElement] would be directly compared. Now, they will be strictly matched by reference, making it possible to use host objects directly in arrays, without the use of a library designed for manipulating collections of elements. Most importantly for Sugar this has been achieved without requiring the complex task of identifying host objects in cross-browser environments.

Other

  • Fixed issue with Array.create not properly creating arrays.
  • Date#setWeekday now returns a timestamp like native methods.
  • Date#clone will now preserve the utc flag.
  • Fixed issue with DateRanges going into an infinite loop when traversing DST timezones.
  • Various date parsing fixes.
  • timers object is now exposed on functions.
  • Function#debounce now properly sets the timer on the debounced function.
  • Function#bind no longer overwrites native implementations.

1 2 3 4 5 Next