spontaneous 0.2.0.beta5 → 0.2.0.beta6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/CHANGELOG.md +39 -0
- data/Gemfile +2 -0
- data/Readme.markdown +4 -4
- data/application/css/core.css.scss +144 -43
- data/application/css/definitions.css.scss +50 -16
- data/application/css/dialogue.css.scss +5 -2
- data/application/css/editing.css.scss +7 -7
- data/application/css/font.css.scss +1 -1
- data/application/css/meta.css.scss +6 -6
- data/application/css/popover.css.scss +6 -6
- data/application/css/top.css.scss +8 -1
- data/application/js/add_alias_dialogue.js +137 -36
- data/application/js/add_home_dialogue.js +10 -10
- data/application/js/ajax.js +26 -26
- data/application/js/authentication.js +2 -2
- data/application/js/box.js +21 -10
- data/application/js/box_container.js +13 -7
- data/application/js/compatibility.js +19 -17
- data/application/js/conflicted_field_dialogue.js +5 -5
- data/application/js/content.js +22 -16
- data/application/js/content_area.js +62 -33
- data/application/js/dialogue.js +16 -16
- data/application/js/dom.js +9 -10
- data/application/js/edit_panel.js +25 -20
- data/application/js/editing.js +21 -8
- data/application/js/entry.js +1 -1
- data/application/js/extensions.js +11 -11
- data/application/js/field/boolean.js +6 -6
- data/application/js/field/date.js +1 -1
- data/application/js/field/file.js +17 -17
- data/application/js/field/image.js +27 -27
- data/application/js/field/markdown.js +72 -71
- data/application/js/field/select.js +9 -9
- data/application/js/field/string.js +3 -3
- data/application/js/field/webvideo.js +2 -2
- data/application/js/field_preview.js +3 -0
- data/application/js/init.js +3 -2
- data/application/js/jquery-selection-position.js +13 -13
- data/application/js/location.js +17 -12
- data/application/js/login.js +2 -2
- data/application/js/meta_view/user_admin.js +101 -101
- data/application/js/metadata.js +1 -1
- data/application/js/page.js +2 -2
- data/application/js/page_browser.js +13 -13
- data/application/js/page_entry.js +1 -1
- data/application/js/panel/root_menu.js +10 -10
- data/application/js/popover.js +6 -5
- data/application/js/popover_view.js +5 -5
- data/application/js/preview.js +10 -4
- data/application/js/progress.js +6 -6
- data/application/js/properties.js +35 -6
- data/application/js/publish.js +43 -43
- data/application/js/require.js +14 -14
- data/application/js/services.js +3 -3
- data/application/js/sharded_upload.js +9 -8
- data/application/js/side_bar.js +5 -5
- data/application/js/state.js +2 -2
- data/application/js/status_bar.js +6 -6
- data/application/js/top_bar.js +97 -65
- data/application/js/types.js +9 -6
- data/application/js/upload.js +4 -4
- data/application/js/upload_manager.js +21 -21
- data/application/js/user.js +1 -1
- data/application/js/vendor/jquery.velocity.min.js +7 -0
- data/application/js/views.js +32 -8
- data/application/js/views/box_view.js +51 -31
- data/application/js/views/page_piece_view.js +17 -15
- data/application/js/views/page_view.js +54 -43
- data/application/js/views/piece_view.js +44 -37
- data/application/static/font/fontawesome-webfont-4f0022f25672c7f501c339cbf98d9117.ttf +0 -0
- data/application/views/index.erb +1 -0
- data/db/migrations/20130114120000_create_revision_tables.rb +2 -1
- data/db/migrations/20130813111009_increase_path_length.rb +11 -2
- data/db/migrations/20140506171823_add_index_to_target_id.rb +11 -0
- data/db/migrations/20140514090204_add_content_hash.rb +59 -0
- data/db/migrations/20140519150253_add_content_hash_timestamp.rb +20 -0
- data/lib/spontaneous.rb +0 -1
- data/lib/spontaneous/asset/environment.rb +77 -15
- data/lib/spontaneous/box.rb +21 -0
- data/lib/spontaneous/capistrano/deploy.rb +1 -1
- data/lib/spontaneous/capistrano/sync.rb +8 -7
- data/lib/spontaneous/change.rb +4 -2
- data/lib/spontaneous/cli/fields.rb +7 -3
- data/lib/spontaneous/cli/generate.rb +2 -0
- data/lib/spontaneous/cli/init.rb +24 -93
- data/lib/spontaneous/cli/init/db.rb +94 -0
- data/lib/spontaneous/cli/init/mysql.rb +17 -0
- data/lib/spontaneous/cli/init/postgresql.rb +33 -0
- data/lib/spontaneous/cli/init/sqlite.rb +14 -0
- data/lib/spontaneous/cli/site.rb +45 -20
- data/lib/spontaneous/collections/box_set.rb +3 -0
- data/lib/spontaneous/collections/entry_set.rb +43 -4
- data/lib/spontaneous/collections/field_set.rb +14 -2
- data/lib/spontaneous/data_mapper.rb +40 -7
- data/lib/spontaneous/data_mapper/content_model.rb +1 -1
- data/lib/spontaneous/data_mapper/content_model/associations.rb +63 -12
- data/lib/spontaneous/data_mapper/content_model/timestamps.rb +9 -14
- data/lib/spontaneous/data_mapper/content_table.rb +4 -2
- data/lib/spontaneous/data_mapper/dataset.rb +31 -2
- data/lib/spontaneous/data_mapper/scope.rb +37 -20
- data/lib/spontaneous/errors.rb +6 -0
- data/lib/spontaneous/facet.rb +20 -10
- data/lib/spontaneous/field/base.rb +8 -1
- data/lib/spontaneous/field/file.rb +28 -3
- data/lib/spontaneous/field/image.rb +2 -0
- data/lib/spontaneous/field/update.rb +6 -0
- data/lib/spontaneous/field/webvideo/vimeo.rb +6 -1
- data/lib/spontaneous/field/webvideo/vine.rb +1 -1
- data/lib/spontaneous/field/webvideo/youtube.rb +1 -1
- data/lib/spontaneous/generators/site.rb +6 -4
- data/lib/spontaneous/generators/site/.gitignore +1 -0
- data/lib/spontaneous/generators/site/Gemfile.tt +3 -3
- data/lib/spontaneous/generators/site/config/{indexes.rb.tt → initializers/indexes.rb.tt} +0 -0
- data/lib/spontaneous/generators/site/config/initializers/publishing.rb.tt +78 -0
- data/lib/spontaneous/generators/site/{config/database.yml.tt → db/mysql2.yml.tt} +7 -6
- data/lib/spontaneous/generators/site/db/postgres.yml.tt +25 -0
- data/lib/spontaneous/generators/site/db/sqlite3.yml.tt +18 -0
- data/lib/spontaneous/generators/site/public/humans.txt.tt +14 -0
- data/lib/spontaneous/generators/site/templates/layouts/standard.html.cut.tt +51 -0
- data/lib/spontaneous/loader.rb +1 -1
- data/lib/spontaneous/logger.rb +1 -1
- data/lib/spontaneous/media/image/optimizer.rb +1 -1
- data/lib/spontaneous/media/image/processor.rb +11 -2
- data/lib/spontaneous/media/image/renderable.rb +2 -0
- data/lib/spontaneous/model.rb +3 -0
- data/lib/spontaneous/model/box/allowed_types.rb +17 -4
- data/lib/spontaneous/model/core.rb +36 -3
- data/lib/spontaneous/model/core/aliases.rb +5 -2
- data/lib/spontaneous/model/core/boxes.rb +6 -0
- data/lib/spontaneous/model/core/cascading_change.rb +38 -0
- data/lib/spontaneous/model/core/content_hash.rb +171 -0
- data/lib/spontaneous/model/core/entries.rb +0 -19
- data/lib/spontaneous/model/core/fields.rb +11 -0
- data/lib/spontaneous/model/core/modifications.rb +22 -21
- data/lib/spontaneous/model/core/render.rb +3 -0
- data/lib/spontaneous/model/core/serialisation.rb +18 -17
- data/lib/spontaneous/model/page.rb +35 -8
- data/lib/spontaneous/model/page/page_tree.rb +20 -8
- data/lib/spontaneous/model/page/paths.rb +79 -50
- data/lib/spontaneous/model/page/singleton.rb +71 -0
- data/lib/spontaneous/model/page/site_map.rb +2 -1
- data/lib/spontaneous/model/page/site_timestamps.rb +2 -2
- data/lib/spontaneous/model/piece.rb +10 -0
- data/lib/spontaneous/output/context.rb +13 -6
- data/lib/spontaneous/output/format.rb +30 -5
- data/lib/spontaneous/output/helpers/script_helper.rb +8 -0
- data/lib/spontaneous/output/helpers/stylesheet_helper.rb +7 -0
- data/lib/spontaneous/output/renderable.rb +16 -0
- data/lib/spontaneous/output/store.rb +1 -1
- data/lib/spontaneous/output/template/renderer.rb +2 -2
- data/lib/spontaneous/page_piece.rb +25 -1
- data/lib/spontaneous/prototypes/box_prototype.rb +13 -0
- data/lib/spontaneous/prototypes/field_prototype.rb +7 -4
- data/lib/spontaneous/publishing.rb +10 -5
- data/lib/spontaneous/publishing/immediate.rb +32 -349
- data/lib/spontaneous/publishing/pipeline.rb +43 -0
- data/lib/spontaneous/publishing/progress.rb +186 -0
- data/lib/spontaneous/publishing/publish.rb +107 -0
- data/lib/spontaneous/publishing/rerender.rb +17 -0
- data/lib/spontaneous/publishing/revision.rb +53 -18
- data/lib/spontaneous/publishing/simultaneous.rb +1 -1
- data/lib/spontaneous/publishing/steps.rb +154 -0
- data/lib/spontaneous/publishing/steps/activate_revision.rb +45 -0
- data/lib/spontaneous/publishing/steps/archive_old_revisions.rb +22 -0
- data/lib/spontaneous/publishing/steps/base_step.rb +49 -0
- data/lib/spontaneous/publishing/steps/copy_static_files.rb +74 -0
- data/lib/spontaneous/publishing/steps/create_revision_directory.rb +24 -0
- data/lib/spontaneous/publishing/steps/generate_rackup_file.rb +51 -0
- data/lib/spontaneous/publishing/steps/generate_search_indexes.rb +24 -0
- data/lib/spontaneous/publishing/steps/render_revision.rb +69 -0
- data/lib/spontaneous/publishing/steps/write_revision_file.rb +43 -0
- data/lib/spontaneous/rack/back.rb +3 -1
- data/lib/spontaneous/rack/back/alias.rb +9 -8
- data/lib/spontaneous/rack/front.rb +1 -1
- data/lib/spontaneous/rack/middleware.rb +7 -4
- data/lib/spontaneous/rack/middleware/transaction.rb +14 -0
- data/lib/spontaneous/rack/page_controller.rb +23 -8
- data/lib/spontaneous/revision.rb +5 -10
- data/lib/spontaneous/schema.rb +5 -0
- data/lib/spontaneous/server.rb +3 -1
- data/lib/spontaneous/site.rb +17 -10
- data/lib/spontaneous/site/publishing.rb +25 -3
- data/lib/spontaneous/site/state.rb +7 -3
- data/lib/spontaneous/tasks/database.rake +5 -10
- data/lib/spontaneous/utils/database/mysql_dumper.rb +5 -1
- data/lib/spontaneous/version.rb +1 -1
- data/spontaneous.gemspec +4 -3
- data/test/fixtures/example_application/config/initializers/initializer1.rb +1 -0
- data/test/fixtures/example_application/config/initializers/initializer2.rb +1 -0
- data/test/fixtures/example_application/config/initializers/publishing.rb +13 -0
- data/test/fixtures/search/config/{indexes.rb → initializers/indexes.rb} +0 -0
- data/test/fixtures/serialisation/root_hash.yaml.erb +10 -4
- data/test/functional/test_application.rb +10 -0
- data/test/functional/test_back.rb +23 -5
- data/test/functional/test_cli.rb +98 -34
- data/test/functional/test_front.rb +7 -3
- data/test/test_helper.rb +35 -28
- data/test/unit/test_alias.rb +20 -3
- data/test/unit/test_assets.rb +58 -30
- data/test/unit/test_changesets.rb +20 -12
- data/test/unit/test_content_hash.rb +496 -0
- data/test/unit/test_context.rb +28 -1
- data/test/unit/test_controllers.rb +96 -61
- data/test/unit/test_crypt.rb +1 -8
- data/test/unit/test_datamapper.rb +95 -19
- data/test/unit/test_features.rb +1 -4
- data/test/unit/test_fields.rb +61 -12
- data/test/unit/test_generators.rb +39 -2
- data/test/unit/test_images.rb +3 -1
- data/test/unit/test_modifications.rb +224 -219
- data/test/unit/test_output_store.rb +10 -0
- data/test/unit/{test_formats.rb → test_outputs.rb} +75 -6
- data/test/unit/test_page.rb +61 -15
- data/test/unit/test_plugins.rb +2 -42
- data/test/unit/test_publishing_pipeline.rb +1050 -0
- data/test/unit/test_render.rb +30 -0
- data/test/unit/test_revisions.rb +110 -2
- data/test/unit/test_schema.rb +4 -0
- data/test/unit/test_search.rb +1 -1
- data/test/unit/test_serialisation.rb +6 -1
- data/test/unit/test_singletons.rb +159 -0
- data/test/unit/test_site.rb +71 -44
- metadata +140 -86
- data/application/static/font/fontawesome-webfont-1c66a4738b40ef0f6b1abca0ba9a796d.ttf +0 -0
- data/test/unit/test_publishing.rb +0 -330
@@ -11,8 +11,8 @@ Spontaneous.Field.String = (function($, S) {
|
|
11
11
|
},
|
12
12
|
panel: function() {
|
13
13
|
var labels = dom.div('.string-field-conflict.labels.differences'), outer = dom.div(), diff_outer = dom.div('.string-field-conflict.changes.differences'), local_diff = dom.div('.original.diff'), computed_diff = dom.div('.final.diff');
|
14
|
-
var local_diff_label = dom.div('.diff').text(
|
15
|
-
var final_diff_label = dom.div('.diff').text(
|
14
|
+
var local_diff_label = dom.div('.diff').text('Changes made by other person');
|
15
|
+
var final_diff_label = dom.div('.diff').text('Their changes merged with yours');
|
16
16
|
var server_change = this.diff(this.values.local_original, this.values.server_original);
|
17
17
|
var local_change = this.diff(this.values.local_original, this.values.local_edited);
|
18
18
|
var merge = this.differ.patch_apply(local_change.patches, this.values.server_original);
|
@@ -129,7 +129,7 @@ Spontaneous.Field.String = (function($, S) {
|
|
129
129
|
return this.title;
|
130
130
|
},
|
131
131
|
generate_input: function() {
|
132
|
-
return dom.input(dom.id(this.css_id()), {'type':'text', 'name':this.form_name(), 'value':this.unprocessed_value()})
|
132
|
+
return dom.input(dom.id(this.css_id()), {'type':'text', 'name':this.form_name(), 'value':this.unprocessed_value()});
|
133
133
|
},
|
134
134
|
input: function() {
|
135
135
|
if (!this._input) {
|
@@ -16,11 +16,11 @@ Spontaneous.Field.WebVideo = (function($, S) {
|
|
16
16
|
// at the same time I want to replace an immediately inserted video player with an
|
17
17
|
// image + play button to reduce the impact of multiple videos on the cms ui load time
|
18
18
|
var value = this.get('value').replace(/autoplay=1/, '')
|
19
|
-
, iframe = dom.iframe({src:value, frameborder: 0, border: 0}).css({position:
|
19
|
+
, iframe = dom.iframe({src:value, frameborder: 0, border: 0}).css({position: 'absolute', top:0, left:0, height: '100%', width: '100%'});
|
20
20
|
if (!value) { // don't fill up the page with empty iframes...
|
21
21
|
return dom.div();
|
22
22
|
}
|
23
|
-
return dom.div().css({width:
|
23
|
+
return dom.div().css({width: '100%', position: 'relative', 'padding-bottom':'56.25%', height: 0}).append(iframe);
|
24
24
|
}
|
25
25
|
});
|
26
26
|
|
data/application/js/init.js
CHANGED
@@ -9,9 +9,10 @@ Spontaneous.Init = (function($, S) {
|
|
9
9
|
|
10
10
|
location.watch('location', top_bar.location_changed.bind(top_bar));
|
11
11
|
location.watch('location', content_area.location_changed.bind(content_area));
|
12
|
+
location.watch('loading_location', content_area.location_loading.bind(content_area));
|
12
13
|
|
13
|
-
top_bar.watch('mode',
|
14
|
-
top_bar.watch('mode',
|
14
|
+
top_bar.watch('mode', content_area.display.bind(content_area));
|
15
|
+
top_bar.watch('mode', location.view_mode_changed.bind(location));
|
15
16
|
|
16
17
|
S.Editing.watch('page', location.page_loaded.bind(location));
|
17
18
|
S.Editing.watch('path', location.path_changed.bind(location));
|
@@ -7,7 +7,7 @@
|
|
7
7
|
* @author Bevis Zhao (i@bevis.me, http://bevis.me)
|
8
8
|
*/
|
9
9
|
(function($) {
|
10
|
-
|
10
|
+
'use strict';
|
11
11
|
|
12
12
|
var calculator = {
|
13
13
|
// key styles
|
@@ -26,7 +26,7 @@ specificStyle: {
|
|
26
26
|
'overflow-y': 'auto'
|
27
27
|
},
|
28
28
|
|
29
|
-
simulator
|
29
|
+
simulator: $('<div id="textarea_simulator"/>').css({
|
30
30
|
position: 'absolute',
|
31
31
|
top: 0,
|
32
32
|
left: 0,
|
@@ -53,7 +53,7 @@ visibility: 'hidden'
|
|
53
53
|
selectStart = element.selectionStart,
|
54
54
|
selectEnd = element.selectionEnd;
|
55
55
|
|
56
|
-
if (selectEnd === selectStart) { return false; }
|
56
|
+
if (selectEnd === selectStart) { return false; }
|
57
57
|
|
58
58
|
var beforeText = value.substring(0, selectStart),
|
59
59
|
selectedText = value.substring(selectStart, selectEnd),
|
@@ -69,7 +69,7 @@ visibility: 'hidden'
|
|
69
69
|
|
70
70
|
return {
|
71
71
|
top: focusOffset.top - simulatorOffset.top - element.scrollTop,
|
72
|
-
left: focus[0].offsetLeft -
|
72
|
+
left: focus[0].offsetLeft - cal.simulator[0].offsetLeft - element.scrollLeft,
|
73
73
|
width: focus.width(),
|
74
74
|
height: focus.height()
|
75
75
|
};
|
@@ -87,22 +87,22 @@ var showPopup = function(textarea, popup, offsetCalculator) {
|
|
87
87
|
|
88
88
|
// In order to use the size of the popup in the positioning calculations
|
89
89
|
// it needs to be visible in the dom.
|
90
|
-
popup.css(
|
90
|
+
popup.css('visibility', 'hidden').show();
|
91
91
|
var place = offsetCalculator(pos);
|
92
|
-
popup.
|
92
|
+
popup.css({opacity: 0}).css('visibility', 'visible');
|
93
93
|
if (top >= position.top && top < bottom) {
|
94
94
|
popup.css({
|
95
95
|
left: place.left,
|
96
96
|
top: place.top
|
97
|
-
}).
|
97
|
+
}).velocity({opacity: 1}, {duration: 100});
|
98
98
|
} else {
|
99
|
-
popup.fadeOut
|
99
|
+
popup.velocity('fadeOut', 100);
|
100
100
|
}
|
101
101
|
return true;
|
102
|
-
}
|
102
|
+
};
|
103
103
|
$.fn.extend({
|
104
104
|
getComputedStyle: function(styleName) {
|
105
|
-
if (this.length
|
105
|
+
if (this.length === 0) { return; }
|
106
106
|
var self = this[0], result = this.css(styleName);
|
107
107
|
result = result || ($.browser.msie ? self.currentStyle[styleName]: document.defaultView.getComputedStyle(self, null)[styleName]);
|
108
108
|
return result;
|
@@ -118,11 +118,11 @@ showSelectionPopup: function(popup, offsetCalculator) {
|
|
118
118
|
var callback = function() {
|
119
119
|
var selected = showPopup(self, popup, offsetCalculator);
|
120
120
|
if (!selected) {
|
121
|
-
self.unbind(
|
121
|
+
self.unbind('scroll.popup').unbind('mouseup.popup');
|
122
122
|
}
|
123
123
|
};
|
124
|
-
self.bind(
|
125
|
-
self.bind(
|
124
|
+
self.bind('scroll.popup', callback);
|
125
|
+
self.bind('mouseup.popup', callback.delay(1));
|
126
126
|
callback();
|
127
127
|
}
|
128
128
|
});
|
data/application/js/location.js
CHANGED
@@ -19,8 +19,8 @@ Spontaneous.Location = (function($, S) {
|
|
19
19
|
},
|
20
20
|
restore: function() {
|
21
21
|
if (this.mode) {
|
22
|
-
Spontaneous.Location.view_mode_changed(this.mode)
|
23
|
-
Spontaneous.TopBar.set_mode(this.mode)
|
22
|
+
Spontaneous.Location.view_mode_changed(this.mode);
|
23
|
+
Spontaneous.TopBar.set_mode(this.mode);
|
24
24
|
}
|
25
25
|
if (this.page_id) {
|
26
26
|
Spontaneous.Location.load_id(this.page_id);
|
@@ -32,29 +32,29 @@ Spontaneous.Location = (function($, S) {
|
|
32
32
|
return '#/'+(this.page_id || '') + (this.mode ? ('@' + this.mode) : '');
|
33
33
|
},
|
34
34
|
to_path: function() {
|
35
|
-
return [ajax.namespace, (this.page_id || ''), this.mode].join(
|
35
|
+
return [ajax.namespace, (this.page_id || ''), this.mode].join('/');
|
36
36
|
},
|
37
37
|
to_obj: function() {
|
38
38
|
return {
|
39
39
|
page_id: this.page_id,
|
40
40
|
mode: this.mode
|
41
|
-
}
|
41
|
+
};
|
42
42
|
}
|
43
43
|
});
|
44
44
|
|
45
45
|
State.extend({
|
46
46
|
// currently just produces some kind of loop
|
47
47
|
popstate: function(event) {
|
48
|
-
State.restore(event)
|
48
|
+
State.restore(event);
|
49
49
|
return false;
|
50
50
|
},
|
51
51
|
restore: function(event) {
|
52
|
-
var state = new State(window.location.pathname)
|
52
|
+
var state = new State(window.location.pathname);
|
53
53
|
state.restore();
|
54
54
|
},
|
55
55
|
|
56
56
|
page: function(location, mode) {
|
57
|
-
var s = new State
|
57
|
+
var s = new State();
|
58
58
|
s.page_id = location.id;
|
59
59
|
s.mode = mode;
|
60
60
|
window.history.replaceState(s.to_obj(), ''+s.page_id, s.to_path());
|
@@ -94,6 +94,7 @@ Spontaneous.Location = (function($, S) {
|
|
94
94
|
this.set('path', location.path);
|
95
95
|
this.update_state(location, this.get('view_mode'));
|
96
96
|
}
|
97
|
+
this.set('loading_location', null);
|
97
98
|
},
|
98
99
|
update_state: function(location, mode) {
|
99
100
|
State.page(location, mode);
|
@@ -112,14 +113,14 @@ Spontaneous.Location = (function($, S) {
|
|
112
113
|
},
|
113
114
|
url: function() {
|
114
115
|
var l = this.location();
|
115
|
-
return (l ? l.url :
|
116
|
+
return (l ? l.url : '/about');
|
116
117
|
},
|
117
118
|
location: function() {
|
118
119
|
return this.get('location');
|
119
120
|
},
|
120
121
|
update: function(location) {
|
121
122
|
this.set('location', location);
|
122
|
-
this.path_from_url(location.url)
|
123
|
+
this.path_from_url(location.url);
|
123
124
|
},
|
124
125
|
current_path: function() {
|
125
126
|
return this.path_from_url(this.url());
|
@@ -128,13 +129,13 @@ Spontaneous.Location = (function($, S) {
|
|
128
129
|
if (this.location() && path === this.location().path) {
|
129
130
|
return this.location();
|
130
131
|
}
|
131
|
-
this.
|
132
|
+
this.retrieve_with_progress('/map/path'+path, this.location_loaded.bind(this));
|
132
133
|
},
|
133
134
|
find_id: function(id) {
|
134
135
|
if (this.location() && id === this.location().id) {
|
135
136
|
return this.location();
|
136
137
|
}
|
137
|
-
this.
|
138
|
+
this.retrieve_with_progress('/map/'+id, this.location_loaded.bind(this));
|
138
139
|
},
|
139
140
|
path_from_url: function(url) {
|
140
141
|
var map = this.get('map'),
|
@@ -142,7 +143,7 @@ Spontaneous.Location = (function($, S) {
|
|
142
143
|
path = [], i, ii,
|
143
144
|
parts = url.split('/').slice(1), position = 0;
|
144
145
|
// add root to path
|
145
|
-
path.push({selected:0, pages:[
|
146
|
+
path.push({selected:0, pages:[map], root:true});
|
146
147
|
while (position < parts.length) {
|
147
148
|
for (i = 0, ii = children.length; i < ii; i++) {
|
148
149
|
var child = children[i], slug = child.url.split('/').slice(-1)[0];
|
@@ -156,6 +157,10 @@ Spontaneous.Location = (function($, S) {
|
|
156
157
|
}
|
157
158
|
return path;
|
158
159
|
},
|
160
|
+
retrieve_with_progress: function(url, callback) {
|
161
|
+
this.set('loading_location', url);
|
162
|
+
return this.retrieve(url, callback);
|
163
|
+
},
|
159
164
|
retrieve: function(url, callback) {
|
160
165
|
ajax.get(url, {}, callback, {ifModified: true, cache: true});
|
161
166
|
},
|
data/application/js/login.js
CHANGED
@@ -31,7 +31,7 @@
|
|
31
31
|
var $this = $(this);
|
32
32
|
$.ajax({
|
33
33
|
url: $this.attr('action'),
|
34
|
-
type:
|
34
|
+
type: 'POST',
|
35
35
|
data:$this.serialize(),
|
36
36
|
success: function(data) {
|
37
37
|
if (data.key) {
|
@@ -44,7 +44,7 @@
|
|
44
44
|
$('#failed-name').text($('#user-login').val());
|
45
45
|
$(this).fadeIn();
|
46
46
|
});
|
47
|
-
$(
|
47
|
+
$('#error-message:hidden').slideDown(200);
|
48
48
|
},
|
49
49
|
dataType: 'json'
|
50
50
|
});
|
@@ -27,10 +27,10 @@ Spontaneous.MetaView.UserAdmin = (function($, S){
|
|
27
27
|
var levels = this.levels;
|
28
28
|
var nonePosition = function() {
|
29
29
|
for (var i = 0, ii = levels.length; i < ii; i++) {
|
30
|
-
if (levels[i].levelName() ===
|
30
|
+
if (levels[i].levelName() === 'none') {
|
31
31
|
return i;
|
32
32
|
}
|
33
|
-
}
|
33
|
+
}
|
34
34
|
}();
|
35
35
|
return levels[nonePosition + 1];
|
36
36
|
};
|
@@ -43,17 +43,17 @@ Spontaneous.MetaView.UserAdmin = (function($, S){
|
|
43
43
|
element: function(cancelCallback) {
|
44
44
|
var self = this;
|
45
45
|
var levels = Level.levels;
|
46
|
-
var currentLevel = Level.get(this.user.get(
|
47
|
-
var outer = dom.div(
|
48
|
-
var input = dom.input({type:
|
49
|
-
var select = dom.div(
|
50
|
-
var value = dom.div(
|
46
|
+
var currentLevel = Level.get(this.user.get('level')) || Level.defaultLevel();
|
47
|
+
var outer = dom.div('.level-select');
|
48
|
+
var input = dom.input({type: 'hidden', name: Input.inputName(this.name), value: currentLevel.levelName()});
|
49
|
+
var select = dom.div('.select').hide();
|
50
|
+
var value = dom.div('.level-value').text(currentLevel.title());
|
51
51
|
levels.forEach(function(level) {
|
52
|
-
var row = dom.div(
|
53
|
-
row.append(dom.span(
|
54
|
-
row.append(dom.span(
|
55
|
-
row.append(dom.span(
|
56
|
-
row.data(
|
52
|
+
var row = dom.div('.level').addClass('level-' + level.levelName());
|
53
|
+
row.append(dom.span('.level-name').text(level.title()));
|
54
|
+
row.append(dom.span('.level-publish').text('Publish').addClass(''+level.canPublish()));
|
55
|
+
row.append(dom.span('.level-admin').text('Admin').addClass(''+level.isAdmin()));
|
56
|
+
row.data('level', level);
|
57
57
|
row.click(function() {
|
58
58
|
self.choose(level);
|
59
59
|
return false;
|
@@ -75,12 +75,12 @@ Spontaneous.MetaView.UserAdmin = (function($, S){
|
|
75
75
|
var pulldown = this.pulldown;
|
76
76
|
pulldown.fadeIn(100);
|
77
77
|
var level = this.currentLevel();
|
78
|
-
var options = pulldown.find(
|
78
|
+
var options = pulldown.find('.level');
|
79
79
|
var levelDiv = options.filter(function(div) {
|
80
|
-
return $(this).data(
|
80
|
+
return $(this).data('level').levelName() == level.levelName();
|
81
81
|
})[0];
|
82
82
|
var pos = $(levelDiv).position();
|
83
|
-
pulldown.css(
|
83
|
+
pulldown.css('top', dom.px(-pos.top));
|
84
84
|
},
|
85
85
|
|
86
86
|
choose: function(level) {
|
@@ -89,7 +89,7 @@ Spontaneous.MetaView.UserAdmin = (function($, S){
|
|
89
89
|
|
90
90
|
this.close();
|
91
91
|
},
|
92
|
-
close: function(
|
92
|
+
close: function() {
|
93
93
|
this.pulldown.fadeOut(100);
|
94
94
|
},
|
95
95
|
activate: function() {
|
@@ -113,21 +113,21 @@ Spontaneous.MetaView.UserAdmin = (function($, S){
|
|
113
113
|
this.value = value;
|
114
114
|
},
|
115
115
|
element: function(cancelCallback) {
|
116
|
-
var type = (this.name ===
|
116
|
+
var type = (this.name === 'email' ? 'email' : 'text');
|
117
117
|
var input = dom.input({
|
118
118
|
name: this.inputName(),
|
119
119
|
value: this.value,
|
120
120
|
type: type
|
121
121
|
}).focus(function() {
|
122
|
-
$(this).parents(
|
122
|
+
$(this).parents('p').addClass('focus');
|
123
123
|
}).blur(function() {
|
124
|
-
$(this).parents(
|
124
|
+
$(this).parents('p').removeClass('focus');
|
125
125
|
}).keydown(function(event) {
|
126
126
|
if (event.keyCode === 27) { cancelCallback(); }
|
127
127
|
});
|
128
128
|
// TODO: catch RETURN and ESCAPE
|
129
129
|
return input;
|
130
|
-
}.cache(
|
130
|
+
}.cache('input'),
|
131
131
|
inputName: function() { return Input.inputName(this.name); },
|
132
132
|
isModified: function() {
|
133
133
|
// TODO: compare current value of input against original value
|
@@ -136,12 +136,12 @@ Spontaneous.MetaView.UserAdmin = (function($, S){
|
|
136
136
|
showError: function(errors) {
|
137
137
|
var error = errors[0]
|
138
138
|
, element = this.element()
|
139
|
-
, errorWrap = dom.div(
|
139
|
+
, errorWrap = dom.div('.error').append(dom.span().text(error)).hide();
|
140
140
|
element.after(errorWrap);
|
141
141
|
errorWrap.fadeIn(300);
|
142
142
|
},
|
143
143
|
hideError: function() {
|
144
|
-
var error = this.element().next(
|
144
|
+
var error = this.element().next('.error');
|
145
145
|
error.fadeOut(100, function() {
|
146
146
|
error.remove();
|
147
147
|
});
|
@@ -149,71 +149,71 @@ Spontaneous.MetaView.UserAdmin = (function($, S){
|
|
149
149
|
});
|
150
150
|
|
151
151
|
Input.inputName = function(name) {
|
152
|
-
return
|
152
|
+
return 'user[' + name + ']';
|
153
153
|
};
|
154
154
|
|
155
155
|
var responseCallback = function(complete, successCallback, failCallback) {
|
156
|
-
var isFunction = function(f) { return (typeof f ===
|
156
|
+
var isFunction = function(f) { return (typeof f === 'function'); };
|
157
157
|
return function(result, status) {
|
158
|
-
if (status ===
|
158
|
+
if (status === 'success') {
|
159
159
|
if (isFunction(complete)) { complete(result); }
|
160
160
|
if (isFunction(successCallback)) { successCallback(result); }
|
161
161
|
} else {
|
162
162
|
if (isFunction(failCallback)) { failCallback(result); }
|
163
163
|
}
|
164
|
-
}
|
164
|
+
};
|
165
165
|
};
|
166
166
|
|
167
167
|
var UserController = {
|
168
|
-
save:
|
169
|
-
var url = [
|
168
|
+
save: function(user, params, successCallback, failCallback) {
|
169
|
+
var url = ['/users', user.get('id')].join('/');
|
170
170
|
ajax.put(url, params, responseCallback(function(result) {
|
171
171
|
user.update(result);
|
172
172
|
}, successCallback, failCallback));
|
173
173
|
},
|
174
174
|
create: function(user, params, successCallback, failCallback) {
|
175
|
-
var url =
|
175
|
+
var url = '/users';
|
176
176
|
ajax.post(url, params, responseCallback(function(result) {
|
177
177
|
user.update(result);
|
178
178
|
}, successCallback, failCallback));
|
179
179
|
},
|
180
180
|
delete: function(user, successCallback, failCallback) {
|
181
|
-
var url = [
|
181
|
+
var url = ['/users', user.get('id')].join('/');
|
182
182
|
ajax.del(url, {}, responseCallback(function(result) {
|
183
183
|
|
184
184
|
}, successCallback, failCallback));
|
185
185
|
},
|
186
186
|
enable: function(user, enabled, successCallback, failCallback) {
|
187
|
-
var action = (enabled ?
|
188
|
-
, url = [
|
187
|
+
var action = (enabled ? 'enable' : 'disable')
|
188
|
+
, url = ['/users', action, user.get('id')].join('/');
|
189
189
|
ajax.put(url, {}, responseCallback(function(result) {
|
190
|
-
user.set(
|
190
|
+
user.set('disabled', !enabled);
|
191
191
|
}, successCallback, failCallback));
|
192
192
|
},
|
193
193
|
logout: function(user, successCallback, failCallback) {
|
194
|
-
var url = [
|
194
|
+
var url = ['/users', 'keys', user.get('id')].join('/');
|
195
195
|
ajax.del(url, {}, responseCallback(function(result) {
|
196
196
|
|
197
197
|
},successCallback, failCallback));
|
198
|
-
}
|
198
|
+
}
|
199
199
|
};
|
200
200
|
|
201
201
|
var EditUserView = new JS.Class({
|
202
202
|
initialize: function(parent, user) {
|
203
203
|
this.parent = parent;
|
204
|
-
this.user
|
204
|
+
this.user = user;
|
205
205
|
},
|
206
206
|
titleText: function() {
|
207
|
-
return
|
207
|
+
return 'Editing User “' + this.user.get('name') + '”';
|
208
208
|
},
|
209
209
|
view: function() {
|
210
210
|
var self = this;
|
211
211
|
var user = this.user;
|
212
212
|
var wrap = dom.div();
|
213
|
-
var form = dom.form({method:
|
213
|
+
var form = dom.form({method: 'post', action: ajax.request_url('/users/'+ user.get('id'))});
|
214
214
|
var inputs = {};
|
215
215
|
var p, label, input, value;
|
216
|
-
var titleBar = dom.div(
|
216
|
+
var titleBar = dom.div('.title').append(dom.span().text(this.titleText()));
|
217
217
|
|
218
218
|
form.append(self.aboveUserAttributes());
|
219
219
|
|
@@ -221,10 +221,10 @@ Spontaneous.MetaView.UserAdmin = (function($, S){
|
|
221
221
|
self.parent.closeUser();
|
222
222
|
};
|
223
223
|
self.editableAttributes().forEach(function(name) {
|
224
|
-
p = dom.p()
|
224
|
+
p = dom.p();
|
225
225
|
label = dom.label().text(name);
|
226
226
|
input = self.inputForAttribute(name);
|
227
|
-
value = dom.div(
|
227
|
+
value = dom.div('.value').append(input.element(cancel));
|
228
228
|
p.append(label, value);
|
229
229
|
form.append(p);
|
230
230
|
inputs[name] = input;
|
@@ -241,14 +241,14 @@ Spontaneous.MetaView.UserAdmin = (function($, S){
|
|
241
241
|
self.save(form, saveComplete, saveFail);
|
242
242
|
return false;
|
243
243
|
};
|
244
|
-
var cancelBtn = dom.a(
|
245
|
-
var saveBtn = dom.button(
|
246
|
-
p.append(cancelBtn, dom.div(
|
244
|
+
var cancelBtn = dom.a('.button.cancel').text('Cancel').click(cancel);
|
245
|
+
var saveBtn = dom.button('.button', {type: 'submit'}).text(self.saveButtonText()).click(performSave);
|
246
|
+
p.append(cancelBtn, dom.div('.gap'), saveBtn);
|
247
247
|
form.append(p);
|
248
248
|
form.submit(performSave);
|
249
249
|
this.inputs = inputs;
|
250
250
|
form.find('input[type="text"]:first').focus().select();
|
251
|
-
wrap.append(titleBar, form)
|
251
|
+
wrap.append(titleBar, form);
|
252
252
|
return wrap;
|
253
253
|
},
|
254
254
|
verificationErrors: function(errors) {
|
@@ -258,42 +258,42 @@ Spontaneous.MetaView.UserAdmin = (function($, S){
|
|
258
258
|
});
|
259
259
|
},
|
260
260
|
saveButtonText: function() {
|
261
|
-
return
|
261
|
+
return 'Save';
|
262
262
|
},
|
263
263
|
inputForAttribute: function(name) {
|
264
|
-
if (name ===
|
264
|
+
if (name === 'level') {
|
265
265
|
return new LevelSelect(name, this.user);
|
266
266
|
}
|
267
267
|
return new Input(name, this.user.get(name));
|
268
268
|
},
|
269
269
|
editableAttributes: function() {
|
270
|
-
return [
|
270
|
+
return ['login', 'name', 'email', 'level'];
|
271
271
|
},
|
272
272
|
aboveUserAttributes: function() {
|
273
273
|
var self = this;
|
274
|
-
var user = this.user
|
275
|
-
var admin = dom.div(
|
276
|
-
p = dom.p(
|
277
|
-
label = dom.label().text(
|
278
|
-
var checkbox = dom.input({type:
|
279
|
-
var enabled = $(this).attr(
|
274
|
+
var user = this.user;
|
275
|
+
var admin = dom.div('.admin');
|
276
|
+
p = dom.p('.enabled');
|
277
|
+
label = dom.label().text('Enabled');
|
278
|
+
var checkbox = dom.input({type:'checkbox', checked: (!user.get('disabled'))}).click(function() {
|
279
|
+
var enabled = $(this).attr('checked') === 'checked';
|
280
280
|
UserController.enable(user, enabled);
|
281
281
|
return false;
|
282
282
|
});
|
283
|
-
user.watch(
|
284
|
-
checkbox.attr(
|
283
|
+
user.watch('disabled', function(disabled) {
|
284
|
+
checkbox.attr('checked', !disabled);
|
285
285
|
});
|
286
286
|
label.append(checkbox);
|
287
287
|
p.append(label);
|
288
288
|
admin.append(p);
|
289
289
|
|
290
|
-
admin.append(dom.p(
|
291
|
-
p = dom.p(
|
292
|
-
var btn = dom.a(
|
290
|
+
admin.append(dom.p('.gap'));
|
291
|
+
p = dom.p('.log-off');
|
292
|
+
var btn = dom.a('.button.log-out').text('Log '+user.get('login')+' Out').click(function() {
|
293
293
|
var $this = $(this);
|
294
|
-
$this.addClass(
|
294
|
+
$this.addClass('pending');
|
295
295
|
UserController.logout(user, function() {
|
296
|
-
$this.removeClass(
|
296
|
+
$this.removeClass('pending').addClass('complete').text('Logged Out');
|
297
297
|
});
|
298
298
|
});
|
299
299
|
p.append(btn);
|
@@ -324,32 +324,32 @@ Spontaneous.MetaView.UserAdmin = (function($, S){
|
|
324
324
|
},
|
325
325
|
save: function(form, successCallback, failCallback) {
|
326
326
|
var self = this
|
327
|
-
|
327
|
+
, params = self.serialiseForm(form);
|
328
328
|
UserController.save(self.user, params, successCallback, failCallback);
|
329
329
|
}
|
330
330
|
});
|
331
331
|
|
332
332
|
var CreateUserView = new JS.Class(EditUserView, {
|
333
333
|
titleText: function() {
|
334
|
-
return
|
334
|
+
return 'Create User';
|
335
335
|
},
|
336
336
|
aboveUserAttributes: function() {
|
337
|
-
return
|
337
|
+
return '';
|
338
338
|
},
|
339
339
|
belowUserAttributes: function() {
|
340
|
-
return
|
340
|
+
return '';
|
341
341
|
},
|
342
342
|
editableAttributes: function() {
|
343
|
-
return [
|
343
|
+
return ['login', 'name', 'email', 'password', 'level'];
|
344
344
|
},
|
345
345
|
saveButtonText: function() {
|
346
|
-
return
|
346
|
+
return 'Create';
|
347
347
|
},
|
348
348
|
save: function(form, successCallback, failCallback) {
|
349
349
|
var self = this
|
350
|
-
|
350
|
+
, params = self.serialiseForm(form)
|
351
351
|
, callback = function(params) {
|
352
|
-
if (typeof successCallback ===
|
352
|
+
if (typeof successCallback === 'function') {
|
353
353
|
successCallback(params);
|
354
354
|
}
|
355
355
|
self.parent.addUser(self.user);
|
@@ -371,7 +371,7 @@ Spontaneous.MetaView.UserAdmin = (function($, S){
|
|
371
371
|
$.each(attributes, function(key, val) {
|
372
372
|
self.set(key, val);
|
373
373
|
});
|
374
|
-
}
|
374
|
+
}
|
375
375
|
});
|
376
376
|
|
377
377
|
var UserAdmin = new JS.Class({
|
@@ -385,15 +385,15 @@ Spontaneous.MetaView.UserAdmin = (function($, S){
|
|
385
385
|
return;
|
386
386
|
}
|
387
387
|
var self = this;
|
388
|
-
var outer = dom.div(
|
389
|
-
var title = dom.div(
|
390
|
-
var contents = dom.div(
|
391
|
-
var edit = dom.div(
|
392
|
-
var done = dom.a(
|
388
|
+
var outer = dom.div('#user-admin-container');
|
389
|
+
var title = dom.div('.title.main').append(dom.span().text('CMS Users'));
|
390
|
+
var contents = dom.div('.contents');
|
391
|
+
var edit = dom.div('.edit').hide();
|
392
|
+
var done = dom.a('.button.done').text('Done').click(function() {
|
393
393
|
self.close();
|
394
394
|
});
|
395
|
-
var addWrapper = dom.div(
|
396
|
-
var addButton
|
395
|
+
var addWrapper = dom.div('.add-user');
|
396
|
+
var addButton = dom.a('.button.add').text('Create User').click(function() {
|
397
397
|
self.createUser();
|
398
398
|
});
|
399
399
|
addWrapper.append(addButton);
|
@@ -404,8 +404,8 @@ Spontaneous.MetaView.UserAdmin = (function($, S){
|
|
404
404
|
this.titleContainer = title;
|
405
405
|
this.contentsContainer = contents;
|
406
406
|
this.editContainer = edit;
|
407
|
-
container.append(outer)
|
408
|
-
ajax.get(
|
407
|
+
container.append(outer);
|
408
|
+
ajax.get('/users', this.ready.bind(this));
|
409
409
|
},
|
410
410
|
createUser: function() {
|
411
411
|
var user = new User(this, {});
|
@@ -434,11 +434,11 @@ Spontaneous.MetaView.UserAdmin = (function($, S){
|
|
434
434
|
},
|
435
435
|
listEntry: function(user) {
|
436
436
|
var self = this;
|
437
|
-
var row = dom.div(
|
438
|
-
row.attr(
|
439
|
-
var cells = [
|
437
|
+
var row = dom.div('.user');
|
438
|
+
row.attr('id', 'user-admin-' + user.get('id'));
|
439
|
+
var cells = ['name', 'level'].map(function(attr) {
|
440
440
|
var div = dom.div().addClass(attr).text(user.get(attr)).click(function() {
|
441
|
-
self.editUser(user)
|
441
|
+
self.editUser(user);
|
442
442
|
return false;
|
443
443
|
});
|
444
444
|
user.watch(attr, function(newValue) {
|
@@ -448,19 +448,19 @@ Spontaneous.MetaView.UserAdmin = (function($, S){
|
|
448
448
|
});
|
449
449
|
var disabledState = function(disabled) {
|
450
450
|
if (disabled) {
|
451
|
-
row.addClass(
|
451
|
+
row.addClass('disabled');
|
452
452
|
} else {
|
453
|
-
row.removeClass(
|
453
|
+
row.removeClass('disabled');
|
454
454
|
}
|
455
455
|
};
|
456
|
-
user.watch(
|
457
|
-
disabledState(user.get(
|
458
|
-
var del = dom.div(
|
456
|
+
user.watch('disabled', disabledState);
|
457
|
+
disabledState(user.get('disabled'));
|
458
|
+
var del = dom.div('.delete').click(function() {
|
459
459
|
self.confirmDeleteUser(user);
|
460
460
|
return false;
|
461
461
|
});
|
462
462
|
cells.push(del);
|
463
|
-
row.append.apply(row, cells)
|
463
|
+
row.append.apply(row, cells);
|
464
464
|
return row;
|
465
465
|
},
|
466
466
|
animationDuration: 300,
|
@@ -472,19 +472,19 @@ Spontaneous.MetaView.UserAdmin = (function($, S){
|
|
472
472
|
var animationDuration = self.animationDuration;
|
473
473
|
var edit = this.editContainer.empty();
|
474
474
|
var list = this.contentsContainer;
|
475
|
-
var back = dom.div(
|
475
|
+
var back = dom.div('.back');
|
476
476
|
edit.append(back, viewInstance.view());
|
477
|
-
edit.css({ left:
|
478
|
-
list.
|
479
|
-
edit.
|
477
|
+
edit.css({ left: '100%', opacity: 0 }).show();
|
478
|
+
list.velocity({ opacity: 0.2 }, animationDuration);
|
479
|
+
edit.velocity({ left: '48px', opacity: 1 }, animationDuration, 'swing');
|
480
480
|
viewInstance.activate();
|
481
481
|
},
|
482
482
|
closeUser: function() {
|
483
483
|
var animationDuration = this.animationDuration;
|
484
484
|
var edit = this.editContainer.empty();
|
485
485
|
var list = this.contentsContainer;
|
486
|
-
list.
|
487
|
-
edit.
|
486
|
+
list.velocity({ opacity: 1 }, animationDuration);
|
487
|
+
edit.velocity({ left: '100%', opacity: 0 }, animationDuration, function() {
|
488
488
|
edit.empty().hide();
|
489
489
|
});
|
490
490
|
},
|
@@ -492,9 +492,9 @@ Spontaneous.MetaView.UserAdmin = (function($, S){
|
|
492
492
|
var dialogue = Spontaneous.Popover.open(event, new ConfirmDeletePopup(this, user));
|
493
493
|
},
|
494
494
|
deleteUser: function(user) {
|
495
|
-
var url = [
|
495
|
+
var url = ['/users', user.get('id')].join('/');
|
496
496
|
ajax.del(url, {}, function(result, status) {
|
497
|
-
if (status ===
|
497
|
+
if (status === 'success') {
|
498
498
|
user.listEntry.disappear();
|
499
499
|
}
|
500
500
|
});
|
@@ -513,7 +513,7 @@ Spontaneous.MetaView.UserAdmin = (function($, S){
|
|
513
513
|
// return 208;
|
514
514
|
// },
|
515
515
|
title: function() {
|
516
|
-
return
|
516
|
+
return 'Delete user “' + (this.user.get('login')) + '”';
|
517
517
|
},
|
518
518
|
position_from_event: function(target) {
|
519
519
|
var pos = this.position_from_element(target);
|
@@ -527,13 +527,13 @@ Spontaneous.MetaView.UserAdmin = (function($, S){
|
|
527
527
|
return false;
|
528
528
|
});
|
529
529
|
|
530
|
-
var ok = dom.a('.ok').text(
|
530
|
+
var ok = dom.a('.ok').text('Delete').click(function() {
|
531
531
|
self.close();
|
532
532
|
__entry.deleteUser(self.user);
|
533
533
|
return false;
|
534
534
|
});
|
535
|
-
var cancel = dom.a('.cancel').text(
|
536
|
-
w.append(cancel, ok)
|
535
|
+
var cancel = dom.a('.cancel').text('Cancel');
|
536
|
+
w.append(cancel, ok);
|
537
537
|
return w;
|
538
538
|
}
|
539
539
|
});
|