nutella_framework 0.4.5 → 0.4.8

Sign up to get free protection for your applications and to get access to all the features.
Files changed (74) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +14 -15
  3. data/VERSION +1 -1
  4. data/framework_components/beacon-cloud-bot/README.md +27 -0
  5. data/framework_components/beacon-cloud-bot/beacon_cloud_bot.rb +154 -0
  6. data/framework_components/beacon-cloud-bot/nutella.json +6 -0
  7. data/framework_components/beacon-cloud-bot/startup +4 -0
  8. data/framework_components/beacon-cloud-interface/LICENSE +21 -0
  9. data/framework_components/beacon-cloud-interface/Readme.md +0 -0
  10. data/framework_components/beacon-cloud-interface/bower.json +29 -0
  11. data/framework_components/beacon-cloud-interface/bower_components/bower-mqttws/.bower.json +23 -0
  12. data/framework_components/beacon-cloud-interface/bower_components/bower-mqttws/bower.json +14 -0
  13. data/framework_components/beacon-cloud-interface/bower_components/bower-mqttws/mqttws31.js +2081 -0
  14. data/framework_components/beacon-cloud-interface/bower_components/bower-mqttws/readme.md +4 -0
  15. data/framework_components/beacon-cloud-interface/bower_components/nutella_lib/.bower.json +37 -0
  16. data/framework_components/beacon-cloud-interface/bower_components/nutella_lib/LICENSE +21 -0
  17. data/framework_components/beacon-cloud-interface/bower_components/nutella_lib/README.md +15 -0
  18. data/framework_components/beacon-cloud-interface/bower_components/nutella_lib/bower.json +28 -0
  19. data/framework_components/beacon-cloud-interface/bower_components/nutella_lib/examples/browser/mqtt_client_hello_world.html +23 -0
  20. data/framework_components/beacon-cloud-interface/bower_components/nutella_lib/examples/browser/nutella_hello_world.html +52 -0
  21. data/framework_components/beacon-cloud-interface/bower_components/nutella_lib/examples/node/mqtt_client_hello_world.js +14 -0
  22. data/framework_components/beacon-cloud-interface/bower_components/nutella_lib/examples/node/nutella_hello_world.js +38 -0
  23. data/framework_components/beacon-cloud-interface/bower_components/nutella_lib/nutella_lib.js +789 -0
  24. data/framework_components/beacon-cloud-interface/bower_components/nutella_lib/package.json +30 -0
  25. data/framework_components/beacon-cloud-interface/bower_components/nutella_lib/simple-js-mqtt-client.js +428 -0
  26. data/framework_components/beacon-cloud-interface/css/animation.css +17 -0
  27. data/framework_components/beacon-cloud-interface/css/cursor.css +16 -0
  28. data/framework_components/beacon-cloud-interface/css/page_layout.css +73 -0
  29. data/framework_components/beacon-cloud-interface/index.html +157 -0
  30. data/framework_components/beacon-cloud-interface/js/lib/nutella_lib.js +4039 -0
  31. data/framework_components/beacon-cloud-interface/js/react/beacon-add.js +102 -0
  32. data/framework_components/beacon-cloud-interface/js/react/beacon-table.js +73 -0
  33. data/framework_components/beacon-cloud-interface/js/react/beacon.js +97 -0
  34. data/framework_components/beacon-cloud-interface/nutella.json +6 -0
  35. data/framework_components/example_framework_web_interface/index.html +11 -2
  36. data/framework_components/example_framework_web_interface/node_modules/nutella_lib/.npmignore +10 -0
  37. data/framework_components/example_framework_web_interface/node_modules/nutella_lib/.travis.yml +5 -0
  38. data/framework_components/example_framework_web_interface/node_modules/nutella_lib/LICENSE +21 -0
  39. data/framework_components/example_framework_web_interface/node_modules/nutella_lib/README.md +27 -0
  40. data/framework_components/example_framework_web_interface/node_modules/nutella_lib/dist/nutella_lib.js +4039 -0
  41. data/framework_components/example_framework_web_interface/node_modules/nutella_lib/dist/nutella_lib.js.map +1 -0
  42. data/framework_components/example_framework_web_interface/node_modules/nutella_lib/examples/browser_hello_world.html +67 -0
  43. data/framework_components/example_framework_web_interface/node_modules/nutella_lib/examples/node_hello_world.js +51 -0
  44. data/framework_components/example_framework_web_interface/node_modules/nutella_lib/gulpfile.js +31 -0
  45. data/framework_components/example_framework_web_interface/node_modules/nutella_lib/package.json +41 -0
  46. data/framework_components/example_framework_web_interface/node_modules/nutella_lib/src/app_core.js +19 -0
  47. data/framework_components/example_framework_web_interface/node_modules/nutella_lib/src/app_core_browser.js +17 -0
  48. data/framework_components/example_framework_web_interface/node_modules/nutella_lib/src/app_log.js +50 -0
  49. data/framework_components/example_framework_web_interface/node_modules/nutella_lib/src/app_net.js +279 -0
  50. data/framework_components/example_framework_web_interface/node_modules/nutella_lib/src/app_persist.js +20 -0
  51. data/framework_components/example_framework_web_interface/node_modules/nutella_lib/src/fr_core_browser.js +17 -0
  52. data/framework_components/example_framework_web_interface/node_modules/nutella_lib/src/fr_log.js +50 -0
  53. data/framework_components/example_framework_web_interface/node_modules/nutella_lib/src/fr_net.js +499 -0
  54. data/framework_components/example_framework_web_interface/node_modules/nutella_lib/src/nutella_i.js +74 -0
  55. data/framework_components/example_framework_web_interface/node_modules/nutella_lib/src/nutella_i_browser.js +130 -0
  56. data/framework_components/example_framework_web_interface/node_modules/nutella_lib/src/nutella_lib.js +91 -0
  57. data/framework_components/example_framework_web_interface/node_modules/nutella_lib/src/nutella_lib_browser.js +90 -0
  58. data/framework_components/example_framework_web_interface/node_modules/nutella_lib/src/run_log.js +51 -0
  59. data/framework_components/example_framework_web_interface/node_modules/nutella_lib/src/run_net.js +84 -0
  60. data/framework_components/example_framework_web_interface/node_modules/nutella_lib/src/run_persist.js +20 -0
  61. data/framework_components/example_framework_web_interface/node_modules/nutella_lib/src/util/net.js +327 -0
  62. data/framework_components/example_framework_web_interface/node_modules/nutella_lib/test/nutella.test.js +16 -0
  63. data/framework_components/example_framework_web_interface/node_modules/nutella_lib/test/runner.html +22 -0
  64. data/framework_components/example_framework_web_interface/package.json +15 -0
  65. data/framework_components/{order.json.example → order.json} +0 -0
  66. data/framework_components/runs_list_bot/{app_runs_list_bot.rb → runs_list_bot.rb} +9 -3
  67. data/framework_components/runs_list_bot/startup +1 -1
  68. data/lib/commands/meta/run_command.rb +21 -36
  69. data/lib/commands/start.rb +9 -199
  70. data/lib/commands/util/components_list.rb +68 -0
  71. data/lib/commands/util/components_starter.rb +169 -0
  72. data/nutella_framework.gemspec +109 -47
  73. data/nutella_lib/framework_net.rb +17 -13
  74. metadata +84 -106
@@ -0,0 +1,30 @@
1
+ {
2
+ "name": "nutella_lib",
3
+ "version": "0.3.0",
4
+ "description": "Nutella library for JavaScript",
5
+ "main": "nutella_lib.js",
6
+ "scripts": {
7
+ "test": "mocha"
8
+ },
9
+ "repository": {
10
+ "type": "git",
11
+ "url": "https://github.com/nutella-framework/nutella_lib.js"
12
+ },
13
+ "devDependencies": {
14
+ "chai": "*",
15
+ "mocha": "*"
16
+ },
17
+ "keywords": [
18
+ "nutella",
19
+ "framework"
20
+ ],
21
+ "author": "Alessandro Gnoli",
22
+ "license": "MIT",
23
+ "bugs": {
24
+ "url": "https://github.com/nutella-framework/nutella_lib.js/issues"
25
+ },
26
+ "homepage": "https://github.com/nutella-framework/nutella_lib.js",
27
+ "dependencies": {
28
+ "mqtt": "~1.0.x"
29
+ }
30
+ }
@@ -0,0 +1,428 @@
1
+ /**********************
2
+ * Simple MQTT client *
3
+ **********************/
4
+
5
+ (function() {
6
+ "use strict";
7
+
8
+ // Establish the root object, `window` in the browser, or `exports` on the server.
9
+ var root = this;
10
+
11
+ // Save the previous value of the `MQTT` variable to use with noConflict().
12
+ var previous_mqtt = root.MQTT;
13
+
14
+ // Internal reference to this library (used below)
15
+ var mqtt = {};
16
+
17
+ // Detect if we are in the browser or in node and
18
+ // load the appropriate dependencies
19
+ var isNode;
20
+ var mqtt_lib;
21
+ if (typeof window === 'undefined') {
22
+ isNode = true; // Node
23
+ mqtt_lib = require('mqtt');
24
+ if( typeof mqtt_lib === 'undefined' )
25
+ throw new Error('This MQTT client requires the mqtt library (https://www.npmjs.com/package/mqtt)');
26
+ } else {
27
+ isNode = false; // Browser
28
+ mqtt_lib = root.Paho.MQTT;
29
+ if( typeof mqtt_lib === 'undefined' )
30
+ throw new Error('This MQTT client requires the mqtt-ws library (https://github.com/M2MConnections/mqtt-ws) a wrapper of Paho.js');
31
+
32
+ }
33
+
34
+
35
+
36
+ /**
37
+ * Runs simple-js-mqtt-client in noConflict mode by
38
+ * returning the MQTT variable to its previous owner.
39
+ *
40
+ * @return a reference to the MQTT object defined by this library.
41
+ */
42
+ mqtt.noConflict = function() {
43
+ root.MQTT = previous_mqtt;
44
+ return mqtt;
45
+ };
46
+
47
+
48
+
49
+ /**
50
+ * Creates a new instance of SimpleMQTTClient
51
+ * and connects it to an MQTT.
52
+ * This is a factory method.
53
+ *
54
+ * @param {string} host - the hostname of the broker.
55
+ * @param {string} [clientId] - the unique name of this client. If no ID is provided a random one is generated
56
+ */
57
+ mqtt.connect = function (host, clientId) {
58
+ return new SimpleMQTTClient(host, clientId);
59
+ };
60
+
61
+
62
+
63
+ /**
64
+ * Defines a Simple MQTT client.
65
+ *
66
+ * @param {string} host - the hostname of the broker.
67
+ * @param {string} [clientId] - the unique name of this client. If no ID is provided a random one is generated
68
+ */
69
+ var SimpleMQTTClient = function (host, clientId) {
70
+
71
+ // Initializes the object that stores subscriptions
72
+ this.subscriptions = {};
73
+ // Initializes the object that holds the internal client
74
+ this.client = {};
75
+ // Functions backlog
76
+ this.backlog = [];
77
+
78
+ // Handles the optional clientId parameter
79
+ if (arguments.length === 1 || clientId === undefined) {
80
+ clientId = generateRandomClientId();
81
+ }
82
+
83
+ // Connect
84
+ if (isNode)
85
+ this.client = connectNode(this.subscriptions, host, clientId);
86
+ else
87
+ this.client = connectBrowser(this.subscriptions, this.backlog, host, clientId);
88
+ };
89
+
90
+
91
+ //
92
+ // Helper function that connects the MQTT client in node
93
+ //
94
+ function connectNode (subscriptions, host, clientId) {
95
+ // Create client
96
+ var url = "tcp://" + host + ":1883";
97
+ var client = mqtt_lib.connect(url, {clientId : clientId});
98
+ // Register incoming message callback
99
+ client.on('message', function(channel, message) {
100
+ // Executes the appropriate channel callback
101
+ var cbs = findCallbacks(subscriptions, channel);
102
+ if (cbs!==undefined) {
103
+ if (Object.keys(subscriptions).indexOf(channel)!==-1)
104
+ cbs.forEach(function(cb) {
105
+ cb(message);
106
+ });
107
+ else
108
+ cbs.forEach(function(cb) {
109
+ cb(message, channel);
110
+ });
111
+
112
+ }
113
+ });
114
+ return client;
115
+ }
116
+
117
+
118
+ //
119
+ // Helper function that connects the MQTT client in the browser
120
+ //
121
+ function connectBrowser (subscriptions, backlog, host, clientId) {
122
+ // Create client
123
+ var client = new mqtt_lib.Client(host, Number(1884), clientId);
124
+ // Register callback for connection lost
125
+ client.onConnectionLost = function() {
126
+ // TODO try to reconnect
127
+ };
128
+ // Register callback for received message
129
+ client.onMessageArrived = function (message) {
130
+ // Executes the appropriate channel callback
131
+ var cbs = findCallbacks(subscriptions, message.destinationName);
132
+ if (cbs!==undefined) {
133
+ if (Object.keys(subscriptions).indexOf(message.destinationName)!==-1)
134
+ cbs.forEach(function(cb) {
135
+ cb(message.payloadString);
136
+ });
137
+ else
138
+ cbs.forEach(function(cb) {
139
+ cb(message.payloadString, message.destinationName);
140
+ });
141
+ }
142
+ };
143
+ // Connect
144
+ client.connect({onSuccess: function() {
145
+ // Execute the backlog of operations performed while the client wasn't connected
146
+ backlog.forEach(function(e) {
147
+ e.op.apply(this, e.params);
148
+ });
149
+ }});
150
+ return client;
151
+ }
152
+
153
+
154
+
155
+ /**
156
+ * Disconnects from the MQTT client.
157
+ */
158
+ SimpleMQTTClient.prototype.disconnect = function () {
159
+ if (isNode)
160
+ this.client.end();
161
+ else
162
+ this.client.disconnect();
163
+ this.subscriptions = {};
164
+ };
165
+
166
+
167
+
168
+ /**
169
+ * Subscribes to a channel and registers a callback.
170
+ *
171
+ * @param {string} channel - the channel we are subscribing to.
172
+ * @param {callback} callback - A function that is executed every time a message is received on that channel.
173
+ * @param {callback} [done_callback] - A function that is executed once the subscribe operation has completed successfully.
174
+ */
175
+ SimpleMQTTClient.prototype.subscribe = function (channel, callback, done_callback) {
176
+ // Subscribe
177
+ if( isNode )
178
+ subscribeNode(this.client, this.subscriptions, channel, callback, done_callback);
179
+ else
180
+ subscribeBrowser(this.client, this.subscriptions, this.backlog, channel, callback, done_callback);
181
+ };
182
+
183
+
184
+ //
185
+ // Helper function that subscribes to a channel in node
186
+ //
187
+ function subscribeNode (client, subscriptions, channel, callback, done_callback) {
188
+ if (subscriptions[channel]===undefined) {
189
+ subscriptions[channel] = [callback];
190
+ client.subscribe(channel, {qos: 0}, function() {
191
+ // If there is a done_callback defined, execute it
192
+ if (done_callback!==undefined) done_callback();
193
+ });
194
+ } else {
195
+ subscriptions[channel].push(callback);
196
+ }
197
+ }
198
+
199
+
200
+ //
201
+ // Helper function that subscribes to a channel in the browser
202
+ //
203
+ function subscribeBrowser (client, subscriptions, backlog, channel, callback, done_callback) {
204
+ if ( addToBacklog(client, backlog, subscribeBrowser, [client, subscriptions, backlog, channel, callback, done_callback]) ) return;
205
+ if (subscriptions[channel]===undefined) {
206
+ subscriptions[channel] = [callback];
207
+ client.subscribe(channel, {qos: 0, onSuccess: function() {
208
+ // If there is a done_callback defined, execute it
209
+ if (done_callback!==undefined) done_callback();
210
+ }});
211
+ } else {
212
+ subscriptions[channel].push(callback);
213
+ }
214
+ }
215
+
216
+
217
+
218
+ /**
219
+ * Unsubscribe from a channel.
220
+ *
221
+ * @param {string} channel - the channel we are unsubscribing from.
222
+ * @param {function} callback - the callback we are trying to unregister
223
+ * @param {callback} [done_callback] - A function that is executed once the unsubscribe operation has completed successfully.
224
+ */
225
+ SimpleMQTTClient.prototype.unsubscribe = function (channel, callback, done_callback) {
226
+ if( isNode )
227
+ unsubscribeNode(this.client, this.subscriptions, channel, callback, done_callback);
228
+ else
229
+ unsubscribeBrowser(this.client, this.subscriptions, this.backlog, channel, callback, done_callback);
230
+ };
231
+
232
+
233
+ //
234
+ // Helper function that unsubscribes from a channel in node
235
+ //
236
+ var unsubscribeNode = function(client, subscriptions, channel, callback, done_callback) {
237
+ if (subscriptions[channel]===undefined)
238
+ return;
239
+ subscriptions[channel].splice(subscriptions[channel].indexOf(callback), 1);
240
+ if (subscriptions[channel].length===0) {
241
+ delete subscriptions[channel];
242
+ client.unsubscribe(channel, function() {
243
+ // If there is a done_callback defined, execute it
244
+ if (done_callback!==undefined) done_callback();
245
+ });
246
+ }
247
+ };
248
+
249
+
250
+ //
251
+ // Helper function that unsubscribes from a channel in the browser
252
+ //
253
+ var unsubscribeBrowser = function(client, subscriptions, backlog, channel, callback, done_callback) {
254
+ if ( addToBacklog(client, backlog, unsubscribeBrowser, [client, subscriptions, backlog, channel, callback, done_callback]) ) return;
255
+ if (subscriptions[channel]===undefined)
256
+ return;
257
+ subscriptions[channel].splice(subscriptions[channel].indexOf(callback), 1);
258
+ if (subscriptions[channel].length===0) {
259
+ delete subscriptions[channel];
260
+ client.unsubscribe(channel, {onSuccess : function() {
261
+ // If there is a done_callback defined, execute it
262
+ if (done_callback!==undefined) done_callback();
263
+ }});
264
+ }
265
+ };
266
+
267
+
268
+ /**
269
+ * Lists all the channels we are currently subscribed to.
270
+ *
271
+ * @returns {Array} a lists of all the channels we are currently subscribed to.
272
+ */
273
+ SimpleMQTTClient.prototype.getSubscriptions = function () {
274
+ return Object.keys(this.subscriptions);
275
+ };
276
+
277
+
278
+ /**
279
+ * Publishes a message to a channel.
280
+ *
281
+ * @param {string} channel - the channel we are publishing to.
282
+ * @param {string} message - the message we are publishing.
283
+ */
284
+ SimpleMQTTClient.prototype.publish = function (channel, message) {
285
+ if (isNode)
286
+ publishNode(this.client, channel, message)
287
+ else
288
+ publishBrowser(this.client, this.backlog, channel, message)
289
+ };
290
+
291
+
292
+ //
293
+ // Helper function that publishes to a channel in node
294
+ //
295
+ var publishNode = function (client, channel, message) {
296
+ client.publish(channel, message);
297
+ };
298
+
299
+
300
+ //
301
+ // Helper function that publishes to a channel in the browser
302
+ //
303
+ var publishBrowser = function (client, backlog, channel, message) {
304
+ if ( addToBacklog(client, backlog, publishBrowser, [client, backlog, channel, message]) ) return;
305
+ message = new mqtt_lib.Message(message);
306
+ message.destinationName = channel;
307
+ client.send(message);
308
+ };
309
+
310
+
311
+ //
312
+ // Helper functions
313
+ //
314
+
315
+
316
+ //
317
+ // Helper function that generates a random client ID
318
+ //
319
+ function generateRandomClientId () {
320
+ var length = 22;
321
+ var chars = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
322
+ var result = '';
323
+ for (var i = length; i > 0; --i) {
324
+ result += chars[Math.round(Math.random() * (chars.length - 1))];
325
+ }
326
+ return result;
327
+ };
328
+
329
+
330
+ //
331
+ // Helper function that selects the right callback when a message is received
332
+ //
333
+ function findCallbacks (subscriptions, channel) {
334
+ // First try to see if a callback for the exact channel exists
335
+ if(Object.keys(subscriptions).indexOf(channel)!==-1)
336
+ return subscriptions[channel];
337
+ // If it doesn't then let's try to see if the channel matches a wildcard callback
338
+ var pattern = matchesWildcard(subscriptions, channel);
339
+ if (pattern!== undefined) {
340
+ return subscriptions[pattern];
341
+ }
342
+ // If there's no exact match or wildcard we have to return undefined
343
+ return undefined;
344
+ };
345
+
346
+
347
+ //
348
+ // Helper function that tries to match a channel with each subscription
349
+ // it returns undefined if no match is found
350
+ //
351
+ function matchesWildcard (subscriptions, channel) {
352
+ var i;
353
+ var subs = Object.keys(subscriptions);
354
+ for (i=0; i < subs.length; i++) {
355
+ if (matchesFilter(subs[i], channel)) {
356
+ return subs[i];
357
+ }
358
+ }
359
+ return undefined;
360
+ };
361
+
362
+
363
+ //
364
+ // Helper function that checks a certain channel and see if it matches a wildcard pattern
365
+ // Returns true if the channel matches a pattern (including the exact pattern)
366
+ //
367
+ function matchesFilter (pattern, channel) {
368
+ // If multi-level wildcard is the only character in pattern, then any string will match
369
+ if (pattern==="#") {
370
+ return true;
371
+ }
372
+ // Handle all other multi-level wildcards
373
+ // FROM SPEC: The number sign (‘#’ U+0023) is a wildcard character that matches any number of levels within a topic. The multi-level wildcard represents the parent and any number of child levels. The multi-level wildcard character MUST be specified either on its own or following a topic level separator. In either case it MUST be the last character specified in the Topic Filter
374
+ var p_wo_wildcard = pattern.substring(0, pattern.length-2);
375
+ var str_wo_details = channel.substring(0, pattern.length-2);
376
+ if (pattern.slice(-1)=='#' && p_wo_wildcard==str_wo_details) {
377
+ return true;
378
+ }
379
+ // TODO Handle single-level wildcards (+)
380
+ // FROM SPEC: The single-level wildcard can be used at any level in the Topic Filter, including first and last levels. Where it is used it MUST occupy an entire level of the filter [MQTT-4.7.1-3]. It can be used at more than one level in the Topic Filter and can be used in conjunction with the multilevel wildcard.
381
+ // http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718107
382
+ return false;
383
+ };
384
+
385
+
386
+ //
387
+ // Helper method that queues operations into the backlog.
388
+ // This method is used to make `connect` "synchronous" by
389
+ // queueing up operations on the client until it is connected.
390
+ //
391
+ // @param {string} method - the method that needs to be added to the backlog
392
+ // @param {Array} parameters - parameters to the method being added to the backlog
393
+ // @returns {boolean} true if the method was successfully added, false otherwise
394
+ //
395
+ function addToBacklog (client, backlog, method, parameters) {
396
+ if (!client.isConnected() ) {
397
+ backlog.push({
398
+ op : method,
399
+ params : parameters
400
+ });
401
+ return true;
402
+ }
403
+ return false;
404
+ };
405
+
406
+
407
+
408
+
409
+ //
410
+ // End of methods definition for SimpleMQTTClient
411
+ //
412
+
413
+
414
+ // Exports mqtt object
415
+ // For node.js, also with backwards-compatibility for the old `require()` API.
416
+ // If we're in the browser, add `MQTT` as a global object.
417
+ if (typeof exports !== 'undefined') {
418
+ if (typeof module !== 'undefined' && module.exports) {
419
+ exports = module.exports = mqtt;
420
+ }
421
+ exports.MQTT = mqtt;
422
+ } else {
423
+ root.MQTT = mqtt;
424
+ }
425
+
426
+
427
+
428
+ }.call(this));
@@ -0,0 +1,17 @@
1
+ .example-enter {
2
+ opacity: 0.01;
3
+ transition: opacity .2s ease-in;
4
+ }
5
+
6
+ .example-enter.example-enter-active {
7
+ opacity: 1;
8
+ }
9
+
10
+ .example-leave {
11
+ opacity: 1;
12
+ transition: opacity .2s ease-in;
13
+ }
14
+
15
+ .example-leave.example-leave-active {
16
+ opacity: 0.01;
17
+ }
@@ -0,0 +1,16 @@
1
+ .pointer {
2
+ cursor: pointer;
3
+ }
4
+
5
+ /* Makes all the text not selectable */
6
+ body {
7
+ /*
8
+ -webkit-touch-callout: none;
9
+ -webkit-user-select: none;
10
+ -khtml-user-select: none;
11
+ -moz-user-select: none;
12
+ -ms-user-select: none;
13
+ user-select: none;
14
+ cursor:default;
15
+ */
16
+ }
@@ -0,0 +1,73 @@
1
+ .vertical-center {
2
+ min-height: 80%;
3
+ min-height: 80vh;
4
+
5
+ display: flex;
6
+ align-items: center;
7
+ }
8
+
9
+ .text-center {
10
+ text-align: center;
11
+ }
12
+
13
+ table {
14
+ width: 100%;
15
+ }
16
+
17
+ thead, tbody, tr, td, th { display: block; }
18
+
19
+ tr:after {
20
+ content: ' ';
21
+ display: block;
22
+ visibility: hidden;
23
+ clear: both;
24
+ }
25
+
26
+ thead th {
27
+ /*height: 30px;*/
28
+ }
29
+
30
+ tbody {
31
+ max-height: 400px;
32
+ overflow-y: auto;
33
+ }
34
+
35
+ thead {
36
+ }
37
+
38
+
39
+ tbody td, thead th {
40
+ /*width: 25%;*/
41
+ float: left !important;
42
+ }
43
+
44
+ tbody td {
45
+ height: 40px;
46
+ }
47
+
48
+ tbody td.add {
49
+ height: 52px;
50
+ }
51
+
52
+ .right {
53
+ float: right;
54
+ }
55
+
56
+
57
+ /*
58
+ td:nth-child(1), thead th:nth-child(1) {
59
+ width: 25%;
60
+ }
61
+
62
+ td:nth-child(2), thead th:nth-child(2) {
63
+ width: 45%;
64
+ }
65
+
66
+ td:nth-child(3), thead th:nth-child(3) {
67
+ width: 15%;
68
+ }
69
+
70
+ td:nth-child(4), thead th:nth-child(4) {
71
+ width: 15%;
72
+ }
73
+ */