Skip to content

Instantly share code, notes, and snippets.

@ShirtlessKirk
Created October 30, 2015 16:06
Show Gist options
  • Save ShirtlessKirk/1359ee977e94f1ec34b3 to your computer and use it in GitHub Desktop.
Save ShirtlessKirk/1359ee977e94f1ec34b3 to your computer and use it in GitHub Desktop.

Revisions

  1. ShirtlessKirk created this gist Oct 30, 2015.
    154 changes: 154 additions & 0 deletions string.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,154 @@
    /**
    * String.endsWith / String.startsWith polyfills for IE, Opera and Safari
    */
    /*global define: false, module: false */
    (function stringModule(definition) { // non-exporting module magic dance
    'use strict';

    var
    amd = 'amd',
    exports = 'exports'; // keeps the method names for CommonJS / AMD from being compiled to single character variable

    if (typeof define === 'function' && define[amd]) {
    define(function definer() {
    return definition();
    });
    } else if (typeof module === 'function' && module[exports]) {
    module[exports] = definition();
    } else {
    definition();
    }
    }(function stringPolyfill() {
    'use strict';

    if (String.prototype.endsWith && String.prototype.includes && String.prototype.startsWith && String.prototype.trim) {
    return false;
    }

    function tryParse(value) {
    return ({}).valueOf.call(Number(value)).valueOf() === value;
    }

    (function definition(support) {
    var
    prototype = String.prototype,
    toString = {}.toString;

    function check(search) {
    if (this === null || this === undefined || (search && toString.call(search) === '[object RegExp]')) {
    throw new TypeError();
    }
    }

    function defineMethod(name, method) {
    if (!prototype[name]) {
    if (support) {
    Object.defineProperty(prototype, name, {
    configurable: true,
    value: method,
    writable: true
    });
    } else {
    prototype[name] = method;
    }
    }
    }

    function endsWith(search, position) {
    var
    lastIndex,
    length,
    searchStr,
    thisStr;

    check.call(this, search);

    thisStr = String(this);
    length = thisStr.length;
    position = position ? Number(position) : length;
    if (!tryParse(position) || position > length) {
    position = length;
    }

    searchStr = String(search);
    position -= searchStr.length;
    lastIndex = thisStr.indexOf(searchStr, position);

    return lastIndex !== -1 && lastIndex === position;
    }

    function includes() {
    return String.prototype.indexOf.apply(this, arguments) !== -1;
    }

    function startsWith(search, position) {
    var
    index,
    length,
    pos,
    searchLength,
    searchStr,
    start,
    thisStr;

    check.call(this, search);

    thisStr = String(this);
    length = thisStr.length;
    if (arguments.length > 1) {
    pos = position;
    }

    pos = pos ? Number(pos) : 0;
    if (!tryParse(pos)) {
    pos = 0;
    }

    searchStr = String(search);
    searchLength = searchStr.length;
    start = Math.min(Math.max(pos, 0), length);
    if (searchLength === 0 || searchLength + start > length) {
    return false;
    }

    index = 0;
    while (index < searchLength) {
    if (thisStr.charCodeAt(start + index) !== searchStr.charCodeAt(index)) {
    return false;
    }

    index += 1;
    }

    return true;
    }

    function trim() {
    var
    thisStr;

    if (this === null || this === undefined) {
    throw new TypeError();
    }

    thisStr = String(this);

    return thisStr.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, '');
    }

    defineMethod('endsWith', endsWith);
    defineMethod('includes', includes);
    defineMethod('startsWith', startsWith);
    defineMethod('trim', trim);
    }((function supports() {
    var
    defineProperty = Object.defineProperty,
    result;

    try {
    result = defineProperty({}, {}, {}) && defineProperty;
    } catch (ignore) {}

    return result;
    }())));
    }));