active_versioning_workflow 1.0.2 → 1.1.0
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.
- checksums.yaml +4 -4
- data/README.md +47 -1
- data/app/assets/javascripts/active_versioning/live-preview.js +70 -0
- data/app/assets/stylesheets/active_versioning/active-preview.scss +14 -0
- data/app/controllers/active_versioning/workflow/live_preview_controller.rb +9 -0
- data/app/views/active_versioning/workflow/live_preview/show.html.erb +63 -0
- data/config/routes.rb +3 -0
- data/lib/active_versioning/workflow.rb +15 -7
- data/lib/active_versioning/workflow/actions_with_preview.rb +15 -0
- data/lib/active_versioning/workflow/preview_link.rb +23 -0
- data/lib/active_versioning/workflow/show_resource.rb +4 -11
- data/lib/active_versioning/workflow/version.rb +1 -1
- data/lib/generators/active_versioning/templates/initializers/active_versioning_workflow.rb +1 -0
- data/vendor/assets/javascripts/active_versioning/form-serialize.js +267 -0
- data/vendor/assets/javascripts/active_versioning/lodash.custom.js +9 -0
- metadata +11 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: faea94025b06a679c6073bc2eed8677ef498c5ed
|
4
|
+
data.tar.gz: df408b6ccfbda2d62d893908218abae42f3a9913
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 70c31eea328365bd8991b110e32d01016e167d733da322b6302ab37b15332d19a417be4fe22630681696f85d932e3ab5c3562544a65233a5e44eeea4a4db7a64
|
7
|
+
data.tar.gz: 993dde8dae50274d1a4d703d28e2c5b88e0e12def10eb574eceeb2da5b985f3da834a287a7c62ff1bacbdd84d69161b5453fc07ddb6457b9ea1411d4dfe95e5d
|
data/README.md
CHANGED
@@ -142,7 +142,7 @@ end
|
|
142
142
|
When all is said and done, this will give us an awesome interface for version workflow in ActiveAdmin:
|
143
143
|

|
144
144
|
|
145
|
-
###
|
145
|
+
### Preview
|
146
146
|
ActiveVersioning Workflow allows for some optional basic previewing functionality that leverages the non-admin controller for a resource. If you'd like to take advantage of previewing, here's how you'll want to set it up:
|
147
147
|
```ruby
|
148
148
|
class PostsController < ApplicationController
|
@@ -168,3 +168,49 @@ In the ActiveAdmin draft panel, you'll see an extra preview button:
|
|
168
168
|

|
169
169
|
|
170
170
|
This will open a new window with our `PostsController#show` rendered out with the current draft version of our post.
|
171
|
+
|
172
|
+
You'll also be able to use `actions_with_preview` in place of `actions` inside the default `index` block in an ActiveAdmin resource definition:
|
173
|
+
```ruby
|
174
|
+
ActiveAdmin.register Post do
|
175
|
+
include ActiveVersioning::Workflow::Controller
|
176
|
+
|
177
|
+
permit_params :title, :body
|
178
|
+
|
179
|
+
index do
|
180
|
+
column :title
|
181
|
+
|
182
|
+
actions_with_preview
|
183
|
+
end
|
184
|
+
end
|
185
|
+
```
|
186
|
+
|
187
|
+
### Live Preview
|
188
|
+
|
189
|
+
If you're using the above preview functionality, you can also tap into some optional -- somewhat experimental -- real-time live preview on edit pages.
|
190
|
+
|
191
|
+
To use the real-time live preview, there's some additional setup required.
|
192
|
+
|
193
|
+
Mount ActiveVersioning Workflow's routes:
|
194
|
+
```
|
195
|
+
# config/routes.rb
|
196
|
+
|
197
|
+
mount ActiveVerioning::Workflow::Engine, as: 'active_versioning'
|
198
|
+
```
|
199
|
+
|
200
|
+
Inside a JS file included into the asset pipeline, invoke the previewer with:
|
201
|
+
```javascript
|
202
|
+
//= require active_versioning/live-preview
|
203
|
+
|
204
|
+
var updater = ActivePreview({
|
205
|
+
// URL to the page to preview
|
206
|
+
url: "http://example.com/preview",
|
207
|
+
|
208
|
+
// Where to find live-preview.html
|
209
|
+
frameSrc: "/active-versioning/live-preview.html"
|
210
|
+
});
|
211
|
+
|
212
|
+
// Use updater however you want to emit an update. For example, with Colonel Kurtz
|
213
|
+
var editor = new ColonelKurtz();
|
214
|
+
|
215
|
+
editor.listen(updater);
|
216
|
+
```
|
@@ -0,0 +1,70 @@
|
|
1
|
+
//= require active_versioning/form-serialize
|
2
|
+
//= require active_versioning/lodash.custom
|
3
|
+
|
4
|
+
(function (global) {
|
5
|
+
function send (form, callback) {
|
6
|
+
var http = new XMLHttpRequest();
|
7
|
+
var params = global.FormSerialize(form, { hash: true });
|
8
|
+
var method = (params['_method'] || form.method).toUpperCase();
|
9
|
+
|
10
|
+
http.open(method, form.action, true);;
|
11
|
+
|
12
|
+
// Send JSON because we already need to serialize form parameters into JSON
|
13
|
+
// to extract the method
|
14
|
+
http.setRequestHeader("Content-Type", "application/json");
|
15
|
+
|
16
|
+
// Accept JSON to save on paint time rendering the admin again
|
17
|
+
http.setRequestHeader("Accept", "application/json");
|
18
|
+
|
19
|
+
http.send(JSON.stringify(params));
|
20
|
+
|
21
|
+
http.addEventListener('readystatechange', function onUpdate (event) {
|
22
|
+
// We don't care about the payload, so trigger the callback as *soon*
|
23
|
+
// as we get the progress state, which indicates that content is loading.
|
24
|
+
if (http.readyState >= 2) {
|
25
|
+
http.removeEventListener('readystatechange', onUpdate);
|
26
|
+
callback();
|
27
|
+
}
|
28
|
+
})
|
29
|
+
|
30
|
+
return http;
|
31
|
+
}
|
32
|
+
|
33
|
+
function previewer (options) {
|
34
|
+
options = options || {};
|
35
|
+
|
36
|
+
var frame = document.createElement('iframe');
|
37
|
+
var form = document.querySelector('form');
|
38
|
+
var request = null;
|
39
|
+
|
40
|
+
frame.id = "live_preview";
|
41
|
+
frame.frameBorder = 0;
|
42
|
+
|
43
|
+
document.body.appendChild(frame);
|
44
|
+
document.body.className += ' am-live-preview';
|
45
|
+
|
46
|
+
var refresh = function () {
|
47
|
+
frame.contentWindow.postMessage(options.url, window.location.origin);
|
48
|
+
}
|
49
|
+
|
50
|
+
var update = global._.debounce(function() {
|
51
|
+
if (request) {
|
52
|
+
request.abort();
|
53
|
+
}
|
54
|
+
|
55
|
+
request = send(form, refresh);
|
56
|
+
}, 500, { leading: true, trailing: true, maxWait: 1500 });
|
57
|
+
|
58
|
+
frame.onload = function() {
|
59
|
+
frame.onload = null;
|
60
|
+
refresh();
|
61
|
+
form.addEventListener('change', update, true);
|
62
|
+
};
|
63
|
+
|
64
|
+
frame.src = options.frameSrc;
|
65
|
+
|
66
|
+
return update;
|
67
|
+
}
|
68
|
+
|
69
|
+
global.ActivePreview = previewer;
|
70
|
+
})(window);
|
@@ -0,0 +1,63 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<meta charset="utf-8">
|
5
|
+
<title>Live Preview</title>
|
6
|
+
<style>
|
7
|
+
body {
|
8
|
+
background: white;
|
9
|
+
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif;
|
10
|
+
margin: 0;
|
11
|
+
}
|
12
|
+
|
13
|
+
iframe {
|
14
|
+
background: white;
|
15
|
+
bottom: 0;
|
16
|
+
height: 100%;
|
17
|
+
left: 0;
|
18
|
+
opacity: 0;
|
19
|
+
position: fixed;
|
20
|
+
top: 0;
|
21
|
+
transition: 0.2s opacity;
|
22
|
+
width: 100%;
|
23
|
+
}
|
24
|
+
|
25
|
+
.active {
|
26
|
+
opacity: 1;
|
27
|
+
z-index: 1
|
28
|
+
}
|
29
|
+
</style>
|
30
|
+
</head>
|
31
|
+
<body>
|
32
|
+
<iframe id="buffer" frameborder="0"></iframe>
|
33
|
+
|
34
|
+
<script>
|
35
|
+
var template = document.createElement('iframe');
|
36
|
+
template.frameBorder = 0;
|
37
|
+
|
38
|
+
var buffer = template.cloneNode();
|
39
|
+
|
40
|
+
window.addEventListener("message", function (event) {
|
41
|
+
var frame = template.cloneNode();
|
42
|
+
|
43
|
+
document.body.appendChild(frame);
|
44
|
+
|
45
|
+
frame.onload = function () {
|
46
|
+
frame.onload = null;
|
47
|
+
frame.className = 'active';
|
48
|
+
|
49
|
+
if (buffer.contentWindow) {
|
50
|
+
frame.contentWindow.scrollTo(0, buffer.contentWindow.scrollY);
|
51
|
+
}
|
52
|
+
|
53
|
+
setTimeout(function() {
|
54
|
+
buffer.remove();
|
55
|
+
buffer = frame;
|
56
|
+
}, 200);
|
57
|
+
}
|
58
|
+
|
59
|
+
frame.src = event.data;
|
60
|
+
}, false);
|
61
|
+
</script>
|
62
|
+
</body>
|
63
|
+
</html>
|
data/config/routes.rb
ADDED
@@ -4,12 +4,20 @@ require 'generators/active_versioning/workflow_generator'
|
|
4
4
|
|
5
5
|
module ActiveVersioning
|
6
6
|
module Workflow
|
7
|
-
autoload :
|
8
|
-
autoload :
|
9
|
-
autoload :
|
10
|
-
autoload :
|
11
|
-
autoload :
|
12
|
-
autoload :
|
13
|
-
autoload :
|
7
|
+
autoload :ActionsWithPreview, 'active_versioning/workflow/actions_with_preview'
|
8
|
+
autoload :Controller, 'active_versioning/workflow/controller'
|
9
|
+
autoload :DraftActions, 'active_versioning/workflow/draft_actions'
|
10
|
+
autoload :DSL, 'active_versioning/workflow/dsl'
|
11
|
+
autoload :Previewable, 'active_versioning/workflow/previewable'
|
12
|
+
autoload :PreviewLink, 'active_versioning/workflow/preview_link'
|
13
|
+
autoload :Router, 'active_versioning/workflow/router'
|
14
|
+
autoload :ShowResource, 'active_versioning/workflow/show_resource'
|
15
|
+
autoload :ShowVersion, 'active_versioning/workflow/show_version'
|
16
|
+
|
17
|
+
def self.previewable?(resource)
|
18
|
+
preview_controller = "#{resource.class.to_s.pluralize}Controller".safe_constantize
|
19
|
+
|
20
|
+
preview_controller.present? && preview_controller.singleton_class.ancestors.include?(Previewable)
|
21
|
+
end
|
14
22
|
end
|
15
23
|
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module ActiveVersioning
|
2
|
+
module Workflow
|
3
|
+
module ActionsWithPreview
|
4
|
+
include ActiveVersioning::Workflow::PreviewLink
|
5
|
+
|
6
|
+
def actions_with_preview
|
7
|
+
actions defaults: false do |resource|
|
8
|
+
item preview_link_for(resource, class: :member_link) if ActiveVersioning::Workflow.previewable?(resource)
|
9
|
+
|
10
|
+
defaults(resource, css_class: :member_link)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module ActiveVersioning
|
2
|
+
module Workflow
|
3
|
+
module PreviewLink
|
4
|
+
def preview_link_for(resource, link_options={})
|
5
|
+
link_to I18n.t('active_versioning.links.preview'), preview_path_for(resource), link_options.merge(
|
6
|
+
class: 'preview-link',
|
7
|
+
target: :blank
|
8
|
+
)
|
9
|
+
end
|
10
|
+
|
11
|
+
def preview_path_for(resource, options = {})
|
12
|
+
resource_path = proc do |resource|
|
13
|
+
param = resource.try(:slug) || resource.to_param
|
14
|
+
route_key = resource.model_name.singular_route_key
|
15
|
+
|
16
|
+
options.fetch(:context, self).send("#{route_key}_path", param, _preview: true)
|
17
|
+
end
|
18
|
+
|
19
|
+
resource.try(:path, _preview: true) || resource_path.call(resource)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -1,6 +1,8 @@
|
|
1
1
|
module ActiveVersioning
|
2
2
|
module Workflow
|
3
3
|
class ShowResource < ::ActiveAdmin::Views::Pages::Show
|
4
|
+
include ActiveVersioning::Workflow::PreviewLink
|
5
|
+
|
4
6
|
def main_content
|
5
7
|
instance_exec(resource, &show_block)
|
6
8
|
end
|
@@ -101,19 +103,10 @@ module ActiveVersioning
|
|
101
103
|
link_to I18n.t('active_versioning.links.edit'), [:edit, active_admin_namespace.name, resource], class: 'edit-link'
|
102
104
|
end
|
103
105
|
|
104
|
-
def preview_controller
|
105
|
-
@preview_controller ||= "#{resource_class.to_s.pluralize}Controller".safe_constantize
|
106
|
-
end
|
107
|
-
|
108
106
|
def preview_link
|
109
|
-
|
110
|
-
return ''
|
111
|
-
end
|
107
|
+
return '' unless ActiveVersioning::Workflow.previewable?(resource)
|
112
108
|
|
113
|
-
|
114
|
-
class: 'preview-link',
|
115
|
-
target: :blank
|
116
|
-
}
|
109
|
+
preview_link_for(resource)
|
117
110
|
end
|
118
111
|
|
119
112
|
def discard_link
|
@@ -2,3 +2,4 @@ require 'active_versioning/workflow'
|
|
2
2
|
|
3
3
|
ActiveAdmin::ResourceDSL.send(:include, ActiveVersioning::Workflow::DSL)
|
4
4
|
ActiveAdmin::Views::ActiveAdminForm.send(:include, ActiveVersioning::Workflow::DraftActions)
|
5
|
+
ActiveAdmin::Views::IndexAsTable::IndexTableFor.send(:include, ActiveVersioning::Workflow::ActionsWithPreview)
|
@@ -0,0 +1,267 @@
|
|
1
|
+
/**
|
2
|
+
* Form Serialize v0.7.1
|
3
|
+
* via https://github.com/defunctzombie/form-serialize
|
4
|
+
*/
|
5
|
+
|
6
|
+
(function(global) {
|
7
|
+
// get successful control from form and assemble into object
|
8
|
+
// http://www.w3.org/TR/html401/interact/forms.html#h-17.13.2
|
9
|
+
|
10
|
+
// types which indicate a submit action and are not successful controls
|
11
|
+
// these will be ignored
|
12
|
+
var k_r_submitter = /^(?:submit|button|image|reset|file)$/i;
|
13
|
+
|
14
|
+
// node names which could be successful controls
|
15
|
+
var k_r_success_contrls = /^(?:input|select|textarea|keygen)/i;
|
16
|
+
|
17
|
+
// Matches bracket notation.
|
18
|
+
var brackets = /(\[[^\[\]]*\])/g;
|
19
|
+
|
20
|
+
// serializes form fields
|
21
|
+
// @param form MUST be an HTMLForm element
|
22
|
+
// @param options is an optional argument to configure the serialization. Default output
|
23
|
+
// with no options specified is a url encoded string
|
24
|
+
// - hash: [true | false] Configure the output type. If true, the output will
|
25
|
+
// be a js object.
|
26
|
+
// - serializer: [function] Optional serializer function to override the default one.
|
27
|
+
// The function takes 3 arguments (result, key, value) and should return new result
|
28
|
+
// hash and url encoded str serializers are provided with this module
|
29
|
+
// - disabled: [true | false]. If true serialize disabled fields.
|
30
|
+
// - empty: [true | false]. If true serialize empty fields
|
31
|
+
function serialize(form, options) {
|
32
|
+
if (typeof options != 'object') {
|
33
|
+
options = { hash: !!options };
|
34
|
+
}
|
35
|
+
else if (options.hash === undefined) {
|
36
|
+
options.hash = true;
|
37
|
+
}
|
38
|
+
|
39
|
+
var result = (options.hash) ? {} : '';
|
40
|
+
var serializer = options.serializer || ((options.hash) ? hash_serializer : str_serialize);
|
41
|
+
|
42
|
+
var elements = form && form.elements ? form.elements : [];
|
43
|
+
|
44
|
+
//Object store each radio and set if it's empty or not
|
45
|
+
var radio_store = Object.create(null);
|
46
|
+
|
47
|
+
for (var i=0 ; i<elements.length ; ++i) {
|
48
|
+
var element = elements[i];
|
49
|
+
|
50
|
+
// ingore disabled fields
|
51
|
+
if ((!options.disabled && element.disabled) || !element.name) {
|
52
|
+
continue;
|
53
|
+
}
|
54
|
+
// ignore anyhting that is not considered a success field
|
55
|
+
if (!k_r_success_contrls.test(element.nodeName) ||
|
56
|
+
k_r_submitter.test(element.type)) {
|
57
|
+
continue;
|
58
|
+
}
|
59
|
+
|
60
|
+
var key = element.name;
|
61
|
+
var val = element.value;
|
62
|
+
|
63
|
+
// we can't just use element.value for checkboxes cause some browsers lie to us
|
64
|
+
// they say "on" for value when the box isn't checked
|
65
|
+
if ((element.type === 'checkbox' || element.type === 'radio') && !element.checked) {
|
66
|
+
val = undefined;
|
67
|
+
}
|
68
|
+
|
69
|
+
// If we want empty elements
|
70
|
+
if (options.empty) {
|
71
|
+
// for checkbox
|
72
|
+
if (element.type === 'checkbox' && !element.checked) {
|
73
|
+
val = '';
|
74
|
+
}
|
75
|
+
|
76
|
+
// for radio
|
77
|
+
if (element.type === 'radio') {
|
78
|
+
if (!radio_store[element.name] && !element.checked) {
|
79
|
+
radio_store[element.name] = false;
|
80
|
+
}
|
81
|
+
else if (element.checked) {
|
82
|
+
radio_store[element.name] = true;
|
83
|
+
}
|
84
|
+
}
|
85
|
+
|
86
|
+
// if options empty is true, continue only if its radio
|
87
|
+
if (!val && element.type == 'radio') {
|
88
|
+
continue;
|
89
|
+
}
|
90
|
+
}
|
91
|
+
else {
|
92
|
+
// value-less fields are ignored unless options.empty is true
|
93
|
+
if (!val) {
|
94
|
+
continue;
|
95
|
+
}
|
96
|
+
}
|
97
|
+
|
98
|
+
// multi select boxes
|
99
|
+
if (element.type === 'select-multiple') {
|
100
|
+
val = [];
|
101
|
+
|
102
|
+
var selectOptions = element.options;
|
103
|
+
var isSelectedOptions = false;
|
104
|
+
for (var j=0 ; j<selectOptions.length ; ++j) {
|
105
|
+
var option = selectOptions[j];
|
106
|
+
var allowedEmpty = options.empty && !option.value;
|
107
|
+
var hasValue = (option.value || allowedEmpty);
|
108
|
+
if (option.selected && hasValue) {
|
109
|
+
isSelectedOptions = true;
|
110
|
+
|
111
|
+
// If using a hash serializer be sure to add the
|
112
|
+
// correct notation for an array in the multi-select
|
113
|
+
// context. Here the name attribute on the select element
|
114
|
+
// might be missing the trailing bracket pair. Both names
|
115
|
+
// "foo" and "foo[]" should be arrays.
|
116
|
+
if (options.hash && key.slice(key.length - 2) !== '[]') {
|
117
|
+
result = serializer(result, key + '[]', option.value);
|
118
|
+
}
|
119
|
+
else {
|
120
|
+
result = serializer(result, key, option.value);
|
121
|
+
}
|
122
|
+
}
|
123
|
+
}
|
124
|
+
|
125
|
+
// Serialize if no selected options and options.empty is true
|
126
|
+
if (!isSelectedOptions && options.empty) {
|
127
|
+
result = serializer(result, key, '');
|
128
|
+
}
|
129
|
+
|
130
|
+
continue;
|
131
|
+
}
|
132
|
+
|
133
|
+
result = serializer(result, key, val);
|
134
|
+
}
|
135
|
+
|
136
|
+
// Check for all empty radio buttons and serialize them with key=""
|
137
|
+
if (options.empty) {
|
138
|
+
for (var key in radio_store) {
|
139
|
+
if (!radio_store[key]) {
|
140
|
+
result = serializer(result, key, '');
|
141
|
+
}
|
142
|
+
}
|
143
|
+
}
|
144
|
+
|
145
|
+
return result;
|
146
|
+
}
|
147
|
+
|
148
|
+
function parse_keys(string) {
|
149
|
+
var keys = [];
|
150
|
+
var prefix = /^([^\[\]]*)/;
|
151
|
+
var children = new RegExp(brackets);
|
152
|
+
var match = prefix.exec(string);
|
153
|
+
|
154
|
+
if (match[1]) {
|
155
|
+
keys.push(match[1]);
|
156
|
+
}
|
157
|
+
|
158
|
+
while ((match = children.exec(string)) !== null) {
|
159
|
+
keys.push(match[1]);
|
160
|
+
}
|
161
|
+
|
162
|
+
return keys;
|
163
|
+
}
|
164
|
+
|
165
|
+
function hash_assign(result, keys, value) {
|
166
|
+
if (keys.length === 0) {
|
167
|
+
result = value;
|
168
|
+
return result;
|
169
|
+
}
|
170
|
+
|
171
|
+
var key = keys.shift();
|
172
|
+
var between = key.match(/^\[(.+?)\]$/);
|
173
|
+
|
174
|
+
if (key === '[]') {
|
175
|
+
result = result || [];
|
176
|
+
|
177
|
+
if (Array.isArray(result)) {
|
178
|
+
result.push(hash_assign(null, keys, value));
|
179
|
+
}
|
180
|
+
else {
|
181
|
+
// This might be the result of bad name attributes like "[][foo]",
|
182
|
+
// in this case the original `result` object will already be
|
183
|
+
// assigned to an object literal. Rather than coerce the object to
|
184
|
+
// an array, or cause an exception the attribute "_values" is
|
185
|
+
// assigned as an array.
|
186
|
+
result._values = result._values || [];
|
187
|
+
result._values.push(hash_assign(null, keys, value));
|
188
|
+
}
|
189
|
+
|
190
|
+
return result;
|
191
|
+
}
|
192
|
+
|
193
|
+
// Key is an attribute name and can be assigned directly.
|
194
|
+
if (!between) {
|
195
|
+
result[key] = hash_assign(result[key], keys, value);
|
196
|
+
}
|
197
|
+
else {
|
198
|
+
var string = between[1];
|
199
|
+
// +var converts the variable into a number
|
200
|
+
// better than parseInt because it doesn't truncate away trailing
|
201
|
+
// letters and actually fails if whole thing is not a number
|
202
|
+
var index = +string;
|
203
|
+
|
204
|
+
// If the characters between the brackets is not a number it is an
|
205
|
+
// attribute name and can be assigned directly.
|
206
|
+
if (isNaN(index)) {
|
207
|
+
result = result || {};
|
208
|
+
result[string] = hash_assign(result[string], keys, value);
|
209
|
+
}
|
210
|
+
else {
|
211
|
+
result = result || [];
|
212
|
+
result[index] = hash_assign(result[index], keys, value);
|
213
|
+
}
|
214
|
+
}
|
215
|
+
|
216
|
+
return result;
|
217
|
+
}
|
218
|
+
|
219
|
+
// Object/hash encoding serializer.
|
220
|
+
function hash_serializer(result, key, value) {
|
221
|
+
var matches = key.match(brackets);
|
222
|
+
|
223
|
+
// Has brackets? Use the recursive assignment function to walk the keys,
|
224
|
+
// construct any missing objects in the result tree and make the assignment
|
225
|
+
// at the end of the chain.
|
226
|
+
if (matches) {
|
227
|
+
var keys = parse_keys(key);
|
228
|
+
hash_assign(result, keys, value);
|
229
|
+
}
|
230
|
+
else {
|
231
|
+
// Non bracket notation can make assignments directly.
|
232
|
+
var existing = result[key];
|
233
|
+
|
234
|
+
// If the value has been assigned already (for instance when a radio and
|
235
|
+
// a checkbox have the same name attribute) convert the previous value
|
236
|
+
// into an array before pushing into it.
|
237
|
+
//
|
238
|
+
// NOTE: If this requirement were removed all hash creation and
|
239
|
+
// assignment could go through `hash_assign`.
|
240
|
+
if (existing) {
|
241
|
+
if (!Array.isArray(existing)) {
|
242
|
+
result[key] = [ existing ];
|
243
|
+
}
|
244
|
+
|
245
|
+
result[key].push(value);
|
246
|
+
}
|
247
|
+
else {
|
248
|
+
result[key] = value;
|
249
|
+
}
|
250
|
+
}
|
251
|
+
|
252
|
+
return result;
|
253
|
+
}
|
254
|
+
|
255
|
+
// urlform encoding serializer
|
256
|
+
function str_serialize(result, key, value) {
|
257
|
+
// encode newlines as \r\n cause the html spec says so
|
258
|
+
value = value.replace(/(\r)?\n/g, '\r\n');
|
259
|
+
value = encodeURIComponent(value);
|
260
|
+
|
261
|
+
// spaces should be '+' rather than '%20'.
|
262
|
+
value = value.replace(/%20/g, '+');
|
263
|
+
return result + (result ? '&' : '') + encodeURIComponent(key) + '=' + value;
|
264
|
+
}
|
265
|
+
|
266
|
+
global.FormSerialize = serialize;
|
267
|
+
}(window))
|
@@ -0,0 +1,9 @@
|
|
1
|
+
/**
|
2
|
+
* @license
|
3
|
+
* lodash (Custom Build) /license | Underscore.js 1.8.3 underscorejs.org/LICENSE
|
4
|
+
* Build: `lodash include="debounce"`
|
5
|
+
*/
|
6
|
+
;(function(){function t(){}function e(t){var e=typeof t;return!!t&&("object"==e||"function"==e)}function o(t){return!!t&&typeof t=="object"}function n(t){return typeof t=="symbol"||o(t)&&"[object Symbol]"==d.call(t)}function i(t){if(typeof t=="number")return t;if(n(t))return r;if(e(t)&&(t=typeof t.valueOf=="function"?t.valueOf():t,t=e(t)?t+"":t),typeof t!="string")return 0===t?t:+t;t=t.replace(u,"");var o=c.test(t);return o||a.test(t)?l(t.slice(2),o?2:8):f.test(t)?r:+t}var r=NaN,u=/^\s+|\s+$/g,f=/^[-+]0x[0-9a-f]+$/i,c=/^0b[01]+$/i,a=/^0o[0-7]+$/i,l=parseInt,s=typeof self=="object"&&self&&self.Object===Object&&self,p=typeof global=="object"&&global&&global.Object===Object&&global||s||Function("return this")(),b=(s=typeof exports=="object"&&exports&&!exports.nodeType&&exports)&&typeof module=="object"&&module&&!module.nodeType&&module,d=Object.prototype.toString,y=Math.max,m=Math.min,v=function(){
|
7
|
+
return p.Date.now()};t.debounce=function(t,o,n){function r(e){var o=l,n=s;return l=s=void 0,g=e,b=t.apply(n,o)}function u(t){var e=t-j;return t-=g,void 0===j||e>=o||0>e||O&&t>=p}function f(){var t=v();if(u(t))return c(t);var e,n=setTimeout;e=t-g,t=o-(t-j),e=O?m(t,p-e):t,d=n(f,e)}function c(t){return d=void 0,T&&l?r(t):(l=s=void 0,b)}function a(){var t=v(),e=u(t);if(l=arguments,s=this,j=t,e){if(void 0===d)return g=t=j,d=setTimeout(f,o),x?r(t):b;if(O)return d=setTimeout(f,o),r(j)}return void 0===d&&(d=setTimeout(f,o)),
|
8
|
+
b}var l,s,p,b,d,j,g=0,x=false,O=false,T=true;if(typeof t!="function")throw new TypeError("Expected a function");return o=i(o)||0,e(n)&&(x=!!n.leading,p=(O="maxWait"in n)?y(i(n.maxWait)||0,o):p,T="trailing"in n?!!n.trailing:T),a.cancel=function(){void 0!==d&&clearTimeout(d),g=0,l=j=s=d=void 0},a.flush=function(){return void 0===d?b:c(v())},a},t.isObject=e,t.isObjectLike=o,t.isSymbol=n,t.now=v,t.toNumber=i,t.VERSION="4.15.0",typeof define=="function"&&typeof define.amd=="object"&&define.amd?(p._=t, define(function(){
|
9
|
+
return t})):b?((b.exports=t)._=t,s._=t):p._=t}).call(this);
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: active_versioning_workflow
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0
|
4
|
+
version: 1.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ryan Stenberg
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-10-
|
11
|
+
date: 2016-10-14 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: active_versioning
|
@@ -108,16 +108,23 @@ files:
|
|
108
108
|
- README.md
|
109
109
|
- Rakefile
|
110
110
|
- active_versioning_workflow.gemspec
|
111
|
+
- app/assets/javascripts/active_versioning/live-preview.js
|
111
112
|
- app/assets/javascripts/active_versioning/workflow.js
|
113
|
+
- app/assets/stylesheets/active_versioning/active-preview.scss
|
112
114
|
- app/assets/stylesheets/active_versioning/workflow.scss
|
115
|
+
- app/controllers/active_versioning/workflow/live_preview_controller.rb
|
116
|
+
- app/views/active_versioning/workflow/live_preview/show.html.erb
|
113
117
|
- bin/console
|
114
118
|
- bin/setup
|
115
119
|
- circle.yml
|
120
|
+
- config/routes.rb
|
116
121
|
- lib/active_versioning/workflow.rb
|
122
|
+
- lib/active_versioning/workflow/actions_with_preview.rb
|
117
123
|
- lib/active_versioning/workflow/controller.rb
|
118
124
|
- lib/active_versioning/workflow/draft_actions.rb
|
119
125
|
- lib/active_versioning/workflow/dsl.rb
|
120
126
|
- lib/active_versioning/workflow/engine.rb
|
127
|
+
- lib/active_versioning/workflow/preview_link.rb
|
121
128
|
- lib/active_versioning/workflow/previewable.rb
|
122
129
|
- lib/active_versioning/workflow/router.rb
|
123
130
|
- lib/active_versioning/workflow/show_resource.rb
|
@@ -129,6 +136,8 @@ files:
|
|
129
136
|
- lib/generators/active_versioning/templates/initializers/active_versioning_workflow.rb
|
130
137
|
- lib/generators/active_versioning/templates/locales/active_versioning.en.yml
|
131
138
|
- lib/generators/active_versioning/workflow_generator.rb
|
139
|
+
- vendor/assets/javascripts/active_versioning/form-serialize.js
|
140
|
+
- vendor/assets/javascripts/active_versioning/lodash.custom.js
|
132
141
|
homepage: https://github.com/vigetlabs/active_versioning_workflow
|
133
142
|
licenses:
|
134
143
|
- BSD
|