├── ASPTypeScriptSample ├── src │ ├── views │ │ ├── home │ │ │ └── index.html │ │ ├── shared │ │ │ ├── validation-error.html │ │ │ └── layout.html │ │ └── student │ │ │ ├── filter.html │ │ │ ├── details.html │ │ │ ├── index.html │ │ │ ├── create.html │ │ │ └── edit.html │ ├── helpers │ │ ├── helpers.d.ts │ │ ├── session.d.ts │ │ ├── handlebars-helpers.ts │ │ ├── vb-functions.asp │ │ ├── view.ts │ │ └── server-error.ts │ ├── db │ │ └── create.sql │ ├── domain │ │ ├── student.ts │ │ └── validator.ts │ ├── controllers │ │ ├── home-controller.ts │ │ ├── results.ts │ │ ├── base-controller.ts │ │ └── student-controller.ts │ ├── repositories │ │ ├── base-repository.ts │ │ └── student-repository.ts │ ├── errors │ │ └── http-error.ts │ ├── index.ts │ └── routers │ │ └── router.ts ├── assets │ ├── css │ │ └── site.css │ └── js │ │ └── student │ │ └── edit.js ├── Global.asa ├── 500.asp ├── tsconfig.json ├── packages.config ├── Web.config ├── Web.Debug.config ├── Web.Release.config ├── Default.asp ├── lib │ ├── polyfills.js │ └── json2.js ├── types │ ├── adodb │ │ ├── index.d.ts │ │ └── constants.d.ts │ └── asp │ │ └── index.d.ts └── ASPTypeScriptSample.csproj ├── ASPTypeScriptSample.sln ├── .gitattributes ├── .gitignore └── README.md /ASPTypeScriptSample/src/views/home/index.html: -------------------------------------------------------------------------------- 1 |

{{ message }}

-------------------------------------------------------------------------------- /ASPTypeScriptSample/src/helpers/helpers.d.ts: -------------------------------------------------------------------------------- 1 | declare function ToVBDate(jsDate: Date): any; -------------------------------------------------------------------------------- /ASPTypeScriptSample/src/helpers/session.d.ts: -------------------------------------------------------------------------------- 1 | declare function setSession(key: string, val: any): void; -------------------------------------------------------------------------------- /ASPTypeScriptSample/assets/css/site.css: -------------------------------------------------------------------------------- 1 | html { 2 | font-size: 14px; 3 | } 4 | 5 | .form-control { 6 | max-width: 280px; 7 | } -------------------------------------------------------------------------------- /ASPTypeScriptSample/src/db/create.sql: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bysanches/ASPTypeScriptSample/HEAD/ASPTypeScriptSample/src/db/create.sql -------------------------------------------------------------------------------- /ASPTypeScriptSample/src/domain/student.ts: -------------------------------------------------------------------------------- 1 | interface Student { 2 | id: string; 3 | name: string; 4 | document: string; 5 | birthdate: Date; 6 | } -------------------------------------------------------------------------------- /ASPTypeScriptSample/src/helpers/handlebars-helpers.ts: -------------------------------------------------------------------------------- 1 | Handlebars.registerHelper('formatDate', d => { 2 | if (d != null && moment(d).isValid()) { 3 | return moment(d).format('DD/MM/YYYY'); 4 | } 5 | return d; 6 | }); -------------------------------------------------------------------------------- /ASPTypeScriptSample/src/helpers/vb-functions.asp: -------------------------------------------------------------------------------- 1 | <% 2 | Function SetSession(ByVal key, ByVal val) 3 | Session(key) = val 4 | End Function 5 | 6 | Function ToVBDate(ByVal jsDate) 7 | ToVBDate = DateAdd("s", jsDate.getTime() / 1000, #1970-1-1#) 8 | End Function 9 | %> -------------------------------------------------------------------------------- /ASPTypeScriptSample/Global.asa: -------------------------------------------------------------------------------- 1 | 7 | 8 | -------------------------------------------------------------------------------- /ASPTypeScriptSample/src/views/shared/validation-error.html: -------------------------------------------------------------------------------- 1 |

Erro de validação

2 | 7 | 8 |

Por favor, volte e verifique os valores informados.

9 | 10 | Voltar -------------------------------------------------------------------------------- /ASPTypeScriptSample/src/views/student/filter.html: -------------------------------------------------------------------------------- 1 |
2 | 3 | 4 | 5 |
-------------------------------------------------------------------------------- /ASPTypeScriptSample/500.asp: -------------------------------------------------------------------------------- 1 | <%@ language="VBScript" codepage="65001" %> 2 | 3 | 4 | 5 | 6 | ERROR 7 | 8 | 9 | 10 |
<%= getErrorMessage() %>
11 | 12 | 13 | -------------------------------------------------------------------------------- /ASPTypeScriptSample/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "noImplicitAny": false, 4 | "noEmitOnError": true, 5 | "removeComments": true, 6 | "sourceMap": true, 7 | "target": "es3", 8 | "lib": [ "es5", "scripthost" ], 9 | "module": "none" 10 | }, 11 | "exclude": [ 12 | "node_modules", 13 | "wwwroot" 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /ASPTypeScriptSample/src/controllers/home-controller.ts: -------------------------------------------------------------------------------- 1 | namespace ASPTypeScriptSample.Controllers { 2 | export class HomeController extends BaseController { 3 | index() { 4 | let model = { message: 'Classic ASP + TypeScript Sample Web App' }; 5 | return this.view('/src/views/home/index.html', model); 6 | } 7 | 8 | about() { 9 | throw new Error('not implemented'); 10 | } 11 | } 12 | } -------------------------------------------------------------------------------- /ASPTypeScriptSample/src/controllers/results.ts: -------------------------------------------------------------------------------- 1 | namespace ASPTypeScriptSample.Controllers { 2 | export class HtmlResult { 3 | constructor(public content: string) { } 4 | 5 | toString() { 6 | return this.content; 7 | } 8 | } 9 | 10 | export class HttpErrorResult { 11 | constructor(public error: HttpError) { } 12 | 13 | toString() { 14 | return `${this.error.name}: ${this.error.message}`; 15 | } 16 | } 17 | } -------------------------------------------------------------------------------- /ASPTypeScriptSample/packages.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ASPTypeScriptSample/src/views/student/details.html: -------------------------------------------------------------------------------- 1 |

Student {{ name }}

2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 |
Name{{ name }}
Document{{ document }}
Birth Date{{ formatDate birthdate }}
19 | 20 |
21 | Back 22 | Edit 23 |
-------------------------------------------------------------------------------- /ASPTypeScriptSample/Web.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /ASPTypeScriptSample/assets/js/student/edit.js: -------------------------------------------------------------------------------- 1 | jQuery(function ($) { 2 | $('#studentForm').validate({ 3 | errorClass: 'has-danger', 4 | validClass: 'has-success', 5 | highlight: function (element, errorClass, validClass) { 6 | $(element).closest('.form-group').removeClass(validClass).addClass(errorClass); 7 | }, 8 | unhighlight: function (element, errorClass, validClass) { 9 | $(element).closest('.form-group').addClass(validClass).removeClass(errorClass); 10 | }, 11 | errorPlacement: function (error, element) { 12 | error.addClass('form-control-feedback'); 13 | element.closest('.form-group').append(error); 14 | } 15 | }); 16 | }); -------------------------------------------------------------------------------- /ASPTypeScriptSample/src/repositories/base-repository.ts: -------------------------------------------------------------------------------- 1 | namespace ASPTypeScriptSample.Repositories { 2 | const connectionString = Application('connectionString') as string; 3 | 4 | export interface Closable { 5 | Close(); 6 | State: number; 7 | } 8 | 9 | export function using(closable: T, expr: (closable: T) => any) { 10 | try { 11 | return expr.call(this, closable); 12 | } finally { 13 | if (closable.State === adStateOpen) closable.Close(); 14 | } 15 | } 16 | 17 | export class BaseRepository { 18 | protected openConnection(): ADODB.Connection { 19 | let conn = new ActiveXObject('ADODB.Connection') as ADODB.Connection; 20 | conn.Open(connectionString); 21 | return conn; 22 | } 23 | } 24 | } -------------------------------------------------------------------------------- /ASPTypeScriptSample/src/views/student/index.html: -------------------------------------------------------------------------------- 1 |

Students

2 | 3 | {{>filter term}} 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | {{#each items}} 16 | 17 | 20 | 21 | 22 | 23 | {{/each}} 24 | 25 |
NameDocumentBirth Date
18 | {{ name }} 19 | {{ document }}{{ formatDate birthdate }}
26 | 27 |
28 | Create 29 | reset | 30 | debug 31 |
-------------------------------------------------------------------------------- /ASPTypeScriptSample/src/errors/http-error.ts: -------------------------------------------------------------------------------- 1 | class HttpError implements Error { 2 | name: string; 3 | 4 | constructor(public code: number, public message: string) { 5 | this.name = 'HttpError'; 6 | this.message = this.code + ' ' + this.message; 7 | } 8 | 9 | toString() { 10 | return `${this.name}: ${this.message}`; 11 | } 12 | } 13 | 14 | class NotFoundError extends HttpError { 15 | constructor() { 16 | super(404, 'Not Found'); 17 | this.name = 'NotFoundError'; 18 | } 19 | } 20 | 21 | class MethodNotAllowedError extends HttpError { 22 | constructor() { 23 | super(405, 'Method Not Allowed'); 24 | this.name = 'MethodNotAllowedError'; 25 | } 26 | } 27 | 28 | class BadRequestError extends HttpError { 29 | constructor() { 30 | super(400, 'Bad Request'); 31 | this.name = 'BadRequestError'; 32 | } 33 | } -------------------------------------------------------------------------------- /ASPTypeScriptSample.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 14 4 | VisualStudioVersion = 14.0.25420.1 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ASPTypeScriptSample", "ASPTypeScriptSample\ASPTypeScriptSample.csproj", "{EEF92A02-1E4B-404F-AD47-A991A1AD171D}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {EEF92A02-1E4B-404F-AD47-A991A1AD171D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {EEF92A02-1E4B-404F-AD47-A991A1AD171D}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {EEF92A02-1E4B-404F-AD47-A991A1AD171D}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {EEF92A02-1E4B-404F-AD47-A991A1AD171D}.Release|Any CPU.Build.0 = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | EndGlobal 23 | -------------------------------------------------------------------------------- /ASPTypeScriptSample/src/views/shared/layout.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | {{ title }} 5 | 6 | 7 | 8 | 9 | 10 | 19 | 20 | 21 |
22 | {{{ body }}} 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 | {{{ scripts }}} 31 | 32 | -------------------------------------------------------------------------------- /ASPTypeScriptSample/src/views/student/create.html: -------------------------------------------------------------------------------- 1 |

New student

2 | 3 |
4 |
5 | 6 | 7 |
8 | 9 |
10 | 11 | 12 | Digits only. 13 |
14 | 15 |
16 | 17 | 18 | Format: dd/mm/yyyy 19 |
20 | 21 |
22 | 23 | Cancel 24 |
25 |
-------------------------------------------------------------------------------- /ASPTypeScriptSample/Web.Debug.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 17 | 18 | 29 | 30 | -------------------------------------------------------------------------------- /ASPTypeScriptSample/src/index.ts: -------------------------------------------------------------------------------- 1 | function executeHtmlResult(result: ASPTypeScriptSample.Controllers.HtmlResult): string { 2 | let view = ASPTypeScriptSample.View; 3 | 4 | Handlebars.registerHelper('active', controller => 5 | view.activeNavItem(controller)); 6 | 7 | Handlebars.registerHelper('navItem', (label: string, controller: string, action: string) => 8 | new Handlebars.SafeString(view.navItem(label, controller, action))); 9 | 10 | let template = view.getTemplate('/src/views/shared/layout.html'); 11 | 12 | return template({ 13 | title: view.getTitle(), 14 | body: result.content, 15 | scripts: view.renderScripts() 16 | }); 17 | } 18 | 19 | function main() { 20 | let router = new ASPTypeScriptSample.Routers.QueryStringRouter(); 21 | let actionDelegate = router.route(); 22 | let result = actionDelegate(); 23 | 24 | switch (result.constructor) { 25 | case ASPTypeScriptSample.Controllers.HtmlResult: 26 | Response.Write(executeHtmlResult(result)); 27 | break; 28 | case ASPTypeScriptSample.Controllers.HttpErrorResult: 29 | Response.Status = result.error.code; 30 | Response.Write(executeHtmlResult( 31 | new ASPTypeScriptSample.Controllers.HtmlResult(result.toString()))); 32 | break; 33 | default: 34 | Response.Write(result); 35 | } 36 | } -------------------------------------------------------------------------------- /ASPTypeScriptSample/Web.Release.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 17 | 18 | 19 | 30 | 31 | -------------------------------------------------------------------------------- /ASPTypeScriptSample/src/views/student/edit.html: -------------------------------------------------------------------------------- 1 |

Edit student {{ name }}

2 | 3 |
4 | 5 | 6 |
7 | 8 | 9 |
10 | 11 |
12 | 13 | 14 | Digits only. 15 |
16 | 17 |
18 | 19 | 20 | Format: dd/mm/yyyy 21 |
22 | 23 |
24 | 25 | Cancel 26 |
27 |
-------------------------------------------------------------------------------- /ASPTypeScriptSample/Default.asp: -------------------------------------------------------------------------------- 1 | <%@ language="VBScript" codepage="65001" %> 2 | <% Response.ContentType = "text/html; charset=utf-8" %> 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | <% main %> 25 | -------------------------------------------------------------------------------- /ASPTypeScriptSample/src/helpers/view.ts: -------------------------------------------------------------------------------- 1 | namespace ASPTypeScriptSample.View { 2 | var scripts = []; 3 | 4 | export function registerScript(src: string) { 5 | scripts.push(src); 6 | } 7 | 8 | export function renderScripts() { 9 | return scripts.map(src => ``).join(); 10 | } 11 | 12 | export function getTemplate(path: string) { 13 | var stream = new ActiveXObject('ADODB.Stream') as ADODB.Stream; 14 | stream.Type = adTypeText; 15 | stream.CharSet = 'utf-8'; 16 | stream.Open(); 17 | stream.LoadFromFile(Server.MapPath(path)); 18 | var result = stream.ReadText(); 19 | stream.Close(); 20 | 21 | return Handlebars.compile(result); 22 | } 23 | 24 | export function activeNavItem(controller: string, action: string = 'index') { 25 | let c = Request.QueryString('c')() || 'home'; 26 | let a = Request.QueryString('a')() || 'index'; 27 | 28 | if (controller === c && action === a) 29 | return 'active'; 30 | } 31 | 32 | export function navItem(label: string, controller: string = 'home', action: string = 'index') { 33 | let active = activeNavItem(controller, action); 34 | 35 | return ``; 38 | } 39 | 40 | let title: string; 41 | 42 | export function setTitle(t: string) { 43 | title = t; 44 | } 45 | 46 | export function getTitle() { 47 | return (title && title + ' - ' || '') + 'Classic ASP + TypeScript'; 48 | } 49 | } -------------------------------------------------------------------------------- /ASPTypeScriptSample/src/routers/router.ts: -------------------------------------------------------------------------------- 1 | namespace ASPTypeScriptSample.Routers { 2 | function isNullOrWhitespace(str: string) { 3 | return str == null || /^\s*$/.test(str); 4 | } 5 | 6 | function dashedToPascalCase(dashed: string): string { 7 | if (dashed != null) { 8 | return dashed.replace(/^([a-z])|-([a-z])/g, 9 | match => match.toUpperCase()).replace('-', ''); 10 | } 11 | } 12 | 13 | export interface Router { 14 | route(): () => any; 15 | } 16 | 17 | export class QueryStringRouter implements Router { 18 | private controllerName: string; 19 | private actionName: string; 20 | 21 | constructor(defaultCtrl?: string, defaultAction?: string) { 22 | this.controllerName = Request.QueryString('c')(); 23 | this.actionName = Request.QueryString('a')(); 24 | 25 | if (isNullOrWhitespace(this.controllerName)) this.controllerName = defaultCtrl || 'home'; 26 | if (isNullOrWhitespace(this.actionName)) this.actionName = defaultAction || 'index'; 27 | } 28 | 29 | private getControllerClassName(controller: string): string { 30 | return dashedToPascalCase(controller) + 'Controller'; 31 | } 32 | 33 | private invalidRoute() { 34 | throw new Error('Path not found:' + 35 | ` c = ${this.controllerName},` + 36 | ` a = ${this.actionName}`); 37 | } 38 | 39 | route() { 40 | let controllers = ASPTypeScriptSample.Controllers; 41 | let ctrlClassName = this.getControllerClassName(this.controllerName); 42 | 43 | let ctrlClass = controllers[ctrlClassName]; 44 | let actionMethod = ctrlClass && ctrlClass.prototype[this.actionName]; 45 | 46 | if (ctrlClass != null && actionMethod != null) { 47 | return () => actionMethod.call(new ctrlClass()); 48 | } else { 49 | this.invalidRoute(); 50 | } 51 | } 52 | } 53 | } -------------------------------------------------------------------------------- /ASPTypeScriptSample/src/helpers/server-error.ts: -------------------------------------------------------------------------------- 1 | function getErrorMessage() { 2 | let e = Server.GetLastError(); 3 | let result = `ERROR ${new Date().toString()}\n`; 4 | 5 | if (e.ASPCode()) 6 | result += `ASPCode: ${e.ASPCode()}\n`; 7 | 8 | if (e.ASPDescription()) 9 | result += `ASPDescription: ${e.ASPDescription()}\n`; 10 | 11 | if (e.Number()) 12 | result += `Number: ${e.Number().toString(16)}\n`; 13 | 14 | if (e.Source()) 15 | result += `Source: ${e.Source()}\n`; 16 | 17 | if (e.Category()) 18 | result += `Category: ${e.Category()}\n`; 19 | 20 | if (e.Description()) 21 | result += `Description: ${e.Description()}\n`; 22 | 23 | if (e.File()) 24 | result += `File: ${e.File()}\n`; 25 | 26 | if (e.Line()) 27 | result += `Line: ${e.Line()}\n`; 28 | 29 | if (e.Column()) 30 | result += `Column: ${e.Column()}\n`; 31 | 32 | result += '\nAPPLICATION\n' + getSummary(Application.Contents); 33 | result += '\nSESSION\n' + getSummary(Session.Contents); 34 | result += '\nQUERYSTRING\n' + getSummary(Request.QueryString); 35 | result += '\nFORM\n' + getSummary(Request.Form); 36 | result += '\nCOOKIES\n' + getSummary(Request.Cookies); 37 | result += '\nSERVER VARIABLES\n' + getServerVariablesSummary(); 38 | 39 | return result; 40 | } 41 | 42 | function getSummary(dic: ASP.IVariantDictionary | ASP.IRequestDictionary) { 43 | let result = ''; 44 | for (let i = 1; i <= dic.Count(); i++) { 45 | let key = dic.Key(i); 46 | let val = dic.Item(key); 47 | 48 | result += `${key}: ${val}\n`; 49 | } 50 | return result; 51 | } 52 | 53 | function getServerVariablesSummary() { 54 | let result = `URL: ${Request.ServerVariables('URL')()}\n`; 55 | 56 | let referer = Request.ServerVariables('HTTP_REFERER')(); 57 | if (referer) 58 | result += `HTTP_REFERER: ${referer}\n`; 59 | 60 | let userAgent = Request.ServerVariables('HTTP_USER_AGENT')(); 61 | if (userAgent) 62 | result += `HTTP_USER_AGENT: ${userAgent}`; 63 | 64 | return result; 65 | } -------------------------------------------------------------------------------- /ASPTypeScriptSample/src/controllers/base-controller.ts: -------------------------------------------------------------------------------- 1 | namespace ASPTypeScriptSample.Controllers { 2 | export class BaseController { 3 | /** 4 | * Validates the current request to accept POST method only. 5 | */ 6 | protected postOnly() { 7 | let method = Request.ServerVariables('REQUEST_METHOD')(); 8 | if (method !== 'POST') { 9 | return this.methodNotAllowed(); 10 | } 11 | } 12 | 13 | protected methodNotAllowed() { 14 | //Response.Clear(); 15 | //Response.Status = '405 Method Not Allowed'; 16 | //Response.End(); 17 | return new HttpErrorResult(new MethodNotAllowedError()); 18 | } 19 | 20 | protected badRequest() { 21 | //Response.Clear(); 22 | //Response.Status = '400 Bad Request'; 23 | //Response.End(); 24 | return new HttpErrorResult(new BadRequestError()); 25 | } 26 | 27 | protected notFound() { 28 | //Response.Clear(); 29 | //Response.Status = '404 Not Found'; 30 | //Response.End(); 31 | return new HttpErrorResult(new NotFoundError()); 32 | } 33 | 34 | protected redirectTo(ctrl: string, action: string = 'index', params?: object) { 35 | let url = `?c=${ctrl}&a=${action}`; 36 | let qs = ''; 37 | if (params != null) { 38 | for (let key in params) { 39 | if (params.hasOwnProperty(key)) { 40 | if (qs.length > 0) qs += '&'; 41 | qs += key + '=' + Server.URLEncode(params[key]); 42 | } 43 | } 44 | } 45 | url += qs.length > 0 ? '&' + qs : ''; 46 | Response.Redirect(url); 47 | } 48 | 49 | protected getTemplate(path: string) { 50 | return View.getTemplate(path); 51 | } 52 | 53 | protected view(path: string, data: any) { 54 | let template = this.getTemplate(path); 55 | return new HtmlResult(template(data)); 56 | } 57 | } 58 | } -------------------------------------------------------------------------------- /ASPTypeScriptSample/src/domain/validator.ts: -------------------------------------------------------------------------------- 1 | class Validator { 2 | private notifications; 3 | 4 | constructor() { 5 | this.notifications = []; 6 | } 7 | 8 | private addNotification(prop: string, message: string) { 9 | this.notifications.push([prop, message]); 10 | } 11 | 12 | valid() { 13 | return this.notifications.length === 0; 14 | } 15 | 16 | getNotifications() { 17 | return this.notifications.slice(0); 18 | } 19 | 20 | required(prop: string, val: string): Validator { 21 | if (!val || val == null) { 22 | this.addNotification(prop, 'valor requerido'); 23 | } 24 | return this; 25 | } 26 | 27 | number(prop: string, val: string): Validator { 28 | if (val && val != null) { 29 | if (!/^(?:-?\d+|-?\d{1,3}(?:,\d{3})+)?(?:\.\d+)?$/.test(val)) { 30 | this.addNotification(prop, 'valor inválido'); 31 | } 32 | } 33 | return this; 34 | } 35 | 36 | digits(prop: string, val: string): Validator { 37 | if (val && val != null) { 38 | if (/\D/.test(val)) { 39 | this.addNotification(prop, 'o campo deve conter apenas dígitos'); 40 | } 41 | } 42 | return this; 43 | } 44 | 45 | maxLength(prop: string, val: string, length: number): Validator { 46 | if (val && val != null) { 47 | if (val.length > length) { 48 | this.addNotification(prop, `o campo deve ter ${length} caracteres ou menos`); 49 | } 50 | } 51 | return this; 52 | } 53 | 54 | fixedLength(prop: string, val: string, length: number): Validator { 55 | if (val && val != null) { 56 | if (val.length !== length) { 57 | this.addNotification(prop, `o campo deve ter exatamente ${length} caracteres`); 58 | } 59 | } 60 | return this; 61 | } 62 | 63 | date(prop: string, val: string): Validator { 64 | if (val && val != null) { 65 | if (!moment.isDate(val) && !moment(val, 'DD/MM/YYYY').isValid()) { 66 | this.addNotification(prop, 'data inválida'); 67 | } 68 | } 69 | return this; 70 | } 71 | } -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /ASPTypeScriptSample/src/controllers/student-controller.ts: -------------------------------------------------------------------------------- 1 | namespace ASPTypeScriptSample.Controllers { 2 | const viewRoot = '/src/views/student/'; 3 | 4 | export class StudentController extends BaseController { 5 | index() { 6 | let term = Request.QueryString('term')(); 7 | let repo = Repositories.createStudentRepository(); 8 | let students = term ? repo.query(term) : repo.all(); 9 | 10 | this.registerFilterPartial(); 11 | View.setTitle('Students'); 12 | return this.view(viewRoot + 'index.html', { term, items: students }); 13 | } 14 | 15 | private registerFilterPartial() { 16 | Handlebars.registerPartial('filter', this.getTemplate(viewRoot + 'filter.html')) 17 | } 18 | 19 | details() { 20 | let id = Request.QueryString('id')(); 21 | if (!id || id.length !== 36) return this.badRequest(); 22 | 23 | let repo = Repositories.createStudentRepository(); 24 | let student = repo.getById(id); 25 | 26 | if (student == null) return this.notFound(); 27 | 28 | View.setTitle('Student Detail'); 29 | return this.view(viewRoot + 'details.html', student); 30 | } 31 | 32 | create() { 33 | View.registerScript('/assets/js/student/edit.js'); 34 | View.setTitle('New Student'); 35 | return this.view(viewRoot + 'create.html', {}); 36 | } 37 | 38 | edit() { 39 | let id = Request.QueryString('id')(); 40 | if (!id || id.length !== 36) return this.badRequest(); 41 | 42 | let repo = Repositories.createStudentRepository(); 43 | let student = repo.getById(id); 44 | 45 | if (student == null) return this.notFound(); 46 | 47 | View.registerScript('/assets/js/student/edit.js'); 48 | View.setTitle('Edit Student'); 49 | return this.view(viewRoot + 'edit.html', student); 50 | } 51 | 52 | save() { 53 | this.postOnly(); 54 | 55 | let v = this.validateSave(); 56 | 57 | if (!v.valid()) { 58 | return this.view('/src/views/shared/validation-error.html', v.getNotifications()); 59 | } 60 | 61 | let cmd = this.getSaveCommand(); 62 | 63 | let repo = Repositories.createStudentRepository(); 64 | let id: string; 65 | 66 | if (cmd.id) { 67 | repo.update(cmd.id, cmd.name, cmd.document, cmd.birthdate); 68 | id = cmd.id; 69 | } else { 70 | id = repo.create(cmd.name, cmd.document, cmd.birthdate); 71 | } 72 | 73 | this.redirectTo('student', 'details', { id }); 74 | } 75 | 76 | private validateSave() { 77 | let s = { 78 | id: Request.Form('id')(), 79 | name: Request.Form('name')(), 80 | document: Request.Form('document')(), 81 | birthdate: Request.Form('birthdate')(), 82 | }; 83 | 84 | let v = new Validator() 85 | .fixedLength('id', s.id, 36) 86 | .required('name', s.name) 87 | .maxLength('name', s.name, 50) 88 | .required('document', s.document) 89 | .fixedLength('document', s.document, 11) 90 | .required('birthdate', s.birthdate) 91 | .date('birthdate', s.birthdate); 92 | 93 | return v; 94 | } 95 | 96 | private getSaveCommand(): SaveCommand { 97 | return { 98 | id: Request.Form('id')(), 99 | name: Request.Form('name')(), 100 | document: Request.Form('document')(), 101 | birthdate: moment(Request.Form('birthdate')(), 'DD/MM/YYYY').toDate() 102 | }; 103 | } 104 | 105 | reset() { 106 | Session.Contents.Remove('students') 107 | this.redirectTo('student'); 108 | } 109 | 110 | debug() { 111 | let data = JSON.parse(Session('students')); 112 | return `
${JSON.stringify(data, null, 2)}
`; 113 | } 114 | } 115 | 116 | interface SaveCommand { 117 | id?: string; 118 | name: string; 119 | document: string; 120 | birthdate: Date; 121 | } 122 | } -------------------------------------------------------------------------------- /ASPTypeScriptSample/lib/polyfills.js: -------------------------------------------------------------------------------- 1 | if (!Array.prototype.filter) { 2 | Array.prototype.filter = function (fun/*, thisArg*/) { 3 | 'use strict'; 4 | 5 | if (this === void 0 || this === null) { 6 | throw new TypeError(); 7 | } 8 | 9 | var t = Object(this); 10 | var len = t.length >>> 0; 11 | if (typeof fun !== 'function') { 12 | throw new TypeError(); 13 | } 14 | 15 | var res = []; 16 | var thisArg = arguments.length >= 2 ? arguments[1] : void 0; 17 | for (var i = 0; i < len; i++) { 18 | if (i in t) { 19 | var val = t[i]; 20 | 21 | // NOTE: Technically this should Object.defineProperty at 22 | // the next index, as push can be affected by 23 | // properties on Object.prototype and Array.prototype. 24 | // But that method's new, and collisions should be 25 | // rare, so use the more-compatible alternative. 26 | if (fun.call(thisArg, val, i, t)) { 27 | res.push(val); 28 | } 29 | } 30 | } 31 | 32 | return res; 33 | }; 34 | } 35 | 36 | // Production steps of ECMA-262, Edition 5, 15.4.4.19 37 | // Reference: http://es5.github.io/#x15.4.4.19 38 | if (!Array.prototype.map) { 39 | 40 | Array.prototype.map = function (callback, thisArg) { 41 | 42 | var T, A, k; 43 | 44 | if (this == null) { 45 | throw new TypeError(' this is null or not defined'); 46 | } 47 | 48 | // 1. Let O be the result of calling ToObject passing the |this| 49 | // value as the argument. 50 | var O = Object(this); 51 | 52 | // 2. Let lenValue be the result of calling the Get internal 53 | // method of O with the argument "length". 54 | // 3. Let len be ToUint32(lenValue). 55 | var len = O.length >>> 0; 56 | 57 | // 4. If IsCallable(callback) is false, throw a TypeError exception. 58 | // See: http://es5.github.com/#x9.11 59 | if (typeof callback !== 'function') { 60 | throw new TypeError(callback + ' is not a function'); 61 | } 62 | 63 | // 5. If thisArg was supplied, let T be thisArg; else let T be undefined. 64 | if (arguments.length > 1) { 65 | T = thisArg; 66 | } 67 | 68 | // 6. Let A be a new array created as if by the expression new Array(len) 69 | // where Array is the standard built-in constructor with that name and 70 | // len is the value of len. 71 | A = new Array(len); 72 | 73 | // 7. Let k be 0 74 | k = 0; 75 | 76 | // 8. Repeat, while k < len 77 | while (k < len) { 78 | 79 | var kValue, mappedValue; 80 | 81 | // a. Let Pk be ToString(k). 82 | // This is implicit for LHS operands of the in operator 83 | // b. Let kPresent be the result of calling the HasProperty internal 84 | // method of O with argument Pk. 85 | // This step can be combined with c 86 | // c. If kPresent is true, then 87 | if (k in O) { 88 | 89 | // i. Let kValue be the result of calling the Get internal 90 | // method of O with argument Pk. 91 | kValue = O[k]; 92 | 93 | // ii. Let mappedValue be the result of calling the Call internal 94 | // method of callback with T as the this value and argument 95 | // list containing kValue, k, and O. 96 | mappedValue = callback.call(T, kValue, k, O); 97 | 98 | // iii. Call the DefineOwnProperty internal method of A with arguments 99 | // Pk, Property Descriptor 100 | // { Value: mappedValue, 101 | // Writable: true, 102 | // Enumerable: true, 103 | // Configurable: true }, 104 | // and false. 105 | 106 | // In browsers that support Object.defineProperty, use the following: 107 | // Object.defineProperty(A, k, { 108 | // value: mappedValue, 109 | // writable: true, 110 | // enumerable: true, 111 | // configurable: true 112 | // }); 113 | 114 | // For best browser support, use the following: 115 | A[k] = mappedValue; 116 | } 117 | // d. Increase k by 1. 118 | k++; 119 | } 120 | 121 | // 9. return A 122 | return A; 123 | }; 124 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.userosscache 8 | *.sln.docstates 9 | 10 | # User-specific files (MonoDevelop/Xamarin Studio) 11 | *.userprefs 12 | 13 | # Build results 14 | [Dd]ebug/ 15 | [Dd]ebugPublic/ 16 | [Rr]elease/ 17 | [Rr]eleases/ 18 | [Xx]64/ 19 | [Xx]86/ 20 | [Bb]uild/ 21 | bld/ 22 | [Bb]in/ 23 | [Oo]bj/ 24 | 25 | # Visual Studio 2015 cache/options directory 26 | .vs/ 27 | # Uncomment if you have tasks that create the project's static files in wwwroot 28 | #wwwroot/ 29 | 30 | # MSTest test Results 31 | [Tt]est[Rr]esult*/ 32 | [Bb]uild[Ll]og.* 33 | 34 | # NUNIT 35 | *.VisualState.xml 36 | TestResult.xml 37 | 38 | # Build Results of an ATL Project 39 | [Dd]ebugPS/ 40 | [Rr]eleasePS/ 41 | dlldata.c 42 | 43 | # DNX 44 | project.lock.json 45 | artifacts/ 46 | 47 | *_i.c 48 | *_p.c 49 | *_i.h 50 | *.ilk 51 | *.meta 52 | *.obj 53 | *.pch 54 | *.pdb 55 | *.pgc 56 | *.pgd 57 | *.rsp 58 | *.sbr 59 | *.tlb 60 | *.tli 61 | *.tlh 62 | *.tmp 63 | *.tmp_proj 64 | *.log 65 | *.vspscc 66 | *.vssscc 67 | .builds 68 | *.pidb 69 | *.svclog 70 | *.scc 71 | 72 | # Chutzpah Test files 73 | _Chutzpah* 74 | 75 | # Visual C++ cache files 76 | ipch/ 77 | *.aps 78 | *.ncb 79 | *.opendb 80 | *.opensdf 81 | *.sdf 82 | *.cachefile 83 | *.VC.db 84 | 85 | # Visual Studio profiler 86 | *.psess 87 | *.vsp 88 | *.vspx 89 | *.sap 90 | 91 | # TFS 2012 Local Workspace 92 | $tf/ 93 | 94 | # Guidance Automation Toolkit 95 | *.gpState 96 | 97 | # ReSharper is a .NET coding add-in 98 | _ReSharper*/ 99 | *.[Rr]e[Ss]harper 100 | *.DotSettings.user 101 | 102 | # JustCode is a .NET coding add-in 103 | .JustCode 104 | 105 | # TeamCity is a build add-in 106 | _TeamCity* 107 | 108 | # DotCover is a Code Coverage Tool 109 | *.dotCover 110 | 111 | # NCrunch 112 | _NCrunch_* 113 | .*crunch*.local.xml 114 | nCrunchTemp_* 115 | 116 | # MightyMoose 117 | *.mm.* 118 | AutoTest.Net/ 119 | 120 | # Web workbench (sass) 121 | .sass-cache/ 122 | 123 | # Installshield output folder 124 | [Ee]xpress/ 125 | 126 | # DocProject is a documentation generator add-in 127 | DocProject/buildhelp/ 128 | DocProject/Help/*.HxT 129 | DocProject/Help/*.HxC 130 | DocProject/Help/*.hhc 131 | DocProject/Help/*.hhk 132 | DocProject/Help/*.hhp 133 | DocProject/Help/Html2 134 | DocProject/Help/html 135 | 136 | # Click-Once directory 137 | publish/ 138 | 139 | # Publish Web Output 140 | *.[Pp]ublish.xml 141 | *.azurePubxml 142 | 143 | # TODO: Un-comment the next line if you do not want to checkin 144 | # your web deploy settings because they may include unencrypted 145 | # passwords 146 | #*.pubxml 147 | *.publishproj 148 | 149 | # NuGet Packages 150 | *.nupkg 151 | # The packages folder can be ignored because of Package Restore 152 | **/packages/* 153 | # except build/, which is used as an MSBuild target. 154 | !**/packages/build/ 155 | # Uncomment if necessary however generally it will be regenerated when needed 156 | #!**/packages/repositories.config 157 | # NuGet v3's project.json files produces more ignoreable files 158 | *.nuget.props 159 | *.nuget.targets 160 | 161 | # Microsoft Azure Build Output 162 | csx/ 163 | *.build.csdef 164 | 165 | # Microsoft Azure Emulator 166 | ecf/ 167 | rcf/ 168 | 169 | # Windows Store app package directory 170 | AppPackages/ 171 | BundleArtifacts/ 172 | 173 | # Visual Studio cache files 174 | # files ending in .cache can be ignored 175 | *.[Cc]ache 176 | # but keep track of directories ending in .cache 177 | !*.[Cc]ache/ 178 | 179 | # Others 180 | ClientBin/ 181 | [Ss]tyle[Cc]op.* 182 | ~$* 183 | *~ 184 | *.dbmdl 185 | *.dbproj.schemaview 186 | *.pfx 187 | *.publishsettings 188 | node_modules/ 189 | orleans.codegen.cs 190 | 191 | # RIA/Silverlight projects 192 | Generated_Code/ 193 | 194 | # Backup & report files from converting an old project file 195 | # to a newer Visual Studio version. Backup files are not needed, 196 | # because we have git ;-) 197 | _UpgradeReport_Files/ 198 | Backup*/ 199 | UpgradeLog*.XML 200 | UpgradeLog*.htm 201 | 202 | # SQL Server files 203 | *.mdf 204 | *.ldf 205 | 206 | # Business Intelligence projects 207 | *.rdl.data 208 | *.bim.layout 209 | *.bim_*.settings 210 | 211 | # Microsoft Fakes 212 | FakesAssemblies/ 213 | 214 | # GhostDoc plugin setting file 215 | *.GhostDoc.xml 216 | 217 | # Node.js Tools for Visual Studio 218 | .ntvs_analysis.dat 219 | 220 | # Visual Studio 6 build log 221 | *.plg 222 | 223 | # Visual Studio 6 workspace options file 224 | *.opt 225 | 226 | # Visual Studio LightSwitch build output 227 | **/*.HTMLClient/GeneratedArtifacts 228 | **/*.DesktopClient/GeneratedArtifacts 229 | **/*.DesktopClient/ModelManifest.xml 230 | **/*.Server/GeneratedArtifacts 231 | **/*.Server/ModelManifest.xml 232 | _Pvt_Extensions 233 | 234 | # LightSwitch generated files 235 | GeneratedArtifacts/ 236 | ModelManifest.xml 237 | 238 | # Paket dependency manager 239 | .paket/paket.exe 240 | 241 | # FAKE - F# Make 242 | .fake/ 243 | 244 | # NuGet packages 245 | Content 246 | Scripts 247 | fonts 248 | 249 | # TypeScript files 250 | ASPTypeScriptSample/src/**/*.js 251 | ASPTypeScriptSample/src/**/*.map -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Classic ASP + TypeScript sample application 2 | =========================================== 3 | 4 | Inspired by [this post]. 5 | 6 | This is a sample application developed with classic asp and typescript. 7 | 8 | But why 9 | ------- 10 | 11 | ![butwhy.gif](https://media.giphy.com/media/1M9fmo1WAFVK0/giphy.gif) 12 | 13 | Sometimes we're simply stuck with old applications running in classic asp. 14 | 15 | TypeScript adds usefull tools for development like IntelliSense, refactoring, a real class system, a type system, compile time errors, autocompletion, jsdocs, and more. 16 | 17 | It can be used in existing applications, sharing code and session state. 18 | 19 | Also, it was fun to do :) 20 | 21 | Run the project 22 | --------------- 23 | 24 | To fetch the js and css packages from nuget, run the command `Update-Package -Reinstall` from the package manager console. 25 | 26 | The package handlebars.TypeScript.DefinitelyTyped installs two .d.ts files, it is necessary to delete the one for version 1.0.0. 27 | 28 | It runs on IIS Express, it can be executed directly from visual studio (without debug). 29 | 30 | Script execution order 31 | ---------------------- 32 | 33 | Scripts run in classic asp in the following order: 34 | 35 | 1. any `