ants 0.3.5 → 0.3.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml 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
-