diff --git a/.gitignore b/.gitignore index 6d9446a..7404c57 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,9 @@ *~ .idea/ *.iml +atlassian-ide-plugin.xml +node_modules/ +typings/ +app/**/*.js +app/**/*.js.map +npm-debug.log diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 916c442..faf8a09 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,9 +1,6 @@ -#variables: -# NPMPATH: "node_modules/.bin" - stages: -# - build -# - cleanup_build + - build + - cleanup_build - deploy # - cleanup @@ -11,32 +8,50 @@ stages: script: - chmod +x ./deploy.sh - ./deploy.sh + dependencies: + - build_job -#build_job: -# stage: build -# script: -# - npm install -# - $NPMPATH/bower install -# - $NPMPATH/grunt -# tags: -# - javascript -# except: -# - tags -# artifacts: -# paths: -# - dist/*.min.* -# - info/ -# - resources/ -# - index.html -# - manifest.appcache +build_job: + stage: build + script: + - npm install + - npm run tsc + tags: + - javascript + except: + - tags + artifacts: + paths: + - app/*.css + - app/*.html + - app/*.js + - app/*.js.map + - app/converter/*.js + - app/converter/*.js.map + - node_modules/@angular/ + - node_modules/core-js/client/shim.js + - node_modules/zone.js/dist/zone.js + - node_modules/reflect-metadata/Reflect.js + - node_modules/rxjs/ + - node_modules/systemjs/dist/system.src.js + - node_modules/utf8/utf8.js + - node_modules/quoted-printable/quoted-printable.js + - abeezee-regular.woff + - freemono.eot + - freemono.svg + - freemono.ttf + - freemono.woff + - index.html + - package.json + - systemjs.config.js + expire_in: 30 min -#cleanup_build_job: -# stage: cleanup_build -# script: -# - rm -rf node_modules -# - rm -rf bower_components -# - rm -rf dist -# when: on_failure +cleanup_build_job: + stage: cleanup_build + script: + - rm -rf node_modules + - rm -rf typings + when: on_failure develop: stage: deploy @@ -74,5 +89,5 @@ production: # stage: cleanup # script: # - rm -rf node_modules -# - rm -rf bower_components +# - rm -rf typings # when: always diff --git a/abeezee-regular.woff b/abeezee-regular.woff new file mode 100644 index 0000000..86a7468 Binary files /dev/null and b/abeezee-regular.woff differ diff --git a/app/app.component.css b/app/app.component.css new file mode 100644 index 0000000..a1f448b --- /dev/null +++ b/app/app.component.css @@ -0,0 +1,127 @@ +@font-face { + font-family: "ABeeZee"; + font-stretch: normal; + font-style: normal; + font-variant: normal; + font-weight: normal; + src: local("ABeeZee Regular"), + local("ABeeZee-Regular"), + local("ABeeZee"), + url("../abeezee-regular.woff") format("woff"); +} + +@font-face { + font-family: "Free Monospaced"; + src: url("../freemono.eot?") format("eot"), + url("../freemono.woff") format("woff"), + url("../freemono.ttf") format("truetype"), + url("../freemono.svg#FreeMono") format("svg"); + font-weight: normal; + font-style: normal; +} + +.inputwrapper { + font-family: "ABeeZee", sans-serif; + margin: 0 1em 1em 1em; +} + +.textwrapper { + margin: 0 0 1em 0; + padding: 0 1em 0 0; +} + +.arrow_box { + position: relative; + background: #fff; + border: 1px solid #ddd; +} + +.arrow_box:focus { + border-color: #888; +} + +.arrow_box:hover { + border-color: #333; +} + +.arrow_box:after, .arrow_box:before { + top: 100%; + left: 50%; + border: solid transparent; + content: " "; + height: 0; + width: 0; + position: absolute; + pointer-events: none; +} + +.arrow_box:after { + border-color: rgba(255, 255, 255, 0); + border-top-color: #fff; + border-width: 1em; + margin-left: -1em; +} + +.arrow_box:before { + border-color: rgba(221, 221, 221, 0); + border-top-color: #ddd; + border-width: calc(1em + 1px); + margin-left: calc(-1em - 1px); +} + +.arrow_box:focus:before { + border-color: rgba(136, 136, 136, 0); + border-top-color: #888; +} + +.arrow_box:hover:before { + border-color: rgba(51, 51, 51, 0); + border-top-color: #333; +} + +.selectwrapper > .arrow_box { + display: inline-block; +} + +.textinput { + background-color: #fff; + border: none; + color: #000; + font-family: "Free Monospaced", monospace; + height: 10em; + margin: 0; + padding: 0.5em; + resize: vertical; + width: 100%; +} + +.textinput:focus { + border-color: #888; +} + +.textinput:hover { + border-color: #333; +} + +.selectwrapper { + margin: 0 0 1em 0; + padding: 0; + text-align: center; +} + +.select { + background-color: #fff; + border: none; + color: #000; + font-family: "ABeeZee", sans-serif; + margin: 0; + padding: 0.5em; +} + +.option { + /* font-family: "ABeeZee", sans-serif;*/ +} + +.errormessage { + /* font-family: "ABeeZee", sans-serif;*/ +} diff --git a/app/app.component.html b/app/app.component.html new file mode 100644 index 0000000..22b15e3 --- /dev/null +++ b/app/app.component.html @@ -0,0 +1,16 @@ +
+
+ +
+
+
+ +
+
+
{{step.message}}
+
diff --git a/app/app.component.ts b/app/app.component.ts new file mode 100644 index 0000000..79d9816 --- /dev/null +++ b/app/app.component.ts @@ -0,0 +1,61 @@ +import {Component, OnInit} from "@angular/core"; +import {ConverterRegistryService} from "./converterregistry.service"; +import {InputComponentManagerService} from "./inputcomponentmanager.service"; +import {Converter} from "./converter/converter"; +import {NativeLibraryWrapperService} from "./nativelibrarywrapper.service"; + +@Component({ + moduleId: module.id, + selector: "den-app", + templateUrl: "app.component.html", + styleUrls: ["app.component.css"], + providers: [ConverterRegistryService, InputComponentManagerService, NativeLibraryWrapperService] +}) +export class AppComponent extends OnInit { + public steps:any[] = []; + public converters:Converter[] = []; + + constructor(private converterRegistryService:ConverterRegistryService, private inputComponentManagerService:InputComponentManagerService) { + super(); + } + + convert(step:any, $event:any):void { + step.selectedConverter = this.converterRegistryService.getConverter($event.target.selectedOptions[0].id); + this.update(step); + } + + update(step:any):void { + let converter:Converter = step.selectedConverter; + + if (converter !== undefined) { + let content:string = step.content; + let result:string; + try { + result = converter.convert(content); + } catch (error) { + if (typeof console === "object" && typeof console.log === "function") { + console.log(error); + } + result = null; + } + if (result === null) { + step.message = "Error converting. Not applicable?"; + step.error = true; + } else { + step.message = ""; + step.error = false; + if (result !== "") { + let nextComponent:any = this.inputComponentManagerService.getNext(step); + nextComponent.content = result; + this.update(nextComponent); + } + } + } + } + + ngOnInit():void { + this.converters = this.converterRegistryService.getAllConverters(); + this.steps = this.inputComponentManagerService.getAllComponents(); + this.inputComponentManagerService.getFirst(); + } +} diff --git a/app/app.module.ts b/app/app.module.ts new file mode 100644 index 0000000..8988169 --- /dev/null +++ b/app/app.module.ts @@ -0,0 +1,19 @@ +import {NgModule} from "@angular/core"; +import {BrowserModule} from "@angular/platform-browser"; +import {FormsModule} from "@angular/forms"; +import {AppComponent} from "./app.component"; +import {InputareaComponent} from "./inputarea.component"; + +@NgModule({ + imports: [ + BrowserModule, + FormsModule + ], + declarations: [ + AppComponent, + InputareaComponent + ], + bootstrap: [AppComponent] +}) +export class AppModule { +} diff --git a/app/conversioninput.ts b/app/conversioninput.ts new file mode 100644 index 0000000..9f52cca --- /dev/null +++ b/app/conversioninput.ts @@ -0,0 +1,6 @@ +import {ConversionType} from "./conversiontype"; + +export class ConversionInput { + public content:string; + public type:ConversionType; +} diff --git a/app/conversiontype.ts b/app/conversiontype.ts new file mode 100644 index 0000000..4f34586 --- /dev/null +++ b/app/conversiontype.ts @@ -0,0 +1,28 @@ +export enum ConversionType { + ENCODE_BASE64, + DECODE_BASE64 +} + +export namespace ConversionType { + export function getName(type:ConversionType):string { + switch (type) { + case ConversionType.DECODE_BASE64: + return "Decode BASE64"; + case ConversionType.ENCODE_BASE64: + return "Encode BASE64"; + default: + return "Unknown"; + } + } + + export function of(id:number):ConversionType { + switch (id) { + case 0: + return ConversionType.ENCODE_BASE64; + case 1: + return ConversionType.DECODE_BASE64; + default: + return undefined; + } + } +} diff --git a/app/converter/base64decoder.ts b/app/converter/base64decoder.ts new file mode 100644 index 0000000..1b4e5b1 --- /dev/null +++ b/app/converter/base64decoder.ts @@ -0,0 +1,15 @@ +import {Converter} from "./converter"; + +export class Base64Decoder implements Converter { + getDisplayname():string { + return "Decode Base 64"; + } + + getId():string { + return "base64decode"; + } + + convert(input:string):string { + return atob(input); + } +} diff --git a/app/converter/base64encoder.ts b/app/converter/base64encoder.ts new file mode 100644 index 0000000..409636d --- /dev/null +++ b/app/converter/base64encoder.ts @@ -0,0 +1,15 @@ +import {Converter} from "./converter"; + +export class Base64Encoder implements Converter { + getDisplayname():string { + return "Encode Base 64"; + } + + getId():string { + return "base64encode"; + } + + convert(input:string):string { + return btoa(input); + } +} diff --git a/app/converter/bintodecconverter.ts b/app/converter/bintodecconverter.ts new file mode 100644 index 0000000..2c73959 --- /dev/null +++ b/app/converter/bintodecconverter.ts @@ -0,0 +1,14 @@ +import {Converter} from "./converter"; +export class BinToDecConverter implements Converter { + getDisplayname():string { + return "Convert binary to decimal"; + } + + getId():string { + return "bintodec"; + } + + convert(input:string):string { + return parseInt(input, 2).toString(10); + } +} diff --git a/app/converter/converter.ts b/app/converter/converter.ts new file mode 100644 index 0000000..66706f9 --- /dev/null +++ b/app/converter/converter.ts @@ -0,0 +1,5 @@ +export interface Converter { + getDisplayname():string; + getId():string; + convert(input:string):string; +} diff --git a/app/converter/dectobinconverter.ts b/app/converter/dectobinconverter.ts new file mode 100644 index 0000000..8cc2b0d --- /dev/null +++ b/app/converter/dectobinconverter.ts @@ -0,0 +1,14 @@ +import {Converter} from "./converter"; +export class DecToBinConverter implements Converter { + getDisplayname():string { + return "Convert decimal to binary"; + } + + getId():string { + return "dectobin"; + } + + convert(input:string):string { + return parseInt(input, 10).toString(2); + } +} diff --git a/app/converter/dectohexconverter.ts b/app/converter/dectohexconverter.ts new file mode 100644 index 0000000..c0be47f --- /dev/null +++ b/app/converter/dectohexconverter.ts @@ -0,0 +1,14 @@ +import {Converter} from "./converter"; +export class DecToHexConverter implements Converter { + getDisplayname():string { + return "Convert decimal to heximal"; + } + + getId():string { + return "dectohex"; + } + + convert(input:string):string { + return parseInt(input, 10).toString(16); + } +} diff --git a/app/converter/hextodecconverter.ts b/app/converter/hextodecconverter.ts new file mode 100644 index 0000000..c6b3dba --- /dev/null +++ b/app/converter/hextodecconverter.ts @@ -0,0 +1,14 @@ +import {Converter} from "./converter"; +export class HexToDecConverter implements Converter { + getDisplayname():string { + return "Convert heximal to decimal"; + } + + getId():string { + return "hextodec"; + } + + convert(input:string):string { + return parseInt(input, 16).toString(10); + } +} diff --git a/app/converter/htmlentitiesdecoder.ts b/app/converter/htmlentitiesdecoder.ts new file mode 100644 index 0000000..2a793ce --- /dev/null +++ b/app/converter/htmlentitiesdecoder.ts @@ -0,0 +1,19 @@ +import {Converter} from "./converter"; + +export class HTMLEntitiesDecoder implements Converter { + getDisplayname():string { + return "Decode HTML entities"; + } + + getId():string { + return "decodehtmlentities"; + } + + convert(input:string):string { + return input + .replace(/\"\;/g, "\"") + .replace(/\>\;/g, ">") + .replace(/\<\;/g, "<") + .replace(/\&\;/g, "&"); + } +} diff --git a/app/converter/htmlentitiesencoder.ts b/app/converter/htmlentitiesencoder.ts new file mode 100644 index 0000000..cf626b6 --- /dev/null +++ b/app/converter/htmlentitiesencoder.ts @@ -0,0 +1,19 @@ +import {Converter} from "./converter"; + +export class HTMLEntitiesEncoder implements Converter { + getDisplayname():string { + return "Encode HTML entities"; + } + + getId():string { + return "encodehtmlentities"; + } + + convert(input:string):string { + return input + .replace(/\&/g, "&") + .replace(/\/g, ">") + .replace(/\"/g, """); + } +} diff --git a/app/converter/quotedprintabledecoder.ts b/app/converter/quotedprintabledecoder.ts new file mode 100644 index 0000000..6787ff1 --- /dev/null +++ b/app/converter/quotedprintabledecoder.ts @@ -0,0 +1,19 @@ +import {Converter} from "./converter"; +import {NativeLibraryWrapperService} from "../nativelibrarywrapper.service"; + +export class QuotedPrintableDecoder implements Converter { + constructor(private nativeLibraryWrapperService:NativeLibraryWrapperService) { + } + + getDisplayname():string { + return "Decode quoted printable"; + } + + getId():string { + return "decodequotedprintable"; + } + + convert(input:string):string { + return this.nativeLibraryWrapperService.utf8.decode(this.nativeLibraryWrapperService.quotedPrintable.decode(input)); + } +} diff --git a/app/converter/quotedprintableencoder.ts b/app/converter/quotedprintableencoder.ts new file mode 100644 index 0000000..048dbc6 --- /dev/null +++ b/app/converter/quotedprintableencoder.ts @@ -0,0 +1,19 @@ +import {Converter} from "./converter"; +import {NativeLibraryWrapperService} from "../nativelibrarywrapper.service"; + +export class QuotedPrintableEncoder implements Converter { + constructor(private nativeLibraryWrapperService:NativeLibraryWrapperService) { + } + + getDisplayname():string { + return "Encode quoted printable"; + } + + getId():string { + return "encodequotedprintable"; + } + + convert(input:string):string { + return this.nativeLibraryWrapperService.quotedPrintable.encode(this.nativeLibraryWrapperService.utf8.encode(input)); + } +} diff --git a/app/converter/uricomponentdecoder.ts b/app/converter/uricomponentdecoder.ts new file mode 100644 index 0000000..ee96e28 --- /dev/null +++ b/app/converter/uricomponentdecoder.ts @@ -0,0 +1,15 @@ +import {Converter} from "./converter"; + +export class URIComponentDecoder implements Converter { + getDisplayname():string { + return "Decode URI component"; + } + + getId():string { + return "uricomponentdecode"; + } + + convert(input:string):string { + return decodeURIComponent(input); + } +} diff --git a/app/converter/uricomponentencoder.ts b/app/converter/uricomponentencoder.ts new file mode 100644 index 0000000..b4fb478 --- /dev/null +++ b/app/converter/uricomponentencoder.ts @@ -0,0 +1,17 @@ +import {Converter} from "./converter"; + +export class URIComponentEncoder implements Converter { + getDisplayname():string { + return "Encode URI component"; + } + + getId():string { + return "uricomponentencode"; + } + + convert(input:string):string { + return encodeURIComponent(input).replace(/[!'()*]/g, function (c) { + return '%' + c.charCodeAt(0).toString(16); + }); + } +} diff --git a/app/converter/uridecoder.ts b/app/converter/uridecoder.ts new file mode 100644 index 0000000..1949940 --- /dev/null +++ b/app/converter/uridecoder.ts @@ -0,0 +1,15 @@ +import {Converter} from "./converter"; + +export class URIDecoder implements Converter { + getDisplayname():string { + return "Decode URI"; + } + + getId():string { + return "uridecode"; + } + + convert(input:string):string { + return decodeURI(input); + } +} diff --git a/app/converter/uriencoder.ts b/app/converter/uriencoder.ts new file mode 100644 index 0000000..b56c747 --- /dev/null +++ b/app/converter/uriencoder.ts @@ -0,0 +1,15 @@ +import {Converter} from "./converter"; + +export class URIEncoder implements Converter { + getDisplayname():string { + return "Encode URI"; + } + + getId():string { + return "uriencode"; + } + + convert(input:string):string { + return encodeURI(input).replace(/%5B/g, '[').replace(/%5D/g, ']'); + } +} diff --git a/app/converterregistry.service.ts b/app/converterregistry.service.ts new file mode 100644 index 0000000..48817b7 --- /dev/null +++ b/app/converterregistry.service.ts @@ -0,0 +1,65 @@ +import {Injectable} from "@angular/core"; +import {Converter} from "./converter/converter"; +import {Base64Encoder} from "./converter/base64encoder"; +import {Base64Decoder} from "./converter/base64decoder"; +import {URIEncoder} from "./converter/uriencoder"; +import {URIDecoder} from "./converter/uridecoder"; +import {URIComponentEncoder} from "./converter/uricomponentencoder"; +import {URIComponentDecoder} from "./converter/uricomponentdecoder"; +import {HTMLEntitiesEncoder} from "./converter/htmlentitiesencoder"; +import {HTMLEntitiesDecoder} from "./converter/htmlentitiesdecoder"; +import {DecToHexConverter} from "./converter/dectohexconverter"; +import {HexToDecConverter} from "./converter/hextodecconverter"; +import {DecToBinConverter} from "./converter/dectobinconverter"; +import {BinToDecConverter} from "./converter/bintodecconverter"; +import {QuotedPrintableDecoder} from "./converter/quotedprintabledecoder"; +import {QuotedPrintableEncoder} from "./converter/quotedprintableencoder"; +import {NativeLibraryWrapperService} from "./nativelibrarywrapper.service"; + +@Injectable() +export class ConverterRegistryService { + private converters:Converter[] = []; + + constructor(private wrapper:NativeLibraryWrapperService) { + this.init(); + } + + public getAllConverters():Converter[] { + return this.converters; + } + + public getConverter(id:string):Converter { + for (let i = 0; i < this.converters.length; i++) { + if (this.converters[i].getId() == id) { + return this.converters[i]; + } + } + return undefined; + } + + private init():void { + this.registerConverter(new Base64Encoder()); + this.registerConverter(new Base64Decoder()); + this.registerConverter(new URIEncoder()); + this.registerConverter(new URIDecoder()); + this.registerConverter(new URIComponentEncoder()); + this.registerConverter(new URIComponentDecoder()); + this.registerConverter(new HTMLEntitiesEncoder()); + this.registerConverter(new HTMLEntitiesDecoder()); + this.registerConverter(new QuotedPrintableEncoder(this.wrapper)); + this.registerConverter(new QuotedPrintableDecoder(this.wrapper)); + this.registerConverter(new DecToHexConverter()); + this.registerConverter(new HexToDecConverter()); + this.registerConverter(new DecToBinConverter()); + this.registerConverter(new BinToDecConverter()); + } + + private registerConverter(converter:Converter):void { + this.converters.forEach((c:Converter) => { + if (c.getId() == converter.getId()) { + throw new Error("Converter-ID " + converter.getId() + " is already registered!"); + } + }); + this.converters.push(converter); + } +} diff --git a/app/inputarea.component.css b/app/inputarea.component.css new file mode 100644 index 0000000..e69de29 diff --git a/app/inputarea.component.html b/app/inputarea.component.html new file mode 100644 index 0000000..d8e65ee --- /dev/null +++ b/app/inputarea.component.html @@ -0,0 +1,15 @@ + + + + + + + + + + + diff --git a/app/inputarea.component.ts b/app/inputarea.component.ts new file mode 100644 index 0000000..d6164ad --- /dev/null +++ b/app/inputarea.component.ts @@ -0,0 +1,47 @@ +import {Component, OnInit} from "@angular/core"; +import {ConverterRegistryService} from "./converterregistry.service"; +import {Converter} from "./converter/converter"; +import {InputComponentManagerService} from "./inputcomponentmanager.service"; + + +@Component({ + moduleId: module.id, + selector: "den-inputarea", + templateUrl: "inputarea.component.html", + styleUrls: ["inputarea.component.css"] +}) +export class InputareaComponent extends OnInit { + public converters:Converter[] = []; + public content:string = ''; + private selectedConverter:Converter; + + constructor(private converterRegistryService:ConverterRegistryService, private inputComponentManagerService:InputComponentManagerService) { + super(); + } + + public convert(e):void { + this.selectedConverter = this.converterRegistryService.getConverter(e.target.selectedOptions[0].id); + this.update(); + } + + public update():void { + if (this.selectedConverter !== undefined) { + let result:string = this.selectedConverter.convert(this.content); + let nextComponent:InputareaComponent = this.inputComponentManagerService.getNext(this); + if (nextComponent !== undefined) { + nextComponent.setContent(result); + } + } + } + + public setContent(content:string):void { + this.content = content; + this.update(); + } + + ngOnInit():void { + this.converters = this.converterRegistryService.getAllConverters(); + this.selectedConverter = undefined; + this.inputComponentManagerService.register(this); + } +} diff --git a/app/inputcomponentmanager.service.ts b/app/inputcomponentmanager.service.ts new file mode 100644 index 0000000..a15b97c --- /dev/null +++ b/app/inputcomponentmanager.service.ts @@ -0,0 +1,42 @@ +import {Injectable} from "@angular/core"; + +@Injectable() +export class InputComponentManagerService { + private components:any[] = []; + + public constructor() { + } + + public register(component:any):void { + this.components.push(component); + } + + public getAllComponents():any[] { + return this.components; + } + + public getNext(component:any):any { + let index:number = component.index; + if (index == this.components.length - 1) { + this.addComponent(); + } + return this.components[index + 1]; + } + + public getFirst():any { + if (this.components.length == 0) { + this.addComponent(); + } + return this.components[0]; + } + + private addComponent():void { + this.register({ + content: "", + selectedConverter: undefined, + index: this.components.length, + error: false, + message: "" + }); + } +} \ No newline at end of file diff --git a/app/main.ts b/app/main.ts new file mode 100644 index 0000000..c31c26f --- /dev/null +++ b/app/main.ts @@ -0,0 +1,4 @@ +import {platformBrowserDynamic} from "@angular/platform-browser-dynamic"; +import {AppModule} from "./app.module"; + +platformBrowserDynamic().bootstrapModule(AppModule); diff --git a/app/nativelibrarywrapper.service.ts b/app/nativelibrarywrapper.service.ts new file mode 100644 index 0000000..6a7d840 --- /dev/null +++ b/app/nativelibrarywrapper.service.ts @@ -0,0 +1,15 @@ +import {Injectable} from "@angular/core"; + +declare var utf8:any; +declare var quotedPrintable:any; + +@Injectable() +export class NativeLibraryWrapperService { + public utf8:any; + public quotedPrintable:any; + + constructor() { + this.utf8 = utf8; + this.quotedPrintable = quotedPrintable; + } +} \ No newline at end of file diff --git a/app/option.component._t_s_ b/app/option.component._t_s_ new file mode 100644 index 0000000..1398f21 --- /dev/null +++ b/app/option.component._t_s_ @@ -0,0 +1,12 @@ +//import {Component} from "@angular/core"; +// +//@Component({ +// selector: "den-option", +// template: ` +// +// ` +//}) +//export class OptionComponent { +// public id:string; +// public displayName:string; +//} \ No newline at end of file diff --git a/app/selector.component._t_s_ b/app/selector.component._t_s_ new file mode 100644 index 0000000..0c17a7e --- /dev/null +++ b/app/selector.component._t_s_ @@ -0,0 +1,19 @@ +//import {Component} from "@angular/core"; +// +//import {OptionComponent} from "./option.component"; +// +//@Component({ +// selector: "den-selector", +// template: ` +// +// `, +// directives: [OptionComponent] +//}) +//export class SelectorComponent { +// private options:OptionComponent[]; +// +//} \ No newline at end of file diff --git a/dencode.css b/dencode.css deleted file mode 100644 index 8fadfda..0000000 --- a/dencode.css +++ /dev/null @@ -1,113 +0,0 @@ -@import url(//fonts.googleapis.com/css?family=Open+Sans:300,600&subset=latin,latin-ext); - -@media (max-width: 980px) { - body { - margin: 0; - padding: 0; - } - - h1 { - font-size: 120%; - margin: 0; - } - - div.wrapper { - border-radius: 0; - margin-left: 0; - margin-right: 0; - } - - textarea.input { - border-radius: 0; - } -} - -@media (min-width: 981px) { - div.wrapper { - border-radius: 0.5em; - margin-left: auto; - margin-right: auto; - width: 50%; - } - - textarea.input { - border-radius: 0.5em; - } -} -body { - font-family: 'Open Sans', sans-serif; - font-weight: 300; -} - -h1 { - text-align: center; - font-weight: 600; -} - -strong { - font-weight: 600; -} - -div.wrapper { - background-color: #fc0; - border-color: #da0; - border-style: solid; - border-width: 1px; - box-shadow: 0 0 1px 1px #ea0 inset; - color: #000; - margin-bottom: 0.5em; - padding: 0.5em; -} - -textarea.input { - border-style: solid; - border-width: 1px; - display: block; - font-family: 'Open Sans', sans-serif; - font-weight: 300; - font-size: 80%; - height: 150px; - padding: 0.1em 0.3em; - resize: vertical; - width: -moz-available; - width: -webkit-fill-available; -} - -textarea.input.error { - background-color: #f88; - border-color: #f00; - color: #000; -} - -textarea.input.error:focus, textarea.input.error:hover { - background-color: #faa; - border-color: #f00; - color: #000; -} - -select.conversion { - border-radius: 0.2em; - border-style: solid; - border-width: 1px; - font-family: 'Open Sans', sans-serif; - font-weight: 300; - margin-top: 0.5em; -} - -textarea.input, select.conversion { - background-color: #fdfbf0; - border-color: #fae8e7; - color: #000; -} - -textarea.input:focus, textarea.input:hover, -select.conversion:focus, select.conversion:hover { - background-color: #fff; - border-color: #fdfbf0; - color: #000; -} - -textarea.input:hover, -select.conversion:hover { - box-shadow: 0 0 6px 4px #c90; -} diff --git a/dencode.js b/dencode.js deleted file mode 100644 index a076423..0000000 --- a/dencode.js +++ /dev/null @@ -1,321 +0,0 @@ -(function($) { - var plugins = [ - { - "id": "CHOOSE", - "name": "Please choose your conversion ...", - "convert": function (input) { - return { - "status": "OK", - "content": "" - }; - } - }, - { - "id": "base64decode", - "name": "Decode Base64", - "convert": function (input) { - try { - return { - "status": "OK", - "content": atob(input) - }; - } catch (exception) { - return { - "status": "ERROR", - "content": "Invalid base64 input string." - }; - } - } - }, - { - "id": "decodeuri", - "name": "Decode URI", - "convert": function (input) { - try { - return { - "status": "OK", - "content": decodeURI(input) - }; - } catch (exception) { - return { - "status": "ERROR", - "content": "Invalid URI input string." - }; - } - } - }, - { - "id": "decodeuricomponent", - "name": "Decode URI component", - "convert": function (input) { - try { - return { - "status": "OK", - "content": decodeURIComponent(input) - }; - } catch (exception) { - return { - "status": "ERROR", - "content": "Invalid URI component input string." - }; - } - } - }, - { - "id": "decodehtmlentities", - "name": "Decode HTML entities", - "convert": function (input) { - try { - return { - "status": "OK", - "content": input - .replace(/\"\;/g, "\"") - .replace(/\>\;/g, ">") - .replace(/\<\;/g, "<") - .replace(/\&\;/g, "&") - }; - } catch (exception) { - return { - "status": "ERROR", - "content": "Invalid HTML entity string." - }; - } - } - }, - { - "id": "decodequotedprintable", - "name": "Decode quoted printable", - "convert": function (input) { - try { - return { - "status": "OK", - "content": utf8.decode(quotedPrintable.decode(input)) - }; - } catch (exception) { - return { - "status": "ERROR", - "content": "Invalid quoted printable string." - }; - } - } - }, - { - "id": "hextodec", - "name": "Decode hex as decimal", - "convert": function (input) { - try { - return { - "status": "OK", - "content": parseInt(input, 16).toString(10) - }; - } catch (exception) { - return { - "status": "ERROR", - "content": "Invalid number (integer) string." - }; - } - } - }, - { - "id": "bintodec", - "name": "Decode binary as decimal", - "convert": function (input) { - try { - return { - "status": "OK", - "content": parseInt(input, 2).toString(10) - }; - } catch (exception) { - return { - "status": "ERROR", - "content": "Invalid number (integer) string." - }; - } - } - }, - { - "id": "base64encode", - "name": "Encode Base64", - "convert": function (input) { - return { - "status": "OK", - "content": btoa(input) - }; - } - }, - { - "id": "encodeuri", - "name": "Encode URI", - "convert": function (input) { - return { - "status": "OK", - "content": encodeURI(input).replace(/%5B/g, '[').replace(/%5D/g, ']') - }; - } - }, - { - "id": "encodeuricomponent", - "name": "Encode URI component", - "convert": function (input) { - return { - "status": "OK", - "content": encodeURIComponent(input).replace(/[!'()*]/g, function(c) { - return '%' + c.charCodeAt(0).toString(16); - }) - }; - } - }, - { - "id": "encodehtmlentities", - "name": "Encode HTML entities", - "convert": function (input) { - return { - "status": "OK", - "content": input - .replace(/\&/g, "&") - .replace(/\/g, ">") - .replace(/\"/g, """) - }; - } - }, - { - "id": "encodequotedprintable", - "name": "Encode quoted printable", - "convert": function (input) { - return { - "status": "OK", - "content": quotedPrintable.encode(utf8.encode(input)) - }; - } - }, - { - "id": "dectohex", - "name": "Encode decimal as hex", - "convert": function (input) { - try { - return { - "status": "OK", - "content": parseInt(input).toString(16) - }; - } catch (exception) { - return { - "status": "ERROR", - "content": "Invalid number (integer) string." - }; - } - } - }, - { - "id": "dectobin", - "name": "Encode decimal as binary", - "convert": function (input) { - try { - return { - "status": "OK", - "content": parseInt(input).toString(2) - }; - } catch (exception) { - return { - "status": "ERROR", - "content": "Invalid number (integer) string." - }; - } - } - } - ]; - - var optiontemplate = ""; - var template = "
" - + "
"; - var options = ""; - var i, plugin, option; - for (i = 0; i < plugins.length; i++) { - plugin = plugins[i]; - option = optiontemplate.replace(/\{identifier\}/g, plugin.id).replace(/\{name\}/g, plugin.name); - if (plugin.disabled) { - option = $(option).attr("disabled", "disabled")[0].outerHTML; - } - options += option; - } - template = template.replace(/\{options\}/g, options); - - $(document).ready(function() { - var $new = $(template.replace(/\{index\}/g, "0").replace(/\{content\}/g, "")); - $("body").append($new); - }); - - function getPluginById(id) { - for (i = 0; i < plugins.length; i++) { - if (plugins[i].id === id) { - return plugins[i]; - } - } - return null; - } - - function convert(select) { - var $select = $(select); - var selectid = $select.attr("id"); - var inputIndex = +selectid.split("-")[1]; - var outputIndex = inputIndex + 1; - var $input = $("#input-" + inputIndex); - var $output = $("#input-" + outputIndex); - var appendNewOutput = false; - var input = $input.val(); - var conversion = $select.find(":selected").attr("name"); - var result; - var status; - var output; - var plugin; - if ($output.length == 0) { - appendNewOutput = true; - } - plugin = getPluginById(conversion); - if (plugin !== null) { - result = plugin.convert(input); - output = result.content; - status = result.status - } else { - output = "Internal error. Sorry."; - status = "ERROR"; - } - if (appendNewOutput) { - if (output !== "") { - $output = $(template.replace(/\{index\}/g, "" + outputIndex).replace(/\{content\}/g, output.replace(/\&/g, "&"))); - if (status === "ERROR") { - $output.find("textarea").addClass("error"); - } - $("body").append($output); - } - } else { - $output.val(output); - if (status === "ERROR") { - $output.addClass("error"); - } else { - $output.removeClass("error"); - } - update($output); - } - } - - function update(textarea) { - var $textarea = $(textarea); - var areaid = $textarea.attr("id"); - var inputindex = +areaid.split("-")[1]; - var $select = $("#type-" + inputindex); - var conversion = $select.find(":selected").attr("name"); - var plugin = getPluginById(conversion); - if (plugin !== null) { - convert($select); - } - } - - var den = {}; - den.convert = convert; - den.update = update; - window.den = window.den || den; - -})(jQuery); diff --git a/deploy.sh b/deploy.sh index ab6faf6..06374f3 100644 --- a/deploy.sh +++ b/deploy.sh @@ -1,5 +1,10 @@ #!/bin/sh +function die() { + echo $* + exit 1 +} + declare destination case "${TARGET}" in "${WWW_DEPLOY_ROOT_DEVELOP}") @@ -9,17 +14,45 @@ case "${TARGET}" in destination="${TARGET}" ;; *) - echo "Invalid TARGET specified. Aborting deployment." - exit 1 + die "Invalid TARGET specified. Aborting deployment." ;; esac if [[ ! -d "${destination}" ]] ; then - mkdir -p "${destination}" || echo "Failed to create target directory for deployment!" + mkdir -p "${destination}" || die "Failed to create target directory for deployment!" fi -rm -rf "${destination}/*" -rm -rf "${destination}/.??*" -cp -a dencode.css dencode.js index.html quoted-printable.js utf8.js "${destination}" +rm -rf "${destination}"/* || die "Failed to clean destination directory (step 1)" +rm -rf "${destination}"/.??* || die "Failed to clean destination directory (step 2)" + +cp -a index.html abeezee-regular.woff freemono.* package.json systemjs.config.js "${destination}" || die "Failed to copy resources to dest/" + +mkdir -p "${destination}/app/converter" || die "Failed to create dest/app/converter directory" +cp -a app/*.css app/*.html app/*.js app/*.js.map "${destination}/app" || die "Failed to copy resources to dest/app" +cp -a app/converter/*.js app/converter/*.js.map "${destination}/app/converter" || die "Failed to copy resources to dest/app/converter" + +mkdir -p "${destination}/node_modules/@angular" || die "Failed to create dest/node_modules/@angular" +cp -a node_modules/@angular/* "${destination}/node_modules/@angular/" || die "Failed to copy @angular" + +mkdir -p "${destination}/node_modules/core-js/client" || die "Failed to create dest/node_modules/core-js" +cp -a node_modules/core-js/client/shim.js "${destination}/node_modules/core-js/client/" || die "Failed to copy core-js" + +mkdir -p "${destination}/node_modules/zone.js/dist" || die "Failed to create dest/node_modules/zone.js" +cp -a node_modules/zone.js/dist/zone.js "${destination}/node_modules/zone.js/dist/" || die "Failed to copy zone.js" + +mkdir -p "${destination}/node_modules/reflect-metadata" || die "Failed to create dest/node_modules/reflect-metadata" +cp -a node_modules/reflect-metadata/Reflect.js "${destination}/node_modules/reflect-metadata/" || die "Failed to copy Reflect.js" + +mkdir -p "${destination}/node_modules/rxjs" || die "Failed to create dest/node_modules/rxjs" +cp -a node_modules/rxjs/* "${destination}/node_modules/rxjs/" || die "Failed to copy rxjs" + +mkdir -p "${destination}/node_modules/systemjs/dist" || die "Failed to create dest/node_modules/systemjs" +cp -a node_modules/systemjs/dist/system.src.js "${destination}/node_modules/systemjs/dist/" || die "Failed to copy system.src.js" + +mkdir -p "${destination}/node_modules/utf8" || die "Failed to create dest/node_modules/utf8" +cp -a node_modules/utf8/utf8.js "${destination}/node_modules/utf8/" || die "Failed to copy utf8.js" + +mkdir -p "${destination}/node_modules/quoted-printable" || die "Failed to create dest/node_modules/quoted-printable" +cp -a node_modules/quoted-printable/quoted-printable.js "${destination}/node_modules/quoted-printable/" || die "Failed to copy quoted-printable.js" echo "Deployment successful." diff --git a/freemono.eot b/freemono.eot new file mode 100644 index 0000000..2646fe5 Binary files /dev/null and b/freemono.eot differ diff --git a/freemono.svg b/freemono.svg new file mode 100644 index 0000000..68fb46a --- /dev/null +++ b/freemono.svg @@ -0,0 +1,635 @@ + + + + +Created by FontForge 20110222 at Fri Feb 17 12:20:04 2012 + By www-data +Copyleft 2002, 2003, 2005, 2008, 2009, 2010 Free Software Foundation. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/freemono.ttf b/freemono.ttf new file mode 100644 index 0000000..3a661a3 Binary files /dev/null and b/freemono.ttf differ diff --git a/freemono.woff b/freemono.woff new file mode 100644 index 0000000..97fe047 Binary files /dev/null and b/freemono.woff differ diff --git a/index.html b/index.html index dadf298..0481aa4 100644 --- a/index.html +++ b/index.html @@ -1,19 +1,54 @@ - - - Decode? Encode? DENcode! - - - - - + + + Decode? Encode? DENcode! + + + + + + + + + + -

Decode? Encode? DENcode!

- +

Decode? Encode? DENcode!

+ + +
Please hold on, we're starting the turbines ...
+
- \ No newline at end of file + diff --git a/package.json b/package.json new file mode 100644 index 0000000..56a1dde --- /dev/null +++ b/package.json @@ -0,0 +1,46 @@ +{ + "name": "dencode.org", + "version": "1.0.0-alpha.1", + "description": "Convert to and fro!", + "keywords": [ + "dencode", "conversion", "converter", "convert" + ], + "author": { + "name": "Manuel Friedli", + "email": "manuel@fritteli.ch" + }, + "license": "MIT", + "homepage": "https://test.friedli.info/~manuel/dencode", + "repository": "https://gittr.ch/manuel/dencode.org.git", + "dependencies": { + "@angular/common": "2.0.0", + "@angular/compiler": "2.0.0", + "@angular/core": "2.0.0", + "@angular/forms": "2.0.0", + "@angular/platform-browser": "2.0.0", + "@angular/platform-browser-dynamic": "2.0.0", + "@angular/upgrade": "2.0.0", + "bootstrap": "^3.3.6", + "core-js": "^2.4.0", + "reflect-metadata": "^0.1.3", + "rxjs": "5.0.0-beta.12", + "systemjs": "^0.19.27", + "zone.js": "^0.6.12", + "quoted-printable": "^1.0.0", + "utf8": "^2.1.1" + }, + "devDependencies": { + "concurrently": "^2.2.0", + "lite-server": "^2.2.0", + "typescript": "^2.0.2", + "typings": "^1.3.2" + }, + "scripts": { + "start": "tsc && concurrently \"npm run tsc:w\" \"npm run lite\"", + "lite": "lite-server", + "postinstall": "typings install", + "tsc": "tsc", + "tsc:w": "tsc -w", + "typings": "typings" + } +} diff --git a/quoted-printable.js b/quoted-printable.js deleted file mode 100644 index a10c4a2..0000000 --- a/quoted-printable.js +++ /dev/null @@ -1,153 +0,0 @@ -/*! https://mths.be/quoted-printable v1.0.0 by @mathias | MIT license */ -;(function(root) { - - // Detect free variables `exports`. - var freeExports = typeof exports == 'object' && exports; - - // Detect free variable `module`. - var freeModule = typeof module == 'object' && module && - module.exports == freeExports && module; - - // Detect free variable `global`, from Node.js or Browserified code, and use - // it as `root`. - var freeGlobal = typeof global == 'object' && global; - if (freeGlobal.global === freeGlobal || freeGlobal.window === freeGlobal) { - root = freeGlobal; - } - - /*--------------------------------------------------------------------------*/ - - var stringFromCharCode = String.fromCharCode; - var decode = function(input) { - return input - // https://tools.ietf.org/html/rfc2045#section-6.7, rule 3: - // “Therefore, when decoding a `Quoted-Printable` body, any trailing white - // space on a line must be deleted, as it will necessarily have been added - // by intermediate transport agents.” - .replace(/[\t\x20]$/gm, '') - // Remove hard line breaks preceded by `=`. Proper `Quoted-Printable`- - // encoded data only contains CRLF line endings, but for compatibility - // reasons we support separate CR and LF too. - .replace(/=(?:\r\n?|\n|$)/g, '') - // Decode escape sequences of the form `=XX` where `XX` is any - // combination of two hexidecimal digits. For optimal compatibility, - // lowercase hexadecimal digits are supported as well. See - // https://tools.ietf.org/html/rfc2045#section-6.7, note 1. - .replace(/=([a-fA-F0-9]{2})/g, function($0, $1) { - var codePoint = parseInt($1, 16); - return stringFromCharCode(codePoint); - }); - }; - - var handleTrailingCharacters = function(string) { - return string - .replace(/\x20$/, '=20') // Handle trailing space. - .replace(/\t$/, '=09') // Handle trailing tab. - }; - - var regexUnsafeSymbols = /[\0-\x08\n-\x1F=\x7F-\uFFFF]|[\uD800-\uDBFF][\uDC00-\uDFFF]/g; - var encode = function(string) { - - // Encode symbols that are definitely unsafe (i.e. unsafe in any context). - var encoded = string.replace(regexUnsafeSymbols, function(symbol) { - if (symbol > '\xFF') { - throw RangeError( - '`quotedPrintable.encode()` expects extended ASCII input only. ' + - 'Don\u2019t forget to encode the input first using a character ' + - 'encoding like UTF-8.' - ); - } - var codePoint = symbol.charCodeAt(0); - var hexadecimal = codePoint.toString(16).toUpperCase(); - return '=' + ('0' + hexadecimal).slice(-2); - }); - - // Limit lines to 76 characters (not counting the CRLF line endings). - var lines = encoded.split(/\r\n?|\n/g); - var lineIndex = -1; - var lineCount = lines.length; - var result = []; - while (++lineIndex < lineCount) { - var line = lines[lineIndex]; - // Leave room for the trailing `=` for soft line breaks. - var LINE_LENGTH = 75; - var index = 0; - var length = line.length; - while (index < length) { - var buffer = encoded.slice(index, index + LINE_LENGTH); - // If this line ends with `=`, optionally followed by a single uppercase - // hexadecimal digit, we broke an escape sequence in half. Fix it by - // moving these characters to the next line. - if (/=$/.test(buffer)) { - buffer = buffer.slice(0, LINE_LENGTH - 1); - index += LINE_LENGTH - 1; - } else if (/=[A-F0-9]$/.test(buffer)) { - buffer = buffer.slice(0, LINE_LENGTH - 2); - index += LINE_LENGTH - 2; - } else { - index += LINE_LENGTH; - } - result.push(buffer); - } - } - - // Encode space and tab characters at the end of encoded lines. Note that - // with the current implementation, this can only occur at the very end of - // the encoded string — every other line ends with `=` anyway. - var lastLineLength = buffer.length; - if (/[\t\x20]$/.test(buffer)) { - // There’s a space or a tab at the end of the last encoded line. Remove - // this line from the `result` array, as it needs to change. - result.pop(); - if (lastLineLength + 2 <= LINE_LENGTH + 1) { - // It’s possible to encode the character without exceeding the line - // length limit. - result.push( - handleTrailingCharacters(buffer) - ); - } else { - // It’s not possible to encode the character without exceeding the line - // length limit. Remvoe the character from the line, and insert a new - // line that contains only the encoded character. - result.push( - buffer.slice(0, lastLineLength - 1), - handleTrailingCharacters( - buffer.slice(lastLineLength - 1, lastLineLength) - ) - ); - } - } - - // `Quoted-Printable` uses CRLF. - return result.join('=\r\n'); - }; - - var quotedPrintable = { - 'encode': encode, - 'decode': decode, - 'version': '1.0.0' - }; - - // Some AMD build optimizers, like r.js, check for specific condition patterns - // like the following: - if ( - typeof define == 'function' && - typeof define.amd == 'object' && - define.amd - ) { - define(function() { - return quotedPrintable; - }); - } else if (freeExports && !freeExports.nodeType) { - if (freeModule) { // in Node.js, io.js, or RingoJS v0.8.0+ - freeModule.exports = quotedPrintable; - } else { // in Narwhal or RingoJS v0.7.0- - for (var key in quotedPrintable) { - quotedPrintable.hasOwnProperty(key) && (freeExports[key] = quotedPrintable[key]); - } - } - } else { // in Rhino or a web browser - root.quotedPrintable = quotedPrintable; - } - -}(this)); diff --git a/systemjs.config.js b/systemjs.config.js new file mode 100644 index 0000000..5ac6290 --- /dev/null +++ b/systemjs.config.js @@ -0,0 +1,43 @@ +/** + * System configuration for Angular 2 samples + * Adjust as necessary for your application needs. + */ +(function (global) { + System.config({ + paths: { + // paths serve as alias + 'npm:': 'node_modules/' + }, + // map tells the System loader where to look for things + map: { + // our app is within the app folder + app: 'app', + // angular bundles + '@angular/core': 'npm:@angular/core/bundles/core.umd.js', + '@angular/common': 'npm:@angular/common/bundles/common.umd.js', + '@angular/compiler': 'npm:@angular/compiler/bundles/compiler.umd.js', + '@angular/platform-browser': 'npm:@angular/platform-browser/bundles/platform-browser.umd.js', + '@angular/platform-browser-dynamic': 'npm:@angular/platform-browser-dynamic/bundles/platform-browser-dynamic.umd.js', +// '@angular/http': 'npm:@angular/http/bundles/http.umd.js', +// '@angular/router': 'npm:@angular/router/bundles/router.umd.js', + '@angular/forms': 'npm:@angular/forms/bundles/forms.umd.js', + // other libraries + 'rxjs': 'npm:rxjs'//, +// 'angular2-in-memory-web-api': 'npm:angular2-in-memory-web-api', + }, + // packages tells the System loader how to load when no filename and/or no extension + packages: { + app: { + main: './main.js', + defaultExtension: 'js' + }, + rxjs: { + defaultExtension: 'js' + }, + 'angular2-in-memory-web-api': { + main: './index.js', + defaultExtension: 'js' + } + } + }); +})(this); \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..e6a6eac --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,12 @@ +{ + "compilerOptions": { + "target": "es5", + "module": "commonjs", + "moduleResolution": "node", + "sourceMap": true, + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "removeComments": false, + "noImplicitAny": false + } +} diff --git a/typings.json b/typings.json new file mode 100644 index 0000000..c43d8b7 --- /dev/null +++ b/typings.json @@ -0,0 +1,9 @@ +{ + "name": "dencode.org", + "dependencies": {}, + "globalDependencies": { + "core-js": "registry:dt/core-js#0.0.0+20160914114559", + "jasmine": "registry:dt/jasmine#2.2.0+20160621224255", + "node": "registry:dt/node#6.0.0+20160915134512" + } +} diff --git a/utf8.js b/utf8.js deleted file mode 100644 index c138a38..0000000 --- a/utf8.js +++ /dev/null @@ -1,244 +0,0 @@ -/*! https://mths.be/utf8js v2.0.0 by @mathias */ -;(function(root) { - - // Detect free variables `exports` - var freeExports = typeof exports == 'object' && exports; - - // Detect free variable `module` - var freeModule = typeof module == 'object' && module && - module.exports == freeExports && module; - - // Detect free variable `global`, from Node.js or Browserified code, - // and use it as `root` - var freeGlobal = typeof global == 'object' && global; - if (freeGlobal.global === freeGlobal || freeGlobal.window === freeGlobal) { - root = freeGlobal; - } - - /*--------------------------------------------------------------------------*/ - - var stringFromCharCode = String.fromCharCode; - - // Taken from https://mths.be/punycode - function ucs2decode(string) { - var output = []; - var counter = 0; - var length = string.length; - var value; - var extra; - while (counter < length) { - value = string.charCodeAt(counter++); - if (value >= 0xD800 && value <= 0xDBFF && counter < length) { - // high surrogate, and there is a next character - extra = string.charCodeAt(counter++); - if ((extra & 0xFC00) == 0xDC00) { // low surrogate - output.push(((value & 0x3FF) << 10) + (extra & 0x3FF) + 0x10000); - } else { - // unmatched surrogate; only append this code unit, in case the next - // code unit is the high surrogate of a surrogate pair - output.push(value); - counter--; - } - } else { - output.push(value); - } - } - return output; - } - - // Taken from https://mths.be/punycode - function ucs2encode(array) { - var length = array.length; - var index = -1; - var value; - var output = ''; - while (++index < length) { - value = array[index]; - if (value > 0xFFFF) { - value -= 0x10000; - output += stringFromCharCode(value >>> 10 & 0x3FF | 0xD800); - value = 0xDC00 | value & 0x3FF; - } - output += stringFromCharCode(value); - } - return output; - } - - function checkScalarValue(codePoint) { - if (codePoint >= 0xD800 && codePoint <= 0xDFFF) { - throw Error( - 'Lone surrogate U+' + codePoint.toString(16).toUpperCase() + - ' is not a scalar value' - ); - } - } - /*--------------------------------------------------------------------------*/ - - function createByte(codePoint, shift) { - return stringFromCharCode(((codePoint >> shift) & 0x3F) | 0x80); - } - - function encodeCodePoint(codePoint) { - if ((codePoint & 0xFFFFFF80) == 0) { // 1-byte sequence - return stringFromCharCode(codePoint); - } - var symbol = ''; - if ((codePoint & 0xFFFFF800) == 0) { // 2-byte sequence - symbol = stringFromCharCode(((codePoint >> 6) & 0x1F) | 0xC0); - } - else if ((codePoint & 0xFFFF0000) == 0) { // 3-byte sequence - checkScalarValue(codePoint); - symbol = stringFromCharCode(((codePoint >> 12) & 0x0F) | 0xE0); - symbol += createByte(codePoint, 6); - } - else if ((codePoint & 0xFFE00000) == 0) { // 4-byte sequence - symbol = stringFromCharCode(((codePoint >> 18) & 0x07) | 0xF0); - symbol += createByte(codePoint, 12); - symbol += createByte(codePoint, 6); - } - symbol += stringFromCharCode((codePoint & 0x3F) | 0x80); - return symbol; - } - - function utf8encode(string) { - var codePoints = ucs2decode(string); - var length = codePoints.length; - var index = -1; - var codePoint; - var byteString = ''; - while (++index < length) { - codePoint = codePoints[index]; - byteString += encodeCodePoint(codePoint); - } - return byteString; - } - - /*--------------------------------------------------------------------------*/ - - function readContinuationByte() { - if (byteIndex >= byteCount) { - throw Error('Invalid byte index'); - } - - var continuationByte = byteArray[byteIndex] & 0xFF; - byteIndex++; - - if ((continuationByte & 0xC0) == 0x80) { - return continuationByte & 0x3F; - } - - // If we end up here, it’s not a continuation byte - throw Error('Invalid continuation byte'); - } - - function decodeSymbol() { - var byte1; - var byte2; - var byte3; - var byte4; - var codePoint; - - if (byteIndex > byteCount) { - throw Error('Invalid byte index'); - } - - if (byteIndex == byteCount) { - return false; - } - - // Read first byte - byte1 = byteArray[byteIndex] & 0xFF; - byteIndex++; - - // 1-byte sequence (no continuation bytes) - if ((byte1 & 0x80) == 0) { - return byte1; - } - - // 2-byte sequence - if ((byte1 & 0xE0) == 0xC0) { - var byte2 = readContinuationByte(); - codePoint = ((byte1 & 0x1F) << 6) | byte2; - if (codePoint >= 0x80) { - return codePoint; - } else { - throw Error('Invalid continuation byte'); - } - } - - // 3-byte sequence (may include unpaired surrogates) - if ((byte1 & 0xF0) == 0xE0) { - byte2 = readContinuationByte(); - byte3 = readContinuationByte(); - codePoint = ((byte1 & 0x0F) << 12) | (byte2 << 6) | byte3; - if (codePoint >= 0x0800) { - checkScalarValue(codePoint); - return codePoint; - } else { - throw Error('Invalid continuation byte'); - } - } - - // 4-byte sequence - if ((byte1 & 0xF8) == 0xF0) { - byte2 = readContinuationByte(); - byte3 = readContinuationByte(); - byte4 = readContinuationByte(); - codePoint = ((byte1 & 0x0F) << 0x12) | (byte2 << 0x0C) | - (byte3 << 0x06) | byte4; - if (codePoint >= 0x010000 && codePoint <= 0x10FFFF) { - return codePoint; - } - } - - throw Error('Invalid UTF-8 detected'); - } - - var byteArray; - var byteCount; - var byteIndex; - function utf8decode(byteString) { - byteArray = ucs2decode(byteString); - byteCount = byteArray.length; - byteIndex = 0; - var codePoints = []; - var tmp; - while ((tmp = decodeSymbol()) !== false) { - codePoints.push(tmp); - } - return ucs2encode(codePoints); - } - - /*--------------------------------------------------------------------------*/ - - var utf8 = { - 'version': '2.0.0', - 'encode': utf8encode, - 'decode': utf8decode - }; - - // Some AMD build optimizers, like r.js, check for specific condition patterns - // like the following: - if ( - typeof define == 'function' && - typeof define.amd == 'object' && - define.amd - ) { - define(function() { - return utf8; - }); - } else if (freeExports && !freeExports.nodeType) { - if (freeModule) { // in Node.js or RingoJS v0.8.0+ - freeModule.exports = utf8; - } else { // in Narwhal or RingoJS v0.7.0- - var object = {}; - var hasOwnProperty = object.hasOwnProperty; - for (var key in utf8) { - hasOwnProperty.call(utf8, key) && (freeExports[key] = utf8[key]); - } - } - } else { // in Rhino or a web browser - root.utf8 = utf8; - } - -}(this));