{# 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) -%}
{% if (field.id != 'csrf_token' or field.type != 'HiddenField') %} {% endif %} {{ field(class_='form-control', **kwargs) }} {% if field.errors %} {% for e in field.errors %}

{{ e }}

{% endfor %} {% endif %}
{%- 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) -%}
{%- 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() %}
{% 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.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 %}
{%- 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: '
{{ _("Click a row to select it (hold ctrl to select several)") }}', 1: '{{ _("You have selected 1 row") }}' }, }, buttons: { 'selectAll': '{{ _("Select all") }} ', 'selectNone': '{{ _("Deselect all") }} ', } }, {%- 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).tz(TIMEZONE).valueOf(); // we are using the filter the "right" way here if (moment(a, moment.ISO_8601).isValid()) return ''+moment(a, moment.ISO_8601).tz(TIMEZONE).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: * * * * @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 %}