nutella_framework 0.4.5 → 0.4.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
+ */