spontaneous 0.2.0.beta1 → 0.2.0.beta2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +24 -0
- data/.locat +42 -0
- data/.travis/gemfiles/Gemfile.empty +7 -0
- data/.travis.yml +18 -0
- data/Gemfile +12 -8
- data/LICENSE +1 -1
- data/Rakefile +15 -157
- data/Readme.markdown +1 -1
- data/application/css/core.css.scss +22 -146
- data/application/css/definitions.css.scss +7 -3
- data/application/css/dialogue.css.scss +26 -1
- data/application/css/editing.css.scss +70 -28
- data/application/css/font.css.scss +1 -1
- data/application/css/popover.css.scss +2 -0
- data/application/css/top.css.scss +231 -0
- data/application/js/add_alias_dialogue.js +1 -1
- data/application/js/add_home_dialogue.js +1 -1
- data/application/js/ajax.js +61 -31
- data/application/js/box.js +4 -4
- data/application/js/conflicted_field_dialogue.js +1 -1
- data/application/js/content.js +5 -5
- data/application/js/dom.js +5 -0
- data/application/js/edit_panel.js +1 -0
- data/application/js/editing.js +1 -1
- data/application/js/extensions.js +8 -0
- data/application/js/field/boolean.js +31 -0
- data/application/js/field/file.js +32 -4
- data/application/js/field/image.js +24 -9
- data/application/js/field/markdown.js +87 -59
- data/application/js/field/select.js +1 -1
- data/application/js/field/webvideo.js +6 -1
- data/application/js/init.js +2 -2
- data/application/js/jquery-selection-position.js +130 -0
- data/application/js/location.js +4 -25
- data/application/js/meta_view/user_admin.js +2 -2
- data/application/js/metadata.js +2 -2
- data/application/js/page_browser.js +1 -1
- data/application/js/panel/root_menu.js +0 -1
- data/application/js/popover.js +27 -12
- data/application/js/popover_view.js +20 -4
- data/application/js/preview.js +31 -16
- data/application/js/progress.js +22 -21
- data/application/js/publish.js +18 -7
- data/application/js/sharded_upload.js +9 -6
- data/application/js/spontaneous.js +3 -1
- data/application/js/top_bar.js +264 -173
- data/application/js/upload.js +12 -5
- data/application/js/upload_manager.js +4 -3
- data/application/js/user.js +1 -2
- data/application/js/views/box_view.js +1 -1
- data/application/js/views/page_view.js +16 -5
- data/application/js/views/piece_view.js +5 -4
- data/application/static/font/fontawesome-webfont-1c66a4738b40ef0f6b1abca0ba9a796d.ttf +0 -0
- data/application/views/index.erb +6 -14
- data/application/views/login.erb +6 -25
- data/application/views/schema_modification_error.html.erb +3 -7
- data/db/migrations/20130114120000_create_revision_tables.rb +2 -2
- data/db/migrations/20130813111009_increase_path_length.rb +14 -0
- data/gem-public_cert.pem +20 -0
- data/lib/spontaneous/asset/app_compiler.rb +44 -0
- data/lib/spontaneous/asset/environment.rb +225 -0
- data/lib/spontaneous/asset.rb +2 -67
- data/lib/spontaneous/box.rb +0 -1
- data/lib/spontaneous/capistrano/deploy.rb +2 -2
- data/lib/spontaneous/capistrano/sync.rb +1 -1
- data/lib/spontaneous/cli/init.rb +36 -13
- data/lib/spontaneous/cli/server.rb +0 -1
- data/lib/spontaneous/cli/site.rb +2 -1
- data/lib/spontaneous/cli.rb +3 -1
- data/lib/spontaneous/collections/entry_set.rb +4 -12
- data/lib/spontaneous/collections/hash_with_fallback.rb +20 -0
- data/lib/spontaneous/collections/prototype_set.rb +6 -5
- data/lib/spontaneous/crypt.rb +2 -2
- data/lib/spontaneous/data_mapper/content_model/associations.rb +115 -63
- data/lib/spontaneous/data_mapper.rb +1 -1
- data/lib/spontaneous/errors.rb +6 -0
- data/lib/spontaneous/extensions/object_space.rb +6 -0
- data/lib/spontaneous/facet.rb +1 -0
- data/lib/spontaneous/field/base.rb +86 -13
- data/lib/spontaneous/field/boolean.rb +65 -0
- data/lib/spontaneous/field/file.rb +17 -6
- data/lib/spontaneous/field/html.rb +13 -0
- data/lib/spontaneous/field/image/size.rb +76 -0
- data/lib/spontaneous/field/image.rb +99 -414
- data/lib/spontaneous/field/tags.rb +36 -0
- data/lib/spontaneous/field/update.rb +1 -1
- data/lib/spontaneous/field/webvideo/fallback.rb +41 -0
- data/lib/spontaneous/field/webvideo/vimeo.rb +113 -0
- data/lib/spontaneous/field/webvideo/vine.rb +94 -0
- data/lib/spontaneous/field/webvideo/youtube.rb +133 -0
- data/lib/spontaneous/field/webvideo.rb +100 -250
- data/lib/spontaneous/field.rb +1 -1
- data/lib/spontaneous/generators/site/Gemfile.tt +5 -14
- data/lib/spontaneous/generators/site/assets/README.md +20 -0
- data/lib/spontaneous/generators/site/assets/css/site.scss +8 -0
- data/lib/spontaneous/generators/site/assets/js/site.js +6 -0
- data/lib/spontaneous/generators/site/config/deploy.rb.tt +9 -0
- data/lib/spontaneous/generators/site/config/user_levels.yml +14 -3
- data/lib/spontaneous/generators/site/public/README.md +12 -0
- data/lib/spontaneous/generators/site/templates/layouts/standard.html.cut.tt +2 -2
- data/lib/spontaneous/generators/site.rb +77 -35
- data/lib/spontaneous/layout.rb +6 -7
- data/lib/spontaneous/loader.rb +21 -13
- data/lib/spontaneous/media/file.rb +22 -9
- data/lib/spontaneous/media/image/attributes.rb +33 -0
- data/lib/spontaneous/media/image/format/gif.rb +4 -0
- data/lib/spontaneous/media/image/format/jpg.rb +17 -0
- data/lib/spontaneous/media/image/format/png.rb +4 -0
- data/lib/spontaneous/media/image/format/webp.rb +26 -0
- data/lib/spontaneous/media/image/format.rb +79 -0
- data/lib/spontaneous/media/image/optimizer.rb +69 -0
- data/lib/spontaneous/media/image/processor.rb +17 -0
- data/lib/spontaneous/media/image/renderable.rb +52 -0
- data/lib/spontaneous/media/image/skeptick.rb +70 -0
- data/lib/spontaneous/media/image.rb +50 -0
- data/lib/spontaneous/media/temp_file.rb +4 -0
- data/lib/spontaneous/media.rb +1 -0
- data/lib/spontaneous/model/core/aliases.rb +14 -8
- data/lib/spontaneous/model/core/boxes.rb +5 -2
- data/lib/spontaneous/model/core/entries.rb +4 -0
- data/lib/spontaneous/model/core/entry.rb +1 -0
- data/lib/spontaneous/model/core/fields.rb +5 -2
- data/lib/spontaneous/model/core/locks.rb +16 -0
- data/lib/spontaneous/model/core/media.rb +1 -15
- data/lib/spontaneous/model/core.rb +31 -1
- data/lib/spontaneous/model/page/controllers.rb +2 -2
- data/lib/spontaneous/model/page/formats.rb +1 -4
- data/lib/spontaneous/model/page/layouts.rb +6 -2
- data/lib/spontaneous/model/page/locks.rb +8 -2
- data/lib/spontaneous/model/page/page_tree.rb +2 -2
- data/lib/spontaneous/model/page/paths.rb +74 -9
- data/lib/spontaneous/model/page.rb +11 -3
- data/lib/spontaneous/model.rb +6 -6
- data/lib/spontaneous/output/context/render_cache.rb +23 -0
- data/lib/spontaneous/output/context.rb +56 -30
- data/lib/spontaneous/output/helpers/script_helper.rb +9 -53
- data/lib/spontaneous/output/helpers/stylesheet_helper.rb +8 -40
- data/lib/spontaneous/output/template/renderer.rb +17 -5
- data/lib/spontaneous/output.rb +0 -1
- data/lib/spontaneous/paths.rb +6 -2
- data/lib/spontaneous/permissions/access_key.rb +18 -0
- data/lib/spontaneous/permissions/user.rb +1 -1
- data/lib/spontaneous/permissions.rb +4 -1
- data/lib/spontaneous/plugins/application/state.rb +19 -12
- data/lib/spontaneous/prototypes/field_prototype.rb +14 -8
- data/lib/spontaneous/published_revision.rb +7 -0
- data/lib/spontaneous/publishing/immediate.rb +43 -34
- data/lib/spontaneous/publishing/revision.rb +9 -6
- data/lib/spontaneous/rack/asset_server.rb +20 -0
- data/lib/spontaneous/rack/back/alias.rb +46 -0
- data/lib/spontaneous/rack/back/application_assets.rb +28 -0
- data/lib/spontaneous/rack/back/base.rb +34 -0
- data/lib/spontaneous/rack/back/changes.rb +19 -0
- data/lib/spontaneous/rack/back/content.rb +54 -0
- data/lib/spontaneous/rack/back/events.rb +38 -0
- data/lib/spontaneous/rack/back/field.rb +37 -0
- data/lib/spontaneous/rack/back/file.rb +118 -0
- data/lib/spontaneous/rack/back/helpers.rb +71 -0
- data/lib/spontaneous/rack/back/index.rb +16 -0
- data/lib/spontaneous/rack/back/login.rb +47 -0
- data/lib/spontaneous/rack/back/map.rb +24 -0
- data/lib/spontaneous/rack/back/page.rb +46 -0
- data/lib/spontaneous/rack/back/preview.rb +43 -0
- data/lib/spontaneous/rack/back/schema.rb +30 -0
- data/lib/spontaneous/rack/back/site.rb +25 -0
- data/lib/spontaneous/rack/back/site_assets.rb +13 -0
- data/lib/spontaneous/rack/back/unsupported_browser.rb +7 -0
- data/lib/spontaneous/rack/{user_admin.rb → back/user_admin.rb} +2 -5
- data/lib/spontaneous/rack/back.rb +85 -764
- data/lib/spontaneous/rack/cacheable_file.rb +3 -3
- data/lib/spontaneous/rack/front.rb +16 -9
- data/lib/spontaneous/rack/middleware/authenticate.rb +65 -0
- data/lib/spontaneous/rack/middleware/csrf.rb +66 -0
- data/lib/spontaneous/rack/middleware/reloader.rb +52 -0
- data/lib/spontaneous/rack/middleware/scope.rb +60 -0
- data/lib/spontaneous/rack/middleware.rb +6 -0
- data/lib/spontaneous/rack/page_controller.rb +18 -5
- data/lib/spontaneous/rack/public.rb +17 -11
- data/lib/spontaneous/rack.rb +34 -24
- data/lib/spontaneous/revision.rb +29 -2
- data/lib/spontaneous/schema/uid.rb +4 -3
- data/lib/spontaneous/schema/uid_map.rb +5 -24
- data/lib/spontaneous/schema.rb +1 -0
- data/lib/spontaneous/search/database.rb +8 -0
- data/lib/spontaneous/search/field.rb +1 -1
- data/lib/spontaneous/search/index.rb +3 -5
- data/lib/spontaneous/server.rb +1 -1
- data/lib/spontaneous/simultaneous.rb +1 -1
- data/lib/spontaneous/site/features.rb +4 -5
- data/lib/spontaneous/site/helpers.rb +22 -5
- data/lib/spontaneous/site/instance.rb +2 -2
- data/lib/spontaneous/site/selectors.rb +22 -3
- data/lib/spontaneous/storage/cloud.rb +13 -9
- data/lib/spontaneous/storage/local.rb +11 -6
- data/lib/spontaneous/style.rb +40 -23
- data/lib/spontaneous/utils/database/mysql_dumper.rb +1 -1
- data/lib/spontaneous/utils/smush_it.rb +1 -1
- data/lib/spontaneous/version.rb +1 -1
- data/lib/spontaneous.rb +35 -33
- data/spontaneous.gemspec +53 -787
- data/test/experimental/test_crypt.rb +56 -56
- data/test/experimental/test_features.rb +16 -27
- data/test/fixtures/assets/public1/css/data.css.scss +3 -0
- data/test/fixtures/assets/public1/css/image1.css.scss +4 -0
- data/test/fixtures/assets/public1/css/import.css.scss +1 -0
- data/test/fixtures/assets/public1/css/urlhash.css.scss +3 -0
- data/test/fixtures/assets/public1/js/a.js +1 -1
- data/test/fixtures/assets/public1/js/all.js +4 -0
- data/test/fixtures/assets/public1/js/{m.coffee → m.js.coffee} +1 -0
- data/test/fixtures/assets/public1/x.js +1 -0
- data/test/fixtures/assets/public2/css/all.css +4 -0
- data/test/fixtures/assets/public2/css/missing.css.scss +3 -0
- data/test/fixtures/assets/public2/i/y.png +0 -0
- data/test/fixtures/assets/public2/js/b.js +1 -1
- data/test/fixtures/assets/public2/js/c.js +1 -1
- data/test/fixtures/images/size.extended.webp +0 -0
- data/test/fixtures/images/size.lossless.webp +0 -0
- data/test/fixtures/images/size.lossy.webp +0 -0
- data/test/fixtures/schema/before.yml +4 -4
- data/test/fixtures/schema/schema.yml +1 -1
- data/test/fixtures/templates/aliases/aaa.html.cut +0 -0
- data/test/fixtures/templates/extended/partial_with_renderer.html.cut +1 -0
- data/test/fixtures/templates/extended/with_includes_and_renderer.html.cut +2 -0
- data/test/functional/test_application.rb +108 -106
- data/test/functional/test_back.rb +924 -930
- data/test/functional/test_front.rb +285 -238
- data/test/functional/test_user_manager.rb +75 -100
- data/test/integration/test_installation.rb +1 -1
- data/test/support/matchers.rb +12 -0
- data/test/support/minitest.rb +121 -0
- data/test/support/rack.rb +45 -0
- data/test/support/test_start_finish.rb +103 -0
- data/test/test_helper.rb +21 -68
- data/test/test_integration_helper.rb +1 -3
- data/test/unit/test_alias.rb +432 -408
- data/test/unit/test_asset_bundler.rb +58 -58
- data/test/unit/test_assets.rb +485 -155
- data/test/unit/test_async.rb +16 -37
- data/test/unit/test_authentication.rb +425 -457
- data/test/unit/test_boxes.rb +191 -191
- data/test/unit/test_changesets.rb +244 -254
- data/test/unit/test_config.rb +128 -142
- data/test/unit/test_content.rb +313 -359
- data/test/unit/test_content_inheritance.rb +29 -30
- data/test/unit/test_datamapper.rb +1205 -1080
- data/test/unit/test_datamapper_content.rb +49 -51
- data/test/unit/test_extensions.rb +23 -23
- data/test/unit/test_fields.rb +1488 -1180
- data/test/unit/test_formats.rb +158 -158
- data/test/unit/test_generators.rb +98 -40
- data/test/unit/test_helpers.rb +73 -76
- data/test/unit/test_image_size.rb +53 -22
- data/test/unit/test_images.rb +164 -165
- data/test/unit/test_layouts.rb +133 -122
- data/test/unit/test_logger.rb +14 -17
- data/test/unit/test_media.rb +69 -84
- data/test/unit/test_modifications.rb +513 -525
- data/test/unit/test_page.rb +462 -361
- data/test/unit/test_permissions.rb +379 -364
- data/test/unit/test_piece.rb +67 -75
- data/test/unit/test_plugins.rb +82 -89
- data/test/unit/test_prototype_set.rb +215 -216
- data/test/unit/test_prototypes.rb +114 -124
- data/test/unit/test_publishing.rb +252 -289
- data/test/unit/test_render.rb +167 -115
- data/test/unit/test_revisions.rb +436 -444
- data/test/unit/test_schema.rb +339 -309
- data/test/unit/test_search.rb +577 -574
- data/test/unit/test_serialisation.rb +136 -147
- data/test/unit/test_site.rb +252 -227
- data/test/unit/test_skeptick.rb +130 -0
- data/test/unit/test_storage.rb +46 -40
- data/test/unit/test_structure.rb +57 -66
- data/test/unit/test_styles.rb +104 -104
- data/test/unit/test_templates.rb +72 -57
- data/test/unit/test_type_hierarchy.rb +15 -16
- data/test/unit/test_visibility.rb +239 -257
- metadata +455 -326
- data/application/js/vendor/JS.Class-2.1.5/CHANGELOG +0 -283
- data/application/js/vendor/JS.Class-2.1.5/MIT-LICENSE +0 -30
- data/application/js/vendor/JS.Class-2.1.5/README +0 -30
- data/application/js/vendor/JS.Class-2.1.5/min/command.js +0 -1
- data/application/js/vendor/JS.Class-2.1.5/min/comparable.js +0 -1
- data/application/js/vendor/JS.Class-2.1.5/min/constant_scope.js +0 -1
- data/application/js/vendor/JS.Class-2.1.5/min/decorator.js +0 -1
- data/application/js/vendor/JS.Class-2.1.5/min/enumerable.js +0 -1
- data/application/js/vendor/JS.Class-2.1.5/min/forwardable.js +0 -1
- data/application/js/vendor/JS.Class-2.1.5/min/hash.js +0 -1
- data/application/js/vendor/JS.Class-2.1.5/min/linked_list.js +0 -1
- data/application/js/vendor/JS.Class-2.1.5/min/loader.js +0 -1
- data/application/js/vendor/JS.Class-2.1.5/min/method_chain.js +0 -1
- data/application/js/vendor/JS.Class-2.1.5/min/observable.js +0 -1
- data/application/js/vendor/JS.Class-2.1.5/min/package.js +0 -1
- data/application/js/vendor/JS.Class-2.1.5/min/proxy.js +0 -1
- data/application/js/vendor/JS.Class-2.1.5/min/ruby.js +0 -1
- data/application/js/vendor/JS.Class-2.1.5/min/set.js +0 -1
- data/application/js/vendor/JS.Class-2.1.5/min/stack_trace.js +0 -1
- data/application/js/vendor/JS.Class-2.1.5/min/state.js +0 -1
- data/application/js/vendor/JS.Class-2.1.5/min/stdlib.js +0 -16
- data/application/js/vendor/jquery-1.6.2.min.js +0 -18
- data/application/js/vendor/jquery-ui-1.8.16.custom.min.js +0 -791
- data/application/js/vendor/jquery-ui-1.8.9.custom.min.js +0 -415
- data/application/static/font/fontawesome-webfont-5c5c21100a346972a82c34c5e96ffcfe.ttf +0 -0
- data/application/static/select-arrow-6e7dd3745b00e934b0d7a3250c46558b.png +0 -0
- data/bin/limit-upload +0 -5
- data/bin/unlimit-upload +0 -3
- data/lib/spontaneous/asset/file.rb +0 -25
- data/lib/spontaneous/asset/source.rb +0 -28
- data/lib/spontaneous/image_size.rb +0 -123
- data/lib/spontaneous/output/assets/compression.rb +0 -58
- data/lib/spontaneous/output/assets.rb +0 -32
- data/lib/spontaneous/rack/around_back.rb +0 -20
- data/lib/spontaneous/rack/around_front.rb +0 -27
- data/lib/spontaneous/rack/around_preview.rb +0 -22
- data/lib/spontaneous/rack/assets.rb +0 -126
- data/lib/spontaneous/rack/authentication.rb +0 -20
- data/lib/spontaneous/rack/cookie_authentication.rb +0 -38
- data/lib/spontaneous/rack/helpers.rb +0 -52
- data/lib/spontaneous/rack/http.rb +0 -18
- data/lib/spontaneous/rack/media.rb +0 -30
- data/lib/spontaneous/rack/query_authentication.rb +0 -35
- data/lib/spontaneous/rack/reloader.rb +0 -45
- data/lib/spontaneous/rack/user_helpers.rb +0 -28
- /data/{README → application/js/field/markdown/text_command.js} +0 -0
- /data/application/js/vendor/{JS.Class-2.1.5/min/core.js → js.class-2.1.5.min.js} +0 -0
- /data/test/fixtures/assets/public1/css/{a.scss → a.css.scss} +0 -0
- /data/{lib/spontaneous/generators/site/public/css/site.scss → test/fixtures/assets/public1/x.css} +0 -0
- /data/{lib/spontaneous/generators/site/public/js/.empty_directory → test/fixtures/assets/public1/x.png} +0 -0
- /data/test/fixtures/assets/public2/css/{b.scss → b.css.scss} +0 -0
- /data/test/fixtures/assets/public2/js/{n.coffee → n.js.coffee} +0 -0
- /data/test/fixtures/back/{public → assets}/css/sass_include.scss +0 -0
- /data/test/fixtures/back/{public → assets}/css/sass_template.scss +0 -0
- /data/test/fixtures/back/{public → assets}/js/coffeescript.coffee +0 -0
- /data/{lib/spontaneous/generators/site/public/js/site.js → test/fixtures/templates/aliases/aa_alias.html.cut} +0 -0
@@ -0,0 +1,31 @@
|
|
1
|
+
Spontaneous.Field.Boolean = (function($, S) {
|
2
|
+
var dom = S.Dom;
|
3
|
+
var BooleanField = new JS.Class(Spontaneous.Field.String, {
|
4
|
+
edit: function() {
|
5
|
+
var self = this
|
6
|
+
, w = dom.div(dom.id(self.css_id()))
|
7
|
+
, input = self.input() // ensure we have created the radio inputs $on & $off
|
8
|
+
, labels = self.type.labels
|
9
|
+
, label = function(label, radio) { return dom.label().text(label).prepend(radio); }
|
10
|
+
;
|
11
|
+
w.append(label(labels['true'], self.$on), label(labels['false'], self.$off));
|
12
|
+
return w;
|
13
|
+
},
|
14
|
+
generate_input: function() {
|
15
|
+
var self = this
|
16
|
+
, checked = (this.get('unprocessed_value') == 'true')
|
17
|
+
, click = function() { self.editor.field_focus(self.input()); }
|
18
|
+
, on = dom.radio({'name':this.form_name(), 'value': 'true', 'checked': checked})
|
19
|
+
, off = dom.radio({'name':this.form_name(), 'value': 'false', 'checked': !checked})
|
20
|
+
;
|
21
|
+
self.$on = on;
|
22
|
+
self.$off = off;
|
23
|
+
return $(on).add(off).click(click);
|
24
|
+
},
|
25
|
+
edited_value: function() {
|
26
|
+
return this.input().filter(':checked').val();
|
27
|
+
}
|
28
|
+
});
|
29
|
+
return BooleanField;
|
30
|
+
})(jQuery, Spontaneous);
|
31
|
+
|
@@ -4,11 +4,40 @@ Spontaneous.Field.File = (function($, S) {
|
|
4
4
|
var FileField = new JS.Class(Spontaneous.Field.String, {
|
5
5
|
selected_files: false,
|
6
6
|
|
7
|
+
currentValue: function() {
|
8
|
+
var pending, v = this.get('value');
|
9
|
+
if ((pending = v['__pending__'])) {
|
10
|
+
return pending['value'];
|
11
|
+
}
|
12
|
+
return v;
|
13
|
+
},
|
14
|
+
|
15
|
+
currentFilename: function() {
|
16
|
+
return this.currentValue()['filename'];
|
17
|
+
},
|
18
|
+
|
19
|
+
currentFilesize: function() {
|
20
|
+
return this.currentValue()['filesize'];
|
21
|
+
},
|
22
|
+
|
23
|
+
currentEditValue: function() {
|
24
|
+
var value, pending, ui, v = this.get('value');
|
25
|
+
if ((pending = v['__pending__'])) {
|
26
|
+
return pending['value'];
|
27
|
+
}
|
28
|
+
value = v['original'];
|
29
|
+
if ((ui = v['__ui__'])) {
|
30
|
+
value['path'] = value['src'];
|
31
|
+
value['src'] = ui['src'];
|
32
|
+
}
|
33
|
+
return value;
|
34
|
+
},
|
35
|
+
|
7
36
|
preview: function() {
|
8
37
|
Spontaneous.UploadManager.register(this);
|
9
38
|
var self = this
|
10
|
-
, value = this.
|
11
|
-
, filename = this.
|
39
|
+
, value = this.currentValue()
|
40
|
+
, filename = this.currentFilename();
|
12
41
|
var wrap = dom.div('.file-field');
|
13
42
|
var dropper = dom.div('.file-drop');
|
14
43
|
|
@@ -61,7 +90,7 @@ Spontaneous.Field.File = (function($, S) {
|
|
61
90
|
}
|
62
91
|
};
|
63
92
|
if (value) {
|
64
|
-
set_info(value.html, this.
|
93
|
+
set_info(value.html, this.currentFilename(), this.currentFilesize());
|
65
94
|
}
|
66
95
|
|
67
96
|
dropper.append(this.progress_bar().parent());
|
@@ -237,7 +266,6 @@ Spontaneous.Field.File = (function($, S) {
|
|
237
266
|
this.processed_value();
|
238
267
|
},
|
239
268
|
set_edited_value: function(value) {
|
240
|
-
console.log('set_edited_value', value, this.edited_value(), this.original_value())
|
241
269
|
if (value === this.edited_value()) {
|
242
270
|
// do nothing
|
243
271
|
} else {
|
@@ -1,5 +1,6 @@
|
|
1
1
|
// console.log('Loading ImageField...')
|
2
2
|
Spontaneous.Field.Image = (function($, S) {
|
3
|
+
"use strict";
|
3
4
|
var dom = S.Dom;
|
4
5
|
var ImageFieldConflictView = new JS.Class(S.Field.String.ConflictView, {
|
5
6
|
|
@@ -58,13 +59,31 @@ Spontaneous.Field.Image = (function($, S) {
|
|
58
59
|
},
|
59
60
|
|
60
61
|
currentValue: function() {
|
61
|
-
var v = this.get('value');
|
62
|
+
var pending, v = this.get('value');
|
62
63
|
if ((pending = v['__pending__'])) {
|
64
|
+
pending['path'] = pending['src'];
|
63
65
|
return pending['value'];
|
64
66
|
}
|
65
67
|
return v['__ui__'] || v['original'];
|
66
68
|
},
|
67
69
|
|
70
|
+
currentEditValue: function() {
|
71
|
+
var value, pending, ui, v = this.get('value');
|
72
|
+
if ((pending = v['__pending__'])) {
|
73
|
+
return pending['value'];
|
74
|
+
}
|
75
|
+
value = v['original'];
|
76
|
+
if ((ui = v['__ui__'])) {
|
77
|
+
value['path'] = value['src'];
|
78
|
+
value['src'] = ui['src'];
|
79
|
+
}
|
80
|
+
return value;
|
81
|
+
},
|
82
|
+
|
83
|
+
currentFilename: function() {
|
84
|
+
var v = this.currentValue();
|
85
|
+
return v['filename'];
|
86
|
+
},
|
68
87
|
/*
|
69
88
|
* HACK: The async nature of image updates means that the version setting
|
70
89
|
* may be out of date not because of the actions of another, but because
|
@@ -80,7 +99,7 @@ Spontaneous.Field.Image = (function($, S) {
|
|
80
99
|
* weird problems with simultaneous updates.
|
81
100
|
*/
|
82
101
|
version: function() {
|
83
|
-
var value = this.get("value");
|
102
|
+
var pending, value = this.get("value");
|
84
103
|
if ((pending = value["__pending__"])) {
|
85
104
|
return pending["version"];
|
86
105
|
}
|
@@ -245,7 +264,7 @@ Spontaneous.Field.Image = (function($, S) {
|
|
245
264
|
},
|
246
265
|
edit: function() {
|
247
266
|
var wrap = dom.div({'style':'position:relative;'}),
|
248
|
-
value = this.
|
267
|
+
value = this.currentEditValue(),
|
249
268
|
src = value.src,
|
250
269
|
img = dom.img({'src':src}),
|
251
270
|
info, sizes, filename_info, filesize_info, dimensions_info;
|
@@ -350,8 +369,8 @@ Spontaneous.Field.Image = (function($, S) {
|
|
350
369
|
wrap.append(img, actions, info);
|
351
370
|
|
352
371
|
if (value) {
|
353
|
-
var s = value.
|
354
|
-
set_info(
|
372
|
+
// var s = value.path.split('/'), filename = s[s.length - 1];
|
373
|
+
set_info(this.currentFilename(), value.filesize, value.width, value.height);
|
355
374
|
}
|
356
375
|
this.preview_img = img;
|
357
376
|
return wrap;
|
@@ -370,10 +389,6 @@ Spontaneous.Field.Image = (function($, S) {
|
|
370
389
|
this.input = this.generate_input();
|
371
390
|
return this.input;
|
372
391
|
},
|
373
|
-
|
374
|
-
edited_value: function() {
|
375
|
-
return this.input.val();
|
376
|
-
},
|
377
392
|
cancel_edit: function() {
|
378
393
|
this.image.attr('src', this.currentValue().src);
|
379
394
|
},
|
@@ -447,7 +447,8 @@ Spontaneous.Field.Markdown = (function($, S) {
|
|
447
447
|
},
|
448
448
|
page_selected: function(page) {
|
449
449
|
this.url_input.val(page.path);
|
450
|
-
}
|
450
|
+
},
|
451
|
+
scroll: true
|
451
452
|
});
|
452
453
|
|
453
454
|
var PageSelector = new JS.Class({
|
@@ -502,38 +503,25 @@ Spontaneous.Field.Markdown = (function($, S) {
|
|
502
503
|
state = this.fix_selection_whitespace(state)
|
503
504
|
var selected = state.selection, m, n, start = state.start, end = state.end;
|
504
505
|
|
505
|
-
|
506
|
-
|
507
|
-
|
508
|
-
|
509
|
-
|
510
|
-
|
511
|
-
|
512
|
-
|
513
|
-
|
514
|
-
|
515
|
-
|
516
|
-
|
517
|
-
|
518
|
-
|
519
|
-
if (
|
520
|
-
|
521
|
-
|
522
|
-
|
523
|
-
selected
|
524
|
-
end += n[1].length;
|
525
|
-
selected += n[1];
|
526
|
-
}
|
527
|
-
}
|
528
|
-
// finally check for being exactly between the two
|
529
|
-
m = /(\[.+?\])$/.exec(state.before);
|
530
|
-
if (m) {
|
531
|
-
n = /^(\(.+?\))/.exec(state.after);
|
532
|
-
if (n) {
|
533
|
-
start -= m[1].length;
|
534
|
-
selected += m[1];
|
535
|
-
end += n[1].length;
|
536
|
-
selected += n[1];
|
506
|
+
var linkExp = /(\[[^\]]*?\]\([^\ ]*?\))/g;
|
507
|
+
var text = this.input.val(), cursor = start, match = 0;
|
508
|
+
// First look at all the text before and move the cursor past any links.
|
509
|
+
// This stops us expanding backwards to grab any link found in the text before
|
510
|
+
// the selection start.
|
511
|
+
do {
|
512
|
+
if ((m = linkExp.exec(state.before))) { match = linkExp.lastIndex; }
|
513
|
+
} while (m && (linkExp.lastIndex < cursor));
|
514
|
+
|
515
|
+
// now we've established where the last whole link lives, and can stop ourselves
|
516
|
+
// including it in the search, we can look backwards
|
517
|
+
// until we find the start of any link that's around the current selection.
|
518
|
+
while ((cursor >= match) && (text[cursor] !== "[")) { cursor--; }
|
519
|
+
|
520
|
+
if (text[cursor] === "[") {
|
521
|
+
if (m = linkExp.exec(text.substr(cursor))) {
|
522
|
+
start = cursor;
|
523
|
+
end = cursor + m[1].length;
|
524
|
+
selected = m[1];
|
537
525
|
}
|
538
526
|
}
|
539
527
|
return {selection:selected, start:start, end:end};
|
@@ -637,45 +625,86 @@ Spontaneous.Field.Markdown = (function($, S) {
|
|
637
625
|
this.callSuper();
|
638
626
|
},
|
639
627
|
toolbar: function() {
|
640
|
-
|
641
|
-
|
642
|
-
|
643
|
-
|
644
|
-
|
645
|
-
|
646
|
-
|
628
|
+
var self = this;
|
629
|
+
if (!self._toolbar) {
|
630
|
+
self._wrapper = dom.div([dom.id('editor-'+self.css_id()), '.markdown-editor']);
|
631
|
+
self._wrapper.append(self.popupToolbar());
|
632
|
+
}
|
633
|
+
return self._wrapper;
|
634
|
+
},
|
635
|
+
popupToolbar: function() {
|
636
|
+
var self = this;
|
637
|
+
if (!self._popupToolbar) {
|
638
|
+
var toolbar = dom.div('.md-toolbar');
|
639
|
+
var arrow = dom.div(".arrow");
|
640
|
+
toolbar.append(arrow);
|
641
|
+
self.commands = [];
|
642
|
+
var input = self.input();
|
643
|
+
for (var i = 0, c = self.actions, ii = c.length; i < ii; i++) {
|
647
644
|
var cmd_class = c[i], cmd = new cmd_class(input);
|
648
|
-
|
649
|
-
|
645
|
+
self.commands.push(cmd);
|
646
|
+
toolbar.append(cmd.button());
|
650
647
|
}
|
651
|
-
|
652
|
-
|
648
|
+
toolbar.hide();
|
649
|
+
self._popupToolbar = toolbar;
|
653
650
|
}
|
654
|
-
return
|
651
|
+
return self._popupToolbar;
|
655
652
|
},
|
656
653
|
edit: function() {
|
657
|
-
this
|
658
|
-
|
659
|
-
|
660
|
-
input.
|
661
|
-
input.bind('
|
662
|
-
input.bind('
|
654
|
+
var self = this, input = self.input();
|
655
|
+
self.expanded = false;
|
656
|
+
// clear previously assigned bindings
|
657
|
+
input.unbind('select.markdown');
|
658
|
+
input.bind('select.markdown', self.on_select.bind(self))
|
659
|
+
// input.bind('click.markdown', self.on_select.bind(self))
|
660
|
+
// input.bind('keyup.markdown', self.on_select.bind(self))
|
663
661
|
return input;
|
664
662
|
},
|
665
663
|
close_edit: function() {
|
666
|
-
|
667
|
-
|
668
|
-
|
669
|
-
|
670
|
-
|
664
|
+
var self = this;
|
665
|
+
self._input = null;
|
666
|
+
self._toolbar = null;
|
667
|
+
self._popupToolbar = null;
|
668
|
+
self.commands = [];
|
669
|
+
self.expanded = false;
|
670
|
+
self.callSuper();
|
671
671
|
},
|
672
672
|
// iterates through all the buttons and lets them highlight themselves depending on the
|
673
673
|
// currently selected text
|
674
674
|
on_select: function(event) {
|
675
|
-
var state = TextCommand.get_state(
|
675
|
+
var input = this.input(), toolbar = this.popupToolbar(), state = TextCommand.get_state(input);
|
676
676
|
$.each(this.commands, function() {
|
677
677
|
this.respond_to_selection(state);
|
678
678
|
});
|
679
|
+
input.showSelectionPopup(toolbar, function(position) {
|
680
|
+
var tools = {width: toolbar.width(), height: toolbar.height()},
|
681
|
+
text = { width: input.width(), height: input.height()};
|
682
|
+
// console.log("position", position, tools, text);
|
683
|
+
var place = {
|
684
|
+
left: position.left,
|
685
|
+
// 5 is half the height of the arrow
|
686
|
+
// 7 is the padding of the field
|
687
|
+
top: position.top + 7 - 5 - tools.height
|
688
|
+
};
|
689
|
+
var dx = 0;
|
690
|
+
var arrow = toolbar.find(".arrow"),
|
691
|
+
arrowLeft = (position.width / 2) - 5;
|
692
|
+
// if the selection is narrow the arrow can peek over the left
|
693
|
+
// of the toolbar. This shifts everything over and keeps it neat.
|
694
|
+
if (position.width < 40) {
|
695
|
+
place.left = place.left - 15;
|
696
|
+
arrowLeft += 15;
|
697
|
+
}
|
698
|
+
if ((place.left + tools.width) > (text.width)) {
|
699
|
+
dx = ((place.left + tools.width) - (text.width + 20));
|
700
|
+
place.left = place.left - dx;
|
701
|
+
arrowLeft += dx;
|
702
|
+
}
|
703
|
+
|
704
|
+
arrowLeft = Math.min(toolbar.width() - 30, arrowLeft);
|
705
|
+
arrow.css("left", dom.px(arrowLeft));
|
706
|
+
return place;
|
707
|
+
});
|
679
708
|
}
|
680
709
|
});
|
681
710
|
|
@@ -688,9 +717,8 @@ Spontaneous.Field.Markdown = (function($, S) {
|
|
688
717
|
H1: H1,
|
689
718
|
H2: H2,
|
690
719
|
Link: Link
|
691
|
-
|
692
|
-
|
693
720
|
});
|
721
|
+
|
694
722
|
return MarkdownField;
|
695
723
|
})(jQuery, Spontaneous);
|
696
724
|
|
@@ -25,7 +25,7 @@ Spontaneous.Field.Select = (function($, S) {
|
|
25
25
|
},
|
26
26
|
|
27
27
|
optionsURL: function() {
|
28
|
-
return ["/options", this.type.schema_id, this.content.id()].join("/");
|
28
|
+
return ["/field/options", this.type.schema_id, this.content.id()].join("/");
|
29
29
|
},
|
30
30
|
|
31
31
|
append_select: function(wrapper, option_list) {
|
@@ -10,7 +10,12 @@ Spontaneous.Field.WebVideo = (function($, S) {
|
|
10
10
|
// return this.get_input();
|
11
11
|
// }
|
12
12
|
preview: function() {
|
13
|
-
|
13
|
+
// oh god. I need to have a UI only version of the player code which disables autoplay etc
|
14
|
+
// at the moment the value passed to the ui is the same as the one used for templates
|
15
|
+
// which, in the case of autoplay, is wildly inappropriate
|
16
|
+
// at the same time I want to replace an immediately inserted video player with an
|
17
|
+
// image + play button to reduce the impact of multiple videos on the cms ui load time
|
18
|
+
var value = this.get('value').replace(/autoplay=1/, '')
|
14
19
|
, iframe = dom.iframe({src:value, frameborder: 0, border: 0}).css({position: "absolute", top:0, left:0, height: "100%", width: "100%"});
|
15
20
|
if (!value) { // don't fill up the page with empty iframes...
|
16
21
|
return dom.div();
|
data/application/js/init.js
CHANGED
@@ -20,9 +20,9 @@ Spontaneous.Init = (function($, S) {
|
|
20
20
|
b.append(content_area.init());
|
21
21
|
b.append(S.StatusBar.init());
|
22
22
|
|
23
|
-
S.Metadata.load(function() {
|
23
|
+
S.Metadata.load(function(metadata) {
|
24
24
|
location.init(function() {
|
25
|
-
top_bar.init();
|
25
|
+
top_bar.init(metadata);
|
26
26
|
});
|
27
27
|
});
|
28
28
|
};
|
@@ -0,0 +1,130 @@
|
|
1
|
+
/**
|
2
|
+
* Based on an original plugin "jquery-caret-position-getter"
|
3
|
+
*
|
4
|
+
* https://github.com/beviz/jquery-caret-position-getter
|
5
|
+
*
|
6
|
+
* @license under Apache license
|
7
|
+
* @author Bevis Zhao (i@bevis.me, http://bevis.me)
|
8
|
+
*/
|
9
|
+
(function($) {
|
10
|
+
"use strict";
|
11
|
+
|
12
|
+
var calculator = {
|
13
|
+
// key styles
|
14
|
+
primaryStyles: ['fontFamily', 'fontSize', 'fontWeight', 'fontVariant',
|
15
|
+
'fontStyle', 'paddingLeft', 'paddingTop', 'paddingBottom', 'paddingRight',
|
16
|
+
'marginLeft', 'marginTop', 'marginBottom', 'marginRight', 'borderLeftColor',
|
17
|
+
'borderTopColor', 'borderBottomColor', 'borderRightColor', 'borderLeftStyle',
|
18
|
+
'borderTopStyle', 'borderBottomStyle', 'borderRightStyle', 'borderLeftWidth',
|
19
|
+
'borderTopWidth', 'borderBottomWidth', 'borderRightWidth', 'line-height',
|
20
|
+
'outline'],
|
21
|
+
|
22
|
+
specificStyle: {
|
23
|
+
'white-space': 'pre-wrap',
|
24
|
+
'word-wrap': 'normal',
|
25
|
+
'overflow-x': 'hidden',
|
26
|
+
'overflow-y': 'auto'
|
27
|
+
},
|
28
|
+
|
29
|
+
simulator : $('<div id="textarea_simulator"/>').css({
|
30
|
+
position: 'absolute',
|
31
|
+
top: 0,
|
32
|
+
left: 0,
|
33
|
+
visibility: 'hidden'
|
34
|
+
}).appendTo(document.body),
|
35
|
+
|
36
|
+
// calculate position
|
37
|
+
getSelectionPosition: function() {
|
38
|
+
var cal = calculator, self = this, element = self[0], elementOffset = self.offset();
|
39
|
+
|
40
|
+
cal.simulator.empty();
|
41
|
+
// clone primary styles to imitate textarea
|
42
|
+
$.each(cal.primaryStyles, function(index, styleName) {
|
43
|
+
self.cloneStyle(cal.simulator, styleName);
|
44
|
+
});
|
45
|
+
|
46
|
+
// caculate width and height
|
47
|
+
cal.simulator.css($.extend({
|
48
|
+
'width': self.width(),
|
49
|
+
'height': self.height()
|
50
|
+
}, cal.specificStyle));
|
51
|
+
|
52
|
+
var value = self.val(),
|
53
|
+
selectStart = element.selectionStart,
|
54
|
+
selectEnd = element.selectionEnd;
|
55
|
+
|
56
|
+
if (selectEnd === selectStart) { return false; };
|
57
|
+
|
58
|
+
var beforeText = value.substring(0, selectStart),
|
59
|
+
selectedText = value.substring(selectStart, selectEnd),
|
60
|
+
afterText = value.substring(selectEnd);
|
61
|
+
|
62
|
+
var before = $('<span class="before"/>').html(beforeText),
|
63
|
+
focus = $('<span class="focus"/>').html(selectedText),
|
64
|
+
after = $('<span class="after"/>').html(afterText);
|
65
|
+
|
66
|
+
cal.simulator.append(before, focus, after);
|
67
|
+
|
68
|
+
var focusOffset = focus.offset(), simulatorOffset = cal.simulator.offset();
|
69
|
+
|
70
|
+
return {
|
71
|
+
top: focusOffset.top - simulatorOffset.top - element.scrollTop,
|
72
|
+
left: focus[0].offsetLeft - cal.simulator[0].offsetLeft - element.scrollLeft,
|
73
|
+
width: focus.width(),
|
74
|
+
height: focus.height()
|
75
|
+
};
|
76
|
+
}
|
77
|
+
};
|
78
|
+
|
79
|
+
var showPopup = function(textarea, popup, offsetCalculator) {
|
80
|
+
var pos = calculator.getSelectionPosition.call(textarea);
|
81
|
+
if (pos === false) {
|
82
|
+
popup.hide();
|
83
|
+
return false;
|
84
|
+
}
|
85
|
+
var position = textarea.position(), height = textarea.height(),
|
86
|
+
top = position.top + pos.top, bottom = position.top + height;
|
87
|
+
|
88
|
+
// In order to use the size of the popup in the positioning calculations
|
89
|
+
// it needs to be visible in the dom.
|
90
|
+
popup.css("visibility", "hidden").show();
|
91
|
+
var place = offsetCalculator(pos);
|
92
|
+
popup.hide().css("visibility", "visible");
|
93
|
+
if (top >= position.top && top < bottom) {
|
94
|
+
popup.css({
|
95
|
+
left: place.left,
|
96
|
+
top: place.top
|
97
|
+
}).fadeIn(100)
|
98
|
+
} else {
|
99
|
+
popup.fadeOut(100);
|
100
|
+
}
|
101
|
+
return true;
|
102
|
+
}
|
103
|
+
$.fn.extend({
|
104
|
+
getComputedStyle: function(styleName) {
|
105
|
+
if (this.length == 0) return;
|
106
|
+
var self = this[0], result = this.css(styleName);
|
107
|
+
result = result || ($.browser.msie ? self.currentStyle[styleName]: document.defaultView.getComputedStyle(self, null)[styleName]);
|
108
|
+
return result;
|
109
|
+
},
|
110
|
+
cloneStyle: function(target, styleName) {
|
111
|
+
var styleVal = this.getComputedStyle(styleName);
|
112
|
+
if (!!styleVal) {
|
113
|
+
$(target).css(styleName, styleVal);
|
114
|
+
}
|
115
|
+
},
|
116
|
+
showSelectionPopup: function(popup, offsetCalculator) {
|
117
|
+
var self = $(this);
|
118
|
+
var callback = function() {
|
119
|
+
var selected = showPopup(self, popup, offsetCalculator);
|
120
|
+
if (!selected) {
|
121
|
+
self.unbind("scroll.popup").unbind("mouseup.popup");
|
122
|
+
}
|
123
|
+
};
|
124
|
+
self.bind("scroll.popup", callback);
|
125
|
+
self.bind("mouseup.popup", callback.delay(1));
|
126
|
+
callback();
|
127
|
+
}
|
128
|
+
});
|
129
|
+
}(jQuery));
|
130
|
+
|
data/application/js/location.js
CHANGED
@@ -83,7 +83,8 @@ Spontaneous.Location = (function($, S) {
|
|
83
83
|
},
|
84
84
|
load_map: function() {
|
85
85
|
},
|
86
|
-
location_loaded: function(location, xhr) {
|
86
|
+
location_loaded: function(location, status, xhr) {
|
87
|
+
S.Popover.close();
|
87
88
|
if (xhr.status === 406) { // Code returned if site is missing a root page
|
88
89
|
var d = new Spontaneous.AddHomeDialogue(Spontaneous.Types.get('types'));
|
89
90
|
d.open();
|
@@ -127,7 +128,7 @@ Spontaneous.Location = (function($, S) {
|
|
127
128
|
if (this.location() && path === this.location().path) {
|
128
129
|
return this.location();
|
129
130
|
}
|
130
|
-
this.retrieve('/
|
131
|
+
this.retrieve('/map/path'+path, this.location_loaded.bind(this));
|
131
132
|
},
|
132
133
|
find_id: function(id) {
|
133
134
|
if (this.location() && id === this.location().id) {
|
@@ -155,30 +156,8 @@ Spontaneous.Location = (function($, S) {
|
|
155
156
|
}
|
156
157
|
return path;
|
157
158
|
},
|
158
|
-
// easier to create my own 304 sensitive ajax request
|
159
|
-
// than peg on a content cache to jQuery's
|
160
159
|
retrieve: function(url, callback) {
|
161
|
-
|
162
|
-
, req = new XMLHttpRequest()
|
163
|
-
, data;
|
164
|
-
req.open("GET", ajax.request_url(url, true), true)
|
165
|
-
req.setRequestHeader('If-Modified-Since', self.lastModified(url));
|
166
|
-
req.onreadystatechange = function(event) {
|
167
|
-
if (req.readyState === XMLHttpRequest.DONE) {
|
168
|
-
if (req.status === 200) {
|
169
|
-
data = jQuery.parseJSON(req.responseText);
|
170
|
-
self.setLocationCache(url, req.getResponseHeader("Last-Modified"), data)
|
171
|
-
}
|
172
|
-
if (req.status === 304) {
|
173
|
-
data = self.getLocationCache(url)
|
174
|
-
}
|
175
|
-
if (req.status === 401) {
|
176
|
-
S.Ajax.unauthorized();
|
177
|
-
}
|
178
|
-
callback(data, req);
|
179
|
-
}
|
180
|
-
};
|
181
|
-
req.send(null);
|
160
|
+
ajax.get(url, {}, callback, {ifModified: true, cache: true});
|
182
161
|
},
|
183
162
|
lastModified: function(path) {
|
184
163
|
return (this.locationCache[path] || {}).lastModified;
|
@@ -515,8 +515,8 @@ Spontaneous.MetaView.UserAdmin = (function($, S){
|
|
515
515
|
title: function() {
|
516
516
|
return "Delete user “" + (this.user.get("login")) + "”";
|
517
517
|
},
|
518
|
-
position_from_event: function(
|
519
|
-
var pos = this.position_from_element(
|
518
|
+
position_from_event: function(target) {
|
519
|
+
var pos = this.position_from_element(target);
|
520
520
|
pos.left += 40;
|
521
521
|
return pos;
|
522
522
|
},
|
data/application/js/metadata.js
CHANGED
@@ -7,12 +7,12 @@ Spontaneous.Metadata = (function($, S) {
|
|
7
7
|
S.Types.loaded(metadata.types);
|
8
8
|
S.User.loaded(metadata.user);
|
9
9
|
S.Services.loaded(metadata.services);
|
10
|
-
if (callback) { callback
|
10
|
+
if (callback) { callback(metadata); };
|
11
11
|
};
|
12
12
|
};
|
13
13
|
return {
|
14
14
|
load: function(onComplete) {
|
15
|
-
ajax.get('/
|
15
|
+
ajax.get('/site', loaded(onComplete));
|
16
16
|
}
|
17
17
|
};
|
18
18
|
}(jQuery, Spontaneous));
|