# frozen_string_literal: true # Redmine - project management software # Copyright (C) 2006-2020 Jean-Philippe Lang # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. module Redmine module MenuManager # @private class MenuError < StandardError end module MenuController def self.included(base) base.class_attribute :main_menu base.main_menu = true base.extend(ClassMethods) end module ClassMethods @@menu_items = Hash.new {|hash, key| hash[key] = {:default => key, :actions => {}}} mattr_accessor :menu_items # Set the menu item name for a controller or specific actions # Examples: # * menu_item :tickets # => sets the menu name to :tickets for the whole controller # * menu_item :tickets, :only => :list # => sets the menu name to :tickets for the 'list' action only # * menu_item :tickets, :only => [:list, :show] # => sets the menu name to :tickets for 2 actions only # # The default menu item name for a controller is controller_name by default # Eg. the default menu item name for ProjectsController is :projects def menu_item(id, options = {}) if actions = options[:only] actions = [] << actions unless actions.is_a?(Array) actions.each {|a| menu_items[controller_name.to_sym][:actions][a.to_sym] = id} else menu_items[controller_name.to_sym][:default] = id end end end def menu_items self.class.menu_items end def current_menu(project) if project && !project.new_record? :project_menu elsif self.class.main_menu :application_menu end end # Returns the menu item name according to the current action def current_menu_item @current_menu_item ||= menu_items[controller_name.to_sym][:actions][action_name.to_sym] || menu_items[controller_name.to_sym][:default] end # Redirects user to the menu item # Returns false if user is not authorized def redirect_to_menu_item(name) redirect_to_project_menu_item(nil, name) end # Redirects user to the menu item of the given project # Returns false if user is not authorized def redirect_to_project_menu_item(project, name) menu = project.nil? ? :application_menu : :project_menu item = Redmine::MenuManager.items(menu).detect {|i| i.name.to_s == name.to_s} if item && item.allowed?(User.current, project) url = item.url url = {item.param => project}.merge(url) if project redirect_to url return true end false end end module MenuHelper # Returns the current menu item name def current_menu_item controller.current_menu_item end # Renders the application main menu def render_main_menu(project) if menu_name = controller.current_menu(project) render_menu(menu_name, project) end end def display_main_menu?(project) menu_name = controller.current_menu(project) menu_name.present? && Redmine::MenuManager.items(menu_name).children.present? end def render_menu(menu, project=nil) links = [] menu_items_for(menu, project) do |node| links << render_menu_node(node, project) end links.empty? ? nil : content_tag('ul', links.join.html_safe) end def render_menu_node(node, project=nil) if node.children.present? || !node.child_menus.nil? return render_menu_node_with_children(node, project) else caption, url, selected = extract_node_details(node, project) return content_tag('li', render_single_menu_node(node, caption, url, selected)) end end def render_menu_node_with_children(node, project=nil) caption, url, selected = extract_node_details(node, project) html = [].tap do |html| html << '
  • ' # Parent html << render_single_menu_node(node, caption, url, selected) # Standard children standard_children_list = "".html_safe.tap do |child_html| node.children.each do |child| child_html << render_menu_node(child, project) if allowed_node?(child, User.current, project) end end html << content_tag(:ul, standard_children_list, :class => 'menu-children') unless standard_children_list.empty? # Unattached children unattached_children_list = render_unattached_children_menu(node, project) html << content_tag(:ul, unattached_children_list, :class => 'menu-children unattached') unless unattached_children_list.blank? html << '
  • ' end return html.join("\n").html_safe end # Returns a list of unattached children menu items def render_unattached_children_menu(node, project) return nil unless node.child_menus "".html_safe.tap do |child_html| unattached_children = node.child_menus.call(project) # Tree nodes support #each so we need to do object detection if unattached_children.is_a? Array unattached_children.each do |child| child_html << content_tag(:li, render_unattached_menu_item(child, project)) if allowed_node?(child, User.current, project) end else raise MenuError, ":child_menus must be an array of MenuItems" end end end def render_single_menu_node(item, caption, url, selected) options = item.html_options(:selected => selected) # virtual nodes are only there for their children to be displayed in the menu # and should not do anything on click, except if otherwise defined elsewhere if url.blank? url = '#' options.reverse_merge!(:onclick => 'return false;') end link_to(h(caption), url, options) end def render_unattached_menu_item(menu_item, project) raise MenuError, ":child_menus must be an array of MenuItems" unless menu_item.is_a? MenuItem if menu_item.allowed?(User.current, project) link_to(menu_item.caption, menu_item.url, menu_item.html_options) end end def menu_items_for(menu, project=nil) items = [] Redmine::MenuManager.items(menu).root.children.each do |node| if node.allowed?(User.current, project) if block_given? yield node else items << node # TODO: not used? end end end return block_given? ? nil : items end def extract_node_details(node, project=nil) item = node url = case item.url when Hash project.nil? ? item.url : {item.param => project}.merge(item.url) when Symbol if project send(item.url, project) else send(item.url) end else item.url end caption = item.caption(project) return [caption, url, (current_menu_item == item.name)] end # See MenuItem#allowed? def allowed_node?(node, user, project) raise MenuError, ":child_menus must be an array of MenuItems" unless node.is_a? MenuItem node.allowed?(user, project) end end class << self def map(menu_name) @items ||= {} mapper = Mapper.new(menu_name.to_sym, @items) if block_given? yield mapper else mapper end end def items(menu_name) @items[menu_name.to_sym] || MenuNode.new(:root, {}) end end class Mapper attr_reader :menu, :menu_items def initialize(menu, items) items[menu] ||= MenuNode.new(:root, {}) @menu = menu @menu_items = items[menu] end # Adds an item at the end of the menu. Available options: # * param: the parameter name that is used for the project id (default is :id) # * if: a Proc that is called before rendering the item, the item is displayed only if it returns true # * caption that can be: # * a localized string Symbol # * a String # * a Proc that can take the project as argument # * before, after: specify where the menu item should be inserted (eg. :after => :activity) # * parent: menu item will be added as a child of another named menu (eg. :parent => :issues) # * children: a Proc that is called before rendering the item. The Proc should return an array of MenuItems, which will be added as children to this item. # eg. :children => Proc.new {|project| [Redmine::MenuManager::MenuItem.new(...)] } # * last: menu item will stay at the end (eg. :last => true) # * html_options: a hash of html options that are passed to link_to def push(name, url, options={}) options = options.dup if options[:parent] subtree = self.find(options[:parent]) if subtree target_root = subtree else target_root = @menu_items.root end else target_root = @menu_items.root end # menu item position if first = options.delete(:first) target_root.prepend(MenuItem.new(name, url, options)) elsif before = options.delete(:before) if exists?(before) target_root.add_at(MenuItem.new(name, url, options), position_of(before)) else target_root.add(MenuItem.new(name, url, options)) end elsif after = options.delete(:after) if exists?(after) target_root.add_at(MenuItem.new(name, url, options), position_of(after) + 1) else target_root.add(MenuItem.new(name, url, options)) end elsif options[:last] # don't delete, needs to be stored target_root.add_last(MenuItem.new(name, url, options)) else target_root.add(MenuItem.new(name, url, options)) end end # Removes a menu item def delete(name) if found = self.find(name) @menu_items.remove!(found) end end # Checks if a menu item exists def exists?(name) @menu_items.any? {|node| node.name == name} end def find(name) @menu_items.find {|node| node.name == name} end def position_of(name) @menu_items.each do |node| if node.name == name return node.position end end end end class MenuNode include Enumerable attr_accessor :parent attr_reader :last_items_count, :name def initialize(name, content = nil) @name = name @children = [] @last_items_count = 0 end def children if block_given? @children.each {|child| yield child} else @children end end # Returns the number of descendants + 1 def size @children.inject(1) {|sum, node| sum + node.size} end def each(&block) yield self children { |child| child.each(&block) } end # Adds a child at first position def prepend(child) add_at(child, 0) end # Adds a child at given position def add_at(child, position) raise "Child already added" if find {|node| node.name == child.name} @children = @children.insert(position, child) child.parent = self child end # Adds a child as last child def add_last(child) add_at(child, -1) @last_items_count += 1 child end # Adds a child def add(child) position = @children.size - @last_items_count add_at(child, position) end alias :<< :add # Removes a child def remove!(child) @children.delete(child) @last_items_count -= +1 if child && child.last child.parent = nil child end # Returns the position for this node in it's parent def position self.parent.children.index(self) end # Returns the root for this node def root root = self root = root.parent while root.parent root end end class MenuItem < MenuNode include Redmine::I18n attr_reader :name, :url, :param, :condition, :parent, :child_menus, :last, :permission def initialize(name, url, options={}) raise ArgumentError, "Invalid option :if for menu item '#{name}'" if options[:if] && !options[:if].respond_to?(:call) raise ArgumentError, "Invalid option :html for menu item '#{name}'" if options[:html] && !options[:html].is_a?(Hash) raise ArgumentError, "Cannot set the :parent to be the same as this item" if options[:parent] == name.to_sym raise ArgumentError, "Invalid option :children for menu item '#{name}'" if options[:children] && !options[:children].respond_to?(:call) @name = name @url = url @condition = options[:if] @permission = options[:permission] @permission ||= false if options.key?(:permission) @param = options[:param] || :id @caption = options[:caption] @html_options = options[:html] || {} # Adds a unique class to each menu item based on its name @html_options[:class] = [@html_options[:class], @name.to_s.dasherize].compact.join(' ') @parent = options[:parent] @child_menus = options[:children] @last = options[:last] || false super @name.to_sym end def caption(project=nil) if @caption.is_a?(Proc) c = @caption.call(project).to_s c = @name.to_s.humanize if c.blank? c else if @caption.nil? l_or_humanize(name, :prefix => 'label_') else @caption.is_a?(Symbol) ? l(@caption) : @caption end end end def html_options(options={}) if options[:selected] o = @html_options.dup o[:class] += ' selected' o else @html_options end end # Checks if a user is allowed to access the menu item by: # # * Checking the permission or the url target (project only) # * Checking the conditions of the item def allowed?(user, project) if url.blank? # this is a virtual node that is only there for its children to be diplayed in the menu # it is considered an allowed node if at least one of the children is allowed all_children = children all_children += child_menus.call(project) if child_menus return false unless all_children.detect{|child| child.allowed?(user, project) } elsif user && project if permission unless user.allowed_to?(permission, project) return false end elsif permission.nil? && url.is_a?(Hash) unless user.allowed_to?(url, project) return false end end end if condition && !condition.call(project) # Condition that doesn't pass return false end return true end end end end 40367/stable25'>backport/40367/stable25 Nextcloud server, a safe home for all your data: https://github.com/nextcloud/serverwww-data
    aboutsummaryrefslogtreecommitdiffstats
    path: root/apps/files_external/l10n/sv.js
    blob: 30facd487d6726f24ef0722809dc6ddfe96b4a23 (plain)
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167