')
+ .css(blockerCSS)
+ .css('right', 0)
+ .addClass(this.classes.rightBottomBlocker),
+ rightTopBlocker: $('
')
+ .css(blockerCSS)
+ .css({
+ right: 0,
+ top: 0
+ })
+ .addClass(this.classes.rightTopBlocker)
+ };
+ if (this.s.dt.settings()[0]._bInitComplete) {
+ // Fixed Columns Initialisation
+ this._addStyles();
+ this._setKeyTableListener();
+ }
+ else {
+ table.one('init.dt', function () {
+ // Fixed Columns Initialisation
+ _this._addStyles();
+ _this._setKeyTableListener();
+ });
+ }
+ table.on('column-sizing.dt', function () { return _this._addStyles(); });
+ // Make class available through dt object
+ table.settings()[0]._fixedColumns = this;
+ return this;
+ }
+ /**
+ * Getter/Setter for the `fixedColumns.left` property
+ *
+ * @param newVal Optional. If present this will be the new value for the number of left fixed columns
+ * @returns The number of left fixed columns
+ */
+ FixedColumns.prototype.left = function (newVal) {
+ // If the value is to change
+ if (newVal !== undefined) {
+ // Set the new values and redraw the columns
+ this.c.left = newVal;
+ this._addStyles();
+ }
+ return this.c.left;
+ };
+ /**
+ * Getter/Setter for the `fixedColumns.left` property
+ *
+ * @param newVal Optional. If present this will be the new value for the number of right fixed columns
+ * @returns The number of right fixed columns
+ */
+ FixedColumns.prototype.right = function (newVal) {
+ // If the value is to change
+ if (newVal !== undefined) {
+ // Set the new values and redraw the columns
+ this.c.right = newVal;
+ this._addStyles();
+ }
+ return this.c.right;
+ };
+ /**
+ * Iterates over the columns, fixing the appropriate ones to the left and right
+ */
+ FixedColumns.prototype._addStyles = function () {
+ // Set the bar width if vertical scrolling is enabled
+ if (this.s.dt.settings()[0].oScroll.sY) {
+ var scroll_1 = $(this.s.dt.table().node()).closest('div.dataTables_scrollBody')[0];
+ var barWidth = this.s.dt.settings()[0].oBrowser.barWidth;
+ if (scroll_1.offsetWidth - scroll_1.clientWidth >= barWidth) {
+ this.s.barWidth = barWidth;
+ }
+ else {
+ this.s.barWidth = 0;
+ }
+ this.dom.rightTopBlocker.css('width', this.s.barWidth + 1);
+ this.dom.leftTopBlocker.css('width', this.s.barWidth + 1);
+ this.dom.rightBottomBlocker.css('width', this.s.barWidth + 1);
+ this.dom.leftBottomBlocker.css('width', this.s.barWidth + 1);
+ }
+ var parentDiv = null;
+ // Get the header and it's height
+ var header = this.s.dt.column(0).header();
+ var headerHeight = null;
+ if (header !== null) {
+ header = $(header);
+ headerHeight = header.outerHeight() + 1;
+ parentDiv = $(header.closest('div.dataTables_scroll')).css('position', 'relative');
+ }
+ // Get the footer and it's height
+ var footer = this.s.dt.column(0).footer();
+ var footerHeight = null;
+ if (footer !== null) {
+ footer = $(footer);
+ footerHeight = footer.outerHeight();
+ // Only attempt to retrieve the parentDiv if it has not been retrieved already
+ if (parentDiv === null) {
+ parentDiv = $(footer.closest('div.dataTables_scroll')).css('position', 'relative');
+ }
+ }
+ // Get the number of columns in the table - this is used often so better to only make 1 api call
+ var numCols = this.s.dt.columns().data().toArray().length;
+ // Tracker for the number of pixels should be left to the left of the table
+ var distLeft = 0;
+ // Sometimes the headers have slightly different widths so need to track them individually
+ var headLeft = 0;
+ // Get all of the row elements in the table
+ var rows = $(this.s.dt.table().node()).children('tbody').children('tr');
+ var invisibles = 0;
+ // When working from right to left we need to know how many are invisible before a point,
+ // without including those that are invisible after
+ var prevInvisible = new Map();
+ // Iterate over all of the columns
+ for (var i = 0; i < numCols; i++) {
+ var column = this.s.dt.column(i);
+ // Set the map for the previous column
+ if (i > 0) {
+ prevInvisible.set(i - 1, invisibles);
+ }
+ if (!column.visible()) {
+ invisibles++;
+ continue;
+ }
+ // Get the columns header and footer element
+ var colHeader = $(column.header());
+ var colFooter = $(column.footer());
+ // If i is less than the value of left then this column should be fixed left
+ if (i - invisibles < this.c.left) {
+ $(this.s.dt.table().node()).addClass(this.classes.tableFixedLeft);
+ parentDiv.addClass(this.classes.tableFixedLeft);
+ // Add the width of the previous node - only if we are on atleast the second column
+ if (i - invisibles > 0) {
+ var prevIdx = i;
+ // Simply using the number of hidden columns doesn't work here,
+ // if the first is hidden then this would be thrown off
+ while (prevIdx + 1 < numCols) {
+ var prevCol = this.s.dt.column(prevIdx - 1, { page: 'current' });
+ if (prevCol.visible()) {
+ distLeft += $(prevCol.nodes()[0]).outerWidth();
+ headLeft += prevCol.header() ?
+ $(prevCol.header()).outerWidth() :
+ prevCol.footer() ?
+ $(prevCol.header()).outerWidth() :
+ 0;
+ break;
+ }
+ prevIdx--;
+ }
+ }
+ // Iterate over all of the rows, fixing the cell to the left
+ for (var _i = 0, rows_1 = rows; _i < rows_1.length; _i++) {
+ var row = rows_1[_i];
+ $($(row).children()[i - invisibles])
+ .css(this._getCellCSS(false, distLeft, 'left'))
+ .addClass(this.classes.fixedLeft);
+ }
+ // Add the css for the header and the footer
+ colHeader
+ .css(this._getCellCSS(true, headLeft, 'left'))
+ .addClass(this.classes.fixedLeft);
+ colFooter
+ .css(this._getCellCSS(true, headLeft, 'left'))
+ .addClass(this.classes.fixedLeft);
+ }
+ else {
+ // Iteriate through all of the rows, making sure they aren't currently trying to fix left
+ for (var _a = 0, rows_2 = rows; _a < rows_2.length; _a++) {
+ var row = rows_2[_a];
+ var cell = $($(row).children()[i - invisibles]);
+ // If the cell is trying to fix to the left, remove the class and the css
+ if (cell.hasClass(this.classes.fixedLeft)) {
+ cell
+ .css(this._clearCellCSS('left'))
+ .removeClass(this.classes.fixedLeft);
+ }
+ }
+ // Make sure the header for this column isn't fixed left
+ if (colHeader.hasClass(this.classes.fixedLeft)) {
+ colHeader
+ .css(this._clearCellCSS('left'))
+ .removeClass(this.classes.fixedLeft);
+ }
+ // Make sure the footer for this column isn't fixed left
+ if (colFooter.hasClass(this.classes.fixedLeft)) {
+ colFooter
+ .css(this._clearCellCSS('left'))
+ .removeClass(this.classes.fixedLeft);
+ }
+ }
+ }
+ // If there is a header with the index class and reading rtl then add left top blocker
+ if (header !== null && !header.hasClass('index')) {
+ if (this.s.rtl) {
+ this.dom.leftTopBlocker.outerHeight(headerHeight);
+ parentDiv.append(this.dom.leftTopBlocker);
+ }
+ else {
+ this.dom.rightTopBlocker.outerHeight(headerHeight);
+ parentDiv.append(this.dom.rightTopBlocker);
+ }
+ }
+ // If there is a footer with the index class and reading rtl then add left bottom blocker
+ if (footer !== null && !footer.hasClass('index')) {
+ if (this.s.rtl) {
+ this.dom.leftBottomBlocker.outerHeight(footerHeight);
+ parentDiv.append(this.dom.leftBottomBlocker);
+ }
+ else {
+ this.dom.rightBottomBlocker.outerHeight(footerHeight);
+ parentDiv.append(this.dom.rightBottomBlocker);
+ }
+ }
+ var distRight = 0;
+ var headRight = 0;
+ // Counter for the number of invisible columns so far
+ var rightInvisibles = 0;
+ for (var i = numCols - 1; i >= 0; i--) {
+ var column = this.s.dt.column(i);
+ // If a column is invisible just skip it
+ if (!column.visible()) {
+ rightInvisibles++;
+ continue;
+ }
+ // Get the columns header and footer element
+ var colHeader = $(column.header());
+ var colFooter = $(column.footer());
+ // Get the number of visible columns that came before this one
+ var prev = prevInvisible.get(i);
+ if (prev === undefined) {
+ // If it wasn't set then it was the last column so just use the final value
+ prev = invisibles;
+ }
+ if (i + rightInvisibles >= numCols - this.c.right) {
+ $(this.s.dt.table().node()).addClass(this.classes.tableFixedRight);
+ parentDiv.addClass(this.classes.tableFixedRight);
+ // Add the widht of the previous node, only if we are on atleast the second column
+ if (i + 1 + rightInvisibles < numCols) {
+ var prevIdx = i;
+ // Simply using the number of hidden columns doesn't work here,
+ // if the first is hidden then this would be thrown off
+ while (prevIdx + 1 < numCols) {
+ var prevCol = this.s.dt.column(prevIdx + 1, { page: 'current' });
+ if (prevCol.visible()) {
+ distRight += $(prevCol.nodes()[0]).outerWidth();
+ headRight += prevCol.header() ?
+ $(prevCol.header()).outerWidth() :
+ prevCol.footer() ?
+ $(prevCol.header()).outerWidth() :
+ 0;
+ break;
+ }
+ prevIdx++;
+ }
+ }
+ // Iterate over all of the rows, fixing the cell to the right
+ for (var _b = 0, rows_3 = rows; _b < rows_3.length; _b++) {
+ var row = rows_3[_b];
+ $($(row).children()[i - prev])
+ .css(this._getCellCSS(false, distRight, 'right'))
+ .addClass(this.classes.fixedRight);
+ }
+ // Add the css for the header and the footer
+ colHeader
+ .css(this._getCellCSS(true, headRight, 'right'))
+ .addClass(this.classes.fixedRight);
+ colFooter
+ .css(this._getCellCSS(true, headRight, 'right'))
+ .addClass(this.classes.fixedRight);
+ }
+ else {
+ // Iteriate through all of the rows, making sure they aren't currently trying to fix right
+ for (var _c = 0, rows_4 = rows; _c < rows_4.length; _c++) {
+ var row = rows_4[_c];
+ var cell = $($(row).children()[i - prev]);
+ // If the cell is trying to fix to the right, remove the class and the css
+ if (cell.hasClass(this.classes.fixedRight)) {
+ cell
+ .css(this._clearCellCSS('right'))
+ .removeClass(this.classes.fixedRight);
+ }
+ }
+ // Make sure the header for this column isn't fixed right
+ if (colHeader.hasClass(this.classes.fixedRight)) {
+ colHeader
+ .css(this._clearCellCSS('right'))
+ .removeClass(this.classes.fixedRight);
+ }
+ // Make sure the footer for this column isn't fixed right
+ if (colFooter.hasClass(this.classes.fixedRight)) {
+ colFooter
+ .css(this._clearCellCSS('right'))
+ .removeClass(this.classes.fixedRight);
+ }
+ }
+ }
+ // If there is a header with the index class and reading rtl then add right top blocker
+ if (header) {
+ if (!this.s.rtl) {
+ this.dom.rightTopBlocker.outerHeight(headerHeight);
+ parentDiv.append(this.dom.rightTopBlocker);
+ }
+ else {
+ this.dom.leftTopBlocker.outerHeight(headerHeight);
+ parentDiv.append(this.dom.leftTopBlocker);
+ }
+ }
+ // If there is a footer with the index class and reading rtl then add right bottom blocker
+ if (footer) {
+ if (!this.s.rtl) {
+ this.dom.rightBottomBlocker.outerHeight(footerHeight);
+ parentDiv.append(this.dom.rightBottomBlocker);
+ }
+ else {
+ this.dom.leftBottomBlocker.outerHeight(footerHeight);
+ parentDiv.append(this.dom.leftBottomBlocker);
+ }
+ }
+ };
+ /**
+ * Gets the correct CSS for the cell, header or footer based on options provided
+ *
+ * @param header Whether this cell is a header or a footer
+ * @param dist The distance that the cell should be moved away from the edge
+ * @param lr Indicator of fixing to the left or the right
+ * @returns An object containing the correct css
+ */
+ FixedColumns.prototype._getCellCSS = function (header, dist, lr) {
+ if (lr === 'left') {
+ return this.s.rtl
+ ? {
+ position: 'sticky',
+ right: dist + 'px'
+ }
+ : {
+ left: dist + 'px',
+ position: 'sticky'
+ };
+ }
+ else {
+ return this.s.rtl
+ ? {
+ left: dist + (header ? this.s.barWidth : 0) + 'px',
+ position: 'sticky'
+ }
+ : {
+ position: 'sticky',
+ right: dist + (header ? this.s.barWidth : 0) + 'px'
+ };
+ }
+ };
+ /**
+ * Gets the css that is required to clear the fixing to a side
+ *
+ * @param lr Indicator of fixing to the left or the right
+ * @returns An object containing the correct css
+ */
+ FixedColumns.prototype._clearCellCSS = function (lr) {
+ if (lr === 'left') {
+ return !this.s.rtl ?
+ {
+ left: '',
+ position: ''
+ } :
+ {
+ position: '',
+ right: ''
+ };
+ }
+ else {
+ return !this.s.rtl ?
+ {
+ position: '',
+ right: ''
+ } :
+ {
+ left: '',
+ position: ''
+ };
+ }
+ };
+ FixedColumns.prototype._setKeyTableListener = function () {
+ var _this = this;
+ this.s.dt.on('key-focus', function (e, dt, cell) {
+ var cellPos = $(cell.node()).offset();
+ var scroll = $($(_this.s.dt.table().node()).closest('div.dataTables_scrollBody'));
+ // If there are fixed columns to the left
+ if (_this.c.left > 0) {
+ // Get the rightmost left fixed column header, it's position and it's width
+ var rightMost = $(_this.s.dt.column(_this.c.left - 1).header());
+ var rightMostPos = rightMost.offset();
+ var rightMostWidth = rightMost.outerWidth();
+ // If the current highlighted cell is left of the rightmost cell on the screen
+ if (cellPos.left < rightMostPos.left + rightMostWidth) {
+ // Scroll it into view
+ var currScroll = scroll.scrollLeft();
+ scroll.scrollLeft(currScroll - (rightMostPos.left + rightMostWidth - cellPos.left));
+ }
+ }
+ // If there are fixed columns to the right
+ if (_this.c.right > 0) {
+ // Get the number of columns and the width of the cell as doing right side calc
+ var numCols = _this.s.dt.columns().data().toArray().length;
+ var cellWidth = $(cell.node()).outerWidth();
+ // Get the leftmost right fixed column header and it's position
+ var leftMost = $(_this.s.dt.column(numCols - _this.c.right).header());
+ var leftMostPos = leftMost.offset();
+ // If the current highlighted cell is right of the leftmost cell on the screen
+ if (cellPos.left + cellWidth > leftMostPos.left) {
+ // Scroll it into view
+ var currScroll = scroll.scrollLeft();
+ scroll.scrollLeft(currScroll - (leftMostPos.left - (cellPos.left + cellWidth)));
+ }
+ }
+ });
+ // Whenever a draw occurs there is potential for the data to have changed and therefore also the column widths
+ // Therefore it is necessary to recalculate the values for the fixed columns
+ this.s.dt.on('draw', function () {
+ _this._addStyles();
+ });
+ this.s.dt.on('column-reorder', function () {
+ _this._addStyles();
+ });
+ this.s.dt.on('column-visibility', function (e, settings, column, state, recalc) {
+ if (recalc && !settings.bDestroying) {
+ setTimeout(function () {
+ _this._addStyles();
+ }, 50);
+ }
+ });
+ };
+ FixedColumns.version = '4.1.0';
+ FixedColumns.classes = {
+ fixedLeft: 'dtfc-fixed-left',
+ fixedRight: 'dtfc-fixed-right',
+ leftBottomBlocker: 'dtfc-left-bottom-blocker',
+ leftTopBlocker: 'dtfc-left-top-blocker',
+ rightBottomBlocker: 'dtfc-right-bottom-blocker',
+ rightTopBlocker: 'dtfc-right-top-blocker',
+ tableFixedLeft: 'dtfc-has-left',
+ tableFixedRight: 'dtfc-has-right'
+ };
+ FixedColumns.defaults = {
+ i18n: {
+ button: 'FixedColumns'
+ },
+ left: 1,
+ right: 0
+ };
+ return FixedColumns;
+ }());
+
+ /*! FixedColumns 4.1.0
+ * 2019-2022 SpryMedia Ltd - datatables.net/license
+ */
+ // DataTables extensions common UMD. Note that this allows for AMD, CommonJS
+ // (with window and jQuery being allowed as parameters to the returned
+ // function) or just default browser loading.
+ (function (factory) {
+ if (typeof define === 'function' && define.amd) {
+ // AMD
+ define(['jquery', 'datatables.net'], function ($) {
+ return factory($, window, document);
+ });
+ }
+ else if (typeof exports === 'object') {
+ // CommonJS
+ module.exports = function (root, $) {
+ if (!root) {
+ root = window;
+ }
+ if (!$ || !$.fn.dataTable) {
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
+ $ = require('datatables.net')(root, $).$;
+ }
+ return factory($, root, root.document);
+ };
+ }
+ else {
+ // Browser - assume jQuery has already been loaded
+ factory(window.jQuery, window, document);
+ }
+ }(function ($, window, document) {
+ setJQuery($);
+ var dataTable = $.fn.dataTable;
+ $.fn.dataTable.FixedColumns = FixedColumns;
+ $.fn.DataTable.FixedColumns = FixedColumns;
+ var apiRegister = $.fn.dataTable.Api.register;
+ apiRegister('fixedColumns()', function () {
+ return this;
+ });
+ apiRegister('fixedColumns().left()', function (newVal) {
+ var ctx = this.context[0];
+ if (newVal !== undefined) {
+ ctx._fixedColumns.left(newVal);
+ return this;
+ }
+ else {
+ return ctx._fixedColumns.left();
+ }
+ });
+ apiRegister('fixedColumns().right()', function (newVal) {
+ var ctx = this.context[0];
+ if (newVal !== undefined) {
+ ctx._fixedColumns.right(newVal);
+ return this;
+ }
+ else {
+ return ctx._fixedColumns.right();
+ }
+ });
+ $.fn.dataTable.ext.buttons.fixedColumns = {
+ action: function (e, dt, node, config) {
+ if ($(node).attr('active')) {
+ $(node).removeAttr('active').removeClass('active');
+ dt.fixedColumns().left(0);
+ dt.fixedColumns().right(0);
+ }
+ else {
+ $(node).attr('active', true).addClass('active');
+ dt.fixedColumns().left(config.config.left);
+ dt.fixedColumns().right(config.config.right);
+ }
+ },
+ config: {
+ left: 1,
+ right: 0
+ },
+ init: function (dt, node, config) {
+ if (dt.settings()[0]._fixedColumns === undefined) {
+ _init(dt.settings(), config);
+ }
+ $(node).attr('active', true).addClass('active');
+ dt.button(node).text(config.text || dt.i18n('buttons.fixedColumns', dt.settings()[0]._fixedColumns.c.i18n.button));
+ },
+ text: null
+ };
+ function _init(settings, options) {
+ if (options === void 0) { options = null; }
+ var api = new dataTable.Api(settings);
+ var opts = options
+ ? options
+ : api.init().fixedColumns || dataTable.defaults.fixedColumns;
+ var fixedColumns = new FixedColumns(api, opts);
+ return fixedColumns;
+ }
+ // Attach a listener to the document which listens for DataTables initialisation
+ // events so we can automatically initialise
+ $(document).on('plugin-init.dt', function (e, settings) {
+ if (e.namespace !== 'dt') {
+ return;
+ }
+ if (settings.oInit.fixedColumns ||
+ dataTable.defaults.fixedColumns) {
+ if (!settings._fixedColumns) {
+ _init(settings, null);
+ }
+ }
+ });
+ }));
+
+})();
+
+
+/*! KeyTable 2.7.0
+ * ©2009-2022 SpryMedia Ltd - datatables.net/license
+ */
+
+/**
+ * @summary KeyTable
+ * @description Spreadsheet like keyboard navigation for DataTables
+ * @version 2.7.0
+ * @author SpryMedia Ltd (www.sprymedia.co.uk)
+ * @contact www.sprymedia.co.uk
+ * @copyright SpryMedia Ltd.
+ *
+ * This source file is free software, available under the following license:
+ * MIT license - http://datatables.net/license/mit
+ *
+ * This source file is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details.
+ *
+ * For details please refer to: http://www.datatables.net
+ */
+
+(function( factory ){
+ if ( typeof define === 'function' && define.amd ) {
+ // AMD
+ define( ['jquery', 'datatables.net'], function ( $ ) {
+ return factory( $, window, document );
+ } );
+ }
+ else if ( typeof exports === 'object' ) {
+ // CommonJS
+ module.exports = function (root, $) {
+ if ( ! root ) {
+ root = window;
+ }
+
+ if ( ! $ || ! $.fn.dataTable ) {
+ $ = require('datatables.net')(root, $).$;
+ }
+
+ return factory( $, root, root.document );
+ };
+ }
+ else {
+ // Browser
+ factory( jQuery, window, document );
+ }
+}(function( $, window, document, undefined ) {
+'use strict';
+var DataTable = $.fn.dataTable;
+var namespaceCounter = 0;
+var editorNamespaceCounter = 0;
+
+
+var KeyTable = function ( dt, opts ) {
+ // Sanity check that we are using DataTables 1.10 or newer
+ if ( ! DataTable.versionCheck || ! DataTable.versionCheck( '1.10.8' ) ) {
+ throw 'KeyTable requires DataTables 1.10.8 or newer';
+ }
+
+ // User and defaults configuration object
+ this.c = $.extend( true, {},
+ DataTable.defaults.keyTable,
+ KeyTable.defaults,
+ opts
+ );
+
+ // Internal settings
+ this.s = {
+ /** @type {DataTable.Api} DataTables' API instance */
+ dt: new DataTable.Api( dt ),
+
+ enable: true,
+
+ /** @type {bool} Flag for if a draw is triggered by focus */
+ focusDraw: false,
+
+ /** @type {bool} Flag to indicate when waiting for a draw to happen.
+ * Will ignore key presses at this point
+ */
+ waitingForDraw: false,
+
+ /** @type {object} Information about the last cell that was focused */
+ lastFocus: null,
+
+ /** @type {string} Unique namespace per instance */
+ namespace: '.keyTable-'+(namespaceCounter++),
+
+ /** @type {Node} Input element for tabbing into the table */
+ tabInput: null
+ };
+
+ // DOM items
+ this.dom = {
+
+ };
+
+ // Check if row reorder has already been initialised on this table
+ var settings = this.s.dt.settings()[0];
+ var exisiting = settings.keytable;
+ if ( exisiting ) {
+ return exisiting;
+ }
+
+ settings.keytable = this;
+ this._constructor();
+};
+
+
+$.extend( KeyTable.prototype, {
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * API methods for DataTables API interface
+ */
+
+ /**
+ * Blur the table's cell focus
+ */
+ blur: function ()
+ {
+ this._blur();
+ },
+
+ /**
+ * Enable cell focus for the table
+ *
+ * @param {string} state Can be `true`, `false` or `-string navigation-only`
+ */
+ enable: function ( state )
+ {
+ this.s.enable = state;
+ },
+
+ /**
+ * Get enable status
+ */
+ enabled: function () {
+ return this.s.enable;
+ },
+
+ /**
+ * Focus on a cell
+ * @param {integer} row Row index
+ * @param {integer} column Column index
+ */
+ focus: function ( row, column )
+ {
+ this._focus( this.s.dt.cell( row, column ) );
+ },
+
+ /**
+ * Is the cell focused
+ * @param {object} cell Cell index to check
+ * @returns {boolean} true if focused, false otherwise
+ */
+ focused: function ( cell )
+ {
+ var lastFocus = this.s.lastFocus;
+
+ if ( ! lastFocus ) {
+ return false;
+ }
+
+ var lastIdx = this.s.lastFocus.cell.index();
+ return cell.row === lastIdx.row && cell.column === lastIdx.column;
+ },
+
+
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Constructor
+ */
+
+ /**
+ * Initialise the KeyTable instance
+ *
+ * @private
+ */
+ _constructor: function ()
+ {
+ this._tabInput();
+
+ var that = this;
+ var dt = this.s.dt;
+ var table = $( dt.table().node() );
+ var namespace = this.s.namespace;
+ var editorBlock = false;
+
+ // Need to be able to calculate the cell positions relative to the table
+ if ( table.css('position') === 'static' ) {
+ table.css( 'position', 'relative' );
+ }
+
+ // Click to focus
+ $( dt.table().body() ).on( 'click'+namespace, 'th, td', function (e) {
+ if ( that.s.enable === false ) {
+ return;
+ }
+
+ var cell = dt.cell( this );
+
+ if ( ! cell.any() ) {
+ return;
+ }
+
+ that._focus( cell, null, false, e );
+ } );
+
+ // Key events
+ $( document ).on( 'keydown'+namespace, function (e) {
+ if ( ! editorBlock ) {
+ that._key( e );
+ }
+ } );
+
+ // Click blur
+ if ( this.c.blurable ) {
+ $( document ).on( 'mousedown'+namespace, function ( e ) {
+ // Click on the search input will blur focus
+ if ( $(e.target).parents( '.dataTables_filter' ).length ) {
+ that._blur();
+ }
+
+ // If the click was inside the DataTables container, don't blur
+ if ( $(e.target).parents().filter( dt.table().container() ).length ) {
+ return;
+ }
+
+ // Don't blur in Editor form
+ if ( $(e.target).parents('div.DTE').length ) {
+ return;
+ }
+
+ // Or an Editor date input
+ if (
+ $(e.target).parents('div.editor-datetime').length ||
+ $(e.target).parents('div.dt-datetime').length
+ ) {
+ return;
+ }
+
+ //If the click was inside the fixed columns container, don't blur
+ if ( $(e.target).parents().filter('.DTFC_Cloned').length ) {
+ return;
+ }
+
+ that._blur();
+ } );
+ }
+
+ if ( this.c.editor ) {
+ var editor = this.c.editor;
+
+ // Need to disable KeyTable when the main editor is shown
+ editor.on( 'open.keyTableMain', function (e, mode, action) {
+ if ( mode !== 'inline' && that.s.enable ) {
+ that.enable( false );
+
+ editor.one( 'close'+namespace, function () {
+ that.enable( true );
+ } );
+ }
+ } );
+
+ if ( this.c.editOnFocus ) {
+ dt.on( 'key-focus'+namespace+' key-refocus'+namespace, function ( e, dt, cell, orig ) {
+ that._editor( null, orig, true );
+ } );
+ }
+
+ // Activate Editor when a key is pressed (will be ignored, if
+ // already active).
+ dt.on( 'key'+namespace, function ( e, dt, key, cell, orig ) {
+ that._editor( key, orig, false );
+ } );
+
+ // Active editing on double click - it will already have focus from
+ // the click event handler above
+ $( dt.table().body() ).on( 'dblclick'+namespace, 'th, td', function (e) {
+ if ( that.s.enable === false ) {
+ return;
+ }
+
+ var cell = dt.cell( this );
+
+ if ( ! cell.any() ) {
+ return;
+ }
+
+ if ( that.s.lastFocus && this !== that.s.lastFocus.cell.node() ) {
+ return;
+ }
+
+ that._editor( null, e, true );
+ } );
+
+ // While Editor is busy processing, we don't want to process any key events
+ editor
+ .on('preSubmit', function () {
+ editorBlock = true;
+ } )
+ .on('preSubmitCancelled', function () {
+ editorBlock = false;
+ } )
+ .on('submitComplete', function () {
+ editorBlock = false;
+ } );
+ }
+
+ // Stave saving
+ // if ( dt.settings()[0].oFeatures.bStateSave ) {
+ dt.on( 'stateSaveParams'+namespace, function (e, s, d) {
+ d.keyTable = that.s.lastFocus ?
+ that.s.lastFocus.cell.index() :
+ null;
+ } );
+ // }
+
+ dt.on( 'column-visibility'+namespace, function (e) {
+ that._tabInput();
+ } );
+
+ dt.on( 'column-reorder'+namespace, function (e, s, d) {
+ // Need to update the last focus cell's index
+ var lastFocus = that.s.lastFocus;
+
+ if (lastFocus && lastFocus.cell) {
+ var curr = lastFocus.relative.column;
+
+ // Manipulate the API instance to correct the column index
+ lastFocus.cell[0][0].column = d.mapping.indexOf(curr);
+ lastFocus.relative.column = d.mapping.indexOf(curr);
+ }
+ } );
+
+ // Redraw - retain focus on the current cell
+ dt.on( 'draw'+namespace, function (e) {
+ that._tabInput();
+
+ if ( that.s.focusDraw ) {
+ return;
+ }
+
+ var lastFocus = that.s.lastFocus;
+
+ if ( lastFocus ) {
+ var relative = that.s.lastFocus.relative;
+ var info = dt.page.info();
+ var row = relative.row + info.start;
+
+ if ( info.recordsDisplay === 0 ) {
+ return;
+ }
+
+ // Reverse if needed
+ if ( row >= info.recordsDisplay ) {
+ row = info.recordsDisplay - 1;
+ }
+
+ that._focus( row, relative.column, true, e );
+ }
+ } );
+
+ // Clipboard support
+ if ( this.c.clipboard ) {
+ this._clipboard();
+ }
+
+ dt.on( 'destroy'+namespace, function () {
+ that._blur( true );
+
+ // Event tidy up
+ dt.off( namespace );
+
+ $( dt.table().body() )
+ .off( 'click'+namespace, 'th, td' )
+ .off( 'dblclick'+namespace, 'th, td' );
+
+ $( document )
+ .off( 'mousedown'+namespace )
+ .off( 'keydown'+namespace )
+ .off( 'copy'+namespace )
+ .off( 'paste'+namespace );
+ } );
+
+ // Initial focus comes from state or options
+ var state = dt.state.loaded();
+
+ if ( state && state.keyTable ) {
+ // Wait until init is done
+ dt.one( 'init', function () {
+ var cell = dt.cell( state.keyTable );
+
+ // Ensure that the saved cell still exists
+ if ( cell.any() ) {
+ cell.focus();
+ }
+ } );
+ }
+ else if ( this.c.focus ) {
+ dt.cell( this.c.focus ).focus();
+ }
+ },
+
+
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Private methods
+ */
+
+ /**
+ * Blur the control
+ *
+ * @param {boolean} [noEvents=false] Don't trigger updates / events (for destroying)
+ * @private
+ */
+ _blur: function (noEvents)
+ {
+ if ( ! this.s.enable || ! this.s.lastFocus ) {
+ return;
+ }
+
+ var cell = this.s.lastFocus.cell;
+
+ $( cell.node() ).removeClass( this.c.className );
+ this.s.lastFocus = null;
+
+ if ( ! noEvents ) {
+ this._updateFixedColumns(cell.index().column);
+
+ this._emitEvent( 'key-blur', [ this.s.dt, cell ] );
+ }
+ },
+
+
+ /**
+ * Clipboard interaction handlers
+ *
+ * @private
+ */
+ _clipboard: function () {
+ var dt = this.s.dt;
+ var that = this;
+ var namespace = this.s.namespace;
+
+ // IE8 doesn't support getting selected text
+ if ( ! window.getSelection ) {
+ return;
+ }
+
+ $(document).on( 'copy'+namespace, function (ejq) {
+ var e = ejq.originalEvent;
+ var selection = window.getSelection().toString();
+ var focused = that.s.lastFocus;
+
+ // Only copy cell text to clipboard if there is no other selection
+ // and there is a focused cell
+ if ( ! selection && focused ) {
+ e.clipboardData.setData(
+ 'text/plain',
+ focused.cell.render( that.c.clipboardOrthogonal )
+ );
+ e.preventDefault();
+ }
+ } );
+
+ $(document).on( 'paste'+namespace, function (ejq) {
+ var e = ejq.originalEvent;
+ var focused = that.s.lastFocus;
+ var activeEl = document.activeElement;
+ var editor = that.c.editor;
+ var pastedText;
+
+ if ( focused && (! activeEl || activeEl.nodeName.toLowerCase() === 'body') ) {
+ e.preventDefault();
+
+ if ( window.clipboardData && window.clipboardData.getData ) {
+ // IE
+ pastedText = window.clipboardData.getData('Text');
+ }
+ else if ( e.clipboardData && e.clipboardData.getData ) {
+ // Everything else
+ pastedText = e.clipboardData.getData('text/plain');
+ }
+
+ if ( editor ) {
+ // Got Editor - need to activate inline editing,
+ // set the value and submit
+ var options = that._inlineOptions(focused.cell.index());
+
+ editor
+ .inline(options.cell, options.field, options.options)
+ .set( editor.displayed()[0], pastedText )
+ .submit();
+ }
+ else {
+ // No editor, so just dump the data in
+ focused.cell.data( pastedText );
+ dt.draw(false);
+ }
+ }
+ } );
+ },
+
+
+ /**
+ * Get an array of the column indexes that KeyTable can operate on. This
+ * is a merge of the user supplied columns and the visible columns.
+ *
+ * @private
+ */
+ _columns: function ()
+ {
+ var dt = this.s.dt;
+ var user = dt.columns( this.c.columns ).indexes();
+ var out = [];
+
+ dt.columns( ':visible' ).every( function (i) {
+ if ( user.indexOf( i ) !== -1 ) {
+ out.push( i );
+ }
+ } );
+
+ return out;
+ },
+
+
+ /**
+ * Perform excel like navigation for Editor by triggering an edit on key
+ * press
+ *
+ * @param {integer} key Key code for the pressed key
+ * @param {object} orig Original event
+ * @private
+ */
+ _editor: function ( key, orig, hardEdit )
+ {
+ // If nothing focused, we can't take any action
+ if (! this.s.lastFocus) {
+ return;
+ }
+
+ // DataTables draw event
+ if (orig && orig.type === 'draw') {
+ return;
+ }
+
+ var that = this;
+ var dt = this.s.dt;
+ var editor = this.c.editor;
+ var editCell = this.s.lastFocus.cell;
+ var namespace = this.s.namespace + 'e' + editorNamespaceCounter++;
+
+ // Do nothing if there is already an inline edit in this cell
+ if ( $('div.DTE', editCell.node()).length ) {
+ return;
+ }
+
+ // Don't activate Editor on control key presses
+ if ( key !== null && (
+ (key >= 0x00 && key <= 0x09) ||
+ key === 0x0b ||
+ key === 0x0c ||
+ (key >= 0x0e && key <= 0x1f) ||
+ (key >= 0x70 && key <= 0x7b) ||
+ (key >= 0x7f && key <= 0x9f)
+ ) ) {
+ return;
+ }
+
+ if ( orig ) {
+ orig.stopPropagation();
+
+ // Return key should do nothing - for textareas it would empty the
+ // contents
+ if ( key === 13 ) {
+ orig.preventDefault();
+ }
+ }
+
+ var editInline = function () {
+ var options = that._inlineOptions(editCell.index());
+
+ editor
+ .one( 'open'+namespace, function () {
+ // Remove cancel open
+ editor.off( 'cancelOpen'+namespace );
+
+ // Excel style - select all text
+ if ( ! hardEdit ) {
+ $('div.DTE_Field_InputControl input, div.DTE_Field_InputControl textarea').select();
+ }
+
+ // Reduce the keys the Keys listens for
+ dt.keys.enable( hardEdit ? 'tab-only' : 'navigation-only' );
+
+ // On blur of the navigation submit
+ dt.on( 'key-blur.editor', function (e, dt, cell) {
+ if ( editor.displayed() && cell.node() === editCell.node() ) {
+ editor.submit();
+ }
+ } );
+
+ // Highlight the cell a different colour on full edit
+ if ( hardEdit ) {
+ $( dt.table().container() ).addClass('dtk-focus-alt');
+ }
+
+ // If the dev cancels the submit, we need to return focus
+ editor.on( 'preSubmitCancelled'+namespace, function () {
+ setTimeout( function () {
+ that._focus( editCell, null, false );
+ }, 50 );
+ } );
+
+ editor.on( 'submitUnsuccessful'+namespace, function () {
+ that._focus( editCell, null, false );
+ } );
+
+ // Restore full key navigation on close
+ editor.one( 'close'+namespace, function () {
+ dt.keys.enable( true );
+ dt.off( 'key-blur.editor' );
+ editor.off( namespace );
+ $( dt.table().container() ).removeClass('dtk-focus-alt');
+
+ if (that.s.returnSubmit) {
+ that.s.returnSubmit = false;
+ that._emitEvent( 'key-return-submit', [dt, editCell] );
+ }
+ } );
+ } )
+ .one( 'cancelOpen'+namespace, function () {
+ // `preOpen` can cancel the display of the form, so it
+ // might be that the open event handler isn't needed
+ editor.off( namespace );
+ } )
+ .inline(options.cell, options.field, options.options);
+ };
+
+ // Editor 1.7 listens for `return` on keyup, so if return is the trigger
+ // key, we need to wait for `keyup` otherwise Editor would just submit
+ // the content triggered by this keypress.
+ if ( key === 13 ) {
+ hardEdit = true;
+
+ $(document).one( 'keyup', function () { // immediately removed
+ editInline();
+ } );
+ }
+ else {
+ editInline();
+ }
+ },
+
+
+ _inlineOptions: function (cellIdx)
+ {
+ if (this.c.editorOptions) {
+ return this.c.editorOptions(cellIdx);
+ }
+
+ return {
+ cell: cellIdx,
+ field: undefined,
+ options: undefined
+ };
+ },
+
+
+ /**
+ * Emit an event on the DataTable for listeners
+ *
+ * @param {string} name Event name
+ * @param {array} args Event arguments
+ * @private
+ */
+ _emitEvent: function ( name, args )
+ {
+ this.s.dt.iterator( 'table', function ( ctx, i ) {
+ $(ctx.nTable).triggerHandler( name, args );
+ } );
+ },
+
+
+ /**
+ * Focus on a particular cell, shifting the table's paging if required
+ *
+ * @param {DataTables.Api|integer} row Can be given as an API instance that
+ * contains the cell to focus or as an integer. As the latter it is the
+ * visible row index (from the whole data set) - NOT the data index
+ * @param {integer} [column] Not required if a cell is given as the first
+ * parameter. Otherwise this is the column data index for the cell to
+ * focus on
+ * @param {boolean} [shift=true] Should the viewport be moved to show cell
+ * @private
+ */
+ _focus: function ( row, column, shift, originalEvent )
+ {
+ var that = this;
+ var dt = this.s.dt;
+ var pageInfo = dt.page.info();
+ var lastFocus = this.s.lastFocus;
+
+ if ( ! originalEvent) {
+ originalEvent = null;
+ }
+
+ if ( ! this.s.enable ) {
+ return;
+ }
+
+ if ( typeof row !== 'number' ) {
+ // Its an API instance - check that there is actually a row
+ if ( ! row.any() ) {
+ return;
+ }
+
+ // Convert the cell to a row and column
+ var index = row.index();
+ column = index.column;
+ row = dt
+ .rows( { filter: 'applied', order: 'applied' } )
+ .indexes()
+ .indexOf( index.row );
+
+ // Don't focus rows that were filtered out.
+ if ( row < 0 ) {
+ return;
+ }
+
+ // For server-side processing normalise the row by adding the start
+ // point, since `rows().indexes()` includes only rows that are
+ // available at the client-side
+ if ( pageInfo.serverSide ) {
+ row += pageInfo.start;
+ }
+ }
+
+ // Is the row on the current page? If not, we need to redraw to show the
+ // page
+ if ( pageInfo.length !== -1 && (row < pageInfo.start || row >= pageInfo.start+pageInfo.length) ) {
+ this.s.focusDraw = true;
+ this.s.waitingForDraw = true;
+
+ dt
+ .one( 'draw', function () {
+ that.s.focusDraw = false;
+ that.s.waitingForDraw = false;
+ that._focus( row, column, undefined, originalEvent );
+ } )
+ .page( Math.floor( row / pageInfo.length ) )
+ .draw( false );
+
+ return;
+ }
+
+ // In the available columns?
+ if ( $.inArray( column, this._columns() ) === -1 ) {
+ return;
+ }
+
+ // De-normalise the server-side processing row, so we select the row
+ // in its displayed position
+ if ( pageInfo.serverSide ) {
+ row -= pageInfo.start;
+ }
+
+ // Get the cell from the current position - ignoring any cells which might
+ // not have been rendered (therefore can't use `:eq()` selector).
+ var cells = dt.cells( null, column, {search: 'applied', order: 'applied'} ).flatten();
+ var cell = dt.cell( cells[ row ] );
+
+ if ( lastFocus ) {
+ // Don't trigger a refocus on the same cell
+ if ( lastFocus.node === cell.node() ) {
+ this._emitEvent( 'key-refocus', [ this.s.dt, cell, originalEvent || null ] );
+ return;
+ }
+
+ // Otherwise blur the old focus
+ this._blur();
+ }
+
+ // Clear focus from other tables
+ this._removeOtherFocus();
+
+ var node = $( cell.node() );
+ node.addClass( this.c.className );
+
+ this._updateFixedColumns(column);
+
+ // Shift viewpoint and page to make cell visible
+ if ( shift === undefined || shift === true ) {
+ this._scroll( $(window), $(document.body), node, 'offset' );
+
+ var bodyParent = dt.table().body().parentNode;
+ if ( bodyParent !== dt.table().header().parentNode ) {
+ var parent = $(bodyParent.parentNode);
+
+ this._scroll( parent, parent, node, 'position' );
+ }
+ }
+
+ // Event and finish
+ this.s.lastFocus = {
+ cell: cell,
+ node: cell.node(),
+ relative: {
+ row: dt.rows( { page: 'current' } ).indexes().indexOf( cell.index().row ),
+ column: cell.index().column
+ }
+ };
+
+ this._emitEvent( 'key-focus', [ this.s.dt, cell, originalEvent || null ] );
+ dt.state.save();
+ },
+
+
+ /**
+ * Handle key press
+ *
+ * @param {object} e Event
+ * @private
+ */
+ _key: function ( e )
+ {
+ // If we are waiting for a draw to happen from another key event, then
+ // do nothing for this new key press.
+ if ( this.s.waitingForDraw ) {
+ e.preventDefault();
+ return;
+ }
+
+ var enable = this.s.enable;
+ this.s.returnSubmit = (enable === 'navigation-only' || enable === 'tab-only') && e.keyCode === 13
+ ? true
+ : false;
+
+ var navEnable = enable === true || enable === 'navigation-only';
+ if ( ! enable ) {
+ return;
+ }
+
+ if ( (e.keyCode === 0 || e.ctrlKey || e.metaKey || e.altKey) && !(e.ctrlKey && e.altKey) ) {
+ return;
+ }
+
+ // If not focused, then there is no key action to take
+ var lastFocus = this.s.lastFocus;
+ if ( ! lastFocus ) {
+ return;
+ }
+
+ // And the last focus still exists!
+ if ( ! this.s.dt.cell(lastFocus.node).any() ) {
+ this.s.lastFocus = null;
+ return;
+ }
+
+ var that = this;
+ var dt = this.s.dt;
+ var scrolling = this.s.dt.settings()[0].oScroll.sY ? true : false;
+
+ // If we are not listening for this key, do nothing
+ if ( this.c.keys && $.inArray( e.keyCode, this.c.keys ) === -1 ) {
+ return;
+ }
+
+ switch( e.keyCode ) {
+ case 9: // tab
+ // `enable` can be tab-only
+ this._shift( e, e.shiftKey ? 'left' : 'right', true );
+ break;
+
+ case 27: // esc
+ if ( this.c.blurable && enable === true ) {
+ this._blur();
+ }
+ break;
+
+ case 33: // page up (previous page)
+ case 34: // page down (next page)
+ if ( navEnable && !scrolling ) {
+ e.preventDefault();
+
+ dt
+ .page( e.keyCode === 33 ? 'previous' : 'next' )
+ .draw( false );
+ }
+ break;
+
+ case 35: // end (end of current page)
+ case 36: // home (start of current page)
+ if ( navEnable ) {
+ e.preventDefault();
+ var indexes = dt.cells( {page: 'current'} ).indexes();
+ var colIndexes = this._columns();
+
+ this._focus( dt.cell(
+ indexes[ e.keyCode === 35 ? indexes.length-1 : colIndexes[0] ]
+ ), null, true, e );
+ }
+ break;
+
+ case 37: // left arrow
+ if ( navEnable ) {
+ this._shift( e, 'left' );
+ }
+ break;
+
+ case 38: // up arrow
+ if ( navEnable ) {
+ this._shift( e, 'up' );
+ }
+ break;
+
+ case 39: // right arrow
+ if ( navEnable ) {
+ this._shift( e, 'right' );
+ }
+ break;
+
+ case 40: // down arrow
+ if ( navEnable ) {
+ this._shift( e, 'down' );
+ }
+ break;
+
+ case 113: // F2 - Excel like hard edit
+ if ( this.c.editor ) {
+ this._editor(null, e, true);
+ break;
+ }
+ // else fallthrough
+
+ default:
+ // Everything else - pass through only when fully enabled
+ if ( enable === true ) {
+ this._emitEvent( 'key', [ dt, e.keyCode, this.s.lastFocus.cell, e ] );
+ }
+ break;
+ }
+ },
+
+ /**
+ * Remove focus from all tables other than this one
+ */
+ _removeOtherFocus: function ()
+ {
+ var thisTable = this.s.dt.table().node();
+
+ $.fn.dataTable.tables({api:true}).iterator('table', function (settings) {
+ if (this.table().node() !== thisTable) {
+ this.cell.blur();
+ }
+ });
+ },
+
+ /**
+ * Scroll a container to make a cell visible in it. This can be used for
+ * both DataTables scrolling and native window scrolling.
+ *
+ * @param {jQuery} container Scrolling container
+ * @param {jQuery} scroller Item being scrolled
+ * @param {jQuery} cell Cell in the scroller
+ * @param {string} posOff `position` or `offset` - which to use for the
+ * calculation. `offset` for the document, otherwise `position`
+ * @private
+ */
+ _scroll: function ( container, scroller, cell, posOff )
+ {
+ var offset = cell[posOff]();
+ var height = cell.outerHeight();
+ var width = cell.outerWidth();
+
+ var scrollTop = scroller.scrollTop();
+ var scrollLeft = scroller.scrollLeft();
+ var containerHeight = container.height();
+ var containerWidth = container.width();
+
+ // If Scroller is being used, the table can be `position: absolute` and that
+ // needs to be taken account of in the offset. If no Scroller, this will be 0
+ if ( posOff === 'position' ) {
+ offset.top += parseInt( cell.closest('table').css('top'), 10 );
+ }
+
+ // Top correction
+ if ( offset.top < scrollTop ) {
+ scroller.scrollTop( offset.top );
+ }
+
+ // Left correction
+ if ( offset.left < scrollLeft ) {
+ scroller.scrollLeft( offset.left );
+ }
+
+ // Bottom correction
+ if ( offset.top + height > scrollTop + containerHeight && height < containerHeight ) {
+ scroller.scrollTop( offset.top + height - containerHeight );
+ }
+
+ // Right correction
+ if ( offset.left + width > scrollLeft + containerWidth && width < containerWidth ) {
+ scroller.scrollLeft( offset.left + width - containerWidth );
+ }
+ },
+
+
+ /**
+ * Calculate a single offset movement in the table - up, down, left and
+ * right and then perform the focus if possible
+ *
+ * @param {object} e Event object
+ * @param {string} direction Movement direction
+ * @param {boolean} keyBlurable `true` if the key press can result in the
+ * table being blurred. This is so arrow keys won't blur the table, but
+ * tab will.
+ * @private
+ */
+ _shift: function ( e, direction, keyBlurable )
+ {
+ var that = this;
+ var dt = this.s.dt;
+ var pageInfo = dt.page.info();
+ var rows = pageInfo.recordsDisplay;
+ var columns = this._columns();
+ var last = this.s.lastFocus;
+ if ( ! last ) {
+ return;
+ }
+
+ var currentCell = last.cell;
+ if ( ! currentCell ) {
+ return;
+ }
+
+ var currRow = dt
+ .rows( { filter: 'applied', order: 'applied' } )
+ .indexes()
+ .indexOf( currentCell.index().row );
+
+ // When server-side processing, `rows().indexes()` only gives the rows
+ // that are available at the client-side, so we need to normalise the
+ // row's current position by the display start point
+ if ( pageInfo.serverSide ) {
+ currRow += pageInfo.start;
+ }
+
+ var currCol = dt
+ .columns( columns )
+ .indexes()
+ .indexOf( currentCell.index().column );
+
+ var
+ row = currRow,
+ column = columns[ currCol ]; // row is the display, column is an index
+
+ // If the direction is rtl then the logic needs to be inverted from this point forwards
+ if($(dt.table().node()).css('direction') === 'rtl') {
+ if(direction === 'right') {
+ direction = 'left';
+ }
+ else if(direction === 'left'){
+ direction = 'right';
+ }
+ }
+
+ if ( direction === 'right' ) {
+ if ( currCol >= columns.length - 1 ) {
+ row++;
+ column = columns[0];
+ }
+ else {
+ column = columns[ currCol+1 ];
+ }
+ }
+ else if ( direction === 'left' ) {
+ if ( currCol === 0 ) {
+ row--;
+ column = columns[ columns.length - 1 ];
+ }
+ else {
+ column = columns[ currCol-1 ];
+ }
+ }
+ else if ( direction === 'up' ) {
+ row--;
+ }
+ else if ( direction === 'down' ) {
+ row++;
+ }
+
+ if ( row >= 0 && row < rows && $.inArray( column, columns ) !== -1 ) {
+ if (e) {
+ e.preventDefault();
+ }
+
+ this._focus( row, column, true, e );
+ }
+ else if ( ! keyBlurable || ! this.c.blurable ) {
+ // No new focus, but if the table isn't blurable, then don't loose
+ // focus
+ if (e) {
+ e.preventDefault();
+ }
+ }
+ else {
+ this._blur();
+ }
+ },
+
+
+ /**
+ * Create and insert a hidden input element that can receive focus on behalf
+ * of the table
+ *
+ * @private
+ */
+ _tabInput: function ()
+ {
+ var that = this;
+ var dt = this.s.dt;
+ var tabIndex = this.c.tabIndex !== null ?
+ this.c.tabIndex :
+ dt.settings()[0].iTabIndex;
+
+ if ( tabIndex == -1 ) {
+ return;
+ }
+
+ // Only create the input element once on first class
+ if (! this.s.tabInput) {
+ var div = $('
')
+ .css( {
+ position: 'absolute',
+ height: 1,
+ width: 0,
+ overflow: 'hidden'
+ } );
+
+ div.children().on( 'focus', function (e) {
+ var cell = dt.cell(':eq(0)', that._columns(), {page: 'current'});
+
+ if ( cell.any() ) {
+ that._focus( cell, null, true, e );
+ }
+ } );
+
+ this.s.tabInput = div;
+ }
+
+ // Insert the input element into the first cell in the table's body
+ var cell = this.s.dt.cell(':eq(0)', '0:visible', {page: 'current', order: 'current'}).node();
+ if (cell) {
+ $(cell).prepend(this.s.tabInput);
+ }
+ },
+
+ /**
+ * Update fixed columns if they are enabled and if the cell we are
+ * focusing is inside a fixed column
+ * @param {integer} column Index of the column being changed
+ * @private
+ */
+ _updateFixedColumns: function( column )
+ {
+ var dt = this.s.dt;
+ var settings = dt.settings()[0];
+
+ if ( settings._oFixedColumns ) {
+ var leftCols = settings._oFixedColumns.s.iLeftColumns;
+ var rightCols = settings.aoColumns.length - settings._oFixedColumns.s.iRightColumns;
+
+ if (column < leftCols || column >= rightCols) {
+ dt.fixedColumns().update();
+ }
+ }
+ }
+} );
+
+
+/**
+ * KeyTable default settings for initialisation
+ *
+ * @namespace
+ * @name KeyTable.defaults
+ * @static
+ */
+KeyTable.defaults = {
+ /**
+ * Can focus be removed from the table
+ * @type {Boolean}
+ */
+ blurable: true,
+
+ /**
+ * Class to give to the focused cell
+ * @type {String}
+ */
+ className: 'focus',
+
+ /**
+ * Enable or disable clipboard support
+ * @type {Boolean}
+ */
+ clipboard: true,
+
+ /**
+ * Orthogonal data that should be copied to clipboard
+ * @type {string}
+ */
+ clipboardOrthogonal: 'display',
+
+ /**
+ * Columns that can be focused. This is automatically merged with the
+ * visible columns as only visible columns can gain focus.
+ * @type {String}
+ */
+ columns: '', // all
+
+ /**
+ * Editor instance to automatically perform Excel like navigation
+ * @type {Editor}
+ */
+ editor: null,
+
+ /**
+ * Trigger editing immediately on focus
+ * @type {boolean}
+ */
+ editOnFocus: false,
+
+ /**
+ * Options to pass to Editor's inline method
+ * @type {function}
+ */
+ editorOptions: null,
+
+ /**
+ * Select a cell to automatically select on start up. `null` for no
+ * automatic selection
+ * @type {cell-selector}
+ */
+ focus: null,
+
+ /**
+ * Array of keys to listen for
+ * @type {null|array}
+ */
+ keys: null,
+
+ /**
+ * Tab index for where the table should sit in the document's tab flow
+ * @type {integer|null}
+ */
+ tabIndex: null
+};
+
+
+
+KeyTable.version = "2.7.0";
+
+
+$.fn.dataTable.KeyTable = KeyTable;
+$.fn.DataTable.KeyTable = KeyTable;
+
+
+DataTable.Api.register( 'cell.blur()', function () {
+ return this.iterator( 'table', function (ctx) {
+ if ( ctx.keytable ) {
+ ctx.keytable.blur();
+ }
+ } );
+} );
+
+DataTable.Api.register( 'cell().focus()', function () {
+ return this.iterator( 'cell', function (ctx, row, column) {
+ if ( ctx.keytable ) {
+ ctx.keytable.focus( row, column );
+ }
+ } );
+} );
+
+DataTable.Api.register( 'keys.disable()', function () {
+ return this.iterator( 'table', function (ctx) {
+ if ( ctx.keytable ) {
+ ctx.keytable.enable( false );
+ }
+ } );
+} );
+
+DataTable.Api.register( 'keys.enable()', function ( opts ) {
+ return this.iterator( 'table', function (ctx) {
+ if ( ctx.keytable ) {
+ ctx.keytable.enable( opts === undefined ? true : opts );
+ }
+ } );
+} );
+
+DataTable.Api.register( 'keys.enabled()', function ( opts ) {
+ var ctx = this.context;
+
+ if (ctx.length) {
+ return ctx[0].keytable
+ ? ctx[0].keytable.enabled()
+ : false;
+ }
+
+ return false;
+} );
+
+DataTable.Api.register( 'keys.move()', function ( dir ) {
+ return this.iterator( 'table', function (ctx) {
+ if ( ctx.keytable ) {
+ ctx.keytable._shift( null, dir, false );
+ }
+ } );
+} );
+
+// Cell selector
+DataTable.ext.selector.cell.push( function ( settings, opts, cells ) {
+ var focused = opts.focused;
+ var kt = settings.keytable;
+ var out = [];
+
+ if ( ! kt || focused === undefined ) {
+ return cells;
+ }
+
+ for ( var i=0, ien=cells.length ; i
td, >th', tr).each( function ( i ) {
+ var idx = dt.column.index( 'toData', i );
+
+ if ( that.s.current[idx] === false ) {
+ $(this).css('display', 'none');
+ }
+ } );
+ }
+ } );
+
+ // Destroy event handler
+ dt.on( 'destroy.dtr', function () {
+ dt.off( '.dtr' );
+ $( dt.table().body() ).off( '.dtr' );
+ $(window).off( 'resize.dtr orientationchange.dtr' );
+ dt.cells('.dtr-control').nodes().to$().removeClass('dtr-control');
+
+ // Restore the columns that we've hidden
+ $.each( that.s.current, function ( i, val ) {
+ if ( val === false ) {
+ that._setColumnVis( i, true );
+ }
+ } );
+ } );
+
+ // Reorder the breakpoints array here in case they have been added out
+ // of order
+ this.c.breakpoints.sort( function (a, b) {
+ return a.width < b.width ? 1 :
+ a.width > b.width ? -1 : 0;
+ } );
+
+ this._classLogic();
+ this._resizeAuto();
+
+ // Details handler
+ var details = this.c.details;
+
+ if ( details.type !== false ) {
+ that._detailsInit();
+
+ // DataTables will trigger this event on every column it shows and
+ // hides individually
+ dt.on( 'column-visibility.dtr', function () {
+ // Use a small debounce to allow multiple columns to be set together
+ if ( that._timer ) {
+ clearTimeout( that._timer );
+ }
+
+ that._timer = setTimeout( function () {
+ that._timer = null;
+
+ that._classLogic();
+ that._resizeAuto();
+ that._resize(true);
+
+ that._redrawChildren();
+ }, 100 );
+ } );
+
+ // Redraw the details box on each draw which will happen if the data
+ // has changed. This is used until DataTables implements a native
+ // `updated` event for rows
+ dt.on( 'draw.dtr', function () {
+ that._redrawChildren();
+ } );
+
+ $(dt.table().node()).addClass( 'dtr-'+details.type );
+ }
+
+ dt.on( 'column-reorder.dtr', function (e, settings, details) {
+ that._classLogic();
+ that._resizeAuto();
+ that._resize(true);
+ } );
+
+ // Change in column sizes means we need to calc
+ dt.on( 'column-sizing.dtr', function () {
+ that._resizeAuto();
+ that._resize();
+ });
+
+ // DT2 let's us tell it if we are hiding columns
+ dt.on( 'column-calc.dt', function (e, d) {
+ var curr = that.s.current;
+
+ for (var i=0 ; i= 0) {
+ d.visible.splice(idx, 1);
+ }
+ }
+ } );
+
+ // On Ajax reload we want to reopen any child rows which are displayed
+ // by responsive
+ dt.on( 'preXhr.dtr', function () {
+ var rowIds = [];
+ dt.rows().every( function () {
+ if ( this.child.isShown() ) {
+ rowIds.push( this.id(true) );
+ }
+ } );
+
+ dt.one( 'draw.dtr', function () {
+ that._resizeAuto();
+ that._resize();
+
+ dt.rows( rowIds ).every( function () {
+ that._detailsDisplay( this, false );
+ } );
+ } );
+ });
+
+ dt
+ .on( 'draw.dtr', function () {
+ that._controlClass();
+ })
+ .on( 'init.dtr', function (e, settings, details) {
+ if ( e.namespace !== 'dt' ) {
+ return;
+ }
+
+ that._resizeAuto();
+ that._resize();
+
+ // If columns were hidden, then DataTables needs to adjust the
+ // column sizing
+ if ( $.inArray( false, that.s.current ) ) {
+ dt.columns.adjust();
+ }
+ } );
+
+ // First pass - draw the table for the current viewport size
+ this._resize();
+ },
+
+
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Private methods
+ */
+
+ /**
+ * Calculate the visibility for the columns in a table for a given
+ * breakpoint. The result is pre-determined based on the class logic if
+ * class names are used to control all columns, but the width of the table
+ * is also used if there are columns which are to be automatically shown
+ * and hidden.
+ *
+ * @param {string} breakpoint Breakpoint name to use for the calculation
+ * @return {array} Array of boolean values initiating the visibility of each
+ * column.
+ * @private
+ */
+ _columnsVisiblity: function ( breakpoint )
+ {
+ var dt = this.s.dt;
+ var columns = this.s.columns;
+ var i, ien;
+
+ // Create an array that defines the column ordering based first on the
+ // column's priority, and secondly the column index. This allows the
+ // columns to be removed from the right if the priority matches
+ var order = columns
+ .map( function ( col, idx ) {
+ return {
+ columnIdx: idx,
+ priority: col.priority
+ };
+ } )
+ .sort( function ( a, b ) {
+ if ( a.priority !== b.priority ) {
+ return a.priority - b.priority;
+ }
+ return a.columnIdx - b.columnIdx;
+ } );
+
+ // Class logic - determine which columns are in this breakpoint based
+ // on the classes. If no class control (i.e. `auto`) then `-` is used
+ // to indicate this to the rest of the function
+ var display = $.map( columns, function ( col, i ) {
+ if ( dt.column(i).visible() === false ) {
+ return 'not-visible';
+ }
+ return col.auto && col.minWidth === null ?
+ false :
+ col.auto === true ?
+ '-' :
+ $.inArray( breakpoint, col.includeIn ) !== -1;
+ } );
+
+ // Auto column control - first pass: how much width is taken by the
+ // ones that must be included from the non-auto columns
+ var requiredWidth = 0;
+ for ( i=0, ien=display.length ; i= size ) {
+ add( colIdx, breakpoints[i].name );
+ }
+ }
+ }
+ else if ( operator === 'not-' ) {
+ // Add all but this breakpoint
+ for ( i=0, ien=breakpoints.length ; i=0 ; i-- ) {
+ if ( width <= breakpoints[i].width ) {
+ breakpoint = breakpoints[i].name;
+ break;
+ }
+ }
+
+ // Show the columns for that break point
+ var columnsVis = this._columnsVisiblity( breakpoint );
+ this.s.current = columnsVis;
+
+ // Set the class before the column visibility is changed so event
+ // listeners know what the state is. Need to determine if there are
+ // any columns that are not visible but can be shown
+ var collapsedClass = false;
+
+ for ( i=0, ien=columns.length ; i ')
+ .append( footerCells )
+ .appendTo( clonedFooter );
+ }
+
+ $(' ')
+ .append( headerCells )
+ .appendTo( clonedHeader );
+
+ // In the inline case extra padding is applied to the first column to
+ // give space for the show / hide icon. We need to use this in the
+ // calculation
+ if ( this.c.details.type === 'inline' ) {
+ $(clonedTable).addClass( 'dtr-inline collapsed' );
+ }
+
+ // It is unsafe to insert elements with the same name into the DOM
+ // multiple times. For example, cloning and inserting a checked radio
+ // clears the chcecked state of the original radio.
+ $( clonedTable ).find( '[name]' ).removeAttr( 'name' );
+
+ // A position absolute table would take the table out of the flow of
+ // our container element, bypassing the height and width (Scroller)
+ $( clonedTable ).css( 'position', 'relative' )
+
+ var inserted = $('
')
+ .css( {
+ width: 1,
+ height: 1,
+ overflow: 'hidden',
+ clear: 'both'
+ } )
+ .append( clonedTable );
+
+ inserted.insertBefore( dt.table().node() );
+
+ // The cloned header now contains the smallest that each column can be
+ headerCells.each( function (i) {
+ var idx = dt.column.index( 'fromVisible', i );
+ columns[ idx ].minWidth = this.offsetWidth || 0;
+ } );
+
+ inserted.remove();
+ },
+
+ /**
+ * Get the state of the current hidden columns - controlled by Responsive only
+ */
+ _responsiveOnlyHidden: function ()
+ {
+ var dt = this.s.dt;
+
+ return $.map( this.s.current, function (v, i) {
+ // If the column is hidden by DataTables then it can't be hidden by
+ // Responsive!
+ if ( dt.column(i).visible() === false ) {
+ return true;
+ }
+ return v;
+ } );
+ },
+
+ /**
+ * Set a column's visibility.
+ *
+ * We don't use DataTables' column visibility controls in order to ensure
+ * that column visibility can Responsive can no-exist. Since only IE8+ is
+ * supported (and all evergreen browsers of course) the control of the
+ * display attribute works well.
+ *
+ * @param {integer} col Column index
+ * @param {boolean} showHide Show or hide (true or false)
+ * @private
+ */
+ _setColumnVis: function ( col, showHide )
+ {
+ var dt = this.s.dt;
+ var display = showHide ? '' : 'none'; // empty string will remove the attr
+
+ $( dt.column( col ).header() )
+ .css( 'display', display )
+ .toggleClass('dtr-hidden', !showHide);
+
+ $( dt.column( col ).footer() )
+ .css( 'display', display )
+ .toggleClass('dtr-hidden', !showHide);
+
+ dt.column( col ).nodes().to$()
+ .css( 'display', display )
+ .toggleClass('dtr-hidden', !showHide);
+
+ // If the are child nodes stored, we might need to reinsert them
+ if ( ! $.isEmptyObject( _childNodeStore ) ) {
+ dt.cells( null, col ).indexes().each( function (idx) {
+ _childNodesRestore( dt, idx.row, idx.column );
+ } );
+ }
+ },
+
+
+ /**
+ * Update the cell tab indexes for keyboard accessibility. This is called on
+ * every table draw - that is potentially inefficient, but also the least
+ * complex option given that column visibility can change on the fly. Its a
+ * shame user-focus was removed from CSS 3 UI, as it would have solved this
+ * issue with a single CSS statement.
+ *
+ * @private
+ */
+ _tabIndexes: function ()
+ {
+ var dt = this.s.dt;
+ var cells = dt.cells( { page: 'current' } ).nodes().to$();
+ var ctx = dt.settings()[0];
+ var target = this.c.details.target;
+
+ cells.filter( '[data-dtr-keyboard]' ).removeData( '[data-dtr-keyboard]' );
+
+ if ( typeof target === 'number' ) {
+ dt.cells( null, target, { page: 'current' } ).nodes().to$()
+ .attr( 'tabIndex', ctx.iTabIndex )
+ .data( 'dtr-keyboard', 1 );
+ }
+ else {
+ // This is a bit of a hack - we need to limit the selected nodes to just
+ // those of this table
+ if ( target === 'td:first-child, th:first-child' ) {
+ target = '>td:first-child, >th:first-child';
+ }
+
+ $( target, dt.rows( { page: 'current' } ).nodes() )
+ .attr( 'tabIndex', ctx.iTabIndex )
+ .data( 'dtr-keyboard', 1 );
+ }
+ }
+} );
+
+
+/**
+ * List of default breakpoints. Each item in the array is an object with two
+ * properties:
+ *
+ * * `name` - the breakpoint name.
+ * * `width` - the breakpoint width
+ *
+ * @name Responsive.breakpoints
+ * @static
+ */
+Responsive.breakpoints = [
+ { name: 'desktop', width: Infinity },
+ { name: 'tablet-l', width: 1024 },
+ { name: 'tablet-p', width: 768 },
+ { name: 'mobile-l', width: 480 },
+ { name: 'mobile-p', width: 320 }
+];
+
+
+/**
+ * Display methods - functions which define how the hidden data should be shown
+ * in the table.
+ *
+ * @namespace
+ * @name Responsive.defaults
+ * @static
+ */
+Responsive.display = {
+ childRow: function ( row, update, render ) {
+ if ( update ) {
+ if ( $(row.node()).hasClass('parent') ) {
+ row.child( render(), 'child' ).show();
+
+ return true;
+ }
+ }
+ else {
+ if ( ! row.child.isShown() ) {
+ row.child( render(), 'child' ).show();
+ $( row.node() ).addClass( 'parent' );
+
+ return true;
+ }
+ else {
+ row.child( false );
+ $( row.node() ).removeClass( 'parent' );
+
+ return false;
+ }
+ }
+ },
+
+ childRowImmediate: function ( row, update, render ) {
+ if ( (! update && row.child.isShown()) || ! row.responsive.hasHidden() ) {
+ // User interaction and the row is show, or nothing to show
+ row.child( false );
+ $( row.node() ).removeClass( 'parent' );
+
+ return false;
+ }
+ else {
+ // Display
+ row.child( render(), 'child' ).show();
+ $( row.node() ).addClass( 'parent' );
+
+ return true;
+ }
+ },
+
+ // This is a wrapper so the modal options for Bootstrap and jQuery UI can
+ // have options passed into them. This specific one doesn't need to be a
+ // function but it is for consistency in the `modal` name
+ modal: function ( options ) {
+ return function ( row, update, render ) {
+ if ( ! update ) {
+ // Show a modal
+ var close = function () {
+ modal.remove(); // will tidy events for us
+ $(document).off( 'keypress.dtr' );
+ };
+
+ var modal = $('
')
+ .append( $('
')
+ .append( $('
')
+ .append( render() )
+ )
+ .append( $('×
' )
+ .click( function () {
+ close();
+ } )
+ )
+ )
+ .append( $('
')
+ .click( function () {
+ close();
+ } )
+ )
+ .appendTo( 'body' );
+
+ $(document).on( 'keyup.dtr', function (e) {
+ if ( e.keyCode === 27 ) {
+ e.stopPropagation();
+
+ close();
+ }
+ } );
+ }
+ else {
+ $('div.dtr-modal-content')
+ .empty()
+ .append( render() );
+ }
+
+ if ( options && options.header ) {
+ $('div.dtr-modal-content').prepend(
+ ''+options.header( row )+' '
+ );
+ }
+ };
+ }
+};
+
+
+var _childNodeStore = {};
+
+function _childNodes( dt, row, col ) {
+ var name = row+'-'+col;
+
+ if ( _childNodeStore[ name ] ) {
+ return _childNodeStore[ name ];
+ }
+
+ // https://jsperf.com/childnodes-array-slice-vs-loop
+ var nodes = [];
+ var children = dt.cell( row, col ).node().childNodes;
+ for ( var i=0, ien=children.length ; i ');
+ var found = false;
+
+ var data = $.each( columns, function ( i, col ) {
+ if ( col.hidden ) {
+ var klass = col.className ?
+ 'class="'+ col.className +'"' :
+ '';
+
+ $(
+ ''+
+ ''+
+ col.title+
+ ' '+
+ ' '
+ )
+ .append( $(' ').append( _childNodes( api, col.rowIndex, col.columnIndex ) ) )// api.cell( col.rowIndex, col.columnIndex ).node().childNodes ) )
+ .appendTo( ul );
+
+ found = true;
+ }
+ } );
+
+ return found ?
+ ul :
+ false;
+ };
+ },
+
+ listHidden: function () {
+ return function ( api, rowIdx, columns ) {
+ var data = $.map( columns, function ( col ) {
+ var klass = col.className ?
+ 'class="'+ col.className +'"' :
+ '';
+
+ return col.hidden ?
+ ''+
+ ''+
+ col.title+
+ ' '+
+ ''+
+ col.data+
+ ' '+
+ ' ' :
+ '';
+ } ).join('');
+
+ return data ?
+ $('').append( data ) :
+ false;
+ }
+ },
+
+ tableAll: function ( options ) {
+ options = $.extend( {
+ tableClass: ''
+ }, options );
+
+ return function ( api, rowIdx, columns ) {
+ var data = $.map( columns, function ( col ) {
+ var klass = col.className ?
+ 'class="'+ col.className +'"' :
+ '';
+
+ return ''+
+ ''+col.title+':'+' '+
+ ''+col.data+' '+
+ ' ';
+ } ).join('');
+
+ return $('').append( data );
+ }
+ }
+};
+
+/**
+ * Responsive default settings for initialisation
+ *
+ * @namespace
+ * @name Responsive.defaults
+ * @static
+ */
+Responsive.defaults = {
+ /**
+ * List of breakpoints for the instance. Note that this means that each
+ * instance can have its own breakpoints. Additionally, the breakpoints
+ * cannot be changed once an instance has been creased.
+ *
+ * @type {Array}
+ * @default Takes the value of `Responsive.breakpoints`
+ */
+ breakpoints: Responsive.breakpoints,
+
+ /**
+ * Enable / disable auto hiding calculations. It can help to increase
+ * performance slightly if you disable this option, but all columns would
+ * need to have breakpoint classes assigned to them
+ *
+ * @type {Boolean}
+ * @default `true`
+ */
+ auto: true,
+
+ /**
+ * Details control. If given as a string value, the `type` property of the
+ * default object is set to that value, and the defaults used for the rest
+ * of the object - this is for ease of implementation.
+ *
+ * The object consists of the following properties:
+ *
+ * * `display` - A function that is used to show and hide the hidden details
+ * * `renderer` - function that is called for display of the child row data.
+ * The default function will show the data from the hidden columns
+ * * `target` - Used as the selector for what objects to attach the child
+ * open / close to
+ * * `type` - `false` to disable the details display, `inline` or `column`
+ * for the two control types
+ *
+ * @type {Object|string}
+ */
+ details: {
+ display: Responsive.display.childRow,
+
+ renderer: Responsive.renderer.listHidden(),
+
+ target: 0,
+
+ type: 'inline'
+ },
+
+ /**
+ * Orthogonal data request option. This is used to define the data type
+ * requested when Responsive gets the data to show in the child row.
+ *
+ * @type {String}
+ */
+ orthogonal: 'display'
+};
+
+
+/*
+ * API
+ */
+var Api = $.fn.dataTable.Api;
+
+// Doesn't do anything - work around for a bug in DT... Not documented
+Api.register( 'responsive()', function () {
+ return this;
+} );
+
+Api.register( 'responsive.index()', function ( li ) {
+ li = $(li);
+
+ return {
+ column: li.data('dtr-index'),
+ row: li.parent().data('dtr-index')
+ };
+} );
+
+Api.register( 'responsive.rebuild()', function () {
+ return this.iterator( 'table', function ( ctx ) {
+ if ( ctx._responsive ) {
+ ctx._responsive._classLogic();
+ }
+ } );
+} );
+
+Api.register( 'responsive.recalc()', function () {
+ return this.iterator( 'table', function ( ctx ) {
+ if ( ctx._responsive ) {
+ ctx._responsive._resizeAuto();
+ ctx._responsive._resize();
+ }
+ } );
+} );
+
+Api.register( 'responsive.hasHidden()', function () {
+ var ctx = this.context[0];
+
+ return ctx._responsive ?
+ $.inArray( false, ctx._responsive._responsiveOnlyHidden() ) !== -1 :
+ false;
+} );
+
+Api.registerPlural( 'columns().responsiveHidden()', 'column().responsiveHidden()', function () {
+ return this.iterator( 'column', function ( settings, column ) {
+ return settings._responsive ?
+ settings._responsive._responsiveOnlyHidden()[ column ] :
+ false;
+ }, 1 );
+} );
+
+
+/**
+ * Version information
+ *
+ * @name Responsive.version
+ * @static
+ */
+Responsive.version = '2.3.0';
+
+
+$.fn.dataTable.Responsive = Responsive;
+$.fn.DataTable.Responsive = Responsive;
+
+// Attach a listener to the document which listens for DataTables initialisation
+// events so we can automatically initialise
+$(document).on( 'preInit.dt.dtr', function (e, settings, json) {
+ if ( e.namespace !== 'dt' ) {
+ return;
+ }
+
+ if ( $(settings.nTable).hasClass( 'responsive' ) ||
+ $(settings.nTable).hasClass( 'dt-responsive' ) ||
+ settings.oInit.responsive ||
+ DataTable.defaults.responsive
+ ) {
+ var init = settings.oInit.responsive;
+
+ if ( init !== false ) {
+ new Responsive( settings, $.isPlainObject( init ) ? init : {} );
+ }
+ }
+} );
+
+
+return Responsive;
+}));
+
+
+/*! Bootstrap 5 integration for DataTables' Responsive
+ * ©2021 SpryMedia Ltd - datatables.net/license
+ */
+
+(function( factory ){
+ if ( typeof define === 'function' && define.amd ) {
+ // AMD
+ define( ['jquery', 'datatables.net-bs5', 'datatables.net-responsive'], function ( $ ) {
+ return factory( $, window, document );
+ } );
+ }
+ else if ( typeof exports === 'object' ) {
+ // CommonJS
+ module.exports = function (root, $) {
+ if ( ! root ) {
+ root = window;
+ }
+
+ if ( ! $ || ! $.fn.dataTable ) {
+ $ = require('datatables.net-bs5')(root, $).$;
+ }
+
+ if ( ! $.fn.dataTable.Responsive ) {
+ require('datatables.net-responsive')(root, $);
+ }
+
+ return factory( $, root, root.document );
+ };
+ }
+ else {
+ // Browser
+ factory( jQuery, window, document );
+ }
+}(function( $, window, document, undefined ) {
+'use strict';
+var DataTable = $.fn.dataTable;
+
+
+var _display = DataTable.Responsive.display;
+var _original = _display.modal;
+var _modal = $(
+ ''
+);
+var modal;
+
+// Note this could be undefined at the time of initialisation - the
+// DataTable.Responsive.bootstrap function can be used to set a different
+// bootstrap object
+var _bs = window.bootstrap;
+
+DataTable.Responsive.bootstrap = function (bs) {
+ _bs = bs;
+}
+
+_display.modal = function ( options ) {
+ if (! modal) {
+ modal = new _bs.Modal(_modal[0]);
+ }
+
+ return function ( row, update, render ) {
+ if ( ! $.fn.modal ) {
+ _original( row, update, render );
+ }
+ else {
+ if ( ! update ) {
+ if ( options && options.header ) {
+ var header = _modal.find('div.modal-header');
+ var button = header.find('button.btn-close').detach(); // CKAN mod - only remove the close button (leave the ones generated by CKAN)
+
+ header
+ .empty()
+ .append( ''+options.header( row )+' ' )
+ .append( button );
+ }
+
+ _modal.find( 'div.modal-body' )
+ .empty()
+ .append( render() );
+
+ _modal
+ .appendTo( 'body' )
+ .modal();
+
+ modal.show();
+ }
+ }
+ };
+};
+
+
+return DataTable.Responsive;
+}));
+
+
+/*! Select for DataTables 1.4.0
+ * 2015-2021 SpryMedia Ltd - datatables.net/license/mit
+ */
+
+/**
+ * @summary Select for DataTables
+ * @description A collection of API methods, events and buttons for DataTables
+ * that provides selection options of the items in a DataTable
+ * @version 1.4.0
+ * @file dataTables.select.js
+ * @author SpryMedia Ltd (www.sprymedia.co.uk)
+ * @contact datatables.net/forums
+ * @copyright Copyright 2015-2021 SpryMedia Ltd.
+ *
+ * This source file is free software, available under the following license:
+ * MIT license - http://datatables.net/license/mit
+ *
+ * This source file is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details.
+ *
+ * For details please refer to: http://www.datatables.net/extensions/select
+ */
+(function( factory ){
+ if ( typeof define === 'function' && define.amd ) {
+ // AMD
+ define( ['jquery', 'datatables.net'], function ( $ ) {
+ return factory( $, window, document );
+ } );
+ }
+ else if ( typeof exports === 'object' ) {
+ // CommonJS
+ module.exports = function (root, $) {
+ if ( ! root ) {
+ root = window;
+ }
+
+ if ( ! $ || ! $.fn.dataTable ) {
+ $ = require('datatables.net')(root, $).$;
+ }
+
+ return factory( $, root, root.document );
+ };
+ }
+ else {
+ // Browser
+ factory( jQuery, window, document );
+ }
+}(function( $, window, document, undefined ) {
+'use strict';
+var DataTable = $.fn.dataTable;
+
+
+// Version information for debugger
+DataTable.select = {};
+
+DataTable.select.version = '1.4.0';
+
+DataTable.select.init = function ( dt ) {
+ var ctx = dt.settings()[0];
+
+ if (ctx._select) {
+ return;
+ }
+
+ var savedSelected = dt.state.loaded();
+
+ var selectAndSave = function(e, settings, data) {
+ if(data === null || data.select === undefined) {
+ return;
+ }
+
+ // Clear any currently selected rows, before restoring state
+ // None will be selected on first initialisation
+ if (dt.rows({selected: true}).any()) {
+ dt.rows().deselect();
+ }
+ if (data.select.rows !== undefined) {
+ dt.rows(data.select.rows).select();
+ }
+
+ if (dt.columns({selected: true}).any()) {
+ dt.columns().deselect();
+ }
+ if (data.select.columns !== undefined) {
+ dt.columns(data.select.columns).select();
+ }
+
+ if (dt.cells({selected: true}).any()) {
+ dt.cells().deselect();
+ }
+ if (data.select.cells !== undefined) {
+ for(var i = 0; i < data.select.cells.length; i++) {
+ dt.cell(data.select.cells[i].row, data.select.cells[i].column).select();
+ }
+ }
+ dt.state.save();
+ }
+
+ dt.one('init', function() {
+ dt.on('stateSaveParams', function(e, settings, data) {
+ data.select = {};
+ data.select.rows = dt.rows({selected:true}).ids(true).toArray();
+ data.select.columns = dt.columns({selected:true})[0];
+ data.select.cells = dt.cells({selected:true})[0].map(function(coords) {
+ return {row: dt.row(coords.row).id(true), column: coords.column}
+ });
+ })
+
+ selectAndSave(undefined, undefined, savedSelected)
+ dt.on('stateLoaded stateLoadParams', selectAndSave)
+ })
+
+ var init = ctx.oInit.select;
+ var defaults = DataTable.defaults.select;
+ var opts = init === undefined ?
+ defaults :
+ init;
+
+ // Set defaults
+ var items = 'row';
+ var style = 'api';
+ var blurable = false;
+ var toggleable = true;
+ var info = true;
+ var selector = 'td, th';
+ var className = 'selected';
+ var setStyle = false;
+
+ ctx._select = {};
+
+ // Initialisation customisations
+ if ( opts === true ) {
+ style = 'os';
+ setStyle = true;
+ }
+ else if ( typeof opts === 'string' ) {
+ style = opts;
+ setStyle = true;
+ }
+ else if ( $.isPlainObject( opts ) ) {
+ if ( opts.blurable !== undefined ) {
+ blurable = opts.blurable;
+ }
+
+ if ( opts.toggleable !== undefined ) {
+ toggleable = opts.toggleable;
+ }
+
+ if ( opts.info !== undefined ) {
+ info = opts.info;
+ }
+
+ if ( opts.items !== undefined ) {
+ items = opts.items;
+ }
+
+ if ( opts.style !== undefined ) {
+ style = opts.style;
+ setStyle = true;
+ }
+ else {
+ style = 'os';
+ setStyle = true;
+ }
+
+ if ( opts.selector !== undefined ) {
+ selector = opts.selector;
+ }
+
+ if ( opts.className !== undefined ) {
+ className = opts.className;
+ }
+ }
+
+ dt.select.selector( selector );
+ dt.select.items( items );
+ dt.select.style( style );
+ dt.select.blurable( blurable );
+ dt.select.toggleable( toggleable );
+ dt.select.info( info );
+ ctx._select.className = className;
+
+
+ // Sort table based on selected rows. Requires Select Datatables extension
+ $.fn.dataTable.ext.order['select-checkbox'] = function ( settings, col ) {
+ return this.api().column( col, {order: 'index'} ).nodes().map( function ( td ) {
+ if ( settings._select.items === 'row' ) {
+ return $( td ).parent().hasClass( settings._select.className );
+ } else if ( settings._select.items === 'cell' ) {
+ return $( td ).hasClass( settings._select.className );
+ }
+ return false;
+ });
+ };
+
+ // If the init options haven't enabled select, but there is a selectable
+ // class name, then enable
+ if ( ! setStyle && $( dt.table().node() ).hasClass( 'selectable' ) ) {
+ dt.select.style( 'os' );
+ }
+};
+
+/*
+
+Select is a collection of API methods, event handlers, event emitters and
+buttons (for the `Buttons` extension) for DataTables. It provides the following
+features, with an overview of how they are implemented:
+
+## Selection of rows, columns and cells. Whether an item is selected or not is
+ stored in:
+
+* rows: a `_select_selected` property which contains a boolean value of the
+ DataTables' `aoData` object for each row
+* columns: a `_select_selected` property which contains a boolean value of the
+ DataTables' `aoColumns` object for each column
+* cells: a `_selected_cells` property which contains an array of boolean values
+ of the `aoData` object for each row. The array is the same length as the
+ columns array, with each element of it representing a cell.
+
+This method of using boolean flags allows Select to operate when nodes have not
+been created for rows / cells (DataTables' defer rendering feature).
+
+## API methods
+
+A range of API methods are available for triggering selection and de-selection
+of rows. Methods are also available to configure the selection events that can
+be triggered by an end user (such as which items are to be selected). To a large
+extent, these of API methods *is* Select. It is basically a collection of helper
+functions that can be used to select items in a DataTable.
+
+Configuration of select is held in the object `_select` which is attached to the
+DataTables settings object on initialisation. Select being available on a table
+is not optional when Select is loaded, but its default is for selection only to
+be available via the API - so the end user wouldn't be able to select rows
+without additional configuration.
+
+The `_select` object contains the following properties:
+
+```
+{
+ items:string - Can be `rows`, `columns` or `cells`. Defines what item
+ will be selected if the user is allowed to activate row
+ selection using the mouse.
+ style:string - Can be `none`, `single`, `multi` or `os`. Defines the
+ interaction style when selecting items
+ blurable:boolean - If row selection can be cleared by clicking outside of
+ the table
+ toggleable:boolean - If row selection can be cancelled by repeated clicking
+ on the row
+ info:boolean - If the selection summary should be shown in the table
+ information elements
+}
+```
+
+In addition to the API methods, Select also extends the DataTables selector
+options for rows, columns and cells adding a `selected` option to the selector
+options object, allowing the developer to select only selected items or
+unselected items.
+
+## Mouse selection of items
+
+Clicking on items can be used to select items. This is done by a simple event
+handler that will select the items using the API methods.
+
+ */
+
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Local functions
+ */
+
+/**
+ * Add one or more cells to the selection when shift clicking in OS selection
+ * style cell selection.
+ *
+ * Cell range is more complicated than row and column as we want to select
+ * in the visible grid rather than by index in sequence. For example, if you
+ * click first in cell 1-1 and then shift click in 2-2 - cells 1-2 and 2-1
+ * should also be selected (and not 1-3, 1-4. etc)
+ *
+ * @param {DataTable.Api} dt DataTable
+ * @param {object} idx Cell index to select to
+ * @param {object} last Cell index to select from
+ * @private
+ */
+function cellRange( dt, idx, last )
+{
+ var indexes;
+ var columnIndexes;
+ var rowIndexes;
+ var selectColumns = function ( start, end ) {
+ if ( start > end ) {
+ var tmp = end;
+ end = start;
+ start = tmp;
+ }
+
+ var record = false;
+ return dt.columns( ':visible' ).indexes().filter( function (i) {
+ if ( i === start ) {
+ record = true;
+ }
+
+ if ( i === end ) { // not else if, as start might === end
+ record = false;
+ return true;
+ }
+
+ return record;
+ } );
+ };
+
+ var selectRows = function ( start, end ) {
+ var indexes = dt.rows( { search: 'applied' } ).indexes();
+
+ // Which comes first - might need to swap
+ if ( indexes.indexOf( start ) > indexes.indexOf( end ) ) {
+ var tmp = end;
+ end = start;
+ start = tmp;
+ }
+
+ var record = false;
+ return indexes.filter( function (i) {
+ if ( i === start ) {
+ record = true;
+ }
+
+ if ( i === end ) {
+ record = false;
+ return true;
+ }
+
+ return record;
+ } );
+ };
+
+ if ( ! dt.cells( { selected: true } ).any() && ! last ) {
+ // select from the top left cell to this one
+ columnIndexes = selectColumns( 0, idx.column );
+ rowIndexes = selectRows( 0 , idx.row );
+ }
+ else {
+ // Get column indexes between old and new
+ columnIndexes = selectColumns( last.column, idx.column );
+ rowIndexes = selectRows( last.row , idx.row );
+ }
+
+ indexes = dt.cells( rowIndexes, columnIndexes ).flatten();
+
+ if ( ! dt.cells( idx, { selected: true } ).any() ) {
+ // Select range
+ dt.cells( indexes ).select();
+ }
+ else {
+ // Deselect range
+ dt.cells( indexes ).deselect();
+ }
+}
+
+/**
+ * Disable mouse selection by removing the selectors
+ *
+ * @param {DataTable.Api} dt DataTable to remove events from
+ * @private
+ */
+function disableMouseSelection( dt )
+{
+ var ctx = dt.settings()[0];
+ var selector = ctx._select.selector;
+
+ $( dt.table().container() )
+ .off( 'mousedown.dtSelect', selector )
+ .off( 'mouseup.dtSelect', selector )
+ .off( 'click.dtSelect', selector );
+
+ $('body').off( 'click.dtSelect' + _safeId(dt.table().node()) );
+}
+
+/**
+ * Attach mouse listeners to the table to allow mouse selection of items
+ *
+ * @param {DataTable.Api} dt DataTable to remove events from
+ * @private
+ */
+function enableMouseSelection ( dt )
+{
+ var container = $( dt.table().container() );
+ var ctx = dt.settings()[0];
+ var selector = ctx._select.selector;
+ var matchSelection;
+
+ container
+ .on( 'mousedown.dtSelect', selector, function(e) {
+ // Disallow text selection for shift clicking on the table so multi
+ // element selection doesn't look terrible!
+ if ( e.shiftKey || e.metaKey || e.ctrlKey ) {
+ container
+ .css( '-moz-user-select', 'none' )
+ .one('selectstart.dtSelect', selector, function () {
+ return false;
+ } );
+ }
+
+ if ( window.getSelection ) {
+ matchSelection = window.getSelection();
+ }
+ } )
+ .on( 'mouseup.dtSelect', selector, function() {
+ // Allow text selection to occur again, Mozilla style (tested in FF
+ // 35.0.1 - still required)
+ container.css( '-moz-user-select', '' );
+ } )
+ .on( 'click.dtSelect', selector, function ( e ) {
+ var items = dt.select.items();
+ var idx;
+
+ // If text was selected (click and drag), then we shouldn't change
+ // the row's selected state
+ if ( matchSelection ) {
+ var selection = window.getSelection();
+
+ // If the element that contains the selection is not in the table, we can ignore it
+ // This can happen if the developer selects text from the click event
+ if ( ! selection.anchorNode || $(selection.anchorNode).closest('table')[0] === dt.table().node() ) {
+ if ( selection !== matchSelection ) {
+ return;
+ }
+ }
+ }
+
+ var ctx = dt.settings()[0];
+ var wrapperClass = dt.settings()[0].oClasses.sWrapper.trim().replace(/ +/g, '.');
+
+ // Ignore clicks inside a sub-table
+ if ( $(e.target).closest('div.'+wrapperClass)[0] != dt.table().container() ) {
+ return;
+ }
+
+ var cell = dt.cell( $(e.target).closest('td, th') );
+
+ // Check the cell actually belongs to the host DataTable (so child
+ // rows, etc, are ignored)
+ if ( ! cell.any() ) {
+ return;
+ }
+
+ var event = $.Event('user-select.dt');
+ eventTrigger( dt, event, [ items, cell, e ] );
+
+ if ( event.isDefaultPrevented() ) {
+ return;
+ }
+
+ var cellIndex = cell.index();
+ if ( items === 'row' ) {
+ idx = cellIndex.row;
+ typeSelect( e, dt, ctx, 'row', idx );
+ }
+ else if ( items === 'column' ) {
+ idx = cell.index().column;
+ typeSelect( e, dt, ctx, 'column', idx );
+ }
+ else if ( items === 'cell' ) {
+ idx = cell.index();
+ typeSelect( e, dt, ctx, 'cell', idx );
+ }
+
+ ctx._select_lastCell = cellIndex;
+ } );
+
+ // Blurable
+ $('body').on( 'click.dtSelect' + _safeId(dt.table().node()), function ( e ) {
+ if ( ctx._select.blurable ) {
+ // If the click was inside the DataTables container, don't blur
+ if ( $(e.target).parents().filter( dt.table().container() ).length ) {
+ return;
+ }
+
+ // Ignore elements which have been removed from the DOM (i.e. paging
+ // buttons)
+ if ( $(e.target).parents('html').length === 0 ) {
+ return;
+ }
+
+ // Don't blur in Editor form
+ if ( $(e.target).parents('div.DTE').length ) {
+ return;
+ }
+
+ var event = $.Event('select-blur.dt');
+ eventTrigger( dt, event, [ e.target, e ] );
+
+ if ( event.isDefaultPrevented() ) {
+ return;
+ }
+
+ clear( ctx, true );
+ }
+ } );
+}
+
+/**
+ * Trigger an event on a DataTable
+ *
+ * @param {DataTable.Api} api DataTable to trigger events on
+ * @param {boolean} selected true if selected, false if deselected
+ * @param {string} type Item type acting on
+ * @param {boolean} any Require that there are values before
+ * triggering
+ * @private
+ */
+function eventTrigger ( api, type, args, any )
+{
+ if ( any && ! api.flatten().length ) {
+ return;
+ }
+
+ if ( typeof type === 'string' ) {
+ type = type +'.dt';
+ }
+
+ args.unshift( api );
+
+ $(api.table().node()).trigger( type, args );
+}
+
+/**
+ * Update the information element of the DataTable showing information about the
+ * items selected. This is done by adding tags to the existing text
+ *
+ * @param {DataTable.Api} api DataTable to update
+ * @private
+ */
+function info ( api )
+{
+ var ctx = api.settings()[0];
+
+ if ( ! ctx._select.info || ! ctx.aanFeatures.i ) {
+ return;
+ }
+
+ if ( api.select.style() === 'api' ) {
+ return;
+ }
+
+ var rows = api.rows( { selected: true } ).flatten().length;
+ var columns = api.columns( { selected: true } ).flatten().length;
+ var cells = api.cells( { selected: true } ).flatten().length;
+
+ var add = function ( el, name, num ) {
+ el.append( $(' ').append( api.i18n(
+ 'select.'+name+'s',
+ { _: '%d '+name+'s selected', 0: '', 1: '1 '+name+' selected' },
+ num
+ ) ) );
+ };
+
+ // Internal knowledge of DataTables to loop over all information elements
+ $.each( ctx.aanFeatures.i, function ( i, el ) {
+ el = $(el);
+
+ var output = $(' ');
+ add( output, 'row', rows );
+ add( output, 'column', columns );
+ add( output, 'cell', cells );
+
+ var exisiting = el.children('span.select-info');
+ if ( exisiting.length ) {
+ exisiting.remove();
+ }
+
+ if ( output.text() !== '' ) {
+ el.append( output );
+ }
+ } );
+}
+
+/**
+ * Initialisation of a new table. Attach event handlers and callbacks to allow
+ * Select to operate correctly.
+ *
+ * This will occur _after_ the initial DataTables initialisation, although
+ * before Ajax data is rendered, if there is ajax data
+ *
+ * @param {DataTable.settings} ctx Settings object to operate on
+ * @private
+ */
+function init ( ctx ) {
+ var api = new DataTable.Api( ctx );
+ ctx._select_init = true;
+
+ // Row callback so that classes can be added to rows and cells if the item
+ // was selected before the element was created. This will happen with the
+ // `deferRender` option enabled.
+ //
+ // This method of attaching to `aoRowCreatedCallback` is a hack until
+ // DataTables has proper events for row manipulation If you are reviewing
+ // this code to create your own plug-ins, please do not do this!
+ ctx.aoRowCreatedCallback.push( {
+ fn: function ( row, data, index ) {
+ var i, ien;
+ var d = ctx.aoData[ index ];
+
+ // Row
+ if ( d._select_selected ) {
+ $( row ).addClass( ctx._select.className );
+ }
+
+ // Cells and columns - if separated out, we would need to do two
+ // loops, so it makes sense to combine them into a single one
+ for ( i=0, ien=ctx.aoColumns.length ; i idx2 ) {
+ var tmp = idx2;
+ idx2 = idx1;
+ idx1 = tmp;
+ }
+
+ indexes.splice( idx2+1, indexes.length );
+ indexes.splice( 0, idx1 );
+ }
+
+ if ( ! dt[type]( idx, { selected: true } ).any() ) {
+ // Select range
+ dt[type+'s']( indexes ).select();
+ }
+ else {
+ // Deselect range - need to keep the clicked on row selected
+ indexes.splice( $.inArray( idx, indexes ), 1 );
+ dt[type+'s']( indexes ).deselect();
+ }
+}
+
+/**
+ * Clear all selected items
+ *
+ * @param {DataTable.settings} ctx Settings object of the host DataTable
+ * @param {boolean} [force=false] Force the de-selection to happen, regardless
+ * of selection style
+ * @private
+ */
+function clear( ctx, force )
+{
+ if ( force || ctx._select.style === 'single' ) {
+ var api = new DataTable.Api( ctx );
+
+ api.rows( { selected: true } ).deselect();
+ api.columns( { selected: true } ).deselect();
+ api.cells( { selected: true } ).deselect();
+ }
+}
+
+/**
+ * Select items based on the current configuration for style and items.
+ *
+ * @param {object} e Mouse event object
+ * @param {DataTables.Api} dt DataTable
+ * @param {DataTable.settings} ctx Settings object of the host DataTable
+ * @param {string} type Items to select
+ * @param {int|object} idx Index of the item to select
+ * @private
+ */
+function typeSelect ( e, dt, ctx, type, idx )
+{
+ var style = dt.select.style();
+ var toggleable = dt.select.toggleable();
+ var isSelected = dt[type]( idx, { selected: true } ).any();
+
+ if ( isSelected && ! toggleable ) {
+ return;
+ }
+
+ if ( style === 'os' ) {
+ if ( e.ctrlKey || e.metaKey ) {
+ // Add or remove from the selection
+ dt[type]( idx ).select( ! isSelected );
+ }
+ else if ( e.shiftKey ) {
+ if ( type === 'cell' ) {
+ cellRange( dt, idx, ctx._select_lastCell || null );
+ }
+ else {
+ rowColumnRange( dt, type, idx, ctx._select_lastCell ?
+ ctx._select_lastCell[type] :
+ null
+ );
+ }
+ }
+ else {
+ // No cmd or shift click - deselect if selected, or select
+ // this row only
+ var selected = dt[type+'s']( { selected: true } );
+
+ if ( isSelected && selected.flatten().length === 1 ) {
+ dt[type]( idx ).deselect();
+ }
+ else {
+ selected.deselect();
+ dt[type]( idx ).select();
+ }
+ }
+ } else if ( style == 'multi+shift' ) {
+ if ( e.shiftKey ) {
+ if ( type === 'cell' ) {
+ cellRange( dt, idx, ctx._select_lastCell || null );
+ }
+ else {
+ rowColumnRange( dt, type, idx, ctx._select_lastCell ?
+ ctx._select_lastCell[type] :
+ null
+ );
+ }
+ }
+ else {
+ dt[ type ]( idx ).select( ! isSelected );
+ }
+ }
+ else {
+ dt[ type ]( idx ).select( ! isSelected );
+ }
+}
+
+function _safeId( node ) {
+ return node.id.replace(/[^a-zA-Z0-9\-\_]/g, '-');
+}
+
+
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * DataTables selectors
+ */
+
+// row and column are basically identical just assigned to different properties
+// and checking a different array, so we can dynamically create the functions to
+// reduce the code size
+$.each( [
+ { type: 'row', prop: 'aoData' },
+ { type: 'column', prop: 'aoColumns' }
+], function ( i, o ) {
+ DataTable.ext.selector[ o.type ].push( function ( settings, opts, indexes ) {
+ var selected = opts.selected;
+ var data;
+ var out = [];
+
+ if ( selected !== true && selected !== false ) {
+ return indexes;
+ }
+
+ for ( var i=0, ien=indexes.length ; i 0 );
+ } );
+
+ this.disable();
+ },
+ destroy: function ( dt, node, config ) {
+ dt.off( config._eventNamespace );
+ }
+ }
+} );
+
+$.each( [ 'Row', 'Column', 'Cell' ], function ( i, item ) {
+ var lc = item.toLowerCase();
+
+ DataTable.ext.buttons[ 'select'+item+'s' ] = {
+ text: i18n( 'select'+item+'s', 'Select '+lc+'s' ),
+ className: 'buttons-select-'+lc+'s',
+ action: function () {
+ this.select.items( lc );
+ },
+ init: function ( dt ) {
+ var that = this;
+
+ dt.on( 'selectItems.dt.DT', function ( e, ctx, items ) {
+ that.active( items === lc );
+ } );
+ }
+ };
+} );
+
+
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Initialisation
+ */
+
+// DataTables creation - check if select has been defined in the options. Note
+// this required that the table be in the document! If it isn't then something
+// needs to trigger this method unfortunately. The next major release of
+// DataTables will rework the events and address this.
+$(document).on( 'preInit.dt.dtSelect', function (e, ctx) {
+ if ( e.namespace !== 'dt' ) {
+ return;
+ }
+
+ DataTable.select.init( new DataTable.Api( ctx ) );
+} );
+
+
+return DataTable.select;
+}));
+
+
diff --git a/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/datatables.mark.css b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/datatables.mark.css
new file mode 100644
index 0000000..aa5eaaa
--- /dev/null
+++ b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/datatables.mark.css
@@ -0,0 +1,4 @@
+mark {
+ background: orange;
+ color: black;
+}
diff --git a/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/datatables.mark.js b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/datatables.mark.js
new file mode 100644
index 0000000..34688f8
--- /dev/null
+++ b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/datatables.mark.js
@@ -0,0 +1,119 @@
+/*!***************************************************
+ * datatables.mark.js v2.1.0
+ * https://github.com/julmot/datatables.mark.js
+ * Copyright (c) 2016–2020, Julian Kühnel
+ * Released under the MIT license https://git.io/voRZ7
+ *****************************************************/
+
+'use strict';
+
+var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
+
+var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+(function (factory, window, document) {
+ if ((typeof exports === 'undefined' ? 'undefined' : _typeof(exports)) === 'object') {
+ var jquery = require('jquery');
+ require('datatables.net');
+ require('mark.js/dist/jquery.mark.js');
+ module.exports = factory(window, document, jquery);
+ } else if (typeof define === 'function' && define.amd) {
+ define(['jquery', 'datatables.net', 'markjs'], function (jQuery) {
+ return factory(window, document, jQuery);
+ });
+ } else {
+ factory(window, document, jQuery);
+ }
+})(function (window, document, $) {
+ var MarkDataTables = function () {
+ function MarkDataTables(dtInstance, options) {
+ _classCallCheck(this, MarkDataTables);
+
+ if (!$.fn.mark || !$.fn.unmark) {
+ throw new Error('jquery.mark.js is necessary for datatables.mark.js');
+ }
+ this.instance = dtInstance;
+ this.options = (typeof options === 'undefined' ? 'undefined' : _typeof(options)) === 'object' ? options : {};
+ this.intervalThreshold = 49;
+ this.intervalMs = 300;
+ this.initMarkListener();
+ }
+
+ _createClass(MarkDataTables, [{
+ key: 'initMarkListener',
+ value: function initMarkListener() {
+ var _this = this;
+
+ var ev = 'draw.dt.dth column-visibility.dt.dth column-reorder.dt.dth';
+ ev += ' responsive-display.dt.dth';
+ var intvl = null;
+ this.instance.on(ev, function () {
+ var rows = _this.instance.rows({
+ filter: 'applied',
+ page: 'current'
+ }).nodes().length;
+ if (rows > _this.intervalThreshold) {
+ clearTimeout(intvl);
+ intvl = setTimeout(function () {
+ _this.mark();
+ }, _this.intervalMs);
+ } else {
+ _this.mark();
+ }
+ });
+ this.instance.on('destroy', function () {
+ _this.instance.off(ev);
+ });
+ this.mark();
+ }
+ }, {
+ key: 'mark',
+ value: function mark() {
+ var _this2 = this;
+
+ var globalSearch = this.instance.search();
+ var $tableBody = $(this.instance.table().body());
+ $tableBody.unmark(this.options);
+ if (this.instance.table().rows({ search: 'applied' }).data().length) {
+ $tableBody.mark(globalSearch, this.options);
+ }
+ this.instance.columns({
+ search: 'applied',
+ page: 'current'
+ }).nodes().each(function (nodes, colIndex) {
+ var columnSearch = _this2.instance.column(colIndex).search(),
+ searchVal = columnSearch || globalSearch;
+ if (searchVal) {
+ nodes.forEach(function (node) {
+ $(node).unmark(_this2.options).mark(searchVal, _this2.options);
+ });
+ }
+ });
+ }
+ }]);
+
+ return MarkDataTables;
+ }();
+
+ $(document).on('init.dt.dth', function (event, settings) {
+ if (event.namespace !== 'dt') {
+ return;
+ }
+
+ var dtInstance = $.fn.dataTable.Api(settings);
+
+ var options = null;
+ if (dtInstance.init().mark) {
+ options = dtInstance.init().mark;
+ } else if ($.fn.dataTable.defaults.mark) {
+ options = $.fn.dataTable.defaults.mark;
+ }
+ if (options === null) {
+ return;
+ }
+
+ new MarkDataTables(dtInstance, options);
+ });
+}, window, document);
diff --git a/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/datetime.js b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/datetime.js
new file mode 100644
index 0000000..08f9b6a
--- /dev/null
+++ b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/datetime.js
@@ -0,0 +1,126 @@
+/**
+ * Date / time formats often from back from server APIs in a format that you
+ * don't wish to display to your end users (ISO8601 for example). This rendering
+ * helper can be used to transform any source date / time format into something
+ * which can be easily understood by your users when reading the table, and also
+ * by DataTables for sorting the table.
+ *
+ * The [MomentJS library](http://momentjs.com/) is used to accomplish this and
+ * you simply need to tell it which format to transfer from, to and specify a
+ * locale if required.
+ *
+ * This function should be used with the `dt-init columns.render` configuration
+ * option of DataTables.
+ *
+ * It accepts one, two or three parameters:
+ *
+ * * `$.fn.dataTable.render.moment( to );`
+ * * `$.fn.dataTable.render.moment( from, to );`
+ * * `$.fn.dataTable.render.moment( from, to, locale );`
+ *
+ * Where:
+ *
+ * * `to` - the format that will be displayed to the end user
+ * * `from` - the format that is supplied in the data (the default is ISO8601 -
+ * `YYYY-MM-DD`)
+ * * `locale` - the locale which MomentJS should use - the default is `en`
+ * (English).
+ *
+ * @name datetime
+ * @summary Convert date / time source data into one suitable for display
+ * @author [Allan Jardine](http://datatables.net)
+ * @requires DataTables 1.10+, Moment.js 1.7+
+ *
+ * @example
+ * // Convert ISO8601 dates into a simple human readable format
+ * $('#example').DataTable( {
+ * columnDefs: [ {
+ * targets: 1,
+ * render: $.fn.dataTable.render.moment( 'Do MMM YYYY' )
+ * } ]
+ * } );
+ *
+ * @example
+ * // Specify a source format - in this case a unix timestamp
+ * $('#example').DataTable( {
+ * columnDefs: [ {
+ * targets: 2,
+ * render: $.fn.dataTable.render.moment( 'X', 'Do MMM YY' )
+ * } ]
+ * } );
+ *
+ * @example
+ * // Specify a source format and locale
+ * $('#example').DataTable( {
+ * columnDefs: [ {
+ * targets: 2,
+ * render: $.fn.dataTable.render.moment( 'YYYY/MM/DD', 'Do MMM YY', 'fr' )
+ * } ]
+ * } );
+ */
+
+
+// UMD
+(function( factory ) {
+ "use strict";
+
+ if ( typeof define === 'function' && define.amd ) {
+ // AMD
+ define( ['jquery'], function ( $ ) {
+ return factory( $, window, document );
+ } );
+ }
+ else if ( typeof exports === 'object' ) {
+ // CommonJS
+ module.exports = function (root, $) {
+ if ( ! root ) {
+ root = window;
+ }
+
+ if ( ! $ ) {
+ $ = typeof window !== 'undefined' ?
+ require('jquery') :
+ require('jquery')( root );
+ }
+
+ return factory( $, root, root.document );
+ };
+ }
+ else {
+ // Browser
+ factory( jQuery, window, document );
+ }
+}
+(function( $, window, document ) {
+
+
+$.fn.dataTable.render.moment = function ( from, to, locale ) {
+ // Argument shifting
+ if ( arguments.length === 1 ) {
+ locale = 'en';
+ to = from;
+ from = 'YYYY-MM-DD';
+ }
+ else if ( arguments.length === 2 ) {
+ locale = 'en';
+ }
+
+ return function ( d, type, row ) {
+ if (! d) {
+ return type === 'sort' || type === 'type' ? 0 : d;
+ }
+
+ var m = window.moment( d, from, locale, true );
+
+ // Order and type get a number value from Moment, everything else
+ // sees the rendered value
+ if (m.isValid()) {
+ return m.format( type === 'sort' || type === 'type' ? 'x' : to );
+ } else {
+ return type === 'sort' || type === 'type' ? 0 : d;
+ }
+ };
+};
+
+
+}));
diff --git a/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/af.json b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/af.json
new file mode 100644
index 0000000..1214039
--- /dev/null
+++ b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/af.json
@@ -0,0 +1,22 @@
+{
+ "emptyTable": "Geen data beskikbaar in tabel",
+ "info": "uitstalling _START_ to _END_ of _TOTAL_ inskrywings",
+ "infoEmpty": "uitstalling 0 to 0 of 0 inskrywings",
+ "infoFiltered": "(gefiltreer uit _MAX_ totaal inskrywings)",
+ "infoThousands": ",",
+ "lengthMenu": "uitstal _MENU_ inskrywings",
+ "loadingRecords": "laai...",
+ "processing": "verwerking...",
+ "search": "soektog:",
+ "zeroRecords": "Geen treffers gevind",
+ "paginate": {
+ "first": "eerste",
+ "last": "laaste",
+ "next": "volgende",
+ "previous": "vorige"
+ },
+ "aria": {
+ "sortAscending": ": aktiveer kolom stygende te sorteer",
+ "sortDescending": ": aktiveer kolom orde te sorteer"
+ }
+}
\ No newline at end of file
diff --git a/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/am.json b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/am.json
new file mode 100644
index 0000000..83e61a4
--- /dev/null
+++ b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/am.json
@@ -0,0 +1,22 @@
+{
+ "emptyTable": "ባዶ ሰንጠረዥ",
+ "info": "ከጠቅላላው _TOTAL_ ዝርዝሮች ውስጥ ከ _START_ እስከ _END_ ያሉት ዝርዝር",
+ "infoEmpty": "ከጠቅላላው 0 ዝርዝሮች ውስጥ ከ 0 እስከ 0 ያሉት ዝርዝር",
+ "infoFiltered": "(ከጠቅላላው _MAX_ የተመረጡ ዝርዝሮች)",
+ "infoThousands": ",",
+ "lengthMenu": "የዝርዝሮች ብዛት _MENU_",
+ "loadingRecords": "በማቅረብ ላይ...",
+ "processing": "በማቀናበር ላይ...",
+ "search": "ፈልግ:",
+ "zeroRecords": "ከሚፈለገው ጋር የሚሚሳሰል ዝርዝር አልተገኘም",
+ "paginate": {
+ "first": "መጀመሪያ",
+ "last": "መጨረሻ",
+ "next": "ቀጣዩ",
+ "previous": "የበፊቱ"
+ },
+ "aria": {
+ "sortAscending": ": ከመጀመሪያ ወደ መጨረሻ(ወጪ) አደራደር",
+ "sortDescending": ": ከመጨረሻ ወደ መጀመሪያ(ወራጅ) አደራደር"
+ }
+}
\ No newline at end of file
diff --git a/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/ar.json b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/ar.json
new file mode 100644
index 0000000..be1488d
--- /dev/null
+++ b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/ar.json
@@ -0,0 +1,43 @@
+{
+ "emptyTable": "ليست هناك بيانات متاحة في الجدول",
+ "loadingRecords": "جارٍ التحميل...",
+ "processing": "جارٍ التحميل...",
+ "lengthMenu": "أظهر _MENU_ مدخلات",
+ "zeroRecords": "لم يعثر على أية سجلات",
+ "info": "إظهار _START_ إلى _END_ من أصل _TOTAL_ مدخل",
+ "infoEmpty": "يعرض 0 إلى 0 من أصل 0 سجل",
+ "infoFiltered": "(منتقاة من مجموع _MAX_ مُدخل)",
+ "search": "ابحث:",
+ "paginate": {
+ "first": "الأول",
+ "previous": "السابق",
+ "next": "التالي",
+ "last": "الأخير"
+ },
+ "aria": {
+ "sortAscending": ": تفعيل لترتيب العمود تصاعدياً",
+ "sortDescending": ": تفعيل لترتيب العمود تنازلياً"
+ },
+ "select": {
+ "rows": {
+ "_": "%d قيمة محددة",
+ "0": "",
+ "1": "1 قيمة محددة"
+ }
+ },
+ "buttons": {
+ "print": "طباعة",
+ "colvis": "الأعمدة الظاهرة",
+ "copy": "نسخ إلى الحافظة",
+ "copyTitle": "نسخ",
+ "copyKeys": "زر ctrl<\/i> أو ⌘<\/i> + C<\/i> من الجدول ليتم نسخها إلى الحافظة للإلغاء اضغط على الرسالة أو اضغط على زر الخروج.",
+ "copySuccess": {
+ "_": "%d قيمة نسخت",
+ "1": "1 قيمة نسخت"
+ },
+ "pageLength": {
+ "-1": "اظهار الكل",
+ "_": "إظهار %d أسطر"
+ }
+ }
+}
\ No newline at end of file
diff --git a/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/az.json b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/az.json
new file mode 100644
index 0000000..881ed40
--- /dev/null
+++ b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/az.json
@@ -0,0 +1,22 @@
+{
+ "emptyTable": "Cədvəldə heç bir məlumat yoxdur",
+ "info": " _TOTAL_ Nəticədən _START_ - _END_ Arası Nəticələr",
+ "infoEmpty": "Nəticə Yoxdur",
+ "infoFiltered": "( _MAX_ Nəticə İçindən Tapılanlar)",
+ "infoThousands": ",",
+ "lengthMenu": "Səhifədə _MENU_ Nəticə Göstər",
+ "loadingRecords": "Yüklənir...",
+ "processing": "Gözləyin...",
+ "search": "Axtarış:",
+ "zeroRecords": "Nəticə Tapılmadı.",
+ "paginate": {
+ "first": "İlk",
+ "last": "Axırıncı",
+ "next": "Sonraki",
+ "previous": "Öncəki"
+ },
+ "aria": {
+ "sortAscending": ": sütunu artma sırası üzərə aktiv etmək",
+ "sortDescending": ": sütunu azalma sırası üzərə aktiv etmək"
+ }
+}
\ No newline at end of file
diff --git a/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/az_az.json b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/az_az.json
new file mode 100644
index 0000000..881ed40
--- /dev/null
+++ b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/az_az.json
@@ -0,0 +1,22 @@
+{
+ "emptyTable": "Cədvəldə heç bir məlumat yoxdur",
+ "info": " _TOTAL_ Nəticədən _START_ - _END_ Arası Nəticələr",
+ "infoEmpty": "Nəticə Yoxdur",
+ "infoFiltered": "( _MAX_ Nəticə İçindən Tapılanlar)",
+ "infoThousands": ",",
+ "lengthMenu": "Səhifədə _MENU_ Nəticə Göstər",
+ "loadingRecords": "Yüklənir...",
+ "processing": "Gözləyin...",
+ "search": "Axtarış:",
+ "zeroRecords": "Nəticə Tapılmadı.",
+ "paginate": {
+ "first": "İlk",
+ "last": "Axırıncı",
+ "next": "Sonraki",
+ "previous": "Öncəki"
+ },
+ "aria": {
+ "sortAscending": ": sütunu artma sırası üzərə aktiv etmək",
+ "sortDescending": ": sütunu azalma sırası üzərə aktiv etmək"
+ }
+}
\ No newline at end of file
diff --git a/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/be.json b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/be.json
new file mode 100644
index 0000000..06e2799
--- /dev/null
+++ b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/be.json
@@ -0,0 +1,19 @@
+{
+ "processing": "Пачакайце...",
+ "lengthMenu": "Паказваць _MENU_ запісаў",
+ "zeroRecords": "Запісы адсутнічаюць.",
+ "info": "Запісы з _START_ па _END_ з _TOTAL_ запісаў",
+ "infoEmpty": "Запісы з 0 па 0 з 0 запісаў",
+ "infoFiltered": "(адфільтравана з _MAX_ запісаў)",
+ "search": "Пошук:",
+ "paginate": {
+ "first": "Першая",
+ "previous": "Папярэдняя",
+ "next": "Наступная",
+ "last": "Апошняя"
+ },
+ "aria": {
+ "sortAscending": ": актываваць для сартавання слупка па ўзрастанні",
+ "sortDescending": ": актываваць для сартавання слупка па змяншэнні"
+ }
+}
\ No newline at end of file
diff --git a/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/bg.json b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/bg.json
new file mode 100644
index 0000000..5e247be
--- /dev/null
+++ b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/bg.json
@@ -0,0 +1,15 @@
+{
+ "processing": "Обработка на резултатите...",
+ "lengthMenu": "Показване на _MENU_ резултата",
+ "zeroRecords": "Няма намерени резултати",
+ "info": "Показване на резултати от _START_ до _END_ от общо _TOTAL_",
+ "infoEmpty": "Показване на резултати от 0 до 0 от общо 0",
+ "infoFiltered": "(филтрирани от общо _MAX_ резултата)",
+ "search": "Търсене:",
+ "paginate": {
+ "first": "Първа",
+ "previous": "Предишна",
+ "next": "Следваща",
+ "last": "Последна"
+ }
+}
\ No newline at end of file
diff --git a/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/bn.json b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/bn.json
new file mode 100644
index 0000000..5700e53
--- /dev/null
+++ b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/bn.json
@@ -0,0 +1,15 @@
+{
+ "processing": "প্রসেসিং হচ্ছে...",
+ "lengthMenu": "_MENU_ টা এন্ট্রি দেখাও",
+ "zeroRecords": "আপনি যা অনুসন্ধান করেছেন তার সাথে মিলে যাওয়া কোন রেকর্ড খুঁজে পাওয়া যায় নাই",
+ "info": "_TOTAL_ টা এন্ট্রির মধ্যে _START_ থেকে _END_ পর্যন্ত দেখানো হচ্ছে",
+ "infoEmpty": "কোন এন্ট্রি খুঁজে পাওয়া যায় নাই",
+ "infoFiltered": "(মোট _MAX_ টা এন্ট্রির মধ্যে থেকে বাছাইকৃত)",
+ "search": "অনুসন্ধান:",
+ "paginate": {
+ "first": "প্রথমটা",
+ "previous": "আগেরটা",
+ "next": "পরবর্তীটা",
+ "last": "শেষেরটা"
+ }
+}
\ No newline at end of file
diff --git a/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/bs.json b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/bs.json
new file mode 100644
index 0000000..e2b1bf4
--- /dev/null
+++ b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/bs.json
@@ -0,0 +1,76 @@
+{
+ "aria": {
+ "sortAscending": ": aktivirajte da sortirate kolonu uzlazno",
+ "sortDescending": ": aktivirajte da sortirate kolonu silazno"
+ },
+ "autoFill": {
+ "cancel": "Poništiti",
+ "fill": "Ispunite sve ćelije s % d <\/i>",
+ "fillHorizontal": "Ispunite ćelije vodoravno",
+ "fillVertical": "Ispunite ćelije vertikalno"
+ },
+ "buttons": {
+ "collection": "Collection <\/span>",
+ "colvis": "Vidljivost kolone",
+ "colvisRestore": "Vratite vidljivost",
+ "copy": "Kopiraj",
+ "copyKeys": "Pritisnite ctrl ili u2318 + C da biste kopirali podatke tabele u sistemski međuspremnik. Za otkazivanje kliknite ovu poruku ili pritisnite Escape.",
+ "copySuccess": {
+ "1": "Kopiran je 1 red u međuspremnik",
+ "_": "Kopirani su %d redova u međuspremnik"
+ },
+ "copyTitle": "Kopirajte u međuspremnik",
+ "csv": "CSV",
+ "excel": "Excel",
+ "pageLength": {
+ "-1": "Prikaži sve redove",
+ "1": "Prikaži 1 red",
+ "_": "Prikaži %d redova"
+ },
+ "pdf": "PDF",
+ "print": "Štampaj"
+ },
+ "emptyTable": "Nema podataka u tabeli",
+ "info": "Prikaz _START_ do _END_ od ukupno _TOTAL_ zapisa",
+ "infoEmpty": "Prikaz 0 do 0 od ukupno 0 zapisa",
+ "infoFiltered": "(filtrirano od ukupno _MAX_ zapisa)",
+ "infoThousands": ".",
+ "lengthMenu": "Prikaži _MENU_ zapisa",
+ "loadingRecords": "Učitavanje...",
+ "paginate": {
+ "first": "Početna",
+ "last": "Poslednja",
+ "next": "Sledeća",
+ "previous": "Prethodna"
+ },
+ "processing": "Obrada...",
+ "search": "Pretraga:",
+ "searchBuilder": {
+ "add": "Dodaj uslov",
+ "clearAll": "Obriši sve"
+ },
+ "searchPanes": {
+ "clearMessage": "Obriši sve",
+ "collapse": {
+ "0": "Paneli za Pretragu",
+ "_": "Paneli za Pretragu (%d)"
+ },
+ "count": "{total}",
+ "countFiltered": "{shown} ({total})",
+ "emptyPanes": "Nema panela za pretragu",
+ "loadMessage": "Učitavanje panela za pretragu",
+ "title": "Aktivni filteri - %d"
+ },
+ "select": {
+ "_": "Broj odabranih redova: %d ",
+ "cells": {
+ "1": "Odabran je 1 red",
+ "_": "Broj odabranih redova: %d"
+ },
+ "columns": {
+ "1": "Jedna colona odabrana",
+ "_": "Broj odabranih kolona: %d"
+ }
+ },
+ "zeroRecords": "Nisu pronađeni odgovarajući zapisi"
+}
\ No newline at end of file
diff --git a/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/ca.json b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/ca.json
new file mode 100644
index 0000000..388b171
--- /dev/null
+++ b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/ca.json
@@ -0,0 +1,44 @@
+{
+ "processing": "Processant...",
+ "lengthMenu": "Mostra _MENU_ registres",
+ "zeroRecords": "No s'han trobat registres",
+ "emptyTable": "No hi ha registres disponible en aquesta taula",
+ "info": "Mostrant del _START_ al _END_ d'un total de _TOTAL_ registres",
+ "infoEmpty": "No hi ha registres disponibles",
+ "infoFiltered": "(filtrat de _MAX_ registres)",
+ "search": "Cerca:",
+ "infoThousands": ".",
+ "decimal": ",",
+ "loadingRecords": "Carregant...",
+ "paginate": {
+ "first": "Primer",
+ "previous": "Anterior",
+ "next": "Següent",
+ "last": "Últim"
+ },
+ "aria": {
+ "sortAscending": ": Activa per ordenar la columna de manera ascendent",
+ "sortDescending": ": Activa per ordenar la columna de manera descendent"
+ },
+ "buttons": {
+ "print": "Imprimeix",
+ "copy": "Copia",
+ "colvis": "Columnes",
+ "copyTitle": "Copia al portapapers",
+ "copySuccess": {
+ "_": "%d files copiades",
+ "1": "1 fila copiada"
+ },
+ "pageLength": {
+ "-1": "Mostra totes les files",
+ "_": "Mostra %d files"
+ }
+ },
+ "select": {
+ "rows": {
+ "_": "%d files seleccionades",
+ "0": "Cap fila seleccionada",
+ "1": "1 fila seleccionada"
+ }
+ }
+}
\ No newline at end of file
diff --git a/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/cs.json b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/cs.json
new file mode 100644
index 0000000..9890f1c
--- /dev/null
+++ b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/cs.json
@@ -0,0 +1,22 @@
+{
+ "emptyTable": "Tabulka neobsahuje žádná data",
+ "info": "Zobrazuji _START_ až _END_ z celkem _TOTAL_ záznamů",
+ "infoEmpty": "Zobrazuji 0 až 0 z 0 záznamů",
+ "infoFiltered": "(filtrováno z celkem _MAX_ záznamů)",
+ "infoThousands": " ",
+ "lengthMenu": "Zobraz záznamů _MENU_",
+ "loadingRecords": "Načítám...",
+ "processing": "Provádím...",
+ "search": "Hledat:",
+ "zeroRecords": "Žádné záznamy nebyly nalezeny",
+ "paginate": {
+ "first": "První",
+ "last": "Poslední",
+ "next": "Další",
+ "previous": "Předchozí"
+ },
+ "aria": {
+ "sortAscending": ": aktivujte pro řazení sloupce vzestupně",
+ "sortDescending": ": aktivujte pro řazení sloupce sestupně"
+ }
+}
\ No newline at end of file
diff --git a/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/cs_CZ.json b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/cs_CZ.json
new file mode 100644
index 0000000..be2c04f
--- /dev/null
+++ b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/cs_CZ.json
@@ -0,0 +1,134 @@
+{
+ "emptyTable": "Tabulka neobsahuje žádná data",
+ "info": "Zobrazuji _START_ až _END_ z celkem _TOTAL_ záznamů",
+ "infoEmpty": "Zobrazuji 0 až 0 z 0 záznamů",
+ "infoFiltered": "(filtrováno z celkem _MAX_ záznamů)",
+ "infoThousands": " ",
+ "lengthMenu": "Zobraz záznamů _MENU_",
+ "loadingRecords": "Načítám...",
+ "processing": "Provádím...",
+ "search": "Hledat:",
+ "zeroRecords": "Žádné záznamy nebyly nalezeny",
+ "paginate": {
+ "first": "První",
+ "last": "Poslední",
+ "next": "Další",
+ "previous": "Předchozí"
+ },
+ "aria": {
+ "sortAscending": ": aktivujte pro řazení sloupce vzestupně",
+ "sortDescending": ": aktivujte pro řazení sloupce sestupně"
+ },
+ "buttons": {
+ "colvis": "Zobrazení sloupců",
+ "colvisRestore": "Původní nastavení",
+ "collection": "Kolekce <\/span>",
+ "copy": "Kopírovat",
+ "copyKeys": "Stlačte ctrl nebo u2318 + C pro kopírování dat tabulky do systémové schránky. Pro zrušení klepněte na tuhle správne nebo stiskněte ESC.",
+ "copySuccess": {
+ "1": "Skopírován 1 řádek do schránky",
+ "_": "SKopírováno %d řádků do schránky"
+ },
+ "copyTitle": "Kopírovat do schránky",
+ "csv": "CSV",
+ "excel": "Excel",
+ "pageLength": {
+ "-1": "Zobrazit všechny řádky",
+ "1": "Zobrazit 1 řádek",
+ "_": "Zobrazit %d řádků"
+ },
+ "pdf": "PDF",
+ "print": "Tisknout"
+ },
+ "searchBuilder": {
+ "add": "Přidat podmínku",
+ "clearAll": "Smazat vše",
+ "condition": "Podmínka",
+ "conditions": {
+ "date": {
+ "after": "po",
+ "before": "před",
+ "between": "mezi",
+ "empty": "prázdné",
+ "equals": "rovno",
+ "not": "není",
+ "notBetween": "není mezi",
+ "notEmpty": "není prázdné"
+ },
+ "number": {
+ "between": "mezi",
+ "empty": "prázdné",
+ "equals": "rovno",
+ "gt": "větší",
+ "gte": "rovno a větší",
+ "lt": "menší",
+ "lte": "rovno a menší",
+ "not": "není",
+ "notBetween": "není mezi",
+ "notEmpty": "není prázdné"
+ },
+ "string": {
+ "contains": "obsahuje",
+ "empty": "prázdné",
+ "endsWith": "končí na",
+ "equals": "rovno",
+ "not": "není",
+ "notEmpty": "není prázdné",
+ "startsWith": "začíná na"
+ },
+ "array": {
+ "equals": "rovno",
+ "empty": "prázdné",
+ "contains": "obsahuje",
+ "not": "není",
+ "notEmpty": "není prázdné",
+ "without": "neobsahuje"
+ }
+ },
+ "data": "Sloupec",
+ "logicAnd": "A",
+ "logicOr": "NEBO",
+ "title": {
+ "0": "Rozšířený filtr",
+ "_": "Rozšířený filtr (%d)"
+ },
+ "value": "Hodnota",
+ "button": {
+ "0": "Rozšířený filtr",
+ "_": "Rozšířený filtr (%d)"
+ },
+ "deleteTitle": "Smazat filtrovací pravidlo"
+ },
+ "select": {
+ "1": "Vybrán %d záznam",
+ "2": "Vybrány %d záznamy",
+ "_": "Vybráno %d záznamů",
+ "cells": {
+ "1": "Vybrán 1 záznam",
+ "_": "Vybráno %d záznamů"
+ },
+ "columns": {
+ "1": "Vybrán 1 sloupec",
+ "_": "Vybráno %d sloupců"
+ }
+ },
+ "autoFill": {
+ "cancel": "Zrušit",
+ "fill": "Vyplnit všechny buňky s %d<\/i><\/i>",
+ "fillHorizontal": "Vyplnit buňky horizontálne",
+ "fillVertical": "Vyplnit buňky vertikálne"
+ },
+ "searchPanes": {
+ "clearMessage": "Smazat vše",
+ "collapse": {
+ "0": "Vyhledávací Panely",
+ "_": "Vyhledávací Panely (%d)"
+ },
+ "count": "{total}",
+ "countFiltered": "{shown} ({total})",
+ "emptyPanes": "Žádné Vyhledávací Panely",
+ "loadMessage": "Načítám Vyhledávací Panely",
+ "title": "Aktivních filtrů - %d"
+ },
+ "thousands": " "
+}
\ No newline at end of file
diff --git a/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/cy.json b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/cy.json
new file mode 100644
index 0000000..876755f
--- /dev/null
+++ b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/cy.json
@@ -0,0 +1,22 @@
+{
+ "emptyTable": "Dim data ar gael yn y tabl",
+ "info": "Dangos _START_ i _END_ o _TOTAL_ cofnod",
+ "infoEmpty": "Dangos 0 i 0 o 0 cofnod",
+ "infoFiltered": "(wedi hidlo o gyfanswm o _MAX_ cofnod)",
+ "infoThousands": ",",
+ "lengthMenu": "Dangos _MENU_ cofnod",
+ "loadingRecords": "Wrthi'n llwytho...",
+ "processing": "Wrthi'n prosesu...",
+ "search": "Chwilio:",
+ "zeroRecords": "Heb ddod o hyd i gofnodion sy'n cyfateb",
+ "paginate": {
+ "first": "Cyntaf",
+ "last": "Olaf",
+ "next": "Nesaf",
+ "previous": "Blaenorol"
+ },
+ "aria": {
+ "sortAscending": ": rhoi ar waith i drefnu colofnau o'r lleiaf i'r mwyaf",
+ "sortDescending": ": rhoi ar waith i drefnu colofnau o'r mwyaf i'r lleiaf"
+ }
+}
\ No newline at end of file
diff --git a/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/da.json b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/da.json
new file mode 100644
index 0000000..191fc9a
--- /dev/null
+++ b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/da.json
@@ -0,0 +1,15 @@
+{
+ "processing": "Henter...",
+ "lengthMenu": "Vis _MENU_ linjer",
+ "zeroRecords": "Ingen linjer matcher søgningen",
+ "info": "Viser _START_ til _END_ af _TOTAL_ linjer",
+ "infoEmpty": "Viser 0 til 0 af 0 linjer",
+ "infoFiltered": "(filtreret fra _MAX_ linjer)",
+ "search": "Søg:",
+ "paginate": {
+ "first": "Første",
+ "previous": "Forrige",
+ "next": "Næste",
+ "last": "Sidste"
+ }
+}
\ No newline at end of file
diff --git a/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/de.json b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/de.json
new file mode 100644
index 0000000..789d2e3
--- /dev/null
+++ b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/de.json
@@ -0,0 +1,43 @@
+{
+ "emptyTable": "Keine Daten in der Tabelle vorhanden",
+ "info": "_START_ bis _END_ von _TOTAL_ Einträgen",
+ "infoEmpty": "Keine Daten vorhanden",
+ "infoFiltered": "(gefiltert von _MAX_ Einträgen)",
+ "infoThousands": ".",
+ "lengthMenu": "_MENU_ Einträge anzeigen",
+ "loadingRecords": "Wird geladen ..",
+ "processing": "Bitte warten ..",
+ "search": "Suchen",
+ "zeroRecords": "Keine Einträge vorhanden",
+ "paginate": {
+ "first": "Erste",
+ "previous": "Zurück",
+ "next": "Nächste",
+ "last": "Letzte"
+ },
+ "aria": {
+ "sortAscending": ": aktivieren, um Spalte aufsteigend zu sortieren",
+ "sortDescending": ": aktivieren, um Spalte absteigend zu sortieren"
+ },
+ "select": {
+ "rows": {
+ "_": "%d Zeilen ausgewählt",
+ "1": "1 Zeile ausgewählt"
+ }
+ },
+ "buttons": {
+ "print": "Drucken",
+ "colvis": "Spalten",
+ "copy": "Kopieren",
+ "copyTitle": "In Zwischenablage kopieren",
+ "copyKeys": "Taste ctrl<\/i> oder ⌘<\/i> + C<\/i> um Tabelle in Zwischenspeicher zu kopieren. Um abzubrechen die Nachricht anklicken oder Escape drücken.",
+ "copySuccess": {
+ "_": "%d Zeilen kopiert",
+ "1": "1 Zeile kopiert"
+ },
+ "pageLength": {
+ "-1": "Zeige alle Zeilen",
+ "_": "Zeige %d Zeilen"
+ }
+ }
+}
\ No newline at end of file
diff --git a/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/el.json b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/el.json
new file mode 100644
index 0000000..017ffee
--- /dev/null
+++ b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/el.json
@@ -0,0 +1,25 @@
+{
+ "decimal": ",",
+ "emptyTable": "Δεν υπάρχουν δεδομένα στον πίνακα",
+ "info": "Εμφανίζονται _START_ έως _END_ από _TOTAL_ εγγραφές",
+ "infoEmpty": "Εμφανίζονται 0 έως 0 από 0 εγγραφές",
+ "infoFiltered": "(φιλτραρισμένες από _MAX_ συνολικά εγγραφές)",
+ "infoThousands": ".",
+ "lengthMenu": "Δείξε _MENU_ εγγραφές",
+ "loadingRecords": "Φόρτωση...",
+ "processing": "Επεξεργασία...",
+ "search": "Αναζήτηση:",
+ "searchPlaceholder": "Αναζήτηση",
+ "thousands": ".",
+ "zeroRecords": "Δεν βρέθηκαν εγγραφές που να ταιριάζουν",
+ "paginate": {
+ "first": "Πρώτη",
+ "previous": "Προηγούμενη",
+ "next": "Επόμενη",
+ "last": "Τελευταία"
+ },
+ "aria": {
+ "sortAscending": ": ενεργοποιήστε για αύξουσα ταξινόμηση της στήλης",
+ "sortDescending": ": ενεργοποιήστε για φθίνουσα ταξινόμηση της στήλης"
+ }
+}
\ No newline at end of file
diff --git a/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/en-gb.json b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/en-gb.json
new file mode 100644
index 0000000..66da55a
--- /dev/null
+++ b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/en-gb.json
@@ -0,0 +1,137 @@
+{
+ "emptyTable": "No data available in table",
+ "info": "Showing _START_ to _END_ of _TOTAL_ entries",
+ "infoEmpty": "Showing 0 to 0 of 0 entries",
+ "infoFiltered": "(filtered from _MAX_ total entries)",
+ "infoThousands": ",",
+ "lengthMenu": "Show _MENU_ entries",
+ "loadingRecords": "Loading...",
+ "processing": "Processing...",
+ "search": "Search:",
+ "zeroRecords": "No matching records found",
+ "thousands": ",",
+ "paginate": {
+ "first": "First",
+ "last": "Last",
+ "next": "Next",
+ "previous": "Previous"
+ },
+ "aria": {
+ "sortAscending": ": activate to sort column ascending",
+ "sortDescending": ": activate to sort column descending"
+ },
+ "autoFill": {
+ "cancel": "Cancel",
+ "fill": "Fill all cells with %d<\/i>",
+ "fillHorizontal": "Fill cells horizontally",
+ "fillVertical": "Fill cells vertically"
+ },
+ "buttons": {
+ "collection": "Collection ",
+ "colvis": "Column Visibility",
+ "colvisRestore": "Restore visibility",
+ "copy": "Copy",
+ "copyKeys": "Press ctrl or u2318 + C to copy the table data to your system clipboard. To cancel, click this message or press escape.",
+ "copySuccess": {
+ "1": "Copied 1 row to clipboard",
+ "_": "Copied %d rows to clipboard"
+ },
+ "copyTitle": "Copy to Clipboard",
+ "csv": "CSV",
+ "excel": "Excel",
+ "pageLength": {
+ "-1": "Show all rows",
+ "1": "Show 1 row",
+ "_": "Show %d rows"
+ },
+ "pdf": "PDF",
+ "print": "Print"
+ },
+ "searchBuilder": {
+ "add": "Add Condition",
+ "button": {
+ "0": "Search Builder",
+ "_": "Search Builder (%d)"
+ },
+ "clearAll": "Clear All",
+ "condition": "Condition",
+ "conditions": {
+ "date": {
+ "after": "After",
+ "before": "Before",
+ "between": "Between",
+ "empty": "Empty",
+ "equals": "Equals",
+ "not": "Not",
+ "notBetween": "Not Between",
+ "notEmpty": "Not Empty"
+ },
+ "moment": {
+ "after": "After",
+ "before": "Before",
+ "between": "Between",
+ "empty": "Empty",
+ "equals": "Equals",
+ "not": "Not",
+ "notBetween": "Not Between",
+ "notEmpty": "Not Empty"
+ },
+ "number": {
+ "between": "Between",
+ "empty": "Empty",
+ "equals": "Equals",
+ "gt": "Greater Than",
+ "gte": "Greater Than Equal To",
+ "lt": "Less Than",
+ "lte": "Less Than Equal To",
+ "not": "Not",
+ "notBetween": "Not Between",
+ "notEmpty": "Not Empty"
+ },
+ "string": {
+ "contains": "Contains",
+ "empty": "Empty",
+ "endsWith": "Ends With",
+ "equals": "Equals",
+ "not": "Not",
+ "notEmpty": "Not Empty",
+ "startsWith": "Starts With"
+ }
+ },
+ "data": "Data",
+ "deleteTitle": "Delete filtering rule",
+ "leftTitle": "Outdent Criteria",
+ "logicAnd": "And",
+ "logicOr": "Or",
+ "rightTitle": "Indent Criteria",
+ "title": {
+ "0": "Search Builder",
+ "_": "Search Builder (%d)"
+ },
+ "value": "Value"
+ },
+ "searchPanes": {
+ "clearMessage": "Clear All",
+ "collapse": {
+ "0": "SearchPanes",
+ "_": "SearchPanes (%d)"
+ },
+ "count": "{total}",
+ "countFiltered": "{shown} ({total})",
+ "emptyPanes": "No SearchPanes",
+ "loadMessage": "Loading SearchPanes",
+ "title": "Filters Active - %d"
+ },
+ "select": {
+ "1": "%d row selected",
+ "_": "%d rows selected",
+ "cells": {
+ "1": "1 cell selected",
+ "_": "%d cells selected"
+ },
+ "columns": {
+ "1": "1 column selected",
+ "_": "%d columns selected"
+ }
+ }
+}
\ No newline at end of file
diff --git a/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/en_GB.json b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/en_GB.json
new file mode 100644
index 0000000..9c2537d
--- /dev/null
+++ b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/en_GB.json
@@ -0,0 +1,178 @@
+{
+ "emptyTable": "No data available in table",
+ "info": "Showing _START_ to _END_ of _TOTAL_ entries",
+ "infoEmpty": "Showing 0 to 0 of 0 entries",
+ "infoFiltered": "(filtered from _MAX_ total entries)",
+ "infoThousands": ",",
+ "lengthMenu": "Show _MENU_ entries",
+ "loadingRecords": "Loading...",
+ "processing": "Processing...",
+ "search": "Search:",
+ "zeroRecords": "No matching records found",
+ "thousands": ",",
+ "paginate": {
+ "first": "First",
+ "last": "Last",
+ "next": "Next",
+ "previous": "Previous"
+ },
+ "aria": {
+ "sortAscending": ": activate to sort column ascending",
+ "sortDescending": ": activate to sort column descending"
+ },
+ "autoFill": {
+ "cancel": "Cancel",
+ "fill": "Fill all cells with %d<\/i>",
+ "fillHorizontal": "Fill cells horizontally",
+ "fillVertical": "Fill cells vertically"
+ },
+ "buttons": {
+ "collection": "Collection ",
+ "colvis": "Column Visibility",
+ "colvisRestore": "Restore visibility",
+ "copy": "Copy",
+ "copyKeys": "Press ctrl or u2318 + C to copy the table data to your system clipboard. To cancel, click this message or press escape.",
+ "copySuccess": {
+ "1": "Copied 1 row to clipboard",
+ "_": "Copied %d rows to clipboard"
+ },
+ "copyTitle": "Copy to Clipboard",
+ "csv": "CSV",
+ "excel": "Excel",
+ "pageLength": {
+ "-1": "Show all rows",
+ "1": "Show 1 row",
+ "_": "Show %d rows"
+ },
+ "pdf": "PDF",
+ "print": "Print"
+ },
+ "searchBuilder": {
+ "add": "Add Condition",
+ "button": {
+ "0": "Search Builder",
+ "_": "Search Builder (%d)"
+ },
+ "clearAll": "Clear All",
+ "condition": "Condition",
+ "conditions": {
+ "date": {
+ "after": "After",
+ "before": "Before",
+ "between": "Between",
+ "empty": "Empty",
+ "equals": "Equals",
+ "not": "Not",
+ "notBetween": "Not Between",
+ "notEmpty": "Not Empty"
+ },
+ "number": {
+ "between": "Between",
+ "empty": "Empty",
+ "equals": "Equals",
+ "gt": "Greater Than",
+ "gte": "Greater Than Equal To",
+ "lt": "Less Than",
+ "lte": "Less Than Equal To",
+ "not": "Not",
+ "notBetween": "Not Between",
+ "notEmpty": "Not Empty"
+ },
+ "string": {
+ "contains": "Contains",
+ "empty": "Empty",
+ "endsWith": "Ends With",
+ "equals": "Equals",
+ "not": "Not",
+ "notEmpty": "Not Empty",
+ "startsWith": "Starts With"
+ },
+ "array": {
+ "without": "Without",
+ "notEmpty": "Not Empty",
+ "not": "Not",
+ "contains": "Contains",
+ "empty": "Empty",
+ "equals": "Equals"
+ }
+ },
+ "data": "Data",
+ "deleteTitle": "Delete filtering rule",
+ "leftTitle": "Outdent Criteria",
+ "logicAnd": "And",
+ "logicOr": "Or",
+ "rightTitle": "Indent Criteria",
+ "title": {
+ "0": "Search Builder",
+ "_": "Search Builder (%d)"
+ },
+ "value": "Value"
+ },
+ "searchPanes": {
+ "clearMessage": "Clear All",
+ "collapse": {
+ "0": "SearchPanes",
+ "_": "SearchPanes (%d)"
+ },
+ "count": "{total}",
+ "countFiltered": "{shown} ({total})",
+ "emptyPanes": "No SearchPanes",
+ "loadMessage": "Loading SearchPanes",
+ "title": "Filters Active - %d"
+ },
+ "select": {
+ "1": "%d row selected",
+ "_": "%d rows selected",
+ "cells": {
+ "1": "1 cell selected",
+ "_": "%d cells selected"
+ },
+ "columns": {
+ "1": "1 column selected",
+ "_": "%d columns selected"
+ }
+ },
+ "datetime": {
+ "previous": "Previous",
+ "next": "Next",
+ "hours": "Hour",
+ "minutes": "Minute",
+ "seconds": "Second",
+ "unknown": "-",
+ "amPm": [
+ "am",
+ "pm"
+ ]
+ },
+ "editor": {
+ "close": "Close",
+ "create": {
+ "button": "New",
+ "title": "Create new entry",
+ "submit": "Create"
+ },
+ "edit": {
+ "button": "Edit",
+ "title": "Edit Entry",
+ "submit": "Update"
+ },
+ "remove": {
+ "button": "Delete",
+ "title": "Delete",
+ "submit": "Delete",
+ "confirm": {
+ "_": "Are you sure you wish to delete %d rows?",
+ "1": "Are you sure you wish to delete 1 row?"
+ }
+ },
+ "error": {
+ "system": "A system error has occurred (More information<\/a>)."
+ },
+ "multi": {
+ "title": "Multiple Values",
+ "info": "The selected items contain different values for this input. To edit and set all items for this input to the same value, click or tap here, otherwise they will retain their individual values.",
+ "restore": "Undo Changes",
+ "noMulti": "This input can be edited individually, but not part of a group. "
+ }
+ }
+}
\ No newline at end of file
diff --git a/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/eo.json b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/eo.json
new file mode 100644
index 0000000..b9b2362
--- /dev/null
+++ b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/eo.json
@@ -0,0 +1,22 @@
+{
+ "emptyTable": "Neniuj datumoj en tabelo",
+ "info": "Montras _START_ ĝis _END_ el _TOTAL_ vicoj",
+ "infoEmpty": "Montras 0 ĝis 0 el 0 vicoj",
+ "infoFiltered": "(filtrita el entute _MAX_ vicoj)",
+ "infoThousands": ".",
+ "lengthMenu": "Montri _MENU_ vicojn",
+ "loadingRecords": "Ŝarĝas ...",
+ "processing": "Pretigas ...",
+ "search": "Serĉi:",
+ "zeroRecords": "Neniuj rezultoj trovitaj",
+ "paginate": {
+ "first": "Unua",
+ "last": "Lasta",
+ "next": "Venonta",
+ "previous": "Antaŭa"
+ },
+ "aria": {
+ "sortAscending": ": aktivigi por filtri kolumnon kreskante",
+ "sortDescending": ": aktivigi por filtri kolumnon malkreskante"
+ }
+}
\ No newline at end of file
diff --git a/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/es.json b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/es.json
new file mode 100644
index 0000000..40ba45d
--- /dev/null
+++ b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/es.json
@@ -0,0 +1,26 @@
+{
+ "processing": "Procesando...",
+ "lengthMenu": "Mostrar _MENU_ registros",
+ "zeroRecords": "No se encontraron resultados",
+ "emptyTable": "Ningún dato disponible en esta tabla",
+ "info": "Mostrando registros del _START_ al _END_ de un total de _TOTAL_ registros",
+ "infoEmpty": "Mostrando registros del 0 al 0 de un total de 0 registros",
+ "infoFiltered": "(filtrado de un total de _MAX_ registros)",
+ "search": "Buscar:",
+ "infoThousands": ",",
+ "loadingRecords": "Cargando...",
+ "paginate": {
+ "first": "Primero",
+ "last": "Último",
+ "next": "Siguiente",
+ "previous": "Anterior"
+ },
+ "aria": {
+ "sortAscending": ": Activar para ordenar la columna de manera ascendente",
+ "sortDescending": ": Activar para ordenar la columna de manera descendente"
+ },
+ "buttons": {
+ "copy": "Copiar",
+ "colvis": "Visibilidad"
+ }
+}
\ No newline at end of file
diff --git a/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/et.json b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/et.json
new file mode 100644
index 0000000..bc60246
--- /dev/null
+++ b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/et.json
@@ -0,0 +1,15 @@
+{
+ "processing": "Palun oodake, koostan kuvamiseks nimekirja!",
+ "lengthMenu": "Näita kirjeid _MENU_ kaupa",
+ "zeroRecords": "Otsitavat vastet ei leitud.",
+ "info": "Kuvatud: _TOTAL_ kirjet (_START_-_END_)",
+ "infoEmpty": "Otsinguvasteid ei leitud",
+ "infoFiltered": " - filteeritud _MAX_ kirje seast.",
+ "search": "Otsi kõikide tulemuste seast:",
+ "paginate": {
+ "first": "Algus",
+ "previous": "Eelmine",
+ "next": "Järgmine",
+ "last": "Viimane"
+ }
+}
\ No newline at end of file
diff --git a/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/eu.json b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/eu.json
new file mode 100644
index 0000000..2e5a59c
--- /dev/null
+++ b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/eu.json
@@ -0,0 +1,22 @@
+{
+ "processing": "Prozesatzen...",
+ "lengthMenu": "Erakutsi _MENU_ erregistro",
+ "zeroRecords": "Ez da emaitzarik aurkitu",
+ "emptyTable": "Taula hontan ez dago inongo datu erabilgarririk",
+ "info": "_START_ -etik _END_ -erako erregistroak erakusten, guztira _TOTAL_ erregistro",
+ "infoEmpty": "0tik 0rako erregistroak erakusten, guztira 0 erregistro",
+ "infoFiltered": "(guztira _MAX_ erregistro iragazten)",
+ "search": "Aurkitu:",
+ "infoThousands": ",",
+ "loadingRecords": "Abiarazten...",
+ "paginate": {
+ "first": "Lehena",
+ "last": "Azkena",
+ "next": "Hurrengoa",
+ "previous": "Aurrekoa"
+ },
+ "aria": {
+ "sortAscending": ": Zutabea goranzko eran ordenatzeko aktibatu ",
+ "sortDescending": ": Zutabea beheranzko eran ordenatzeko aktibatu"
+ }
+}
\ No newline at end of file
diff --git a/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/fa.json b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/fa.json
new file mode 100644
index 0000000..46576cc
--- /dev/null
+++ b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/fa.json
@@ -0,0 +1,22 @@
+{
+ "emptyTable": "هیچ دادهای در جدول وجود ندارد",
+ "info": "نمایش _START_ تا _END_ از _TOTAL_ ردیف",
+ "infoEmpty": "نمایش 0 تا 0 از 0 ردیف",
+ "infoFiltered": "(فیلتر شده از _MAX_ ردیف)",
+ "infoThousands": ",",
+ "lengthMenu": "نمایش _MENU_ ردیف",
+ "loadingRecords": "در حال بارگزاری...",
+ "processing": "در حال پردازش...",
+ "search": "جستجو:",
+ "zeroRecords": "رکوردی با این مشخصات پیدا نشد",
+ "paginate": {
+ "first": "برگهی نخست",
+ "last": "برگهی آخر",
+ "next": "بعدی",
+ "previous": "قبلی"
+ },
+ "aria": {
+ "sortAscending": ": فعال سازی نمایش به صورت صعودی",
+ "sortDescending": ": فعال سازی نمایش به صورت نزولی"
+ }
+}
\ No newline at end of file
diff --git a/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/fi.json b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/fi.json
new file mode 100644
index 0000000..5efaac9
--- /dev/null
+++ b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/fi.json
@@ -0,0 +1,38 @@
+{
+ "emptyTable": "Ei näytettäviä tuloksia.",
+ "info": "Näytetään rivit _START_ - _END_ (yhteensä _TOTAL_ )",
+ "infoEmpty": "Näytetään 0 - 0 (yhteensä 0)",
+ "infoFiltered": "(suodatettu _MAX_ tuloksen joukosta)",
+ "infoThousands": ",",
+ "lengthMenu": "Näytä kerralla _MENU_ riviä",
+ "loadingRecords": "Ladataan...",
+ "processing": "Hetkinen...",
+ "search": "Etsi:",
+ "zeroRecords": "Tietoja ei löytynyt",
+ "paginate": {
+ "first": "Ensimmäinen",
+ "last": "Viimeinen",
+ "next": "Seuraava",
+ "previous": "Edellinen"
+ },
+ "aria": {
+ "sortAscending": ": lajittele sarake nousevasti",
+ "sortDescending": ": lajittele sarake laskevasti"
+ },
+ "select": {
+ "rows": {
+ "_": "Valittuna %d riviä",
+ "0": "Klikkaa riviä valitaksesi sen",
+ "1": "Valittuna vain yksi rivi"
+ }
+ },
+ "buttons": {
+ "copy": "Kopioi",
+ "copySuccess": {
+ "1": "Yksi rivi kopioitu leikepöydälle",
+ "_": "%d riviä kopioitu leikepöydälle"
+ },
+ "copyTitle": "Kopioi leikepöydälle",
+ "copyKeys": "Paina ctrl<\/i> tai ⌘<\/i> + C<\/i> kopioidaksesi taulukon arvot leikepöydälle. Peruuttaaksesi klikkaa tähän tai Esc."
+ }
+}
\ No newline at end of file
diff --git a/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/fil.json b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/fil.json
new file mode 100644
index 0000000..32f3962
--- /dev/null
+++ b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/fil.json
@@ -0,0 +1,15 @@
+{
+ "processing": "Pagproseso...",
+ "lengthMenu": "Ipakita _MENU_ entries",
+ "zeroRecords": "Walang katugmang mga talaan na natagpuan",
+ "info": "Ipinapakita ang _START_ sa _END_ ng _TOTAL_ entries",
+ "infoEmpty": "Ipinapakita ang 0-0 ng 0 entries",
+ "infoFiltered": "(na-filter mula _MAX_ kabuuang entries)",
+ "search": "Paghahanap:",
+ "paginate": {
+ "first": "Unang",
+ "previous": "Nakaraan",
+ "next": "Susunod",
+ "last": "Huli"
+ }
+}
\ No newline at end of file
diff --git a/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/fr.json b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/fr.json
new file mode 100644
index 0000000..756fc56
--- /dev/null
+++ b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/fr.json
@@ -0,0 +1,29 @@
+{
+ "emptyTable": "Aucune donnée disponible dans le tableau",
+ "info": "Affichage de l'élément _START_ à _END_ sur _TOTAL_ éléments",
+ "infoEmpty": "Affichage de l'élément 0 à 0 sur 0 élément",
+ "infoFiltered": "(filtré à partir de _MAX_ éléments au total)",
+ "infoThousands": ",",
+ "lengthMenu": "Afficher _MENU_ éléments",
+ "loadingRecords": "Chargement...",
+ "processing": "Traitement...",
+ "search": "Rechercher :",
+ "zeroRecords": "Aucun élément correspondant trouvé",
+ "paginate": {
+ "first": "Premier",
+ "last": "Dernier",
+ "next": "Suivant",
+ "previous": "Précédent"
+ },
+ "aria": {
+ "sortAscending": ": activer pour trier la colonne par ordre croissant",
+ "sortDescending": ": activer pour trier la colonne par ordre décroissant"
+ },
+ "select": {
+ "rows": {
+ "_": "%d lignes sélectionnées",
+ "0": "Aucune ligne sélectionnée",
+ "1": "1 ligne sélectionnée"
+ }
+ }
+}
\ No newline at end of file
diff --git a/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/ga.json b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/ga.json
new file mode 100644
index 0000000..ab76af7
--- /dev/null
+++ b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/ga.json
@@ -0,0 +1,15 @@
+{
+ "processing": "Próiseáil...",
+ "lengthMenu": "Taispeáin iontrálacha _MENU_",
+ "zeroRecords": "Gan aon taifead meaitseáil aimsithe",
+ "info": "_START_ Showing a _END_ na n-iontrálacha _TOTAL_",
+ "infoEmpty": "Showing 0-0 na n-iontrálacha 0",
+ "infoFiltered": "(scagtha ó _MAX_ iontrálacha iomlán)",
+ "search": "Cuardaigh:",
+ "paginate": {
+ "first": "An Chéad",
+ "previous": "Roimhe Seo",
+ "next": "Ar Aghaidh",
+ "last": "Last"
+ }
+}
\ No newline at end of file
diff --git a/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/gl.json b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/gl.json
new file mode 100644
index 0000000..ecb164e
--- /dev/null
+++ b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/gl.json
@@ -0,0 +1,22 @@
+{
+ "processing": "Procesando...",
+ "lengthMenu": "Mostrar _MENU_ rexistros",
+ "zeroRecords": "Non se atoparon resultados",
+ "emptyTable": "Ningún dato dispoñible nesta táboa",
+ "info": "Mostrando rexistros do _START_ ao _END_ dun total de _TOTAL_ rexistros",
+ "infoEmpty": "Mostrando rexistros do 0 ao 0 dun total de 0 rexistros",
+ "infoFiltered": "(filtrado dun total de _MAX_ rexistros)",
+ "search": "Buscar:",
+ "infoThousands": ",",
+ "loadingRecords": "Cargando...",
+ "paginate": {
+ "first": "Primeiro",
+ "last": "Último",
+ "next": "Seguinte",
+ "previous": "Anterior"
+ },
+ "aria": {
+ "sortAscending": ": Activar para ordenar a columna de maneira ascendente",
+ "sortDescending": ": Activar para ordenar a columna de maneira descendente"
+ }
+}
\ No newline at end of file
diff --git a/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/gu.json b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/gu.json
new file mode 100644
index 0000000..8d7fdc4
--- /dev/null
+++ b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/gu.json
@@ -0,0 +1,22 @@
+{
+ "emptyTable": "કોષ્ટકમાં કોઈ ડેટા ઉપલબ્ધ નથી",
+ "info": "કુલ _TOTAL_ માંથી _START_ થી _END_ પ્રવેશો દર્શાવે છે",
+ "infoEmpty": "કુલ 0 પ્રવેશ માંથી 0 થી 0 બતાવી રહ્યું છે",
+ "infoFiltered": "(_MAX_ કુલ પ્રવેશો માંથી ફિલ્ટર)",
+ "infoThousands": ",",
+ "lengthMenu": "બતાવો _MENU_ પ્રવેશો",
+ "loadingRecords": "લોડ કરી રહ્યું છે ...",
+ "processing": "પ્રક્રિયા ...",
+ "search": "શોધો:",
+ "zeroRecords": "કોઈ મેળ ખાતા રેકોર્ડ મળ્યા નથી ",
+ "paginate": {
+ "first": "પ્રથમ",
+ "last": "અંતિમ",
+ "next": "આગામી",
+ "previous": "ગત"
+ },
+ "aria": {
+ "sortAscending": ": સ્તંભ ચડતા ક્રમમાં ગોઠવવા માટે સક્રિય",
+ "sortDescending": ": કૉલમ ઉતરતા ક્રમમાં ગોઠવવા માટે સક્રિય"
+ }
+}
\ No newline at end of file
diff --git a/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/he.json b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/he.json
new file mode 100644
index 0000000..ecbd0af
--- /dev/null
+++ b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/he.json
@@ -0,0 +1,16 @@
+{
+ "processing": "מעבד...",
+ "lengthMenu": "הצג _MENU_ פריטים",
+ "zeroRecords": "לא נמצאו רשומות מתאימות",
+ "emptyTable": "לא נמצאו רשומות מתאימות",
+ "info": "_START_ עד _END_ מתוך _TOTAL_ רשומות",
+ "infoEmpty": "0 עד 0 מתוך 0 רשומות",
+ "infoFiltered": "(מסונן מסך _MAX_ רשומות)",
+ "search": "חפש:",
+ "paginate": {
+ "first": "ראשון",
+ "previous": "קודם",
+ "next": "הבא",
+ "last": "אחרון"
+ }
+}
\ No newline at end of file
diff --git a/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/hi.json b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/hi.json
new file mode 100644
index 0000000..8a2168f
--- /dev/null
+++ b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/hi.json
@@ -0,0 +1,15 @@
+{
+ "processing": "प्रगति पे हैं ...",
+ "lengthMenu": " _MENU_ प्रविष्टियां दिखाएं ",
+ "zeroRecords": "रिकॉर्ड्स का मेल नहीं मिला",
+ "info": "_START_ to _END_ of _TOTAL_ प्रविष्टियां दिखा रहे हैं",
+ "infoEmpty": "0 में से 0 से 0 प्रविष्टियां दिखा रहे हैं",
+ "infoFiltered": "(_MAX_ कुल प्रविष्टियों में से छठा हुआ)",
+ "search": "खोजें:",
+ "paginate": {
+ "first": "प्रथम",
+ "previous": "पिछला",
+ "next": "अगला",
+ "last": "अंतिम"
+ }
+}
\ No newline at end of file
diff --git a/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/hr.json b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/hr.json
new file mode 100644
index 0000000..8076418
--- /dev/null
+++ b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/hr.json
@@ -0,0 +1,22 @@
+{
+ "emptyTable": "Nema podataka u tablici",
+ "info": "Prikazano _START_ do _END_ od _TOTAL_ rezultata",
+ "infoEmpty": "Prikazano 0 do 0 od 0 rezultata",
+ "infoFiltered": "(filtrirano iz _MAX_ ukupnih rezultata)",
+ "infoThousands": ",",
+ "lengthMenu": "Prikaži _MENU_ rezultata po stranici",
+ "loadingRecords": "Dohvaćam...",
+ "processing": "Obrađujem...",
+ "search": "Pretraži:",
+ "zeroRecords": "Ništa nije pronađeno",
+ "paginate": {
+ "first": "Prva",
+ "previous": "Nazad",
+ "next": "Naprijed",
+ "last": "Zadnja"
+ },
+ "aria": {
+ "sortAscending": ": aktiviraj za rastući poredak",
+ "sortDescending": ": aktiviraj za padajući poredak"
+ }
+}
\ No newline at end of file
diff --git a/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/hu.json b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/hu.json
new file mode 100644
index 0000000..1017046
--- /dev/null
+++ b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/hu.json
@@ -0,0 +1,38 @@
+{
+ "emptyTable": "Nincs rendelkezésre álló adat",
+ "info": "Találatok: _START_ - _END_ Összesen: _TOTAL_",
+ "infoEmpty": "Nulla találat",
+ "infoFiltered": "(_MAX_ összes rekord közül szűrve)",
+ "infoThousands": " ",
+ "lengthMenu": "_MENU_ találat oldalanként",
+ "loadingRecords": "Betöltés...",
+ "processing": "Feldolgozás...",
+ "search": "Keresés:",
+ "zeroRecords": "Nincs a keresésnek megfelelő találat",
+ "paginate": {
+ "first": "Első",
+ "previous": "Előző",
+ "next": "Következő",
+ "last": "Utolsó"
+ },
+ "aria": {
+ "sortAscending": ": aktiválja a növekvő rendezéshez",
+ "sortDescending": ": aktiválja a csökkenő rendezéshez"
+ },
+ "select": {
+ "rows": {
+ "_": "%d sor kiválasztva",
+ "1": "1 sor kiválasztva"
+ }
+ },
+ "buttons": {
+ "print": "Nyomtatás",
+ "colvis": "Oszlopok",
+ "copy": "Másolás",
+ "copyTitle": "Vágólapra másolás",
+ "copySuccess": {
+ "_": "%d sor másolva",
+ "1": "1 sor másolva"
+ }
+ }
+}
\ No newline at end of file
diff --git a/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/hy.json b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/hy.json
new file mode 100644
index 0000000..3d04430
--- /dev/null
+++ b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/hy.json
@@ -0,0 +1,22 @@
+{
+ "emptyTable": "Տվյալները բացակայում են",
+ "processing": "Կատարվում է...",
+ "infoThousands": ",",
+ "lengthMenu": "Ցուցադրել _MENU_ արդյունքներ մեկ էջում",
+ "loadingRecords": "Բեռնվում է ...",
+ "zeroRecords": "Հարցմանը համապատասխանող արդյունքներ չկան",
+ "info": "Ցուցադրված են _START_-ից _END_ արդյունքները ընդհանուր _TOTAL_-ից",
+ "infoEmpty": "Արդյունքներ գտնված չեն",
+ "infoFiltered": "(ֆիլտրվել է ընդհանուր _MAX_ արդյունքներից)",
+ "search": "Փնտրել",
+ "paginate": {
+ "first": "Առաջին էջ",
+ "previous": "Նախորդ էջ",
+ "next": "Հաջորդ էջ",
+ "last": "Վերջին էջ"
+ },
+ "aria": {
+ "sortAscending": ": ակտիվացրեք աճման կարգով դասավորելու համար",
+ "sortDescending": ": ակտիվացրեք նվազման կարգով դասավորելու համար"
+ }
+}
\ No newline at end of file
diff --git a/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/id.json b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/id.json
new file mode 100644
index 0000000..ab4221c
--- /dev/null
+++ b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/id.json
@@ -0,0 +1,82 @@
+{
+ "emptyTable": "Tidak ada data yang tersedia pada tabel ini",
+ "info": "Menampilkan _START_ sampai _END_ dari _TOTAL_ entri",
+ "infoEmpty": "Menampilkan 0 sampai 0 dari 0 entri",
+ "infoFiltered": "(disaring dari _MAX_ entri keseluruhan)",
+ "infoThousands": "'",
+ "lengthMenu": "Tampilkan _MENU_ entri",
+ "loadingRecords": "Sedang memuat...",
+ "processing": "Sedang memproses...",
+ "search": "Cari:",
+ "zeroRecords": "Tidak ditemukan data yang sesuai",
+ "thousands": "'",
+ "paginate": {
+ "first": "Pertama",
+ "last": "Terakhir",
+ "next": "Selanjutnya",
+ "previous": "Sebelumnya"
+ },
+ "aria": {
+ "sortAscending": ": aktifkan untuk mengurutkan kolom ke atas",
+ "sortDescending": ": aktifkan untuk mengurutkan kolom menurun"
+ },
+ "autoFill": {
+ "cancel": "Batalkan",
+ "fill": "Isi semua sel dengan %d<\/i>",
+ "fillHorizontal": "Isi sel secara horizontal",
+ "fillVertical": "Isi sel secara vertikal"
+ },
+ "buttons": {
+ "collection": "Kumpulan ",
+ "colvis": "Visibilitas Kolom",
+ "colvisRestore": "Kembalikan visibilitas",
+ "copy": "Salin",
+ "copyKeys": "Tekan ctrl atau u2318 + C untuk menyalin tabel ke papan klip. To membatalkan, klik pesan ini atau tekan esc.",
+ "copySuccess": {
+ "1": "1 baris disalin ke papan klip",
+ "_": "%d baris disalin ke papan klip"
+ },
+ "copyTitle": "Salin ke Papan klip",
+ "csv": "CSV",
+ "excel": "Excel",
+ "pageLength": {
+ "-1": "Tampilkan semua baris",
+ "1": "Tampilkan 1 baris",
+ "_": "Tampilkan %d baris"
+ },
+ "pdf": "PDF",
+ "print": "Cetak"
+ },
+ "searchBuilder": {
+ "add": "Tambah Kondisi",
+ "button": {
+ "0": "Cari Builder",
+ "_": "Cari Builder (%d)"
+ },
+ "clearAll": "Bersihkan Semua",
+ "condition": "Kondisi",
+ "data": "Data",
+ "deleteTitle": "Hapus filter",
+ "leftTitle": "Ke Kiri",
+ "logicAnd": "Dan",
+ "logicOr": "Atau",
+ "rightTitle": "Ke Kanan",
+ "title": {
+ "0": "Cari Builder",
+ "_": "Cari Builder (%d)"
+ },
+ "value": "Nilai"
+ },
+ "searchPanes": {
+ "clearMessage": "Bersihkan Semua",
+ "collapse": {
+ "0": "SearchPanes",
+ "_": "SearchPanes (%d)"
+ },
+ "count": "{total}",
+ "countFiltered": "{shown} ({total})",
+ "emptyPanes": "Tidak Ada SearchPanes",
+ "loadMessage": "Memuat SearchPanes",
+ "title": "Filter Aktif - %d"
+ }
+}
\ No newline at end of file
diff --git a/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/id_alt.json b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/id_alt.json
new file mode 100644
index 0000000..61c11b8
--- /dev/null
+++ b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/id_alt.json
@@ -0,0 +1,15 @@
+{
+ "processing": "Sedang proses...",
+ "lengthMenu": "Tampilan _MENU_ entri",
+ "zeroRecords": "Tidak ditemukan data yang sesuai",
+ "info": "Tampilan _START_ sampai _END_ dari _TOTAL_ entri",
+ "infoEmpty": "Tampilan 0 hingga 0 dari 0 entri",
+ "infoFiltered": "(disaring dari _MAX_ entri keseluruhan)",
+ "search": "Cari:",
+ "paginate": {
+ "first": "Awal",
+ "previous": "Balik",
+ "next": "Lanjut",
+ "last": "Akhir"
+ }
+}
\ No newline at end of file
diff --git a/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/is.json b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/is.json
new file mode 100644
index 0000000..1fd7964
--- /dev/null
+++ b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/is.json
@@ -0,0 +1,22 @@
+{
+ "emptyTable": "Engin gögn eru í þessari töflu",
+ "info": "Sýni _START_ til _END_ af _TOTAL_ færslum",
+ "infoEmpty": "Sýni 0 til 0 af 0 færslum",
+ "infoFiltered": "(síað út frá _MAX_ færslum)",
+ "infoThousands": ".",
+ "lengthMenu": "Sýna _MENU_ færslur",
+ "loadingRecords": "Hleð...",
+ "processing": "Úrvinnsla...",
+ "search": "Leita:",
+ "zeroRecords": "Engar færslur fundust",
+ "paginate": {
+ "first": "Fyrsta",
+ "last": "Síðasta",
+ "next": "Næsta",
+ "previous": "Fyrri"
+ },
+ "aria": {
+ "sortAscending": ": virkja til að raða dálki í hækkandi röð",
+ "sortDescending": ": virkja til að raða dálki lækkandi í röð"
+ }
+}
\ No newline at end of file
diff --git a/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/it.json b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/it.json
new file mode 100644
index 0000000..cd699c9
--- /dev/null
+++ b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/it.json
@@ -0,0 +1,22 @@
+{
+ "emptyTable": "Nessun dato presente nella tabella",
+ "info": "Vista da _START_ a _END_ di _TOTAL_ elementi",
+ "infoEmpty": "Vista da 0 a 0 di 0 elementi",
+ "infoFiltered": "(filtrati da _MAX_ elementi totali)",
+ "infoThousands": ".",
+ "lengthMenu": "Visualizza _MENU_ elementi",
+ "loadingRecords": "Caricamento...",
+ "processing": "Elaborazione...",
+ "search": "Cerca:",
+ "zeroRecords": "La ricerca non ha portato alcun risultato.",
+ "paginate": {
+ "first": "Inizio",
+ "previous": "Precedente",
+ "next": "Successivo",
+ "last": "Fine"
+ },
+ "aria": {
+ "sortAscending": ": attiva per ordinare la colonna in ordine crescente",
+ "sortDescending": ": attiva per ordinare la colonna in ordine decrescente"
+ }
+}
\ No newline at end of file
diff --git a/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/ja.json b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/ja.json
new file mode 100644
index 0000000..31e094b
--- /dev/null
+++ b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/ja.json
@@ -0,0 +1,22 @@
+{
+ "emptyTable": "テーブルにデータがありません",
+ "info": " _TOTAL_ 件中 _START_ から _END_ まで表示",
+ "infoEmpty": " 0 件中 0 から 0 まで表示",
+ "infoFiltered": "(全 _MAX_ 件より抽出)",
+ "infoThousands": ",",
+ "lengthMenu": "_MENU_ 件表示",
+ "loadingRecords": "読み込み中...",
+ "processing": "処理中...",
+ "search": "検索:",
+ "zeroRecords": "一致するレコードがありません",
+ "paginate": {
+ "first": "先頭",
+ "last": "最終",
+ "next": "次",
+ "previous": "前"
+ },
+ "aria": {
+ "sortAscending": ": 列を昇順に並べ替えるにはアクティブにする",
+ "sortDescending": ": 列を降順に並べ替えるにはアクティブにする"
+ }
+}
\ No newline at end of file
diff --git a/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/ka.json b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/ka.json
new file mode 100644
index 0000000..d16ed4f
--- /dev/null
+++ b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/ka.json
@@ -0,0 +1,22 @@
+{
+ "emptyTable": "ცხრილში არ არის მონაცემები",
+ "info": "ნაჩვენებია ჩანაწერები _START_–დან _END_–მდე, _TOTAL_ ჩანაწერიდან",
+ "infoEmpty": "ნაჩვენებია ჩანაწერები 0–დან 0–მდე, 0 ჩანაწერიდან",
+ "infoFiltered": "(გაფილტრული შედეგი _MAX_ ჩანაწერიდან)",
+ "infoThousands": ".",
+ "lengthMenu": "აჩვენე _MENU_ ჩანაწერი",
+ "loadingRecords": "იტვირთება...",
+ "processing": "მუშავდება...",
+ "search": "ძიება:",
+ "zeroRecords": "არაფერი მოიძებნა",
+ "paginate": {
+ "first": "პირველი",
+ "last": "ბოლო",
+ "next": "შემდეგი",
+ "previous": "წინა"
+ },
+ "aria": {
+ "sortAscending": ": სვეტის დალაგება ზრდის მიხედვით",
+ "sortDescending": ": სვეტის დალაგება კლების მიხედვით"
+ }
+}
\ No newline at end of file
diff --git a/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/kk.json b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/kk.json
new file mode 100644
index 0000000..549baa3
--- /dev/null
+++ b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/kk.json
@@ -0,0 +1,21 @@
+{
+ "processing": "Күте тұрыңыз...",
+ "search": "Іздеу:",
+ "lengthMenu": "Жазбалар _MENU_ көрсету",
+ "info": "_TOTAL_ жазбалары бойынша _START_ бастап _END_ дейінгі жазбалар",
+ "infoEmpty": "0 жазбалары бойынша 0 бастап 0 дейінгі жазбалар",
+ "infoFiltered": "(_MAX_ жазбасынан сұрыпталды)",
+ "loadingRecords": "Жазбалар жүктемесі...",
+ "zeroRecords": "Жазбалар жоқ",
+ "emptyTable": "Кестеде деректер жоқ",
+ "paginate": {
+ "first": "Бірінші",
+ "previous": "Алдыңғысы",
+ "next": "Келесі",
+ "last": "Соңғы"
+ },
+ "aria": {
+ "sortAscending": ": өсімі бойынша бағанды сұрыптау үшін активациялау",
+ "sortDescending": ": кемуі бойынша бағанды сұрыптау үшін активациялау"
+ }
+}
\ No newline at end of file
diff --git a/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/km.json b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/km.json
new file mode 100644
index 0000000..e9aa5cc
--- /dev/null
+++ b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/km.json
@@ -0,0 +1,22 @@
+{
+ "emptyTable": "មិនមានទិន្នន័យក្នុងតារាងនេះទេ",
+ "info": "បង្ហាញជួរទី _START_ ដល់ទី _END_ ក្នុងចំណោម _TOTAL_ ជួរ",
+ "infoEmpty": "បង្ហាញជួរទី 0 ដល់ទី 0 ក្នុងចំណោម 0 ជួរ",
+ "infoFiltered": "(បានចម្រាញ់ចេញពីទិន្នន័យសរុប _MAX_ ជួរ)",
+ "infoThousands": ",",
+ "lengthMenu": "បង្ហាញ _MENU_ ជួរ",
+ "loadingRecords": "កំពុងផ្ទុក...",
+ "processing": "កំពុងដំណើរការ...",
+ "search": "ស្វែងរក:",
+ "zeroRecords": "មិនមានទិន្នន័យត្រូវតាមលក្ខខណ្ឌស្វែងរកទេ",
+ "paginate": {
+ "first": "ដំបូងគេ",
+ "last": "ចុងក្រោយ",
+ "next": "បន្ទាប់",
+ "previous": "ក្រោយ"
+ },
+ "aria": {
+ "sortAscending": ": ចុចដើម្បីរៀបជួរឈរនេះតាមលំដាប់ឡើង",
+ "sortDescending": ": ចុចដើម្បីរៀបជួរឈរនេះតាមលំដាប់ចុះ"
+ }
+}
\ No newline at end of file
diff --git a/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/kn.json b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/kn.json
new file mode 100644
index 0000000..0444bca
--- /dev/null
+++ b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/kn.json
@@ -0,0 +1,22 @@
+{
+ "emptyTable": "ಕೋಷ್ಟಕದಲ್ಲಿ ಯಾವುದೇ ಡೇಟಾ ಲಭ್ಯವಿಲ್ಲ",
+ "info": "ಒಟ್ಟು _TOTAL_ ಎಂಟ್ರಿಗಳಲ್ಲಿ _START_ ರಿಂದ _END_ ವರೆಗು ತೋರಿಸಲಾಗುತ್ತಿದೆ",
+ "infoEmpty": "ಒಟ್ಟು 0 ಎಂಟ್ರಿಗಳಲ್ಲಿ 0 ರಿಂದ 0 ವರೆಗು ತೋರಿಸಲಾಗುತ್ತಿದೆ",
+ "infoFiltered": "(ಒಟ್ಟು _MAX_ ಎಂಟ್ರಿ ಗಳಿಂದ ಫಿಲ್ಟರ್ ಮಾಡಲಾಗಿದೆ)",
+ "infoThousands": ",",
+ "lengthMenu": "_MENU_ ಎಂಟ್ರಿಗಳು ತೋರಿಸು",
+ "loadingRecords": "ಲೋಡ್ ಆಗುತ್ತಿದೆ...",
+ "processing": "ಸಂಸ್ಕರಿಸಲಾಗುತ್ತಿದೆ...",
+ "search": "ಹುಡುಕಿ:",
+ "zeroRecords": "ಯಾವುದೇ ಹೊಂದಾಣಿಕೆಯ ದಾಖಲೆಗಳು ಇಲ್ಲ",
+ "paginate": {
+ "first": "ಪ್ರಥಮ",
+ "last": "ಅಂತಿಮ",
+ "next": "ಮುಂದಿನದು",
+ "previous": "ಹಿಂದಿನದು"
+ },
+ "aria": {
+ "sortAscending": ": ಕಾಲಂ ಅನ್ನು ಆರೋಹಣವಾಗಿ ವಿಂಗಡಿಸಲು ಸಕ್ರಿಯಗೊಳಿಸಿ",
+ "sortDescending": ": ಕಾಲಂ ಅನ್ನು ಅವರೋಹಣವಾಗಿ ವಿಂಗಡಿಸಲು ಸಕ್ರಿಯಗೊಳಿಸಿ"
+ }
+}
\ No newline at end of file
diff --git a/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/ko.json b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/ko.json
new file mode 100644
index 0000000..0cf889e
--- /dev/null
+++ b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/ko.json
@@ -0,0 +1,22 @@
+{
+ "emptyTable": "데이터가 없습니다",
+ "info": "_START_ - _END_ \/ _TOTAL_",
+ "infoEmpty": "0 - 0 \/ 0",
+ "infoFiltered": "(총 _MAX_ 개)",
+ "infoThousands": ",",
+ "lengthMenu": "페이지당 줄수 _MENU_",
+ "loadingRecords": "읽는중...",
+ "processing": "처리중...",
+ "search": "검색:",
+ "zeroRecords": "검색 결과가 없습니다",
+ "paginate": {
+ "first": "처음",
+ "last": "마지막",
+ "next": "다음",
+ "previous": "이전"
+ },
+ "aria": {
+ "sortAscending": ": 오름차순 정렬",
+ "sortDescending": ": 내림차순 정렬"
+ }
+}
\ No newline at end of file
diff --git a/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/ko_KR.json b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/ko_KR.json
new file mode 100644
index 0000000..0c6d4d4
--- /dev/null
+++ b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/ko_KR.json
@@ -0,0 +1,68 @@
+{
+ "emptyTable": "데이터가 없습니다",
+ "info": "_START_ - _END_ \/ _TOTAL_",
+ "infoEmpty": "0 - 0 \/ 0",
+ "infoFiltered": "(총 _MAX_ 개)",
+ "infoThousands": ",",
+ "lengthMenu": "페이지당 줄수 _MENU_",
+ "loadingRecords": "읽는중...",
+ "processing": "처리중...",
+ "search": "검색:",
+ "zeroRecords": "검색 결과가 없습니다",
+ "paginate": {
+ "first": "처음",
+ "last": "마지막",
+ "next": "다음",
+ "previous": "이전"
+ },
+ "aria": {
+ "sortAscending": ": 오름차순 정렬",
+ "sortDescending": ": 내림차순 정렬"
+ },
+ "buttons": {
+ "copyKeys": "ctrl키 나 u2318 + C키로 테이블 데이터를 시스텝 복사판에서 복사하고 취소하려면 이 메시지를 클릭하거나 ESC키를 누르면됩니다. to copy the table data to your system clipboard. To cancel, click this message or press escape.",
+ "copySuccess": {
+ "_": "%d행을 복사판에서 복사됨",
+ "1": "1행을 복사판에서 복사됨"
+ },
+ "copyTitle": "복사판에서 복사",
+ "csv": "CSV",
+ "excel": "엑설",
+ "pageLength": {
+ "-1": "모든 행 보기",
+ "1": "1행 보기",
+ "_": "%d행 보기"
+ },
+ "pdf": "PDF",
+ "print": "인쇄",
+ "collection": "집합 <\/span>",
+ "colvis": "컬럼 보기",
+ "colvisRestore": "보기 복원",
+ "copy": "복사"
+ },
+ "searchBuilder": {
+ "add": "조건 추가",
+ "button": {
+ "0": "빌더 조회",
+ "_": "빌더 조회(%d)"
+ },
+ "clearAll": "모두 지우기",
+ "condition": "조건",
+ "data": "데이터",
+ "deleteTitle": "필터 규칙을 삭제",
+ "logicAnd": "And",
+ "logicOr": "Or",
+ "title": {
+ "0": "빌더 조회",
+ "_": "빌더 조회(%d)"
+ },
+ "value": "값"
+ },
+ "autoFill": {
+ "cancel": "취소",
+ "fill": "모든 셀에서 %d을(를) 삽입<\/i><\/i>",
+ "fillHorizontal": "수평 셀에서 값을 삽입",
+ "fillVertical": "수직 설에서 값을 삽입",
+ "info": "자동삽입 샘플 정보"
+ }
+}
\ No newline at end of file
diff --git a/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/ku.json b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/ku.json
new file mode 100644
index 0000000..fd68a82
--- /dev/null
+++ b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/ku.json
@@ -0,0 +1,21 @@
+{
+ "emptyTable": "هیچ تۆمارێک نەدۆزرایەوە",
+ "loadingRecords": "گەراندنەوەی تۆمارەکان...",
+ "processing": "تکایە چاوەرێکە...",
+ "lengthMenu": "نیشانبدە _MENU_ تۆمارەکان",
+ "zeroRecords": "هیچ تۆمارێک نەدۆزرایەوە",
+ "info": "نیشاندانی _START_ لە _END_ کۆی _TOTAL_ تۆمار",
+ "infoEmpty": "نیشاندانی 0 لە 0 لە کۆی 0 تۆمار",
+ "infoFiltered": "(پاڵێوراوە لە کۆی _MAX_ تۆمار)",
+ "search": "گەران:",
+ "paginate": {
+ "first": "یەکەم",
+ "previous": "پێشوو",
+ "next": "داهاتوو",
+ "last": "کۆتایی"
+ },
+ "aria": {
+ "sortAscending": ": چاڵاککردن بۆ ریزکردنی سەر بەرەو ژوور",
+ "sortDescending": ": چاڵاککردن بۆ ریزکردنی سەر بەرەو خوار"
+ }
+}
\ No newline at end of file
diff --git a/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/ky.json b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/ky.json
new file mode 100644
index 0000000..28beed5
--- /dev/null
+++ b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/ky.json
@@ -0,0 +1,22 @@
+{
+ "emptyTable": "Таблицада эч кандай берилиш жок",
+ "info": "Жалпы _TOTAL_ саптын ичинен _START_-саптан _END_-сапка чейинкилер",
+ "infoEmpty": "Жалпы 0 саптын ичинен 0-саптан 0-сапка чейинкилер",
+ "infoFiltered": "(жалпы _MAX_ саптан фильтрленди)",
+ "infoThousands": " ",
+ "lengthMenu": "_MENU_ саптан көрсөт",
+ "loadingRecords": "Жүктөлүүдө...",
+ "processing": "Иштеп жатат...",
+ "search": "Издөө:",
+ "zeroRecords": "Туура келген бир да сап жок",
+ "paginate": {
+ "first": "Биринчи",
+ "last": "Акыркы",
+ "next": "Кийинки",
+ "previous": "Мурунку"
+ },
+ "aria": {
+ "sortAscending": ": иретте",
+ "sortDescending": ": тескери иретте"
+ }
+}
\ No newline at end of file
diff --git a/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/lo.json b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/lo.json
new file mode 100644
index 0000000..bd92992
--- /dev/null
+++ b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/lo.json
@@ -0,0 +1,22 @@
+{
+ "emptyTable": "ບໍ່ພົບຂໍ້ມູນໃນຕາຕະລາງ",
+ "info": "ສະແດງ _START_ ເຖິງ _END_ ຈາກ _TOTAL_ ແຖວ",
+ "infoEmpty": "ສະແດງ 0 ເຖິງ 0 ຈາກ 0 ແຖວ",
+ "infoFiltered": "(ກັ່ນຕອງຂໍ້ມູນ _MAX_ ທຸກແຖວ)",
+ "infoThousands": ",",
+ "lengthMenu": "ສະແດງ _MENU_ ແຖວ",
+ "loadingRecords": "ກຳລັງໂຫຼດຂໍ້ມູນ...",
+ "processing": "ກຳລັງດຳເນີນການ...",
+ "search": "ຄົ້ນຫາ: ",
+ "zeroRecords": "ບໍ່ພົບຂໍ້ມູນ",
+ "paginate": {
+ "first": "ໜ້າທຳອິດ",
+ "previous": "ກ່ອນໜ້ານີ້",
+ "next": "ໜ້າຕໍ່ໄປ",
+ "last": "ໜ້າສຸດທ້າຍ"
+ },
+ "aria": {
+ "sortAscending": ": ເປີດໃຊ້ການຈັດລຽງຂໍ້ມູນແຕ່ນ້ອຍຫາໃຫຍ່",
+ "sortDescending": ": ເປີດໃຊ້ການຈັດລຽງຂໍ້ມູນແຕ່ໃຫຍ່ຫານ້ອຍ"
+ }
+}
\ No newline at end of file
diff --git a/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/lt.json b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/lt.json
new file mode 100644
index 0000000..6d43e6b
--- /dev/null
+++ b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/lt.json
@@ -0,0 +1,19 @@
+{
+ "emptyTable": "Lentelėje nėra duomenų",
+ "info": "Rodomi įrašai nuo _START_ iki _END_ iš _TOTAL_ įrašų",
+ "infoEmpty": "Rodomi įrašai nuo 0 iki 0 iš 0",
+ "infoFiltered": "(atrinkta iš _MAX_ įrašų)",
+ "infoThousands": " ",
+ "lengthMenu": "Rodyti _MENU_ įrašus",
+ "loadingRecords": "Įkeliama...",
+ "processing": "Apdorojama...",
+ "search": "Ieškoti:",
+ "thousands": " ",
+ "zeroRecords": "Įrašų nerasta",
+ "paginate": {
+ "first": "Pirmas",
+ "previous": "Ankstesnis",
+ "next": "Tolimesnis",
+ "last": "Paskutinis"
+ }
+}
\ No newline at end of file
diff --git a/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/lv.json b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/lv.json
new file mode 100644
index 0000000..1cd93fc
--- /dev/null
+++ b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/lv.json
@@ -0,0 +1,21 @@
+{
+ "processing": "Uzgaidiet ...",
+ "search": "Meklēt:",
+ "lengthMenu": "Rādīt _MENU_ ierakstus",
+ "info": "Parādīti _START_ līdz _END_ no _TOTAL_ ierakstiem",
+ "infoEmpty": "Nav ierakstu",
+ "infoFiltered": "(atlasīts no pavisam _MAX_ ierakstiem)",
+ "loadingRecords": "Notiek ielāde ...",
+ "zeroRecords": "Nav atrasti vaicājumam atbilstoši ieraksti",
+ "emptyTable": "Tabulā nav datu",
+ "paginate": {
+ "first": "Pirmā",
+ "previous": "Iepriekšējā",
+ "next": "Nākošā",
+ "last": "Pēdējā"
+ },
+ "aria": {
+ "sortAscending": ": aktivizēt kolonnu, lai kārtotu augoši",
+ "sortDescending": ": aktivizēt kolonnu, lai kārtotu dilstoši"
+ }
+}
\ No newline at end of file
diff --git a/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/mk.json b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/mk.json
new file mode 100644
index 0000000..55ea164
--- /dev/null
+++ b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/mk.json
@@ -0,0 +1,17 @@
+{
+ "processing": "Процесирање...",
+ "lengthMenu": "Прикажи _MENU_ записи",
+ "zeroRecords": "Не се пронајдени записи",
+ "emptyTable": "Нема податоци во табелата",
+ "loadingRecords": "Вчитување...",
+ "info": "Прикажани _START_ до _END_ од _TOTAL_ записи",
+ "infoEmpty": "Прикажани 0 до 0 од 0 записи",
+ "infoFiltered": "(филтрирано од вкупно _MAX_ записи)",
+ "search": "Барај",
+ "paginate": {
+ "first": "Почетна",
+ "previous": "Претходна",
+ "next": "Следна",
+ "last": "Последна"
+ }
+}
\ No newline at end of file
diff --git a/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/mn.json b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/mn.json
new file mode 100644
index 0000000..985fb2a
--- /dev/null
+++ b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/mn.json
@@ -0,0 +1,22 @@
+{
+ "emptyTable": "Хүснэгт хоосон байна",
+ "info": "Нийт _TOTAL_ бичлэгээс _START_ - _END_ харуулж байна",
+ "infoEmpty": "Тохирох үр дүн алга",
+ "infoFiltered": "(нийт _MAX_ бичлэгээс шүүв)",
+ "infoThousands": ",",
+ "lengthMenu": "Дэлгэцэд _MENU_ бичлэг харуулна",
+ "loadingRecords": "Ачааллаж байна...",
+ "processing": "Боловсруулж байна...",
+ "search": "Хайлт:",
+ "zeroRecords": "Тохирох бичлэг олдсонгүй",
+ "paginate": {
+ "first": "Эхнийх",
+ "last": "Сүүлийнх",
+ "next": "Дараах",
+ "previous": "Өмнөх"
+ },
+ "aria": {
+ "sortAscending": ": цагаан толгойн дарааллаар эрэмбэлэх",
+ "sortDescending": ": цагаан толгойн эсрэг дарааллаар эрэмбэлэх"
+ }
+}
\ No newline at end of file
diff --git a/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/ms.json b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/ms.json
new file mode 100644
index 0000000..9736044
--- /dev/null
+++ b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/ms.json
@@ -0,0 +1,22 @@
+{
+ "emptyTable": "Tiada data",
+ "info": "Paparan dari _START_ hingga _END_ dari _TOTAL_ rekod",
+ "infoEmpty": "Paparan 0 hingga 0 dari 0 rekod",
+ "infoFiltered": "(Ditapis dari jumlah _MAX_ rekod)",
+ "infoThousands": ",",
+ "lengthMenu": "Papar _MENU_ rekod",
+ "loadingRecords": "Diproses...",
+ "processing": "Sedang diproses...",
+ "search": "Carian:",
+ "zeroRecords": "Tiada padanan rekod yang dijumpai.",
+ "paginate": {
+ "first": "Pertama",
+ "previous": "Sebelum",
+ "next": "Seterusnya",
+ "last": "Akhir"
+ },
+ "aria": {
+ "sortAscending": ": diaktifkan kepada susunan lajur menaik",
+ "sortDescending": ": diaktifkan kepada susunan lajur menurun"
+ }
+}
\ No newline at end of file
diff --git a/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/ne.json b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/ne.json
new file mode 100644
index 0000000..764d15a
--- /dev/null
+++ b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/ne.json
@@ -0,0 +1,22 @@
+{
+ "emptyTable": "टेबलमा डाटा उपलब्ध भएन",
+ "info": "_TOTAL_ रेकर्ड मध्य _START_ देखि _END_ रेकर्ड देखाउंदै",
+ "infoEmpty": "0 मध्य 0 देखि 0 रेकर्ड देखाउंदै",
+ "infoFiltered": "(_MAX_ कुल रेकर्डबाट छनौट गरिएको)",
+ "infoThousands": ",",
+ "lengthMenu": " _MENU_ रेकर्ड देखाउने ",
+ "loadingRecords": "लोड हुँदैछ...",
+ "processing": "प्रगति हुदैंछ ...",
+ "search": "खोजी:",
+ "zeroRecords": "कुनै मिल्ने रेकर्ड फेला परेन",
+ "paginate": {
+ "first": "प्रथम",
+ "previous": "पछिल्लो",
+ "next": "अघिल्लो",
+ "last": "अन्तिम"
+ },
+ "aria": {
+ "sortAscending": ": अगाडिबाट अक्षरात्मक रूपमा क्रमबद्ध गराउने",
+ "sortDescending": ": पछाडिबाट अक्षरात्मक रूपमा क्रमबद्ध गराउने"
+ }
+}
\ No newline at end of file
diff --git a/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/nl.json b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/nl.json
new file mode 100644
index 0000000..a6af897
--- /dev/null
+++ b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/nl.json
@@ -0,0 +1,22 @@
+{
+ "processing": "Bezig...",
+ "lengthMenu": "_MENU_ resultaten weergeven",
+ "zeroRecords": "Geen resultaten gevonden",
+ "info": "_START_ tot _END_ van _TOTAL_ resultaten",
+ "infoEmpty": "Geen resultaten om weer te geven",
+ "infoFiltered": " (gefilterd uit _MAX_ resultaten)",
+ "search": "Zoeken:",
+ "emptyTable": "Geen resultaten aanwezig in de tabel",
+ "infoThousands": ".",
+ "loadingRecords": "Een moment geduld aub - bezig met laden...",
+ "paginate": {
+ "first": "Eerste",
+ "last": "Laatste",
+ "next": "Volgende",
+ "previous": "Vorige"
+ },
+ "aria": {
+ "sortAscending": ": activeer om kolom oplopend te sorteren",
+ "sortDescending": ": activeer om kolom aflopend te sorteren"
+ }
+}
\ No newline at end of file
diff --git a/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/no.json b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/no.json
new file mode 100644
index 0000000..8f40eda
--- /dev/null
+++ b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/no.json
@@ -0,0 +1,22 @@
+{
+ "emptyTable": "Inga data tilgjengeleg i tabellen",
+ "info": "Syner _START_ til _END_ av _TOTAL_ linjer",
+ "infoEmpty": "Syner 0 til 0 av 0 linjer",
+ "infoFiltered": "(filtrert frå _MAX_ totalt antal linjer)",
+ "infoThousands": " ",
+ "loadingRecords": "Lastar...",
+ "lengthMenu": "Syn _MENU_ linjer",
+ "processing": "Lastar...",
+ "search": "Søk:",
+ "zeroRecords": "Inga linjer treff på søket",
+ "paginate": {
+ "first": "Fyrste",
+ "previous": "Forrige",
+ "next": "Neste",
+ "last": "Siste"
+ },
+ "aria": {
+ "sortAscending": ": aktiver for å sortere kolonna stigande",
+ "sortDescending": ": aktiver for å sortere kolonna synkande"
+ }
+}
\ No newline at end of file
diff --git a/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/no_nb.json b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/no_nb.json
new file mode 100644
index 0000000..70afb1b
--- /dev/null
+++ b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/no_nb.json
@@ -0,0 +1,22 @@
+{
+ "emptyTable": "Ingen data tilgjengelig i tabellen",
+ "info": "Viser _START_ til _END_ av _TOTAL_ linjer",
+ "infoEmpty": "Viser 0 til 0 av 0 linjer",
+ "infoFiltered": "(filtrert fra _MAX_ totalt antall linjer)",
+ "infoThousands": " ",
+ "loadingRecords": "Laster...",
+ "lengthMenu": "Vis _MENU_ linjer",
+ "processing": "Laster...",
+ "search": "Søk:",
+ "zeroRecords": "Ingen linjer matcher søket",
+ "paginate": {
+ "first": "Første",
+ "previous": "Forrige",
+ "next": "Neste",
+ "last": "Siste"
+ },
+ "aria": {
+ "sortAscending": ": aktiver for å sortere kolonnen stigende",
+ "sortDescending": ": aktiver for å sortere kolonnen synkende"
+ }
+}
\ No newline at end of file
diff --git a/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/pa.json b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/pa.json
new file mode 100644
index 0000000..00822aa
--- /dev/null
+++ b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/pa.json
@@ -0,0 +1,22 @@
+{
+ "emptyTable": "ਸੂਚੀ ਵਿੱਚ ਕੋਈ ਕਤਾਰ ਉਪਲਬਧ ਨਹੀਂ ਹੈ",
+ "info": "_TOTAL_ ਵਿੱਚੋਂ _START_ ਤੋਂ _END_ ਐਂਟਰੀਆਂ ਦਿੱਖ ਰਹੀਆਂ ਹਨ",
+ "infoEmpty": "0 ਵਿੱਚੋਂ 0 ਤੋਂ 0 ਕਤਾਰਾਂ ਦਿੱਖ ਰਹੀਆਂ ਹਨ",
+ "infoFiltered": "(ਕੁੱਲ _MAX_ ਵਿਚੋਂ ਛਾਂਟੀਆਂ ਗਈਆਂ ਕਤਾਰਾਂ)",
+ "infoThousands": ",",
+ "lengthMenu": "ਕੁੱਲ _MENU_ ਕਤਾਰਾਂ",
+ "loadingRecords": "ਸੂਚੀ ਲੋਡ ਹੋ ਰਹੀ ਹੈ...",
+ "processing": "ਕਾਰਵਾਈ ਚੱਲ ਰਹੀ ਹੈ...",
+ "search": "ਖੋਜ ਕਰੋ:",
+ "zeroRecords": "ਕੋਈ ਕਤਾਰ ਨਹੀਂ ਮਿਲੀ",
+ "paginate": {
+ "first": "ਪਹਿਲਾ",
+ "last": "ਅਖੀਰਲਾ",
+ "next": "ਅਗਲਾ",
+ "previous": "ਪਿਛਲਾ"
+ },
+ "aria": {
+ "sortAscending": ": ਕਾਲਮ ਨੂੰ ਵੱਧਦੇ ਕ੍ਰਮ ਵਿਚ ਵੇਖੋ",
+ "sortDescending": ": ਕਾਲਮ ਨੂੰ ਘਟਦੇ ਕ੍ਰਮ ਵਿਚ ਵੇਖੋ"
+ }
+}
\ No newline at end of file
diff --git a/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/pl.json b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/pl.json
new file mode 100644
index 0000000..6653ee5
--- /dev/null
+++ b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/pl.json
@@ -0,0 +1,21 @@
+{
+ "processing": "Przetwarzanie...",
+ "search": "Szukaj:",
+ "lengthMenu": "Pokaż _MENU_ pozycji",
+ "info": "Pozycje od _START_ do _END_ z _TOTAL_ łącznie",
+ "infoEmpty": "Pozycji 0 z 0 dostępnych",
+ "infoFiltered": "(filtrowanie spośród _MAX_ dostępnych pozycji)",
+ "loadingRecords": "Wczytywanie...",
+ "zeroRecords": "Nie znaleziono pasujących pozycji",
+ "emptyTable": "Brak danych",
+ "paginate": {
+ "first": "Pierwsza",
+ "previous": "Poprzednia",
+ "next": "Następna",
+ "last": "Ostatnia"
+ },
+ "aria": {
+ "sortAscending": ": aktywuj, by posortować kolumnę rosnąco",
+ "sortDescending": ": aktywuj, by posortować kolumnę malejąco"
+ }
+}
\ No newline at end of file
diff --git a/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/ps.json b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/ps.json
new file mode 100644
index 0000000..8d77a8d
--- /dev/null
+++ b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/ps.json
@@ -0,0 +1,22 @@
+{
+ "emptyTable": "جدول خالي دی",
+ "info": "د _START_ څخه تر _END_ پوري، له ټولو _TOTAL_ څخه",
+ "infoEmpty": "د 0 څخه تر 0 پوري، له ټولو 0 څخه",
+ "infoFiltered": "(لټول سوي له ټولو _MAX_ څخه)",
+ "infoThousands": ",",
+ "lengthMenu": "_MENU_ کتاره وښايه",
+ "loadingRecords": "منتظر اوسئ...",
+ "processing": "منتظر اوسئ...",
+ "search": "لټون:",
+ "zeroRecords": "د لټون مطابق معلومات و نه موندل سول",
+ "paginate": {
+ "first": "لومړۍ",
+ "last": "وروستۍ",
+ "next": "بله",
+ "previous": "شاته"
+ },
+ "aria": {
+ "sortAscending": ": په صعودي ډول مرتبول",
+ "sortDescending": ": په نزولي ډول مرتبول"
+ }
+}
\ No newline at end of file
diff --git a/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/pt.json b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/pt.json
new file mode 100644
index 0000000..c8a2a8e
--- /dev/null
+++ b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/pt.json
@@ -0,0 +1,37 @@
+{
+ "emptyTable": "Nenhum registro encontrado",
+ "info": "Mostrando de _START_ até _END_ de _TOTAL_ registros",
+ "infoEmpty": "Mostrando 0 até 0 de 0 registros",
+ "infoFiltered": "(Filtrados de _MAX_ registros)",
+ "infoThousands": ".",
+ "lengthMenu": "_MENU_ resultados por página",
+ "loadingRecords": "Carregando...",
+ "processing": "Processando...",
+ "zeroRecords": "Nenhum registro encontrado",
+ "search": "Pesquisar",
+ "paginate": {
+ "next": "Próximo",
+ "previous": "Anterior",
+ "first": "Primeiro",
+ "last": "Último"
+ },
+ "aria": {
+ "sortAscending": ": Ordenar colunas de forma ascendente",
+ "sortDescending": ": Ordenar colunas de forma descendente"
+ },
+ "select": {
+ "rows": {
+ "_": "Selecionado %d linhas",
+ "0": "Nenhuma linha selecionada",
+ "1": "Selecionado 1 linha"
+ }
+ },
+ "buttons": {
+ "copy": "Copiar para a área de transferência",
+ "copyTitle": "Cópia bem sucedida",
+ "copySuccess": {
+ "1": "Uma linha copiada com sucesso",
+ "_": "%d linhas copiadas com sucesso"
+ }
+ }
+}
\ No newline at end of file
diff --git a/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/pt_BR.json b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/pt_BR.json
new file mode 100644
index 0000000..cf32738
--- /dev/null
+++ b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/pt_BR.json
@@ -0,0 +1,131 @@
+{
+ "emptyTable": "Nenhum registro encontrado",
+ "info": "Mostrando de _START_ até _END_ de _TOTAL_ registros",
+ "infoEmpty": "Mostrando 0 até 0 de 0 registros",
+ "infoFiltered": "(Filtrados de _MAX_ registros)",
+ "infoThousands": ".",
+ "loadingRecords": "Carregando...",
+ "processing": "Processando...",
+ "zeroRecords": "Nenhum registro encontrado",
+ "search": "Pesquisar",
+ "paginate": {
+ "next": "Próximo",
+ "previous": "Anterior",
+ "first": "Primeiro",
+ "last": "Último"
+ },
+ "aria": {
+ "sortAscending": ": Ordenar colunas de forma ascendente",
+ "sortDescending": ": Ordenar colunas de forma descendente"
+ },
+ "select": {
+ "rows": {
+ "_": "Selecionado %d linhas",
+ "0": "Nenhuma linha selecionada",
+ "1": "Selecionado 1 linha"
+ },
+ "1": "%d linha selecionada",
+ "_": "%d linhas selecionadas",
+ "cells": {
+ "1": "1 célula selecionada",
+ "_": "%d células selecionadas"
+ },
+ "columns": {
+ "1": "1 coluna selecionada",
+ "_": "%d colunas selecionadas"
+ }
+ },
+ "buttons": {
+ "copySuccess": {
+ "1": "Uma linha copiada com sucesso",
+ "_": "%d linhas copiadas com sucesso"
+ },
+ "collection": "Coleção <\/span>",
+ "colvis": "Visibilidade da Coluna",
+ "colvisRestore": "Restaurar Visibilidade",
+ "copy": "Copiar",
+ "copyKeys": "Pressione ctrl ou u2318 + C para copiar os dados da tabela para a área de transferência do sistema. Para cancelar, clique nesta mensagem ou pressione Esc..",
+ "copyTitle": "Copiar para a Área de Transferência",
+ "csv": "CSV",
+ "excel": "Excel",
+ "pageLength": {
+ "-1": "Mostrar todos os registros",
+ "1": "Mostrar 1 registro",
+ "_": "Mostrar %d registros"
+ },
+ "pdf": "PDF",
+ "print": "Imprimir"
+ },
+ "autoFill": {
+ "cancel": "Cancelar",
+ "fill": "Preencher todas as células com",
+ "fillHorizontal": "Preencher células horizontalmente",
+ "fillVertical": "Preencher células verticalmente"
+ },
+ "lengthMenu": "Exibir _MENU_ resultados por página",
+ "searchBuilder": {
+ "add": "Adicionar Condição",
+ "button": {
+ "0": "Construtor de Pesquisa",
+ "_": "Construtor de Pesquisa (%d)"
+ },
+ "clearAll": "Limpar Tudo",
+ "condition": "Condição",
+ "conditions": {
+ "date": {
+ "after": "Depois",
+ "before": "Antes",
+ "between": "Entre",
+ "empty": "Vazio",
+ "equals": "Igual",
+ "not": "Não",
+ "notBetween": "Não Entre",
+ "notEmpty": "Não Vazio"
+ },
+ "number": {
+ "between": "Entre",
+ "empty": "Vazio",
+ "equals": "Igual",
+ "gt": "Maior Que",
+ "gte": "Maior ou Igual a",
+ "lt": "Menor Que",
+ "lte": "Menor ou Igual a",
+ "not": "Não",
+ "notBetween": "Não Entre",
+ "notEmpty": "Não Vazio"
+ },
+ "string": {
+ "contains": "Contém",
+ "empty": "Vazio",
+ "endsWith": "Termina Com",
+ "equals": "Igual",
+ "not": "Não",
+ "notEmpty": "Não Vazio",
+ "startsWith": "Começa Com"
+ }
+ },
+ "data": "Data",
+ "deleteTitle": "Excluir regra de filtragem",
+ "logicAnd": "E",
+ "logicOr": "Ou",
+ "title": {
+ "0": "Construtor de Pesquisa",
+ "_": "Construtor de Pesquisa (%d)"
+ },
+ "value": "Valor"
+ },
+ "searchPanes": {
+ "clearMessage": "Limpar Tudo",
+ "collapse": {
+ "0": "Painéis de Pesquisa",
+ "_": "Painéis de Pesquisa (%d)"
+ },
+ "count": "{total}",
+ "countFiltered": "{shown} ({total})",
+ "emptyPanes": "Nenhum Painel de Pesquisa",
+ "loadMessage": "Carregando Painéis de Pesquisa...",
+ "title": "Filtros Ativos"
+ },
+ "searchPlaceholder": "Digite um termo para pesquisar",
+ "thousands": "."
+}
\ No newline at end of file
diff --git a/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/pt_pt.json b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/pt_pt.json
new file mode 100644
index 0000000..87aef58
--- /dev/null
+++ b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/pt_pt.json
@@ -0,0 +1,21 @@
+{
+ "emptyTable": "Não foi encontrado nenhum registo",
+ "loadingRecords": "A carregar...",
+ "processing": "A processar...",
+ "lengthMenu": "Mostrar _MENU_ registos",
+ "zeroRecords": "Não foram encontrados resultados",
+ "info": "Mostrando de _START_ até _END_ de _TOTAL_ registos",
+ "infoEmpty": "Mostrando de 0 até 0 de 0 registos",
+ "infoFiltered": "(filtrado de _MAX_ registos no total)",
+ "search": "Procurar:",
+ "paginate": {
+ "first": "Primeiro",
+ "previous": "Anterior",
+ "next": "Seguinte",
+ "last": "Último"
+ },
+ "aria": {
+ "sortAscending": ": Ordenar colunas de forma ascendente",
+ "sortDescending": ": Ordenar colunas de forma descendente"
+ }
+}
\ No newline at end of file
diff --git a/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/rm.json b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/rm.json
new file mode 100644
index 0000000..3b46a64
--- /dev/null
+++ b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/rm.json
@@ -0,0 +1,43 @@
+{
+ "emptyTable": "Naginas endataziuns",
+ "info": "_START_ fin _END_ da _TOTAL_ endataziuns",
+ "infoEmpty": "Naginas endataziuns",
+ "infoFiltered": "(filtrà da _MAX_ endataziuns)",
+ "infoThousands": ".",
+ "lengthMenu": "_MENU_ Dumber da cumparsas",
+ "loadingRecords": "vegn chargià ..",
+ "processing": "Spetgar p.pl...",
+ "search": "Tschertga",
+ "zeroRecords": "Naginas endataziuns.",
+ "paginate": {
+ "first": "Emprima",
+ "previous": "Anavos",
+ "next": "Proxima",
+ "last": "Ultima"
+ },
+ "aria": {
+ "sortAscending": ": activar per zavrar las colonnas ensi",
+ "sortDescending": ": activar per zavrar las colonnas engiu"
+ },
+ "select": {
+ "rows": {
+ "_": "%d lingias selecziunadas",
+ "1": "1 lingia selecziunada"
+ }
+ },
+ "buttons": {
+ "print": "Stampar",
+ "colvis": "Colonnas",
+ "copy": "Copiar",
+ "copyTitle": "Copiar en l'archiv provisoric",
+ "copyKeys": "Tasta ctrl<\/i> u ⌘<\/i> + C<\/i> per copiar la tabella en l'arcun provisoric. Per interrumper cliccar il messadi u smatgar Escape",
+ "copySuccess": {
+ "_": "%d lingias copiadas",
+ "1": "1 lingia copiada"
+ },
+ "pageLength": {
+ "-1": "Mussar tut las lingias",
+ "_": "Mussar %d lingias"
+ }
+ }
+}
\ No newline at end of file
diff --git a/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/ro.json b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/ro.json
new file mode 100644
index 0000000..d2cfa28
--- /dev/null
+++ b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/ro.json
@@ -0,0 +1,15 @@
+{
+ "processing": "Procesează...",
+ "lengthMenu": "Afișează _MENU_ înregistrări pe pagină",
+ "zeroRecords": "Nu am găsit nimic - ne pare rău",
+ "info": "Afișate de la _START_ la _END_ din _TOTAL_ înregistrări",
+ "infoEmpty": "Afișate de la 0 la 0 din 0 înregistrări",
+ "infoFiltered": "(filtrate dintr-un total de _MAX_ înregistrări)",
+ "search": "Caută:",
+ "paginate": {
+ "first": "Prima",
+ "previous": "Precedenta",
+ "next": "Următoarea",
+ "last": "Ultima"
+ }
+}
\ No newline at end of file
diff --git a/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/ru.json b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/ru.json
new file mode 100644
index 0000000..ee68ac5
--- /dev/null
+++ b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/ru.json
@@ -0,0 +1,28 @@
+{
+ "processing": "Подождите...",
+ "search": "Поиск:",
+ "lengthMenu": "Показать _MENU_ записей",
+ "info": "Записи с _START_ до _END_ из _TOTAL_ записей",
+ "infoEmpty": "Записи с 0 до 0 из 0 записей",
+ "infoFiltered": "(отфильтровано из _MAX_ записей)",
+ "loadingRecords": "Загрузка записей...",
+ "zeroRecords": "Записи отсутствуют.",
+ "emptyTable": "В таблице отсутствуют данные",
+ "paginate": {
+ "first": "Первая",
+ "previous": "Предыдущая",
+ "next": "Следующая",
+ "last": "Последняя"
+ },
+ "aria": {
+ "sortAscending": ": активировать для сортировки столбца по возрастанию",
+ "sortDescending": ": активировать для сортировки столбца по убыванию"
+ },
+ "select": {
+ "rows": {
+ "_": "Выбрано записей: %d",
+ "0": "Кликните по записи для выбора",
+ "1": "Выбрана одна запись"
+ }
+ }
+}
\ No newline at end of file
diff --git a/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/si.json b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/si.json
new file mode 100644
index 0000000..8817d6b
--- /dev/null
+++ b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/si.json
@@ -0,0 +1,22 @@
+{
+ "emptyTable": "වගුවේ දත්ත කිසිවක් නොමැත",
+ "info": "_TOTAL_ න් _START_ සිට _END_ දක්වා",
+ "infoEmpty": "0 න් 0 සිට 0 දක්වා",
+ "infoFiltered": "(_MAX_ න් තෝරාගත් )",
+ "infoThousands": ",",
+ "lengthMenu": "_MENU_ ක් පෙන්වන්න",
+ "loadingRecords": "පූරණය වෙමින් පවතී...",
+ "processing": "සැකසෙමින් පවතී...",
+ "search": "සොයන්න :",
+ "zeroRecords": "ගැලපෙන වාර්තා නොමැත.",
+ "paginate": {
+ "first": "පළමු",
+ "last": "අන්තිම",
+ "next": "ඊළග",
+ "previous": "පසුගිය"
+ },
+ "aria": {
+ "sortAscending": ": තීරුව ආරෝහනව තෝරන්න",
+ "sortDescending": ": තීරුව අවරෝහනව තෝරන්න"
+ }
+}
\ No newline at end of file
diff --git a/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/sk.json b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/sk.json
new file mode 100644
index 0000000..042d4e2
--- /dev/null
+++ b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/sk.json
@@ -0,0 +1,22 @@
+{
+ "emptyTable": "Nie sú k dispozícii žiadne dáta",
+ "info": "Záznamy _START_ až _END_ z celkom _TOTAL_",
+ "infoEmpty": "Záznamy 0 až 0 z celkom 0 ",
+ "infoFiltered": "(vyfiltrované spomedzi _MAX_ záznamov)",
+ "infoThousands": " ",
+ "lengthMenu": "Zobraz _MENU_ záznamov",
+ "loadingRecords": "Načítavam...",
+ "processing": "Spracúvam...",
+ "search": "Hľadať:",
+ "zeroRecords": "Nenašli sa žiadne vyhovujúce záznamy",
+ "paginate": {
+ "first": "Prvá",
+ "last": "Posledná",
+ "next": "Nasledujúca",
+ "previous": "Predchádzajúca"
+ },
+ "aria": {
+ "sortAscending": ": aktivujte na zoradenie stĺpca vzostupne",
+ "sortDescending": ": aktivujte na zoradenie stĺpca zostupne"
+ }
+}
\ No newline at end of file
diff --git a/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/sl.json b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/sl.json
new file mode 100644
index 0000000..eea2938
--- /dev/null
+++ b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/sl.json
@@ -0,0 +1,22 @@
+{
+ "emptyTable": "Nobenih podatkov ni na voljo",
+ "info": "Prikazujem _START_ do _END_ od _TOTAL_ zapisov",
+ "infoEmpty": "Prikazujem 0 do 0 od 0 zapisov",
+ "infoFiltered": "(filtrirano od _MAX_ vseh zapisov)",
+ "infoThousands": ",",
+ "lengthMenu": "Prikaži _MENU_ zapisov",
+ "loadingRecords": "Nalagam...",
+ "processing": "Obdelujem...",
+ "search": "Išči:",
+ "zeroRecords": "Nobeden zapis ne ustreza",
+ "paginate": {
+ "first": "Prvi",
+ "last": "Zadnji",
+ "next": "Nasl.",
+ "previous": "Pred."
+ },
+ "aria": {
+ "sortAscending": ": vključite za naraščujoči sort",
+ "sortDescending": ": vključite za padajoči sort"
+ }
+}
\ No newline at end of file
diff --git a/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/snd.json b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/snd.json
new file mode 100644
index 0000000..b91cec9
--- /dev/null
+++ b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/snd.json
@@ -0,0 +1,30 @@
+{
+ "autoFill": {
+ "cancel": "منسوخ"
+ },
+ "buttons": {
+ "collection": "سھيڙ",
+ "colvis": "ڪالم جو ڏيک",
+ "colvisRestore": "ڏيک ڦيرايو",
+ "copy": "ڪاپي ڪريو",
+ "copyTitle": "ڪلپ بورڊ ۾ ڪاپي ڪريو",
+ "csv": "سي.ايس.وِي",
+ "excel": "ايڪسل",
+ "pdf": "پي.ڊي.ايف",
+ "print": "پرنٽ"
+ },
+ "emptyTable": "ٽيبل ۾ ڪوبہ مواد ناھي",
+ "paginate": {
+ "first": "پھريون",
+ "last": "آخري",
+ "next": "اڳيون",
+ "previous": "پويون"
+ },
+ "processing": "پراسيس ڪري رھيو آھي",
+ "search": "ڳولا",
+ "searchBuilder": {
+ "add": "سھيڙ شامل ڪريو",
+ "clearAll": "سڀ صاف ڪريو",
+ "data": "ڊيٽا"
+ }
+}
\ No newline at end of file
diff --git a/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/sq.json b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/sq.json
new file mode 100644
index 0000000..823ef2f
--- /dev/null
+++ b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/sq.json
@@ -0,0 +1,22 @@
+{
+ "emptyTable": "Nuk ka asnjë të dhënë në tabele",
+ "info": "Duke treguar _START_ deri _END_ prej _TOTAL_ reshtave",
+ "infoEmpty": "Duke treguar 0 deri 0 prej 0 reshtave",
+ "infoFiltered": "(të filtruara nga gjithësej _MAX_ reshtave)",
+ "infoThousands": ",",
+ "lengthMenu": "Shiko _MENU_ reshta",
+ "loadingRecords": "Duke punuar...",
+ "processing": "Duke procesuar...",
+ "search": "Kërkoni:",
+ "zeroRecords": "Asnjë e dhënë nuk u gjet",
+ "paginate": {
+ "first": "E para",
+ "last": "E Fundit",
+ "next": "Tjetra",
+ "previous": "E Kaluara"
+ },
+ "aria": {
+ "sortAscending": ": aktivizo për të sortuar kolumnin me vlera në ngritje",
+ "sortDescending": ": aktivizo për të sortuar kolumnin me vlera në zbritje"
+ }
+}
\ No newline at end of file
diff --git a/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/sr.json b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/sr.json
new file mode 100644
index 0000000..4106ef8
--- /dev/null
+++ b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/sr.json
@@ -0,0 +1,22 @@
+{
+ "emptyTable": "Нема података у табели",
+ "info": "Приказ _START_ до _END_ од укупно _TOTAL_ записа",
+ "infoEmpty": "Приказ 0 до 0 од укупно 0 записа",
+ "infoFiltered": "(филтрирано од укупно _MAX_ записа)",
+ "infoThousands": ".",
+ "lengthMenu": "Прикажи _MENU_ записа",
+ "loadingRecords": "Учитавање...",
+ "processing": "Обрада...",
+ "search": "Претрага:",
+ "zeroRecords": "Нису пронађени одговарајући записи",
+ "paginate": {
+ "first": "Почетна",
+ "last": "Последња",
+ "next": "Следећа",
+ "previous": "Претходна"
+ },
+ "aria": {
+ "sortAscending": ": активирајте да сортирате колону узлазно",
+ "sortDescending": ": активирајте да сортирате колону силазно"
+ }
+}
\ No newline at end of file
diff --git a/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/sr@latin.json b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/sr@latin.json
new file mode 100644
index 0000000..90d1720
--- /dev/null
+++ b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/sr@latin.json
@@ -0,0 +1,22 @@
+{
+ "emptyTable": "Nema podataka u tabeli",
+ "info": "Prikaz _START_ do _END_ od ukupno _TOTAL_ zapisa",
+ "infoEmpty": "Prikaz 0 do 0 od ukupno 0 zapisa",
+ "infoFiltered": "(filtrirano od ukupno _MAX_ zapisa)",
+ "infoThousands": ".",
+ "lengthMenu": "Prikaži _MENU_ zapisa",
+ "loadingRecords": "Učitavanje...",
+ "processing": "Obrada...",
+ "search": "Pretraga:",
+ "zeroRecords": "Nisu pronađeni odgovarajući zapisi",
+ "paginate": {
+ "first": "Početna",
+ "last": "Poslednja",
+ "next": "Sledeća",
+ "previous": "Prethodna"
+ },
+ "aria": {
+ "sortAscending": ": aktivirajte da sortirate kolonu uzlazno",
+ "sortDescending": ": aktivirajte da sortirate kolonu silazno"
+ }
+}
\ No newline at end of file
diff --git a/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/sr_sp.json b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/sr_sp.json
new file mode 100644
index 0000000..90d1720
--- /dev/null
+++ b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/sr_sp.json
@@ -0,0 +1,22 @@
+{
+ "emptyTable": "Nema podataka u tabeli",
+ "info": "Prikaz _START_ do _END_ od ukupno _TOTAL_ zapisa",
+ "infoEmpty": "Prikaz 0 do 0 od ukupno 0 zapisa",
+ "infoFiltered": "(filtrirano od ukupno _MAX_ zapisa)",
+ "infoThousands": ".",
+ "lengthMenu": "Prikaži _MENU_ zapisa",
+ "loadingRecords": "Učitavanje...",
+ "processing": "Obrada...",
+ "search": "Pretraga:",
+ "zeroRecords": "Nisu pronađeni odgovarajući zapisi",
+ "paginate": {
+ "first": "Početna",
+ "last": "Poslednja",
+ "next": "Sledeća",
+ "previous": "Prethodna"
+ },
+ "aria": {
+ "sortAscending": ": aktivirajte da sortirate kolonu uzlazno",
+ "sortDescending": ": aktivirajte da sortirate kolonu silazno"
+ }
+}
\ No newline at end of file
diff --git a/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/sv.json b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/sv.json
new file mode 100644
index 0000000..b8c0d49
--- /dev/null
+++ b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/sv.json
@@ -0,0 +1,22 @@
+{
+ "emptyTable": "Tabellen innehåller inga data",
+ "info": "Visar _START_ till _END_ av totalt _TOTAL_ rader",
+ "infoEmpty": "Visar 0 till 0 av totalt 0 rader",
+ "infoFiltered": "(filtrerade från totalt _MAX_ rader)",
+ "infoThousands": " ",
+ "lengthMenu": "Visa _MENU_ rader",
+ "loadingRecords": "Laddar …",
+ "processing": "Bearbetar …",
+ "search": "Sök:",
+ "zeroRecords": "Hittade inga matchande resultat",
+ "paginate": {
+ "first": "Första",
+ "last": "Sista",
+ "next": "Nästa",
+ "previous": "Föregående"
+ },
+ "aria": {
+ "sortAscending": ": aktivera för att sortera kolumnen i stigande ordning",
+ "sortDescending": ": aktivera för att sortera kolumnen i fallande ordning"
+ }
+}
\ No newline at end of file
diff --git a/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/sw.json b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/sw.json
new file mode 100644
index 0000000..bf9f44a
--- /dev/null
+++ b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/sw.json
@@ -0,0 +1,22 @@
+{
+ "emptyTable": "Hakuna data iliyo patikana",
+ "info": "Inaonyesha _START_ mpaka _END_ ya matokeo _TOTAL_",
+ "infoEmpty": "Inaonyesha 0 hadi 0 ya matokeo 0",
+ "infoFiltered": "(uschujo kutoka matokeo idadi _MAX_)",
+ "infoThousands": ",",
+ "lengthMenu": "Onyesha _MENU_ matokeo",
+ "loadingRecords": "Inapakia...",
+ "processing": "Processing...",
+ "search": "Tafuta:",
+ "zeroRecords": "Rekodi vinavyolingana haziku patikana",
+ "paginate": {
+ "first": "Mwanzo",
+ "last": "Mwisho",
+ "next": "Ijayo",
+ "previous": "Kabla"
+ },
+ "aria": {
+ "sortAscending": ": seti kulainisha sanjari kwa mtindo wa upandaji",
+ "sortDescending": ": seti kulainisha sanjari kwa mtindo wa mteremko"
+ }
+}
\ No newline at end of file
diff --git a/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/ta.json b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/ta.json
new file mode 100644
index 0000000..58047e9
--- /dev/null
+++ b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/ta.json
@@ -0,0 +1,22 @@
+{
+ "emptyTable": "அட்டவணையில் தரவு கிடைக்கவில்லை",
+ "info": "உள்ளீடுகளை் _START_ முதல _END_ உள்ள _TOTAL_ காட்டும்",
+ "infoEmpty": "0 உள்ளீடுகளை 0 0 காட்டும்",
+ "infoFiltered": "(_MAX_ மொத்த உள்ளீடுகளை இருந்து வடிகட்டி)",
+ "infoThousands": ",",
+ "lengthMenu": "_MENU_ காண்பி",
+ "loadingRecords": "ஏற்றுகிறது ...",
+ "processing": "செயலாக்க ...",
+ "search": "தேடல்:",
+ "zeroRecords": "பொருத்தமான பதிவுகள் இல்லை",
+ "paginate": {
+ "first": "முதல்",
+ "last": "இறுதி",
+ "next": "அடுத்து",
+ "previous": "முந்தைய"
+ },
+ "aria": {
+ "sortAscending": ": நிரலை ஏறுவரிசையில் வரிசைப்படுத்த செயல்படுத்த",
+ "sortDescending": ": நிரலை இறங்கு வரிசைப்படுத்த செயல்படுத்த"
+ }
+}
\ No newline at end of file
diff --git a/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/te.json b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/te.json
new file mode 100644
index 0000000..b8b1b32
--- /dev/null
+++ b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/te.json
@@ -0,0 +1,22 @@
+{
+ "emptyTable": "పట్టికలో డేటా లేదు.",
+ "info": "మొత్తం _TOTAL_ ఎంట్రీలులో _START_ నుండి _END_ వరకు చూపిస్తున్నాం",
+ "infoEmpty": "చూపిస్తున్నాం 0 నుండి 0 వరకు 0 ఎంట్రీలు లో",
+ "infoFiltered": "( _MAX_ ఎంట్రీలులో నుండి వడపోయాబడినవి)",
+ "infoThousands": ",",
+ "lengthMenu": " _MENU_ ఎంట్రీలు చూపించు",
+ "loadingRecords": "లోడ్ అవుతుంది ...",
+ "processing": "ప్రాసెస్ చేయబడుతుంది...",
+ "search": "వెతుకు:",
+ "zeroRecords": "మ్యాచింగ్ రికార్డులు లేవు",
+ "paginate": {
+ "first": "మొదటి",
+ "last": "చివరి",
+ "next": "తర్వాత",
+ "previous": "మునుపటి"
+ },
+ "aria": {
+ "sortAscending": ": నిలువరుసను ఆరోహణ క్రమం అమర్చండి",
+ "sortDescending": ": నిలువరుసను అవరోహణ క్రమం అమర్చండి"
+ }
+}
\ No newline at end of file
diff --git a/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/tg.json b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/tg.json
new file mode 100644
index 0000000..87f4bad
--- /dev/null
+++ b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/tg.json
@@ -0,0 +1,28 @@
+{
+ "processing": "Интизор шавед...",
+ "search": "Ҷустуҷӯ:",
+ "lengthMenu": "Намоиши сабтҳои _MENU_",
+ "info": "Сабтҳо аз _START_ то _END_ аз _TOTAL_ сабтҳо",
+ "infoEmpty": "Сабтҳо аз 0 то 0 аз 0 сабтҳо",
+ "infoFiltered": "(филтр карда шудааст аз _MAX_ сабтҳо)",
+ "loadingRecords": "Боргирии сабтҳо...",
+ "zeroRecords": "Сабтҳо вуҷуд надорад.",
+ "emptyTable": "Дар ҷадвал маълумот нест",
+ "paginate": {
+ "first": "Якум",
+ "previous": "Ба қафо",
+ "next": "Ба пеш",
+ "last": "Охирон"
+ },
+ "aria": {
+ "sortAscending": ": фаъолкунӣ барои ҷобаҷогузории сатрҳо аз рӯи бисёршавӣ",
+ "sortDescending": ": фаъолкунӣ барои ҷобаҷогузории сатрҳо аз рӯи камшавӣ"
+ },
+ "select": {
+ "rows": {
+ "_": "Сабтҳо интихобшуда: %d",
+ "0": "Барои интихоб сабтро пахш намоед",
+ "1": "Як сабт интихоб шудааст"
+ }
+ }
+}
\ No newline at end of file
diff --git a/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/th.json b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/th.json
new file mode 100644
index 0000000..9e6b3b5
--- /dev/null
+++ b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/th.json
@@ -0,0 +1,22 @@
+{
+ "emptyTable": "ไม่มีข้อมูลในตาราง",
+ "info": "แสดง _START_ ถึง _END_ จาก _TOTAL_ แถว",
+ "infoEmpty": "แสดง 0 ถึง 0 จาก 0 แถว",
+ "infoFiltered": "(กรองข้อมูล _MAX_ ทุกแถว)",
+ "infoThousands": ",",
+ "lengthMenu": "แสดง _MENU_ แถว",
+ "loadingRecords": "กำลังโหลดข้อมูล...",
+ "processing": "กำลังดำเนินการ...",
+ "search": "ค้นหา: ",
+ "zeroRecords": "ไม่พบข้อมูล",
+ "paginate": {
+ "first": "หน้าแรก",
+ "previous": "ก่อนหน้า",
+ "next": "ถัดไป",
+ "last": "หน้าสุดท้าย"
+ },
+ "aria": {
+ "sortAscending": ": เปิดใช้งานการเรียงข้อมูลจากน้อยไปมาก",
+ "sortDescending": ": เปิดใช้งานการเรียงข้อมูลจากมากไปน้อย"
+ }
+}
\ No newline at end of file
diff --git a/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/tl.json b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/tl.json
new file mode 100644
index 0000000..32f3962
--- /dev/null
+++ b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/tl.json
@@ -0,0 +1,15 @@
+{
+ "processing": "Pagproseso...",
+ "lengthMenu": "Ipakita _MENU_ entries",
+ "zeroRecords": "Walang katugmang mga talaan na natagpuan",
+ "info": "Ipinapakita ang _START_ sa _END_ ng _TOTAL_ entries",
+ "infoEmpty": "Ipinapakita ang 0-0 ng 0 entries",
+ "infoFiltered": "(na-filter mula _MAX_ kabuuang entries)",
+ "search": "Paghahanap:",
+ "paginate": {
+ "first": "Unang",
+ "previous": "Nakaraan",
+ "next": "Susunod",
+ "last": "Huli"
+ }
+}
\ No newline at end of file
diff --git a/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/tr.json b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/tr.json
new file mode 100644
index 0000000..e9dcbdb
--- /dev/null
+++ b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/tr.json
@@ -0,0 +1,29 @@
+{
+ "decimal": ",",
+ "emptyTable": "Tabloda herhangi bir veri mevcut değil",
+ "info": "_TOTAL_ kayıttan _START_ - _END_ arasındaki kayıtlar gösteriliyor",
+ "infoEmpty": "Kayıt yok",
+ "infoFiltered": "(_MAX_ kayıt içerisinden bulunan)",
+ "infoThousands": ".",
+ "lengthMenu": "Sayfada _MENU_ kayıt göster",
+ "loadingRecords": "Yükleniyor...",
+ "processing": "İşleniyor...",
+ "search": "Ara:",
+ "zeroRecords": "Eşleşen kayıt bulunamadı",
+ "paginate": {
+ "first": "İlk",
+ "last": "Son",
+ "next": "Sonraki",
+ "previous": "Önceki"
+ },
+ "aria": {
+ "sortAscending": ": artan sütun sıralamasını aktifleştir",
+ "sortDescending": ": azalan sütun sıralamasını aktifleştir"
+ },
+ "select": {
+ "rows": {
+ "_": "%d kayıt seçildi",
+ "1": "1 kayıt seçildi"
+ }
+ }
+}
\ No newline at end of file
diff --git a/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/uk.json b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/uk.json
new file mode 100644
index 0000000..cef2f02
--- /dev/null
+++ b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/uk.json
@@ -0,0 +1,19 @@
+{
+ "processing": "Зачекайте...",
+ "lengthMenu": "Показати _MENU_ записів",
+ "zeroRecords": "Записи відсутні.",
+ "info": "Записи з _START_ по _END_ із _TOTAL_ записів",
+ "infoEmpty": "Записи з 0 по 0 із 0 записів",
+ "infoFiltered": "(відфільтровано з _MAX_ записів)",
+ "search": "Пошук:",
+ "paginate": {
+ "first": "Перша",
+ "previous": "Попередня",
+ "next": "Наступна",
+ "last": "Остання"
+ },
+ "aria": {
+ "sortAscending": ": активувати для сортування стовпців за зростанням",
+ "sortDescending": ": активувати для сортування стовпців за спаданням"
+ }
+}
\ No newline at end of file
diff --git a/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/ur.json b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/ur.json
new file mode 100644
index 0000000..70e6991
--- /dev/null
+++ b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/ur.json
@@ -0,0 +1,15 @@
+{
+ "processing": "ہے جاري عملدرامد...",
+ "lengthMenu": "دکہائين شقيں کي (_MENU_) فہرست",
+ "zeroRecords": "ملے نہيں مفروضات جلتے ملتے کوئ",
+ "info": "فہرست کي تک _END_ سے _START_ سے ميں _TOTAL_ فہرست پوري ہے نظر پيش",
+ "infoEmpty": "فہرست کي تک 0 سے 0 سے ميں 0 قل ہے نظر پيشّ",
+ "infoFiltered": "(فہرست ہوئ چھني سے ميں _MAX_ قل)",
+ "search": "کرو تلاش:",
+ "paginate": {
+ "first": "پہلا",
+ "previous": "پچہلا",
+ "next": "اگلا",
+ "last": "آخري"
+ }
+}
\ No newline at end of file
diff --git a/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/uz.json b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/uz.json
new file mode 100644
index 0000000..c2b9017
--- /dev/null
+++ b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/uz.json
@@ -0,0 +1,21 @@
+{
+ "emptyTable": "Ma'lumot yo'q",
+ "info": "Umumiy _TOTAL_ yozuvlarlardan _START_ dan _END_ gachasi ko'rsatilmoqda",
+ "infoEmpty": "Umumiy 0 yozuvlardan 0 dan 0 gachasi ko'rsatilmoqda",
+ "infoFiltered": "(_MAX_ yozuvlardan filtrlandi)",
+ "lengthMenu": "_MENU_ ta yozuvlarni ko'rsat",
+ "loadingRecords": "Yozuvlar yuklanmoqda...",
+ "processing": "Ishlayapman...",
+ "search": "Izlash:",
+ "zeroRecords": "Ma'lumot yo'q.",
+ "paginate": {
+ "first": "Birinchi",
+ "previous": "Avvalgi",
+ "next": "Keyingi",
+ "last": "Son'ggi"
+ },
+ "aria": {
+ "sortAscending": ": to'g'ri tartiblash",
+ "sortDescending": ": teskari tartiblash"
+ }
+}
\ No newline at end of file
diff --git a/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/vi.json b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/vi.json
new file mode 100644
index 0000000..d56d032
--- /dev/null
+++ b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/vi.json
@@ -0,0 +1,15 @@
+{
+ "processing": "Đang xử lý...",
+ "lengthMenu": "Xem _MENU_ mục",
+ "zeroRecords": "Không tìm thấy dòng nào phù hợp",
+ "info": "Đang xem _START_ đến _END_ trong tổng số _TOTAL_ mục",
+ "infoEmpty": "Đang xem 0 đến 0 trong tổng số 0 mục",
+ "infoFiltered": "(được lọc từ _MAX_ mục)",
+ "search": "Tìm:",
+ "paginate": {
+ "first": "Đầu",
+ "previous": "Trước",
+ "next": "Tiếp",
+ "last": "Cuối"
+ }
+}
\ No newline at end of file
diff --git a/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/zh.json b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/zh.json
new file mode 100644
index 0000000..387725e
--- /dev/null
+++ b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/zh.json
@@ -0,0 +1,22 @@
+{
+ "processing": "处理中...",
+ "lengthMenu": "显示 _MENU_ 项结果",
+ "zeroRecords": "没有匹配结果",
+ "info": "显示第 _START_ 至 _END_ 项结果,共 _TOTAL_ 项",
+ "infoEmpty": "显示第 0 至 0 项结果,共 0 项",
+ "infoFiltered": "(由 _MAX_ 项结果过滤)",
+ "search": "搜索:",
+ "emptyTable": "表中数据为空",
+ "loadingRecords": "载入中...",
+ "infoThousands": ",",
+ "paginate": {
+ "first": "首页",
+ "previous": "上页",
+ "next": "下页",
+ "last": "末页"
+ },
+ "aria": {
+ "sortAscending": ": 以升序排列此列",
+ "sortDescending": ": 以降序排列此列"
+ }
+}
\ No newline at end of file
diff --git a/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/zh_CN.json b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/zh_CN.json
new file mode 100644
index 0000000..387725e
--- /dev/null
+++ b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/zh_CN.json
@@ -0,0 +1,22 @@
+{
+ "processing": "处理中...",
+ "lengthMenu": "显示 _MENU_ 项结果",
+ "zeroRecords": "没有匹配结果",
+ "info": "显示第 _START_ 至 _END_ 项结果,共 _TOTAL_ 项",
+ "infoEmpty": "显示第 0 至 0 项结果,共 0 项",
+ "infoFiltered": "(由 _MAX_ 项结果过滤)",
+ "search": "搜索:",
+ "emptyTable": "表中数据为空",
+ "loadingRecords": "载入中...",
+ "infoThousands": ",",
+ "paginate": {
+ "first": "首页",
+ "previous": "上页",
+ "next": "下页",
+ "last": "末页"
+ },
+ "aria": {
+ "sortAscending": ": 以升序排列此列",
+ "sortDescending": ": 以降序排列此列"
+ }
+}
\ No newline at end of file
diff --git a/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/zh_Hant.json b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/zh_Hant.json
new file mode 100644
index 0000000..d8d30c6
--- /dev/null
+++ b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/i18n/zh_Hant.json
@@ -0,0 +1,20 @@
+{
+ "processing": "處理中...",
+ "loadingRecords": "載入中...",
+ "lengthMenu": "顯示 _MENU_ 項結果",
+ "zeroRecords": "沒有符合的結果",
+ "info": "顯示第 _START_ 至 _END_ 項結果,共 _TOTAL_ 項",
+ "infoEmpty": "顯示第 0 至 0 項結果,共 0 項",
+ "infoFiltered": "(從 _MAX_ 項結果中過濾)",
+ "search": "搜尋:",
+ "paginate": {
+ "first": "第一頁",
+ "previous": "上一頁",
+ "next": "下一頁",
+ "last": "最後一頁"
+ },
+ "aria": {
+ "sortAscending": ": 升冪排列",
+ "sortDescending": ": 降冪排列"
+ }
+}
\ No newline at end of file
diff --git a/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/jquery.mark.js b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/jquery.mark.js
new file mode 100644
index 0000000..e20b237
--- /dev/null
+++ b/ckanext/og_datatables_datefilterview/assets/vendor/DataTables/jquery.mark.js
@@ -0,0 +1,1228 @@
+/*!***************************************************
+* mark.js v9.0.0
+* https://markjs.io/
+* Copyright (c) 2014–2018, Julian Kühnel
+* Released under the MIT license https://git.io/vwTVl
+*****************************************************/
+
+(function (global, factory) {
+ typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('jquery')) :
+ typeof define === 'function' && define.amd ? define(['jquery'], factory) :
+ (global.Mark = factory(global.jQuery));
+}(this, (function ($) { 'use strict';
+
+ $ = $ && $.hasOwnProperty('default') ? $['default'] : $;
+
+ function _typeof(obj) {
+ if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") {
+ _typeof = function (obj) {
+ return typeof obj;
+ };
+ } else {
+ _typeof = function (obj) {
+ return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
+ };
+ }
+
+ return _typeof(obj);
+ }
+
+ function _classCallCheck(instance, Constructor) {
+ if (!(instance instanceof Constructor)) {
+ throw new TypeError("Cannot call a class as a function");
+ }
+ }
+
+ function _defineProperties(target, props) {
+ for (var i = 0; i < props.length; i++) {
+ var descriptor = props[i];
+ descriptor.enumerable = descriptor.enumerable || false;
+ descriptor.configurable = true;
+ if ("value" in descriptor) descriptor.writable = true;
+ Object.defineProperty(target, descriptor.key, descriptor);
+ }
+ }
+
+ function _createClass(Constructor, protoProps, staticProps) {
+ if (protoProps) _defineProperties(Constructor.prototype, protoProps);
+ if (staticProps) _defineProperties(Constructor, staticProps);
+ return Constructor;
+ }
+
+ function _extends() {
+ _extends = Object.assign || function (target) {
+ for (var i = 1; i < arguments.length; i++) {
+ var source = arguments[i];
+
+ for (var key in source) {
+ if (Object.prototype.hasOwnProperty.call(source, key)) {
+ target[key] = source[key];
+ }
+ }
+ }
+
+ return target;
+ };
+
+ return _extends.apply(this, arguments);
+ }
+
+ var DOMIterator =
+ /*#__PURE__*/
+ function () {
+ function DOMIterator(ctx) {
+ var iframes = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
+ var exclude = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : [];
+ var iframesTimeout = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 5000;
+
+ _classCallCheck(this, DOMIterator);
+
+ this.ctx = ctx;
+ this.iframes = iframes;
+ this.exclude = exclude;
+ this.iframesTimeout = iframesTimeout;
+ }
+
+ _createClass(DOMIterator, [{
+ key: "getContexts",
+ value: function getContexts() {
+ var ctx,
+ filteredCtx = [];
+
+ if (typeof this.ctx === 'undefined' || !this.ctx) {
+ ctx = [];
+ } else if (NodeList.prototype.isPrototypeOf(this.ctx)) {
+ ctx = Array.prototype.slice.call(this.ctx);
+ } else if (Array.isArray(this.ctx)) {
+ ctx = this.ctx;
+ } else if (typeof this.ctx === 'string') {
+ ctx = Array.prototype.slice.call(document.querySelectorAll(this.ctx));
+ } else {
+ ctx = [this.ctx];
+ }
+
+ ctx.forEach(function (ctx) {
+ var isDescendant = filteredCtx.filter(function (contexts) {
+ return contexts.contains(ctx);
+ }).length > 0;
+
+ if (filteredCtx.indexOf(ctx) === -1 && !isDescendant) {
+ filteredCtx.push(ctx);
+ }
+ });
+ return filteredCtx;
+ }
+ }, {
+ key: "getIframeContents",
+ value: function getIframeContents(ifr, successFn) {
+ var errorFn = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : function () {};
+ var doc;
+
+ try {
+ var ifrWin = ifr.contentWindow;
+ doc = ifrWin.document;
+
+ if (!ifrWin || !doc) {
+ throw new Error('iframe inaccessible');
+ }
+ } catch (e) {
+ errorFn();
+ }
+
+ if (doc) {
+ successFn(doc);
+ }
+ }
+ }, {
+ key: "isIframeBlank",
+ value: function isIframeBlank(ifr) {
+ var bl = 'about:blank',
+ src = ifr.getAttribute('src').trim(),
+ href = ifr.contentWindow.location.href;
+ return href === bl && src !== bl && src;
+ }
+ }, {
+ key: "observeIframeLoad",
+ value: function observeIframeLoad(ifr, successFn, errorFn) {
+ var _this = this;
+
+ var called = false,
+ tout = null;
+
+ var listener = function listener() {
+ if (called) {
+ return;
+ }
+
+ called = true;
+ clearTimeout(tout);
+
+ try {
+ if (!_this.isIframeBlank(ifr)) {
+ ifr.removeEventListener('load', listener);
+
+ _this.getIframeContents(ifr, successFn, errorFn);
+ }
+ } catch (e) {
+ errorFn();
+ }
+ };
+
+ ifr.addEventListener('load', listener);
+ tout = setTimeout(listener, this.iframesTimeout);
+ }
+ }, {
+ key: "onIframeReady",
+ value: function onIframeReady(ifr, successFn, errorFn) {
+ try {
+ if (ifr.contentWindow.document.readyState === 'complete') {
+ if (this.isIframeBlank(ifr)) {
+ this.observeIframeLoad(ifr, successFn, errorFn);
+ } else {
+ this.getIframeContents(ifr, successFn, errorFn);
+ }
+ } else {
+ this.observeIframeLoad(ifr, successFn, errorFn);
+ }
+ } catch (e) {
+ errorFn();
+ }
+ }
+ }, {
+ key: "waitForIframes",
+ value: function waitForIframes(ctx, done) {
+ var _this2 = this;
+
+ var eachCalled = 0;
+ this.forEachIframe(ctx, function () {
+ return true;
+ }, function (ifr) {
+ eachCalled++;
+
+ _this2.waitForIframes(ifr.querySelector('html'), function () {
+ if (! --eachCalled) {
+ done();
+ }
+ });
+ }, function (handled) {
+ if (!handled) {
+ done();
+ }
+ });
+ }
+ }, {
+ key: "forEachIframe",
+ value: function forEachIframe(ctx, filter, each) {
+ var _this3 = this;
+
+ var end = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : function () {};
+ var ifr = ctx.querySelectorAll('iframe'),
+ open = ifr.length,
+ handled = 0;
+ ifr = Array.prototype.slice.call(ifr);
+
+ var checkEnd = function checkEnd() {
+ if (--open <= 0) {
+ end(handled);
+ }
+ };
+
+ if (!open) {
+ checkEnd();
+ }
+
+ ifr.forEach(function (ifr) {
+ if (DOMIterator.matches(ifr, _this3.exclude)) {
+ checkEnd();
+ } else {
+ _this3.onIframeReady(ifr, function (con) {
+ if (filter(ifr)) {
+ handled++;
+ each(con);
+ }
+
+ checkEnd();
+ }, checkEnd);
+ }
+ });
+ }
+ }, {
+ key: "createIterator",
+ value: function createIterator(ctx, whatToShow, filter) {
+ return document.createNodeIterator(ctx, whatToShow, filter, false);
+ }
+ }, {
+ key: "createInstanceOnIframe",
+ value: function createInstanceOnIframe(contents) {
+ return new DOMIterator(contents.querySelector('html'), this.iframes);
+ }
+ }, {
+ key: "compareNodeIframe",
+ value: function compareNodeIframe(node, prevNode, ifr) {
+ var compCurr = node.compareDocumentPosition(ifr),
+ prev = Node.DOCUMENT_POSITION_PRECEDING;
+
+ if (compCurr & prev) {
+ if (prevNode !== null) {
+ var compPrev = prevNode.compareDocumentPosition(ifr),
+ after = Node.DOCUMENT_POSITION_FOLLOWING;
+
+ if (compPrev & after) {
+ return true;
+ }
+ } else {
+ return true;
+ }
+ }
+
+ return false;
+ }
+ }, {
+ key: "getIteratorNode",
+ value: function getIteratorNode(itr) {
+ var prevNode = itr.previousNode();
+ var node;
+
+ if (prevNode === null) {
+ node = itr.nextNode();
+ } else {
+ node = itr.nextNode() && itr.nextNode();
+ }
+
+ return {
+ prevNode: prevNode,
+ node: node
+ };
+ }
+ }, {
+ key: "checkIframeFilter",
+ value: function checkIframeFilter(node, prevNode, currIfr, ifr) {
+ var key = false,
+ handled = false;
+ ifr.forEach(function (ifrDict, i) {
+ if (ifrDict.val === currIfr) {
+ key = i;
+ handled = ifrDict.handled;
+ }
+ });
+
+ if (this.compareNodeIframe(node, prevNode, currIfr)) {
+ if (key === false && !handled) {
+ ifr.push({
+ val: currIfr,
+ handled: true
+ });
+ } else if (key !== false && !handled) {
+ ifr[key].handled = true;
+ }
+
+ return true;
+ }
+
+ if (key === false) {
+ ifr.push({
+ val: currIfr,
+ handled: false
+ });
+ }
+
+ return false;
+ }
+ }, {
+ key: "handleOpenIframes",
+ value: function handleOpenIframes(ifr, whatToShow, eCb, fCb) {
+ var _this4 = this;
+
+ ifr.forEach(function (ifrDict) {
+ if (!ifrDict.handled) {
+ _this4.getIframeContents(ifrDict.val, function (con) {
+ _this4.createInstanceOnIframe(con).forEachNode(whatToShow, eCb, fCb);
+ });
+ }
+ });
+ }
+ }, {
+ key: "iterateThroughNodes",
+ value: function iterateThroughNodes(whatToShow, ctx, eachCb, filterCb, doneCb) {
+ var _this5 = this;
+
+ var itr = this.createIterator(ctx, whatToShow, filterCb);
+
+ var ifr = [],
+ elements = [],
+ node,
+ prevNode,
+ retrieveNodes = function retrieveNodes() {
+ var _this5$getIteratorNod = _this5.getIteratorNode(itr);
+
+ prevNode = _this5$getIteratorNod.prevNode;
+ node = _this5$getIteratorNod.node;
+ return node;
+ };
+
+ while (retrieveNodes()) {
+ if (this.iframes) {
+ this.forEachIframe(ctx, function (currIfr) {
+ return _this5.checkIframeFilter(node, prevNode, currIfr, ifr);
+ }, function (con) {
+ _this5.createInstanceOnIframe(con).forEachNode(whatToShow, function (ifrNode) {
+ return elements.push(ifrNode);
+ }, filterCb);
+ });
+ }
+
+ elements.push(node);
+ }
+
+ elements.forEach(function (node) {
+ eachCb(node);
+ });
+
+ if (this.iframes) {
+ this.handleOpenIframes(ifr, whatToShow, eachCb, filterCb);
+ }
+
+ doneCb();
+ }
+ }, {
+ key: "forEachNode",
+ value: function forEachNode(whatToShow, each, filter) {
+ var _this6 = this;
+
+ var done = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : function () {};
+ var contexts = this.getContexts();
+ var open = contexts.length;
+
+ if (!open) {
+ done();
+ }
+
+ contexts.forEach(function (ctx) {
+ var ready = function ready() {
+ _this6.iterateThroughNodes(whatToShow, ctx, each, filter, function () {
+ if (--open <= 0) {
+ done();
+ }
+ });
+ };
+
+ if (_this6.iframes) {
+ _this6.waitForIframes(ctx, ready);
+ } else {
+ ready();
+ }
+ });
+ }
+ }], [{
+ key: "matches",
+ value: function matches(element, selector) {
+ var selectors = typeof selector === 'string' ? [selector] : selector,
+ fn = element.matches || element.matchesSelector || element.msMatchesSelector || element.mozMatchesSelector || element.oMatchesSelector || element.webkitMatchesSelector;
+
+ if (fn) {
+ var match = false;
+ selectors.every(function (sel) {
+ if (fn.call(element, sel)) {
+ match = true;
+ return false;
+ }
+
+ return true;
+ });
+ return match;
+ } else {
+ return false;
+ }
+ }
+ }]);
+
+ return DOMIterator;
+ }();
+
+ var RegExpCreator =
+ /*#__PURE__*/
+ function () {
+ function RegExpCreator(options) {
+ _classCallCheck(this, RegExpCreator);
+
+ this.opt = _extends({}, {
+ 'diacritics': true,
+ 'synonyms': {},
+ 'accuracy': 'partially',
+ 'caseSensitive': false,
+ 'ignoreJoiners': false,
+ 'ignorePunctuation': [],
+ 'wildcards': 'disabled'
+ }, options);
+ }
+
+ _createClass(RegExpCreator, [{
+ key: "create",
+ value: function create(str) {
+ if (this.opt.wildcards !== 'disabled') {
+ str = this.setupWildcardsRegExp(str);
+ }
+
+ str = this.escapeStr(str);
+
+ if (Object.keys(this.opt.synonyms).length) {
+ str = this.createSynonymsRegExp(str);
+ }
+
+ if (this.opt.ignoreJoiners || this.opt.ignorePunctuation.length) {
+ str = this.setupIgnoreJoinersRegExp(str);
+ }
+
+ if (this.opt.diacritics) {
+ str = this.createDiacriticsRegExp(str);
+ }
+
+ str = this.createMergedBlanksRegExp(str);
+
+ if (this.opt.ignoreJoiners || this.opt.ignorePunctuation.length) {
+ str = this.createJoinersRegExp(str);
+ }
+
+ if (this.opt.wildcards !== 'disabled') {
+ str = this.createWildcardsRegExp(str);
+ }
+
+ str = this.createAccuracyRegExp(str);
+ return new RegExp(str, "gm".concat(this.opt.caseSensitive ? '' : 'i'));
+ }
+ }, {
+ key: "sortByLength",
+ value: function sortByLength(arry) {
+ return arry.sort(function (a, b) {
+ return a.length === b.length ? a > b ? 1 : -1 : b.length - a.length;
+ });
+ }
+ }, {
+ key: "escapeStr",
+ value: function escapeStr(str) {
+ return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, '\\$&');
+ }
+ }, {
+ key: "createSynonymsRegExp",
+ value: function createSynonymsRegExp(str) {
+ var _this = this;
+
+ var syn = this.opt.synonyms,
+ sens = this.opt.caseSensitive ? '' : 'i',
+ joinerPlaceholder = this.opt.ignoreJoiners || this.opt.ignorePunctuation.length ? "\0" : '';
+
+ for (var index in syn) {
+ if (syn.hasOwnProperty(index)) {
+ var keys = Array.isArray(syn[index]) ? syn[index] : [syn[index]];
+ keys.unshift(index);
+ keys = this.sortByLength(keys).map(function (key) {
+ if (_this.opt.wildcards !== 'disabled') {
+ key = _this.setupWildcardsRegExp(key);
+ }
+
+ key = _this.escapeStr(key);
+ return key;
+ }).filter(function (k) {
+ return k !== '';
+ });
+
+ if (keys.length > 1) {
+ str = str.replace(new RegExp("(".concat(keys.map(function (k) {
+ return _this.escapeStr(k);
+ }).join('|'), ")"), "gm".concat(sens)), joinerPlaceholder + "(".concat(keys.map(function (k) {
+ return _this.processSynonyms(k);
+ }).join('|'), ")") + joinerPlaceholder);
+ }
+ }
+ }
+
+ return str;
+ }
+ }, {
+ key: "processSynonyms",
+ value: function processSynonyms(str) {
+ if (this.opt.ignoreJoiners || this.opt.ignorePunctuation.length) {
+ str = this.setupIgnoreJoinersRegExp(str);
+ }
+
+ return str;
+ }
+ }, {
+ key: "setupWildcardsRegExp",
+ value: function setupWildcardsRegExp(str) {
+ str = str.replace(/(?:\\)*\?/g, function (val) {
+ return val.charAt(0) === '\\' ? '?' : "\x01";
+ });
+ return str.replace(/(?:\\)*\*/g, function (val) {
+ return val.charAt(0) === '\\' ? '*' : "\x02";
+ });
+ }
+ }, {
+ key: "createWildcardsRegExp",
+ value: function createWildcardsRegExp(str) {
+ var spaces = this.opt.wildcards === 'withSpaces';
+ return str.replace(/\u0001/g, spaces ? '[\\S\\s]?' : '\\S?').replace(/\u0002/g, spaces ? '[\\S\\s]*?' : '\\S*');
+ }
+ }, {
+ key: "setupIgnoreJoinersRegExp",
+ value: function setupIgnoreJoinersRegExp(str) {
+ return str.replace(/[^(|)\\]/g, function (val, indx, original) {
+ var nextChar = original.charAt(indx + 1);
+
+ if (/[(|)\\]/.test(nextChar) || nextChar === '') {
+ return val;
+ } else {
+ return val + "\0";
+ }
+ });
+ }
+ }, {
+ key: "createJoinersRegExp",
+ value: function createJoinersRegExp(str) {
+ var joiner = [];
+ var ignorePunctuation = this.opt.ignorePunctuation;
+
+ if (Array.isArray(ignorePunctuation) && ignorePunctuation.length) {
+ joiner.push(this.escapeStr(ignorePunctuation.join('')));
+ }
+
+ if (this.opt.ignoreJoiners) {
+ joiner.push("\\u00ad\\u200b\\u200c\\u200d");
+ }
+
+ return joiner.length ? str.split(/\u0000+/).join("[".concat(joiner.join(''), "]*")) : str;
+ }
+ }, {
+ key: "createDiacriticsRegExp",
+ value: function createDiacriticsRegExp(str) {
+ var sens = this.opt.caseSensitive ? '' : 'i',
+ dct = this.opt.caseSensitive ? ['aàáảãạăằắẳẵặâầấẩẫậäåāą', 'AÀÁẢÃẠĂẰẮẲẴẶÂẦẤẨẪẬÄÅĀĄ', 'cçćč', 'CÇĆČ', 'dđď', 'DĐĎ', 'eèéẻẽẹêềếểễệëěēę', 'EÈÉẺẼẸÊỀẾỂỄỆËĚĒĘ', 'iìíỉĩịîïī', 'IÌÍỈĨỊÎÏĪ', 'lł', 'LŁ', 'nñňń', 'NÑŇŃ', 'oòóỏõọôồốổỗộơởỡớờợöøō', 'OÒÓỎÕỌÔỒỐỔỖỘƠỞỠỚỜỢÖØŌ', 'rř', 'RŘ', 'sšśșş', 'SŠŚȘŞ', 'tťțţ', 'TŤȚŢ', 'uùúủũụưừứửữựûüůū', 'UÙÚỦŨỤƯỪỨỬỮỰÛÜŮŪ', 'yýỳỷỹỵÿ', 'YÝỲỶỸỴŸ', 'zžżź', 'ZŽŻŹ'] : ['aàáảãạăằắẳẵặâầấẩẫậäåāąAÀÁẢÃẠĂẰẮẲẴẶÂẦẤẨẪẬÄÅĀĄ', 'cçćčCÇĆČ', 'dđďDĐĎ', 'eèéẻẽẹêềếểễệëěēęEÈÉẺẼẸÊỀẾỂỄỆËĚĒĘ', 'iìíỉĩịîïīIÌÍỈĨỊÎÏĪ', 'lłLŁ', 'nñňńNÑŇŃ', 'oòóỏõọôồốổỗộơởỡớờợöøōOÒÓỎÕỌÔỒỐỔỖỘƠỞỠỚỜỢÖØŌ', 'rřRŘ', 'sšśșşSŠŚȘŞ', 'tťțţTŤȚŢ', 'uùúủũụưừứửữựûüůūUÙÚỦŨỤƯỪỨỬỮỰÛÜŮŪ', 'yýỳỷỹỵÿYÝỲỶỸỴŸ', 'zžżźZŽŻŹ'];
+ var handled = [];
+ str.split('').forEach(function (ch) {
+ dct.every(function (dct) {
+ if (dct.indexOf(ch) !== -1) {
+ if (handled.indexOf(dct) > -1) {
+ return false;
+ }
+
+ str = str.replace(new RegExp("[".concat(dct, "]"), "gm".concat(sens)), "[".concat(dct, "]"));
+ handled.push(dct);
+ }
+
+ return true;
+ });
+ });
+ return str;
+ }
+ }, {
+ key: "createMergedBlanksRegExp",
+ value: function createMergedBlanksRegExp(str) {
+ return str.replace(/[\s]+/gmi, '[\\s]+');
+ }
+ }, {
+ key: "createAccuracyRegExp",
+ value: function createAccuracyRegExp(str) {
+ var _this2 = this;
+
+ var chars = '!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~¡¿';
+ var acc = this.opt.accuracy,
+ val = typeof acc === 'string' ? acc : acc.value,
+ ls = typeof acc === 'string' ? [] : acc.limiters,
+ lsJoin = '';
+ ls.forEach(function (limiter) {
+ lsJoin += "|".concat(_this2.escapeStr(limiter));
+ });
+
+ switch (val) {
+ case 'partially':
+ default:
+ return "()(".concat(str, ")");
+
+ case 'complementary':
+ lsJoin = '\\s' + (lsJoin ? lsJoin : this.escapeStr(chars));
+ return "()([^".concat(lsJoin, "]*").concat(str, "[^").concat(lsJoin, "]*)");
+
+ case 'exactly':
+ return "(^|\\s".concat(lsJoin, ")(").concat(str, ")(?=$|\\s").concat(lsJoin, ")");
+ }
+ }
+ }]);
+
+ return RegExpCreator;
+ }();
+
+ var Mark =
+ /*#__PURE__*/
+ function () {
+ function Mark(ctx) {
+ _classCallCheck(this, Mark);
+
+ this.ctx = ctx;
+ this.ie = false;
+ var ua = window.navigator.userAgent;
+
+ if (ua.indexOf('MSIE') > -1 || ua.indexOf('Trident') > -1) {
+ this.ie = true;
+ }
+ }
+
+ _createClass(Mark, [{
+ key: "log",
+ value: function log(msg) {
+ var level = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'debug';
+ var log = this.opt.log;
+
+ if (!this.opt.debug) {
+ return;
+ }
+
+ if (_typeof(log) === 'object' && typeof log[level] === 'function') {
+ log[level]("mark.js: ".concat(msg));
+ }
+ }
+ }, {
+ key: "getSeparatedKeywords",
+ value: function getSeparatedKeywords(sv) {
+ var _this = this;
+
+ var stack = [];
+ sv.forEach(function (kw) {
+ if (!_this.opt.separateWordSearch) {
+ if (kw.trim() && stack.indexOf(kw) === -1) {
+ stack.push(kw);
+ }
+ } else {
+ kw.split(' ').forEach(function (kwSplitted) {
+ if (kwSplitted.trim() && stack.indexOf(kwSplitted) === -1) {
+ stack.push(kwSplitted);
+ }
+ });
+ }
+ });
+ return {
+ 'keywords': stack.sort(function (a, b) {
+ return b.length - a.length;
+ }),
+ 'length': stack.length
+ };
+ }
+ }, {
+ key: "isNumeric",
+ value: function isNumeric(value) {
+ return Number(parseFloat(value)) == value;
+ }
+ }, {
+ key: "checkRanges",
+ value: function checkRanges(array) {
+ var _this2 = this;
+
+ if (!Array.isArray(array) || Object.prototype.toString.call(array[0]) !== '[object Object]') {
+ this.log('markRanges() will only accept an array of objects');
+ this.opt.noMatch(array);
+ return [];
+ }
+
+ var stack = [];
+ var last = 0;
+ array.sort(function (a, b) {
+ return a.start - b.start;
+ }).forEach(function (item) {
+ var _this2$callNoMatchOnI = _this2.callNoMatchOnInvalidRanges(item, last),
+ start = _this2$callNoMatchOnI.start,
+ end = _this2$callNoMatchOnI.end,
+ valid = _this2$callNoMatchOnI.valid;
+
+ if (valid) {
+ item.start = start;
+ item.length = end - start;
+ stack.push(item);
+ last = end;
+ }
+ });
+ return stack;
+ }
+ }, {
+ key: "callNoMatchOnInvalidRanges",
+ value: function callNoMatchOnInvalidRanges(range, last) {
+ var start,
+ end,
+ valid = false;
+
+ if (range && typeof range.start !== 'undefined') {
+ start = parseInt(range.start, 10);
+ end = start + parseInt(range.length, 10);
+
+ if (this.isNumeric(range.start) && this.isNumeric(range.length) && end - last > 0 && end - start > 0) {
+ valid = true;
+ } else {
+ this.log('Ignoring invalid or overlapping range: ' + "".concat(JSON.stringify(range)));
+ this.opt.noMatch(range);
+ }
+ } else {
+ this.log("Ignoring invalid range: ".concat(JSON.stringify(range)));
+ this.opt.noMatch(range);
+ }
+
+ return {
+ start: start,
+ end: end,
+ valid: valid
+ };
+ }
+ }, {
+ key: "checkWhitespaceRanges",
+ value: function checkWhitespaceRanges(range, originalLength, string) {
+ var end,
+ valid = true,
+ max = string.length,
+ offset = originalLength - max,
+ start = parseInt(range.start, 10) - offset;
+ start = start > max ? max : start;
+ end = start + parseInt(range.length, 10);
+
+ if (end > max) {
+ end = max;
+ this.log("End range automatically set to the max value of ".concat(max));
+ }
+
+ if (start < 0 || end - start < 0 || start > max || end > max) {
+ valid = false;
+ this.log("Invalid range: ".concat(JSON.stringify(range)));
+ this.opt.noMatch(range);
+ } else if (string.substring(start, end).replace(/\s+/g, '') === '') {
+ valid = false;
+ this.log('Skipping whitespace only range: ' + JSON.stringify(range));
+ this.opt.noMatch(range);
+ }
+
+ return {
+ start: start,
+ end: end,
+ valid: valid
+ };
+ }
+ }, {
+ key: "getTextNodes",
+ value: function getTextNodes(cb) {
+ var _this3 = this;
+
+ var val = '',
+ nodes = [];
+ this.iterator.forEachNode(NodeFilter.SHOW_TEXT, function (node) {
+ nodes.push({
+ start: val.length,
+ end: (val += node.textContent).length,
+ node: node
+ });
+ }, function (node) {
+ if (_this3.matchesExclude(node.parentNode)) {
+ return NodeFilter.FILTER_REJECT;
+ } else {
+ return NodeFilter.FILTER_ACCEPT;
+ }
+ }, function () {
+ cb({
+ value: val,
+ nodes: nodes
+ });
+ });
+ }
+ }, {
+ key: "matchesExclude",
+ value: function matchesExclude(el) {
+ return DOMIterator.matches(el, this.opt.exclude.concat(['script', 'style', 'title', 'head', 'html']));
+ }
+ }, {
+ key: "wrapRangeInTextNode",
+ value: function wrapRangeInTextNode(node, start, end) {
+ var hEl = !this.opt.element ? 'mark' : this.opt.element,
+ startNode = node.splitText(start),
+ ret = startNode.splitText(end - start);
+ var repl = document.createElement(hEl);
+ repl.setAttribute('data-markjs', 'true');
+
+ if (this.opt.className) {
+ repl.setAttribute('class', this.opt.className);
+ }
+
+ repl.textContent = startNode.textContent;
+ startNode.parentNode.replaceChild(repl, startNode);
+ return ret;
+ }
+ }, {
+ key: "wrapRangeInMappedTextNode",
+ value: function wrapRangeInMappedTextNode(dict, start, end, filterCb, eachCb) {
+ var _this4 = this;
+
+ dict.nodes.every(function (n, i) {
+ var sibl = dict.nodes[i + 1];
+
+ if (typeof sibl === 'undefined' || sibl.start > start) {
+ if (!filterCb(n.node)) {
+ return false;
+ }
+
+ var s = start - n.start,
+ e = (end > n.end ? n.end : end) - n.start,
+ startStr = dict.value.substr(0, n.start),
+ endStr = dict.value.substr(e + n.start);
+ n.node = _this4.wrapRangeInTextNode(n.node, s, e);
+ dict.value = startStr + endStr;
+ dict.nodes.forEach(function (k, j) {
+ if (j >= i) {
+ if (dict.nodes[j].start > 0 && j !== i) {
+ dict.nodes[j].start -= e;
+ }
+
+ dict.nodes[j].end -= e;
+ }
+ });
+ end -= e;
+ eachCb(n.node.previousSibling, n.start);
+
+ if (end > n.end) {
+ start = n.end;
+ } else {
+ return false;
+ }
+ }
+
+ return true;
+ });
+ }
+ }, {
+ key: "wrapGroups",
+ value: function wrapGroups(node, pos, len, eachCb) {
+ node = this.wrapRangeInTextNode(node, pos, pos + len);
+ eachCb(node.previousSibling);
+ return node;
+ }
+ }, {
+ key: "separateGroups",
+ value: function separateGroups(node, match, matchIdx, filterCb, eachCb) {
+ var matchLen = match.length;
+
+ for (var i = 1; i < matchLen; i++) {
+ var pos = node.textContent.indexOf(match[i]);
+
+ if (match[i] && pos > -1 && filterCb(match[i], node)) {
+ node = this.wrapGroups(node, pos, match[i].length, eachCb);
+ }
+ }
+
+ return node;
+ }
+ }, {
+ key: "wrapMatches",
+ value: function wrapMatches(regex, ignoreGroups, filterCb, eachCb, endCb) {
+ var _this5 = this;
+
+ var matchIdx = ignoreGroups === 0 ? 0 : ignoreGroups + 1;
+ this.getTextNodes(function (dict) {
+ dict.nodes.forEach(function (node) {
+ node = node.node;
+ var match;
+
+ while ((match = regex.exec(node.textContent)) !== null && match[matchIdx] !== '') {
+ if (_this5.opt.separateGroups) {
+ node = _this5.separateGroups(node, match, matchIdx, filterCb, eachCb);
+ } else {
+ if (!filterCb(match[matchIdx], node)) {
+ continue;
+ }
+
+ var pos = match.index;
+
+ if (matchIdx !== 0) {
+ for (var i = 1; i < matchIdx; i++) {
+ pos += match[i].length;
+ }
+ }
+
+ node = _this5.wrapGroups(node, pos, match[matchIdx].length, eachCb);
+ }
+
+ regex.lastIndex = 0;
+ }
+ });
+ endCb();
+ });
+ }
+ }, {
+ key: "wrapMatchesAcrossElements",
+ value: function wrapMatchesAcrossElements(regex, ignoreGroups, filterCb, eachCb, endCb) {
+ var _this6 = this;
+
+ var matchIdx = ignoreGroups === 0 ? 0 : ignoreGroups + 1;
+ this.getTextNodes(function (dict) {
+ var match;
+
+ while ((match = regex.exec(dict.value)) !== null && match[matchIdx] !== '') {
+ var start = match.index;
+
+ if (matchIdx !== 0) {
+ for (var i = 1; i < matchIdx; i++) {
+ start += match[i].length;
+ }
+ }
+
+ var end = start + match[matchIdx].length;
+
+ _this6.wrapRangeInMappedTextNode(dict, start, end, function (node) {
+ return filterCb(match[matchIdx], node);
+ }, function (node, lastIndex) {
+ regex.lastIndex = lastIndex;
+ eachCb(node);
+ });
+ }
+
+ endCb();
+ });
+ }
+ }, {
+ key: "wrapRangeFromIndex",
+ value: function wrapRangeFromIndex(ranges, filterCb, eachCb, endCb) {
+ var _this7 = this;
+
+ this.getTextNodes(function (dict) {
+ var originalLength = dict.value.length;
+ ranges.forEach(function (range, counter) {
+ var _this7$checkWhitespac = _this7.checkWhitespaceRanges(range, originalLength, dict.value),
+ start = _this7$checkWhitespac.start,
+ end = _this7$checkWhitespac.end,
+ valid = _this7$checkWhitespac.valid;
+
+ if (valid) {
+ _this7.wrapRangeInMappedTextNode(dict, start, end, function (node) {
+ return filterCb(node, range, dict.value.substring(start, end), counter);
+ }, function (node) {
+ eachCb(node, range);
+ });
+ }
+ });
+ endCb();
+ });
+ }
+ }, {
+ key: "unwrapMatches",
+ value: function unwrapMatches(node) {
+ var parent = node.parentNode;
+ var docFrag = document.createDocumentFragment();
+
+ while (node.firstChild) {
+ docFrag.appendChild(node.removeChild(node.firstChild));
+ }
+
+ parent.replaceChild(docFrag, node);
+
+ if (!this.ie) {
+ parent.normalize();
+ } else {
+ this.normalizeTextNode(parent);
+ }
+ }
+ }, {
+ key: "normalizeTextNode",
+ value: function normalizeTextNode(node) {
+ if (!node) {
+ return;
+ }
+
+ if (node.nodeType === 3) {
+ while (node.nextSibling && node.nextSibling.nodeType === 3) {
+ node.nodeValue += node.nextSibling.nodeValue;
+ node.parentNode.removeChild(node.nextSibling);
+ }
+ } else {
+ this.normalizeTextNode(node.firstChild);
+ }
+
+ this.normalizeTextNode(node.nextSibling);
+ }
+ }, {
+ key: "markRegExp",
+ value: function markRegExp(regexp, opt) {
+ var _this8 = this;
+
+ this.opt = opt;
+ this.log("Searching with expression \"".concat(regexp, "\""));
+ var totalMatches = 0,
+ fn = 'wrapMatches';
+
+ var eachCb = function eachCb(element) {
+ totalMatches++;
+
+ _this8.opt.each(element);
+ };
+
+ if (this.opt.acrossElements) {
+ fn = 'wrapMatchesAcrossElements';
+ }
+
+ this[fn](regexp, this.opt.ignoreGroups, function (match, node) {
+ return _this8.opt.filter(node, match, totalMatches);
+ }, eachCb, function () {
+ if (totalMatches === 0) {
+ _this8.opt.noMatch(regexp);
+ }
+
+ _this8.opt.done(totalMatches);
+ });
+ }
+ }, {
+ key: "mark",
+ value: function mark(sv, opt) {
+ var _this9 = this;
+
+ this.opt = opt;
+ var totalMatches = 0,
+ fn = 'wrapMatches';
+
+ var _this$getSeparatedKey = this.getSeparatedKeywords(typeof sv === 'string' ? [sv] : sv),
+ kwArr = _this$getSeparatedKey.keywords,
+ kwArrLen = _this$getSeparatedKey.length,
+ handler = function handler(kw) {
+ var regex = new RegExpCreator(_this9.opt).create(kw);
+ var matches = 0;
+
+ _this9.log("Searching with expression \"".concat(regex, "\""));
+
+ _this9[fn](regex, 1, function (term, node) {
+ return _this9.opt.filter(node, kw, totalMatches, matches);
+ }, function (element) {
+ matches++;
+ totalMatches++;
+
+ _this9.opt.each(element);
+ }, function () {
+ if (matches === 0) {
+ _this9.opt.noMatch(kw);
+ }
+
+ if (kwArr[kwArrLen - 1] === kw) {
+ _this9.opt.done(totalMatches);
+ } else {
+ handler(kwArr[kwArr.indexOf(kw) + 1]);
+ }
+ });
+ };
+
+ if (this.opt.acrossElements) {
+ fn = 'wrapMatchesAcrossElements';
+ }
+
+ if (kwArrLen === 0) {
+ this.opt.done(totalMatches);
+ } else {
+ handler(kwArr[0]);
+ }
+ }
+ }, {
+ key: "markRanges",
+ value: function markRanges(rawRanges, opt) {
+ var _this10 = this;
+
+ this.opt = opt;
+ var totalMatches = 0,
+ ranges = this.checkRanges(rawRanges);
+
+ if (ranges && ranges.length) {
+ this.log('Starting to mark with the following ranges: ' + JSON.stringify(ranges));
+ this.wrapRangeFromIndex(ranges, function (node, range, match, counter) {
+ return _this10.opt.filter(node, range, match, counter);
+ }, function (element, range) {
+ totalMatches++;
+
+ _this10.opt.each(element, range);
+ }, function () {
+ _this10.opt.done(totalMatches);
+ });
+ } else {
+ this.opt.done(totalMatches);
+ }
+ }
+ }, {
+ key: "unmark",
+ value: function unmark(opt) {
+ var _this11 = this;
+
+ this.opt = opt;
+ var sel = this.opt.element ? this.opt.element : '*';
+ sel += '[data-markjs]';
+
+ if (this.opt.className) {
+ sel += ".".concat(this.opt.className);
+ }
+
+ this.log("Removal selector \"".concat(sel, "\""));
+ this.iterator.forEachNode(NodeFilter.SHOW_ELEMENT, function (node) {
+ _this11.unwrapMatches(node);
+ }, function (node) {
+ var matchesSel = DOMIterator.matches(node, sel),
+ matchesExclude = _this11.matchesExclude(node);
+
+ if (!matchesSel || matchesExclude) {
+ return NodeFilter.FILTER_REJECT;
+ } else {
+ return NodeFilter.FILTER_ACCEPT;
+ }
+ }, this.opt.done);
+ }
+ }, {
+ key: "opt",
+ set: function set(val) {
+ this._opt = _extends({}, {
+ 'element': '',
+ 'className': '',
+ 'exclude': [],
+ 'iframes': false,
+ 'iframesTimeout': 5000,
+ 'separateWordSearch': true,
+ 'acrossElements': false,
+ 'ignoreGroups': 0,
+ 'each': function each() {},
+ 'noMatch': function noMatch() {},
+ 'filter': function filter() {
+ return true;
+ },
+ 'done': function done() {},
+ 'debug': false,
+ 'log': window.console
+ }, val);
+ },
+ get: function get() {
+ return this._opt;
+ }
+ }, {
+ key: "iterator",
+ get: function get() {
+ return new DOMIterator(this.ctx, this.opt.iframes, this.opt.exclude, this.opt.iframesTimeout);
+ }
+ }]);
+
+ return Mark;
+ }();
+
+ $.fn.mark = function (sv, opt) {
+ new Mark(this.get()).mark(sv, opt);
+ return this;
+ };
+
+ $.fn.markRegExp = function (regexp, opt) {
+ new Mark(this.get()).markRegExp(regexp, opt);
+ return this;
+ };
+
+ $.fn.markRanges = function (ranges, opt) {
+ new Mark(this.get()).markRanges(ranges, opt);
+ return this;
+ };
+
+ $.fn.unmark = function (opt) {
+ new Mark(this.get()).unmark(opt);
+ return this;
+ };
+
+ return $;
+
+})));
diff --git a/ckanext/og_datatables_datefilterview/assets/vendor/FontAwesome/images/times-circle-solid.svg b/ckanext/og_datatables_datefilterview/assets/vendor/FontAwesome/images/times-circle-solid.svg
new file mode 100644
index 0000000..9046b0f
--- /dev/null
+++ b/ckanext/og_datatables_datefilterview/assets/vendor/FontAwesome/images/times-circle-solid.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/ckanext/og_datatables_datefilterview/assets/webassets.yml b/ckanext/og_datatables_datefilterview/assets/webassets.yml
new file mode 100644
index 0000000..fc81874
--- /dev/null
+++ b/ckanext/og_datatables_datefilterview/assets/webassets.yml
@@ -0,0 +1,25 @@
+main-css:
+ output: ckanext-og_datatables_datefilterview/%(version)s_og_datatables_datefilterview.css
+ contents:
+ - vendor/DataTables/datatables.css
+ - vendor/DataTables/datatables.mark.css
+ - og_datatables_datefilterview.css
+main-js:
+ output: ckanext-og_datatables_datefilterview/%(version)s_og_datatables_datefilterview.js
+ extra:
+ preload:
+ - base/main
+ contents:
+ - vendor/DataTables/datatables.js
+ - vendor/DataTables/datatables.mark.js
+ - vendor/DataTables/jquery.mark.js
+ - vendor/DataTables/dataTables.scrollResize.js
+ - vendor/DataTables/datetime.js
+ - og_datatables_datefilterview.js
+form-js:
+ output: ckanext-og_datatables_datefilterview/%(version)s_og_datatables_datefilterview_form.js
+ extra:
+ preload:
+ - base/main
+ contents:
+ - og_datatables_datefilterview_form.js
\ No newline at end of file
diff --git a/ckanext/og_datatables_datefilterview/blueprint.py b/ckanext/og_datatables_datefilterview/blueprint.py
new file mode 100644
index 0000000..e3fbebc
--- /dev/null
+++ b/ckanext/og_datatables_datefilterview/blueprint.py
@@ -0,0 +1,597 @@
+# encoding: utf-8
+
+from urllib.parse import urlencode
+from html import escape
+from datetime import datetime
+import csv
+import io
+
+from flask import Blueprint, Response
+
+
+from ckan.common import json
+from ckan.plugins.toolkit import get_action, request, h
+import re
+
+ogdatatablesdatefilterview = Blueprint(u'ogdatatablesdatefilterview', __name__)
+
+
+def merge_filters(view_filters, user_filters_str):
+ u'''
+ view filters are built as part of the view, user filters
+ are selected by the user interacting with the view. Any filters
+ selected by user may only tighten filters set in the view,
+ others are ignored.
+
+ >>> merge_filters({
+ ... u'Department': [u'BTDT'], u'OnTime_Status': [u'ONTIME']},
+ ... u'CASE_STATUS:Open|CASE_STATUS:Closed|Department:INFO')
+ {u'Department': [u'BTDT'],
+ u'OnTime_Status': [u'ONTIME'],
+ u'CASE_STATUS': [u'Open', u'Closed']}
+ '''
+ filters = dict(view_filters)
+ if not user_filters_str:
+ return filters
+ user_filters = {}
+ for k_v in user_filters_str.split(u'|'):
+ k, sep, v = k_v.partition(u':')
+ if k not in view_filters or v in view_filters[k]:
+ user_filters.setdefault(k, []).append(v)
+ for k in user_filters:
+ filters[k] = user_filters[k]
+ return filters
+
+
+def is_date_range_filter(value):
+ u'''
+ Check if a filter value contains a date range pattern.
+ Supports formats like:
+ - "2024-01-01 to 2024-12-31"
+ - "2024-01-01,2024-12-31"
+ - "2024-01-01 - 2024-12-31"
+
+ Returns tuple (is_date_range, start_date, end_date) or (False, None, None)
+ '''
+ if not value:
+ return (False, None, None)
+
+ value = value.strip()
+
+ # Try "to" separator
+ if u' to ' in value.lower():
+ parts = re.split(r'\s+to\s+', value, flags=re.IGNORECASE)
+ if len(parts) == 2:
+ start_date = parts[0].strip()
+ end_date = parts[1].strip()
+ if _is_valid_date(start_date) and _is_valid_date(end_date):
+ return (True, start_date, end_date)
+
+ # Try comma separator
+ if u',' in value:
+ parts = value.split(u',')
+ if len(parts) == 2:
+ start_date = parts[0].strip()
+ end_date = parts[1].strip()
+ if _is_valid_date(start_date) and _is_valid_date(end_date):
+ return (True, start_date, end_date)
+
+ # Try dash separator (with spaces)
+ if u' - ' in value:
+ parts = value.split(u' - ')
+ if len(parts) == 2:
+ start_date = parts[0].strip()
+ end_date = parts[1].strip()
+ if _is_valid_date(start_date) and _is_valid_date(end_date):
+ return (True, start_date, end_date)
+
+ return (False, None, None)
+
+
+def _is_valid_date(date_str):
+ u'''
+ Check if a string is a valid date in YYYY-MM-DD format.
+ '''
+ try:
+ datetime.strptime(date_str, u'%Y-%m-%d')
+ return True
+ except ValueError:
+ return False
+
+
+def is_date_column(column_name, fields):
+ u'''
+ Check if a column is a date/timestamp type.
+ '''
+ for field in fields:
+ if field.get(u'id') == column_name:
+ field_type = field.get(u'type', u'').lower()
+ return field_type in (u'timestamp', u'timestamptz', u'date')
+ return False
+
+
+def datastore_search_sql_date_range(resource_id, column_name, start_date, end_date,
+ filters, sort_list, offset, limit, cols):
+ u'''
+ Perform a datastore_search_sql query for date range filtering.
+ Returns the response dictionary similar to datastore_search.
+ '''
+ datastore_search_sql = get_action(u'datastore_search_sql')
+
+ # Build WHERE clause for date range
+ # Escape column name to prevent SQL injection
+ # Column names in datastore are typically quoted
+ safe_column = u'"{}"'.format(column_name.replace(u'"', u'""'))
+
+ # Escape date values to prevent SQL injection
+ safe_start_date = start_date.replace(u"'", u"''")
+ safe_end_date = end_date.replace(u"'", u"''")
+
+ # Include full day for end date by adding time component
+ where_clauses = [u'{} >= \'{}\'::timestamp'.format(safe_column, safe_start_date),
+ u'{} < (\'{}\'::date + interval \'1 day\')::timestamp'.format(safe_column, safe_end_date)]
+
+ # Add filters as additional WHERE conditions
+ filter_conditions = []
+ for filter_key, filter_values in filters.items():
+ if isinstance(filter_values, list):
+ if len(filter_values) == 1:
+ safe_filter_key = u'"{}"'.format(filter_key.replace(u'"', u'""'))
+ safe_filter_value = str(filter_values[0]).replace(u"'", u"''")
+ filter_conditions.append(
+ u'{} = \'{}\''.format(safe_filter_key, safe_filter_value)
+ )
+ else:
+ safe_filter_key = u'"{}"'.format(filter_key.replace(u'"', u'""'))
+ values = u", ".join([u"'" + str(v).replace(u"'", u"''") + u"'" for v in filter_values])
+ filter_conditions.append(u'{} IN ({})'.format(safe_filter_key, values))
+ else:
+ safe_filter_key = u'"{}"'.format(filter_key.replace(u'"', u'""'))
+ safe_filter_value = str(filter_values).replace(u"'", u"''")
+ filter_conditions.append(
+ u'{} = \'{}\''.format(safe_filter_key, safe_filter_value)
+ )
+
+ if filter_conditions:
+ where_clauses.extend(filter_conditions)
+
+ where_clause = u' AND '.join(where_clauses)
+
+ # Build ORDER BY clause - quote column names to handle spaces
+ if sort_list:
+ quoted_sort_list = []
+ for sort_item in sort_list:
+ # sort_item format: "column_name asc" or "column_name desc"
+ # Split from the right (rsplit) to get direction and column name
+ # This handles column names with spaces correctly
+ parts = sort_item.rsplit(None, 1) # Split on whitespace from right, max 1 split
+ if len(parts) == 2:
+ col_name, direction = parts
+ # Quote column name to handle spaces and special characters
+ safe_col_name = u'"{}"'.format(col_name.replace(u'"', u'""'))
+ quoted_sort_list.append(u'{} {}'.format(safe_col_name, direction))
+ else:
+ # Fallback if format is unexpected - quote the whole thing
+ safe_col_name = u'"{}"'.format(sort_item.replace(u'"', u'""'))
+ quoted_sort_list.append(safe_col_name)
+ order_by = u', '.join(quoted_sort_list)
+ else:
+ order_by = u'"_id" asc'
+
+ # Build SELECT clause - escape column names
+ select_fields = u', '.join([u'"{}"'.format(col.replace(u'"', u'""')) for col in cols])
+
+ # CKAN datastore uses resource_id as table identifier
+ # Escape resource_id for SQL
+ safe_resource_id = resource_id.replace(u'"', u'""')
+
+ # Build SQL query - CKAN datastore_search_sql uses resource_id directly
+ sql = u'SELECT {select_fields} FROM "{safe_resource_id}" WHERE {where_clause} ORDER BY {order_by} LIMIT {limit} OFFSET {offset}'.format(
+ select_fields=select_fields,
+ safe_resource_id=safe_resource_id,
+ where_clause=where_clause,
+ order_by=order_by,
+ limit=limit,
+ offset=offset
+ )
+
+ # Also get total count for filtered results
+ count_sql = u'SELECT COUNT(*) as total FROM "{safe_resource_id}" WHERE {where_clause}'.format(
+ safe_resource_id=safe_resource_id,
+ where_clause=where_clause
+ )
+
+ try:
+ # Execute main query
+ response = datastore_search_sql(
+ None, {
+ u'sql': sql
+ }
+ )
+
+ # Execute count query
+ count_response = datastore_search_sql(
+ None, {
+ u'sql': count_sql
+ }
+ )
+
+ # datastore_search_sql returns records as list of dicts with column names as keys
+ records = response.get(u'records', [])
+
+ # Get total from count query
+ count_records = count_response.get(u'records', [])
+ total = count_records[0].get(u'total', 0) if count_records else 0
+
+ return {
+ u'records': records,
+ u'total': total,
+ u'fields': [{'id': col} for col in cols]
+ }
+ except Exception as e:
+ raise Exception(u'SQL query error: {}'.format(str(e)))
+
+
+def ajax(resource_view_id):
+ resource_view = get_action(u'resource_view_show'
+ )(None, {
+ u'id': resource_view_id
+ })
+
+ draw = int(request.form[u'draw'])
+ search_text = str(request.form[u'search[value]'])
+ offset = int(request.form[u'start'])
+ limit = int(request.form[u'length'])
+ view_filters = resource_view.get(u'filters', {})
+ user_filters = str(request.form[u'filters'])
+ filters = merge_filters(view_filters, user_filters)
+
+ datastore_search = get_action(u'datastore_search')
+ unfiltered_response = datastore_search(
+ None, {
+ u"resource_id": resource_view[u'resource_id'],
+ u"limit": 0,
+ u"filters": view_filters,
+ }
+ )
+
+ cols = [f[u'id'] for f in unfiltered_response[u'fields']]
+ if u'show_fields' in resource_view:
+ if '_id' not in resource_view[u'show_fields']:
+ resource_view[u'show_fields'].insert(0, '_id')
+ cols = [c for c in cols if c in resource_view[u'show_fields']]
+
+ sort_list = []
+ i = 0
+ while True:
+ if u'order[%d][column]' % i not in request.form:
+ break
+ sort_by_num = int(request.form[u'order[%d][column]' % i])
+ sort_order = (
+ u'desc' if request.form[u'order[%d][dir]' %
+ i] == u'desc' else u'asc'
+ )
+ sort_list.append(cols[sort_by_num] + u' ' + sort_order)
+ i += 1
+
+ # Add default sorting
+ if u'_id asc' not in sort_list and u'_id desc' not in sort_list:
+ sort_list.append(u'_id asc')
+
+ colsearch_dict = {}
+ date_range_filter = None
+ date_range_column = None
+
+ # Check merged filters for date range values (from URL parameters)
+ for filter_key, filter_values in filters.items():
+ if filter_values:
+ # Handle both single value and list of values
+ values_to_check = filter_values if isinstance(filter_values, list) else [filter_values]
+ for filter_value in values_to_check:
+ if filter_value:
+ # Check if this is a date range filter
+ is_date_range, start_date, end_date = is_date_range_filter(str(filter_value))
+ if is_date_range and is_date_column(filter_key, unfiltered_response[u'fields']):
+ # Store date range filter info
+ date_range_filter = (start_date, end_date)
+ date_range_column = filter_key
+ # Remove date range from regular filters (it will be handled by SQL query)
+ if isinstance(filters[filter_key], list):
+ filters[filter_key] = [v for v in filters[filter_key] if v != filter_value]
+ if not filters[filter_key]:
+ del filters[filter_key]
+ else:
+ del filters[filter_key]
+ break
+ if date_range_filter:
+ break
+
+ i = 0
+ while True:
+ if u'columns[%d][search][value]' % i not in request.form:
+ break
+ v = str(request.form[u'columns[%d][search][value]' % i])
+ if v:
+ k = str(request.form[u'columns[%d][name]' % i])
+ # Check if this is a date range filter (only if not already found in filters)
+ if not date_range_filter:
+ is_date_range, start_date, end_date = is_date_range_filter(v)
+ if is_date_range and is_date_column(k, unfiltered_response[u'fields']):
+ # Store date range filter info
+ date_range_filter = (start_date, end_date)
+ date_range_column = k
+ else:
+ # replace non-alphanumeric characters with FTS wildcard (_)
+ v = re.sub(r'[^0-9a-zA-Z\-]+', '_', v)
+ # append ':*' so we can do partial FTS searches
+ colsearch_dict[k] = v + u':*'
+ else:
+ # If date range already found, skip column search processing for date columns
+ if not (is_date_column(k, unfiltered_response[u'fields']) and is_date_range_filter(v)[0]):
+ # replace non-alphanumeric characters with FTS wildcard (_)
+ v = re.sub(r'[^0-9a-zA-Z\-]+', '_', v)
+ # append ':*' so we can do partial FTS searches
+ colsearch_dict[k] = v + u':*'
+ i += 1
+
+ # If date range filter is found, use SQL query instead
+ if date_range_filter:
+ try:
+ start_date, end_date = date_range_filter
+ response = datastore_search_sql_date_range(
+ resource_view[u'resource_id'],
+ date_range_column,
+ start_date,
+ end_date,
+ filters,
+ sort_list,
+ offset,
+ limit,
+ cols
+ )
+ except Exception as e:
+ query_error = u'Invalid date range query... ' + str(e)
+ dtdata = {u'error': query_error}
+ else:
+ data = []
+ null_label = h.og_datatablesview_null_label()
+ for row in response[u'records']:
+ record = {colname.replace('.', ''): escape(str(null_label if row.get(colname, u'')
+ is None else row.get(colname, u'')))
+ for colname in cols}
+ # the DT_RowId is used in DT to set an element id for each record
+ record['DT_RowId'] = 'row' + str(row.get(u'_id', u''))
+ data.append(record)
+
+ dtdata = {
+ u'draw': draw,
+ u'recordsTotal': unfiltered_response.get(u'total', 0),
+ u'recordsFiltered': response.get(u'total', 0),
+ u'data': data
+ }
+ else:
+ # Original logic for non-date-range filters
+ if colsearch_dict:
+ search_text = json.dumps(colsearch_dict)
+ else:
+ search_text = re.sub(r'[^0-9a-zA-Z\-]+', '_',
+ search_text) + u':*' if search_text else u''
+
+ try:
+ response = datastore_search(
+ None, {
+ u"q": search_text,
+ u"resource_id": resource_view[u'resource_id'],
+ u'plain': False,
+ u'language': u'simple',
+ u"offset": offset,
+ u"limit": limit,
+ u"sort": u', '.join(sort_list),
+ u"filters": filters,
+ }
+ )
+ except Exception:
+ query_error = u'Invalid search query... ' + search_text
+ dtdata = {u'error': query_error}
+ else:
+ data = []
+ null_label = h.og_datatablesview_null_label()
+ for row in response[u'records']:
+ record = {colname.replace('.', ''): escape(str(null_label if row.get(colname, u'')
+ is None else row.get(colname, u'')))
+ for colname in cols}
+ # the DT_RowId is used in DT to set an element id for each record
+ record['DT_RowId'] = 'row' + str(row.get(u'_id', u''))
+ data.append(record)
+
+ dtdata = {
+ u'draw': draw,
+ u'recordsTotal': unfiltered_response.get(u'total', 0),
+ u'recordsFiltered': response.get(u'total', 0),
+ u'data': data
+ }
+
+ return json.dumps(dtdata)
+
+
+def filtered_download(resource_view_id):
+ params = json.loads(request.form[u'params'])
+ resource_view = get_action(u'resource_view_show'
+ )(None, {
+ u'id': resource_view_id
+ })
+
+ search_text = str(params[u'search'][u'value'])
+ view_filters = resource_view.get(u'filters', {})
+ user_filters = str(params[u'filters'])
+ filters = merge_filters(view_filters, user_filters)
+
+ datastore_search = get_action(u'datastore_search')
+ unfiltered_response = datastore_search(
+ None, {
+ u"resource_id": resource_view[u'resource_id'],
+ u"limit": 0,
+ u"filters": view_filters,
+ }
+ )
+
+ cols = [f[u'id'] for f in unfiltered_response[u'fields']]
+ if u'show_fields' in resource_view:
+ if '_id' not in resource_view[u'show_fields']:
+ resource_view[u'show_fields'].insert(0, '_id')
+ cols = [c for c in cols if c in resource_view[u'show_fields']]
+
+ sort_list = []
+ for order in params[u'order']:
+ sort_by_num = int(order[u'column'])
+ sort_order = (u'desc' if order[u'dir'] == u'desc' else u'asc')
+ sort_list.append(cols[sort_by_num] + u' ' + sort_order)
+
+ cols = [c for (c, v) in zip(cols, params[u'visible']) if v]
+
+ colsearch_dict = {}
+ columns = params[u'columns']
+ for column in columns:
+ if column[u'search'][u'value']:
+ v = column[u'search'][u'value']
+ if v:
+ k = column[u'name']
+ # replace non-alphanumeric characters with FTS wildcard (_)
+ v = re.sub(r'[^0-9a-zA-Z\-]+', '_', v)
+ # append ':*' so we can do partial FTS searches
+ colsearch_dict[k] = v + u':*'
+
+ # Check for date range filters
+ date_range_filter = None
+ date_range_column = None
+ filters_for_query = {}
+
+ for filter_key, filter_values in filters.items():
+ if filter_values:
+ # Handle both single value and list of values
+ values_to_check = filter_values if isinstance(filter_values, list) else [filter_values]
+ has_date_range = False
+ for filter_value in values_to_check:
+ if filter_value:
+ # Check if this is a date range filter
+ is_date_range, start_date, end_date = is_date_range_filter(str(filter_value))
+ if is_date_range and is_date_column(filter_key, unfiltered_response[u'fields']):
+ # Store date range filter info
+ date_range_filter = (start_date, end_date)
+ date_range_column = filter_key
+ has_date_range = True
+ break
+
+ # Add to filters_for_query if not a date range
+ if not has_date_range:
+ filters_for_query[filter_key] = filter_values
+
+ # If we have a date range filter, use SQL query for export
+ if date_range_filter:
+ start_date, end_date = date_range_filter
+ try:
+ # Get all records using SQL query with date range
+ # Use a large limit to get all records for export
+ response = datastore_search_sql_date_range(
+ resource_view[u'resource_id'],
+ date_range_column,
+ start_date,
+ end_date,
+ filters_for_query,
+ sort_list,
+ 0, # offset
+ 1000000, # large limit to get all records
+ cols
+ )
+ records = response.get(u'records', [])
+ except Exception as e:
+ # Fall back to regular search if SQL query fails
+ data = {
+ u"resource_id": resource_view[u'resource_id'],
+ u"filters": filters_for_query,
+ u"limit": 1000000,
+ u"sort": u','.join(sort_list) if sort_list else None,
+ }
+ response = datastore_search(None, data)
+ records = response.get(u'records', [])
+ else:
+ # No date range, use regular datastore_search
+ # Build query string for FTS search
+ if colsearch_dict:
+ search_text = json.dumps(colsearch_dict)
+ else:
+ search_text = re.sub(r'[^0-9a-zA-Z\-]+', '_',
+ search_text) + u':*' if search_text else ''
+
+ # Use redirect to datastore.dump for non-date-range exports
+ return h.redirect_to(
+ h.url_for(
+ u'datastore.dump',
+ resource_id=resource_view[u'resource_id']) + u'?' + urlencode(
+ {
+ u'q': search_text,
+ u'plain': False,
+ u'language': u'simple',
+ u'sort': u','.join(sort_list),
+ u'filters': json.dumps(filters_for_query),
+ u'format': request.form[u'format'],
+ u'fields': u','.join(cols),
+ }))
+
+ # Format the export based on requested format
+ export_format = request.form.get(u'format', u'csv').lower()
+
+ if export_format == u'csv':
+ output = io.StringIO()
+ if records:
+ writer = csv.DictWriter(output, fieldnames=cols, extrasaction='ignore')
+ writer.writeheader()
+ for record in records:
+ writer.writerow(record)
+ return Response(
+ output.getvalue(),
+ mimetype='text/csv',
+ headers={'Content-Disposition': 'attachment; filename=export.csv'}
+ )
+ elif export_format == u'tsv':
+ output = io.StringIO()
+ if records:
+ writer = csv.DictWriter(output, fieldnames=cols, delimiter='\t', extrasaction='ignore')
+ writer.writeheader()
+ for record in records:
+ writer.writerow(record)
+ return Response(
+ output.getvalue(),
+ mimetype='text/tab-separated-values',
+ headers={'Content-Disposition': 'attachment; filename=export.tsv'}
+ )
+ elif export_format == u'json':
+ return Response(
+ json.dumps(records, indent=2),
+ mimetype='application/json',
+ headers={'Content-Disposition': 'attachment; filename=export.json'}
+ )
+ else:
+ # Default to CSV
+ output = io.StringIO()
+ if records:
+ writer = csv.DictWriter(output, fieldnames=cols, extrasaction='ignore')
+ writer.writeheader()
+ for record in records:
+ writer.writerow(record)
+ return Response(
+ output.getvalue(),
+ mimetype='text/csv',
+ headers={'Content-Disposition': 'attachment; filename=export.csv'}
+ )
+
+
+ogdatatablesdatefilterview.add_url_rule(
+ u'/og_datatables_datefilter/ajax/',
+ view_func=ajax, methods=[u'POST']
+)
+
+ogdatatablesdatefilterview.add_url_rule(
+ u'/og_datatables_datefilter/filtered-download/',
+ view_func=filtered_download, methods=[u'POST']
+)
diff --git a/ckanext/og_datatables_datefilterview/helpers.py b/ckanext/og_datatables_datefilterview/helpers.py
new file mode 100644
index 0000000..67d4c63
--- /dev/null
+++ b/ckanext/og_datatables_datefilterview/helpers.py
@@ -0,0 +1,38 @@
+# encoding: utf-8
+import ckan.plugins.toolkit as toolkit
+from typing import (
+ Any, Optional
+)
+
+
+def og_datatables_datefilterview_null_label() -> str:
+ """
+ Get the label used to display NoneType values for the front-end
+
+ :returns: The label.
+ :rtype: str
+ """
+ label = toolkit.config.get("ckan.datatables.null_label")
+ return toolkit._(label) if label else ""
+
+
+def og_datastore_dictionary(
+ resource_id: str, include_columns: Optional[list[str]] = None
+) -> list[dict[str, Any]]:
+ """
+ Return the data dictionary info for a resource, optionally filtering
+ columns returned.
+
+ include_columns is a list of column ids to include in the output
+ """
+ try:
+ return [
+ f for f in toolkit.get_action('datastore_search')({}, {
+ 'id': resource_id,
+ 'limit': 0
+ })['fields']
+ if not f['id'].startswith(u'_') and (
+ include_columns is None or f['id'] in include_columns)
+ ]
+ except (toolkit.ObjectNotFound, toolkit.NotAuthorized):
+ return []
diff --git a/ckanext/og_datatables_datefilterview/plugin.py b/ckanext/og_datatables_datefilterview/plugin.py
new file mode 100644
index 0000000..20a3f35
--- /dev/null
+++ b/ckanext/og_datatables_datefilterview/plugin.py
@@ -0,0 +1,186 @@
+# encoding: utf-8
+
+import ckan.plugins as p
+import ckan.plugins.toolkit as toolkit
+import ckan.lib.navl.dictization_functions as df
+import ckanext.og_datatables_datefilterview.helpers as helpers
+from ckanext.og_datatables_datefilterview import blueprint
+
+missing = df.missing
+
+default = toolkit.get_validator(u'default')
+boolean_validator = toolkit.get_validator(u'boolean_validator')
+natural_number_validator = toolkit.get_validator(u'natural_number_validator')
+ignore_missing = toolkit.get_validator(u'ignore_missing')
+
+DEFAULT_PAGE_LENGTH_CHOICES = '25 50 100 500'
+
+
+class OG_DataTablesDateFilterView(p.SingletonPlugin):
+ u'''
+ DataTables table view plugin
+ '''
+ p.implements(p.IConfigurer, inherit=True)
+ p.implements(p.IResourceView, inherit=True)
+ p.implements(p.IBlueprint)
+ p.implements(p.IValidators)
+ p.implements(p.ITemplateHelpers)
+
+ # IBlueprint
+
+ def get_blueprint(self):
+ return blueprint.ogdatatablesdatefilterview
+
+ # IConfigurer
+
+ def update_config(self, config):
+ u'''
+ Set up the resource library, public directory and
+ template directory for the view
+ '''
+
+ self.responsive_button_def = toolkit.asbool(
+ config.get(u'ckan.datatables.view_table_responsive_default', False))
+ self.col_unhide_button_def = toolkit.asbool(
+ config.get(u'ckan.datatables.view_table_columnhide_default', True))
+ self.export_button_def = toolkit.asbool(
+ config.get(u'ckan.datatables.view_table_displayexport_default', False))
+ self.copy_print_buttons_def = toolkit.asbool(
+ config.get(u'ckan.datatables.view_table_displaycopyprint_default', False))
+ self.col_reorder_def = toolkit.asbool(
+ config.get(u'ckan.datatables.view_table_colreorder_default', True))
+
+ # https://datatables.net/reference/option/lengthMenu
+ self.page_length_choices = toolkit.aslist(
+ config.get(
+ u'ckan.datatables.page_length_choices',
+ DEFAULT_PAGE_LENGTH_CHOICES
+ )
+ )
+ self.page_length_choices = [int(i) for i in self.page_length_choices]
+ self.state_saving = config.get(u'ckan.datatables.state_saving', True)
+
+ # https://datatables.net/reference/option/stateDuration
+ self.state_duration = config.get(
+ u"ckan.datatables.state_duration", 7200)
+ self.data_dictionary_labels = config.get(
+ u"ckan.datatables.data_dictionary_labels", False)
+ self.ellipsis_length = config.get(
+ u"ckan.datatables.ellipsis_length", 0)
+ self.date_format = config.get(u"ckan.datatables.date_format", "llll")
+ self.default_view = config.get(u"ckan.datatables.default_view", "table")
+
+ toolkit.add_template_directory(config, u'templates')
+ toolkit.add_public_directory(config, u'assets')
+ toolkit.add_resource(u'assets', u'ckanext-og_datatables_datefilterview')
+
+ # IResourceView
+
+ def can_view(self, data_dict):
+ resource = data_dict['resource']
+ return resource.get(u'datastore_active')
+
+ def setup_template_variables(self, context, data_dict):
+ return {u'page_length_choices': self.page_length_choices,
+ u'state_saving': self.state_saving,
+ u'state_duration': self.state_duration,
+ u'data_dictionary_labels': self.data_dictionary_labels,
+ u'ellipsis_length': self.ellipsis_length,
+ u'date_format': self.date_format,
+ u'default_view': self.default_view}
+
+ def view_template(self, context, data_dict):
+ resource_view = data_dict.get('resource_view')
+ sort_column = resource_view.get('sort_column')
+ show_fields = resource_view.get('show_fields', [])
+ # Set the index of the sort column if it's displayed
+ if sort_column in show_fields:
+ sort_index = show_fields.index(sort_column)
+ data_dict['resource_view']['sort_index'] = sort_index
+ return u'og_datatables_datefilterview/datatables_view.html'
+
+ def form_template(self, context, data_dict):
+ data_dict['resource_view']['responsive_button_def'] = self.responsive_button_def
+ data_dict['resource_view']['col_unhide_button_def'] = self.col_unhide_button_def
+ data_dict['resource_view']['export_button_def'] = self.export_button_def
+ data_dict['resource_view']['copy_print_buttons_def'] = self.copy_print_buttons_def
+ data_dict['resource_view']['col_reorder_def'] = self.col_reorder_def
+ return u'og_datatables_datefilterview/datatables_form.html'
+
+ def info(self):
+ return {
+ u'name': u'og_datatables_datefilter_view',
+ u'title': u'Data Table with Date Filter',
+ u'filterable': True,
+ u'icon': u'table',
+ u'requires_datastore': True,
+ u'default_title': p.toolkit._(u'Data Table'),
+ u'preview_enabled': False,
+ u'schema': {
+ # The root of the problem here is that this info(self) method is called on two different scenarios:
+ # 1. When the user is creating/updating a view with their browser (form_template method)
+ # 2. When ckan is creating a new view from a resource that was just uploaded (ckan.views.default_views)
+
+ # Why we cannot use the default(True) validator here:
+ # When the web user unchecks the checkbox and saves, the browser POSTs a null value for
+ # that key, so: if the user unchecked the checkbox and saved, the value will be null
+ # and if we have default(True) validator, it will be set to True, as the
+ # validator will replace the null value with true, which is the opposite of what the user wanted
+ # (The CRD that started this issue)
+
+ # We also cannot use the default(False) validator here,
+ # When you upload a new csv, ckan will automatically create a DataTable view using this info() method
+ # and we need it to use the configurable values when that happens, not a hardcoded value. The problem
+ # there is, when the view is being created by ckan, it doesn't use the form_template() method above,
+ # so the configurable defaults are not being followed.
+
+ # The only way to fix both problems is writing our own validator, because Null means either the user
+ # unchecked the checkbox or the view is being created by ckan. If it was the user, it should be false,
+ # if it was CKAN, it should be the default value by configuration.
+ u'responsive': [configurabledefaults_validator(self.responsive_button_def), boolean_validator],
+ u'col_unhide_button': [configurabledefaults_validator(self.col_unhide_button_def), boolean_validator],
+ u'export_button': [configurabledefaults_validator(self.export_button_def), boolean_validator],
+ u'copy_print_buttons': [configurabledefaults_validator(self.copy_print_buttons_def), boolean_validator],
+ u'col_reorder': [configurabledefaults_validator(self.col_reorder_def), boolean_validator],
+ u'ellipsis_length': [default(self.ellipsis_length),
+ natural_number_validator],
+ u'date_format': [default(self.date_format)],
+ u'show_fields': [ignore_missing],
+ u'sort_column': [ignore_missing],
+ u'sort_order': [ignore_missing],
+ u'filterable': [default(True), boolean_validator],
+ }
+ }
+
+ # IValidators
+
+ def get_validators(self):
+ return {
+ 'configurabledefaults_validator': configurabledefaults_validator,
+ }
+
+ # ITemplateHelpers
+
+ def get_helpers(self):
+ return {
+ 'og_datatables_datefilterview_null_label': helpers.og_datatables_datefilterview_null_label,
+ 'og_datastore_dictionary': helpers.og_datastore_dictionary,
+ }
+
+
+def configurabledefaults_validator(default_configurable_value):
+ def callable(key, data, errors, context):
+ # looking at the "for_view" property we can determine if the view is being created
+ # by the internal default view mechanism or by the user's browser
+ if context.get('for_view'):
+ # This means the user is creating/editing the view with their browser
+ # so we set the values chosen by the user,
+ if data.get(key) is missing or data.get(key) is None or data.get(key) == '':
+ # When the web user unchecks the checkbox and saves,
+ # the browser POSTs a null value, so we set it to False
+ data[key] = False
+ else:
+ # the view is being created by the default view mechanism,
+ # so we set the values following the configurable defaults
+ data[key] = default_configurable_value
+ return callable
diff --git a/ckanext/og_datatables_datefilterview/templates/.gitignore b/ckanext/og_datatables_datefilterview/templates/.gitignore
new file mode 100644
index 0000000..e69de29
diff --git a/ckanext/og_datatables_datefilterview/templates/og_datatables_datefilterview/datatables_form.html b/ckanext/og_datatables_datefilterview/templates/og_datatables_datefilterview/datatables_form.html
new file mode 100644
index 0000000..17650b6
--- /dev/null
+++ b/ckanext/og_datatables_datefilterview/templates/og_datatables_datefilterview/datatables_form.html
@@ -0,0 +1,132 @@
+{% import 'macros/form.html' as form %}
+
+
+
+
+
{{ _('Show Columns') }}
+
+
+ {{ _('Show All') }}
+ {{ _('Hide All') }}
+
+
+
+
+
+
+{% asset 'ckanext-og_datatablesview/form-js' %}
\ No newline at end of file
diff --git a/ckanext/og_datatables_datefilterview/templates/og_datatables_datefilterview/datatables_view.html b/ckanext/og_datatables_datefilterview/templates/og_datatables_datefilterview/datatables_view.html
new file mode 100644
index 0000000..011e8df
--- /dev/null
+++ b/ckanext/og_datatables_datefilterview/templates/og_datatables_datefilterview/datatables_view.html
@@ -0,0 +1,117 @@
+{% extends "base.html" %}
+
+{% block title %}{{ h.dataset_display_name(package)}}—{{ h.resource_display_name(resource)}} - {{ super() }}{% endblock %}
+{% block bodytag %}
+ {{- super() -}}
+ class="dt-view"
+{%- endblock -%}
+
+{% block page %}
+{% set ajax_url = h.url_for('ogdatatablesdatefilterview.ajax', resource_view_id=resource_view.id) %}
+{% set filtered_download_action = h.url_for('ogdatatablesdatefilterview.filtered_download', resource_view_id=resource_view.id) %}
+
+{#- pass the datadictionary to javascript, so we can init columns there -#}
+{%- set datadictionary = h.og_datastore_dictionary(resource.id, resource_view.get('show_fields')) -%}
+{%- set nbspval = " "|safe -%}
+
+
+
+
+
+
+
+ _id
+ {% for field in datadictionary -%}
+ {% if 'show_fields' not in resource_view or field.id in resource_view.show_fields -%}
+
+ {%- if data_dictionary_labels and field.info is defined and field.info.label|length -%}
+ {{ field.info.label|replace(" ", nbspval) }}
+ {%- else -%}
+ {{ field.id|replace(" ", nbspval) }}
+ {%- endif -%}
+
+ {%- if data_dictionary_labels and field.info is defined and (field.info.label|length or field.info.notes|length)-%}
+
+ {%- endif -%}
+
+ {%- endif %}
+ {% endfor -%}
+ colspacer
+
+
+
+ {% for field in datadictionary -%}
+ {% if 'show_fields' not in resource_view or field.id in resource_view.show_fields -%}
+
+ {{- field.id -}}
+
+ {% endif -%}
+ {% endfor -%}
+
+
+
+
+
+
+
+
+
+
+{#- we do this macro instead of the snippet because the snippet pollutes the output with comments/whitespaces which #}
+{# may be invisible for regular html, but not for tooltips -#}
+{%- macro local_friendly_datetime(dt_obj) -%}
+
+ {{- h.render_datetime(dt_obj, with_hours=True) -}}
+
+{%- endmacro -%}
+
+{#- we create tooltip here instead of javascript so we can leverage the automatic-local-datetime class date conversion CKAN does -#}
+{%- set res = resource %}
+
+ {{- _('Data last updated') }}: {{ local_friendly_datetime(res.last_modified) }}
+ {{- _('Metadata last updated') }}: {{ local_friendly_datetime(res.metadata_modified) }}
+ {{- _('Created') }}: {{ local_friendly_datetime(res.created) }}
+ {{- res.format or res.mimetype_inner or res.mimetype or _('unknown') -}}
+ {%- if res.size and res.size|int != 0 -%}
+ ( {{ h.SI_number_span(res.size)|striptags }} )
+ {%- endif -%}
+
+{%- endblock -%}
+
+{%- block styles -%}
+ {{- super() -}}
+ {% asset 'ckanext-og_datatables_datefilterview/main-css' %}
+ {% asset 'ckanext-og_datatables_datefilterview/main-js' %}
+{% endblock %}
+{% block custom_styles %}{% endblock %}
diff --git a/setup.py b/setup.py
index 8a5dddb..768430a 100644
--- a/setup.py
+++ b/setup.py
@@ -82,6 +82,7 @@
entry_points='''
[ckan.plugins]
og_datatables_view=ckanext.og_datatablesview.plugin:OG_DataTablesView
+ og_datatables_datefilter_view=ckanext.og_datatables_datefilterview.plugin:OG_DataTablesDateFilterView
[babel.extractors]
ckan = ckan.lib.extract:extract_ckan