diff --git a/.npm/package/.gitignore b/.npm/package/.gitignore
deleted file mode 100644
index 3c3629e..0000000
--- a/.npm/package/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-node_modules
diff --git a/.npm/package/README b/.npm/package/README
deleted file mode 100644
index 3d49255..0000000
--- a/.npm/package/README
+++ /dev/null
@@ -1,7 +0,0 @@
-This directory and the files immediately inside it are automatically generated
-when you change this package's NPM dependencies. Commit the files in this
-directory (npm-shrinkwrap.json, .gitignore, and this README) to source control
-so that others run the same versions of sub-dependencies.
-
-You should NOT check in the node_modules directory that Meteor automatically
-creates; if you are using git, the .gitignore file tells git to ignore it.
diff --git a/.npm/package/npm-shrinkwrap.json b/.npm/package/npm-shrinkwrap.json
deleted file mode 100644
index 84fe8dc..0000000
--- a/.npm/package/npm-shrinkwrap.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "lockfileVersion": 1,
- "dependencies": {
- "datatables.net": {
- "version": "2.0.8",
- "resolved": "https://registry.npmjs.org/datatables.net/-/datatables.net-2.0.8.tgz",
- "integrity": "sha512-4/2dYx4vl975zQqZbyoVEm0huPe61qffjBRby7K7V+y9E+ORq4R8KavkgrNMmIgO6cl85Pg4AvCbVjvPCIT1Yg=="
- },
- "jquery": {
- "version": "3.7.1",
- "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.7.1.tgz",
- "integrity": "sha512-m4avr8yL8kmFN8psrbFFFmB/If14iN5o9nw/NgnnM+kybDJpRsAynV2BsfpTYrTRysYUdADVD7CkUUizgkpLfg=="
- }
- }
-}
diff --git a/.versions b/.versions
index 6b0a62b..61b8746 100644
--- a/.versions
+++ b/.versions
@@ -1,65 +1,69 @@
-aldeed:tabular@3.0.0-rc.0
-allow-deny@1.1.1
+aldeed:tabular@3.0.0-rc.4
+allow-deny@2.0.0
anti:fake@0.4.1
-babel-compiler@7.10.5
-babel-runtime@1.5.1
-base64@1.0.12
-binary-heap@1.0.11
-blaze@2.9.0
-blaze-tools@1.0.10
-boilerplate-generator@1.7.2
-caching-compiler@1.2.2
-caching-html-compiler@1.0.5
-callback-hook@1.5.1
-check@1.4.1
-ddp@1.4.1
-ddp-client@2.6.2
-ddp-common@1.4.1
-ddp-server@2.7.1
-diff-sequence@1.1.2
-dynamic-import@0.7.3
-ecmascript@0.16.8
-ecmascript-runtime@0.8.1
-ecmascript-runtime-client@0.12.1
-ecmascript-runtime-server@0.11.0
-ejson@1.1.3
-fetch@0.1.4
-geojson-utils@1.0.11
-html-tools@1.0.11
-htmljs@1.2.1
-id-map@1.1.1
-inter-process-messaging@0.1.1
-local-test:aldeed:tabular@3.0.0-rc.0
-logging@1.3.4
-meteor@1.11.5
-minimongo@1.9.4
-modern-browsers@0.1.10
-modules@0.20.0
-modules-runtime@0.13.1
-mongo@1.16.10
-mongo-decimal@0.1.3
-mongo-dev-server@1.1.0
-mongo-id@1.0.8
-npm-mongo@4.17.2
-observe-sequence@1.0.21
-ordered-dict@1.1.0
-promise@0.12.2
-random@1.2.1
-react-fast-refresh@0.2.8
-reactive-dict@1.3.1
-reactive-var@1.0.12
-reload@1.3.1
-retry@1.1.0
-routepolicy@1.1.1
-session@1.2.1
-socket-stream-client@0.5.2
-spacebars@1.0.10
-spacebars-compiler@1.1.0
-templating@1.1.8
-templating-tools@1.1.1
-tinytest@1.2.3
-tracker@1.3.3
-typescript@4.9.5
-underscore@1.6.1
-webapp@1.13.8
-webapp-hashing@1.1.1
+babel-compiler@7.11.0
+babel-runtime@1.5.2
+base64@1.0.13
+binary-heap@1.0.12
+blaze@3.0.0
+blaze-tools@2.0.0
+boilerplate-generator@2.0.0
+caching-compiler@2.0.0
+caching-html-compiler@2.0.0
+callback-hook@1.6.0
+check@1.4.2
+core-runtime@1.0.0
+ddp@1.4.2
+ddp-client@3.0.1
+ddp-common@1.4.4
+ddp-server@3.0.1
+diff-sequence@1.1.3
+dynamic-import@0.7.4
+ecmascript@0.16.9
+ecmascript-runtime@0.8.2
+ecmascript-runtime-client@0.12.2
+ecmascript-runtime-server@0.11.1
+ejson@1.1.4
+facts-base@1.0.2
+fetch@0.1.5
+geojson-utils@1.0.12
+html-tools@2.0.0
+htmljs@2.0.1
+id-map@1.2.0
+inter-process-messaging@0.1.2
+local-test:aldeed:tabular@3.0.0-rc.4
+logging@1.3.5
+meteor@2.0.1
+minimongo@2.0.1
+modern-browsers@0.1.11
+modules@0.20.1
+modules-runtime@0.13.2
+mongo@2.0.2
+mongo-decimal@0.1.4-beta300.7
+mongo-dev-server@1.1.1
+mongo-id@1.0.9
+npm-mongo@4.17.4
+observe-sequence@2.0.0
+ordered-dict@1.2.0
+promise@1.0.0
+random@1.2.2
+react-fast-refresh@0.2.9
+reactive-dict@1.3.2
+reactive-var@1.0.13
+reload@1.3.2
+retry@1.1.1
+routepolicy@1.1.2
+session@1.2.2
+socket-stream-client@0.5.3
+spacebars@2.0.0
+spacebars-compiler@2.0.0
+templating@1.4.4
+templating-compiler@2.0.0
+templating-runtime@2.0.0
+templating-tools@2.0.0
+tinytest@1.3.0
+tracker@1.3.4
+typescript@5.4.3
+underscore@1.6.4
+webapp@2.0.1
+webapp-hashing@1.1.2
diff --git a/README.md b/README.md
index 8bc33a9..4abd49e 100755
--- a/README.md
+++ b/README.md
@@ -1,5 +1,4 @@
-aldeed:tabular
-=========================
+# aldeed:tabular
A Meteor package that creates reactive [DataTables](http://datatables.net/) in an efficient way, allowing you to display the contents of enormous collections without impacting app performance.
@@ -50,14 +49,12 @@ Please open an issue if you like to help out with maintenance on this package.
-## ATTENTION: Updating to 2.0
+## ATTENTION: Release v3 and datatables 2.x
-Version 2.0 API is backwards compatible other than the following changes:
-- Requires Meteor 1.3+
-- You must explicitly import the `Tabular` object into every file where you use it. (`import Tabular from 'meteor/aldeed:tabular';`)
-- You must configure the Bootstrap theme (or whatever theme you want) yourself. See [Installing and Configuring a Theme](#installing-and-configuring-a-theme)
+Version 3.0 is Meteor 3 compatible but **slightly breaking** in order to support more flexibility in importing
+different versions of DataTables.
-This version also includes a few fixes and a few new features.
+Read the respective sections on how to install/setup aldeed:tabular v3
## Features
@@ -87,27 +84,58 @@ This example is for the Bootstrap theme. You can use another theme package. See
First:
```bash
-$ npm install --save jquery@1.12.1 datatables.net-bs
+$ meteor add jquery@3.0.2
+$ npm install --save jquery@latest datatables.net-bs@latest
```
-Note that we install jquery@1.12.1. This needs to match the current version of jQuery included with Meteor's `jquery` package. (See the version comment in https://github.com/meteor/meteor/blob/master/packages/non-core/jquery/package.js) Otherwise, due to the `datatables.net` package depending on `jquery` NPM package, it might automatically install the latest `jquery` version, which may conflict with Bootstrap or Meteor.
+> Heads up! If you want to use datatables 2.x and newer, you need to [recompile these modules](https://guide.meteor.com/using-npm-packages#recompile)
+> or they will not detect the correct jquery module :-(
+
+FOr this, open `package.json` and add to the `"meteor": {...}` the the nodes modules to recompile:
+
+```json
+{
+ "meteor": {
+ "nodeModules": {
+ "recompile": {
+ "datatables.net": ["client", "legacy"],
+ "datatables.net-bs": ["client", "legacy"]
+ }
+ }
+ }
+}
+```
+
+In this example the datatables core and bootstrap are recopmiled.
+While core (`datatables.net`) is always to be added, the other packages may vary, depending on your needs.
Then, somewhere in your client JavaScript:
+**Datatables 1.x**
+
```js
import { $ } from 'meteor/jquery';
+import Tabular from 'meteor/aldeeed:tabular'
import dataTablesBootstrap from 'datatables.net-bs';
import 'datatables.net-bs/css/dataTables.bootstrap.css';
+// and maybe other DT imports
+
dataTablesBootstrap(window, $);
+// and maybe other DT-init calls
+
+// finally initializing Tabular
+Tabular.init()
```
-## Online Demo App
+**Datatables 2.x**
-View a [demonstration project on Meteorpad](http://meteorpad.com/pad/xNafF9N5XJNrFJEyG/TabularDemo).
+```js
+import DataTables from 'datatables.net-bs';
+import 'datatables.net-bs/css/dataTables.bootstrap.css';
+// and maybe other DT imports
-Another example app courtesy of @AnnotatedJS:
-* Hosted app: http://greatalbums.meteor.com/albums (You can sign in with email "admin@demo.com" and password "password")
-* Source: https://github.com/AnnotatedJS/GreatAlbums
+Tabular.init({ DataTables })
+```
## Example
@@ -604,6 +632,10 @@ For package names for other themes, see https://datatables.net/download/npm
Once the packages are installed, you need to import them in one of your client JavaScript files:
+
+datatables.net 1.x
+
+
```js
import { $ } from 'meteor/jquery';
@@ -629,6 +661,47 @@ flashExportButtons(window, $);
printButton(window, $);
```
+
+
+
+
+datatables.net >= 2.x
+
+You need to have Meteor [to recompile the packages](https://guide.meteor.com/using-npm-packages#recompile):
+
+```json
+{
+ ...
+ "meteor": {
+ ...
+ "nodeModules": {
+ "recompile": {
+ "datatables.net": ["client", "legacy"],
+ "datatables.net-bs": ["client", "legacy"],
+ "datatables.net-buttons": ["client", "legacy"],
+ "datatables.net-buttons-bs": ["client", "legacy"]
+ }
+ }
+ }
+}
+```
+
+```js
+// Bootstrap Theme
+import 'datatables.net-bs';
+import 'datatables.net-bs/css/dataTables.bootstrap.css';
+
+// Buttons Core
+import 'datatables.net-buttons-bs';
+// Import whichever buttons you are using
+import 'datatables.net-buttons/js/buttons.colVis.js';
+import 'datatables.net-buttons/js/buttons.html5.js';
+import 'datatables.net-buttons/js/buttons.flash.js';
+import 'datatables.net-buttons/js/buttons.print.js';
+```
+
+
+
Finally, for the Tabular tables that need them, add the `buttons` and `buttonContainer` options. The `buttons` option is part of DataTables and is documented here: https://datatables.net/extensions/buttons/ The `buttonContainer` option is part of `aldeed:tabular` and does the tricky task of appending the buttons to some element in the generated table. Set it to the CSS selector for the container.
Bootstrap example:
diff --git a/client/main.js b/client/main.js
index 3a0d41b..4fc3bf5 100644
--- a/client/main.js
+++ b/client/main.js
@@ -1,558 +1,572 @@
+/* global _, Blaze, Tracker, ReactiveVar, Session, Meteor, $ */
import './tabular.html';
-
-/* global _, Blaze, Tracker, ReactiveVar, Session, Meteor, */
-import { $ } from 'meteor/jquery';
-//This is a bit shit that we're initialising this explicit version within the library
-import 'datatables.net-bs5';
-
import { Mongo } from 'meteor/mongo';
import { Template } from 'meteor/templating';
-
import Tabular from '../common/Tabular';
import tableInit from './tableInit';
import getPubSelector from './getPubSelector';
import { getMongoSort, objectsAreEqual, sortsAreEqual } from '../common/util';
-//dataTableInit(window, $);
Template.registerHelper('TabularTables', Tabular.tablesByName);
Tabular.tableRecords = new Mongo.Collection('tabular_records');
Tabular.remoteTableRecords = [];
-Tabular.getTableRecordsCollection = function (connection) {
- if (!connection || connection === Tabular.tableRecords._connection) {
- return Tabular.tableRecords;
- }
+/**
+ * Initialize tabular after you've imported your DataTable code, so
+ * there are no conflicts or race conditions.
+ *
+ * Dependening on which datatables versions you use,
+ * you might want to pass the DataTable constructor directly.
+ *
+ * @param DataTable {object=} only pass this instance if you're using DataTables >= 2.x
+ */
+Tabular.init = ({ DataTable } = {}) => {
+ Tabular.getTableRecordsCollection = function (connection) {
+ if (!connection || connection === Tabular.tableRecords._connection) {
+ return Tabular.tableRecords;
+ }
- let remote = _.find(Tabular.remoteTableRecords, (remote) => remote.connection === connection);
- if (!remote) {
- remote = {
- connection,
- tableRecords: new Mongo.Collection('tabular_records', { connection })
- };
- Tabular.remoteTableRecords.push(remote);
- }
- return remote.tableRecords;
-};
-
-Tabular.getRecord = function (name, collection) {
- return Tabular.getTableRecordsCollection(collection._connection).findOne(name);
-};
-
-Template.tabular.helpers({
- atts() {
- // We remove the "table" and "selector" attributes and assume the rest belong
- // on the
element
- return _.omit(this, 'table', 'selector');
+ let remote = _.find(Tabular.remoteTableRecords, (remote) => remote.connection === connection);
+ if (!remote) {
+ remote = {
+ connection,
+ tableRecords: new Mongo.Collection('tabular_records', { connection })
+ };
+ Tabular.remoteTableRecords.push(remote);
+ }
+ return remote.tableRecords;
+ };
+
+ Tabular.getRecord = function (name, collection) {
+ return Tabular.getTableRecordsCollection(collection._connection).findOne(name);
+ };
+
+ Template.tabular.helpers({
+ atts () {
+ // We remove the "table" and "selector" attributes and assume the rest belong
+ // on the element
+ return _.omit(this, 'table', 'selector');
+ }
+ });
+
+
+ const createDatatable = (template, options) => {
+ return DataTable
+ ? new DataTable(template.data?.id
+ ? `#${template.data?.id}`
+ :template.$tableElement.get(0), options)
+ : template.$tableElement.DataTable(options)
}
-});
-
-Template.tabular.onRendered(function () {
- const template = this;
- template.$tableElement = template.$('table');
- let table;
- let resetTablePaging = false;
-
- template.tabular = {};
- template.tabular.data = [];
- template.tabular.pubSelector = new ReactiveVar({}, objectsAreEqual);
- template.tabular.skip = new ReactiveVar(0);
- template.tabular.limit = new ReactiveVar(10);
- template.tabular.sort = new ReactiveVar(null, sortsAreEqual);
- template.tabular.columns = null;
- template.tabular.fields = null;
- template.tabular.searchFields = null;
- template.tabular.searchCaseInsensitive = true;
- template.tabular.splitSearchByWhitespace = true;
- template.tabular.tableName = new ReactiveVar(null);
- template.tabular.options = new ReactiveVar({}, objectsAreEqual);
- template.tabular.docPub = new ReactiveVar(null);
- template.tabular.collection = new ReactiveVar(null);
- template.tabular.connection = null;
- template.tabular.ready = new ReactiveVar(false);
- template.tabular.recordsTotal = 0;
- template.tabular.recordsFiltered = 0;
- template.tabular.isLoading = new ReactiveVar(true);
- template.tabular.blazeViews = [];
- template.tabular.searchTerm = new ReactiveVar(this.data.searchTerm || null);
-
- // These are some DataTables options that we need for everything to work.
- // We add them to the options specified by the user.
- const ajaxOptions = {
- // tell DataTables that we're getting the table data from a server
- serverSide: true,
- processing: true,
- // define the function that DataTables will call upon first load and whenever
- // we tell it to reload data, such as when paging, etc.
- ajax: function (data, callback /*, settings*/) {
- // When DataTables requests data, first we set
- // the new skip, limit, order, and pubSelector values
- // that DataTables has requested. These trigger
- // the first subscription, which will then trigger the
- // second subscription.
-
- //console.log( 'data', data, 'template.tabular.data', template.tabular.data );
-
- // Update skip
- template.tabular.skip.set(data.start);
- Session.set('Tabular.LastSkip', data.start);
-
- // Update limit
- let options = template.tabular.options.get();
- let hardLimit = options && options.limit;
- if (data.length === -1) {
- if (hardLimit === undefined) {
- console.warn(
- 'When using no paging or an "All" option with tabular, it is best to also add a hard limit in your table options like {limit: 500}'
- );
- template.tabular.limit.set(null);
- } else {
- template.tabular.limit.set(hardLimit);
+
+ Template.tabular.onRendered(function () {
+ const template = this;
+ template.$tableElement = template.$('table');
+ let table;
+ let resetTablePaging = false;
+
+ template.tabular = {};
+ template.tabular.data = [];
+ template.tabular.pubSelector = new ReactiveVar({}, objectsAreEqual);
+ template.tabular.skip = new ReactiveVar(0);
+ template.tabular.limit = new ReactiveVar(10);
+ template.tabular.sort = new ReactiveVar(null, sortsAreEqual);
+ template.tabular.columns = null;
+ template.tabular.fields = null;
+ template.tabular.searchFields = null;
+ template.tabular.searchCaseInsensitive = true;
+ template.tabular.splitSearchByWhitespace = true;
+ template.tabular.tableName = new ReactiveVar(null);
+ template.tabular.options = new ReactiveVar({}, objectsAreEqual);
+ template.tabular.docPub = new ReactiveVar(null);
+ template.tabular.collection = new ReactiveVar(null);
+ template.tabular.connection = null;
+ template.tabular.ready = new ReactiveVar(false);
+ template.tabular.recordsTotal = 0;
+ template.tabular.recordsFiltered = 0;
+ template.tabular.isLoading = new ReactiveVar(true);
+ template.tabular.blazeViews = [];
+ template.tabular.searchTerm = new ReactiveVar(this.data.searchTerm || null);
+
+ // These are some DataTables options that we need for everything to work.
+ // We add them to the options specified by the user.
+ const ajaxOptions = {
+ // tell DataTables that we're getting the table data from a server
+ serverSide: true,
+ processing: true,
+ // define the function that DataTables will call upon first load and whenever
+ // we tell it to reload data, such as when paging, etc.
+ ajax: function (data, callback /*, settings*/) {
+ // When DataTables requests data, first we set
+ // the new skip, limit, order, and pubSelector values
+ // that DataTables has requested. These trigger
+ // the first subscription, which will then trigger the
+ // second subscription.
+
+ //console.log( 'data', data, 'template.tabular.data', template.tabular.data );
+
+ // Update skip
+ template.tabular.skip.set(data.start);
+ Session.set('Tabular.LastSkip', data.start);
+
+ // Update limit
+ let options = template.tabular.options.get();
+ let hardLimit = options && options.limit;
+ if (data.length === -1) {
+ if (hardLimit === undefined) {
+ console.warn(
+ 'When using no paging or an "All" option with tabular, it is best to also add a hard limit in your table options like {limit: 500}'
+ );
+ template.tabular.limit.set(null);
+ }
+ else {
+ template.tabular.limit.set(hardLimit);
+ }
+ }
+ else {
+ template.tabular.limit.set(data.length);
}
- } else {
- template.tabular.limit.set(data.length);
- }
- // Update sort
- template.tabular.sort.set(getMongoSort(data.order, options.columns));
-
- // Update pubSelector
- let pubSelector = template.tabular.selector;
- //if we're using the searchCustom functionality don't do the default client side regex via getPubSelector
- if (!template.tabular.tableDef.searchCustom) {
- pubSelector = getPubSelector(
- template.tabular.selector,
- (data.search && data.search.value) || null,
- template.tabular.searchFields,
- template.tabular.searchCaseInsensitive,
- template.tabular.splitSearchByWhitespace,
- data.columns || null,
- options.columns
- );
- }
- template.tabular.pubSelector.set(pubSelector);
+ // Update sort
+ template.tabular.sort.set(getMongoSort(data.order, options.columns));
+
+ // Update pubSelector
+ let pubSelector = template.tabular.selector;
+ //if we're using the searchCustom functionality don't do the default client side regex via getPubSelector
+ if (!template.tabular.tableDef.searchCustom) {
+ pubSelector = getPubSelector(
+ template.tabular.selector,
+ (data.search && data.search.value) || null,
+ template.tabular.searchFields,
+ template.tabular.searchCaseInsensitive,
+ template.tabular.splitSearchByWhitespace,
+ data.columns || null,
+ options.columns
+ );
+ }
+ template.tabular.pubSelector.set(pubSelector);
- // We're ready to subscribe to the data.
- // Matters on the first run only.
- template.tabular.ready.set(true);
+ // We're ready to subscribe to the data.
+ // Matters on the first run only.
+ template.tabular.ready.set(true);
- //console.log('ajax');
- //console.debug( 'calling ajax callback with', template.tabular.data );
+ //console.log('ajax');
+ //console.debug( 'calling ajax callback with', template.tabular.data );
- callback({
- draw: data.draw,
- recordsTotal: template.tabular.recordsTotal,
- recordsFiltered: template.tabular.recordsFiltered,
- data: template.tabular.data
- });
- },
- initComplete: function () {
- // Fix THOMAS modified 24.11.2021
- // Fix the case of multiple table on the same page
- const tableId = template.data.id;
- const options = template.tabular.options.get();
- if (options.search && options.search.onEnterOnly) {
- const replaceSearchLabel = function (newText) {
- $('#' + tableId + '_filter label')
- .contents()
- .filter(function () {
- return this.nodeType === 3 && this.textContent.trim().length;
- })
- .replaceWith(newText);
- };
- $('#' + tableId + '_filter input')
- .unbind()
- .bind('keyup change', function (event) {
- if (!table) return;
- if (event.keyCode === 13 || this.value === '') {
- replaceSearchLabel(table.i18n('search'));
- table.search(this.value).draw();
- } else {
- replaceSearchLabel(table.i18n('Press enter to filter'));
+ callback({
+ draw: data.draw,
+ recordsTotal: template.tabular.recordsTotal,
+ recordsFiltered: template.tabular.recordsFiltered,
+ data: template.tabular.data
+ });
+ },
+ initComplete: function () {
+ // Fix THOMAS modified 24.11.2021
+ // Fix the case of multiple table on the same page
+ const tableId = template.data.id;
+ const options = template.tabular.options.get();
+ if (options.search && options.search.onEnterOnly) {
+ const replaceSearchLabel = function (newText) {
+ $('#' + tableId + '_filter label')
+ .contents()
+ .filter(function () {
+ return this.nodeType === 3 && this.textContent.trim().length;
+ })
+ .replaceWith(newText);
+ };
+ $('#' + tableId + '_filter input')
+ .unbind()
+ .bind('keyup change', function (event) {
+ if (!table) return;
+ if (event.keyCode === 13 || this.value === '') {
+ replaceSearchLabel(table.i18n('search'));
+ table.search(this.value).draw();
+ }
+ else {
+ replaceSearchLabel(table.i18n('Press enter to filter'));
+ }
+ });
+ }
+ },
+ headerCallback (headerRow) {
+ const options = template.tabular.options.get();
+ const columns = options.columns;
+
+ $(headerRow)
+ .find('td,th')
+ .each((index, headerCell) => {
+ const titleFunction = columns[index] && columns[index].titleFn;
+ if (typeof titleFunction === 'function') {
+ headerCell.innerHTML = '';
+ if (headerCell.__blazeViewInstance) {
+ Blaze.remove(headerCell.__blazeViewInstance);
+ }
+ const view = new Blaze.View(titleFunction);
+ headerCell.__blazeViewInstance = Blaze.render(view, headerCell);
}
});
}
- },
- headerCallback(headerRow) {
- const options = template.tabular.options.get();
- const columns = options.columns;
-
- $(headerRow)
- .find('td,th')
- .each((index, headerCell) => {
- const titleFunction = columns[index] && columns[index].titleFn;
- if (typeof titleFunction === 'function') {
- headerCell.innerHTML = '';
- if (headerCell.__blazeViewInstance) {
- Blaze.remove(headerCell.__blazeViewInstance);
- }
- const view = new Blaze.View(titleFunction);
- headerCell.__blazeViewInstance = Blaze.render(view, headerCell);
- }
- });
- }
- };
+ };
- // For testing
- //setUpTestingAutoRunLogging(template);
+ // For testing
+ //setUpTestingAutoRunLogging(template);
- // Reactively determine table columns, fields, and searchFields.
- // This will rerun whenever the current template data changes.
- let lastTableName;
- template.autorun(function () {
- let data = Template.currentData();
+ // Reactively determine table columns, fields, and searchFields.
+ // This will rerun whenever the current template data changes.
+ let lastTableName;
+ template.autorun(function () {
+ let data = Template.currentData();
- //console.log('currentData autorun', data);
+ // if we don't have data OR the selector didn't actually change return out
+ if (!data || (data.selector && template.tabular.selector === data.selector)) {
+ return;
+ }
- // if we don't have data OR the selector didn't actually change return out
- if (!data || (data.selector && template.tabular.selector === data.selector)) {
- return;
- }
+ // We get the current TabularTable instance, and cache it on the
+ // template instance for access elsewhere
+ let tabularTable = (template.tabular.tableDef = data.table);
- // We get the current TabularTable instance, and cache it on the
- // template instance for access elsewhere
- let tabularTable = (template.tabular.tableDef = data.table);
+ if (!(tabularTable instanceof Tabular.Table)) {
+ throw new Error('You must pass Tabular.Table instance as the table attribute');
+ }
- if (!(tabularTable instanceof Tabular.Table)) {
- throw new Error('You must pass Tabular.Table instance as the table attribute');
- }
+ // Always update the selector reactively
+ template.tabular.selector = data.selector;
+ template.tabular.searchTerm.set(data.searchTerm || null);
+
+ // The remaining stuff relates to changing the `table`
+ // attribute. If we didn't change it, we can stop here,
+ // but we need to reload the table if this is not the first
+ // run
+ if (tabularTable.name === lastTableName) {
+ if (table) {
+ // passing `false` as the second arg tells it to
+ // reset the paging
+ table.ajax.reload(null, true);
+ }
+ return;
+ }
+
+ // If we reactively changed the `table` attribute, run
+ // onUnload for the previous table
+ if (lastTableName !== undefined) {
+ let lastTableDef = Tabular.tablesByName[lastTableName];
+ if (lastTableDef && typeof lastTableDef.onUnload === 'function') {
+ lastTableDef.onUnload();
+ }
+ }
- // Always update the selector reactively
- template.tabular.selector = data.selector;
- template.tabular.searchTerm.set(data.searchTerm || null);
+ // Cache this table name as the last table name for next run
+ lastTableName = tabularTable.name;
- // The remaining stuff relates to changing the `table`
- // attribute. If we didn't change it, we can stop here,
- // but we need to reload the table if this is not the first
- // run
- if (tabularTable.name === lastTableName) {
+ // Figure out and update the columns, fields, and searchFields
+ const columns = tableInit(tabularTable, template);
+
+ // Set/update everything else
+ template.tabular.searchCaseInsensitive = true;
+ template.tabular.splitSearchByWhitespace = true;
+
+ if (tabularTable.options && tabularTable.options.search) {
+ if (tabularTable.options.search.caseInsensitive === false) {
+ template.tabular.searchCaseInsensitive = false;
+ }
+ if (tabularTable.options.search.smart === false) {
+ template.tabular.splitSearchByWhitespace = false;
+ }
+ }
+ template.tabular.options.set({
+ ...tabularTable.options,
+ columns
+ });
+ template.tabular.tableName.set(tabularTable.name);
+ template.tabular.docPub.set(tabularTable.pub);
+ template.tabular.collection.set(tabularTable.collection);
+ if (tabularTable.collection && tabularTable.collection._connection) {
+ template.tabular.connection = tabularTable.collection._connection;
+ }
+
+ // userOptions rerun should do this?
if (table) {
- // passing `false` as the second arg tells it to
+ // passing `true` as the second arg tells it to
// reset the paging
table.ajax.reload(null, true);
}
- return;
- }
+ });
+
+ template.autorun(() => {
+ // these 5 are the parameters passed to "tabular_getInfo" subscription
+ // so when they *change*, set the isLoading flag to true
+ template.tabular.tableName.get();
+ template.tabular.pubSelector.get();
+ template.tabular.sort.get();
+ template.tabular.skip.get();
+ template.tabular.limit.get();
+ template.tabular.isLoading.set(true);
+ template.tabular.searchTerm.get();
+ });
- // If we reactively changed the `table` attribute, run
- // onUnload for the previous table
- if (lastTableName !== undefined) {
- let lastTableDef = Tabular.tablesByName[lastTableName];
- if (lastTableDef && typeof lastTableDef.onUnload === 'function') {
- lastTableDef.onUnload();
+ // First Subscription
+ // Subscribe to an array of _ids that should be on the
+ // current page of the table, plus some aggregate
+ // numbers that DataTables needs in order to show the paging.
+ // The server will reactively keep this info accurate.
+ // It's not necessary to call stop
+ // on subscriptions that are within autorun computations.
+ template.autorun(function () {
+ if (!template.tabular.ready.get()) {
+ return;
}
- }
- // Cache this table name as the last table name for next run
- lastTableName = tabularTable.name;
+ //console.log('tabular_getInfo autorun');
- // Figure out and update the columns, fields, and searchFields
- const columns = tableInit(tabularTable, template);
+ function onReady () {
+ template.tabular.isLoading.set(false);
+ }
- // Set/update everything else
- template.tabular.searchCaseInsensitive = true;
- template.tabular.splitSearchByWhitespace = true;
+ let connection = template.tabular.connection;
+ let context = connection || Meteor;
+ context.subscribe(
+ 'tabular_getInfo',
+ template.tabular.tableName.get(),
+ template.tabular.pubSelector.get(),
+ template.tabular.sort.get(),
+ template.tabular.skip.get(),
+ template.tabular.limit.get(),
+ template.tabular.searchTerm.get(),
+ onReady
+ );
+ });
- if (tabularTable.options && tabularTable.options.search) {
- if (tabularTable.options.search.caseInsensitive === false) {
- template.tabular.searchCaseInsensitive = false;
+ // Second Subscription
+ // Reactively subscribe to the documents with _ids given to us. Limit the
+ // fields to only those we need to display. It's not necessary to call stop
+ // on subscriptions that are within autorun computations.
+ template.autorun(function () {
+ // tableInfo is reactive and causes a rerun whenever the
+ // list of docs that should currently be in the table changes.
+ // It does not cause reruns based on the documents themselves
+ // changing.
+ let tableName = template.tabular.tableName.get();
+ let collection = template.tabular.collection.get();
+ let tableInfo = Tabular.getRecord(tableName, collection) || {};
+
+ //console.log('tableName and tableInfo autorun', tableName, tableInfo);
+
+ template.tabular.recordsTotal = tableInfo.recordsTotal || 0;
+ template.tabular.recordsFiltered = tableInfo.recordsFiltered || 0;
+
+ // In some cases, there is no point in subscribing to nothing
+ if (
+ _.isEmpty(tableInfo) ||
+ template.tabular.recordsTotal === 0 ||
+ template.tabular.recordsFiltered === 0
+ ) {
+ return;
}
- if (tabularTable.options.search.smart === false) {
- template.tabular.splitSearchByWhitespace = false;
+
+ // Extend with extraFields from table definition
+ let fields = template.tabular.fields;
+ if (fields) {
+ // Extend with extraFields from table definition
+ if (typeof template.tabular.tableDef.extraFields === 'object') {
+ fields = _.extend(_.clone(fields), template.tabular.tableDef.extraFields);
+ }
}
- }
- template.tabular.options.set({
- ...tabularTable.options,
- columns
+
+ template.tabular.tableDef.sub.subscribe(
+ template.tabular.docPub.get(),
+ tableName,
+ tableInfo.ids || [],
+ fields
+ );
});
- template.tabular.tableName.set(tabularTable.name);
- template.tabular.docPub.set(tabularTable.pub);
- template.tabular.collection.set(tabularTable.collection);
- if (tabularTable.collection && tabularTable.collection._connection) {
- template.tabular.connection = tabularTable.collection._connection;
- }
- // userOptions rerun should do this?
- if (table) {
- // passing `true` as the second arg tells it to
- // reset the paging
- table.ajax.reload(null, true);
- }
- });
+ // Build the table. We rerun this only when the table
+ // options specified by the user changes, which should be
+ // only when the `table` attribute changes reactively.
+ template.autorun((c) => {
+ const userOptions = template.tabular.options.get();
+ const options = _.extend({}, ajaxOptions, userOptions);
+
+ //console.log('userOptions autorun', userOptions);
+
+ // unless the user provides her own displayStart,
+ // we use a value from Session. This keeps the
+ // same page selected after a hot code push.
+ if (c.firstRun && !('displayStart' in options)) {
+ options.displayStart = Tracker.nonreactive(function () {
+ return Session.get('Tabular.LastSkip');
+ });
+ }
- template.autorun(() => {
- // these 5 are the parameters passed to "tabular_getInfo" subscription
- // so when they *change*, set the isLoading flag to true
- template.tabular.tableName.get();
- template.tabular.pubSelector.get();
- template.tabular.sort.get();
- template.tabular.skip.get();
- template.tabular.limit.get();
- template.tabular.isLoading.set(true);
- template.tabular.searchTerm.get();
- });
+ if (!('order' in options)) {
+ options.order = [];
+ }
- // First Subscription
- // Subscribe to an array of _ids that should be on the
- // current page of the table, plus some aggregate
- // numbers that DataTables needs in order to show the paging.
- // The server will reactively keep this info accurate.
- // It's not necessary to call stop
- // on subscriptions that are within autorun computations.
- template.autorun(function () {
- if (!template.tabular.ready.get()) {
- return;
- }
+ // After the first time, we need to destroy before rebuilding.
+ if (table) {
- //console.log('tabular_getInfo autorun');
+ let dt = createDatatable(template);
+ if (dt) {
+ dt.destroy();
+ }
+ template.$tableElement.empty();
+ }
- function onReady() {
- template.tabular.isLoading.set(false);
- }
+ // We start with an empty table.
+ // Data will be populated by ajax function now.
+ table = createDatatable(template, options);
- let connection = template.tabular.connection;
- let context = connection || Meteor;
- context.subscribe(
- 'tabular_getInfo',
- template.tabular.tableName.get(),
- template.tabular.pubSelector.get(),
- template.tabular.sort.get(),
- template.tabular.skip.get(),
- template.tabular.limit.get(),
- template.tabular.searchTerm.get(),
- onReady
- );
- });
+ if (options.buttonContainer) {
+ const container = $(options.buttonContainer, table.table().container());
+ table.buttons().container().appendTo(container);
+ }
+ });
- // Second Subscription
- // Reactively subscribe to the documents with _ids given to us. Limit the
- // fields to only those we need to display. It's not necessary to call stop
- // on subscriptions that are within autorun computations.
- template.autorun(function () {
- // tableInfo is reactive and causes a rerun whenever the
- // list of docs that should currently be in the table changes.
- // It does not cause reruns based on the documents themselves
- // changing.
- let tableName = template.tabular.tableName.get();
- let collection = template.tabular.collection.get();
- let tableInfo = Tabular.getRecord(tableName, collection) || {};
-
- //console.log('tableName and tableInfo autorun', tableName, tableInfo);
-
- template.tabular.recordsTotal = tableInfo.recordsTotal || 0;
- template.tabular.recordsFiltered = tableInfo.recordsFiltered || 0;
-
- // In some cases, there is no point in subscribing to nothing
- if (
- _.isEmpty(tableInfo) ||
- template.tabular.recordsTotal === 0 ||
- template.tabular.recordsFiltered === 0
- ) {
- return;
- }
+ template.autorun(() => {
+ // Get table name non-reactively
+ let tableName = Tracker.nonreactive(function () {
+ return template.tabular.tableName.get();
+ });
+ // Get the collection that we're showing in the table non-reactively
+ let collection = Tracker.nonreactive(function () {
+ return template.tabular.collection.get();
+ });
- // Extend with extraFields from table definition
- let fields = template.tabular.fields;
- if (fields) {
- // Extend with extraFields from table definition
- if (typeof template.tabular.tableDef.extraFields === 'object') {
- fields = _.extend(_.clone(fields), template.tabular.tableDef.extraFields);
+ // React when the requested list of records changes.
+ // This can happen for various reasons.
+ // * DataTables reran ajax due to sort changing.
+ // * DataTables reran ajax due to page changing.
+ // * DataTables reran ajax due to results-per-page changing.
+ // * DataTables reran ajax due to search terms changing.
+ // * `selector` attribute changed reactively
+ // * Docs were added/changed/removed by this user or
+ // another user, causing visible result set to change.
+ let tableInfo = Tabular.getRecord(tableName, collection);
+ if (!collection || !tableInfo) {
+ return;
}
- }
- template.tabular.tableDef.sub.subscribe(
- template.tabular.docPub.get(),
- tableName,
- tableInfo.ids || [],
- fields
- );
- });
+ // Build options object to pass to `find`.
+ // It's important that we use the same options
+ // that were used in generating the list of `_id`s
+ // on the server.
+ let findOptions = {};
+ let fields = template.tabular.fields;
+ if (fields) {
+ // Extend with extraFields from table definition
+ if (typeof template.tabular.tableDef.extraFields === 'object') {
+ _.extend(fields, template.tabular.tableDef.extraFields);
+ }
+ findOptions.fields = fields;
+ }
- // Build the table. We rerun this only when the table
- // options specified by the user changes, which should be
- // only when the `table` attribute changes reactively.
- template.autorun((c) => {
- const userOptions = template.tabular.options.get();
- const options = _.extend({}, ajaxOptions, userOptions);
-
- //console.log('userOptions autorun', userOptions);
-
- // unless the user provides her own displayStart,
- // we use a value from Session. This keeps the
- // same page selected after a hot code push.
- if (c.firstRun && !('displayStart' in options)) {
- options.displayStart = Tracker.nonreactive(function () {
- return Session.get('Tabular.LastSkip');
+ // Sort does not need to be reactive here; using
+ // reactive sort would result in extra rerunning.
+ let sort = Tracker.nonreactive(function () {
+ return template.tabular.sort.get();
});
- }
-
- if (!('order' in options)) {
- options.order = [];
- }
-
- // After the first time, we need to destroy before rebuilding.
- if (table) {
- let dt = template.$tableElement.DataTable();
- if (dt) {
- dt.destroy();
+ if (sort) {
+ findOptions.sort = sort;
}
- template.$tableElement.empty();
- }
- // We start with an empty table.
- // Data will be populated by ajax function now.
- table = template.$tableElement.DataTable(options);
+ // Get the updated list of docs we should be showing
+ let cursor = collection.find({ _id: { $in: tableInfo.ids } }, findOptions);
+
+ //console.log('tableInfo, fields, sort, find autorun', cursor.count());
+ //console.log( 'autorun: cursor.count', cursor.count(), 'tableInfo.ids.length', tableInfo.ids.length );
+
+ // We're subscribing to the docs just in time, so there's
+ // a good chance that they aren't all sent to the client yet.
+ // We'll stop here if we didn't find all the docs we asked for.
+ // This will rerun one or more times as the docs are received
+ // from the server, and eventually we'll have them all.
+ // Without this check in here, there's a lot of flashing in the
+ // table as rows are added.
+ if (cursor.count() < tableInfo.ids.length) {
+ return;
+ }
+ // Get data as array for DataTables to consume in the ajax function
+ template.tabular.data = cursor.fetch();
+
+ if (template.tabular.blazeViews) {
+ //console.log(`Removing ${template.blazeViews.length}`);
+ template.tabular.blazeViews.forEach(view => {
+ try {
+ Blaze.remove(view);
+ } catch (err) {
+ console.error(err);
+ }
+ });
+ template.tabular.blazeViews = [];
+ }
- if (options.buttonContainer) {
- const container = $(options.buttonContainer, table.table().container());
- table.buttons().container().appendTo(container);
- }
- });
+ // For these types of reactive changes, we don't want to
+ // reset the page we're on, so we pass `false` as second arg.
+ // The exception is if we changed the results-per-page number,
+ // in which cases `resetTablePaging` will be `true` and we will do so.
+ if (table) {
+ if (resetTablePaging) {
+ table.ajax.reload(null, true);
+ resetTablePaging = false;
+ }
+ else {
+ table.ajax.reload(null, false);
+ }
+ }
- template.autorun(() => {
- // Get table name non-reactively
- let tableName = Tracker.nonreactive(function () {
- return template.tabular.tableName.get();
- });
- // Get the collection that we're showing in the table non-reactively
- let collection = Tracker.nonreactive(function () {
- return template.tabular.collection.get();
+ template.tabular.isLoading.set(false);
});
- // React when the requested list of records changes.
- // This can happen for various reasons.
- // * DataTables reran ajax due to sort changing.
- // * DataTables reran ajax due to page changing.
- // * DataTables reran ajax due to results-per-page changing.
- // * DataTables reran ajax due to search terms changing.
- // * `selector` attribute changed reactively
- // * Docs were added/changed/removed by this user or
- // another user, causing visible result set to change.
- let tableInfo = Tabular.getRecord(tableName, collection);
- if (!collection || !tableInfo) {
- return;
- }
-
- // Build options object to pass to `find`.
- // It's important that we use the same options
- // that were used in generating the list of `_id`s
- // on the server.
- let findOptions = {};
- let fields = template.tabular.fields;
- if (fields) {
- // Extend with extraFields from table definition
- if (typeof template.tabular.tableDef.extraFields === 'object') {
- _.extend(fields, template.tabular.tableDef.extraFields);
+ template.autorun(() => {
+ const isLoading = template.tabular.isLoading.get();
+ if (isLoading) {
+ template.$('.dataTables_processing').show();
}
- findOptions.fields = fields;
- }
+ else {
+ template.$('.dataTables_processing').hide();
+ }
+ });
- // Sort does not need to be reactive here; using
- // reactive sort would result in extra rerunning.
- let sort = Tracker.nonreactive(function () {
- return template.tabular.sort.get();
+ // force table paging to reset to first page when we change page length
+ template.$tableElement.on('length.dt', function () {
+ resetTablePaging = true;
});
- if (sort) {
- findOptions.sort = sort;
- }
+ });
- // Get the updated list of docs we should be showing
- let cursor = collection.find({ _id: { $in: tableInfo.ids } }, findOptions);
-
- //console.log('tableInfo, fields, sort, find autorun', cursor.count());
- //console.log( 'autorun: cursor.count', cursor.count(), 'tableInfo.ids.length', tableInfo.ids.length );
-
- // We're subscribing to the docs just in time, so there's
- // a good chance that they aren't all sent to the client yet.
- // We'll stop here if we didn't find all the docs we asked for.
- // This will rerun one or more times as the docs are received
- // from the server, and eventually we'll have them all.
- // Without this check in here, there's a lot of flashing in the
- // table as rows are added.
- if (cursor.count() < tableInfo.ids.length) {
- return;
+ Template.tabular.onDestroyed(function () {
+ // Clear last skip tracking
+ Session.set('Tabular.LastSkip', 0);
+ // Run a user-provided onUnload function
+ if (
+ this.tabular &&
+ this.tabular.tableDef &&
+ typeof this.tabular.tableDef.onUnload === 'function'
+ ) {
+ this.tabular.tableDef.onUnload();
}
- // Get data as array for DataTables to consume in the ajax function
- template.tabular.data = cursor.fetch();
- if (template.tabular.blazeViews) {
- //console.log(`Removing ${template.blazeViews.length}`);
- template.tabular.blazeViews.forEach(view => {
+ if (this.tabular?.blazeViews) {
+ //console.log(`Removing ${this.blazeViews.length}`);
+ this.tabular.blazeViews.forEach(view => {
try {
Blaze.remove(view);
- }
- catch(err) {
+ } catch (err) {
console.error(err);
}
});
- template.tabular.blazeViews = [];
+ this.tabular.blazeViews = [];
}
- // For these types of reactive changes, we don't want to
- // reset the page we're on, so we pass `false` as second arg.
- // The exception is if we changed the results-per-page number,
- // in which cases `resetTablePaging` will be `true` and we will do so.
- if (table) {
- if (resetTablePaging) {
- table.ajax.reload(null, true);
- resetTablePaging = false;
- } else {
- table.ajax.reload(null, false);
+ // Destroy the DataTable instance to avoid memory leak
+ if (this.$tableElement && this.$tableElement.length) {
+ const dt = createDatatable(this);
+ if (dt) {
+ dt.destroy();
}
- }
-
- template.tabular.isLoading.set(false);
- });
-
- template.autorun(() => {
- const isLoading = template.tabular.isLoading.get();
- if (isLoading) {
- template.$('.dataTables_processing').show();
- } else {
- template.$('.dataTables_processing').hide();
+ this.$tableElement.empty();
}
});
- // force table paging to reset to first page when we change page length
- template.$tableElement.on('length.dt', function () {
- resetTablePaging = true;
- });
-});
-
-Template.tabular.onDestroyed(function () {
- // Clear last skip tracking
- Session.set('Tabular.LastSkip', 0);
- // Run a user-provided onUnload function
- if (
- this.tabular &&
- this.tabular.tableDef &&
- typeof this.tabular.tableDef.onUnload === 'function'
- ) {
- this.tabular.tableDef.onUnload();
- }
-
- if (this.tabular?.blazeViews) {
- //console.log(`Removing ${this.blazeViews.length}`);
- this.tabular.blazeViews.forEach(view => {
- try {
- Blaze.remove(view);
- }
- catch(err) {
- console.error(err);
- }
- });
- this.tabular.blazeViews = [];
- }
-
- // Destroy the DataTable instance to avoid memory leak
- if (this.$tableElement && this.$tableElement.length) {
- const dt = this.$tableElement.DataTable();
- if (dt) {
- dt.destroy();
- }
- this.$tableElement.empty();
- }
-});
-
//function setUpTestingAutoRunLogging(template) {
// template.autorun(function () {
// var val = template.tabular.tableName.get();
@@ -579,5 +593,5 @@ Template.tabular.onDestroyed(function () {
// console.log('limit changed', val);
// });
//}
-
+}
export default Tabular;
diff --git a/common/Tabular.js b/common/Tabular.js
index 5eb0fca..315724e 100644
--- a/common/Tabular.js
+++ b/common/Tabular.js
@@ -79,4 +79,9 @@ Tabular.Table = class {
}
};
+/**
+ * Does nothing, used to keep Isomorphic with client.
+ */
+Tabular.init = () => {}
+
export default Tabular;
diff --git a/package.js b/package.js
index 1a74f41..3b98416 100755
--- a/package.js
+++ b/package.js
@@ -3,22 +3,19 @@
Package.describe({
name: 'aldeed:tabular',
summary: 'Datatables for large or small datasets in Meteor',
- version: '3.0.0-rc.0',
+ version: '3.0.0-rc.4',
git: 'https://github.com/Meteor-Community-Packages/meteor-tabular.git'
});
-Npm.depends({
- 'datatables.net': '2.0.8'
-});
Package.onUse(function(api) {
- api.versionsFrom([ '1.3', '2.8.0', '3.0-rc.4']);
+ api.versionsFrom([ '1.3', '2.8.0', '3.0']);
api.use([
'check',
'ecmascript',
'underscore',
'mongo',
- 'blaze@2.9.0 || 3.0.0-rc300.2',
+ 'blaze@2.9.0 || 3.0.0',
'templating',
'reactive-var',
'tracker',
@@ -28,7 +25,7 @@ Package.onUse(function(api) {
// jquery is a weak reference in case you want to use a different package or
// pull it in another way, but regardless you need to make sure it is loaded
// before any tabular tables are rendered
- api.use(['jquery@1.1.6 || 3.0.0 || 3.0.1-alpha300.10'], 'client', {weak: true});
+ api.use(['jquery@1.1.6 || 3.0.0'], 'client', {weak: true});
api.use(['meteorhacks:subs-manager@1.2.0'], ['client', 'server'], {weak: true});
@@ -48,7 +45,7 @@ Package.onUse(function(api) {
});
Package.onTest(function(api) {
- api.versionsFrom([ '1.3', '2.8.0', '3.0-rc.4']);
+ api.versionsFrom([ '1.3', '2.8.0', '3.0']);
api.use(['aldeed:tabular', 'tinytest']);
api.use([
'anti:fake',
diff --git a/server/main.js b/server/main.js
index 8aa6d89..cb242c3 100755
--- a/server/main.js
+++ b/server/main.js
@@ -72,7 +72,7 @@ Meteor.publish('tabular_getInfo', async function (tableName, selector, sort, ski
// from this function, with sensitive data, there is
// a chance someone could do a query and learn something
// just based on whether a result is found or not.
- if (typeof table.allow === 'function' && !table.allow(this.userId)) {
+ if (typeof table.allow === 'function' && !(await table.allow(this.userId))) {
this.ready();
return;
}
@@ -81,7 +81,7 @@ Meteor.publish('tabular_getInfo', async function (tableName, selector, sort, ski
// Allow the user to modify the selector before we use it
if (typeof table.changeSelector === 'function') {
- newSelector = table.changeSelector(newSelector, this.userId);
+ newSelector = await table.changeSelector(newSelector, this.userId);
}
// Apply the server side selector specified in the tabular
@@ -89,7 +89,7 @@ Meteor.publish('tabular_getInfo', async function (tableName, selector, sort, ski
// them using $and, allowing both selectors to have
// the same keys.
if (typeof table.selector === 'function') {
- const tableSelector = table.selector(this.userId);
+ const tableSelector = await table.selector(this.userId);
if (_.isEmpty(newSelector)) {
newSelector = tableSelector;
} else {
@@ -124,7 +124,7 @@ Meteor.publish('tabular_getInfo', async function (tableName, selector, sort, ski
const paths = getSearchPaths(table);
const newSort = transformSortArray(findOptions.sort);
- filteredRecordIds = table.searchCustom(
+ filteredRecordIds = await table.searchCustom(
this.userId,
newSelector,
tokens,
@@ -197,7 +197,7 @@ Meteor.publish('tabular_getInfo', async function (tableName, selector, sort, ski
// Handle docs being added or removed from the result set.
let initializing = true;
- const handle = filteredCursor?.observeChanges({
+ const handle = filteredCursor?.observeChangesAsync({
added: function (id) {
if (initializing) {
return;