Skip to content

Instantly share code, notes, and snippets.

@sphw
Created August 24, 2015 06:09
Show Gist options
  • Save sphw/ac9417a4912adfc42dbc to your computer and use it in GitHub Desktop.
Save sphw/ac9417a4912adfc42dbc to your computer and use it in GitHub Desktop.
//#region "SystemJS Imports"
import {Component, View, bootstrap, NgFor, NgIf, FORM_DIRECTIVES} from 'angular2/angular2';
import {Ace} from '../vendor/ace/ace';
import $ from '../vendor/jquery';
import {Tab, Tabs} from './tabs';
import Utils from '../utils'
import {TestItem} from '../models/TestItem';
import {TestTemplate} from '../models/Template';
import {Project} from '../models/Project'
import {Settings} from '../models/Settings'
//#endregion
//#region "Node Imports"
var request = System._nodeRequire("request");
var progress = System._nodeRequire("request-progress");
var ipc = System._nodeRequire("ipc");
var remote = System._nodeRequire("remote");
var browserWindow = remote.require('browser-window');
var dialog = remote.require('dialog');
var Menu = remote.require('menu');
var fs = System._nodeRequire('fs');
var mime = System._nodeRequire('mime');
var inputEl;
//#endregion
var utils: Utils = new Utils();
function pad(number) {
if (number < 10) {
return '0' + number;
}
return number;
}
Date.prototype.toISOString = function() {
return this.getUTCFullYear() +
'-' + pad(this.getUTCMonth() + 1) +
'-' + pad(this.getUTCDate()) +
'T' + pad(this.getUTCHours()) +
':' + pad(this.getUTCMinutes()) +
':' + pad(this.getUTCSeconds()) +
'.' + (this.getUTCMilliseconds() / 1000).toFixed(3).slice(2, 5) +
'Z';
};
utils.handlebarsHelper();
var items = null;
var project = null;
@Component({
selector: 'rester',
})
@View({
directives: [NgFor, NgIf, Tab, Tabs, FORM_DIRECTIVES],
templateUrl: 'templates/app.html'
})
export class App {
items: Array<TestItem> = [];
project: Project;
selectedTest: TestItem;
rawTextAce;
selectedResponseTab: string = "plain";
templates: Array<TestTemplate> = [{ name: 'Default', id: 1, templateString: "{}" }];
tempEditor;
tempDataEditor;
rightHidden: Boolean = true;
leftHidden: Boolean = false;
settings: Settings;
constructor() {
utils.createSettings();
var self = this;
this.settings = JSON.parse(localStorage["settings"]);
var hidden = $('<span id="hidden" style="display:none;"></span>');
var adjustElemWidth = (elm) => {
hidden.text($(elm).val());
$(elm).width(hidden.width() * 1 + 30 + 'px');
}
$('body').append(hidden);
$(window).on('storage', (e) => {
if(e.originalEvent.key == "settings"){
self.settings = JSON.parse(e.originalEvent.newValue);
}
});
/*var trial = localStorage.getItem("trialA")
var oneDay = 24*60*60*1000;
var now = new Date();
if(trial){
var trialDT = new Date(trial);
console.log(trialDT);
console.log(Math.round(Math.abs(new Date().getTime() - trialDT.getTime())/(24*60*60*1000)))
if(Math.round(Math.abs(new Date().getTime() - trialDT.getTime())/(24*60*60*1000)) >= 7){
ipc.send("windowEvent", "trialQuit");
}
}else{
localStorage["trial"] = now.toString();
}*/
document.addEventListener('mousewheel', function(e) {
if (e.ctrlKey) {
e.preventDefault();
}
});
ipc.send("ready", "on");
this.newTest()
ipc.on('file', (arg) => {
console.log(arg);
if (arg != "new") {
this.items = arg.items;
this.selectedTest = this.items.filter((item: TestItem) => {
return item.selected;
})[0];
if (this.selectedTest == null) {
this.rightHidden = false;
this.selectedTest = this.items[0];
this.itemClick(this.items[0]);
} else {
this.spawnEditTextAce();
this.spawnRawTextAce();
this.itemClick(this.selectedTest);
}
$('span#hidden').text(this.selectedTest.request.type);
$('.combo select').first().width($('span#hidden').width() * 1 + 30 + 'px');
if (arg.project) {
this.project = arg.project;
} else {
this.project = {};
}
}
});
var tmpTestLocalStorage = localStorage.getItem('TestItemsA');
var tmpTemplateLocalStorage = localStorage.getItem('Templates')
if (tmpTemplateLocalStorage != null) {
this.templates = JSON.parse(tmpTemplateLocalStorage);
}
//#region Shortcuts
ipc.on('run', (arg) => {
this.runRequest();
});
ipc.on('delete', (arg) => {
this.deleteTest();
});
ipc.on('save', (arg) => {
this.saveChangesToFile();
});
ipc.on('saveAs', (arg) => {
this.saveAs();
});
//#endregion
//#region Window Events
ipc.on('blur', (arg) => {
$('body').addClass('blurred');
});
ipc.on('focus', (arg) => {
$('body').removeClass('blurred');
});
//#endregion
//#region Click Events
$('.handle').on("mousedown", function(e) {
var down = true;
var $drag = $(this).addClass('draggable');
$('.draggable').parent().addClass('draggingCont');
var z_idx = $drag.css('z-index'),
drg_h = $drag.outerHeight(),
drg_w = $drag.outerWidth(),
pos_y = $drag.offset().top + drg_h - e.pageY,
pos_x = $drag.offset().left + drg_w - e.pageX;
$drag.css('z-index', 1000).parents().on("mousemove", function(e) {
var parent = $('.draggable').parent()
if ($('.draggable').hasClass('hRight')) {
var i = document.body.clientWidth - e.clientX;
if (i + 200 + 361 >= document.body.clientWidth) {
i = document.body.clientWidth - (200 + 361);
}
if (i <= 220) {
i = 560;
$('.draggable').removeClass('draggable').css('z-index', z_idx);
self.toggleView('right', 0);
$('.draggable').parent().removeClass('draggingCont');
}
} else if ($('.draggable').length > 0) {
var i = e.clientX;
if (i <= 150) {
i = '25%';
$('.draggable').removeClass('draggable').css('z-index', z_idx);
self.toggleView('left', 0);
$('.draggable').parent().removeClass('draggingCont');
}
parent.children('.search').width(i - 12);
}
parent.css("flex-grow", "0")
parent.css("flex-shrink", "1")
parent.css('flex-basis', i);
self.rawTextAce.resize()
$(document).one("mouseup", function() {
down = false;
$('.draggable').removeClass('draggable').css('z-index', z_idx);
$('.draggable').parent().removeClass('draggingCont');
});
});
e.preventDefault(); // disable selection
}).on("mouseup", function() {
$(this).removeClass('draggable');
});
$('.list').on('mousedown', function(e) {
if (e.which == 3) {
Menu.buildFromTemplate([
{
label: 'New Item',
click: () => { self.newTest() }
}
]).popup(remote.getCurrentWindow())
e.preventDefault();
}
})
$('.list').on('mousedown', 'li', function(e) {
if (e.which == 3) {
Menu.buildFromTemplate([
{
label: 'Run',
click: () => { self.itemClick(self.items[$(this).attr('id')]); self.runRequest() }
},
{
type: 'separator'
},
{
label: 'Delete',
click: () => { self.deleteTest(self.items[$(this).attr('id')]) }
},
{
label: 'New Item',
click: () => { self.newTest() }
}
]).popup(remote.getCurrentWindow())
e.preventDefault();
e.stopPropagation();
}
});
//#endregion
//#region Change Detect
$('span[contenteditable]').keydown(function(e) {
if (e.keyCode === 13) {
this.saveChanges()
return false;
}
});
$('#tempSelect').change(() => {
this.selectTemplate();
});
$('#requestFormat, .bodyDropdown ').change(() => {
this.saveChanges();
});
$('.combo select').change(function() {
adjustElemWidth(this);
self.saveChanges();
});
//#endregion
remote.getCurrentWindow().show(); // Show Current Window*/
}
//#region "Misc Events"
titlebarAction(windowEvent) {
var obj = {};
obj.winID = browserWindow.getFocusedWindow().id;
obj.e = windowEvent;
ipc.send("windowEvent", obj);
}
responseTabClick(tab) {
this.selectedResponseTab = tab;
this.rawTextAce.resize()
this.rawTextAce.renderer.updateFull()
}
bodyDropdown() {
var elem = $('.bodyDropdown')
if (document.createEvent) {
var e = document.createEvent("MouseEvents");
e.initMouseEvent("mousedown", true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
elem[0].dispatchEvent(e);
} else if (elem.fireEvent) {
elem[0].fireEvent("onmousedown");
}
}
doneTyping($event) {
if ($event.which == 13) {
this.saveChanges();
$event.preventDefault()
return false;
} else {
$('#name').val($('#name').text());
}
}
//#endregion
//#region Deletion Events
deleteHeader(i) {
this.selectedTest.request.headers.splice(i, 1);
}
deleteTest(item?: TestItem) {
var select = false;
if (!item) {
item = this.selectedTest;
select = true;
} else {
select = (item == this.selectedTest);
}
var i = this.items.indexOf(item)
if (i > -1) {
this.items.splice(i, 1);
}
if (i > 0) {
if (select) {
this.itemClick(this.items[i - 1])
}
} else if (this.items.length > 0) {
if (select) {
this.selectedTest = this.items[0];
this.itemClick(this.items[0]);
}
} else {
this.newTest();
}
}
//#endregion
//#region Creation Events
newHeader(key, value, $event) {
if ($event && $event.which === 13) {
var i = this.items.indexOf(this.selectedTest);
this.selectedTest.request.headers.push({ key: key, value: value });
$('#keyInput').val("");
$('#valueInput').val("");
this.saveChangesToDisk(i);
} else if ($event == null) {
var i = this.items.indexOf(this.selectedTest);
this.selectedTest.request.headers.push({ key: key, value: value });
$('#keyInput').val("");
$('#valueInput').val("");
this.saveChangesToDisk(i);
}
}
newTest() {
var newTest: TestItem = {
name: 'Run Me!',
selected: true,
url: "http://example.org",
cachedJSON: "",
selectedTemplate: this.templates[0],
request: {
type: "GET",
body: "",
httpAuth: {
user: "",
pass: ""
},
headers: [],
format: 'Text',
gzip: false,
timeout: 3000,
followRedirect: 'get',
maxRedirects: 10
},
response: {
body: "",
headers: [],
format: "Auto",
final_url: ""
}
};
this.items.push(newTest);
this.itemClick(newTest);
}
newTemplate() {
var tempString = ` {
"name": "{{name}}",
"url": "{{url}}",
"requestType": "{{requestType}}",
"requestBody": "{{requestBody}}",
"httpAuth": {
"user": "{{httpAuthPass}}",
"pass": "{{httpAuthPass}}"
},
"requestHeaders": {{requestHeaders}},
"gzip": {{gzip}},
"requestFormat": "{{requestFormat}}",
"responseFormat": "{{responseFormat}}"
}`
var tempDataString = `{
"name": "foo",
"url": "http://foo.bar",
"requestType": "GET",
"requestBody": "FOO=BAR",
"httpAuth": {
"user": "user",
"pass": "pass"
},
"requestHeaders": {
"foo": "bar"
},
"gzip": false,
"requestFormat": "URLEncoded",
"responseFormat": "Text"
}`
var template = { templateString: tempString, id: Math.random() * 1000, name: "Lorem Ipsum", templateData: tempDataString }
this.templates.push(template);
}
//#endregion
//#region "Selection Events"
toggleView(section: String, time: Number = 400) {
this[section + 'Hidden'] = !this[section + 'Hidden'];
this.rawTextAce.resize()
this.rawTextAce.renderer.updateFull()
}
selectTemplate() {
var template: TestTemplate = this.templates.filter((template: TestTemplate) => {
return template.id == $('#tempSelect').val();
})[0];
$('#tempSelect').val();
this.selectedTest.selectedTemplate = template;
this.spawnTempTextAce()
this.tempEditor.setValue(this.selectedTest.selectedTemplate.templateString, -1);
this.tempDataEditor.setValue(this.selectedTest.selectedTemplate.templateData, -1);
$('#editTempButton').webuiPopover({ title: 'Title', content: 'Content', closeable: true });
}
itemClick(item: TestItem, httpuser?, httppass?, gzip?) {
if (item && item != {}) {
this.rightHidden = true;
this.items.forEach(function(i: TestItem) {
i.selected = false;
});
this.items.filter(function(i: TestItem) {
return i == item
})[0].selected = true;
this.selectedTest = item;
document.title = "RESTer: " + item.name;
if (this.selectedTest.response.body) {
this.rightHidden = false;
}
this.spawnEditTextAce();
this.spawnRawTextAce();
this.spawnTempTextAce()
$('.progress-bar').css('width', $('.combo').width() * (0.90) + 2);
window.editor.setValue(this.selectedTest.request.body, -1)
if (this.selectedTest.response.body) {
this.rawTextAce.setValue(this.selectedTest.response.body, -1);
}
if (this.selectedTest.request.format == "JSON" || this.selectedTest.request.format == "URLENCODED") {
window.editor.getSession().setMode("ace/mode/json");
this.rawTextAce.renderer.updateFull()
} else {
window.editor.getSession().setMode("ace/mode/text");
}
$('span#hidden').text(this.selectedTest.request.type);
console.log($('span#hidden').text())
console.log($('span#hidden').width())
$('.combo select').first().width($('span#hidden').width() * 1 + 30 + 'px');
if (this.selectedTest.response.body) {
try {
$('.rendered-view-iframe')[0].src = ""
console.log("JSON")
var json = JSON.parse(this.selectedTest.response.body);
if (this.selectedTest.cachedJSON == null) {
var loop = (object, appendElement) => {
var tmp = Handlebars.compile(`
<div class="item" id="{{index}}" data-hidden="false">
<span class="values">
<span class="text">
{{#if object}}
<i class="fa fa-caret-down"></i>
{{/if}}
{{key}}
</span>
<span class="text">{{value}}</span>
</span>
{{#if object}}
<div class="contents" id="{{index}}"></div>
{{/if}}
</div>
`);
var iterator = (o, i) => {
if (typeof object[o] == "object" || typeof object[o] == "array") {
$(appendElement).append(tmp({ index: i, key: o, value: typeof object[o], object: true }))
loop(object[o], $(appendElement).children('.item#' + i).first().children('.contents').first())
} else {
$(appendElement).append(tmp({ index: i, key: o, value: object[o], object: false }))
}
}
Object.keys(object).forEach(iterator);
}
$('.rendered-view').html(`
<div class="headers">
<span class="item">Key</span>
<span class="item">Value</span>
</div>
<div class="items"></div>
`)
$('.progress-bar').css('width', $('.combo').width() * (0.92) + 2);
loop(json, $('.rendered-view').children('.items')[0]);
$('.progress-bar').css('width', $('.combo').width() * (0.97) + 2);
this.selectedTest.cachedJSON = $('.rendered-view').html()
} else {
$('.rendered-view').html(this.selectedTest.cachedJSON)
}
$('.values, i').click(function() {
var hidden = $(this).parent().data('hidden');
$(this).siblings('.contents').first().toggle(hidden)
$(this).children('.text').children('i.fa').first().toggleClass('fa-caret-right', !hidden)
$(this).children('.text').children('i.fa').first().toggleClass('fa-caret-down', hidden)
$(this).parent().data('hidden', !hidden)
})
// $('.renderedViewDiv').JSONView(json);
} catch (e) {
console.log(e)
$('.rendered-view').html("");
var iframe = document.createElement("iframe");
iframe.srcdoc = this.selectedTest.response.body;
iframe.className = "rendered-view-iframe";
$(iframe).load(() => {
$(iframe).contents().find('head').append(`<base href="${this.selectedTest.url}"></base>`);
});
$('.rendered-view-iframe').replaceWith(iframe);
}
}
this.spawnEditTextAce();
this.spawnRawTextAce();
} else {
this.selectedTest = null;
}
$('.progress-bar').css('width', 0);
}
//#endregion
//#region Ace
spawnRawTextAce() {
try{
this.rawTextAce = ace.edit("raw-text");
this.rawTextAce.setTheme("ace/theme/xcode");
this.rawTextAce.setReadOnly(true);
this.rawTextAce.session.setUseWrapMode(true);
this.rawTextAce.session.setWrapLimitRange();
this.rawTextAce.getSession().setMode("ace/mode/" + this.selectedTest.response.format.toLowerCase());
if ($('.bodyDropdown').val().toLowerCase() == "auto") {
this.rawTextAce.getSession().setMode("ace/mode/" + this.selectedTest.response.type);
}
}
}
spawnEditTextAce() {
try{
window.editor = ace.edit("editor");
window.editor.setTheme("ace/theme/xcode");
window.editor.getSession().setMode("ace/mode/" + this.selectedTest.request.format.replace("URLEncoded", "json").toLowerCase());
console.log('spawning edit')
}
}
spawnTempTextAce() {
try{
this.tempDataEditor = ace.edit("tempDataEditor");
this.tempDataEditor.setTheme("ace/theme/xcode");
this.tempDataEditor.session.setUseWrapMode(true);
this.tempDataEditor.getSession().setMode("ace/mode/json");
this.tempEditor = ace.edit("tempEditor");
this.tempEditor.setTheme("ace/theme/xcode");
this.tempEditor.session.setUseWrapMode(true);
this.tempEditor.getSession().setMode("ace/mode/json");
}catch(e){}
}
//#endregion
saveChanges() {
var i: number = this.items.indexOf(this.selectedTest);
console.log(this.selectedTest.url);
this.selectedTest.name = $('#name').text();
this.selectedTest.request.body = window.editor.getValue().replace(/ /g, '');
this.selectedTest.request.timeout = parseInt($('#timeout').val());
this.selectedTest.request.maxRedirects = parseInt($("#maxredirects").val());
var self = this;
try {
$(".headerItem").each(function(i, header) {
console.log($(this).children('input'))
self.selectedTest.request.headers[i].key = $(this).children('input')[0].value
self.selectedTest.request.headers[i].value = $(this).children('input')[1].value
});
} catch (e) {
console.log(e);
}
window.editor.getSession().setMode("ace/mode/" + this.selectedTest.request.format.replace("URLEncoded", "json").toLowerCase());
this.rawTextAce.getSession().setMode("ace/mode/" + $('.bodyDropdown').val().toLowerCase());
this.selectedTest.response.format = $('.bodyDropdown').val();
if ($('.bodyDropdown').val().toLowerCase() == "auto") {
this.rawTextAce.getSession().setMode("ace/mode/" + this.selectedTest.response.type);
}
this.saveChangesToDisk(i);
}
saveTemplate(name, $event) {
if ($event) {
if ($event.which == 13) {
var i = this.templates.indexOf(this.selectedTest.selectedTemplate);
this.templates[i].name = name;
this.templates[i].templateString = this.selectedTest.selectedTemplate.templateString;
this.templates[i].templateData = this.selectedTest.selectedTemplate.templateData;
localStorage["Templates"] = JSON.stringify(this.templates);
}
} else {
var i = this.templates.indexOf(this.selectedTest.selectedTemplate);
this.templates[i].name = name;
this.templates[i].templateString = this.selectedTest.selectedTemplate.templateString;
this.templates[i].templateData = this.selectedTest.selectedTemplate.templateData;
localStorage["Templates"] = JSON.stringify(this.templates);
}
}
saveChangesToDisk(i: number) {
this.items[i] = this.selectedTest;
}
saveChangesToFile() {
var self = this;
var utils = new Utils();
if (this.project.path) {
fs.writeFile(this.project.path, JSON.stringify({ project: self.project, items: self.items }));
utils.addProjectToRecent(self.project);
} else {
self.saveAs();
}
}
saveAs() {
var self = this;
dialog.showSaveDialog(remote.getCurrentWindow(), {
title: "Save Project",
defaultPath: process.env.HOME + '/Documents',
filters: [{ name: 'Project', extensions: ['restproject'] }]
}, function(f) {
self.project.path = f;
utils.addProjectToRecent(self.project);
fs.writeFile(f, JSON.stringify({ project: self.project, items: self.items }));
});
}
//#region Run Events
applyTemplate() {
var i = this.templates.indexOf(this.selectedTest.selectedTemplate);
this.selectedTest.selectedTemplate.templateString = this.tempEditor.getValue();
this.selectedTest.selectedTemplate.templateData = JSON.parse(this.tempDataEditor.getValue());
this.selectedTest.selectedTemplate.template = Handlebars.compile(this.selectedTest.selectedTemplate.templateString);
var temp = this.selectedTest.selectedTemplate.template(this.selectedTest.selectedTemplate.templateData)
console.log(temp);
var testData = JSON.parse(temp);
Object.keys(testData).forEach((o) => {
console.log(o);
if (this.selectedTest[o]) {
this.selectedTest[o] = testData[o];
}
});
}
runRequest() {
var i: number = this.items.indexOf(this.selectedTest);
this.saveChanges();
this.selectedTest.cachedJSON = null;
var options = {
url: this.selectedTest.url,
method: this.selectedTest.request.type,
gzip: this.selectedTest.request.gzip,
timeout: this.selectedTest.request.timeout,
maxRedirects: this.selectedTest.request.maxRedirects,
headers: {}
}
if (this.selectedTest.request.followRedirect == "all") {
options["followAllRedirects"] = true
} else if (this.selectedTest.request.followRedirect == "none") {
options["followRedirect"] = false;
}
if (this.selectedTest.request.body != "" && this.selectedTest.request.format != 'URLEncoded') {
options["body"] = this.selectedTest.request.body;
} else if (this.selectedTest.request.format == "URLEncoded") {
options["form"] = JSON.parse(this.selectedTest.request.body)
}
options["json"] = (this.selectedTest.request.format == 'JSON')
this.selectedTest.request.headers.forEach((o) => {
console.log(o)
options.headers[o.key] = o.value
});
console.log(options);
if (this.selectedTest.request.body != "", this.selectedTest.request.type == "HEAD") {
this.selectedTest.status = false;
this.selectedTest.httpStatus = "BAD FORMAT";
this.selectedTest.response.body = "ERORR: Can't include body with HEAD request"
}
var start = process.hrtime();
progress(request(options, (error, response, body) => {
this.selectedTest.response.time = process.hrtime(start)[1] / 1000000000;
if (error) {
console.log(error);
this.selectedTest.status = false;
this.selectedTest.response.body = error.toString();
this.selectedTest.httpStatus = error.code;
new Notification(`${this.selectedTest.name}`, {
body: `${this.selectedTest.url}
Error: ${error.code}`
})
} else {
this.selectedTest.status = true;
console.log(body);
if (response.statusCode >= 400) {
this.selectedTest.status = false;
new Notification(`${this.selectedTest.name}`, {
body: `${this.selectedTest.url}
Error: ${error.code}`
})
} else {
new Notification(`${this.selectedTest.name}`, {
body: `${this.selectedTest.url}
Staus: ${response.statusCode}`
})
}
this.selectedTest.httpStatus = response.statusCode;
if (this.selectedTest.request.type == "HEAD") {
this.selectedTest.response.body = " "
}
$('.progress-bar').css('width', $('.combo').width() * (0.80) + 2);
if (typeof body == "object") {
this.selectedTest.response.body = JSON.stringify(body);
} else {
this.selectedTest.response.body = body;
}
$('.progress-bar').css('width', $('.combo').width() * (0.82) + 2);
this.selectedTest.response.final_url = response.request.uri.href;
this.selectedTest.response.headers = [];
Object.keys(response.headers).forEach((o) => {
this.selectedTest.response.headers.push({ key: o, value: response.headers[o] });
});
this.selectedTest.response.type = mime.extension(response.headers["content-type"]);
}
this.selectedTest.response.date = new Date().toISOString();
$('.progress-bar').css('width', $('.combo').width() * (0.85) + 2);
this.saveChangesToDisk(i);
$('.progress-bar').css('width', $('.combo').width() * (0.87) + 2);
this.itemClick(this.selectedTest);
}), { throttle: 0, delay: 0 }).on('progress', (state) => {
$('.progress-bar').css('width', $('.combo').width() * (state.percent / 100 - 0.25) + 2);
this.selectedTest.response.size = state.total;
});
}
//#endregion
};
bootstrap(App);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment