Skip to content

Commit

Permalink
fix #27
Browse files Browse the repository at this point in the history
  • Loading branch information
mirkoperillo committed Oct 1, 2018
1 parent cd6357c commit ab7a2b6
Show file tree
Hide file tree
Showing 5 changed files with 197 additions and 26 deletions.
47 changes: 45 additions & 2 deletions src/css/resting.css
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,17 @@ body {
z-index: 100;
}

.context-dialog {
position: absolute;
top: 100px;
width: 700px;
z-index: 100;
}

.bookmark {
display: block;
padding: 10px 15px;
cursor: pointer;
cursor: pointer;
}

.folder {
Expand All @@ -54,7 +61,7 @@ a.bookmark, a.folder {
}

a.folder:hover, a.bookmark:hover, .folder .panel-heading:hover {
background-color: #337ab7;
background-color: #337ab7;
color: #fff;
}

Expand Down Expand Up @@ -82,3 +89,39 @@ label.disabled {
color: gray;
}

.dropdown-submenu{ position: relative; }

.dropdown-submenu>.dropdown-menu{
top:0;
left:100%;
margin-top:-6px;
margin-left:-1px;
-webkit-border-radius:0 6px 6px 6px;
-moz-border-radius:0 6px 6px 6px;
border-radius:0 6px 6px 6px;
}

.dropdown-submenu>a:after{
display:block;
content:" ";
float:right;
width:0;
height:0;
border-color:transparent;
border-style:solid;
border-width:5px 0 5px 5px;
border-left-color:#cccccc;
margin-top:5px;margin-right:-10px;
}
.dropdown-submenu:hover>a:after{
border-left-color:#555;
}
.dropdown-submenu.pull-left{ float: none; }
.dropdown-submenu.pull-left>.dropdown-menu{
left: -100%;
margin-left: 10px;
-webkit-border-radius: 6px 0 6px 6px;
-moz-border-radius: 6px 0 6px 6px;
border-radius: 6px 0 6px 6px;
}

33 changes: 32 additions & 1 deletion src/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,15 @@
</div>
<div class="collapse navbar-collapse">
<ul class="nav navbar-nav">
<li class="dropdown"><a href="#" class="dropdown-toggle" data-toggle="dropdown"><h4>Settings <b class="caret"></b></h4></a>
<ul class="dropdown-menu">
<li class="dropdown dropdown-submenu"><a href="#" class="dropdown-toggle" data-toggle="dropdown">Contexts</a>
<ul class="dropdown-menu">
<li><a href="#" data-bind="click: contextDialog">default</a></li>
</ul>
</li>
</ul>
</li>
<li><a href="#" data-bind="click: aboutDialog"><h4>About</h4></a></li>
<li><a href="#" data-bind="click: creditsDialog"><h4>Credits</h4></a></li>
</ul>
Expand Down Expand Up @@ -198,7 +207,7 @@ <h4 class="panel-title"><a href="#" data-bind="click: responseHeadersPanel">Head
About Resting<span style="cursor: pointer;" class="glyphicon glyphicon-remove pull-right" data-bind="click: dismissAboutDialog"></span>
</div>
<div class="panel-body">
<h4>Resting v0.7.3</h4>
<h4>Resting v0.8.0</h4>
<a target="_blank" href="https://github.com/mirkoperillo/resting">Project Website</a> --
<a target="_blank" href="https://github.com/mirkoperillo/resting/issues">Issue tracker</a>
</div>
Expand All @@ -213,6 +222,28 @@ <h4>Resting v0.7.3</h4>
</div>
</div>

<div id="context-dialog" class="panel panel-primary context-dialog" data-bind="visible: showContextDialog">
<div class="panel-heading">
Context <span data-bind="text: contexts.name"></span><span style="cursor: pointer;" class="glyphicon glyphicon-remove pull-right" data-bind="click: dismissContextDialog"></span>
</div>
<div class="panel-body">
<p>
Use variables as <strong>{var_name}</strong> in
<ul>
<li>the request URL</li>
<li>value of header</li>
<li>part of the body</li>
<li>value of querystring</li>
<li>as username and password in BASIC authentication</li>
</ul>
</p>
<entry-list params="entryList : contexts.variables"></entry-list>
</div>
<div class="panel-footer">
<button class="btn btn-default" data-bind="click: saveContext">Save</button><button class="btn btn-default" data-bind="click: dismissContextDialog">Cancel</button>
</div>
</div>

<script data-main="js/app" src="js/require.js"></script>

</div>
Expand Down
111 changes: 95 additions & 16 deletions src/js/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,13 @@ requirejs.config({

requirejs(['jquery','app/storage','knockout','knockout-secure-binding','hjls','app/request','app/bookmark','bootstrap'], function($,storage,ko,ksb,hjls,request,makeBookmarkProvider, bootstrap) {

function ContextVm(createDefault) {
const self = this;
this.name = ko.observable(createDefault ? 'default' : '');
this.variables = ko.observableArray();
this.isDefault = createDefault;
};

function RequestVm(request = {}) {
const self = this;
this.method = ko.observable('');
Expand Down Expand Up @@ -49,6 +56,8 @@ requirejs(['jquery','app/storage','knockout','knockout-secure-binding','hjls','a

function AppViewModel() {
const Resting = {
contexts : new ContextVm(true),

bookmarkSelected : new BookmarkSelectedVm(),
requestSelected : new RequestVm(),
responseContent : {},
Expand Down Expand Up @@ -92,13 +101,14 @@ requirejs(['jquery','app/storage','knockout','knockout-secure-binding','hjls','a
showBookmarkDeleteDialog: ko.observable(false),
showAboutDialog: ko.observable(false),
showCreditsDialog: ko.observable(false),
showContextDialog: ko.observable(false),
};

const bookmarkProvider = makeBookmarkProvider(storage);

const convertToFormData = (data = []) =>
const convertToFormData = (data = [], context = {}) =>
data.filter(param => param.enabled()).reduce((acc, record) => {
acc[record.name()] = record.value();
acc[record.name()] = _applyContext(record.value(),context);
return acc;
}, {});

Expand All @@ -114,6 +124,10 @@ requirejs(['jquery','app/storage','knockout','knockout-secure-binding','hjls','a
Resting.showCreditsDialog(true);
};

const contextDialog = () => {
Resting.showContextDialog(true);
};

const dismissCreditsDialog = () => {
Resting.showCreditsDialog(false);
};
Expand All @@ -122,8 +136,12 @@ requirejs(['jquery','app/storage','knockout','knockout-secure-binding','hjls','a
Resting.showAboutDialog(false);
};

const convertToUrlEncoded = (data = []) =>
data.filter(param => param.enabled()).map( param => `${param.name()}=${param.value()}`).join('&');
const dismissContextDialog = () => {
Resting.showContextDialog(false);
};

const convertToUrlEncoded = (data = [], context) =>
data.filter(param => param.enabled()).map( param => `${param.name()}=${_applyContext(param.value(),context)}`).join('&');

const updateBody = (bodyType, body) => {
clearRequestBody();
Expand Down Expand Up @@ -197,17 +215,20 @@ requirejs(['jquery','app/storage','knockout','knockout-secure-binding','hjls','a
}
};

const dataToSend = () => {
const dataToSend = (context) => {
if (Resting.bodyType() === 'form-data') {
return convertToFormData(Resting.formDataParams());
return convertToFormData(Resting.formDataParams(),context);
} else if (Resting.bodyType() === 'x-www-form-urlencoded') {
return convertToUrlEncoded(Resting.formEncodedParams());
return convertToUrlEncoded(Resting.formEncodedParams(), context);
} else if (Resting.bodyType() === 'raw') {
return Resting.rawBody().trim();
return _applyContext(Resting.rawBody().trim(),context);
}
};

const _authentication = () => ({type: Resting.authenticationType(), username: Resting.username(), password: Resting.password()});
const _applyContextToArray = (a = [], context = {}) => {
return
};
const _authentication = (context = {}) => ({type: Resting.authenticationType(), username: _applyContext(Resting.username(),context), password: _applyContext(Resting.password(),context)});

const body = (bodyType) => {
if (bodyType === 'form-data') {
Expand Down Expand Up @@ -346,9 +367,9 @@ requirejs(['jquery','app/storage','knockout','knockout-secure-binding','hjls','a
}
};

const convertToHeaderObj = headersList =>
const convertToHeaderObj = (headersList = [], context = {}) =>
headersList.filter(header => header.enabled()).reduce((acc, header) => {
acc[header.name()] = header.value();
acc[header.name()] = _applyContext(header.value(),context);
return acc;
}, {});

Expand All @@ -367,16 +388,44 @@ requirejs(['jquery','app/storage','knockout','knockout-secure-binding','hjls','a
}
};

const _convertToQueryString = (params = []) => {
return params.filter(param => param.enabled()).map( param => ({name: param.name(), value: param.value()}));
const _convertToQueryString = (params = [], context = {}) => {
return params.filter(param => param.enabled()).map( param => ({name: param.name(), value: _applyContext(param.value(), context)}));
};

const send = () => {
const mapping = _mapContext();
if(Resting.requestSelected.url() && Resting.requestSelected.url().trim().length > 0) {
clearResponse();
request.execute(Resting.requestSelected.method(),Resting.requestSelected.url(),convertToHeaderObj(Resting.requestHeaders()), _convertToQueryString(Resting.querystring()), Resting.bodyType(),Resting.dataToSend(),
_authentication(),displayResponse);
const url = _applyContext(Resting.requestSelected.url(),mapping);
request.execute(Resting.requestSelected.method(),url,convertToHeaderObj(Resting.requestHeaders(), mapping), _convertToQueryString(Resting.querystring(), mapping), Resting.bodyType(),Resting.dataToSend(mapping),
_authentication(mapping),displayResponse);
}
};

const _mapContext = () => {
const mapping = {};
Resting.contexts.variables().filter(v => v.enabled()).forEach( v => mapping[v.name()] = v.value());
return mapping;
};

const _applyContext = (value = '',context = {}) => {
const tokens = _tokenize(value);
let computed = value.slice(0);
if(tokens) {
tokens.forEach(t => {
const contextVar = t.substring(1,t.length-1);
if(context[contextVar]) {
computed = computed.replace(t, context[contextVar]);
}
});
}
return computed;
};

const _tokenize = (v = '') => {
const varRegexp = /\{\w+\}/g;
const tokens = v.match(varRegexp);
return tokens;
};

const loadBookmarkInView = (bookmark = {}) => {
Expand Down Expand Up @@ -471,6 +520,19 @@ requirejs(['jquery','app/storage','knockout','knockout-secure-binding','hjls','a
}
};

const saveContext = () => {
storage.saveContext({name : Resting.contexts.name(), variables : _extractModelFromVM(Resting.contexts.variables()) });
dismissContextDialog();
};

const loadContexts = () => {
// load contexts
storage.loadContexts( ctx => {
Resting.contexts.variables(_convertToEntryItemVM(ctx.variables));
});
};


Resting.parseRequest = parseRequest;
Resting.dataToSend = dataToSend;
Resting.send = send;
Expand All @@ -491,15 +553,20 @@ requirejs(['jquery','app/storage','knockout','knockout-secure-binding','hjls','a
Resting.reset = reset;
Resting.aboutDialog = aboutDialog;
Resting.creditsDialog = creditsDialog;
Resting.contextDialog = contextDialog;
Resting.dismissCreditsDialog = dismissCreditsDialog;
Resting.dismissAboutDialog = dismissAboutDialog;
Resting.dismissContextDialog = dismissContextDialog;
Resting.saveContext = saveContext;

// FIXME: not good to expose this internal function
Resting._saveBookmark = _saveBookmark;

Resting.loadBookmarkInView = loadBookmarkInView;
Resting.isBookmarkLoaded = isBookmarkLoaded;
Resting.bookmarkScreenName = bookmarkScreenName;
Resting.loadContexts = loadContexts;

return Resting;
}

Expand Down Expand Up @@ -531,6 +598,7 @@ requirejs(['jquery','app/storage','knockout','knockout-secure-binding','hjls','a
});



// Show all options, more restricted setup than the Knockout regular binding.
var options = {
attribute: "data-bind", // default "data-sbind"
Expand All @@ -541,6 +609,17 @@ requirejs(['jquery','app/storage','knockout','knockout-secure-binding','hjls','a

ko.bindingProvider.instance = new ksb(options);

ko.applyBindings(new AppViewModel());
const appVM = new AppViewModel();
ko.applyBindings(appVM);

$('ul.dropdown-menu [data-toggle=dropdown]').on('click', function(event) {
event.preventDefault();
event.stopPropagation();
$(this).parent().siblings().removeClass('open');
$(this).parent().toggleClass('open');
});

appVM.loadContexts();

});
});
Loading

0 comments on commit ab7a2b6

Please sign in to comment.