Skip to content

Commit

Permalink
IE8 Support (#137)
Browse files Browse the repository at this point in the history
* Better IE8 support for element and HTML interfaces

* Build updates for better IE8 support

* QUnit test updates for IE8 support

* Karma tests now only run qunit.

Mocha tests will test logic/behaviour, Karma ensures test browser
functionality

* Ensure correct jquery version is used for CI tests

* Additional render possibility to get IE8 to work

* IE8 readme docs

[ci skip]
  • Loading branch information
nfrasser committed May 16, 2016
1 parent 7f58815 commit 75e673e
Show file tree
Hide file tree
Showing 30 changed files with 406 additions and 172 deletions.
3 changes: 3 additions & 0 deletions .travis.yml
Expand Up @@ -7,5 +7,8 @@ env:
global:
- secure: LhH+mMqOktTe6cIt97PGKBfgUjZM8vRd0qddyg61FSxg7a3WrHQoHE8WdRioJ9+DDzpu/NSTsHEUFUpGN+kSRw1UY4tsNLH6HoBQnqrNN4tVOeefudJpdeteOKZrJ8r8TaA/eO7sAgXO2T+RLJ8+qTbhx8FVZtLaCAgkrS0w9Qk=
- secure: Okwm1aAR3oo09AhHDsjFSq1UGlIUtWYYvYeoolJScC/UVFGMiK9oC4fzRtUHv3kXcnshDlcVDrr/Q5JL9Qx6E+tosPJp+tioaqE8X4IDbVk7PPs/ToOOEmWnGvxkgmfCGSDuneG8RVhILkhls3fbm0z+rRWlvJkjefeA96T6zps=
install:
- npm install
- npm install jquery@1
script: ./run-tests.sh
after_script: npm run coverage
21 changes: 20 additions & 1 deletion README.md
Expand Up @@ -20,6 +20,7 @@ __Jump to__
- [Node.js/Browserify](#node-js-browserify)
- [AMD Modules](#amd-modules)
- [Browser](#browser)
- [Internet Explorer](#internet-explorer)
- [Downloads](#downloads)
- [API Documentation](#api-documentation)
- [Caveats](#caveats)
Expand All @@ -33,7 +34,7 @@ __Jump to__
* **Extensibility**<br>Linkify is designed to be fast and lightweight, but comes with a powerful plugin API that lets you detect even more information like #hashtags and @mentions.
* **Small footprint**<br>Linkify and its jQuery interface clock in at approximately 15KB minified (5KB gzipped) - approximately 50% the size of Twitter Text
* **Modern implementation**<br>Linkify is written in ECMAScript6 and compiles to ES5 for modern JavaScript runtimes.
* Linkify is compatible with all modern browsers, as well as Internet Explorer 9 and up. Full IE8 support coming soon.
* Linkify is compatible with all modern browsers, as well as Internet Explorer 8 and up.

## Demo
[Launch demo](http://soapbox.github.io/linkifyjs/)
Expand Down Expand Up @@ -64,6 +65,8 @@ Add [linkify](https://github.com/nfrasser/linkify-shim/raw/master/linkify.min.js
<script src="linkify-jquery.min.js"></script>
```

**Note:** A [polyfill](#internet-explorer) is required for Internet Explorer 8.

#### Find all links and convert them to anchor tags

```js
Expand Down Expand Up @@ -167,6 +170,22 @@ var htmlStr = linkifyStr('Check out soapboxhq.com it is great!');
$('p').linkify();
```

## Internet Explorer

Linkify natively supports Internet Explorer 9 and above. Internet Explorer 8 is supported with a polyfill.

You can use either [es5-shim](https://github.com/es-shims/es5-shim) (sham also required) or the provided `linkify-polyfill.js`:

```html
<script src="jquery.js"></script>

<!--[if IE 8]>
<script src="linkify-polyfill.js"></script>
<![endif]-->
<script src="linkify.js"></script>
<script src="linkify-jquery.js"></script>
```

## Downloads

Download the [**latest release**](https://github.com/SoapBox/linkifyjs/releases) or clone the [**build repository**](https://github.com/nfrasser/linkify-shim).
Expand Down
88 changes: 64 additions & 24 deletions gulpfile.js
Expand Up @@ -16,21 +16,17 @@ const concat = require('gulp-concat');
const istanbul = require('gulp-istanbul');
const jshint = require('gulp-jshint');
const mocha = require('gulp-mocha');
const qunit = require('gulp-qunit');
const rename = require('gulp-rename');
const replace = require('gulp-replace');
const uglify = require('gulp-uglify');
const wrap = require('gulp-wrap');

const rollup = require('./tasks/rollup');
const quickEs3 = require('./tasks/quick-es3');

var paths = {
src: 'src/**/*.js',
srcCore: [
'src/linkify/core/*.js',
'src/linkify/utils/*.js',
'src/linkify.js'
],
srcCore: 'src/linkify.js',
lib: ['lib/**/*.js'],
libTest: ['lib/*.js', 'lib/linkify/**/*.js'],
libCore: [
Expand All @@ -41,7 +37,8 @@ var paths = {
amd: 'build/amd/**/*.js',
test: 'test/index.js',
spec: 'test/spec/**.js',
qunit: 'test/qunit/*html'
qunit: 'test/qunit/**.js',
polyfill: 'polyfill.js'
};

var tldsReplaceStr = `'${tlds.join('|')}'.split('|')`;
Expand Down Expand Up @@ -74,14 +71,15 @@ gulp.task('babel-amd', () =>
.pipe(gulp.dest('build/amd')) // Required for building plugins separately
.pipe(amdOptimize('linkify'))
.pipe(concat('linkify.amd.js'))
.pipe(quickEs3())
.pipe(gulp.dest('build'))
);

/**
Build core linkify.js
*/
gulp.task('build-core', () =>
gulp.src('src/linkify.js', {read: false})
gulp.src(paths.srcCore, {read: false})
.pipe(rollup({
bundle: {
format: 'iife',
Expand Down Expand Up @@ -159,6 +157,7 @@ gulp.task('build-interfaces', () => {
stream = gulp.src(files.amd)
.pipe(concat(`linkify-${intrface}.amd.js`))
.pipe(wrap({src: `templates/linkify-${intrface}.amd.js`}))
.pipe(quickEs3())
.pipe(gulp.dest('build'));

streams.push(stream);
Expand Down Expand Up @@ -202,6 +201,7 @@ gulp.task('build-plugins', () => {
stream = gulp.src(`build/amd/linkify/plugins/${plugin}.js`)
.pipe(wrap({src: `templates/linkify/plugins/${plugin}.amd.js`}))
.pipe(concat(`linkify-plugin-${plugin}.amd.js`))
.pipe(quickEs3())
.pipe(gulp.dest('build'));
streams.push(stream);

Expand All @@ -210,20 +210,27 @@ gulp.task('build-plugins', () => {
return merge.apply(this, streams);
});

gulp.task('build-polyfill', () =>
gulp.src(paths.polyfill)
.pipe(concat('linkify-polyfill.js'))
.pipe(gulp.dest('build'))
);

// Build steps
gulp.task('build', [
'babel',
'babel-amd',
'build-core',
'build-interfaces',
'build-plugins'
'build-plugins',
'build-polyfill'
], (cb) => { cb(); });

/**
Lint using jshint
*/
gulp.task('jshint', () =>
gulp.src([paths.src, paths.test, paths.spec])
gulp.src([paths.src, paths.test, paths.spec, paths.qunit])
.pipe(jshint())
.pipe(jshint.reporter(stylish))
.pipe(jshint.reporter('fail'))
Expand All @@ -232,15 +239,15 @@ gulp.task('jshint', () =>
/**
Run mocha tests
*/
gulp.task('mocha', ['build'], () =>
gulp.task('mocha', ['jshint', 'build'], () =>
gulp.src(paths.test, {read: false})
.pipe(mocha())
);

/**
Code coverage reort for mocha tests
*/
gulp.task('coverage', ['build'], (callback) => {
gulp.task('coverage', ['jshint', 'build'], (callback) => {
// IMPORTANT: return not required here (and will actually cause bugs!)
gulp.src(paths.libTest)
.pipe(istanbul()) // Covering files
Expand All @@ -253,33 +260,65 @@ gulp.task('coverage', ['build'], (callback) => {
});
});

gulp.task('karma', ['build'], (callback) => {
gulp.task('karma', (callback) => {
let server = new Server({
configFile: __dirname + '/test/dev.conf.js',
singleRun: true
}, callback);
return server.start();
});

gulp.task('karma-chrome', ['build'], (callback) => {
gulp.task('karma-chrome', (callback) => {
let server = new Server({
configFile: __dirname + '/test/chrome.conf.js',
}, callback);
return server.start();
});

gulp.task('karma-ci', ['build'], (callback) => {
gulp.task('karma-firefox', (callback) => {
let server = new Server({
configFile: __dirname + '/test/firefox.conf.js',
}, callback);
return server.start();
});

gulp.task('karma-ci', (callback) => {
let server = new Server({
configFile: __dirname + '/test/ci.conf.js',
singleRun: true
}, callback);
return server.start();
});

gulp.task('qunit', ['build'], () =>
gulp.src(paths.qunit)
.pipe(qunit())
);
gulp.task('karma-amd', (callback) => {
let server = new Server({
configFile: __dirname + '/test/dev.amd.conf.js',
singleRun: true
}, callback);
return server.start();
});

gulp.task('karma-amd-chrome', (callback) => {
let server = new Server({
configFile: __dirname + '/test/chrome.amd.conf.js',
}, callback);
return server.start();
});

gulp.task('karma-amd-firefox', (callback) => {
let server = new Server({
configFile: __dirname + '/test/firefox.amd.conf.js',
}, callback);
return server.start();
});

gulp.task('karma-amd-ci', (callback) => {
let server = new Server({
configFile: __dirname + '/test/ci.amd.conf.js',
singleRun: true
}, callback);
return server.start();
});

// Build the deprecated legacy interface
gulp.task('build-legacy', ['build'], () =>
Expand Down Expand Up @@ -322,14 +361,15 @@ gulp.task('uglify', ['build-legacy'], () => {

gulp.task('dist', ['uglify']);
gulp.task('test', (callback) =>
runSequence('jshint', 'qunit', 'coverage', callback)
runSequence('coverage', 'karma', 'karma-amd', callback)
);
gulp.task('test-ci', (callback) =>
runSequence('karma-ci', 'karma-amd-ci', callback)
);
gulp.task('test-ci', ['karma-ci']);
// Using with other tasks causes an error here for some reason

/**
Build JS and begin watching for changes
*/
gulp.task('default', ['babel'], () =>
gulp.watch(paths.src, ['babel'])
gulp.task('default', ['jshint', 'babel'], () =>
gulp.watch(paths.src, ['jshint', 'babel'])
);
9 changes: 3 additions & 6 deletions package.json
Expand Up @@ -33,8 +33,6 @@
"babel-plugin-transform-es2015-modules-amd": "^6.6.5",
"babel-preset-es2015": "^6.6.0",
"babel-preset-es2015-loose": "^7.0.0",
"brfs": "^1.4.1",
"browserify": "^13.0.0",
"coveralls": "^2.11.4",
"expect.js": "^0.3.1",
"glob": "^7.0.3",
Expand All @@ -44,7 +42,6 @@
"gulp-istanbul": "^0.10.2",
"gulp-jshint": "^2.0.0",
"gulp-mocha": "^2.1.3",
"gulp-qunit": "^1.3.0",
"gulp-rename": "^1.2.0",
"gulp-replace": "^0.5.4",
"gulp-uglify": "^1.4.2",
Expand All @@ -54,17 +51,17 @@
"jshint": "^2.9.1",
"jshint-stylish": "^2.0.1",
"karma": "^0.13.15",
"karma-browserify": "^5.0.3",
"karma-chrome-launcher": "^0.2.1",
"karma-firefox-launcher": "^0.1.6",
"karma-mocha": "^0.2.0",
"karma-phantomjs-launcher": "^1.0.0",
"karma-qunit": "^1.0.0",
"karma-sauce-launcher": "^0.3.0",
"lazypipe": "^1.0.1",
"lodash": "^4.11.1",
"merge-stream": "^1.0.0",
"mocha": "^2.3.3",
"phantomjs-prebuilt": "^2.1.7",
"qunitjs": "^2.0.0-rc1",
"qunitjs": ">=1.23.1",
"requirejs": "^2.1.22",
"rollup": "^0.26.0",
"run-sequence": "^1.1.5",
Expand Down
60 changes: 60 additions & 0 deletions polyfill.js
@@ -0,0 +1,60 @@
(function () {
if (typeof Object.freeze != 'function') {
Object.freeze = function (obj) { return obj; }
}
if (typeof Object.create != 'function') {
Object.create = (function() {
var Temp = function() {};
return function (prototype) {
if(prototype !== Object(prototype) && prototype !== null) {
throw TypeError('Argument must be an object or null');
}
if (prototype === null) {
throw Error('null [[Prototype]] not supported');
}
Temp.prototype = prototype;
var result = new Temp();
Temp.prototype = null;
return result;
};
})();
}

if (typeof Object.defineProperty != 'function') {
Object.defineProperty = function defineProperty(object, property, descriptor) {
if ('value' in descriptor) {
object[property] = descriptor.value;
}
return object;
};
}

if (!Array.prototype.indexOf) {
Array.prototype.indexOf = function (searchElement, fromIndex) {
var k;
if (this == null) {
throw new TypeError('"this" is null or not defined');
}
var o = Object(this);
var len = o.length >>> 0;
if (len === 0) {
return -1;
}
var n = +fromIndex || 0;
if (Math.abs(n) === Infinity) {
n = 0;
}
if (n >= len) {
return -1;
}
k = Math.max(n >= 0 ? n : len - Math.abs(n), 0);
while (k < len) {
if (k in o && o[k] === searchElement) {
return k;
}
k++;
}
return -1;
};
}
})();
2 changes: 1 addition & 1 deletion src/linkify-element.js
Expand Up @@ -97,7 +97,7 @@ function linkifyElementHelper(element, opts, doc) {
let ignoreTags = opts.ignoreTags;

// Is this element already a link?
if (element.tagName === 'A' || ignoreTags.indexOf(element.tagName) >= 0) {
if (element.tagName === 'A' || options.contains(ignoreTags, element.tagName)) {
// No need to linkify
return element;
}
Expand Down
4 changes: 3 additions & 1 deletion src/linkify-html.js
@@ -1,6 +1,7 @@
import HTML5Tokenizer from './simple-html-tokenizer';
import * as linkify from './linkify';

const options = linkify.options;
const StartTag = 'StartTag';
const EndTag = 'EndTag';
const Chars = 'Chars';
Expand All @@ -27,7 +28,8 @@ export default function linkifyHtml(str, opts={}) {

// Ignore all the contents of ignored tags
let tagName = token.tagName.toUpperCase();
let isIgnored = tagName === 'A' || opts.ignoreTags.indexOf(tagName) >= 0;
let isIgnored = tagName === 'A' ||
options.contains(opts.ignoreTags, tagName);
if (!isIgnored) continue;

let preskipLen = linkifiedTokens.length;
Expand Down

0 comments on commit 75e673e

Please sign in to comment.