ants 0.3.5 → 0.3.9

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: e58b34ea86075f7cb44ac8ae103a3cd1d9d4dd4f
4
- data.tar.gz: 1897ad67c7b775b9194a15794a5b1b1e82492c81
3
+ metadata.gz: 6a28c13709ccfad3dd8b3f61cb3e7928d57d85af
4
+ data.tar.gz: 1753c8d2ce2aa021478cb0ecba65650f3c6bb3e7
5
5
  SHA512:
6
- metadata.gz: e5770f9afa81ad04069fa6c17a39d67252a7c93d30ee888f724d78e6110e7d3b5a411c10633504fc8b2ac9d80f2c49b87b7ec6a2fdd1958a82d6260b7cdf615a
7
- data.tar.gz: e847b7a98afb34bd2f5943f9a91f6be98d0501ad42e22e653df3415cf4086617ca0e9d34d5d5ff4bf5b508de628738b3d167c0e9e67f60cac108fa8bc5b72ec5
6
+ metadata.gz: d76803eb7462cdd16f05914fd460faac70389f8077eba1aa3168d0bf378d40f78d6077f933f347e20a3454a5518361a04c5eec90257e7c6a71855aa40c8d3048
7
+ data.tar.gz: 511bc1e6f8a2dc69c193f585c26e671a6538d184bcdd6a38c376eda44c1883b1cd73fc1791eea0e4350f4b31b59937eb54c5a1c6c844d23d4d446df88fc6ffce
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- ants (0.3.5)
4
+ ants (0.3.9)
5
5
  devise
6
6
  mongoid (>= 4.0)
7
7
  mongoid-slug (>= 4.0.0)
@@ -46,7 +46,7 @@ GEM
46
46
  tzinfo (~> 1.1)
47
47
  arel (6.0.3)
48
48
  bcrypt (3.1.10)
49
- bson (3.2.6)
49
+ bson (4.0.0)
50
50
  builder (3.2.2)
51
51
  coveralls (0.8.2)
52
52
  json (~> 1.8)
@@ -54,7 +54,7 @@ GEM
54
54
  simplecov (~> 0.10.0)
55
55
  term-ansicolor (~> 1.3)
56
56
  thor (~> 0.19.1)
57
- devise (3.5.2)
57
+ devise (3.5.3)
58
58
  bcrypt (~> 3.0)
59
59
  orm_adapter (~> 0.1)
60
60
  railties (>= 3.2.6, < 5)
@@ -79,8 +79,8 @@ GEM
79
79
  mime-types (2.6.1)
80
80
  mini_portile (0.6.2)
81
81
  minitest (5.8.0)
82
- mongo (2.1.2)
83
- bson (~> 3.0)
82
+ mongo (2.2.0)
83
+ bson (~> 4.0)
84
84
  mongoid (5.0.1)
85
85
  activemodel (~> 4.0)
86
86
  mongo (~> 2.1)
@@ -168,7 +168,7 @@ GEM
168
168
  unf (0.1.4)
169
169
  unf_ext
170
170
  unf_ext (0.0.7.1)
171
- warden (1.2.3)
171
+ warden (1.2.4)
172
172
  rack (>= 1.0)
173
173
 
174
174
  PLATFORMS
data/README.md CHANGED
@@ -1,12 +1,14 @@
1
-
2
1
  Ants
3
- ======
2
+ ===============================================================================
4
3
  [![GitHub version](https://badge.fury.io/gh/slate-studio%2Fants.svg)](http://badge.fury.io/gh/slate-studio%2Fants)
5
4
  [![Build Status](https://travis-ci.org/slate-studio/ants.svg)](https://travis-ci.org/slate-studio/ants)
6
5
  [![Code Climate](https://codeclimate.com/github/slate-studio/ants/badges/gpa.svg)](https://codeclimate.com/github/slate-studio/ants)
7
6
  [![Coverage Status](https://coveralls.io/repos/slate-studio/ants/badge.svg)](https://coveralls.io/r/slate-studio/ants)
8
7
 
9
- Collection of concerns and helpers for Rails + Mongoid + Character web development
8
+ Collection of concerns and helpers for `Rails` + `Mongoid` + `Character` stack.
9
+
10
+
11
+ ### Id
10
12
 
11
13
 
12
14
  ### Orderable
@@ -25,6 +27,8 @@ Usage:
25
27
  ModelClass.all.set(_position: 1000)
26
28
  ```
27
29
 
30
+ ### OrderableReverse
31
+
28
32
 
29
33
  ### Meta
30
34
 
@@ -42,6 +46,9 @@ Usage:
42
46
  ```
43
47
 
44
48
 
49
+ ### Featurable
50
+
51
+
45
52
  ### Hideable
46
53
 
47
54
  When you need to hide some documents from public or often used as draft analogue:
@@ -67,6 +74,8 @@ Helpers:
67
74
  ### Slug
68
75
 
69
76
 
77
+ ### Scheduled
78
+
70
79
 
71
80
  ### Sorted Relations
72
81
 
@@ -110,5 +119,19 @@ Helpers:
110
119
  - `_document_versions`
111
120
 
112
121
 
122
+ ### AdminUsers
123
+
124
+
125
+ ### Settings
126
+
127
+
128
+ ### Redirects
129
+
130
+
131
+ ### Content
132
+
133
+
134
+ ### Menus
113
135
 
114
136
 
137
+ ### Profile
@@ -1,63 +1,103 @@
1
1
  class @AntsAdminUsers
2
- constructor: (title='Administrators', apiPath='/admin') ->
3
- config =
4
- title: title
5
- showWithParent: true
6
-
7
- arrayStore: new RailsArrayStore({
8
- resource: 'admin_user'
9
- path: "#{ apiPath }/admin_users"
10
- sortBy: 'name'
11
- searchable: true
12
- })
13
-
14
- formSchema:
15
- details_panel:
16
- type: 'group'
17
- groupClass: 'group-panel'
18
- title: 'Profile'
19
- inputs:
20
- name:
21
- type: 'string'
22
- required: true
23
- label: "Name"
24
- placeholder: 'Full name'
25
- onInitialize: (input) ->
26
- if input.object
27
- input.$el.removeClass 'input-required'
28
- input.config.disabled = true
29
- input._add_disabled()
30
-
31
- email:
32
- type: 'string'
33
- required: true
34
- placeholder: 'Email'
35
-
36
- onInitialize: (input) ->
37
- if input.object
38
- input.$el.removeClass 'input-required'
39
- input.config.disabled = true
40
- input._add_disabled()
41
-
42
- input.$actions =$ "<span class='input-actions'></span>"
43
- input.$avatarBtn =$ "<a href='https://en.gravatar.com/' target='_blank'>Update avatar</a>"
44
- input.$label.append input.$actions
45
- input.$actions.append input.$avatarBtn
46
-
47
- password_panel:
48
- type: 'group'
49
- groupClass: 'group-panel'
50
- title: 'Password'
51
- inputs:
52
- password:
53
- type: 'password'
54
- required: true
55
- placeholder: 'Password'
56
- onInitialize: (input) ->
57
- if input.object
58
- input.$el.removeClass 'input-required'
59
- input.$label.html 'Change password'
60
- input.config.placeholder = 'Enter new password here, then hit "Save"'
61
- input._add_placeholder()
62
-
63
- return config
2
+ constructor: (@title='Administrators', @apiPath='/admin') ->
3
+ @showWithParent = true
4
+
5
+ @arrayStore = new RailsArrayStore
6
+ resource: "admin_user"
7
+ path: "#{ @apiPath }/admin_users"
8
+ sortBy: "name"
9
+ searchable: true
10
+
11
+ @formSchema =
12
+ details_panel:
13
+ type: "group"
14
+ groupClass: "group-panel"
15
+ title: "Profile"
16
+ inputs:
17
+ name:
18
+ type: "string"
19
+ required: true
20
+ label: "Name"
21
+ placeholder: "Enter users full name."
22
+ onInitialize: (input) => @_disable_input_for_edit(input)
23
+
24
+ email:
25
+ type: "string"
26
+ required: true
27
+ placeholder: "Enter users email address used to sign in."
28
+
29
+ onInitialize: (input) => @_disable_input_for_edit(input)
30
+
31
+ password_panel:
32
+ type: "group"
33
+ groupClass: "group-panel"
34
+ title: "Password"
35
+ inputs:
36
+ password:
37
+ type: "password"
38
+ required: true
39
+ placeholder: "Please use a complex password."
40
+ onInitialize: (input) =>
41
+ @_transform_password_to_change_password_on_edit(input)
42
+
43
+ @onEditShow = (view) =>
44
+ @_hide_save_button(view)
45
+
46
+ # PRIVATE ===================================================================
47
+ _hide_save_button: (view) ->
48
+ view.$saveBtn.hide()
49
+
50
+ _disable_input_for_edit: (input) ->
51
+ if input.object
52
+ input.$el.removeClass "input-required"
53
+ input.config.disabled = true
54
+ input._add_disabled()
55
+
56
+ _transform_password_to_change_password_on_edit: (input) ->
57
+ if input.object
58
+ input.$el.prev().children(".group-title").html("Change Password")
59
+ input.$el.removeClass "input-required"
60
+ input.$labelTitle.html "New password"
61
+ input.config.placeholder = 'Enter your new password and hit "Update".'
62
+ input._add_placeholder()
63
+
64
+ @_add_password_update_action(input)
65
+
66
+ _add_password_update_action: (input) ->
67
+ input.$actions =$ "<span class='input-actions'></span>"
68
+ input.$updateBtn =$ "<button>Update</button>"
69
+ input.$label.append input.$actions
70
+ input.$actions.append input.$updateBtn
71
+
72
+ input.$updateBtn.on "click", (e) =>
73
+ @_update_password(input)
74
+
75
+ _update_password: (input) ->
76
+ chr.module.view.showSpinner()
77
+ input.hideErrorMessage()
78
+
79
+ resourcePath = "#{ @apiPath }/admin_users"
80
+ resourceId = input.object._id
81
+ action = "update_password"
82
+ url = "#{resourcePath}/#{resourceId}/#{action}.json"
83
+
84
+ data =
85
+ password: input.$input.val()
86
+
87
+ $.ajax
88
+ type: 'PATCH'
89
+ url: url
90
+ data: data
91
+
92
+ success: (response) ->
93
+ chr.module.view.hideSpinner()
94
+ input.$input.val("")
95
+ chr.showNotification "Password has been updated."
96
+
97
+ error: (jqXHR) ->
98
+ if jqXHR.responseJSON
99
+ firstErrorMessage = jqXHR.responseJSON[input.config.fieldName][0]
100
+ input.showErrorMessage(firstErrorMessage)
101
+
102
+ chr.showError "Your password were not updated. Please fix error and try again."
103
+ chr.module.view.hideSpinner()
@@ -0,0 +1,109 @@
1
+ class @AntsContent
2
+ constructor: (@resourceName="Document") ->
3
+ @disableDelete = true
4
+
5
+ @viewTabs =
6
+ editor: @resourceName
7
+ settings: "Options"
8
+
9
+ @formSchema =
10
+ editor:
11
+ type: "group"
12
+ groupClass: "group-content-editor"
13
+ onInitialize: (form, group) =>
14
+ @_add_actions(form, group)
15
+ inputs:
16
+ title:
17
+ type: "string"
18
+ placeholder: "#{@resourceName} Title"
19
+ slug: new AntsSlugInput("#{location.origin}/")
20
+ body_markdown:
21
+ type: "markdown"
22
+ label: "Content"
23
+ htmlFieldName: "body_html"
24
+ placeholder: "Content"
25
+
26
+ settings:
27
+ type: "group"
28
+ groupClass: "group-content-settings"
29
+ inputs:
30
+ sharing_panel:
31
+ type: "group"
32
+ groupClass: "group-panel"
33
+ title: "Sharing"
34
+ inputs:
35
+ @_meta_inputs()
36
+
37
+ general_panel:
38
+ type: "group"
39
+ groupClass: "group-panel group-content-settings"
40
+ inputs:
41
+ hidden:
42
+ type: "switch"
43
+ label: "Draft"
44
+ default: true
45
+
46
+
47
+ @onEditShow = (view) =>
48
+ @_update_slug_label(view)
49
+
50
+ @onSaveSuccess = (view) =>
51
+ @_update_slug_label(view)
52
+ @_update_preview_href(view.form)
53
+
54
+ # PRIVATE ===================================================================
55
+
56
+ _update_slug_label: (view) ->
57
+ if @_path
58
+ path = @_path(view.object)
59
+ view.form.inputs.slug.$label.text(path)
60
+
61
+ _update_preview_href: (form) ->
62
+ if @_preview_url
63
+ object = form.object
64
+ $button = form.groups[0].$previewBtn
65
+ preview_url = @_preview_url(object)
66
+ $button.attr("href", preview_url)
67
+
68
+ _add_delete_button: (form, group) ->
69
+ group.$deleteBtn =$ """
70
+ <a href='#' target='_blank' class='content-delete'>
71
+ #{Icons.delete}
72
+ </a>"""
73
+ group.$actions.prepend group.$deleteBtn
74
+ group.$deleteBtn.on 'click', (e) -> chr.module.view._delete(e)
75
+
76
+ _add_preview_button: (form, group) ->
77
+ group.$previewBtn =$ """
78
+ <a href='#' target='_blank' class='content-preview'>
79
+ #{Icons.preview}
80
+ </a>"""
81
+ group.$actions.prepend group.$previewBtn
82
+ if form.object
83
+ @_update_preview_href(form)
84
+
85
+ _add_actions: (form, group) ->
86
+ group.$actions =$ "<div class='group-content-editor-actions'/>"
87
+ group.$el.prepend group.$actions
88
+
89
+ @_add_delete_button(form, group)
90
+ @_add_preview_button(form, group)
91
+
92
+ _meta_inputs: ->
93
+ opengraph_image_url:
94
+ name: '_opengraph_image_url'
95
+ type: 'loft-image'
96
+ label: 'Image'
97
+ fullsizePreview: true
98
+
99
+ meta_title:
100
+ name: "_meta_title"
101
+ type: "string"
102
+ label: false
103
+ placeholder: "Title"
104
+
105
+ meta_description:
106
+ name: "_meta_description"
107
+ type: "text"
108
+ label: false
109
+ placeholder: "Content summary"
@@ -1,28 +1,38 @@
1
1
  class @AntsMenu
2
- constructor: (title, apiPath) ->
3
- config =
4
- title: title
2
+ constructor: (@title, @apiPath) ->
3
+ @objectStore = new RailsObjectStore
4
+ resource: 'menu'
5
+ path: "#{ @apiPath }"
5
6
 
6
- objectStore: new RailsObjectStore({
7
- resource: 'menu'
8
- path: "#{ apiPath }"
9
- })
7
+ @formSchema =
8
+ links:
9
+ type: 'documents'
10
+ newButtonLabel: 'Add a Link'
11
+ sortBy: '_position'
12
+ label: false
13
+ formSchema:
14
+ title:
15
+ type: "string"
16
+ placeholder: "Title"
10
17
 
11
- formSchema:
12
- links:
13
- type: 'documents'
14
- newButtonLabel: 'Add a Link'
15
- sortBy: '_position'
16
- formSchema:
17
- title:
18
- type: 'string'
18
+ url:
19
+ type: "url"
20
+ placeholder: "Path or URL, e.g. /about"
21
+ onInitialize: (input) =>
22
+ @_add_preview_action(input)
19
23
 
20
- url:
21
- type: 'string'
24
+ @onViewShow = (view) ->
25
+ view.$el.addClass "view-menu"
22
26
 
23
- target_blank:
24
- type: 'checkbox'
25
- default: false
26
- label: 'Open in a new tab'
27
+ _add_preview_action: (input) ->
28
+ input.$actions =$ "<span class='input-actions'></span>"
29
+ input.$el.append input.$actions
27
30
 
28
- return config
31
+ input.$previewBtn =$ """<a href='#{input.value}' target='_blank'>
32
+ #{Icons.preview}
33
+ </a>"""
34
+ input.$actions.append input.$previewBtn
35
+
36
+ input.$input.on "change", (e) ->
37
+ link = input.$input.val()
38
+ input.$previewBtn.attr "href", link
@@ -1,29 +1,24 @@
1
1
  class @AntsMetaGroup
2
- constructor: (extra_config={}) ->
3
- config =
4
- type: 'group'
5
- inputs:
6
- _meta_title:
7
- type: 'string'
8
- label: 'Meta Title'
9
- limit: 60
10
- placeholder: "Accurate and concise description of a page's content"
2
+ constructor: ->
3
+ @type = 'group'
4
+ @inputs =
5
+ _opengraph_image_url:
6
+ type: 'loft-image'
7
+ label: 'Image'
11
8
 
12
- _meta_description:
13
- type: 'text'
14
- label: 'Meta Description'
15
- limit: 200
16
- placeholder: 'Advertise content with short summary'
9
+ _meta_title:
10
+ type: 'string'
11
+ label: 'Title'
12
+ limit: 60
13
+ placeholder: "Accurate and concise description of a page's content"
17
14
 
18
- _meta_keywords:
19
- type: 'text'
20
- label: 'Meta Keywords'
21
- placeholder: 'e.g. keyword1, keyword2, keyword3'
15
+ _meta_description:
16
+ type: 'text'
17
+ label: 'Description'
18
+ limit: 200
19
+ placeholder: 'Advertise content with short summary'
22
20
 
23
- _opengraph_image_url:
24
- type: 'loft-image'
25
- label: 'Open Graph Image'
26
-
27
- $.extend(config, extra_config)
28
-
29
- return config
21
+ _meta_keywords:
22
+ type: 'string'
23
+ label: 'Keywords'
24
+ placeholder: 'e.g. keyword1, keyword2, keyword3'
@@ -1,15 +1,13 @@
1
1
  class @AntsSlugInput
2
- constructor: (extra_config={}) ->
2
+ constructor: (label="Slug") ->
3
3
  config =
4
- type: 'string'
5
- name: '_slug'
6
- label: 'Slug'
7
- placeholder: ''
4
+ type: "string"
5
+ name: "_slug"
6
+ label: label
7
+ placeholder: " "
8
8
  onInitialize: (input) ->
9
9
  if input.object && input.object._slugs.length
10
10
  defaultSlug = input.object._slugs[0]
11
- input.$input.attr 'placeholder', defaultSlug
12
-
13
- $.extend(config, extra_config)
11
+ input.$input.attr "placeholder", defaultSlug
14
12
 
15
13
  return config
@@ -1 +1,5 @@
1
1
  #= require_tree ./ants
2
+
3
+ @Icons ?= {}
4
+ @Icons.preview = "<i class='fa fa-external-link'></i>"
5
+ @Icons.delete = "<i class='fa fa-trash-o'></i>"
@@ -0,0 +1,113 @@
1
+ .group-content-settings {
2
+ .sharing_panel {
3
+ @include position(relative);
4
+ }
5
+ .input-_meta_title {
6
+ @include no-bottom-border;
7
+ padding: 0.75em 1em 0 6.25em;
8
+ .label { display: none; }
9
+ input { font-weight: $medium; }
10
+ }
11
+ .input-_meta_description {
12
+ @include no-bottom-border;
13
+ min-height: 63px;
14
+ padding: 0.25em 1em 1em 6.25em;
15
+ .label { display: none; }
16
+ textarea { font-size: 0.9em; }
17
+ }
18
+ }
19
+
20
+ .group-content-editor {
21
+ @include position(relative);
22
+ min-height: 16em;
23
+ background-color: $white-color;
24
+
25
+ .input-_slug {
26
+ @include no-bottom-border;
27
+ padding-bottom: 0;
28
+ }
29
+
30
+ .input-title {
31
+ @include no-bottom-border;
32
+ padding-bottom: 0;
33
+ padding-right: 4.5em;
34
+ font-weight: $medium;
35
+
36
+ &.error:after {
37
+ background-color: $assertive-color;
38
+ }
39
+ }
40
+
41
+ .input-title,
42
+ .input-body_markdown {
43
+ padding-top: 1em;
44
+
45
+ .label {
46
+ display: none;
47
+ }
48
+ }
49
+
50
+ .input-_slug {
51
+ padding-top: 0;
52
+ opacity: 0.5;
53
+
54
+ .label {
55
+ display: inline-block;
56
+ font-size: .8em;
57
+ cursor: pointer;
58
+ }
59
+
60
+ .error-message {
61
+ display: none;
62
+ }
63
+
64
+ input {
65
+ display: inline-block;
66
+ width: 18em;
67
+ font-size: .8em;
68
+ padding: 0;
69
+ }
70
+ }
71
+ }
72
+
73
+ .view-new .group-content-editor-actions {
74
+ display: none;
75
+ }
76
+
77
+ .content-delete {
78
+ i { @include position(relative, -1px null null null); }
79
+ &:hover { color: $assertive-color; }
80
+ }
81
+
82
+ .group-content-editor-actions {
83
+ @include position(absolute, 0.5em 0.5em null null);
84
+ z-index: 1;
85
+
86
+ a {
87
+ display: inline-block;
88
+ float: right;
89
+ width: 2em;
90
+ height: 2em;
91
+ line-height: 2;
92
+ text-align: center;
93
+ color: $base-font-color;
94
+ opacity: 0.25;
95
+
96
+ &:hover { opacity: 0.75; }
97
+ }
98
+ }
99
+
100
+ /* Tablet ------------------------------------------------------------------ */
101
+ @media #{$tablet} {
102
+ .group-content-settings {
103
+ .sharing_panel {
104
+ min-height: 17.8em;
105
+ }
106
+ .input-_meta_title {
107
+ padding-left: 15.25em;
108
+ }
109
+ .input-_meta_description {
110
+ padding-left: 15.25em;
111
+ }
112
+ }
113
+ }
@@ -0,0 +1,56 @@
1
+ .view-menu {
2
+ .nested-forms {
3
+ padding-top: 1.5em;
4
+
5
+ &> .label {
6
+ display: none;
7
+ }
8
+ }
9
+
10
+ .input-title {
11
+ padding: 0.75em 1em 0.75em;
12
+
13
+ .label {
14
+ display: none;
15
+ }
16
+
17
+ input {
18
+ font-weight: $medium;
19
+ padding-right: 1em;
20
+ }
21
+ }
22
+
23
+ .input-url {
24
+ padding: .65em 1em 0.75em;
25
+
26
+ .label-title { display: none; }
27
+ .label { height: 0; }
28
+
29
+ .input-actions {
30
+ top: 0.6em;
31
+ right: 1.1em;
32
+
33
+ a {
34
+ @include position(relative, 0.75em -2.8em null null);
35
+ color: $secondary-font-color;
36
+
37
+ &:hover { color: $base-font-color; }
38
+ }
39
+ }
40
+
41
+ input {
42
+ font-size: 0.9em;
43
+ padding-right: 5em;
44
+ color: $secondary-font-color;
45
+ }
46
+ }
47
+ }
48
+
49
+ /* Tablet ------------------------------------------------------------------ */
50
+ @media #{$tablet} {
51
+ .view-menu {
52
+ .nested-forms {
53
+ padding-left: 0;
54
+ }
55
+ }
56
+ }
@@ -1,4 +1,5 @@
1
1
  @import "ants/header";
2
2
  @import "ants/profile";
3
3
  @import "ants/settings";
4
- @import "ants/redirects";
4
+ @import "ants/content";
5
+ @import "ants/menu";
@@ -1,5 +1,31 @@
1
1
  module Admin
2
2
  class AdminUsersController < Admin::BaseController
3
3
  mongosteen
4
+
5
+ def update_password
6
+ user = resource
7
+ new_password = permitted_params[:password]
8
+
9
+ user.password = new_password
10
+ user.password_confirmation = new_password
11
+
12
+ if user.save
13
+ if current_admin_user == user
14
+ sign_in(user, bypass: true)
15
+ end
16
+ render nothing: true
17
+
18
+ else
19
+ render json: user.errors, status: 500
20
+
21
+ end
22
+ end
23
+
24
+ protected
25
+
26
+ def permitted_params
27
+ params.permit!
28
+ end
29
+
4
30
  end
5
31
  end
@@ -1,8 +1,6 @@
1
1
  class RedirectsController < ApplicationController
2
-
3
2
  def show
4
3
  redirect = Redirect.match(request)
5
4
  redirect_to redirect.path_to
6
5
  end
7
-
8
6
  end
@@ -1,16 +1,27 @@
1
1
  module ContentHelper
2
2
  def content_meta_tags(object)
3
- open_graph_tags = { title: object.meta_title,
4
- description: object.meta_description,
5
- url: object.canonical_url,
6
- type: object.meta_type,
7
- image: object.opengraph_image_url,
8
- updated_time: object.updated_at.to_i }
3
+ twitter_tags = {
4
+ url: object.canonical_url,
5
+ title: object.meta_title,
6
+ description: object.meta_description,
7
+ image: object.opengraph_image_url,
8
+ card: "summary"
9
+ }
10
+
11
+ open_graph_tags = {
12
+ title: object.meta_title,
13
+ description: object.meta_description,
14
+ url: object.canonical_url,
15
+ type: object.meta_type,
16
+ image: object.opengraph_image_url,
17
+ updated_time: object.updated_at.to_i
18
+ }
9
19
 
10
20
  set_meta_tags title: object.meta_title,
11
21
  description: object.meta_description,
12
22
  keywords: object.meta_keywords,
13
23
  canonical: object.canonical_url,
14
- og: open_graph_tags
24
+ og: open_graph_tags,
25
+ twitter: twitter_tags
15
26
  end
16
27
  end
@@ -4,8 +4,8 @@ module MenuHelper
4
4
  html = ''
5
5
 
6
6
  menu.links.each do |l|
7
- if l.target_blank
8
- html << link_to(l.title, l.url, _target: '_blank')
7
+ if l.new_tab?
8
+ html << link_to(l.title, l.url, target: '_blank')
9
9
 
10
10
  else
11
11
  html << link_to(l.title, l.url)
@@ -7,8 +7,13 @@ class MenuLink
7
7
  ## Attributes
8
8
  field :title
9
9
  field :url
10
- field :target_blank, type: Boolean, default: false
10
+ field :force_new_tab, type: Boolean, default: false
11
11
 
12
12
  ## Relations
13
13
  embedded_in :menu, class_name: 'Menu'
14
+
15
+ ## Helpers
16
+ def new_tab?
17
+ (!url.start_with?("/") || force_new_tab)
18
+ end
14
19
  end
@@ -50,7 +50,7 @@ class Redirect
50
50
  private
51
51
 
52
52
  def downcase_from_path!
53
- self.path_from.downcase!
53
+ path_from.strip!.downcase!
54
54
 
55
55
  return true
56
56
  end
@@ -0,0 +1,27 @@
1
+ module ActionDispatch::Routing
2
+ class Mapper
3
+ def mount_ants_redirects
4
+ get "/*id" => 'redirects#show', :constraints => ::Constraints::Redirects
5
+ end
6
+
7
+ def mount_ants_admin_users_crud
8
+ resources :admin_users, controller: "admin_users" do
9
+ member do
10
+ patch :update_password
11
+ end
12
+ end
13
+ end
14
+
15
+ def mount_ants_redirects_crud
16
+ resources :redirects, controller: "redirects"
17
+ end
18
+
19
+ def mount_ants_settings_crud
20
+ resources :settings_objects, controller: "settings_objects"
21
+ end
22
+
23
+ def mount_ants_menus_crud
24
+ resources :menus, controller: "menus"
25
+ end
26
+ end
27
+ end
data/lib/ants/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Ants
2
- VERSION = "0.3.5"
2
+ VERSION = "0.3.9"
3
3
  end
data/lib/ants.rb CHANGED
@@ -4,19 +4,18 @@ require 'devise'
4
4
 
5
5
  module Ants
6
6
  require 'ants/engine'
7
-
7
+ require 'ants/routing'
8
8
  require "mongoid/fake_criteria"
9
-
10
9
  require "concerns/ants/id"
11
10
  require "concerns/ants/featurable"
12
11
  require "concerns/ants/hideable"
13
12
  require "concerns/ants/orderable"
13
+ require "concerns/ants/orderable_reverse"
14
14
  require "concerns/ants/meta"
15
15
  require "concerns/ants/slug"
16
- require "concerns/ants/publication"
17
16
  require "concerns/ants/sorted_relations"
18
17
  require "concerns/ants/versions"
18
+ require "concerns/ants/scheduled"
19
19
  require "concerns/ants/content"
20
-
21
20
  require "constraints/redirects"
22
- end
21
+ end
@@ -1,7 +1,6 @@
1
1
  module Ants
2
2
  module Content
3
3
  extend ActiveSupport::Concern
4
-
5
4
  included do
6
5
  include Mongoid::Document
7
6
  include Mongoid::Timestamps
@@ -10,6 +9,7 @@ module Ants
10
9
  include Ants::Slug
11
10
  include Ants::Hideable
12
11
  include Ants::Meta
12
+ include Ants::Scheduled
13
13
 
14
14
  ## Attributes
15
15
  field :title
@@ -49,7 +49,7 @@ module Ants
49
49
  def opengraph_image_url
50
50
  url = _opengraph_image_url.presence
51
51
  if url
52
- if !url.include?('//')
52
+ if !url.include?('//') && Rails.env.production?
53
53
  "#{protocole}#{host}#{url}"
54
54
  else
55
55
  url
@@ -1,43 +1,33 @@
1
1
  module Ants
2
2
  module Featurable
3
3
  extend ActiveSupport::Concern
4
-
5
4
  included do
6
- # attributes
5
+ ## Attributes
7
6
  field :featured, type: Boolean, default: false
8
7
 
9
- # scopes
8
+ ## Scopes
10
9
  scope :featured, -> { where(featured: true) }
11
10
  scope :not_featured, -> { where(featured: false) }
12
11
 
13
- # indexes
12
+ ## Indexes
14
13
  index({ featured: 1 })
15
14
 
16
-
17
- # helpers
15
+ ## Helpers
18
16
  def featured?
19
17
  self.featured
20
18
  end
21
19
 
22
-
23
20
  def set_featured!
24
21
  return if self.featured?
25
22
  self.featured = true
26
23
  self.save!
27
24
  end
28
25
 
29
-
30
26
  def unset_featured!
31
27
  return unless self.featured?
32
28
  self.featured = false
33
29
  self.save!
34
30
  end
35
-
36
-
37
31
  end
38
32
  end
39
33
  end
40
-
41
-
42
-
43
-
@@ -1,33 +1,22 @@
1
- # ==========================================================================
2
- #
1
+ # =============================================================================
3
2
  # IMPORTANT: this default value raises "stack level too deep" if concern is
4
3
  # included for existing objects, to fix issue update _position
5
4
  # value for all objects like this:
6
5
  #
7
6
  # > ModelClass.all.set(_position: 1000)
8
- #
9
- # ==========================================================================
10
-
7
+ # =============================================================================
11
8
  module Ants
12
9
  module Orderable
13
10
  extend ActiveSupport::Concern
14
-
15
11
  included do
16
-
17
- # attributes
12
+ ## Attributes
18
13
  field :_position, type: Float, default: -> { (self.class.all.last.try(:_position) || 1000) + 10 }
19
14
 
20
- # scopes
15
+ ## Scopes
21
16
  default_scope -> { order_by(_position: :asc) }
22
17
 
23
- # helpers
18
+ ## Indexes
24
19
  index({ _position: 1 })
25
-
26
-
27
20
  end
28
21
  end
29
22
  end
30
-
31
-
32
-
33
-
@@ -0,0 +1,24 @@
1
+ # =============================================================================
2
+ # IMPORTANT: this default value raises "stack level too deep" if concern is
3
+ # included for existing objects, to fix issue update _position
4
+ # value for all objects like this:
5
+ #
6
+ # > ModelClass.all.set(_position: 1000)
7
+ # =============================================================================
8
+ module Ants
9
+ module OrderableReverse
10
+ extend ActiveSupport::Concern
11
+ included do
12
+ ## Attributes
13
+ field :_position, type: Float, default: -> {
14
+ (self.class.all.first.try(:_position) || 1000) + 10
15
+ }
16
+
17
+ ## Scopes
18
+ default_scope -> { desc(:_position) }
19
+
20
+ ## Indexes
21
+ index({ _position: -1 })
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,17 @@
1
+ module Ants
2
+ module Scheduled
3
+ extend ActiveSupport::Concern
4
+ included do
5
+ ## Attributes
6
+ field :published_at, type: DateTime
7
+
8
+ ## Scopes
9
+ default_scope -> { desc(:published_at) }
10
+ scope :scheduled, -> { where(:published_at.gt => Time.zone.now) }
11
+ scope :published, -> { where( :published_at.lte => Time.zone.now) }
12
+
13
+ ## Indexes
14
+ index published_at: -1
15
+ end
16
+ end
17
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ants
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.5
4
+ version: 0.3.9
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alexander Kravets
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-12-03 00:00:00.000000000 Z
11
+ date: 2015-12-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: mongoid
@@ -155,6 +155,7 @@ files:
155
155
  - ants.gemspec
156
156
  - app/assets/javascripts/ants.coffee
157
157
  - app/assets/javascripts/ants/admin_users.coffee
158
+ - app/assets/javascripts/ants/content.coffee
158
159
  - app/assets/javascripts/ants/menu.coffee
159
160
  - app/assets/javascripts/ants/meta.coffee
160
161
  - app/assets/javascripts/ants/profile.coffee
@@ -162,9 +163,10 @@ files:
162
163
  - app/assets/javascripts/ants/settings.coffee
163
164
  - app/assets/javascripts/ants/slug.coffee
164
165
  - app/assets/stylesheets/ants.scss
166
+ - app/assets/stylesheets/ants/content.scss
165
167
  - app/assets/stylesheets/ants/header.scss
168
+ - app/assets/stylesheets/ants/menu.scss
166
169
  - app/assets/stylesheets/ants/profile.scss
167
- - app/assets/stylesheets/ants/redirects.scss
168
170
  - app/assets/stylesheets/ants/settings.scss
169
171
  - app/controllers/admin/admin_users_controller.rb
170
172
  - app/controllers/admin/menus_controller.rb
@@ -182,6 +184,7 @@ files:
182
184
  - app/views/ants/_profile.html.erb
183
185
  - lib/ants.rb
184
186
  - lib/ants/engine.rb
187
+ - lib/ants/routing.rb
185
188
  - lib/ants/version.rb
186
189
  - lib/concerns/ants/content.rb
187
190
  - lib/concerns/ants/featurable.rb
@@ -189,7 +192,8 @@ files:
189
192
  - lib/concerns/ants/id.rb
190
193
  - lib/concerns/ants/meta.rb
191
194
  - lib/concerns/ants/orderable.rb
192
- - lib/concerns/ants/publication.rb
195
+ - lib/concerns/ants/orderable_reverse.rb
196
+ - lib/concerns/ants/scheduled.rb
193
197
  - lib/concerns/ants/slug.rb
194
198
  - lib/concerns/ants/sorted_relations.rb
195
199
  - lib/concerns/ants/versions.rb
@@ -1,12 +0,0 @@
1
- // .redirects {
2
- // .item-title {
3
- // line-height: 1.5em;
4
- // }
5
- // .item-subtitle {
6
- // @include position(relative, -20px null null null);
7
- // float: right;
8
- // }
9
- // .item.has-subtitle {
10
- // padding: .6em 1em .8em;
11
- // }
12
- // }
@@ -1,79 +0,0 @@
1
- module Ants
2
- module Publication
3
- extend ActiveSupport::Concern
4
-
5
- included do
6
- include Mongoid::Timestamps
7
-
8
- include Ants::Id
9
- include Ants::Featurable
10
- include Ants::Orderable
11
- include Ants::Slug
12
- include Ants::Meta
13
-
14
- # attributes
15
- field :title
16
- field :draft, type: Boolean, default: false
17
- field :published_at, type: DateTime, default: -> { DateTime.now }
18
-
19
- # slug
20
- slug :title
21
-
22
- # validations
23
- validates_presence_of :title, :published_at
24
-
25
- # scopes
26
- scope :drafts, -> { where(draft: true) }
27
- scope :ready_to_publish, -> { where(draft: false) }
28
- scope :scheduled, -> { ready_to_publish.where(:published_at.gt => Time.zone.now) }
29
- scope :published, -> { ready_to_publish.where(:published_at.lte => Time.zone.now) }
30
- # override featured scope set by Ants::Featured to add ordering by _position
31
- scope :featured, -> { unscoped.published.where(featured: true).asc(:_position) }
32
- scope :featured_first, -> { unscoped.desc(:featured).asc(:_position).desc(:published_at) }
33
- # override default_scope set by Ants::Orderable
34
- default_scope -> { desc(:published_at).desc(:created_at) }
35
-
36
- # indexes @TODO: verify if these indexes are required
37
- index({ featured: -1, _position: 1, published_at: -1 }) # featured first
38
- index({ featured: -1, _position: 1 }) # featured
39
- index({ published_at: -1, created_at: -1 }) # default
40
-
41
-
42
- # helpers
43
- def draft?
44
- self.draft
45
- end
46
-
47
-
48
- def published?
49
- ! draft? && published_at <= Time.zone.now
50
- end
51
-
52
-
53
- def scheduled?
54
- ! draft? && published_at > Time.zone.now
55
- end
56
-
57
-
58
- def _list_item_title
59
- title
60
- end
61
-
62
-
63
- def _list_item_subtitle
64
- published_at.strftime("%B %d, %Y @ %l:%M %P")
65
- end
66
-
67
-
68
- def meta_title
69
- _meta_title.present || title
70
- end
71
-
72
-
73
- end
74
- end
75
- end
76
-
77
-
78
-
79
-