burp-ui/burpui/templates/macros.html
2018-05-04 22:52:48 +02:00

525 lines
16 KiB
HTML

{# Renders field for bootstrap 3 standards.
Params:
field - WTForm field
kwargs - pass any arguments you want in order to put them into the html attributes.
There are few exceptions: for - for_, class - class_, class__ - class_
Example usage:
{{ macros.render_field(form.email, placeholder='Input email', type='email') }}
#}
{% macro render_field(field, label_visible=true) -%}
<div class="form-group {% if field.errors %}has-error{% endif %} {{ kwargs.pop('class_', '') }}">
{% if (field.id != 'csrf_token' or field.type != 'HiddenField') %}
<label for="{{ field.id }}" class="control-label">{{ field.label }}</label>
{% endif %}
{{ field(class_='form-control', **kwargs) }}
{% if field.errors %}
{% for e in field.errors %}
<p class="help-block">{{ e }}</p>
{% endfor %}
{% endif %}
</div>
{%- endmacro %}
{# Renders checkbox fields since they are represented differently in bootstrap
Params:
field - WTForm field (there are no check, but you should put here only BooleanField.
kwargs - pass any arguments you want in order to put them into the html attributes.
There are few exceptions: for - for_, class - class_, class__ - class_
Example usage:
{{ macros.render_checkbox_field(form.remember_me) }}
#}
{% macro render_checkbox_field(field) -%}
<div class="checkbox">
<label>
{{ field(type='checkbox', **kwargs) }} {{ field.label }}
</label>
</div>
{%- endmacro %}
{# Renders radio field
Params:
field - WTForm field (there are no check, but you should put here only BooleanField.
kwargs - pass any arguments you want in order to put them into the html attributes.
There are few exceptions: for - for_, class - class_, class__ - class_
Example usage:
{{ macros.render_radio_field(form.answers) }}
#}
{% macro render_radio_field(field) -%}
{% for value, label, _ in field.iter_choices() %}
<div class="radio">
<label>
<input type="radio" name="{{ field.id }}" id="{{ field.id }}" value="{{ value }}">{{ label }}
</label>
</div>
{% endfor %}
{%- endmacro %}
{# Renders WTForm in bootstrap way. There are two ways to call function:
- as macros: it will render all field forms using cycle to iterate over them
- as call: it will insert form fields as you specify:
e.g. {% call macros.render_form(form, action_url=url_for('view.login_view'), action_text='Login',
class_='login-form') %}
{{ macros.render_field(form.email, placeholder='Input email', type='email') }}
{{ macros.render_field(form.password, placeholder='Input password', type='password') }}
{{ macros.render_checkbox_field(form.remember_me, type='checkbox') }}
{% endcall %}
Params:
form - WTForm class
action_url - url where to submit this form
action_text - text of submit button
class_ - sets a class for form
#}
{% macro render_form(form, action_url='', action_text='Submit', class_='', btn_class='btn btn-success') -%}
<form method="POST" action="{{ action_url }}" role="form" class="{{ class_ }}">
{{ form.hidden_tag() if form.hidden_tag }}
{% if caller %}
{{ caller() }}
{% else %}
{% for f in form %}
{% if f.type == 'BooleanField' %}
{{ render_checkbox_field(f) }}
{% elif f.type == 'RadioField' %}
{{ render_radio_field(f) }}
{% elif f.type == 'SelectField' %}
{{ render_select_field(f) }}
{% else %}
{{ render_field(f) }}
{% endif %}
{% endfor %}
{% endif %}
<button type="submit" class="{{ btn_class }}">{{ action_text }} </button>
</form>
{%- endmacro %}
{% macro smooth_scrolling() -%}
// Add a smooth scrolling to anchor
$(document).ready(function() {
$('a.scroll').click(function() {
var target = $(this.hash);
if (target.length == 0) target = $('a[name="' + this.hash.substr(1) + '"]');
if (target.length == 0) target = $('html');
$('html, body').animate({ scrollTop: target.offset().top }, 500);
return false;
});
$(".dropdown-menu label, .dropdown-menu input, .dropdown-menu li").click(function(e) {
e.stopPropagation();
});
});
{%- endmacro %}
{# Loads the datatable translation if needed #}
{% macro translate_datatable() -%}
language: {
{% if g.locale and g.locale != 'en' -%}
url: '{{ url_for("static", filename="extra/i18n/datatable-{}.json".format(g.locale)) }}',
{% endif -%}
select: {
rows: {
_: '{{ _("You have selected %%d rows") }}',
0: '<br />{{ _("Click a row to select it (hold ctrl to select several)") }}',
1: '{{ _("You have selected 1 row") }}'
},
},
buttons: {
'selectAll': '{{ _("Select all") }}&nbsp;<i class="fa fa-check-square-o" aria-hidden="true"></i>',
'selectNone': '{{ _("Deselect all") }}&nbsp;<i class="fa fa-square-o" aria-hidden="true"></i>',
}
},
{%- endmacro %}
{# Enables the calendar translation if needed #}
{% macro translate_calendar() -%}
{% if g.locale and g.locale != 'en' -%}
locale: {{ g.locale|tojson }},
{% endif -%}
{%- endmacro %}
{# Record number of elements to display #}
{% macro page_length(selector) -%}
$('{{ selector }}').on('length.dt', function(e, settings, len) {
$.post( '{{ url_for("api.prefs_ui") }}', {pageLength: len} );
});
{%- endmacro %}
{# Set number of elements to display #}
{% macro get_page_length() -%}
{% if session.pageLength -%}
pageLength: {{ session.pageLength }},
{% endif -%}
{%- endmacro %}
{# Register a new filter for datatables dates #}
{% macro timestamp_filter() -%}
// extends DataTables sorting
jQuery.extend( jQuery.fn.dataTableExt.oSort, {
"timestamp-pre": function ( a ) {
// legacy code
var $obj = $(a);
var title = $obj.attr('title');
if (typeof title !== typeof undefined && title !== false)
return moment(title, moment.ISO_8601).valueOf();
// we are using the filter the "right" way here
if (moment(a, moment.ISO_8601).isValid())
return ''+moment(a, moment.ISO_8601).valueOf();
// return some string that should be "last"
if (a === '{{ _("now") }}') {
return 'zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz'+a;
}
return 'zzzzzzzzzzzzzzzzzzzz'+a;
},
"timestamp-asc": function ( a, b ) {
return ((a < b) ? -1 : ((a > b) ? 1 : 0));
},
"timestamp-desc": function ( a, b ) {
return ((a < b) ? 1 : ((a > b) ? -1 : 0));
}
} );
{%- endmacro %}
{# create a new uiAce angular directove #}
{% macro angular_ui_ace() -%}
app.directive('uiAce', function () {
if (angular.isUndefined(window.ace)) {
throw new Error('ui-ace need ace to work... (o rly?)');
}
/**
* Sets editor options such as the wrapping mode or the syntax checker.
*
* The supported options are:
*
* <ul>
* <li>showGutter</li>
* <li>useWrapMode</li>
* <li>onLoad</li>
* <li>theme</li>
* <li>mode</li>
* </ul>
*
* @param acee
* @param session ACE editor session
* @param {object} opts Options to be set
*/
var setOptions = function(scope, acee, session, opts) {
// sets the ace worker path, if running from concatenated
// or minified source
if (angular.isDefined(opts.aceWorkerPath)) {
var config = window.ace.require('ace/config');
config.set('workerPath', opts.aceWorkerPath);
}
// ace requires loading
if (angular.isDefined(opts.aceRequire)) {
opts.aceRequire.forEach(function (n) {
window.ace.require(n);
});
}
// Boolean options
if (angular.isDefined(opts.aceShowGutter)) {
acee.renderer.setShowGutter(opts.aceShowGutter);
}
if (angular.isDefined(opts.aceUseWrapMode)) {
session.setUseWrapMode(opts.aceUseWrapMode);
}
if (angular.isDefined(opts.aceShowInvisibles)) {
acee.renderer.setShowInvisibles(opts.aceShowInvisibles);
}
if (angular.isDefined(opts.aceShowIndentGuides)) {
acee.renderer.setDisplayIndentGuides(opts.aceShowIndentGuides);
}
if (angular.isDefined(opts.aceUseSoftTabs)) {
session.setUseSoftTabs(opts.aceUseSoftTabs);
}
if (angular.isDefined(opts.aceShowPrintMargin)) {
acee.setShowPrintMargin(opts.aceShowPrintMargin);
}
if (angular.isDefined(opts.readOnly)) {
acee.setReadOnly(scope.$eval(opts.readOnly) === true);
}
// commands
if (angular.isDefined(opts.aceDisableSearch) && opts.aceDisableSearch) {
acee.commands.addCommands([
{
name: 'unfind',
bindKey: {
win: 'Ctrl-F',
mac: 'Command-F'
},
exec: function () {
return false;
},
readOnly: true
}
]);
}
// Basic options
if (angular.isString(opts.aceTheme)) {
acee.setTheme('ace/theme/' + opts.aceTheme);
}
if (angular.isString(opts.aceMode)) {
session.setMode('ace/mode/' + opts.aceMode);
}
// Advanced options
if (angular.isDefined(opts.aceFirstLineNumber)) {
if (angular.isNumber(opts.aceFirstLineNumber)) {
session.setOption('firstLineNumber', opts.aceFirstLineNumber);
} else if (angular.isFunction(opts.aceFirstLineNumber)) {
session.setOption('firstLineNumber', opts.aceFirstLineNumber());
}
}
// advanced options
var key, obj;
if (angular.isDefined(opts.aceAdvanced)) {
for (key in opts.aceAdvanced) {
// create a javascript object with the key and value
obj = { name: key, value: opts.aceAdvanced[key] };
// try to assign the option to the ace editor
acee.setOption(obj.name, obj.value);
}
}
// advanced options for the renderer
if (angular.isDefined(opts.aceRendererOptions)) {
for (key in opts.aceRendererOptions) {
// create a javascript object with the key and value
obj = { name: key, value: opts.aceRendererOptions[key] };
// try to assign the option to the ace editor
acee.renderer.setOption(obj.name, obj.value);
}
}
// onLoad callbacks
angular.forEach(opts.callbacks, function (cb) {
if (angular.isFunction(cb)) {
cb(acee);
}
});
};
return {
restrict: 'EA',
require: '?ngModel',
link: function (scope, elm, attrs, ngModel) {
/**
* uiAceConfig merged with user options via json in attribute or data binding
* @type object
*/
var opts = attrs;
/**
* ACE editor
* @type object
*/
var acee = window.ace.edit(elm[0]);
/**
* ACE editor session.
* @type object
* @see [EditSession]{@link http://ace.c9.io/#nav=api&api=edit_session}
*/
var session = acee.getSession();
/**
* Reference to a change listener created by the listener factory.
* @function
* @see listenerFactory.onChange
*/
var onChangeListener;
/**
* Reference to a blur listener created by the listener factory.
* @function
* @see listenerFactory.onBlur
*/
var onBlurListener;
/**
* Calls a callback by checking its existing. The argument list
* is variable and thus this function is relying on the arguments
* object.
* @throws {Error} If the callback isn't a function
*/
var executeUserCallback = function () {
/**
* The callback function grabbed from the array-like arguments
* object. The first argument should always be the callback.
*
* @see [arguments]{@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions_and_function_scope/arguments}
* @type {*}
*/
var callback = arguments[0];
/**
* Arguments to be passed to the callback. These are taken
* from the array-like arguments object. The first argument
* is stripped because that should be the callback function.
*
* @see [arguments]{@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions_and_function_scope/arguments}
* @type {Array}
*/
var args = Array.prototype.slice.call(arguments, 1);
if (angular.isDefined(callback)) {
scope.$evalAsync(function () {
if (angular.isFunction(callback)) {
callback(args);
} else {
throw new Error('ui-ace use a function as callback.');
}
});
}
};
/**
* Listener factory. Until now only change listeners can be created.
* @type object
*/
var listenerFactory = {
/**
* Creates a change listener which propagates the change event
* and the editor session to the callback from the user option
* onChange. It might be exchanged during runtime, if this
* happens the old listener will be unbound.
*
* @param callback callback function defined in the user options
* @see onChangeListener
*/
onChange: function (callback) {
return function (e) {
var newValue = session.getValue();
if (ngModel && newValue !== ngModel.$viewValue &&
// HACK make sure to only trigger the apply outside of the
// digest loop 'cause ACE is actually using this callback
// for any text transformation !
!scope.$$phase && !scope.$root.$$phase) {
scope.$evalAsync(function () {
ngModel.$setViewValue(newValue);
});
}
executeUserCallback(callback, e, acee);
};
},
/**
* Creates a blur listener which propagates the editor session
* to the callback from the user option onBlur. It might be
* exchanged during runtime, if this happens the old listener
* will be unbound.
*
* @param callback callback function defined in the user options
* @see onBlurListener
*/
onBlur: function (callback) {
return function () {
executeUserCallback(callback, acee);
};
}
};
session.on('changeMode', function() {
session.$worker.on('annotate', function(errors) {
scope.validGrantInput = errors.data.length <= 0;
scope.$apply();
});
});
// Value Blind
if (ngModel) {
ngModel.$formatters.push(function (value) {
if (angular.isUndefined(value) || value === null) {
return '';
}
else if (angular.isObject(value) || angular.isArray(value)) {
throw new Error('ui-ace cannot use an object or an array as a model');
}
return value;
});
ngModel.$render = function () {
session.setValue(ngModel.$viewValue);
};
}
// Listen for option updates
var updateOptions = function (current, previous) {
if (current === previous) return;
opts = attrs;
// EVENTS
// unbind old change listener
session.removeListener('change', onChangeListener);
// bind new change listener
onChangeListener = listenerFactory.onChange(opts.onChange);
session.on('change', onChangeListener);
// unbind old blur listener
//session.removeListener('blur', onBlurListener);
acee.removeListener('blur', onBlurListener);
// bind new blur listener
onBlurListener = listenerFactory.onBlur(opts.onBlur);
acee.on('blur', onBlurListener);
setOptions(scope, acee, session, opts);
};
options = [
'aceWorkerPath',
'aceRequire',
'aceShowGutter',
'aceUseWrapMode',
'aceShowInvisibles',
'aceShowIndentGuides',
'aceUseSoftTabs',
'aceShowPrintMargin',
'aceDisableSearch',
'aceTheme',
'aceMode',
'aceFirstLineNumber',
'aceAdvanced',
'aceRendererOptions',
];
for (var opt in options) {
attrs.$observe(options[opt], updateOptions);
}
scope.$watch('isLoading', function(value) {
acee.setReadOnly(value === true);
});
// scope.$watch(attrs, updateOptions, /* deep watch */ true);
elm.on('$destroy', function () {
acee.session.$stopWorker();
acee.destroy();
});
scope.$watch(function() {
return [elm[0].offsetWidth, elm[0].offsetHeight];
}, function() {
acee.resize();
acee.renderer.updateFull();
}, true);
}
}
});
{%- endmacro %}