Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Menus #1667

Merged
merged 9 commits into from
Nov 8, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion app/assets/javascripts/alchemy/alchemy.base.js.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ $.extend Alchemy,
Alchemy.setElementDirty $element
false

# Initializes all select tag with .alchemy_selectbox class as selectBoxIt instance
# Initializes all select tag with .alchemy_selectbox class as select2 instance
# Pass a jQuery scope to only init a subset of selectboxes.
SelectBox: (scope) ->
$("select.alchemy_selectbox", scope).select2
Expand Down
1 change: 1 addition & 0 deletions app/assets/stylesheets/alchemy/admin.scss
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
@import "alchemy/icons";
@import "alchemy/image_library";
@import "alchemy/labels";
@import "alchemy/nodes";
@import "alchemy/notices";
@import "alchemy/pagination";
@import "alchemy/preview_window";
Expand Down
11 changes: 6 additions & 5 deletions app/assets/stylesheets/alchemy/forms.scss
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ form {
float: right;
}

.input > .select2-container {
width: 100%;
}

> .autocomplete_tag_list {

.select2-container, .select2-choices {
Expand All @@ -49,11 +53,8 @@ form {
line-height: 16px;
}

&.select, &.grouped_select {

.select2-container {
margin: 4px 0;
}
.select2-container {
margin: 4px 0;
}

&.boolean {
Expand Down
154 changes: 154 additions & 0 deletions app/assets/stylesheets/alchemy/nodes.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
.nodes_tree.list {
margin: 2em 0;

&.sorting {
padding-top: 100px;

.page_icon {
cursor: move
}
}

.sitemap_node-level_0 {

> .node_name {
font-weight: bold;
}
}

.node_page,
.node_url {
width: 200px;
max-width: 45%;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;

> a {
overflow: hidden;
text-overflow: ellipsis;
max-width: 100%;

.external & {
max-width: 90%;
}
}
}

.node_page {
padding: 0 8px;
margin-left: auto;
}

.node_url {
display: flex;
align-items: center;
padding: 0 2*$default-padding;
white-space: nowrap;
background-color: $sitemap-info-background-color;
line-height: $sitemap-line-height;
font-size: $small-font-size;
@include border-right-radius($default-border-radius);

> i {
margin-left: auto;
padding-left: $default-padding;
}
}

.node_folder {
cursor: pointer;
}

ul {
margin: 0;
padding: 0;
}

li {
line-height: $sitemap-line-height;
padding-left: $default-padding;

li {
padding-left: $sitemap-line-height;
}
}
}

#node_filter_result {
display: none;
margin-left: 2*$default-margin;
}

.sitemap_node {
margin: 3*$default-margin 0;
transition: background-color $transition-duration;

&.highlight {
background-color: $sitemap-highlight-color;
}

&.no-match .sitemap_pagename_link {
color: $medium-gray;
}

&:hover {
background-color: $sitemap-page-hover-color;
border-radius: $default-border-radius;
}

.node_name {
display: flex;
justify-content: space-between;
@include border-left-radius($default-border-radius);
padding: 0 0 0 10px;
margin: 2px;
text-decoration: none;
overflow: hidden;
background-color: $sitemap-page-background-color;

&.without-status {
@include border-right-radius($default-border-radius);
}

&.inactive {
color: #656565;
}
}
}

.nodes_tree-left_images {
position: relative;
width: 32px;
line-height: $sitemap-line-height;
float: left;
padding: 0 2*$default-padding;
text-align: center;
}

.nodes_tree-right_tools {
height: $sitemap-line-height;
padding: 0 2*$default-padding;
float: right;

> a {
float: left;
width: $sitemap-line-height;
height: $sitemap-line-height;
line-height: $sitemap-line-height;
text-align: center;
margin: 0;

&.disabled .icon {
opacity: 0.25;
filter: grayscale(100%);
}
}

.icon.blank {
margin-left: 2px;
float: left;
margin-top: 3px;
margin-right: 3px;
}
}
4 changes: 4 additions & 0 deletions app/assets/stylesheets/alchemy/selects.scss
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@ select {
font-weight: normal;
text-align: left;

.select2-chosen {
overflow: visible;
}

.select2-arrow {
top: 0;
width: $form-field-height;
Expand Down
43 changes: 43 additions & 0 deletions app/controllers/alchemy/admin/nodes_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# frozen_string_literal: true

module Alchemy
tvdeyen marked this conversation as resolved.
Show resolved Hide resolved
module Admin
class NodesController < Admin::ResourcesController
def index
@root_nodes = Node.language_root_nodes
end

def new
@node = Node.new(
parent_id: params[:parent_id],
language: Language.current
)
end

def toggle
node = Node.find(params[:id])
node.update(folded: !node.folded)
if node.folded?
head :ok
else
render partial: 'node', collection: node.children.includes(:page, :children)
end
end

private

def resource_params
params.require(:node).permit(
:parent_id,
:language_id,
:page_id,
:name,
:url,
:title,
:nofollow,
:external
)
end
end
end
end
29 changes: 29 additions & 0 deletions app/helpers/alchemy/pages_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ def render_site_layout
end

# Renders the navigation.
# @deprecated
#
# It produces a html <ul><li></li></ul> structure with all necessary classes so you can produce every navigation the web uses today.
# I.E. dropdown-navigations, simple mainnavigations or even complex nested ones.
Expand Down Expand Up @@ -177,6 +178,33 @@ def render_navigation(options = {}, html_options = {})
pages: pages,
html_options: html_options
end
deprecate render_navigation: 'Create a menu and use render_menu instead', deprecator: Alchemy::Deprecation

# Renders a menu partial
#
# Menu partials are placed in the `app/views/alchemy/menus` folder
# Use the `rails g alchemy:menus` generator to create the partials
#
# @param [String] - Name of the menu
# @param [Hash] - A set of options available in your menu partials
def render_menu(name, options = {})
root_node = Alchemy::Node.roots.find_by(name: name)
if root_node.nil?
warning("Menu with name #{name} not found!")
return
end

options = {
node_partial_name: "#{root_node.view_folder_name}/node"
}.merge(options)

render(root_node, node: root_node, options: options)
rescue ActionView::MissingTemplate => e
warning <<~WARN
Menu partial not found for #{name}.
#{e}
WARN
end

# Renders navigation the children and all siblings of the given page (standard is the current page).
#
Expand Down Expand Up @@ -206,6 +234,7 @@ def render_subnavigation(options = {}, html_options = {})
return nil
end
end
deprecate :render_subnavigation, deprecator: Alchemy::Deprecation

# Returns true if page is in the active branch
def page_active?(page)
Expand Down
47 changes: 47 additions & 0 deletions app/models/alchemy/node.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# frozen_string_literal: true

module Alchemy
class Node < BaseRecord
VALID_URL_REGEX = /\A(\/|\D[a-z\+\d\.\-]+:)/
tvdeyen marked this conversation as resolved.
Show resolved Hide resolved

acts_as_nested_set scope: 'language_id', touch: true
stampable stamper_class_name: Alchemy.user_class_name

belongs_to :language, class_name: 'Alchemy::Language'
belongs_to :page, class_name: 'Alchemy::Page', optional: true, inverse_of: :nodes

validates :url, format: { with: VALID_URL_REGEX }, unless: -> { url.nil? }

# Returns the name
#
# Either the value is stored in the database
# or, if attached, the values comes from a page.
def name
read_attribute(:name).presence || page&.name
end

class << self
# Returns all root nodes for current language
def language_root_nodes
raise 'No language found' if Language.current.nil?
roots.where(language_id: Language.current.id)
end
end

# Returns the url
#
# Either the value is stored in the database, aka. an external url.
# Or, if attached, the values comes from a page.
def url
page && "/#{page.urlname}" || read_attribute(:url).presence
end

def to_partial_path
"#{view_folder_name}/wrapper"
end

def view_folder_name
"alchemy/menus/#{name.parameterize.underscore}"
end
end
end
Loading