Squashed commit of the following:

commit 5cce0dbf60781b759f998a01546a759cbdea6bb7
Author: Nils Norman Haukås <nils@thunki.com>
Date:   Sat Jun 25 12:50:15 2016 +0200

    Add comment

commit b4e241f9845ff4e5ce3a1f4d295bab714f061ce7
Author: Nils Norman Haukås <nils@thunki.com>
Date:   Sat Jun 25 12:48:30 2016 +0200

    Update how menu is loaded when distributed as a plugin. Seems to load properly now.

commit ca28432c4717ebc035c754cca7b5fc691ee269d6
Author: Nils Norman Haukås <nils@thunki.com>
Date:   Sat Jun 25 12:46:28 2016 +0200

    remove uneeded deps from typings

commit 3ec733feaf82930d96b2d19d1cd40a95e0c0aab7
Author: Nils Norman Haukås <nils@thunki.com>
Date:   Sat Jun 25 11:40:02 2016 +0200

    removed gulp dependencies

commit 5a21e118a59c184f52c971fa2a9f023676372867
Author: Nils Norman Haukås <nils@thunki.com>
Date:   Wed Jun 22 23:15:36 2016 +0200

    added clean and build scripts to package.json which builds a dist folder

commit e755176a13005fc907617148c418dec793bc4c4a
Author: Nils Norman Haukås <nils@thunki.com>
Date:   Wed Jun 22 21:13:51 2016 +0200

    Added 'npm run server', which will fire up a test page that runs the existing plugin code.

commit 4fccd07c2ed9308c42d97f47837464a180e40f8d
Author: Nils Norman Haukås <nils@thunki.com>
Date:   Wed Jun 22 20:08:14 2016 +0200

    delete files that are no longer needed. Add comments to explain styling setup.

commit 227163df0834eb9b2d57270f2460263837a14212
Author: Nils Norman Haukås <nils@thunki.com>
Date:   Wed Jun 15 00:34:37 2016 +0200

    got test setup up and running. Fixed uuid and rangy import statements.

commit 41b73d35f6e8b12ab04fb04f312e524443689554
Author: Nils Norman Haukås <nils@thunki.com>
Date:   Wed Jun 8 23:03:32 2016 +0200

    kinda working. Still working on starting the application in test mode.

commit cd929b0acd71c486dd7a0ca0b18723f98faa401f
Author: Nils Norman Haukås <nils@thunki.com>
Date:   Sun May 29 22:44:45 2016 +0200

    added pageRebuilder for preparin the page when app is used as a chrome plugin. Still not quite working yet.

commit 722759ae5f5c93fea08570ad14155d741e8f8b63
Author: Nils Norman Haukås <nils@thunki.com>
Date:   Sun May 22 01:23:52 2016 +0200

    Managed to add a basic jspm setup.

commit 7b99c2ed8647f54b8d77d69d37d5f6d05b7f63cc
Author: Nils Norman Haukås <nils@thunki.com>
Date:   Sat May 21 13:13:10 2016 +0200

    Lots of rearranging code. Split up gulpfile for clarity. Updated typescript and gulp dependencies.
This commit is contained in:
Nils Norman Haukås 2016-06-25 20:16:17 +02:00
parent d5f5aba1aa
commit c6c1fbfe54
58 changed files with 1544 additions and 14504 deletions

3
.gitignore vendored
View file

@ -1,5 +1,6 @@
node_modules
jspm_packages
dist
tmp
*.zip
.idea/
.idea/

View file

@ -1,102 +0,0 @@
'use strict';
var gulp = require('gulp');
var $ = require('gulp-load-plugins')({
pattern: ['gulp-*', 'del', 'merge2'],
rename: {
'merge2': 'merge'
}
});
var browserSync = require('browser-sync').create();
var tsProject = $.typescript.createProject('tsconfig.json', {
sortOutput : true
});
gulp.task('scripts', function() {
var tsResult = gulp.src('src/*.ts')
.pipe($.sourcemaps.init())
.pipe($.typescript(tsProject));
return tsResult.js
.pipe($.concat('bundle.js'))
.pipe($.ngAnnotate())
.pipe($.sourcemaps.write()) // Now the sourcemaps are added to the .js file
.pipe(gulp.dest('tmp'));
});
// build project for serving up locally
gulp.task('tmp', ['scripts', 'dist-node-modules'], function () {
return gulp.src([
'src/**/*.html',
'src/**/*.css',
'src/load-menu-for-web-testing.js'
], {base: 'src'})
.pipe($.flatten())
.pipe(gulp.dest('tmp'));
});
// build project for loading up in Chrome
gulp.task('dist', ['tmp'], function () {
return $.merge([
gulp.src([
'tmp/**/*',
'!tmp/index.html',
'!tmp/load-menu-for-web-testing.js'
], {base: 'tmp'}),
gulp.src(
'src/plugin-specific/**/*',
{base: 'src/plugin-specific'})
])
.pipe(gulp.dest('dist'));
});
gulp.task('dist-node-modules', function () {
var cssDeps = gulp.src([
'node_modules/bootstrap/**/*',
'node_modules/jquery/**/*'
], {base: 'node_modules'});
var jsDeps = gulp.src([
'node_modules/angular/angular.js',
'node_modules/jquery/dist/jquery.js',
'node_modules/ngstorage/ngStorage.js',
'node_modules/node-uuid/uuid.js',
'node_modules/rangy/lib/rangy-core.js',
'node_modules/rangy/lib/rangy-serializer.js',
'node_modules/rangy/lib/rangy-selectionsaverestore.js',
'src/lodash.js'
], {base: 'node_modules'})
.pipe($.sourcemaps.init())
.pipe($.concat('vendor.js'))
.pipe($.sourcemaps.write());
return $.merge([cssDeps, jsDeps])
.pipe(gulp.dest('tmp/vendor'));
});
gulp.task('clean', function () {
return $.del(['tmp', 'dist']);
});
gulp.task('watch-plugin', ['dist'], function () {
gulp.watch("src/**/*", ['dist']);
});
gulp.task('serve', ['tmp'], function () {
// Serve files from the root of this project
browserSync.init({
server: {
baseDir: "./tmp"
},
notify: false
});
// add browserSync.reload to the tasks array to make
// all browsers reload after tasks are complete.
gulp.watch("src/**/*.ts", ['scripts']);
gulp.watch([
"src/**/*.html",
"src/**/*.css",
"src/**/*.js"
], ['tmp']);
gulp.watch("tmp/**/*").on("change", browserSync.reload);
});

13
build.sh Executable file
View file

@ -0,0 +1,13 @@
#!/bin/sh
#bundle all javascript, including deps
jspm bundle-sfx src/app/main.ts dist/app.js
#copy styles
cp -v src/app/style.css dist/
#copy html menu
cp -v src/app/menu/menu.tpl.html dist/
#copy plugin specifics
cp -v src/plugin-specific/* dist/

313
config.js Normal file
View file

@ -0,0 +1,313 @@
System.config({
baseURL: "/",
defaultJSExtensions: true,
transpiler: "typescript",
paths: {
"github:*": "jspm_packages/github/*",
"npm:*": "jspm_packages/npm/*"
},
packages: {
'src': {
defaultExtension: 'ts'
}
},
map: {
"angular": "github:angular/bower-angular@1.5.5",
"jquery": "npm:jquery@2.2.4",
"lodash": "npm:lodash@4.12.0",
"ngstorage": "npm:ngstorage@0.3.10",
"rangy": "npm:rangy@1.3.0",
"rangy-serializer": "npm:rangy@1.3.0/lib/rangy-serializer.js",
"rangy-selectionsaverestore": "npm:rangy@1.3.0/lib/rangy-selectionsaverestore.js",
"typescript": "npm:typescript@1.8.10",
"node-uuid": "npm:uuid@2.0.2",
"uuid": "npm:uuid@2.0.2",
"github:jspm/nodelibs-assert@0.1.0": {
"assert": "npm:assert@1.4.0"
},
"github:jspm/nodelibs-buffer@0.1.0": {
"buffer": "npm:buffer@3.6.0"
},
"github:jspm/nodelibs-constants@0.1.0": {
"constants-browserify": "npm:constants-browserify@0.0.1"
},
"github:jspm/nodelibs-crypto@0.1.0": {
"crypto-browserify": "npm:crypto-browserify@3.11.0"
},
"github:jspm/nodelibs-events@0.1.1": {
"events": "npm:events@1.0.2"
},
"github:jspm/nodelibs-os@0.1.0": {
"os-browserify": "npm:os-browserify@0.1.2"
},
"github:jspm/nodelibs-path@0.1.0": {
"path-browserify": "npm:path-browserify@0.0.0"
},
"github:jspm/nodelibs-process@0.1.2": {
"process": "npm:process@0.11.3"
},
"github:jspm/nodelibs-stream@0.1.0": {
"stream-browserify": "npm:stream-browserify@1.0.0"
},
"github:jspm/nodelibs-string_decoder@0.1.0": {
"string_decoder": "npm:string_decoder@0.10.31"
},
"github:jspm/nodelibs-util@0.1.0": {
"util": "npm:util@0.10.3"
},
"github:jspm/nodelibs-vm@0.1.0": {
"vm-browserify": "npm:vm-browserify@0.0.4"
},
"npm:asn1.js@4.6.0": {
"assert": "github:jspm/nodelibs-assert@0.1.0",
"bn.js": "npm:bn.js@4.11.3",
"buffer": "github:jspm/nodelibs-buffer@0.1.0",
"fs": "github:jspm/nodelibs-fs@0.1.2",
"inherits": "npm:inherits@2.0.1",
"minimalistic-assert": "npm:minimalistic-assert@1.0.0",
"vm": "github:jspm/nodelibs-vm@0.1.0"
},
"npm:assert@1.4.0": {
"assert": "github:jspm/nodelibs-assert@0.1.0",
"buffer": "github:jspm/nodelibs-buffer@0.1.0",
"buffer-shims": "npm:buffer-shims@1.0.0",
"process": "github:jspm/nodelibs-process@0.1.2",
"util": "npm:util@0.10.3"
},
"npm:bn.js@4.11.3": {
"buffer": "github:jspm/nodelibs-buffer@0.1.0"
},
"npm:browserify-aes@1.0.6": {
"buffer": "github:jspm/nodelibs-buffer@0.1.0",
"buffer-xor": "npm:buffer-xor@1.0.3",
"cipher-base": "npm:cipher-base@1.0.2",
"create-hash": "npm:create-hash@1.1.2",
"crypto": "github:jspm/nodelibs-crypto@0.1.0",
"evp_bytestokey": "npm:evp_bytestokey@1.0.0",
"fs": "github:jspm/nodelibs-fs@0.1.2",
"inherits": "npm:inherits@2.0.1",
"systemjs-json": "github:systemjs/plugin-json@0.1.2"
},
"npm:browserify-cipher@1.0.0": {
"browserify-aes": "npm:browserify-aes@1.0.6",
"browserify-des": "npm:browserify-des@1.0.0",
"buffer": "github:jspm/nodelibs-buffer@0.1.0",
"crypto": "github:jspm/nodelibs-crypto@0.1.0",
"evp_bytestokey": "npm:evp_bytestokey@1.0.0"
},
"npm:browserify-des@1.0.0": {
"buffer": "github:jspm/nodelibs-buffer@0.1.0",
"cipher-base": "npm:cipher-base@1.0.2",
"crypto": "github:jspm/nodelibs-crypto@0.1.0",
"des.js": "npm:des.js@1.0.0",
"inherits": "npm:inherits@2.0.1"
},
"npm:browserify-rsa@4.0.1": {
"bn.js": "npm:bn.js@4.11.3",
"buffer": "github:jspm/nodelibs-buffer@0.1.0",
"constants": "github:jspm/nodelibs-constants@0.1.0",
"crypto": "github:jspm/nodelibs-crypto@0.1.0",
"randombytes": "npm:randombytes@2.0.3"
},
"npm:browserify-sign@4.0.0": {
"bn.js": "npm:bn.js@4.11.3",
"browserify-rsa": "npm:browserify-rsa@4.0.1",
"buffer": "github:jspm/nodelibs-buffer@0.1.0",
"create-hash": "npm:create-hash@1.1.2",
"create-hmac": "npm:create-hmac@1.1.4",
"crypto": "github:jspm/nodelibs-crypto@0.1.0",
"elliptic": "npm:elliptic@6.2.5",
"inherits": "npm:inherits@2.0.1",
"parse-asn1": "npm:parse-asn1@5.0.0",
"stream": "github:jspm/nodelibs-stream@0.1.0"
},
"npm:buffer-shims@1.0.0": {
"buffer": "github:jspm/nodelibs-buffer@0.1.0"
},
"npm:buffer-xor@1.0.3": {
"buffer": "github:jspm/nodelibs-buffer@0.1.0",
"systemjs-json": "github:systemjs/plugin-json@0.1.2"
},
"npm:buffer@3.6.0": {
"base64-js": "npm:base64-js@0.0.8",
"child_process": "github:jspm/nodelibs-child_process@0.1.0",
"fs": "github:jspm/nodelibs-fs@0.1.2",
"ieee754": "npm:ieee754@1.1.6",
"isarray": "npm:isarray@1.0.0",
"process": "github:jspm/nodelibs-process@0.1.2"
},
"npm:cipher-base@1.0.2": {
"buffer": "github:jspm/nodelibs-buffer@0.1.0",
"inherits": "npm:inherits@2.0.1",
"stream": "github:jspm/nodelibs-stream@0.1.0",
"string_decoder": "github:jspm/nodelibs-string_decoder@0.1.0"
},
"npm:constants-browserify@0.0.1": {
"systemjs-json": "github:systemjs/plugin-json@0.1.2"
},
"npm:core-util-is@1.0.2": {
"buffer": "github:jspm/nodelibs-buffer@0.1.0"
},
"npm:create-ecdh@4.0.0": {
"bn.js": "npm:bn.js@4.11.3",
"buffer": "github:jspm/nodelibs-buffer@0.1.0",
"crypto": "github:jspm/nodelibs-crypto@0.1.0",
"elliptic": "npm:elliptic@6.2.5"
},
"npm:create-hash@1.1.2": {
"buffer": "github:jspm/nodelibs-buffer@0.1.0",
"cipher-base": "npm:cipher-base@1.0.2",
"crypto": "github:jspm/nodelibs-crypto@0.1.0",
"fs": "github:jspm/nodelibs-fs@0.1.2",
"inherits": "npm:inherits@2.0.1",
"ripemd160": "npm:ripemd160@1.0.1",
"sha.js": "npm:sha.js@2.4.5"
},
"npm:create-hmac@1.1.4": {
"buffer": "github:jspm/nodelibs-buffer@0.1.0",
"create-hash": "npm:create-hash@1.1.2",
"crypto": "github:jspm/nodelibs-crypto@0.1.0",
"inherits": "npm:inherits@2.0.1",
"stream": "github:jspm/nodelibs-stream@0.1.0"
},
"npm:crypto-browserify@3.11.0": {
"browserify-cipher": "npm:browserify-cipher@1.0.0",
"browserify-sign": "npm:browserify-sign@4.0.0",
"create-ecdh": "npm:create-ecdh@4.0.0",
"create-hash": "npm:create-hash@1.1.2",
"create-hmac": "npm:create-hmac@1.1.4",
"diffie-hellman": "npm:diffie-hellman@5.0.2",
"inherits": "npm:inherits@2.0.1",
"pbkdf2": "npm:pbkdf2@3.0.4",
"public-encrypt": "npm:public-encrypt@4.0.0",
"randombytes": "npm:randombytes@2.0.3"
},
"npm:des.js@1.0.0": {
"buffer": "github:jspm/nodelibs-buffer@0.1.0",
"inherits": "npm:inherits@2.0.1",
"minimalistic-assert": "npm:minimalistic-assert@1.0.0"
},
"npm:diffie-hellman@5.0.2": {
"bn.js": "npm:bn.js@4.11.3",
"buffer": "github:jspm/nodelibs-buffer@0.1.0",
"crypto": "github:jspm/nodelibs-crypto@0.1.0",
"miller-rabin": "npm:miller-rabin@4.0.0",
"randombytes": "npm:randombytes@2.0.3",
"systemjs-json": "github:systemjs/plugin-json@0.1.2"
},
"npm:elliptic@6.2.5": {
"bn.js": "npm:bn.js@4.11.3",
"brorand": "npm:brorand@1.0.5",
"hash.js": "npm:hash.js@1.0.3",
"inherits": "npm:inherits@2.0.1",
"systemjs-json": "github:systemjs/plugin-json@0.1.2"
},
"npm:evp_bytestokey@1.0.0": {
"buffer": "github:jspm/nodelibs-buffer@0.1.0",
"create-hash": "npm:create-hash@1.1.2",
"crypto": "github:jspm/nodelibs-crypto@0.1.0"
},
"npm:hash.js@1.0.3": {
"inherits": "npm:inherits@2.0.1"
},
"npm:inherits@2.0.1": {
"util": "github:jspm/nodelibs-util@0.1.0"
},
"npm:lodash@4.12.0": {
"buffer": "github:jspm/nodelibs-buffer@0.1.0",
"process": "github:jspm/nodelibs-process@0.1.2"
},
"npm:miller-rabin@4.0.0": {
"bn.js": "npm:bn.js@4.11.3",
"brorand": "npm:brorand@1.0.5"
},
"npm:os-browserify@0.1.2": {
"os": "github:jspm/nodelibs-os@0.1.0"
},
"npm:parse-asn1@5.0.0": {
"asn1.js": "npm:asn1.js@4.6.0",
"browserify-aes": "npm:browserify-aes@1.0.6",
"buffer": "github:jspm/nodelibs-buffer@0.1.0",
"create-hash": "npm:create-hash@1.1.2",
"evp_bytestokey": "npm:evp_bytestokey@1.0.0",
"pbkdf2": "npm:pbkdf2@3.0.4",
"systemjs-json": "github:systemjs/plugin-json@0.1.2"
},
"npm:path-browserify@0.0.0": {
"process": "github:jspm/nodelibs-process@0.1.2"
},
"npm:pbkdf2@3.0.4": {
"buffer": "github:jspm/nodelibs-buffer@0.1.0",
"child_process": "github:jspm/nodelibs-child_process@0.1.0",
"create-hmac": "npm:create-hmac@1.1.4",
"crypto": "github:jspm/nodelibs-crypto@0.1.0",
"path": "github:jspm/nodelibs-path@0.1.0",
"process": "github:jspm/nodelibs-process@0.1.2",
"systemjs-json": "github:systemjs/plugin-json@0.1.2"
},
"npm:process@0.11.3": {
"assert": "github:jspm/nodelibs-assert@0.1.0"
},
"npm:public-encrypt@4.0.0": {
"bn.js": "npm:bn.js@4.11.3",
"browserify-rsa": "npm:browserify-rsa@4.0.1",
"buffer": "github:jspm/nodelibs-buffer@0.1.0",
"create-hash": "npm:create-hash@1.1.2",
"crypto": "github:jspm/nodelibs-crypto@0.1.0",
"parse-asn1": "npm:parse-asn1@5.0.0",
"randombytes": "npm:randombytes@2.0.3"
},
"npm:randombytes@2.0.3": {
"buffer": "github:jspm/nodelibs-buffer@0.1.0",
"crypto": "github:jspm/nodelibs-crypto@0.1.0",
"process": "github:jspm/nodelibs-process@0.1.2"
},
"npm:readable-stream@1.1.14": {
"buffer": "github:jspm/nodelibs-buffer@0.1.0",
"core-util-is": "npm:core-util-is@1.0.2",
"events": "github:jspm/nodelibs-events@0.1.1",
"inherits": "npm:inherits@2.0.1",
"isarray": "npm:isarray@0.0.1",
"process": "github:jspm/nodelibs-process@0.1.2",
"stream-browserify": "npm:stream-browserify@1.0.0",
"string_decoder": "npm:string_decoder@0.10.31"
},
"npm:ripemd160@1.0.1": {
"buffer": "github:jspm/nodelibs-buffer@0.1.0",
"process": "github:jspm/nodelibs-process@0.1.2"
},
"npm:sha.js@2.4.5": {
"buffer": "github:jspm/nodelibs-buffer@0.1.0",
"fs": "github:jspm/nodelibs-fs@0.1.2",
"inherits": "npm:inherits@2.0.1",
"process": "github:jspm/nodelibs-process@0.1.2"
},
"npm:stream-browserify@1.0.0": {
"events": "github:jspm/nodelibs-events@0.1.1",
"inherits": "npm:inherits@2.0.1",
"readable-stream": "npm:readable-stream@1.1.14"
},
"npm:string_decoder@0.10.31": {
"buffer": "github:jspm/nodelibs-buffer@0.1.0"
},
"npm:typescript@1.8.10": {
"os": "github:jspm/nodelibs-os@0.1.0"
},
"npm:util@0.10.3": {
"inherits": "npm:inherits@2.0.1",
"process": "github:jspm/nodelibs-process@0.1.2"
},
"npm:uuid@2.0.2": {
"assert": "github:jspm/nodelibs-assert@0.1.0",
"child_process": "github:jspm/nodelibs-child_process@0.1.0",
"crypto": "github:jspm/nodelibs-crypto@0.1.0",
"os": "github:jspm/nodelibs-os@0.1.0",
"util": "github:jspm/nodelibs-util@0.1.0"
},
"npm:vm-browserify@0.0.4": {
"indexof": "npm:indexof@0.0.1"
}
}
});

View file

@ -4,7 +4,9 @@
"description": "Make the meaning clear. This plugin enables semantic tagging of web content.",
"main": "Gulpfile.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
"clean": "rm -r dist",
"build": "./build.sh",
"server": "browser-sync start -b chromium-browser --startPath test/ --server --files 'src/**/*'"
},
"repository": {
"type": "git",
@ -23,23 +25,19 @@
},
"homepage": "https://github.com/nilsnh/tag-youre-it",
"dependencies": {
"angular": "^1.4.7",
"bootstrap": "^3.3.5",
"browser-sync": "^2.9.6",
"del": "^2.0.2",
"gulp": "^3.9.0",
"gulp-concat": "^2.6.0",
"gulp-flatten": "^0.2.0",
"gulp-load-plugins": "^1.0.0",
"gulp-ng-annotate": "^1.1.0",
"gulp-sourcemaps": "^1.6.0",
"gulp-typescript": "^2.9.2",
"jquery": "^2.1.4",
"lodash": "^3.10.1",
"merge2": "^0.3.6",
"ngstorage": "^0.3.10",
"node-uuid": "^1.4.7",
"rangy": "^1.3.0",
"uuid": "^2.0.1"
"browser-sync": "^2.9.6"
},
"jspm": {
"dependencies": {
"angular": "github:angular/bower-angular@^1.5.5",
"jquery": "npm:jquery@^2.2.4",
"lodash": "npm:lodash@^4.12.0",
"ngstorage": "npm:ngstorage@^0.3.10",
"rangy": "npm:rangy@^1.3.0",
"uuid": "npm:uuid@^2.0.2"
},
"devDependencies": {
"typescript": "npm:typescript@^1.6.2"
}
}
}

18
src/app/globalAugments.d.ts vendored Normal file
View file

@ -0,0 +1,18 @@
// Ensure this is treated as a module.
export {};
declare global {
interface Window {
tagitTestMode: boolean;
}
interface RangyStatic {
init: () => void;
saveSelection: any;
removeMarkers: any;
serializeRange: any;
deserializeRange: any;
restoreSelection: any;
}
}

View file

@ -0,0 +1,9 @@
export function AppConfigInitializer ($logProvider: ng.ILogProvider) {
$logProvider.debugEnabled(true);
}
export class AppConfigService {
serverUrl = 'https://imdb.uib.no/lexitags/lexitags/';
}

View file

@ -0,0 +1,37 @@
export interface ISynset {
config: Object,
data: {
senses: string[]
}
}
export interface IVMScope extends angular.IScope {
vm: Object;
}
export interface ISense {
explanation: string,
rank: number,
related: string,
senseid: string,
source: string,
word: string
}
/*
context: represents the text context of the tag
selectionRange: selectionRangeObject
*/
export interface ISenseTag {
id: string,
userEmail: string;
sense: ISense;
context: string;
iframeIndex: number;
wordThatWasTagged: string;
serializedSelectionRange: string;
deserializedRange?: Range;
urlOfPageThatWasTagged: string;
}

71
src/app/main.ts Normal file
View file

@ -0,0 +1,71 @@
console.log('Trying to load TagIt menu');
import {
BackendService,
WebPageService,
TagStorageService,
FileService} from './services/index';
import {AppConfigInitializer, AppConfigService} from "./index.appConfig";
import {MenuCtrl} from './menu/menu.controller';
import {preparePage} from './pageRebuilder';
import angular from 'angular';
import 'rangy';
import 'uuid';
import 'ngstorage';
console.log('Finished importing');
if (!window.tagitTestMode) {
preparePage(loadAngular);
}
else {
loadAngular();
}
function loadAngular() {
angular.module('tagit', ['ngStorage'])
.config(AppConfigInitializer)
.service('AppConfigService', AppConfigService)
.service('BackendService', BackendService)
.service('WebPageService', WebPageService)
.service('TagStorageService', TagStorageService)
.service('FileService', FileService)
.controller('MenuCtrl', MenuCtrl)
.controller('TestCtrl', function () {
var vm = this;
vm.test = 'hello world';
vm.alert = function () {
alert('test alert');
}
});
angular.bootstrap(
(<HTMLIFrameElement>document.getElementById("tagit-iframe"))
.contentDocument.getElementById('tagit-menu'),
['tagit']);
setupChromeListener()
console.log('TagIt menu loaded');
}
/**
* Enable this script that is loaded
* on the page to receive messages from the plugin code
* running in the background.
*/
function setupChromeListener() {
if (typeof chrome === 'undefined') return; //do nothing
chrome.runtime.onMessage.addListener(
function (request, sender, sendResponse) {
console.log(sender.tab ?
"from a content script:" + sender.tab.url :
"from the extension");
if (request === 'isMenuOpen') {
sendResponse(true);
}
}
);
}

View file

@ -0,0 +1,141 @@
'use strict';
import {
BackendService,
WebPageService,
TagStorageService,
FileService} from '../services/index';
import {IVMScope, ISense} from '../index.interfaces';
export class MenuCtrl {
selectedWord = "";
senses: Object[];
backendService: BackendService;
webPageService: WebPageService;
tagStorageService: TagStorageService;
fileService: FileService;
$log: ng.ILogService;
$scope: ng.IScope;
/* @ngInject */
constructor($scope: IVMScope, $log: angular.ILogService,
BackendService: BackendService,
WebPageService: WebPageService,
TagStorageService: TagStorageService,
FileService: FileService) {
$scope.vm = this;
this.$log = $log;
this.$scope = $scope;
this.backendService = BackendService;
this.webPageService = WebPageService;
this.tagStorageService = TagStorageService;
this.fileService = FileService;
this.$scope.$on('wordWasSelected', (event, selectedWord) => {
this.$log.debug(`Menucontroller received wordWasSelected event for: ${selectedWord}`);
this.onWordSelectedEvent(selectedWord);
});
this.$scope.$on('wordWasSelected', (event, selectedWord) => {
this.$log.debug('a word was selected' + selectedWord);
this.onWordSelectedEvent(selectedWord);
});
// Reload existing tags
var tagsToLoad = this.tagStorageService.loadTagsForCurrentPage();
this.$log.debug('these tags were found in storage');
this.$log.debug(tagsToLoad);
this.webPageService.readdTagsToPage(tagsToLoad);
}
/**
* Fired when user selects a sense amongst the senses
* returned from the backend.
*/
onSenseSelect(sense: ISense) {
//remove all tags so that new tag range is serialized
//based on a document without any highlights
this.webPageService.removeAllTagsFromPage(() => {
//initialize and save the new tag
var senseTag = this.webPageService.initializeNewTag(sense);
this.tagStorageService.saveTag(senseTag);
// deactivate backendService for now.
// this.backendService.sendTaggedDataToServer(senseTag);
//re-add tags, with new tag. Clear menu options.
this.webPageService.readdTagsToPage(
this.tagStorageService.loadTagsForCurrentPage()
);
this.clearMenuVariables();
});
}
/**
* Enables a clickable button to download tags as a json file.
*/
downloadTagsForPage() {
if (typeof chrome === 'undefined') {
this.$log.debug('Did not find chrome facilities. Can\'t download.')
return; //do nothing
}
this.fileService.saveFile(this.tagStorageService.loadTagsForCurrentPage());
}
downloadAllTagsForDomain() {
if (typeof chrome === 'undefined') {
this.$log.debug('Did not find chrome facilities. Can\'t download.')
return; //do nothing
}
this.fileService.saveFile(this.tagStorageService.loadAllTagsInLocalStorage());
}
/**
* Enables clickable link for removing tags.
*/
removeTagsFromLocalStorage() {
if (confirm('Really delete tags from the current page?')) {
this.webPageService.removeAllTagsFromPage(() => {
this.tagStorageService.deleteTagsFromCurrentPage()
})
}
}
onWordSelectedEvent = (newWord: string) => {
if (countWords(newWord) > 2) {
this.selectedWord = "Wops! Plugin can't handle more than two words.";
this.senses = [];
}
else if (newWord.length === 0) {
this.clearMenuVariables();
}
else {
this.selectedWord = newWord;
this.backendService.callServer(newWord)
.then((synsets: any) => {
this.$log.debug(synsets);
this.senses = synsets.data.senses;
});
}
function countWords(wordWithUnderscores: string) {
return wordWithUnderscores.split("_").length;
}
}
onWordDeSelectedEvent = () => {
this.$log.debug("onWordDeSelected");
this.clearMenuVariables()
}
clearMenuVariables() {
this.selectedWord = "";
this.senses = [];
}
}

View file

@ -2,9 +2,21 @@
<html>
<head>
<title>This will be an iframe programmatically included into a parent page.</title>
<title></title>
<style>
/*
This styling is embedded due to the test setup.
When used as a Chrome plugin the main style can be
inserted into all the iframes. But when testing it's
not that easy to dynamically insert the main style into
this file.
So all the styles necessary to style the internals
of this menu is included here instead of the main style.css.
*/
.tagit-menu {
background-color: #FFF;
}

6
src/app/moduleAugments.d.ts vendored Normal file
View file

@ -0,0 +1,6 @@
declare module "rangy" {
export = rangy;
}
declare var rangy: RangyStatic;

69
src/app/pageRebuilder.ts Normal file
View file

@ -0,0 +1,69 @@
import $ from 'jquery';
import _ from 'lodash';
/**
* To prepare the page for running our app
* we reload the page inside an iframe connected to the
* top document. We then add a second iframe that will
* house our app menu.
*/
export function preparePage(callback) {
const done = _.after(2, () => {
console.log('done rebuilding page')
callback()
});
reloadPageInIframe(done);
loadMenu(done);
}
function reloadPageInIframe(done) {
//add a helper class to aid in styling later.
$('html').addClass('tagit-top-wrapper');
/**
* If the page is using a frameset
* we'll need to remove it and
* insert a new body tag instead.
*/
if ($('frameset').length > 0) {
$('frameset').remove();
var newbody = document.createElement("body");
$('html').append(newbody);
} else {
$('body').children().remove();
}
var iframeMainContent = <extendedHTMLIFrameElement> document.createElement('iframe');
iframeMainContent.id = 'tagit-body';
iframeMainContent.className = 'tagit-body';
iframeMainContent.src = window.location.href;
iframeMainContent.seamless = 'seamless';
iframeMainContent.frameBorder = "0";
iframeMainContent.onload = done;
//reinsert page this time inside an iframe
$('body').append(iframeMainContent);
}
function loadMenu(done) {
$.get(chrome.extension.getURL('menu.tpl.html'), function (htmlData) {
var iframeMenu = <extendedHTMLIFrameElement> document.createElement('iframe');
iframeMenu.id = 'tagit-iframe';
iframeMenu.srcdoc = htmlData;
iframeMenu.seamless = 'seamless';
iframeMenu.frameBorder = "0";
iframeMenu.className = 'tagit-iframe';
iframeMenu.onload = done;
// iframe.sandbox = 'allow-same-origin allow-top-navigation allow-scripts';
$('.tagit-body').before(iframeMenu);
});
}
interface extendedHTMLIFrameElement extends HTMLIFrameElement {
srcdoc: any;
seamless: string;
}

View file

@ -0,0 +1,58 @@
'use strict';
import {AppConfigService} from '../index.appConfig';
import {ISenseTag} from '../index.interfaces';
/**
* Service that is responsible for talking to the
* backend server.
*/
export class BackendService {
$http: ng.IHttpService;
$log: ng.ILogService;
$q: ng.IQService;
private serverUrl: string = null;
private previousCall: string;
/* @ngInject */
constructor($http: ng.IHttpService, $q: ng.IQService, $log: ng.ILogService, AppConfigService: AppConfigService) {
this.$http = $http;
this.$log = $log;
this.$q = $q;
this.serverUrl = AppConfigService.serverUrl;
}
callServer(word: string) {
if (!word) {
return this.$q.reject('no use calling server, there is no queryword.')
} else if (this.previousCall === word) {
var errMsg = `callServer has already been called with word: ${word}`;
this.$log.debug(errMsg)
return this.$q.reject(errMsg);
}
//alright let's make this query!
this.previousCall = word;
return this.$http.get(this.serverUrl + word);
}
sendTaggedDataToServer(senseTag: ISenseTag) {
this.$log.debug('sendTaggedDataToServer() was called');
this.$log.debug('would have sent this to the server:');
this.$log.debug(senseTag);
this.$log.debug('please uncomment code for actually sending to server');
// this.$http.post("example.org", senseTag)
// .then((response) => {
// this.$log.debug('successfully posted to server. Response:');
// this.$log.debug(response);
// })
// .catch((error) => {
// this.$log.error('something went wrong when posting to server');
// this.$log.error(error);
// });
}
}

View file

@ -0,0 +1,31 @@
'use strict';
import {ISenseTag} from '../index.interfaces';
//Responsible for saving.
export class FileService {
$log: ng.ILogService;
/* @ngInject */
constructor($log: ng.ILogService) {
this.$log = $log;
}
saveFile(content: ISenseTag[]) {
var json = JSON.stringify(content, null, 2);
var blob = new Blob([json], { type: "application/json" });
var url = URL.createObjectURL(blob);
var a = <any>document.createElement('a');
var date = new Date();
a.download = `
tags downloaded for ${window.location.hostname}
time of download ${date.toLocaleString()}
.json`
.replace('\n', '')
a.href = url;
a.click();
URL.revokeObjectURL(url); //Explicitly release obj from memory.
}
}

View file

@ -0,0 +1,4 @@
export * from './backend.service';
export * from './file.service';
export * from './tagStorage.service';
export * from './webpage.service';

View file

@ -0,0 +1,72 @@
'use strict';
import {ISenseTag} from '../index.interfaces';
// responsible for saving and loading
// any tags related to the current page
export class TagStorageService {
$http: ng.IHttpService;
$log: ng.ILogService;
$localStorage: { tagStorage: ISenseTag[] };
/* @ngInject */
constructor($http: ng.IHttpService, $log: ng.ILogService,
$localStorage: any) {
this.$http = $http;
this.$log = $log;
this.$localStorage = $localStorage;
if (window.location.href.indexOf("tagitreset") !== -1) {
this.deleteTagsFromCurrentPage(); // reset tag storage
this.$log.debug("Resetting tags for this page");
}
if (!this.$localStorage.tagStorage) {
this.$localStorage.tagStorage = [];
}
}
deleteTagById(uuid: string) {
this.$log.debug('deleting tag from localstorage with uuid: ' + uuid);
var newList: ISenseTag[] = [];
var tag: ISenseTag;
for (var i = 0; i < this.$localStorage.tagStorage.length; i++) {
tag = this.$localStorage.tagStorage[i];
if (tag.id !== uuid) {
newList.push(tag);
}
}
this.$localStorage.tagStorage = newList;
}
deleteTagsFromCurrentPage() {
this.$log.debug('deleting tags');
this.$localStorage.tagStorage =
this.$localStorage.tagStorage.filter(
(tag: ISenseTag) => tag.urlOfPageThatWasTagged !== window.location.href)
}
saveTag(tagToSave: ISenseTag) {
this.$log.debug('saving tag in localstorage:');
this.$log.debug(tagToSave);
this.$localStorage.tagStorage.push(tagToSave);
}
loadTagsForCurrentPage(): ISenseTag[] {
this.$log.debug('loadTagsForCurrentPage');
return this.$localStorage.tagStorage
.filter((tag: ISenseTag) =>
tag.urlOfPageThatWasTagged === window.location.href
);
}
/**
* Loads all tags in localstorage (for the current domain).
*/
loadAllTagsInLocalStorage() {
this.$log.debug('loadAllTagsInLocalStorage');
return this.$localStorage.tagStorage
}
}

View file

@ -0,0 +1,285 @@
'use strict';
import {TagStorageService} from './tagStorage.service';
import {ISense, ISenseTag} from '../index.interfaces';
import _ from 'lodash';
import 'rangy-serializer';
import 'rangy-selectionsaverestore';
import uuid from 'node-uuid';
import rangy from 'rangy';
/**
* This service is responsible for interfacing with the content
* that we want to tag. It injects/removes tags and listens for clicks.
*/
export class WebPageService {
$log: ng.ILogService;
// when clicking the menu to select a synset
// we need to remember what the currently selected word was
tagStorageService: TagStorageService;
rootScopeService: ng.IRootScopeService;
savedSelection: Object;
savedText: string;
listOfFramesWithContent: (HTMLFrameElement | HTMLIFrameElement)[] = [];
/* @ngInject */
constructor($log: ng.ILogService, TagStorageService: TagStorageService, $rootScope: ng.IRootScopeService) {
this.$log = $log;
this.tagStorageService = TagStorageService;
this.rootScopeService = $rootScope;
this.wireUpListener();
rangy.init();
}
/**
* The click listening function placed on each of the iframes
* we capture. We then listen for clicks and check if a word
* was selected.
*/
clickhandler = (evt: Event) => {
this.$log.debug('A click happened!');
var documentThatWasClicked = evt.srcElement.ownerDocument;
if (!documentThatWasClicked.hasFocus()) {
return true;
}
else if (wasRemoveTagButtonClicked(evt)) {
this.$log.debug('remove tag button was clicked');
removeTagFromWebAndStorage(evt, this.tagStorageService);
}
else if (documentThatWasClicked.getSelection().toString() !== '') {
resetSavedSelection(this.savedSelection);
this.savedSelection = rangy.saveSelection(documentThatWasClicked);
this.savedText = joinLongWords(documentThatWasClicked.getSelection().toString());
this.rootScopeService.$broadcast('wordWasSelected', this.savedText);
} else {
resetSavedSelection(this.savedSelection);
this.savedText = '';
this.rootScopeService.$broadcast('wordWasDeSelected', null);
}
/**
* Remove markers to ensure a clean page before
* adding markers for a new page.
*/
function resetSavedSelection(savedSelection) {
if (savedSelection) {
rangy.removeMarkers(savedSelection);
}
}
function joinLongWords(possiblyLongWord: string) {
return possiblyLongWord.trim().split(" ").join("_");
}
function wasRemoveTagButtonClicked(evt: any) {
return evt.target.className === 'js-tagit-remove-tag';
}
//todo ensure removing a tag
function removeTagFromWebAndStorage(evt: Event, tagStorageService: TagStorageService) {
var target = <HTMLElement>evt.target;
var theOriginalTextNode = target.previousSibling;
var theSurroundingSpanElement = target.parentElement;
var parentElement = theSurroundingSpanElement.parentElement;
tagStorageService.deleteTagById(theSurroundingSpanElement.id);
parentElement.replaceChild(theOriginalTextNode, theSurroundingSpanElement);
parentElement.normalize();
}
}
/**
* Find one or more iframes in which content has been captured.
* We then place click listeners on each of the frames.
*/
wireUpListener() {
const tagitBodyIframe = <HTMLIFrameElement>parent.document.getElementById('tagit-body');
const tagitBodyIframeDoc = tagitBodyIframe.contentDocument;
if (tagitBodyIframeDoc.getElementsByTagName('frameset').length > 0) {
_.map(tagitBodyIframeDoc.getElementsByTagName('frame'),
(frame) => { this.listOfFramesWithContent.push(frame) });
} else {
this.listOfFramesWithContent.push(tagitBodyIframe);
}
_.map(this.listOfFramesWithContent, (frame: HTMLIFrameElement) => {
frame.contentDocument.addEventListener('click', this.clickhandler, false);
});
}
/**
* Will loop through all content iframes and empty them for
* tags added by us. This is because we need to position a
* new tag in relation to a clean DOM.
* */
removeAllTagsFromPage(callback: () => void) {
//loop that will keep asking for spans to remove
//until they are all gone.
const done = _.after(this.listOfFramesWithContent.length, () => {
callback();
});
_.map(this.listOfFramesWithContent, (iframe) => {
removeTagsFromIframe(iframe, done);
});
function removeTagsFromIframe(iframe: HTMLFrameElement | HTMLIFrameElement,
callback: () => void) {
while (iframe.contentDocument.getElementsByClassName('tagit-tag').length > 0) {
var spanElement = iframe.contentDocument.getElementsByClassName('tagit-tag')[0];
var spanElementParent = spanElement.parentNode;
spanElementParent.replaceChild(
spanElement.firstChild,
spanElement);
/**
* call normalize on the parent element so that it will join up
* any text nodes that might have become chopped up by
* tags and selection markers.
* */
spanElementParent.normalize();
}
callback();
}
}
/**
* Handles adding tags to page which needs to happen in a
* bottom up order, so that all the tags find their right place.
*/
readdTagsToPage(tagsToLoad: ISenseTag[]) {
this.$log.debug('readdTagsToPage()');
//first deselect all places before we go to work
this.removeAllRanges();
/**
* The tags need to be loaded (deserialized) so that
* they can be inserted properly. Deserialization might
* fail if the page has changed since it was tagged. Thus
* we remove tags that fail to load.
*/
tagsToLoad = _.filter(tagsToLoad, (tagToLoad) => {
try {
tagToLoad.deserializedRange = rangy.deserializeRange(
tagToLoad.serializedSelectionRange,
this.listOfFramesWithContent[tagToLoad.iframeIndex].contentDocument.documentElement,
this.listOfFramesWithContent[tagToLoad.iframeIndex]
);
return true;
} catch (e) {
var errorMsg = `Error in rangy.js: Was not able to deserialize range.
In other words: The page might have changed. Is not able
to determine where this tag should have been placed.`
this.$log.debug(errorMsg);
this.$log.debug("Couldn't load: " + tagToLoad.sense.word);
this.$log.debug(e);
return false;
}
})
this.$log.debug('finished deserializing tags');
/**
* sort tags descending (highest number = furthest down on page).
*/
tagsToLoad = _.sortBy(tagsToLoad, (tag: ISenseTag) => {
return tag.deserializedRange.startOffset;
});
this.$log.debug('finished sorting tags');
/**
* Loop through loaded tags and insert them to the page.
*/
_.map(tagsToLoad, (tag: ISenseTag) => {
if (tag.deserializedRange) {
this.surroundRangeWithSpan(
this.listOfFramesWithContent[tag.iframeIndex].contentDocument,
tag.sense,
tag.deserializedRange,
tag.id);
}
});
this.$log.debug('finished adding tags to page');
this.removeAllRanges();
}
initializeNewTag = (sense: ISense): ISenseTag => {
this.$log.debug('initializeNewTag');
/**
* first eliminate all selections to avoid confusion
* with other iframes.
*/
this.removeAllRanges();
rangy.restoreSelection(this.savedSelection);
var iframeOfInterest = getFrameContainingSelection(this.listOfFramesWithContent);
const selection = iframeOfInterest.contentDocument.getSelection();
var range: Range = selection.getRangeAt(0);
var serializedRange = rangy.serializeRange(range, true,
iframeOfInterest.contentDocument.documentElement);
var generatedUuid: string = uuid.v4();
var parentElement = <HTMLElement>range.commonAncestorContainer;
return {
id: generatedUuid,
userEmail: 'testEmail',
sense: sense,
wordThatWasTagged: selection.toString(),
iframeIndex: getIframeIndex(this.listOfFramesWithContent, iframeOfInterest),
context: parentElement.textContent,
serializedSelectionRange: serializedRange,
urlOfPageThatWasTagged: window.location.href
}
/**
* Some pages might have many frames with content. Thus we
* need to loop through them, identify which document contains the current
* selection and then save its index in our list.
*/
function getIframeIndex(iframeList: (HTMLFrameElement | HTMLIFrameElement)[],
iframeToFind: (HTMLFrameElement | HTMLIFrameElement)) {
for (var i = 0; i < iframeList.length; i++) {
var iframeInlist = iframeList[i];
if (iframeInlist === iframeToFind) {
return i;
}
}
return 0;
}
function getFrameContainingSelection(iframeList: (HTMLFrameElement | HTMLIFrameElement)[]) {
return _.find(iframeList, (frame) => {
return frame.contentDocument.getSelection().toString() !== '';
});
}
};
private removeAllRanges = () => {
_.map(this.listOfFramesWithContent, (iframe) => {
iframe.contentDocument.getSelection().removeAllRanges();
});
}
private surroundRangeWithSpan(documentToManipulate: HTMLDocument,
sense: ISense, range: Range, uuid: string) {
// add span around content
var span: HTMLSpanElement = documentToManipulate.createElement('span');
span.id = uuid;
span.title = sense.explanation;
span.className = 'tagit-tag';
range.surroundContents(span);
// add a button for removing the tag.
var btn = documentToManipulate.createElement("BUTTON");
btn.className = 'js-tagit-remove-tag';
btn.appendChild(documentToManipulate.createTextNode("X"));
span.appendChild(btn);
}
}

View file

@ -1,3 +1,11 @@
/*
Main plugin style. When inserted by the Chrome
plugin we insert this plugin into all iframes on
the page.
*/
.tagit-top-wrapper,
.tagit-top-wrapper > body,
.tagit-top-wrapper > body > iframe {
@ -14,11 +22,10 @@ html.tagit-top-wrapper {
}
.tagit-body {
width: 70%;
width: 68%;
}
.tagit-tag {
background-color: #EDDE45;
padding: 3px;
}
}

View file

@ -1,53 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<title>This will be an iframe programmatically included into a parent page.</title>
<style>
.tagit-menu {
background-color: #FFF;
}
.tagit-menu ul {
padding-left: 0px;
margin-top: 10px;
}
.tagit-menu li {
padding: 5px;
}
.tagit-menu li:hover {
background-color: #eee;
cursor: pointer;
}
</style>
</head>
<body id="tagit-menu" ng-app="tagit" class="tagit-menu">
<div ng-controller="MenuCtrl">
<h2>Tag you're it</h2>
<p>
Mark one or two words on the page to the right. And we'll supply you with possible definitions. Select a definition and the
word will be tagged.
</p>
<p>
Currently selected word: <strong>{{vm.selectedWord}}</strong>
</p>
<input type="text" ng-model="wordToFilterBy" class="form-control" placeholder="Filter tags" />
<ul id="senses">
<li ng-click="vm.onSenseSelect(sense)" id="sense.senseid" ng-repeat="sense in vm.senses | filter:wordToFilterBy" class="list-unstyled">
<strong>{{sense.word}}</strong> {{sense.explanation}}
</li>
</ul>
</div>
</body>
</html>

View file

@ -1,15 +0,0 @@
/// <reference path="../typings/tsd.d.ts" />
module tagIt {
/** @ngInject */
export function AppConfigInitializer ($logProvider: ng.ILogProvider) {
$logProvider.debugEnabled(true);
}
export class AppConfigService {
// serverUrl = 'http://lexitags.dyndns.org/server/lexitags2/Semtags?data=';
serverUrl = 'https://imdb.uib.no/lexitags/lexitags/';
}
}

View file

@ -1,77 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<title>Prototype page mockup</title>
<meta charset="UTF-8">
<link href="vendor/bootstrap/dist/css/bootstrap.min.css" rel="stylesheet">
<link href="style.css" rel="stylesheet">
<script src="vendor/vendor.js"></script>
<script src="load-menu-for-web-testing.js"></script>
</head>
<body class="container">
<br/>
<!-- Let's pretend this is the button for activating the plugin -->
<div class="clearfix">
<button id="js-show-menu" class="btn btn-default">
Open menu
</button>
<button id="js-reset-tags" class="btn btn-default">
Reset tags
</button>
</div>
<div>
<h1>Sample text</h1>
<p>
The Triumph of Cleopatra, also known as Cleopatra's Arrival in Cilicia[1] and The Arrival of Cleopatra in Cilicia,[2] is an oil painting by English artist William Etty. It was first exhibited in 1821, and is now in the Lady Lever Art Gallery in Port Sunlight across the River Mersey from Liverpool. During the 1810s Etty had become widely respected among staff and students at the Royal Academy of Arts, in particular for his use of colour and ability to paint realistic flesh tones. Despite having exhibited at every Summer Exhibition since 1811 he attracted little commercial or critical interest. In 1820 he exhibited The Coral Finder, which showed nude figures on a gilded boat. This painting attracted the attention of Sir Francis Freeling, who commissioned a similar painting on a more ambitious scale.
</p>
<p>
Rome's history spans more than two and a half thousand years. While Roman mythology dates the founding of Rome at only around 753 BC, the site has been inhabited for much longer, making it one of the oldest continuously occupied sites in Europe.[5] The city's early population originated from a mix of Latins, Etruscans and Sabines. Eventually, the city successively became the capital of the Roman Kingdom, the Roman Republic and the Roman Empire, and is regarded as one of the birthplaces of Western civilization and as the first ever metropolis.[6] It is referred to as "Roma Aeterna" (The Eternal City) [7] and "Caput Mundi" (Capital of the World), two central notions in ancient Roman culture.
</p>
<p>
After the fall of the Western Empire, which marked the beginning of the Middle Ages, Rome slowly fell under the political control of the Papacy, which had settled in the city since the 1st century AD, until in the 8th century it became the capital of the Papal States, which lasted until 1870.
</p>
<p>
Beginning with the Renaissance, almost all the popes since Nicholas V (142255) pursued coherently along four hundred years an architectonic and urbanistic program aimed to make of the city the world's artistic and cultural center.[8] Due to that, Rome became first one of the major centers of the Italian Renaissance,[9] and then the birthplace of both the Baroque style and Neoclassicism. Famous artists, painters, sculptors and architects made Rome the center of their activity, creating masterpieces throughout the city. In 1871 Rome became the capital of the Kingdom of Italy, and in 1946 that of the Italian Republic.
</p>
<p>
Rome has the status of a global city.[10][11][12] Rome ranked in 2014 as the 14th-most-visited city in the world, 3rd most visited in the European Union, and the most popular tourist attraction in Italy.[13] Its historic centre is listed by UNESCO as a World Heritage Site.[14] Monuments and museums such as the Vatican Museums and the Colosseum are among the world's most visited tourist destinations with both locations receiving millions of tourists a year. Rome hosted the 1960 Summer Olympics and is the seat of United Nations' Food and Agriculture Organization (FAO).
</p>
<p>
The Triumph of Cleopatra, also known as Cleopatra's Arrival in Cilicia[1] and The Arrival of Cleopatra in Cilicia,[2] is an oil painting by English artist William Etty. It was first exhibited in 1821, and is now in the Lady Lever Art Gallery in Port Sunlight across the River Mersey from Liverpool. During the 1810s Etty had become widely respected among staff and students at the Royal Academy of Arts, in particular for his use of colour and ability to paint realistic flesh tones. Despite having exhibited at every Summer Exhibition since 1811 he attracted little commercial or critical interest. In 1820 he exhibited The Coral Finder, which showed nude figures on a gilded boat. This painting attracted the attention of Sir Francis Freeling, who commissioned a similar painting on a more ambitious scale.
</p>
<p>
Rome's history spans more than two and a half thousand years. While Roman mythology dates the founding of Rome at only around 753 BC, the site has been inhabited for much longer, making it one of the oldest continuously occupied sites in Europe.[5] The city's early population originated from a mix of Latins, Etruscans and Sabines. Eventually, the city successively became the capital of the Roman Kingdom, the Roman Republic and the Roman Empire, and is regarded as one of the birthplaces of Western civilization and as the first ever metropolis.[6] It is referred to as "Roma Aeterna" (The Eternal City) [7] and "Caput Mundi" (Capital of the World), two central notions in ancient Roman culture.
</p>
<p>
After the fall of the Western Empire, which marked the beginning of the Middle Ages, Rome slowly fell under the political control of the Papacy, which had settled in the city since the 1st century AD, until in the 8th century it became the capital of the Papal States, which lasted until 1870.
</p>
<p>
Beginning with the Renaissance, almost all the popes since Nicholas V (142255) pursued coherently along four hundred years an architectonic and urbanistic program aimed to make of the city the world's artistic and cultural center.[8] Due to that, Rome became first one of the major centers of the Italian Renaissance,[9] and then the birthplace of both the Baroque style and Neoclassicism. Famous artists, painters, sculptors and architects made Rome the center of their activity, creating masterpieces throughout the city. In 1871 Rome became the capital of the Kingdom of Italy, and in 1946 that of the Italian Republic.
</p>
<p>
Rome has the status of a global city.[10][11][12] Rome ranked in 2014 as the 14th-most-visited city in the world, 3rd most visited in the European Union, and the most popular tourist attraction in Italy.[13] Its historic centre is listed by UNESCO as a World Heritage Site.[14] Monuments and museums such as the Vatican Museums and the Colosseum are among the world's most visited tourist destinations with both locations receiving millions of tourists a year. Rome hosted the 1960 Summer Olympics and is the seat of United Nations' Food and Agriculture Organization (FAO).
</p>
<p>
The Triumph of Cleopatra, also known as Cleopatra's Arrival in Cilicia[1] and The Arrival of Cleopatra in Cilicia,[2] is an oil painting by English artist William Etty. It was first exhibited in 1821, and is now in the Lady Lever Art Gallery in Port Sunlight across the River Mersey from Liverpool. During the 1810s Etty had become widely respected among staff and students at the Royal Academy of Arts, in particular for his use of colour and ability to paint realistic flesh tones. Despite having exhibited at every Summer Exhibition since 1811 he attracted little commercial or critical interest. In 1820 he exhibited The Coral Finder, which showed nude figures on a gilded boat. This painting attracted the attention of Sir Francis Freeling, who commissioned a similar painting on a more ambitious scale.
</p>
<p>
Rome's history spans more than two and a half thousand years. While Roman mythology dates the founding of Rome at only around 753 BC, the site has been inhabited for much longer, making it one of the oldest continuously occupied sites in Europe.[5] The city's early population originated from a mix of Latins, Etruscans and Sabines. Eventually, the city successively became the capital of the Roman Kingdom, the Roman Republic and the Roman Empire, and is regarded as one of the birthplaces of Western civilization and as the first ever metropolis.[6] It is referred to as "Roma Aeterna" (The Eternal City) [7] and "Caput Mundi" (Capital of the World), two central notions in ancient Roman culture.
</p>
<p>
After the fall of the Western Empire, which marked the beginning of the Middle Ages, Rome slowly fell under the political control of the Papacy, which had settled in the city since the 1st century AD, until in the 8th century it became the capital of the Papal States, which lasted until 1870.
</p>
<p>
Beginning with the Renaissance, almost all the popes since Nicholas V (142255) pursued coherently along four hundred years an architectonic and urbanistic program aimed to make of the city the world's artistic and cultural center.[8] Due to that, Rome became first one of the major centers of the Italian Renaissance,[9] and then the birthplace of both the Baroque style and Neoclassicism. Famous artists, painters, sculptors and architects made Rome the center of their activity, creating masterpieces throughout the city. In 1871 Rome became the capital of the Kingdom of Italy, and in 1946 that of the Italian Republic.
</p>
<p>
Rome has the status of a global city.[10][11][12] Rome ranked in 2014 as the 14th-most-visited city in the world, 3rd most visited in the European Union, and the most popular tourist attraction in Italy.[13] Its historic centre is listed by UNESCO as a World Heritage Site.[14] Monuments and museums such as the Vatican Museums and the Colosseum are among the world's most visited tourist destinations with both locations receiving millions of tourists a year. Rome hosted the 1960 Summer Olympics and is the seat of United Nations' Food and Agriculture Organization (FAO).
</p>
</div>
</body>
</html>

View file

@ -1,40 +0,0 @@
/// <reference path="../typings/tsd.d.ts" />
module tagIt {
export interface ISynset {
config: Object,
data: {
senses: string[]
}
}
export interface IVMScope extends angular.IScope {
vm : Object;
}
export interface ISense {
explanation: string,
rank: number,
related: string,
senseid: string,
source: string,
word: string
}
/*
context: represents the text context of the tag
selectionRange: selectionRangeObject
*/
export interface ISenseTag {
id: string,
userEmail: string;
sense: ISense;
context: string;
iframeIndex: number;
wordThatWasTagged: string;
serializedSelectionRange: string;
deserializedRange?: Range;
urlOfPageThatWasTagged: string;
}
}

View file

@ -1,47 +0,0 @@
/// <reference path="../typings/tsd.d.ts" />
/// <reference path="index.appConfig.ts" />
/// <reference path="menu/menu.controller.ts" />
/// <reference path="services/backend.service.ts" />
/// <reference path="services/webpage.service.ts" />
/// <reference path="services/tagStorage.service.ts" />
/// <reference path="services/file.service.ts" />
module tagIt {
export function init(callback: () => void) {
angular.module('tagit', ['ngStorage'])
.config(AppConfigInitializer)
.service('AppConfigService', AppConfigService)
.service('BackendService', BackendService)
.service('WebPageService', WebPageService)
.service('TagStorageService', TagStorageService)
.service('FileService', FileService)
.controller('MenuCtrl', MenuCtrl);
var iframe = <HTMLIFrameElement>document.getElementById("tagit-iframe")
angular.bootstrap(iframe.contentDocument.getElementById("tagit-menu"), ['tagit']);
console.log('TagIt menu loaded');
setupChromeListener();
}
function setupChromeListener() {
if (typeof chrome === 'undefined') return; //do nothing
chrome.runtime.onMessage.addListener(
function(request, sender, sendResponse) {
console.log(sender.tab ?
"from a content script:" + sender.tab.url :
"from the extension");
if (request.greeting == "hello") {
sendResponse({ farewell: "goodbye" });
} else if (request === 'isMenuOpen') {
sendResponse(true);
}
}
);
}
}

View file

@ -1,33 +0,0 @@
// Script loader for local web page testing
document.addEventListener("DOMContentLoaded", function(event) {
document.getElementById('js-show-menu')
.addEventListener('click', function () {
if (!document.getElementById('tagit-menu')) injectIframe();
});
document.getElementById('js-reset-tags')
.addEventListener('click', function () {
// nothing here yet
});
injectIframe();
});
function injectIframe () {
console.log('injectIframe()');
var iframe = document.createElement('iframe');
iframe.src = 'index-angular-app-web.html';
iframe.seamless = 'seamless';
iframe.frameBorder = "0";
iframe.className = 'tagit-iframe';
$('body').children().wrapAll('<div id="tagit-body" class="tagit-body" />');
$('.tagit-body').before(iframe);
}
// Todo: Setup listener that will call angular code
// on new text selections and deselections
// Todo: Add functions that give access to window object.
function getParentWindowObject () {
return window;
}

File diff suppressed because it is too large Load diff

View file

@ -1,136 +0,0 @@
/// <reference path="../index.ts" />
module tagIt {
'use strict';
export class MenuCtrl {
selectedWord = "";
senses: Object[];
backendService: BackendService;
webPageService: WebPageService;
tagStorageService: TagStorageService;
fileService: FileService;
$log: ng.ILogService;
$scope: ng.IScope;
/* @ngInject */
constructor($scope: IVMScope, $log: angular.ILogService,
BackendService: BackendService,
WebPageService: WebPageService,
TagStorageService: TagStorageService,
FileService: FileService) {
$scope.vm = this;
this.$log = $log;
this.$scope = $scope;
this.backendService = BackendService;
this.webPageService = WebPageService;
this.tagStorageService = TagStorageService;
this.fileService = FileService;
this.$scope.$on('wordWasSelected', (event, selectedWord) => {
this.$log.debug(`Menucontroller received wordWasSelected event for: ${selectedWord}`);
this.onWordSelectedEvent(selectedWord);
});
this.$scope.$on('wordWasSelected', (event, selectedWord) => {
this.$log.debug('a word was selected' + selectedWord);
this.onWordSelectedEvent(selectedWord);
});
// Reload existing tags
var tagsToLoad = this.tagStorageService.loadTagsForCurrentPage();
this.$log.debug('these tags were found in storage');
this.$log.debug(tagsToLoad);
this.webPageService.readdTagsToPage(tagsToLoad);
}
/**
* Fired when user selects a sense amongst the senses
* returned from the backend.
*/
onSenseSelect(sense: ISense) {
//remove all tags so that new tag range is serialized
//based on a document without any highlights
this.webPageService.removeAllTagsFromPage(() => {
//initialize and save the new tag
var senseTag = this.webPageService.initializeNewTag(sense);
this.tagStorageService.saveTag(senseTag);
// deactivate backendService for now.
// this.backendService.sendTaggedDataToServer(senseTag);
//re-add tags, with new tag. Clear menu options.
this.webPageService.readdTagsToPage(
this.tagStorageService.loadTagsForCurrentPage()
);
this.clearMenuVariables();
});
}
/**
* Enables a clickable button to download tags as a json file.
*/
downloadTagsForPage() {
if (typeof chrome === 'undefined') {
this.$log.debug('Did not find chrome facilities. Can\'t download.')
return; //do nothing
}
this.fileService.saveFile(this.tagStorageService.loadTagsForCurrentPage());
}
downloadAllTagsForDomain() {
if (typeof chrome === 'undefined') {
this.$log.debug('Did not find chrome facilities. Can\'t download.')
return; //do nothing
}
this.fileService.saveFile(this.tagStorageService.loadAllTagsInLocalStorage());
}
/**
* Enables clickable link for removing tags.
*/
removeTagsFromLocalStorage() {
if (confirm('Really delete tags from the current page?')) {
this.webPageService.removeAllTagsFromPage(() => {
this.tagStorageService.deleteTagsFromCurrentPage()
})
}
}
onWordSelectedEvent = (newWord: string) => {
if (countWords(newWord) > 2) {
this.selectedWord = "Wops! Plugin can't handle more than two words.";
this.senses = [];
}
else if (newWord.length === 0) {
this.clearMenuVariables();
}
else {
this.selectedWord = newWord;
this.backendService.callServer(newWord)
.then((synsets: any) => {
this.$log.debug(synsets);
this.senses = synsets.data.senses;
});
}
function countWords(wordWithUnderscores: string) {
return wordWithUnderscores.split("_").length;
}
}
onWordDeSelectedEvent = () => {
this.$log.debug("onWordDeSelected");
this.clearMenuVariables()
}
clearMenuVariables() {
this.selectedWord = "";
this.senses = [];
}
}
}

View file

@ -1,41 +0,0 @@
/*
This javascript is injected to page by background.js.
*/
$.get(chrome.extension.getURL('index-angular-app.html'), function (htmlData) {
var iframeMainContent = document.createElement('iframe');
iframeMainContent.id = 'tagit-body';
iframeMainContent.className = 'tagit-body';
iframeMainContent.src = window.location.href;
iframeMainContent.seamless = 'seamless';
iframeMainContent.frameBorder = "0";
//add a helper class to aid in styling later.
$('html').addClass('tagit-top-wrapper');
/**
* If the page is using a frameset
* we'll need to remove it and
* insert a new body tag instead.
*/
if ($('frameset').length > 0) {
$('frameset').remove();
var newbody = document.createElement("body");
$('html').append(newbody);
} else {
$('body').children().remove();
}
//reinsert page this time inside an iframe
$('body').append(iframeMainContent);
var iframeMenu = document.createElement('iframe');
iframeMenu.id = 'tagit-iframe';
iframeMenu.srcdoc = htmlData;
iframeMenu.seamless = 'seamless';
iframeMenu.frameBorder = "0";
iframeMenu.className = 'tagit-iframe';
// iframe.sandbox = 'allow-same-origin allow-top-navigation allow-scripts';
$('.tagit-body').before(iframeMenu);
});

View file

@ -6,55 +6,26 @@ chrome.browserAction.onClicked.addListener(function () {
chrome.tabs.reload();
} else {
console.log('Opening menu');
injectIframe();
injectIframe();
}
})
});
function isMenuOpen(callback) {
chrome.tabs.query({ active: true, currentWindow: true }, function (tabs) {
chrome.tabs.sendMessage(tabs[0].id, "isMenuOpen" , callback);
chrome.tabs.sendMessage(tabs[0].id, "isMenuOpen", callback);
});
}
function injectIframe() {
loadJquery(function () {
chrome.tabs.executeScript(null, {
file: 'add-iframe-to-page.js'
}, loadPluginDeps);
});
function loadJquery(callback) {
chrome.tabs.executeScript(null, {
file: 'vendor/jquery/dist/jquery.js',
allFrames: true
}, callback);
}
chrome.tabs.executeScript(null, {
file: 'app.js'
}, () => {
function loadPluginDeps() {
chrome.tabs.executeScript(null, {
file: 'vendor/vendor.js',
allFrames: true
}, loadPlugin);
}
function loadPlugin() {
chrome.tabs.executeScript(null, {
file: 'bundle.js',
allFrames: true
}, loadCss);
}
function loadCss() {
chrome.tabs.insertCSS(null, {
file: 'style.css',
allFrames: true
}, initPlugin);
}
function initPlugin() {
chrome.tabs.executeScript(null, {
code: 'tagIt.init();'
});
}
});
}

View file

@ -1,61 +0,0 @@
/// <reference path="../index.interfaces.ts" />
/// <reference path="../index.appConfig.ts" />
'use strict';
/**
* Service that is responsible for talking to the
* backend server.
*/
module tagIt {
export class BackendService {
$http : ng.IHttpService;
$log : ng.ILogService;
$q: ng.IQService;
private serverUrl : string = null;
private previousCall: string;
/* @ngInject */
constructor($http: ng.IHttpService, $q: ng.IQService, $log: ng.ILogService, AppConfigService: AppConfigService) {
this.$http = $http;
this.$log = $log;
this.$q = $q;
this.serverUrl = AppConfigService.serverUrl;
}
callServer (word: string) {
if (!word) {
return this.$q.reject('no use calling server, there is no queryword.')
} else if (this.previousCall === word) {
var errMsg = `callServer has already been called with word: ${word}`;
this.$log.debug(errMsg)
return this.$q.reject(errMsg);
}
//alright let's make this query!
this.previousCall = word;
return this.$http.get(this.serverUrl + word);
}
sendTaggedDataToServer (senseTag: ISenseTag) {
this.$log.debug('sendTaggedDataToServer() was called');
this.$log.debug('would have sent this to the server:');
this.$log.debug(senseTag);
this.$log.debug('please uncomment code for actually sending to server');
// this.$http.post("example.org", senseTag)
// .then((response) => {
// this.$log.debug('successfully posted to server. Response:');
// this.$log.debug(response);
// })
// .catch((error) => {
// this.$log.error('something went wrong when posting to server');
// this.$log.error(error);
// });
}
}
}

View file

@ -1,34 +0,0 @@
/// <reference path="../index.interfaces.ts" />
'use strict';
//Responsible for saving.
module tagIt {
export class FileService {
$log: ng.ILogService;
/* @ngInject */
constructor($log: ng.ILogService) {
this.$log = $log;
}
saveFile(content: ISenseTag[]) {
var json = JSON.stringify(content, null, 2);
var blob = new Blob([json], { type: "application/json" });
var url = URL.createObjectURL(blob);
var a = <any>document.createElement('a');
var date = new Date();
a.download = `
tags downloaded for ${window.location.hostname}
time of download ${date.toLocaleString()}
.json`
.replace('\n', '')
a.href = url;
a.click();
URL.revokeObjectURL(url); //Explicitly release obj from memory.
}
}
}

View file

@ -1,75 +0,0 @@
/// <reference path="../index.interfaces.ts" />
'use strict';
// responsible for saving and loading
// any tags related to the current page
module tagIt {
export class TagStorageService {
$http: ng.IHttpService;
$log: ng.ILogService;
$localStorage: { tagStorage: ISenseTag[] };
/* @ngInject */
constructor($http: ng.IHttpService, $log: ng.ILogService,
$localStorage: any) {
this.$http = $http;
this.$log = $log;
this.$localStorage = $localStorage;
if (window.location.href.indexOf("tagitreset") !== -1) {
this.deleteTagsFromCurrentPage(); // reset tag storage
this.$log.debug("Resetting tags for this page");
}
if (!this.$localStorage.tagStorage) {
this.$localStorage.tagStorage = [];
}
}
deleteTagById(uuid: string) {
this.$log.debug('deleting tag from localstorage with uuid: ' + uuid);
var newList: ISenseTag[] = [];
var tag: ISenseTag;
for (var i = 0; i < this.$localStorage.tagStorage.length; i++) {
tag = this.$localStorage.tagStorage[i];
if (tag.id !== uuid) {
newList.push(tag);
}
}
this.$localStorage.tagStorage = newList;
}
deleteTagsFromCurrentPage() {
this.$log.debug('deleting tags');
this.$localStorage.tagStorage =
this.$localStorage.tagStorage.filter(
(tag: ISenseTag) => tag.urlOfPageThatWasTagged !== window.location.href)
}
saveTag(tagToSave: ISenseTag) {
this.$log.debug('saving tag in localstorage:');
this.$log.debug(tagToSave);
this.$localStorage.tagStorage.push(tagToSave);
}
loadTagsForCurrentPage(): ISenseTag[] {
this.$log.debug('loadTagsForCurrentPage');
return this.$localStorage.tagStorage
.filter((tag: ISenseTag) =>
tag.urlOfPageThatWasTagged === window.location.href
);
}
/**
* Loads all tags in localstorage (for the current domain).
*/
loadAllTagsInLocalStorage() {
this.$log.debug('loadAllTagsInLocalStorage');
return this.$localStorage.tagStorage
}
}
}

View file

@ -1,283 +0,0 @@
'use strict';
module tagIt {
declare var rangy: any;
declare var uuid: any;
/**
* This service is responsible for interfacing with the content
* that we want to tag. It injects/removes tags and listens for clicks.
*/
export class WebPageService {
$log: ng.ILogService;
// when clicking the menu to select a synset
// we need to remember what the currently selected word was
tagStorageService: TagStorageService;
rootScopeService: ng.IRootScopeService;
savedSelection: Object;
savedText: string;
listOfFramesWithContent: (HTMLFrameElement | HTMLIFrameElement)[] = [];
/* @ngInject */
constructor($log: ng.ILogService, TagStorageService: TagStorageService, $rootScope: ng.IRootScopeService) {
this.$log = $log;
this.tagStorageService = TagStorageService;
this.rootScopeService = $rootScope;
this.wireUpListener();
rangy.init();
}
/**
* The click listening function placed on each of the iframes
* we capture. We then listen for clicks and check if a word
* was selected.
*/
clickhandler = (evt: Event) => {
this.$log.debug('A click happened!');
var documentThatWasClicked = evt.srcElement.ownerDocument;
if (!documentThatWasClicked.hasFocus()) {
return true;
}
else if (wasRemoveTagButtonClicked(evt)) {
this.$log.debug('remove tag button was clicked');
removeTagFromWebAndStorage(evt, this.tagStorageService);
}
else if (documentThatWasClicked.getSelection().toString() !== '') {
resetSavedSelection();
this.savedSelection = rangy.saveSelection(documentThatWasClicked);
this.savedText = joinLongWords(documentThatWasClicked.getSelection().toString());
this.rootScopeService.$broadcast('wordWasSelected', this.savedText);
} else {
resetSavedSelection();
this.savedText = '';
this.rootScopeService.$broadcast('wordWasDeSelected', null);
}
/**
* Remove markers to ensure a clean page before
* adding markers for a new page.
*/
function resetSavedSelection() {
if (this.savedSelection) {
rangy.removeMarkers(this.savedSelection);
}
}
function joinLongWords(possiblyLongWord: string) {
return possiblyLongWord.trim().split(" ").join("_");
}
function wasRemoveTagButtonClicked(evt: any) {
return evt.target.className === 'js-tagit-remove-tag';
}
//todo ensure removing a tag
function removeTagFromWebAndStorage(evt: Event, tagStorageService: TagStorageService) {
var target = <HTMLElement>evt.target;
var theOriginalTextNode = target.previousSibling;
var theSurroundingSpanElement = target.parentElement;
var parentElement = theSurroundingSpanElement.parentElement;
tagStorageService.deleteTagById(theSurroundingSpanElement.id);
parentElement.replaceChild(theOriginalTextNode, theSurroundingSpanElement);
parentElement.normalize();
}
}
/**
* Find one or more iframes in which content has been captured.
* We then place click listeners on each of the frames.
*/
wireUpListener() {
const tagitBodyIframe = <HTMLIFrameElement>parent.document.getElementById('tagit-body');
const tagitBodyIframeDoc = tagitBodyIframe.contentDocument;
if (tagitBodyIframeDoc.getElementsByTagName('frameset').length > 0) {
_.map(tagitBodyIframeDoc.getElementsByTagName('frame'),
(frame) => { this.listOfFramesWithContent.push(frame) });
} else {
this.listOfFramesWithContent.push(tagitBodyIframe);
}
_.map(this.listOfFramesWithContent, (frame: HTMLIFrameElement) => {
frame.contentDocument.addEventListener('click', this.clickhandler, false);
});
}
/**
* Will loop through all content iframes and empty them for
* tags added by us. This is because we need to position a
* new tag in relation to a clean DOM.
* */
removeAllTagsFromPage(callback: () => void) {
//loop that will keep asking for spans to remove
//until they are all gone.
const done = _.after(this.listOfFramesWithContent.length, () => {
callback();
});
_.map(this.listOfFramesWithContent, (iframe) => {
removeTagsFromIframe(iframe, done);
});
function removeTagsFromIframe(iframe: HTMLFrameElement | HTMLIFrameElement,
callback: () => void) {
while (iframe.contentDocument.getElementsByClassName('tagit-tag').length > 0) {
var spanElement = iframe.contentDocument.getElementsByClassName('tagit-tag')[0];
var spanElementParent = spanElement.parentNode;
spanElementParent.replaceChild(
spanElement.firstChild,
spanElement);
/**
* call normalize on the parent element so that it will join up
* any text nodes that might have become chopped up by
* tags and selection markers.
* */
spanElementParent.normalize();
}
callback();
}
}
/**
* Handles adding tags to page which needs to happen in a
* bottom up order, so that all the tags find their right place.
*/
readdTagsToPage(tagsToLoad: ISenseTag[]) {
this.$log.debug('readdTagsToPage()');
//first deselect all places before we go to work
this.removeAllRanges();
/**
* The tags need to be loaded (deserialized) so that
* they can be inserted properly. Deserialization might
* fail if the page has changed since it was tagged. Thus
* we remove tags that fail to load.
*/
tagsToLoad = _.filter(tagsToLoad, (tagToLoad) => {
try {
tagToLoad.deserializedRange = rangy.deserializeRange(
tagToLoad.serializedSelectionRange,
this.listOfFramesWithContent[tagToLoad.iframeIndex].contentDocument.documentElement,
this.listOfFramesWithContent[tagToLoad.iframeIndex]
);
return true;
} catch (e) {
var errorMsg = `Error in rangy.js: Was not able to deserialize range.
In other words: The page might have changed. Is not able
to determine where this tag should have been placed.`
this.$log.debug(errorMsg);
this.$log.debug("Couldn't load: " + tagToLoad.sense.word);
this.$log.debug(e);
return false;
}
})
this.$log.debug('finished deserializing tags');
/**
* sort tags descending (highest number = furthest down on page).
*/
tagsToLoad = _.sortBy(tagsToLoad, (tag: ISenseTag) => {
return tag.deserializedRange.startOffset;
});
this.$log.debug('finished sorting tags');
/**
* Loop through loaded tags and insert them to the page.
*/
_.map(tagsToLoad, (tag: ISenseTag) => {
if (tag.deserializedRange) {
this.surroundRangeWithSpan(
this.listOfFramesWithContent[tag.iframeIndex].contentDocument,
tag.sense,
tag.deserializedRange,
tag.id);
}
});
this.$log.debug('finished adding tags to page');
this.removeAllRanges();
}
initializeNewTag = (sense: ISense): ISenseTag => {
this.$log.debug('initializeNewTag');
/**
* first eliminate all selections to avoid confusion
* with other iframes.
*/
this.removeAllRanges();
rangy.restoreSelection(this.savedSelection);
var iframeOfInterest = getFrameContainingSelection(this.listOfFramesWithContent);
const selection = iframeOfInterest.contentDocument.getSelection();
var range: Range = selection.getRangeAt(0);
var serializedRange = rangy.serializeRange(range, true,
iframeOfInterest.contentDocument.documentElement);
var generatedUuid: string = uuid.v4();
var parentElement = <HTMLElement>range.commonAncestorContainer;
return {
id: generatedUuid,
userEmail: 'testEmail',
sense: sense,
wordThatWasTagged: selection.toString(),
iframeIndex: getIframeIndex(this.listOfFramesWithContent, iframeOfInterest),
context: parentElement.textContent,
serializedSelectionRange: serializedRange,
urlOfPageThatWasTagged: window.location.href
}
/**
* Some pages might have many frames with content. Thus we
* need to loop through them, identify which document contains the current
* selection and then save its index in our list.
*/
function getIframeIndex(iframeList: (HTMLFrameElement | HTMLIFrameElement)[],
iframeToFind: (HTMLFrameElement | HTMLIFrameElement)) {
for (var i = 0; i < iframeList.length; i++) {
var iframeInlist = iframeList[i];
if (iframeInlist === iframeToFind) {
return i;
}
}
return 0;
}
function getFrameContainingSelection(iframeList: (HTMLFrameElement | HTMLIFrameElement)[]) {
return _.find(iframeList, (frame) => {
return frame.contentDocument.getSelection().toString() !== '';
});
}
};
private removeAllRanges = () => {
_.map(this.listOfFramesWithContent, (iframe) => {
iframe.contentDocument.getSelection().removeAllRanges();
});
}
private surroundRangeWithSpan(documentToManipulate: HTMLDocument,
sense: ISense, range: Range, uuid: string) {
// add span around content
var span: HTMLSpanElement = documentToManipulate.createElement('span');
span.id = uuid;
span.title = sense.explanation;
span.className = 'tagit-tag';
range.surroundContents(span);
// add a button for removing the tag.
var btn = documentToManipulate.createElement("BUTTON");
btn.className = 'js-tagit-remove-tag';
btn.appendChild(documentToManipulate.createTextNode("X"));
span.appendChild(btn);
}
}
}

130
test/content.html Normal file
View file

@ -0,0 +1,130 @@
<html>
<head></head>
<style>
.tagit-tag {
background-color: #EDDE45;
padding: 3px;
}
</style>
<body>
<h1>Sample text</h1>
<p>
The Triumph of Cleopatra, also known as Cleopatra's Arrival in Cilicia[1] and The Arrival of Cleopatra in Cilicia,[2] is
an oil painting by English artist William Etty. It was first exhibited in 1821, and is now in the Lady Lever Art Gallery
in Port Sunlight across the River Mersey from Liverpool. During the 1810s Etty had become widely respected among staff
and students at the Royal Academy of Arts, in particular for his use of colour and ability to paint realistic flesh tones.
Despite having exhibited at every Summer Exhibition since 1811 he attracted little commercial or critical interest. In
1820 he exhibited The Coral Finder, which showed nude figures on a gilded boat. This painting attracted the attention
of Sir Francis Freeling, who commissioned a similar painting on a more ambitious scale.
</p>
<p>
Rome's history spans more than two and a half thousand years. While Roman mythology dates the founding of Rome at only around
753 BC, the site has been inhabited for much longer, making it one of the oldest continuously occupied sites in Europe.[5]
The city's early population originated from a mix of Latins, Etruscans and Sabines. Eventually, the city successively
became the capital of the Roman Kingdom, the Roman Republic and the Roman Empire, and is regarded as one of the birthplaces
of Western civilization and as the first ever metropolis.[6] It is referred to as "Roma Aeterna" (The Eternal City) [7]
and "Caput Mundi" (Capital of the World), two central notions in ancient Roman culture.
</p>
<p>
After the fall of the Western Empire, which marked the beginning of the Middle Ages, Rome slowly fell under the political
control of the Papacy, which had settled in the city since the 1st century AD, until in the 8th century it became the
capital of the Papal States, which lasted until 1870.
</p>
<p>
Beginning with the Renaissance, almost all the popes since Nicholas V (142255) pursued coherently along four hundred years
an architectonic and urbanistic program aimed to make of the city the world's artistic and cultural center.[8] Due to
that, Rome became first one of the major centers of the Italian Renaissance,[9] and then the birthplace of both the Baroque
style and Neoclassicism. Famous artists, painters, sculptors and architects made Rome the center of their activity, creating
masterpieces throughout the city. In 1871 Rome became the capital of the Kingdom of Italy, and in 1946 that of the Italian
Republic.
</p>
<p>
Rome has the status of a global city.[10][11][12] Rome ranked in 2014 as the 14th-most-visited city in the world, 3rd most
visited in the European Union, and the most popular tourist attraction in Italy.[13] Its historic centre is listed by
UNESCO as a World Heritage Site.[14] Monuments and museums such as the Vatican Museums and the Colosseum are among the
world's most visited tourist destinations with both locations receiving millions of tourists a year. Rome hosted the
1960 Summer Olympics and is the seat of United Nations' Food and Agriculture Organization (FAO).
</p>
<p>
The Triumph of Cleopatra, also known as Cleopatra's Arrival in Cilicia[1] and The Arrival of Cleopatra in Cilicia,[2] is
an oil painting by English artist William Etty. It was first exhibited in 1821, and is now in the Lady Lever Art Gallery
in Port Sunlight across the River Mersey from Liverpool. During the 1810s Etty had become widely respected among staff
and students at the Royal Academy of Arts, in particular for his use of colour and ability to paint realistic flesh tones.
Despite having exhibited at every Summer Exhibition since 1811 he attracted little commercial or critical interest. In
1820 he exhibited The Coral Finder, which showed nude figures on a gilded boat. This painting attracted the attention
of Sir Francis Freeling, who commissioned a similar painting on a more ambitious scale.
</p>
<p>
Rome's history spans more than two and a half thousand years. While Roman mythology dates the founding of Rome at only around
753 BC, the site has been inhabited for much longer, making it one of the oldest continuously occupied sites in Europe.[5]
The city's early population originated from a mix of Latins, Etruscans and Sabines. Eventually, the city successively
became the capital of the Roman Kingdom, the Roman Republic and the Roman Empire, and is regarded as one of the birthplaces
of Western civilization and as the first ever metropolis.[6] It is referred to as "Roma Aeterna" (The Eternal City) [7]
and "Caput Mundi" (Capital of the World), two central notions in ancient Roman culture.
</p>
<p>
After the fall of the Western Empire, which marked the beginning of the Middle Ages, Rome slowly fell under the political
control of the Papacy, which had settled in the city since the 1st century AD, until in the 8th century it became the
capital of the Papal States, which lasted until 1870.
</p>
<p>
Beginning with the Renaissance, almost all the popes since Nicholas V (142255) pursued coherently along four hundred years
an architectonic and urbanistic program aimed to make of the city the world's artistic and cultural center.[8] Due to
that, Rome became first one of the major centers of the Italian Renaissance,[9] and then the birthplace of both the Baroque
style and Neoclassicism. Famous artists, painters, sculptors and architects made Rome the center of their activity, creating
masterpieces throughout the city. In 1871 Rome became the capital of the Kingdom of Italy, and in 1946 that of the Italian
Republic.
</p>
<p>
Rome has the status of a global city.[10][11][12] Rome ranked in 2014 as the 14th-most-visited city in the world, 3rd most
visited in the European Union, and the most popular tourist attraction in Italy.[13] Its historic centre is listed by
UNESCO as a World Heritage Site.[14] Monuments and museums such as the Vatican Museums and the Colosseum are among the
world's most visited tourist destinations with both locations receiving millions of tourists a year. Rome hosted the
1960 Summer Olympics and is the seat of United Nations' Food and Agriculture Organization (FAO).
</p>
<p>
The Triumph of Cleopatra, also known as Cleopatra's Arrival in Cilicia[1] and The Arrival of Cleopatra in Cilicia,[2] is
an oil painting by English artist William Etty. It was first exhibited in 1821, and is now in the Lady Lever Art Gallery
in Port Sunlight across the River Mersey from Liverpool. During the 1810s Etty had become widely respected among staff
and students at the Royal Academy of Arts, in particular for his use of colour and ability to paint realistic flesh tones.
Despite having exhibited at every Summer Exhibition since 1811 he attracted little commercial or critical interest. In
1820 he exhibited The Coral Finder, which showed nude figures on a gilded boat. This painting attracted the attention
of Sir Francis Freeling, who commissioned a similar painting on a more ambitious scale.
</p>
<p>
Rome's history spans more than two and a half thousand years. While Roman mythology dates the founding of Rome at only around
753 BC, the site has been inhabited for much longer, making it one of the oldest continuously occupied sites in Europe.[5]
The city's early population originated from a mix of Latins, Etruscans and Sabines. Eventually, the city successively
became the capital of the Roman Kingdom, the Roman Republic and the Roman Empire, and is regarded as one of the birthplaces
of Western civilization and as the first ever metropolis.[6] It is referred to as "Roma Aeterna" (The Eternal City) [7]
and "Caput Mundi" (Capital of the World), two central notions in ancient Roman culture.
</p>
<p>
After the fall of the Western Empire, which marked the beginning of the Middle Ages, Rome slowly fell under the political
control of the Papacy, which had settled in the city since the 1st century AD, until in the 8th century it became the
capital of the Papal States, which lasted until 1870.
</p>
<p>
Beginning with the Renaissance, almost all the popes since Nicholas V (142255) pursued coherently along four hundred years
an architectonic and urbanistic program aimed to make of the city the world's artistic and cultural center.[8] Due to
that, Rome became first one of the major centers of the Italian Renaissance,[9] and then the birthplace of both the Baroque
style and Neoclassicism. Famous artists, painters, sculptors and architects made Rome the center of their activity, creating
masterpieces throughout the city. In 1871 Rome became the capital of the Kingdom of Italy, and in 1946 that of the Italian
Republic.
</p>
<p>
Rome has the status of a global city.[10][11][12] Rome ranked in 2014 as the 14th-most-visited city in the world, 3rd most
visited in the European Union, and the most popular tourist attraction in Italy.[13] Its historic centre is listed by
UNESCO as a World Heritage Site.[14] Monuments and museums such as the Vatican Museums and the Colosseum are among the
world's most visited tourist destinations with both locations receiving millions of tourists a year. Rome hosted the
1960 Summer Olympics and is the seat of United Nations' Food and Agriculture Organization (FAO).
</p>
</body>
</html>

31
test/index.html Normal file
View file

@ -0,0 +1,31 @@
<!DOCTYPE html>
<html class="tagit-top-wrapper">
<head>
<title>Prototype page mockup</title>
<meta charset="UTF-8">
<link href="../src/app/style.css" rel="stylesheet">
<script src="../jspm_packages/system.js"></script>
<script src="../config.js"></script>
<script src="../tmp/bundle.js"></script>
<script>
window.tagitTestMode = true;
System.import('main');
</script>
</head>
<body>
<!--Embedd the real menu-->
<iframe id="tagit-iframe" seamless="seamless" frameborder="0" class="tagit-iframe" src="../src/app/menu/menu.tpl.html" frameborder="0"></iframe>
<!--Embedd dummy content page for testing-->
<iframe id="tagit-body" seamless="seamless" frameborder="0" class="tagit-body" src="content.html" frameborder="0"></iframe>
</body>
</html>

View file

@ -1,9 +1,15 @@
{
"compilerOptions": {
"noImplicitAny": true,
"out": "output.js"
"compilerOptions": {
"module": "system",
"target": "es5",
"noImplicitAny": false,
"sourceMap": true,
"outFile": "tmp/bundle.js"
},
"files": [
"src/index.ts"
"src/app/globalAugments.d.ts",
"src/app/moduleAugments.d.ts",
"typings/index.d.ts",
"src/app/main.ts"
]
}

View file

@ -1,33 +0,0 @@
{
"version": "v4",
"repo": "borisyankov/DefinitelyTyped",
"ref": "master",
"path": "typings",
"bundle": "typings/tsd.d.ts",
"installed": {
"jquery/jquery.d.ts": {
"commit": "af5b8275d1f2b92738b93fddabc461fc20c553a1"
},
"angularjs/angular.d.ts": {
"commit": "af5b8275d1f2b92738b93fddabc461fc20c553a1"
},
"filewriter/filewriter.d.ts": {
"commit": "3191f6e0088eee07c4d8fd24e4d27a40a60d9eb9"
},
"webrtc/MediaStream.d.ts": {
"commit": "3191f6e0088eee07c4d8fd24e4d27a40a60d9eb9"
},
"es6-promise/es6-promise.d.ts": {
"commit": "3191f6e0088eee07c4d8fd24e4d27a40a60d9eb9"
},
"filesystem/filesystem.d.ts": {
"commit": "3191f6e0088eee07c4d8fd24e4d27a40a60d9eb9"
},
"chrome/chrome.d.ts": {
"commit": "3191f6e0088eee07c4d8fd24e4d27a40a60d9eb9"
},
"lodash/lodash.d.ts": {
"commit": "e5a27ea95e47b95333784f1f0d590127b4e39a89"
}
}
}

12
typings.json Normal file
View file

@ -0,0 +1,12 @@
{
"name": "tag-youre-it",
"globalDependencies": {
"angular": "github:DefinitelyTyped/DefinitelyTyped/angularjs/angular.d.ts#af5b8275d1f2b92738b93fddabc461fc20c553a1",
"chrome": "github:DefinitelyTyped/DefinitelyTyped/chrome/chrome.d.ts#3191f6e0088eee07c4d8fd24e4d27a40a60d9eb9",
"jquery": "github:DefinitelyTyped/DefinitelyTyped/jquery/jquery.d.ts#af5b8275d1f2b92738b93fddabc461fc20c553a1",
"lodash": "github:DefinitelyTyped/DefinitelyTyped/lodash/lodash.d.ts#e5a27ea95e47b95333784f1f0d590127b4e39a89",
"node-uuid/node-uuid-base": "registry:dt/node-uuid/node-uuid-base#0.0.0+20160316155526",
"node-uuid/node-uuid-cjs": "registry:dt/node-uuid/node-uuid-cjs#0.0.0+20160316155526",
"rangy": "registry:dt/rangy#0.0.0+20160316155526"
}
}

View file

@ -1,73 +0,0 @@
// Type definitions for es6-promise
// Project: https://github.com/jakearchibald/ES6-Promise
// Definitions by: François de Campredon <https://github.com/fdecampredon/>, vvakame <https://github.com/vvakame>
// Definitions: https://github.com/borisyankov/DefinitelyTyped
interface Thenable<R> {
then<U>(onFulfilled?: (value: R) => U | Thenable<U>, onRejected?: (error: any) => U | Thenable<U>): Thenable<U>;
then<U>(onFulfilled?: (value: R) => U | Thenable<U>, onRejected?: (error: any) => void): Thenable<U>;
}
declare class Promise<R> implements Thenable<R> {
/**
* If you call resolve in the body of the callback passed to the constructor,
* your promise is fulfilled with result object passed to resolve.
* If you call reject your promise is rejected with the object passed to resolve.
* For consistency and debugging (eg stack traces), obj should be an instanceof Error.
* Any errors thrown in the constructor callback will be implicitly passed to reject().
*/
constructor(callback: (resolve : (value?: R | Thenable<R>) => void, reject: (error?: any) => void) => void);
/**
* onFulfilled is called when/if "promise" resolves. onRejected is called when/if "promise" rejects.
* Both are optional, if either/both are omitted the next onFulfilled/onRejected in the chain is called.
* Both callbacks have a single parameter , the fulfillment value or rejection reason.
* "then" returns a new promise equivalent to the value you return from onFulfilled/onRejected after being passed through Promise.resolve.
* If an error is thrown in the callback, the returned promise rejects with that error.
*
* @param onFulfilled called when/if "promise" resolves
* @param onRejected called when/if "promise" rejects
*/
then<U>(onFulfilled?: (value: R) => U | Thenable<U>, onRejected?: (error: any) => U | Thenable<U>): Promise<U>;
then<U>(onFulfilled?: (value: R) => U | Thenable<U>, onRejected?: (error: any) => void): Promise<U>;
/**
* Sugar for promise.then(undefined, onRejected)
*
* @param onRejected called when/if "promise" rejects
*/
catch<U>(onRejected?: (error: any) => U | Thenable<U>): Promise<U>;
}
declare module Promise {
/**
* Make a new promise from the thenable.
* A thenable is promise-like in as far as it has a "then" method.
*/
function resolve<R>(value?: R | Thenable<R>): Promise<R>;
/**
* Make a promise that rejects to obj. For consistency and debugging (eg stack traces), obj should be an instanceof Error
*/
function reject(error: any): Promise<any>;
/**
* Make a promise that fulfills when every item in the array fulfills, and rejects if (and when) any item rejects.
* the array passed to all can be a mixture of promise-like objects and other objects.
* The fulfillment value is an array (in order) of fulfillment values. The rejection value is the first rejection value.
*/
function all<R>(promises: (R | Thenable<R>)[]): Promise<R[]>;
/**
* Make a Promise that fulfills when any item fulfills, and rejects if any item rejects.
*/
function race<R>(promises: (R | Thenable<R>)[]): Promise<R>;
}
declare module 'es6-promise' {
var foo: typeof Promise; // Temp variable to reference Promise in local context
module rsvp {
export var Promise: typeof foo;
}
export = rsvp;
}

View file

@ -1,548 +0,0 @@
// Type definitions for File System API
// Project: http://www.w3.org/TR/file-system-api/
// Definitions by: Kon <http://phyzkit.net/>
// Definitions: https://github.com/borisyankov/DefinitelyTyped
/// <reference path="../filewriter/filewriter.d.ts" />
interface LocalFileSystem {
/**
* Used for storage with no guarantee of persistence.
*/
TEMPORARY:number;
/**
* Used for storage that should not be removed by the user agent without application or user permission.
*/
PERSISTENT:number;
/**
* Requests a filesystem in which to store application data.
* @param type Whether the filesystem requested should be persistent, as defined above. Use one of TEMPORARY or PERSISTENT.
* @param size This is an indicator of how much storage space, in bytes, the application expects to need.
* @param successCallback The callback that is called when the user agent provides a filesystem.
* @param errorCallback A callback that is called when errors happen, or when the request to obtain the filesystem is denied.
*/
requestFileSystem(type:number, size:number, successCallback:FileSystemCallback, errorCallback?:ErrorCallback):void;
/**
* Allows the user to look up the Entry for a file or directory referred to by a local URL.
* @param url A URL referring to a local file in a filesystem accessable via this API.
* @param successCallback A callback that is called to report the Entry to which the supplied URL refers.
* @param errorCallback A callback that is called when errors happen, or when the request to obtain the Entry is denied.
*/
resolveLocalFileSystemURL(url:string, successCallback:EntryCallback, errorCallback?:ErrorCallback):void;
/**
* see requestFileSystem.
*/
webkitRequestFileSystem(type:number, size:number, successCallback:FileSystemCallback, errorCallback?:ErrorCallback):void;
}
interface LocalFileSystemSync {
/**
* Used for storage with no guarantee of persistence.
*/
TEMPORARY:number;
/**
* Used for storage that should not be removed by the user agent without application or user permission.
*/
PERSISTENT:number;
/**
* Requests a filesystem in which to store application data.
* @param type Whether the filesystem requested should be persistent, as defined above. Use one of TEMPORARY or PERSISTENT.
* @param size This is an indicator of how much storage space, in bytes, the application expects to need.
*/
requestFileSystemSync(type:number, size:number):FileSystemSync;
/**
* Allows the user to look up the Entry for a file or directory referred to by a local URL.
* @param url A URL referring to a local file in a filesystem accessable via this API.
*/
resolveLocalFileSystemSyncURL(url:string):EntrySync;
/**
* see requestFileSystemSync
*/
webkitRequestFileSystemSync(type:number, size:number):FileSystemSync;
}
interface Metadata {
/**
* This is the time at which the file or directory was last modified.
* @readonly
*/
modificationTime:Date;
/**
* The size of the file, in bytes. This must return 0 for directories.
* @readonly
*/
size:number;
}
interface Flags {
/**
* Used to indicate that the user wants to create a file or directory if it was not previously there.
*/
create?:boolean;
/**
* By itself, exclusive must have no effect. Used with create, it must cause getFile and getDirectory to fail if the target path already exists.
*/
exclusive?:boolean;
}
/**
* This interface represents a file system.
*/
interface FileSystem{
/**
* This is the name of the file system. The specifics of naming filesystems is unspecified, but a name must be unique across the list of exposed file systems.
* @readonly
*/
name: string;
/**
* The root directory of the file system.
* @readonly
*/
root: DirectoryEntry;
}
interface Entry {
/**
* Entry is a file.
*/
isFile:boolean;
/**
* Entry is a directory.
*/
isDirectory:boolean;
/**
* Look up metadata about this entry.
* @param successCallback A callback that is called with the time of the last modification.
* @param errorCallback ErrorCallback A callback that is called when errors happen.
*/
getMetadata(successCallback:MetadataCallback, errorCallback?:ErrorCallback):void;
/**
* The name of the entry, excluding the path leading to it.
*/
name:string;
/**
* The full absolute path from the root to the entry.
*/
fullPath:string;
/**
* The file system on which the entry resides.
*/
filesystem:FileSystem;
/**
* Move an entry to a different location on the file system. It is an error to try to:
*
* <ui>
* <li>move a directory inside itself or to any child at any depth;</li>
* <li>move an entry into its parent if a name different from its current one isn't provided;</li>
* <li>move a file to a path occupied by a directory;</li>
* <li>move a directory to a path occupied by a file;</li>
* <li>move any element to a path occupied by a directory which is not empty.</li>
* <ul>
*
* A move of a file on top of an existing file must attempt to delete and replace that file.
* A move of a directory on top of an existing empty directory must attempt to delete and replace that directory.
*/
moveTo(parent:DirectoryEntry, newName?:string, successCallback?:EntryCallback, errorCallback?:ErrorCallback):string;
/**
* Copy an entry to a different location on the file system. It is an error to try to:
*
* <ul>
* <li> copy a directory inside itself or to any child at any depth;</li>
* <li> copy an entry into its parent if a name different from its current one isn't provided;</li>
* <li> copy a file to a path occupied by a directory;</li>
* <li> copy a directory to a path occupied by a file;</li>
* <li> copy any element to a path occupied by a directory which is not empty.</li>
* <li> A copy of a file on top of an existing file must attempt to delete and replace that file.</li>
* <li> A copy of a directory on top of an existing empty directory must attempt to delete and replace that directory.</li>
* </ul>
*
* Directory copies are always recursive--that is, they copy all contents of the directory.
*/
copyTo(parent:DirectoryEntry, newName?:string, successCallback?:EntryCallback, errorCallback?:ErrorCallback):string;
/**
* Returns a URL that can be used to identify this entry. Unlike the URN defined in [FILE-API-ED], it has no specific expiration; as it describes a location on disk, it should be valid at least as long as that location exists.
*/
toURL():string;
/**
* Deletes a file or directory. It is an error to attempt to delete a directory that is not empty. It is an error to attempt to delete the root directory of a filesystem.
* @param successCallback A callback that is called on success.
* @param errorCallback A callback that is called when errors happen.
*/
remove(successCallback:VoidCallback, errorCallback?:ErrorCallback):void;
/**
* Look up the parent DirectoryEntry containing this Entry. If this Entry is the root of its filesystem, its parent is itself.
* @param successCallback A callback that is called to return the parent Entry.
* @param errorCallback A callback that is called when errors happen.
*/
getParent(successCallback:DirectoryEntryCallback, errorCallback?:ErrorCallback):void;
}
/**
* This interface represents a directory on a file system.
*/
interface DirectoryEntry extends Entry {
/**
* Creates a new DirectoryReader to read Entries from this Directory.
*/
createReader():DirectoryReader;
/**
* Creates or looks up a file.
* @param path Either an absolute path or a relative path from this DirectoryEntry to the file to be looked up or created. It is an error to attempt to create a file whose immediate parent does not yet exist.
* @param options
* <ul>
* <li>If create and exclusive are both true, and the path already exists, getFile must fail.</li>
* <li>If create is true, the path doesn't exist, and no other error occurs, getFile must create it as a zero-length file and return a corresponding FileEntry.</li>
* <li>If create is not true and the path doesn't exist, getFile must fail.</li>
* <li>If create is not true and the path exists, but is a directory, getFile must fail.</li>
* <li>Otherwise, if no other error occurs, getFile must return a FileEntry corresponding to path.</li>
* </ul>
* @param successCallback A callback that is called to return the File selected or created.
* @param errorCallback A callback that is called when errors happen.
*/
getFile(path:string, options?:Flags, successCallback?:FileEntryCallback, errorCallback?:ErrorCallback):void;
/**
* Creates or looks up a directory.
* @param path Either an absolute path or a relative path from this DirectoryEntry to the directory to be looked up or created. It is an error to attempt to create a directory whose immediate parent does not yet exist.
* @param options
* <ul>
* <li>If create and exclusive are both true and the path already exists, getDirectory must fail.</li>
* <li>If create is true, the path doesn't exist, and no other error occurs, getDirectory must create and return a corresponding DirectoryEntry.</li>
* <li>If create is not true and the path doesn't exist, getDirectory must fail.</li>
* <li>If create is not true and the path exists, but is a file, getDirectory must fail.</li>
* <li>Otherwise, if no other error occurs, getDirectory must return a DirectoryEntry corresponding to path.</li>
* </ul>
* @param successCallback A callback that is called to return the DirectoryEntry selected or created.
* @param errorCallback A callback that is called when errors happen.
*
*/
getDirectory(path:string, options?:Flags, successCallback?:DirectoryEntryCallback, errorCallback?:ErrorCallback):void;
/**
* Deletes a directory and all of its contents, if any. In the event of an error [e.g. trying to delete a directory that contains a file that cannot be removed], some of the contents of the directory may be deleted. It is an error to attempt to delete the root directory of a filesystem.
* @param successCallback A callback that is called on success.
* @param errorCallback A callback that is called when errors happen.
*/
removeRecursively(successCallback:VoidCallback, errorCallback?:ErrorCallback):void;
}
/**
* This interface lets a user list files and directories in a directory. If there are no additions to or deletions from a directory between the first and last call to readEntries, and no errors occur, then:
* <ul>
* <li> A series of calls to readEntries must return each entry in the directory exactly once.</li>
* <li> Once all entries have been returned, the next call to readEntries must produce an empty array.</li>
* <li> If not all entries have been returned, the array produced by readEntries must not be empty.</li>
* <li> The entries produced by readEntries must not include the directory itself ["."] or its parent [".."].</li>
* </ul>
*/
interface DirectoryReader {
/**
* Read the next block of entries from this directory.
* @param successCallback Called once per successful call to readEntries to deliver the next previously-unreported set of Entries in the associated Directory. If all Entries have already been returned from previous invocations of readEntries, successCallback must be called with a zero-length array as an argument.
* @param errorCallback A callback indicating that there was an error reading from the Directory.
*/
readEntries(successCallback:EntriesCallback, errorCallback?:ErrorCallback):void;
}
/**
* This interface represents a file on a file system.
*/
interface FileEntry extends Entry {
/**
* Creates a new FileWriter associated with the file that this FileEntry represents.
* @param successCallback A callback that is called with the new FileWriter.
* @param errorCallback A callback that is called when errors happen.
*/
createWriter(successCallback:FileWriterCallback, errorCallback?:ErrorCallback):void;
/**
* Returns a File that represents the current state of the file that this FileEntry represents.
* @param successCallback A callback that is called with the File.
* @param errorCallback A callback that is called when errors happen.
*/
file(successCallback:FileCallback, errorCallback?:ErrorCallback):void;
}
/**
* When requestFileSystem() succeeds, the following callback is made.
*/
interface FileSystemCallback {
/**
* @param filesystem The file systems to which the app is granted access.
*/
(filesystem:FileSystem):void;
}
/**
* This interface is the callback used to look up Entry objects.
*/
interface EntryCallback {
/**
* @param entry
*/
(entry:Entry):void;
}
/**
* This interface is the callback used to look up FileEntry objects.
*/
interface FileEntryCallback {
/**
* @param entry
*/
(entry:FileEntry):void;
}
/**
* This interface is the callback used to look up DirectoryEntry objects.
*/
interface DirectoryEntryCallback {
/**
* @param entry
*/
(entry:DirectoryEntry):void;
}
/**
* When readEntries() succeeds, the following callback is made.
*/
interface EntriesCallback {
(entries:Entry[]):void;
}
/**
* This interface is the callback used to look up file and directory metadata.
*/
interface MetadataCallback {
(metadata:Metadata):void;
}
/**
* This interface is the callback used to create a FileWriter.
*/
interface FileWriterCallback {
(fileWriter:FileWriter):void;
}
/**
* This interface is the callback used to obtain a File.
*/
interface FileCallback {
(file:File):void;
}
/**
* This interface is the generic callback used to indicate success of an asynchronous method.
*/
interface VoidCallback {
():void;
}
/**
* When an error occurs, the following callback is made.
*/
interface ErrorCallback {
(err:DOMError):void;
}
/**
* This interface represents a file system.
*/
interface FileSystemSync {
/**
* This is the name of the file system. The specifics of naming filesystems is unspecified, but a name must be unique across the list of exposed file systems.
*/
name:string;
/**
* root The root directory of the file system.
*/
root:DirectoryEntrySync;
}
/**
* An abstract interface representing entries in a file system, each of which may be a FileEntrySync or DirectoryEntrySync.
*/
interface EntrySync{
/**
* EntrySync is a file.
* @readonly
*/
isFile:boolean;
/**
* EntrySync is a directory.
* @readonly
*/
isDirectory:boolean;
/**
* Look up metadata about this entry.
*/
getMetadata():Metadata;
/**
* The name of the entry, excluding the path leading to it.
*/
name:string;
/**
* The full absolute path from the root to the entry.
*/
fullPath:string;
/**
* The file system on which the entry resides.
*/
filesystem:FileSystemSync;
/**
* Move an entry to a different location on the file system. It is an error to try to:
* <ul>
* <li> move a directory inside itself or to any child at any depth;</li>
* <li> move an entry into its parent if a name different from its current one isn't provided;</li>
* <li> move a file to a path occupied by a directory;</li>
* <li> move a directory to a path occupied by a file;</li>
* <li> move any element to a path occupied by a directory which is not empty.</li>
* </ui>
* A move of a file on top of an existing file must attempt to delete and replace that file. A move of a directory on top of an existing empty directory must attempt to delete and replace that directory.
* @param parent The directory to which to move the entry.
* @param newName The new name of the entry. Defaults to the EntrySync's current name if unspecified.
*/
moveTo(parent:DirectoryEntrySync, newName?:string):EntrySync;
/**
* Copy an entry to a different location on the file system. It is an error to try to:
* <ul>
* <li> copy a directory inside itself or to any child at any depth;</li>
* <li> copy an entry into its parent if a name different from its current one isn't provided;</li>
* <li> copy a file to a path occupied by a directory;</li>
* <li> copy a directory to a path occupied by a file;</li>
* <li> copy any element to a path occupied by a directory which is not empty.</li>
* </ui>
* A copy of a file on top of an existing file must attempt to delete and replace that file.
* A copy of a directory on top of an existing empty directory must attempt to delete and replace that directory.
* Directory copies are always recursive--that is, they copy all contents of the directory.
*/
copyTo(parent:DirectoryEntrySync, newName?:string):EntrySync;
/**
* Returns a URL that can be used to identify this entry. Unlike the URN defined in [FILE-API-ED], it has no specific expiration; as it describes a location on disk, it should be valid at least as long as that location exists.
*/
toURL():string;
/**
* Deletes a file or directory. It is an error to attempt to delete a directory that is not empty. It is an error to attempt to delete the root directory of a filesystem.
*/
remove ():void;
/**
* Look up the parent DirectoryEntrySync containing this Entry. If this EntrySync is the root of its filesystem, its parent is itself.
*/
getParent():DirectoryEntrySync;
}
/**
* This interface represents a directory on a file system.
*/
interface DirectoryEntrySync extends EntrySync {
/**
* Creates a new DirectoryReaderSync to read EntrySyncs from this DirectorySync.
*/
createReader():DirectoryReaderSync;
/**
* Creates or looks up a directory.
* @param path Either an absolute path or a relative path from this DirectoryEntrySync to the file to be looked up or created. It is an error to attempt to create a file whose immediate parent does not yet exist.
* @param options
* <ul>
* <li> If create and exclusive are both true and the path already exists, getFile must fail.</li>
* <li> If create is true, the path doesn't exist, and no other error occurs, getFile must create it as a zero-length file and return a corresponding FileEntry.</li>
* <li> If create is not true and the path doesn't exist, getFile must fail.</li>
* <li> If create is not true and the path exists, but is a directory, getFile must fail.</li>
* <li> Otherwise, if no other error occurs, getFile must return a FileEntrySync corresponding to path.</li>
* </ul>
*/
getFile(path:string, options?:Flags):FileEntrySync;
/**
* Creates or looks up a directory.
* @param path Either an absolute path or a relative path from this DirectoryEntrySync to the directory to be looked up or created. It is an error to attempt to create a directory whose immediate parent does not yet exist.
* @param options
* <ul>
* <li> If create and exclusive are both true and the path already exists, getDirectory must fail.</li>
* <li> If create is true, the path doesn't exist, and no other error occurs, getDirectory must create and return a corresponding DirectoryEntry.</li>
* <li> If create is not true and the path doesn't exist, getDirectory must fail.</li>
* <li> If create is not true and the path exists, but is a file, getDirectory must fail.</li>
* <li> Otherwise, if no other error occurs, getDirectory must return a DirectoryEntrySync corresponding to path.</li>
* </ul>
*/
getDirectory(path:string, options?:Flags):DirectoryEntrySync;
/**
* Deletes a directory and all of its contents, if any. In the event of an error [e.g. trying to delete a directory that contains a file that cannot be removed], some of the contents of the directory may be deleted. It is an error to attempt to delete the root directory of a filesystem.
*/
removeRecursively():void;
}
/**
* This interface lets a user list files and directories in a directory. If there are no additions to or deletions from a directory between the first and last call to readEntries, and no errors occur, then:
* <ul>
* <li> A series of calls to readEntries must return each entry in the directory exactly once.</li>
* <li> Once all entries have been returned, the next call to readEntries must produce an empty array.</li>
* <li> If not all entries have been returned, the array produced by readEntries must not be empty.</li>
* <li> The entries produced by readEntries must not include the directory itself ["."] or its parent [".."].</li>
* </ul>
*/
interface DirectoryReaderSync {
/**
* Read the next block of entries from this directory.
*/
readEntries():EntrySync[];
}
/**
* This interface represents a file on a file system.
*/
interface FileEntrySync extends EntrySync {
/**
* Creates a new FileWriterSync associated with the file that this FileEntrySync represents.
*/
createWriter():FileWriterSync;
/**
* Returns a File that represents the current state of the file that this FileEntrySync represents.
*/
file():File;
}
interface Window extends LocalFileSystem, LocalFileSystemSync{
}
interface WorkerGlobalScope extends LocalFileSystem, LocalFileSystemSync{
}

View file

@ -1,176 +0,0 @@
// Type definitions for File API: Writer
// Project: http://www.w3.org/TR/file-writer-api/
// Definitions by: Kon <http://phyzkit.net/>
// Definitions: https://github.com/borisyankov/DefinitelyTyped
/**
* This interface provides methods to monitor the asynchronous writing of blobs to disk using progress events [PROGRESS-EVENTS] and event handler attributes.
* This interface is specified to be used within the context of the global object (Window [HTML5]) and within Web Workers (WorkerUtils [WEBWORKERS-ED]).
*/
interface FileSaver extends EventTarget {
/**
* When the abort method is called, user agents must run the steps below:
* <ol>
* <li> If readyState == DONE or readyState == INIT, terminate this overall series of steps without doing anything else. </li>
* <li> Set readyState to DONE. </li>
* <li> If there are any tasks from the object's FileSaver task source in one of the task queues, then remove those tasks. </li>
* <li> Terminate the write algorithm being processed. </li>
* <li> Set the error attribute to a DOMError object of type "AbortError". </li>
* <li> Fire a progress event called abort </li>
* <li> Fire a progress event called writeend </li>
* <li> Terminate this algorithm. </li>
* </ol>
*/
abort():void;
/**
* The blob is being written.
* @readonly
*/
INIT:number;
/**
* The object has been constructed, but there is no pending write.
* @readonly
*/
WRITING:number;
/**
* The entire Blob has been written to the file, an error occurred during the write, or the write was aborted using abort(). The FileSaver is no longer writing the blob.
* @readonly
*/
DONE:number;
/**
* The FileSaver object can be in one of 3 states. The readyState attribute, on getting, must return the current state, which must be one of the following values:
* <ul>
* <li>INIT</li>
* <li>WRITING</li>
* <li>DONE</li>
* <ul>
* @readonly
*/
readyState:number;
/**
* The last error that occurred on the FileSaver.
* @readonly
*/
error:DOMError;
/**
* Handler for writestart events
*/
onwritestart:Function;
/**
* Handler for progress events.
*/
onprogress:Function;
/**
* Handler for write events.
*/
onwrite:Function;
/**
* Handler for abort events.
*/
onabort:Function;
/**
* Handler for error events.
*/
onerror:Function;
/**
* Handler for writeend events.
*/
onwriteend:Function;
}
declare var FileSaver: {
/**
* When the FileSaver constructor is called, the user agent must return a new FileSaver object with readyState set to INIT.
* This constructor must be visible when the script's global object is either a Window object or an object implementing the WorkerUtils interface.
*/
new(data:Blob): FileSaver;
}
/**
* This interface expands on the FileSaver interface to allow for multiple write actions, rather than just saving a single Blob.
*/
interface FileWriter extends FileSaver {
/**
* The byte offset at which the next write to the file will occur. This must be no greater than length.
* A newly-created FileWriter must have position set to 0.
*/
position:number;
/**
* The length of the file. If the user does not have read access to the file, this must be the highest byte offset at which the user has written.
*/
length:number;
/**
* Write the supplied data to the file at position.
* @param data The blob to write.
*/
write(data:Blob):void;
/**
* Seek sets the file position at which the next write will occur.
* @param offset If nonnegative, an absolute byte offset into the file. If negative, an offset back from the end of the file.
*/
seek(offset:number):void;
/**
* Changes the length of the file to that specified. If shortening the file, data beyond the new length must be discarded. If extending the file, the existing data must be zero-padded up to the new length.
* @param size The size to which the length of the file is to be adjusted, measured in bytes.
*/
truncate(size:number):void;
}
/**
* This interface lets users write, truncate, and append to files using simple synchronous calls.
* This interface is specified to be used only within Web Workers (WorkerUtils [WEBWORKERS]).
*/
interface FileWriterSync {
/**
* The byte offset at which the next write to the file will occur. This must be no greater than length.
*/
position:number;
/**
* The length of the file. If the user does not have read access to the file, this must be the highest byte offset at which the user has written.
*/
length:number;
/**
* Write the supplied data to the file at position. Upon completion, position will increase by data.size.
* @param data The blob to write.
*/
write(data:Blob):void;
/**
* Seek sets the file position at which the next write will occur.
* @param offset An absolute byte offset into the file. If offset is greater than length, length is used instead. If offset is less than zero, length is added to it, so that it is treated as an offset back from the end of the file. If it is still less than zero, zero is used.
*/
seek(offset:number):void;
/**
* Changes the length of the file to that specified. If shortening the file, data beyond the new length must be discarded. If extending the file, the existing data must be zero-padded up to the new length.
* Upon successful completion:
* <ul>
* <li>length must be equal to size.</li>
* <li>position must be the lesser of
* <ul>
* <li>its pre-truncate value,</li>
* <li>size.</li>
* </ul>
* </li>
* </ul>
* @param size The size to which the length of the file is to be adjusted, measured in bytes.
*/
truncate(size:number):void;
}

View file

@ -1,11 +1,5 @@
// Type definitions for Angular JS 1.4+
// Project: http://angularjs.org
// Definitions by: Diego Vilar <http://github.com/diegovilar>
// Definitions: https://github.com/borisyankov/DefinitelyTyped
/// <reference path="../jquery/jquery.d.ts" />
// Generated by typings
// Source: https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/af5b8275d1f2b92738b93fddabc461fc20c553a1/angularjs/angular.d.ts
declare var angular: angular.IAngularStatic;
// Support for painless dependency injection
@ -1762,4 +1756,4 @@ declare module angular {
}
}
}
}

View file

@ -0,0 +1,8 @@
{
"resolution": "main",
"tree": {
"src": "https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/af5b8275d1f2b92738b93fddabc461fc20c553a1/angularjs/angular.d.ts",
"raw": "github:DefinitelyTyped/DefinitelyTyped/angularjs/angular.d.ts#af5b8275d1f2b92738b93fddabc461fc20c553a1",
"typings": "https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/af5b8275d1f2b92738b93fddabc461fc20c553a1/angularjs/angular.d.ts"
}
}

View file

@ -1,14 +1,5 @@
// Type definitions for Chrome extension development
// Project: http://developer.chrome.com/extensions/
// Definitions by: Matthew Kimber <https://github.com/matthewkimber>, otiai10 <https://github.com/otiai10>, couven92 <https://gitbus.com/couven92>
// Definitions: https://github.com/borisyankov/DefinitelyTyped
/// <reference path='../webrtc/MediaStream.d.ts'/>
/// <reference path='../filesystem/filesystem.d.ts' />
////////////////////
// Global object
////////////////////
// Generated by typings
// Source: https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/3191f6e0088eee07c4d8fd24e4d27a40a60d9eb9/chrome/chrome.d.ts
interface Window {
chrome: typeof chrome;
}
@ -8227,4 +8218,4 @@ declare module chrome.windows {
* Note: On some Linux window managers, WINDOW_ID_NONE will always be sent immediately preceding a switch from one chrome window to another.
*/
var onFocusChanged: WindowIdEvent;
}
}

View file

@ -0,0 +1,8 @@
{
"resolution": "main",
"tree": {
"src": "https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/3191f6e0088eee07c4d8fd24e4d27a40a60d9eb9/chrome/chrome.d.ts",
"raw": "github:DefinitelyTyped/DefinitelyTyped/chrome/chrome.d.ts#3191f6e0088eee07c4d8fd24e4d27a40a60d9eb9",
"typings": "https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/3191f6e0088eee07c4d8fd24e4d27a40a60d9eb9/chrome/chrome.d.ts"
}
}

View file

@ -1,27 +1,5 @@
// Type definitions for jQuery 1.10.x / 2.0.x
// Project: http://jquery.com/
// Definitions by: Boris Yankov <https://github.com/borisyankov/>, Christian Hoffmeister <https://github.com/choffmeister>, Steve Fenton <https://github.com/Steve-Fenton>, Diullei Gomes <https://github.com/Diullei>, Tass Iliopoulos <https://github.com/tasoili>, Jason Swearingen <https://github.com/jasons-novaleaf>, Sean Hill <https://github.com/seanski>, Guus Goossens <https://github.com/Guuz>, Kelly Summerlin <https://github.com/ksummerlin>, Basarat Ali Syed <https://github.com/basarat>, Nicholas Wolverson <https://github.com/nwolverson>, Derek Cicerone <https://github.com/derekcicerone>, Andrew Gaspar <https://github.com/AndrewGaspar>, James Harrison Fisher <https://github.com/jameshfisher>, Seikichi Kondo <https://github.com/seikichi>, Benjamin Jackman <https://github.com/benjaminjackman>, Poul Sorensen <https://github.com/s093294>, Josh Strobl <https://github.com/JoshStrobl>, John Reilly <https://github.com/johnnyreilly/>, Dick van den Brink <https://github.com/DickvdBrink>
// Definitions: https://github.com/borisyankov/DefinitelyTyped
/* *****************************************************************************
Copyright (c) Microsoft Corporation. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License"); you may not use
this file except in compliance with the License. You may obtain a copy of the
License at http://www.apache.org/licenses/LICENSE-2.0
THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
MERCHANTABLITY OR NON-INFRINGEMENT.
See the Apache Version 2.0 License for specific language governing permissions
and limitations under the License.
***************************************************************************** */
/**
* Interface for the AJAX setting that will configure the AJAX request
*/
// Generated by typings
// Source: https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/af5b8275d1f2b92738b93fddabc461fc20c553a1/jquery/jquery.d.ts
interface JQueryAjaxSettings {
/**
* The content type sent in the request header that tells the server what kind of response it will accept in return. If the accepts setting needs modification, it is recommended to do so once in the $.ajaxSetup() method.
@ -3187,4 +3165,4 @@ declare module "jquery" {
export = $;
}
declare var jQuery: JQueryStatic;
declare var $: JQueryStatic;
declare var $: JQueryStatic;

View file

@ -0,0 +1,8 @@
{
"resolution": "main",
"tree": {
"src": "https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/af5b8275d1f2b92738b93fddabc461fc20c553a1/jquery/jquery.d.ts",
"raw": "github:DefinitelyTyped/DefinitelyTyped/jquery/jquery.d.ts#af5b8275d1f2b92738b93fddabc461fc20c553a1",
"typings": "https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/af5b8275d1f2b92738b93fddabc461fc20c553a1/jquery/jquery.d.ts"
}
}

View file

@ -1,8 +1,5 @@
// Type definitions for Lo-Dash
// Project: http://lodash.com/
// Definitions by: Brian Zengel <https://github.com/bczengel>, Ilya Mochalov <https://github.com/chrootsu>
// Definitions: https://github.com/borisyankov/DefinitelyTyped
// Generated by typings
// Source: https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/e5a27ea95e47b95333784f1f0d590127b4e39a89/lodash/lodash.d.ts
declare var _: _.LoDashStatic;
declare module _ {
@ -13532,4 +13529,4 @@ declare module _ {
declare module "lodash" {
export = _;
}
}

View file

@ -0,0 +1,8 @@
{
"resolution": "main",
"tree": {
"src": "https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/e5a27ea95e47b95333784f1f0d590127b4e39a89/lodash/lodash.d.ts",
"raw": "github:DefinitelyTyped/DefinitelyTyped/lodash/lodash.d.ts#e5a27ea95e47b95333784f1f0d590127b4e39a89",
"typings": "https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/e5a27ea95e47b95333784f1f0d590127b4e39a89/lodash/lodash.d.ts"
}
}

View file

@ -0,0 +1,42 @@
// Generated by typings
// Source: https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/56295f5058cac7ae458540423c50ac2dcf9fc711/node-uuid/node-uuid-base.d.ts
declare namespace __NodeUUID {
interface UUIDOptions {
/**
* Node id as Array of 6 bytes (per 4.1.6).
* Default: Randomly generated ID. See note 1.
*/
node?: any[];
/**
* (Number between 0 - 0x3fff) RFC clock sequence.
* Default: An internally maintained clockseq is used.
*/
clockseq?: number;
/**
* (Number | Date) Time in milliseconds since unix Epoch.
* Default: The current time is used.
*/
msecs?: number|Date;
/**
* (Number between 0-9999) additional time, in 100-nanosecond units. Ignored if msecs is unspecified.
* Default: internal uuid counter is used, as per 4.2.1.2.
*/
nsecs?: number;
}
interface UUID {
v1(options?: UUIDOptions): string;
v1(options?: UUIDOptions, buffer?: number[], offset?: number): number[];
v4(options?: UUIDOptions): string;
v4(options?: UUIDOptions, buffer?: number[], offset?: number): number[];
parse(id: string, buffer?: number[], offset?: number): number[];
unparse(buffer: number[], offset?: number): string;
}
}

View file

@ -0,0 +1,8 @@
{
"resolution": "main",
"tree": {
"src": "https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/56295f5058cac7ae458540423c50ac2dcf9fc711/node-uuid/node-uuid-base.d.ts",
"raw": "registry:dt/node-uuid/node-uuid-base#0.0.0+20160316155526",
"typings": "https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/56295f5058cac7ae458540423c50ac2dcf9fc711/node-uuid/node-uuid-base.d.ts"
}
}

View file

@ -0,0 +1,6 @@
// Generated by typings
// Source: https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/56295f5058cac7ae458540423c50ac2dcf9fc711/node-uuid/node-uuid-cjs.d.ts
declare module "node-uuid" {
var uuid: __NodeUUID.UUID;
export = uuid;
}

View file

@ -0,0 +1,8 @@
{
"resolution": "main",
"tree": {
"src": "https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/56295f5058cac7ae458540423c50ac2dcf9fc711/node-uuid/node-uuid-cjs.d.ts",
"raw": "registry:dt/node-uuid/node-uuid-cjs#0.0.0+20160316155526",
"typings": "https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/56295f5058cac7ae458540423c50ac2dcf9fc711/node-uuid/node-uuid-cjs.d.ts"
}
}

63
typings/globals/rangy/index.d.ts vendored Normal file
View file

@ -0,0 +1,63 @@
// Generated by typings
// Source: https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/56295f5058cac7ae458540423c50ac2dcf9fc711/rangy/rangy.d.ts
interface RangyRange extends Range {
setStartAndEnd(startNode:Node, startOffset:number, endNode?:Node, endOffset?:number):any;
setStartAndEnd(startNode:Node, startOffset:number, endOffset:number):any;
canSurroundContents():boolean;
isValid():boolean;
toHtml():string;
compareNode(node:Node):any;
intersectsOrTouchesRange(range:RangyRange):boolean;
intersectsRange(range:RangyRange):boolean;
intersection(range:RangyRange):RangyRange;
union(range:RangyRange):RangyRange;
containsNode(node:Node, partial:boolean):boolean;
containsNodeContents(node:Node):boolean;
containsNodeText(node:Node):boolean;
containsRange(range:RangyRange):boolean;
splitBoundaries():any;
normalizeBoundaries():any;
collapseToPoint(node:Node, offset:number):any;
collapseBefore(node:Node):any;
collapseAfter(node:Node):any;
getNodes(nodeTypes?:any[], filter?:(node:Node) => boolean):Node[];
getBookmark(containerNode?:Node):{start:number, end:number};
moveToBookmark(bookmark:Object):any;
getDocument():Document;
inspect():string;
equals(range:RangyRange):boolean;
refresh():any;
select():any;
}
interface RangySelection extends Selection {
nativeSelection:Selection;
isBackwards():boolean;
refresh(checkForChanges?:boolean):any;
toHtml():string;
getAllRanges():RangyRange[];
getNativeTextRange():TextRange;
setSingleRange(range:RangyRange):any;
setRanges(ranges:RangyRange[]):any;
getBookmark(containerNode:Node):any;
moveToBookmark(bookmark:Object):any;
saveRanges():Object;
restoreRanges(saved:Object):any;
detach():any;
inspect():string;
}
interface RangyStatic {
createNativeRange(doc?:Document|Window|HTMLIFrameElement):TextRange|Range;
createRange(doc?:Document|Window|HTMLIFrameElement):RangyRange;
createRangyRange(doc?:Document|Window|HTMLIFrameElement):RangyRange;
getNativeSelection(win?:Window):Selection;
getSelection():RangySelection;
addInitListener(listener:(rangy:RangyStatic) => void):any;
shim():any;
createMissingNativeApi():any;
initialized:boolean;
supported:boolean;
}
declare var rangy:RangyStatic;

View file

@ -0,0 +1,8 @@
{
"resolution": "main",
"tree": {
"src": "https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/56295f5058cac7ae458540423c50ac2dcf9fc711/rangy/rangy.d.ts",
"raw": "registry:dt/rangy#0.0.0+20160316155526",
"typings": "https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/56295f5058cac7ae458540423c50ac2dcf9fc711/rangy/rangy.d.ts"
}
}

7
typings/index.d.ts vendored Normal file
View file

@ -0,0 +1,7 @@
/// <reference path="globals/angular/index.d.ts" />
/// <reference path="globals/chrome/index.d.ts" />
/// <reference path="globals/jquery/index.d.ts" />
/// <reference path="globals/lodash/index.d.ts" />
/// <reference path="globals/node-uuid/node-uuid-base/index.d.ts" />
/// <reference path="globals/node-uuid/node-uuid-cjs/index.d.ts" />
/// <reference path="globals/rangy/index.d.ts" />

9
typings/tsd.d.ts vendored
View file

@ -1,9 +0,0 @@
/// <reference path="jquery/jquery.d.ts" />
/// <reference path="angularjs/angular.d.ts" />
/// <reference path="chrome/chrome.d.ts" />
/// <reference path="es6-promise/es6-promise.d.ts" />
/// <reference path="filesystem/filesystem.d.ts" />
/// <reference path="filewriter/filewriter.d.ts" />
/// <reference path="webrtc/MediaStream.d.ts" />
/// <reference path="lodash/lodash.d.ts" />

View file

@ -1,201 +0,0 @@
// Type definitions for WebRTC
// Project: http://dev.w3.org/2011/webrtc/
// Definitions by: Ken Smith <https://github.com/smithkl42/>
// Definitions: https://github.com/borisyankov/DefinitelyTyped
// Taken from http://dev.w3.org/2011/webrtc/editor/getusermedia.html
// version: W3C Editor's Draft 29 June 2015
/// <reference path="../es6-promise/es6-promise.d.ts" />
interface ConstrainBooleanParameters {
exact: boolean;
ideal: boolean;
}
interface NumberRange {
max: number;
min: number;
}
interface ConstrainNumberRange extends NumberRange {
exact: number;
ideal: number;
}
interface ConstrainStringParameters {
exact: string | string[];
ideal: string | string[];
}
interface MediaStreamConstraints {
video?: boolean | MediaTrackConstraints;
audio?: boolean | MediaTrackConstraints;
}
declare module W3C {
type LongRange = NumberRange;
type DoubleRange = NumberRange;
type ConstrainBoolean = boolean | ConstrainBooleanParameters;
type ConstrainNumber = number | ConstrainNumberRange;
type ConstrainLong = ConstrainNumber;
type ConstrainDouble = ConstrainNumber;
type ConstrainString = string | string[] | ConstrainStringParameters;
}
interface MediaTrackConstraints extends MediaTrackConstraintSet {
advanced?: MediaTrackConstraintSet[];
}
interface MediaTrackConstraintSet {
width?: W3C.ConstrainLong;
height?: W3C.ConstrainLong;
aspectRatio?: W3C.ConstrainDouble;
frameRate?: W3C.ConstrainDouble;
facingMode?: W3C.ConstrainString;
volume?: W3C.ConstrainDouble;
sampleRate?: W3C.ConstrainLong;
sampleSize?: W3C.ConstrainLong;
echoCancellation?: W3C.ConstrainBoolean;
latency?: W3C.ConstrainDouble;
deviceId?: W3C.ConstrainString;
groupId?: W3C.ConstrainString;
}
interface MediaTrackSupportedConstraints {
width: boolean;
height: boolean;
aspectRatio: boolean;
frameRate: boolean;
facingMode: boolean;
volume: boolean;
sampleRate: boolean;
sampleSize: boolean;
echoCancellation: boolean;
latency: boolean;
deviceId: boolean;
groupId: boolean;
}
interface MediaStream extends EventTarget {
id: string;
active: boolean;
onactive: EventListener;
oninactive: EventListener;
onaddtrack: (event: MediaStreamTrackEvent) => any;
onremovetrack: (event: MediaStreamTrackEvent) => any;
clone(): MediaStream;
stop(): void;
getAudioTracks(): MediaStreamTrack[];
getVideoTracks(): MediaStreamTrack[];
getTracks(): MediaStreamTrack[];
getTrackById(trackId: string): MediaStreamTrack;
addTrack(track: MediaStreamTrack): void;
removeTrack(track: MediaStreamTrack): void;
}
interface MediaStreamTrackEvent extends Event {
track: MediaStreamTrack;
}
declare enum MediaStreamTrackState {
"live",
"ended"
}
interface MediaStreamTrack extends EventTarget {
id: string;
kind: string;
label: string;
enabled: boolean;
muted: boolean;
remote: boolean;
readyState: MediaStreamTrackState;
onmute: EventListener;
onunmute: EventListener;
onended: EventListener;
onoverconstrained: EventListener;
clone(): MediaStreamTrack;
stop(): void;
getCapabilities(): MediaTrackCapabilities;
getConstraints(): MediaTrackConstraints;
getSettings(): MediaTrackSettings;
applyConstraints(constraints: MediaTrackConstraints): Promise<void>;
}
interface MediaTrackCapabilities {
width: number | W3C.LongRange;
height: number | W3C.LongRange;
aspectRatio: number | W3C.DoubleRange;
frameRate: number | W3C.DoubleRange;
facingMode: string;
volume: number | W3C.DoubleRange;
sampleRate: number | W3C.LongRange;
sampleSize: number | W3C.LongRange;
echoCancellation: boolean[];
latency: number | W3C.DoubleRange;
deviceId: string;
groupId: string;
}
interface MediaTrackSettings {
width: number;
height: number;
aspectRatio: number;
frameRate: number;
facingMode: string;
volume: number;
sampleRate: number;
sampleSize: number;
echoCancellation: boolean;
latency: number;
deviceId: string;
groupId: string;
}
interface MediaStreamError {
name: string;
message: string;
constraintName: string;
}
interface NavigatorGetUserMedia {
(constraints: MediaStreamConstraints,
successCallback: (stream: MediaStream) => void,
errorCallback: (error: MediaStreamError) => void): void;
}
interface Navigator {
getUserMedia: NavigatorGetUserMedia;
webkitGetUserMedia: NavigatorGetUserMedia;
mozGetUserMedia: NavigatorGetUserMedia;
msGetUserMedia: NavigatorGetUserMedia;
mediaDevices: MediaDevices;
}
interface MediaDevices {
getSupportedConstraints(): MediaTrackSupportedConstraints;
getUserMedia(constraints: MediaStreamConstraints): Promise<MediaStream>;
enumerateDevices(): Promise<MediaDeviceInfo[]>;
}
interface MediaDeviceInfo {
label: string;
id: string;
kind: string;
facing: string;
}