superconductor 0.0.4 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (97) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +16 -0
  3. data/.rspec +3 -0
  4. data/.ruby-version +1 -0
  5. data/.scss-lint.yml +21 -0
  6. data/.travis.yml +5 -0
  7. data/.yardopts +1 -0
  8. data/Cargo.lock +679 -0
  9. data/Cargo.toml +25 -0
  10. data/Gemfile +4 -0
  11. data/Guardfile +70 -0
  12. data/LICENSE.txt +21 -0
  13. data/Makefile +4 -0
  14. data/README.md +58 -0
  15. data/Rakefile +9 -36
  16. data/assets/__pm.js +424 -0
  17. data/assets/__pm.scss +261 -0
  18. data/assets/_buttons.scss +50 -0
  19. data/assets/_checkbox.scss +59 -0
  20. data/assets/_colors.scss +15 -0
  21. data/assets/_details.scss +54 -0
  22. data/assets/_pm_commits.scss +171 -0
  23. data/assets/_pm_setup.scss +7 -0
  24. data/assets/_pm_tasks.scss +280 -0
  25. data/assets/_tokens.scss +56 -0
  26. data/bin/console +14 -0
  27. data/bin/make +2 -0
  28. data/bin/rake +17 -0
  29. data/bin/release +5 -0
  30. data/bin/setup +8 -0
  31. data/bin/start +5 -0
  32. data/config.ru +10 -0
  33. data/config/properties.yml +37 -0
  34. data/extconf.rb +2 -0
  35. data/lib/superconductor.rb +35 -1
  36. data/lib/superconductor/documentation.rb +34 -0
  37. data/lib/superconductor/middleware.rb +71 -0
  38. data/lib/superconductor/version.rb +1 -1
  39. data/src/lib.rs +101 -0
  40. data/src/server.rs +176 -0
  41. data/src/state/mod.rs +5 -0
  42. data/src/state/state.rs +233 -0
  43. data/src/state/xml.rs +380 -0
  44. data/src/task.rs +129 -0
  45. data/src/view.rs +396 -0
  46. data/superconductor.gemspec +41 -0
  47. metadata +173 -116
  48. data/MIT-LICENSE +0 -20
  49. data/README.rdoc +0 -3
  50. data/app/assets/javascripts/jquery-linedtextarea.js +0 -126
  51. data/app/assets/javascripts/superconductor.js +0 -2
  52. data/app/assets/javascripts/superconductor/panel.js.coffee +0 -42
  53. data/app/assets/stylesheets/jquery-linedtextarea.css +0 -68
  54. data/app/assets/stylesheets/scaffold.css +0 -56
  55. data/app/assets/stylesheets/superconductor.css +0 -4
  56. data/app/assets/stylesheets/superconductor/panel.css.scss +0 -142
  57. data/app/controllers/file_controller.rb +0 -24
  58. data/app/helpers/superconductor/panel_helper.rb +0 -2
  59. data/app/models/superconductor.rb +0 -5
  60. data/app/models/superconductor/exception.rb +0 -0
  61. data/app/views/superconductor/_panel.html.erb +0 -130
  62. data/app/views/superconductor/_panel.js.erb +0 -0
  63. data/config/routes.rb +0 -6
  64. data/lib/superconductor/engine.rb +0 -24
  65. data/lib/tasks/superconductor_tasks.rake +0 -4
  66. data/test/dummy/README.rdoc +0 -261
  67. data/test/dummy/Rakefile +0 -7
  68. data/test/dummy/app/assets/javascripts/application.js +0 -15
  69. data/test/dummy/app/assets/stylesheets/application.css +0 -13
  70. data/test/dummy/app/controllers/application_controller.rb +0 -3
  71. data/test/dummy/app/helpers/application_helper.rb +0 -2
  72. data/test/dummy/app/views/layouts/application.html.erb +0 -14
  73. data/test/dummy/config.ru +0 -4
  74. data/test/dummy/config/application.rb +0 -56
  75. data/test/dummy/config/boot.rb +0 -10
  76. data/test/dummy/config/database.yml +0 -25
  77. data/test/dummy/config/environment.rb +0 -5
  78. data/test/dummy/config/environments/development.rb +0 -37
  79. data/test/dummy/config/environments/production.rb +0 -67
  80. data/test/dummy/config/environments/test.rb +0 -37
  81. data/test/dummy/config/initializers/backtrace_silencers.rb +0 -7
  82. data/test/dummy/config/initializers/inflections.rb +0 -15
  83. data/test/dummy/config/initializers/mime_types.rb +0 -5
  84. data/test/dummy/config/initializers/secret_token.rb +0 -7
  85. data/test/dummy/config/initializers/session_store.rb +0 -8
  86. data/test/dummy/config/initializers/wrap_parameters.rb +0 -14
  87. data/test/dummy/config/locales/en.yml +0 -5
  88. data/test/dummy/config/routes.rb +0 -58
  89. data/test/dummy/public/404.html +0 -26
  90. data/test/dummy/public/422.html +0 -26
  91. data/test/dummy/public/500.html +0 -25
  92. data/test/dummy/public/favicon.ico +0 -0
  93. data/test/dummy/script/rails +0 -6
  94. data/test/integration/navigation_test.rb +0 -10
  95. data/test/superconductor_test.rb +0 -7
  96. data/test/test_helper.rb +0 -10
  97. data/test/unit/helpers/superconductor/panel_helper_test.rb +0 -4
data/Cargo.toml ADDED
@@ -0,0 +1,25 @@
1
+ [package]
2
+ name = "superconductor"
3
+ version = "0.1.0"
4
+ authors = ["Jaden Carver <jaden.carver@gmail.com>"]
5
+
6
+ [lib]
7
+ crate-type = ["dylib"]
8
+
9
+ [dependencies]
10
+ maud = "*"
11
+ maud_macros = "*"
12
+ libc = "*"
13
+ git2 = { version = "*", default-features = false }
14
+ websocket = { version = "*", default-features = false }
15
+ yaml-rust = "*"
16
+ md5 = "*"
17
+ fsevent = "*"
18
+ chrono = "*"
19
+ base64 = "*"
20
+ rand = "0.3"
21
+ termion = "*"
22
+
23
+ serde = "0.8"
24
+ serde_derive = "0.8"
25
+ serde_xml = "0.9.1"
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in superconductor-gem.gemspec
4
+ gemspec
data/Guardfile ADDED
@@ -0,0 +1,70 @@
1
+ # A sample Guardfile
2
+ # More info at https://github.com/guard/guard#readme
3
+
4
+ ## Uncomment and set this to only include directories you want to watch
5
+ # directories %w(app lib config test spec features) \
6
+ # .select{|d| Dir.exists?(d) ? d : UI.warning("Directory #{d} does not exist")}
7
+
8
+ ## Note: if you are using the `directories` clause above and you are not
9
+ ## watching the project directory ('.'), then you will want to move
10
+ ## the Guardfile to a watched dir and symlink it back, e.g.
11
+ #
12
+ # $ mkdir config
13
+ # $ mv Guardfile config/
14
+ # $ ln -s config/Guardfile .
15
+ #
16
+ # and, you'll have to watch "config/Guardfile" instead of "Guardfile"
17
+
18
+ # Note: The cmd option is now required due to the increasing number of ways
19
+ # rspec may be run, below are examples of the most common uses.
20
+ # * bundler: 'bundle exec rspec'
21
+ # * bundler binstubs: 'bin/rspec'
22
+ # * spring: 'bin/rspec' (This will use spring if running and you have
23
+ # installed the spring binstubs per the docs)
24
+ # * zeus: 'zeus rspec' (requires the server to be started separately)
25
+ # * 'just' rspec: 'rspec'
26
+
27
+ guard :rspec, cmd: "bundle exec rspec" do
28
+ require "guard/rspec/dsl"
29
+ dsl = Guard::RSpec::Dsl.new(self)
30
+
31
+ # Feel free to open issues for suggestions and improvements
32
+
33
+ # RSpec files
34
+ rspec = dsl.rspec
35
+ watch(rspec.spec_helper) { rspec.spec_dir }
36
+ watch(rspec.spec_support) { rspec.spec_dir }
37
+ watch(rspec.spec_files)
38
+
39
+ # Ruby files
40
+ ruby = dsl.ruby
41
+ dsl.watch_spec_files_for(ruby.lib_files)
42
+
43
+ # Rails files
44
+ rails = dsl.rails(view_extensions: %w(erb haml slim))
45
+ dsl.watch_spec_files_for(rails.app_files)
46
+ dsl.watch_spec_files_for(rails.views)
47
+
48
+ watch(rails.controllers) do |m|
49
+ [
50
+ rspec.spec.call("routing/#{m[1]}_routing"),
51
+ rspec.spec.call("controllers/#{m[1]}_controller"),
52
+ rspec.spec.call("acceptance/#{m[1]}")
53
+ ]
54
+ end
55
+
56
+ # Rails config changes
57
+ watch(rails.spec_helper) { rspec.spec_dir }
58
+ watch(rails.routes) { "#{rspec.spec_dir}/routing" }
59
+ watch(rails.app_controller) { "#{rspec.spec_dir}/controllers" }
60
+
61
+ # Capybara features specs
62
+ watch(rails.view_dirs) { |m| rspec.spec.call("features/#{m[1]}") }
63
+ watch(rails.layouts) { |m| rspec.spec.call("features/#{m[1]}") }
64
+
65
+ # Turnip features and steps
66
+ watch(%r{^spec/acceptance/(.+)\.feature$})
67
+ watch(%r{^spec/acceptance/steps/(.+)_steps\.rb$}) do |m|
68
+ Dir[File.join("**/#{m[1]}.feature")][0] || "spec/acceptance"
69
+ end
70
+ end
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2017 Jaden Carver
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/Makefile ADDED
@@ -0,0 +1,4 @@
1
+ all:
2
+ cargo rustc --release -- -A overflowing-literals
3
+ clean:
4
+ rm -rf target
data/README.md ADDED
@@ -0,0 +1,58 @@
1
+ # Superconductor
2
+
3
+ Superconductor is a Workflow and Project Management tool.
4
+
5
+ It is written in `rust-lang/rust` and you currently have to compile the dylib manually.
6
+ Install `rust-lang/rust` and `rust-lang/cargo` and then run `./bin/start`.
7
+
8
+ To compile the release build for use by the gem, run `./bin/release`.
9
+
10
+ ![Superconductor](spec/integration/screenshots/tasks-by_status.png)
11
+
12
+ ## Installation
13
+
14
+ Add this line to your application's Gemfile:
15
+
16
+ ```ruby
17
+ gem 'superconductor'
18
+ ```
19
+
20
+ And then execute:
21
+
22
+ $ bundle
23
+
24
+ Or install it yourself as:
25
+
26
+ $ gem install superconductor
27
+
28
+ From here, you can [Try Superconductor](javascript:PM.toggle();).
29
+ For more information, see [Contributing](#label-Contributing).
30
+
31
+ ## Usage
32
+
33
+ ### Ruby on Rails
34
+
35
+ In your `config/environments/development.rb` file, add {Superconductor::Middleware}
36
+
37
+ ```
38
+ config.middleware.insert_before(ActionDispatch::DebugExceptions, Superconductor::Middleware)
39
+ ```
40
+
41
+ ### Rack
42
+
43
+ ```
44
+ require 'superconductor'
45
+
46
+ use Superconductor::Middleware
47
+ run MyApp
48
+ ```
49
+
50
+ ## Contributing
51
+
52
+ Bug reports and pull requests are welcome on GitHub at https://github.com/jadencarver/superconductor.
53
+
54
+
55
+ ## License
56
+
57
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
58
+
data/Rakefile CHANGED
@@ -1,40 +1,13 @@
1
- #!/usr/bin/env rake
2
- begin
3
- require 'bundler/setup'
4
- rescue LoadError
5
- puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
6
- end
7
- begin
8
- require 'rdoc/task'
9
- rescue LoadError
10
- require 'rdoc/rdoc'
11
- require 'rake/rdoctask'
12
- RDoc::Task = Rake::RDocTask
13
- end
14
-
15
- RDoc::Task.new(:rdoc) do |rdoc|
16
- rdoc.rdoc_dir = 'rdoc'
17
- rdoc.title = 'Superconductor'
18
- rdoc.options << '--line-numbers'
19
- rdoc.rdoc_files.include('README.rdoc')
20
- rdoc.rdoc_files.include('lib/**/*.rb')
21
- end
22
-
23
- APP_RAKEFILE = File.expand_path("../test/dummy/Rakefile", __FILE__)
24
- load 'rails/tasks/engine.rake'
25
-
26
-
27
-
28
- Bundler::GemHelper.install_tasks
29
-
30
- require 'rake/testtask'
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+ require "yard"
31
4
 
32
- Rake::TestTask.new(:test) do |t|
33
- t.libs << 'lib'
34
- t.libs << 'test'
35
- t.pattern = 'test/**/*_test.rb'
36
- t.verbose = false
5
+ YARD::Rake::YardocTask.new do |t|
6
+ t.files = ['lib/**/*.rb']
7
+ #t.options = ['--any', '--extra', '--opts']
8
+ #t.stats_options = ['--list-undoc']
37
9
  end
38
10
 
11
+ RSpec::Core::RakeTask.new(:spec)
39
12
 
40
- task :default => :test
13
+ task :default => :spec
data/assets/__pm.js ADDED
@@ -0,0 +1,424 @@
1
+ (PM.superconductor = function(window, PM) {
2
+ var document = window.document;
3
+ var host = document.createElement('div');
4
+ var root = document.createElement('div');
5
+ var DOM;
6
+
7
+ setInterval(applyTimeAgo, 60000);
8
+
9
+ DOM = (host.attachShadow) ? host.attachShadow({mode: 'open'}) : host;
10
+
11
+ DOM.appendChild(root);
12
+ document.body.appendChild(host);
13
+
14
+ var processor = loadProcessor();
15
+ var parser = new DOMParser();
16
+ var socket = openSocket();
17
+ var paused = false;
18
+
19
+ document.addEventListener('keypress', function (event) {
20
+ if (!root) return true;
21
+ if (event.which == 96) { PM.toggle(); }
22
+ });
23
+
24
+ DOM.addEventListener('focus', function (event) {
25
+ if (event.target.id === '__pm__commit__message') {
26
+ var changes = DOM.querySelector('#__pm__commit__changes');
27
+ if (changes) changes.classList.remove('open');
28
+ stickToBottom();
29
+ }
30
+ }, true);
31
+
32
+ DOM.addEventListener('click', function (event) {
33
+ var form = DOM.querySelector('#__pm__commit');
34
+ var legend = closest(event.target, function(e) { return e.id === '__pm__commit__changes_legend'; }, 2);
35
+ if (event.target.type === "submit") {
36
+ serialize(form, event);
37
+ event.preventDefault();
38
+ } else if (legend) {
39
+ legend.focus();
40
+ var detailsElement = legend.parentElement;
41
+ var classList = detailsElement.classList;
42
+ if (classList.contains('open')) {
43
+ classList.remove('open');
44
+ DOM.querySelector('#__pm__commit__message').focus();
45
+ } else {
46
+ classList.add('open');
47
+ }
48
+ stickToBottom();
49
+ }
50
+ });
51
+
52
+ DOM.addEventListener('mouseup', function (event) {
53
+ var target = closest(event.target, function(e) { return e.classList.contains('task'); });
54
+ if (target) {
55
+ var form = DOM.querySelector('#__pm__commit');
56
+ DOM.querySelector("#__pm__commit__task").value = target.dataset.name;
57
+ serialize(form, event);
58
+ event.preventDefault();
59
+ }
60
+ });
61
+
62
+ DOM.addEventListener('change', function (event) {
63
+ var debounceRoot = root;
64
+ setTimeout(function() {
65
+ if (root === debounceRoot) {
66
+ serialize(event.target.form, event);
67
+ }
68
+ }, event.target.tagName === "TEXTAREA" ? 100 : 0);
69
+ });
70
+
71
+ DOM.addEventListener('keyup', function (event) {
72
+ var parentElement = event.target.parentElement;
73
+ var EnterKey = 13, SpaceKey = 32;
74
+ var isActionable = event.which === EnterKey || event.which === SpaceKey;
75
+ var isCheckbox = event.target.querySelector('input[type=checkbox]');
76
+ var isDetails = parentElement && parentElement.classList.contains('details');
77
+
78
+ var openDetails = function (details) {
79
+ details.classList.toggle('open');
80
+ stickToBottom();
81
+ };
82
+ var toggleCheckbox = function (checkbox) {
83
+ checkbox.checked = !checkbox.checked;
84
+ serialize(checkbox.form, event);
85
+ };
86
+
87
+ if (isActionable) {
88
+ if (isDetails) openDetails(parentElement);
89
+ if (isCheckbox) toggleCheckbox(isCheckbox);
90
+ }
91
+ });
92
+
93
+ var menu;
94
+ function contextMenu(event) {
95
+ if (menu) closeMenu();
96
+ menu = document.createElement('menu');
97
+ menu.id = '__pm__context-menu';
98
+ menu.style.top = event.clientY - root.getBoundingClientRect().top + 'px';
99
+ menu.style.left = event.clientX + 'px';
100
+ var options = [
101
+ ['New Subtask', null, function() {}],
102
+ ['Assign Task', null, function() {}],
103
+ ['Inspect Element', null, function() { console.log('inspect', event.target) }],
104
+ ['Delete', 'warning', function() {}]
105
+ ]
106
+ for(option of options) {
107
+ var label = option[0], cssClass = option[1], callback = option[2];
108
+ var item = document.createElement('menuitem');
109
+ item.tabIndex = 10;
110
+ if (cssClass) item.classList.add(cssClass);
111
+ if (callback) item.addEventListener('click', callback);
112
+ item.textContent = label;
113
+ menu.append(item);
114
+ }
115
+ root.append(menu);
116
+ function closeMenu() {
117
+ root.removeEventListener('click', closeMenu);
118
+ if (root.contains(menu)) root.removeChild(menu);
119
+ menu = null;
120
+ }
121
+ setTimeout(function() { root.addEventListener('click', closeMenu); }, 10);
122
+ event.preventDefault();
123
+ };
124
+ DOM.addEventListener('contextmenu', contextMenu);
125
+ DOM.addEventListener('mousedown', function(event) {
126
+ if (event.button === 1 || event.metaKey) {
127
+ contextMenu(event)
128
+ event.preventDefault();
129
+ }
130
+ });
131
+
132
+ var dragging;
133
+ var droppingTile;
134
+ var droppingColumn;
135
+ var droppables = '.tiles .column, .tiles .tile';
136
+
137
+ DOM.addEventListener('dragstart', function (event) {
138
+ dragging = event.target;
139
+ event.dataTransfer.setData('text/plain', null);
140
+ setTimeout(function() {
141
+ dragging.parentElement.style.display = 'none';
142
+ }, 1);
143
+ var dropTargets = DOM.querySelectorAll(droppables);
144
+ for (dropTarget of dropTargets) {
145
+ if (dropTarget === event.target) continue;
146
+ dropTarget.addEventListener('dragenter', dragEnter);
147
+ dropTarget.addEventListener('dragleave', dragLeave);
148
+ dropTarget.addEventListener('dragover', isDropTarget);
149
+ dropTarget.addEventListener('drop', dragDropped);
150
+ };
151
+ });
152
+
153
+ DOM.addEventListener('dragend', function (event) {
154
+ dragging = null;
155
+ var dropTargets = DOM.querySelectorAll(droppables);
156
+ for (dropTarget of dropTargets) {
157
+ if (dropTarget === event.target) continue;
158
+ dropTarget.removeEventListener('dragenter', dragEnter);
159
+ dropTarget.removeEventListener('dragover', isDropTarget);
160
+ dropTarget.removeEventListener('drop', dragDropped);
161
+ };
162
+ });
163
+
164
+ //////////////////////////////////////////////////////////////////////////////////////////////////
165
+
166
+ function dragEnter(event) {
167
+ if (this.classList.contains('column')) {
168
+ if (droppingColumn && droppingColumn !== this) {
169
+ droppingColumn.classList.remove('droppable')
170
+ }
171
+ droppingColumn = this;
172
+ if (droppingTile && !this.contains(droppingTile)) {
173
+ droppingTile.classList.remove('droppable');
174
+ droppingTile = false;
175
+ }
176
+ } else if (this.classList.contains('tile')) {
177
+ if (droppingTile && droppingTile !== this) {
178
+ droppingTile.classList.remove('droppable')
179
+ }
180
+ droppingTile = this;
181
+ }
182
+ if (droppingColumn) droppingColumn.classList.add('droppable');
183
+ if (droppingTile) droppingTile.classList.add('droppable');
184
+ event.preventDefault();
185
+ }
186
+
187
+ function dragLeave(event) {
188
+ }
189
+
190
+ function isDropTarget(event) {
191
+ event.preventDefault();
192
+ };
193
+
194
+ function dragDropped(event) {
195
+ var form = DOM.querySelector('#__pm__commit');
196
+ var task = DOM.querySelector("#__pm__commit__task");
197
+ var drag = DOM.querySelector("#__pm__commit__dragged");
198
+ var blacklist = [];
199
+ closest(this, function(element) {
200
+ if (!element.dataset) return false;
201
+ var name = element.dataset.propertyName;
202
+ var field = form.querySelector("*[data-name='"+name+"']");
203
+ if (field && blacklist.indexOf(name) === -1) {
204
+ blacklist.push(name);
205
+ task.value = dragging ? dragging.dataset.name : '';
206
+ drag.checked = true;
207
+ field.value = element.dataset.propertyValue;
208
+ }
209
+ });
210
+ serialize(form, event);
211
+ dragging = false;
212
+ event.preventDefault();
213
+ };
214
+
215
+ function loadProcessor() {
216
+ var processor = new XSLTProcessor();
217
+ var processorRequest = new XMLHttpRequest();
218
+ processorRequest.open("GET", "/__panel.xslt", false);
219
+ processorRequest.send(null);
220
+ try {
221
+ processor.importStylesheet(processorRequest.responseXML);
222
+ } catch(error) {
223
+ if (typeof(root) !== "undefined") DOM.removeChild(root);
224
+ root = errorNotice();
225
+ DOM.appendChild(root);
226
+ throw error;
227
+ }
228
+ return processor;
229
+ }
230
+
231
+ function openSocket() {
232
+ var socket = new WebSocket("ws://127.0.0.1:"+PM.port, "superconductor");
233
+ socket.onmessage = function (event) {
234
+ var form = DOM.querySelector('#__pm__commit');
235
+ if (event.data === 'submit' && form) {
236
+ serialize(form, event);
237
+ } else {
238
+ var state = parser.parseFromString(event.data, "text/xml");
239
+ setState(state);
240
+ }
241
+ }
242
+ return socket;
243
+ }
244
+
245
+ function serialize(form, event) {
246
+ if (root.classList.contains('blocking')) return false;
247
+ var serializer = new XMLSerializer();
248
+ var request = document.implementation.createDocument(null, form.name);
249
+ var message = request.children[0];
250
+ var elements = form.elements;
251
+ var filter = Array.prototype.filter.bind(elements);
252
+ var reduce = Array.prototype.reduce.bind(elements);
253
+ elements = filter(function (element) { return element.name !== ""; });
254
+ elements = reduce(function (builder, element) {
255
+ var name = element.name;
256
+ builder[name] = builder[name] || [];
257
+ builder[name].push(element);
258
+ return builder;
259
+ }, {});
260
+
261
+ if (event && DOM.activeElement) {
262
+ var focus = request.createElement('focus');
263
+ focus.textContent = DOM.activeElement.id;
264
+ message.appendChild(focus);
265
+ }
266
+ for(name in elements) {
267
+ var inputs = elements[name];
268
+ if (event.target.tagName === 'BUTTON') {
269
+ if (inputs.filter(function(i) { return event.target === i; }).length) {
270
+ inputs = [event.target];
271
+ }
272
+ }
273
+ for (var i = 0; i < inputs.length; i++) {
274
+ var input = inputs[i];
275
+ if (input.name) {
276
+ var element = request.createElement(input.name)
277
+ var valueElement;
278
+ var inputHasData = Object.keys(input.dataset).length > 0;
279
+ if (inputHasData) {
280
+ for(data in input.dataset) {
281
+ var dataElement = request.createElement(data);
282
+ dataElement.textContent = input.dataset[data];
283
+ element.appendChild(dataElement);
284
+ }
285
+ if (input.value) {
286
+ valueElement = request.createElement('value');
287
+ valueElement.textContent = input.value;
288
+ element.appendChild(valueElement);
289
+ }
290
+ } else {
291
+ element.textContent = input.value;
292
+ }
293
+ if (input.tagName === 'INPUT' && input.type.toUpperCase() === 'CHECKBOX') {
294
+ if (input.checked) {
295
+ message.appendChild(element);
296
+ }
297
+ } else if (input.tagName === 'BUTTON' || input.tagName === 'INPUT' && input.type.toUpperCase() === 'SUBMIT') {
298
+ if (event && input === event.target) {
299
+ message.appendChild(element);
300
+ }
301
+ } else {
302
+ message.appendChild(element);
303
+ }
304
+ }
305
+ }
306
+ }
307
+ console.log('serialize', request);
308
+ socket.send(serializer.serializeToString(request));
309
+ root.classList.add('blocking')
310
+ }
311
+
312
+ var restoreState;
313
+ function setState(state) {
314
+ console.log(state);
315
+ root.classList.remove('blocking')
316
+ if (dragging) return restoreState = state;
317
+ if (restoreState) state = restoreState;
318
+ var open, fragment = processor.transformToFragment(state, document);
319
+ if (root) {
320
+ open = root.classList.contains('open');
321
+ DOM.removeChild(root);
322
+ }
323
+ if (fragment) {
324
+ root = fragment.firstChild;
325
+ } else {
326
+ root = errorNotice();
327
+ }
328
+ applyTimeAgo();
329
+ var forEachCodeBlock = Array.prototype.forEach.bind(root.querySelectorAll('pre code'));
330
+ if (typeof hljs !== "undefined") forEachCodeBlock(hljs.highlightBlock);
331
+ DOM.appendChild(root);
332
+ if (open) {
333
+ root.classList.add('open');
334
+ var focus = state.querySelector('focus');
335
+ if (focus) var focusId = focus.textContent;
336
+ if (focusId) var focusElement = DOM.querySelector('#'+focusId);
337
+ if (focusElement) {
338
+ var detailsElement = closest(focusElement, function (e) {
339
+ return e.classList.contains('details');
340
+ });
341
+ if (detailsElement) detailsElement.classList.add('open');
342
+ focusElement.classList.add('no-transition');
343
+ focusElement.focus();
344
+ focusElement.classList.remove('no-transition');
345
+ }
346
+ }
347
+ stickToBottom();
348
+ }
349
+
350
+ function errorNotice() {
351
+ root = document.createElement('div');
352
+ root.style.position = 'fixed';
353
+ root.style.left = 0; root.style.right = 0; root.style.bottom = 0;
354
+ root.style.textAlign = 'center'; root.style.lineHeight = '3em';
355
+ root.style.backgroundColor='#fe6d39'; root.style.color="#fff";
356
+ root.textContent = "An error occurred initializing Superconductor";
357
+ return root;
358
+ }
359
+
360
+ function closest(element, filter, limit) {
361
+ limit = limit || -1
362
+ var count = 0;
363
+ while (element) {
364
+ if (filter(element)) return element;
365
+ else if (count === limit) return false;
366
+ else element = element.parentElement;
367
+ count++;
368
+ }
369
+ }
370
+
371
+ function stickToBottom() {
372
+ var commit = DOM.querySelector('#__pm__task');
373
+ if (!commit) return false;
374
+ var stickToBottomCallback = function () {
375
+ commit.scrollTop = commit.scrollHeight;
376
+ window.requestAnimationFrame(stickToBottomCallback);
377
+ };
378
+ setTimeout(function () { stickToBottomCallback = function () {} }, 250);
379
+ stickToBottomCallback();
380
+ }
381
+
382
+
383
+ function timeAgo(date) {
384
+ var dateString = date.getAttribute("datetime");
385
+ var timestamp = new Date(dateString).getTime();
386
+ var now = new Date().getTime();
387
+ var distance = timestamp - now;
388
+ var seconds = Math.round(Math.abs(distance) / 1000);
389
+ var minutes = Math.round(seconds / 60);
390
+ var hours = Math.round(minutes / 60);
391
+ var days = Math.round(hours / 24);
392
+ var months = Math.round(days / 30);
393
+ var years = Math.round(days / 365);
394
+ if (seconds < 60) date.innerHTML = "less than a minute ago";
395
+ else if (minutes < 2) date.innerHTML = minutes+" minute ago";
396
+ else if (minutes < 60) date.innerHTML = minutes+" minutes ago";
397
+ else if (hours < 2) date.innerHTML = hours+" hour ago";
398
+ else if (hours < 24) date.innerHTML = hours+" hours ago";
399
+ else if (days < 2) date.innerHTML = days+" day ago";
400
+ else if (days < 30) date.innerHTML = days+" days ago";
401
+ else if (months < 2) date.innerHTML = months+" month ago";
402
+ else if (months < 12) date.innerHTML = months+" months ago";
403
+ else if (years < 2) date.innerHTML = years+" year ago";
404
+ else date.innerHTML = years+' years ago';
405
+ }
406
+
407
+ function applyTimeAgo() {
408
+ Array.prototype.forEach.call(root.querySelectorAll('time'), timeAgo)
409
+ }
410
+
411
+ PM.toggle = function () {
412
+ root.classList.toggle('open');
413
+ };
414
+
415
+ PM.close = function () {
416
+ root.classList.remove('open');
417
+ };
418
+
419
+ PM.open = function () {
420
+ root.classList.add('open');
421
+ };
422
+
423
+ //PM.open();
424
+ })(window, PM);