mirror of
https://github.com/ziirish/burp-ui.git
synced 2026-05-21 06:45:24 -06:00
525 lines
16 KiB
HTML
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") }} <i class="fa fa-check-square-o" aria-hidden="true"></i>',
|
|
'selectNone': '{{ _("Deselect all") }} <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 %}
|