diff --git a/Vendorfile b/Vendorfile
index 88f999a40..c1242beb7 100644
--- a/Vendorfile
+++ b/Vendorfile
@@ -5,6 +5,7 @@ folder 'vendor/assets' do
folder 'bootstrap' do
file 'bootstrap.tooltip.js', 'https://raw.github.com/twbs/bootstrap/v2.3.2/js/bootstrap-tooltip.js'
+ file 'bootstrap.dropdown.js', 'https://raw.github.com/twbs/bootstrap/v2.3.2/js/bootstrap-dropdown.js'
end
folder 'leaflet' do
diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js
index a33e281ce..2b8bc5d26 100644
--- a/app/assets/javascripts/application.js
+++ b/app/assets/javascripts/application.js
@@ -4,6 +4,7 @@
//= require jquery.cookie
//= require jquery.throttle-debounce
//= require bootstrap.tooltip
+//= require bootstrap.dropdown
//= require augment
//= require osm
//= require leaflet
@@ -16,7 +17,6 @@
//= require oauth
//= require piwik
//= require map
-//= require menu
//= require sidebar
//= require richtext
//= require geocoder
@@ -95,26 +95,25 @@ function updatelinks(loc, zoom, layers, bounds, object) {
}
link.href = href;
-
- var minzoom = $(link).data("minzoom");
- if (minzoom) {
- var name = link.id.replace(/anchor$/, "");
- $(link).off("click.minzoom");
- if (zoom >= minzoom) {
- $(link)
- .attr("title", I18n.t("javascripts.site." + name + "_tooltip"))
- .removeClass("disabled");
- } else {
- $(link)
- .attr("title", I18n.t("javascripts.site." + name + "_disabled_tooltip"))
- .addClass("disabled")
- .on("click.minzoom", function () {
- alert(I18n.t("javascripts.site." + name + "_zoom_alert"));
- return false;
- });
- }
- }
});
+
+ var editDisabled = zoom < 13;
+ $('#edit_tab')
+ .tooltip({placement: 'bottom'})
+ .off('click.minzoom')
+ .on('click.minzoom', function() { return !editDisabled; })
+ .toggleClass('disabled', editDisabled)
+ .attr('data-original-title', editDisabled ?
+ I18n.t('javascripts.site.edit_disabled_tooltip') : '');
+
+ var historyDisabled = zoom < 11;
+ $('#history_tab')
+ .tooltip({placement: 'bottom'})
+ .off('click.minzoom')
+ .on('click.minzoom', function() { return !historyDisabled; })
+ .toggleClass('disabled', historyDisabled)
+ .attr('data-original-title', historyDisabled ?
+ I18n.t('javascripts.site.history_disabled_tooltip') : '');
}
// generate a cookie-safe string of map state
diff --git a/app/assets/javascripts/browse.js b/app/assets/javascripts/browse.js
index 5d2412183..11818a171 100644
--- a/app/assets/javascripts/browse.js
+++ b/app/assets/javascripts/browse.js
@@ -23,7 +23,7 @@ $(document).ready(function () {
}).addTo(map);
$("#loading").hide();
- $("#browse_map .geolink").show();
+ $("#browse_map .secondary-actions").show();
$("a[data-editor=remote]").click(function () {
return remoteEditHandler(bbox);
@@ -41,7 +41,7 @@ $(document).ready(function () {
bbox = map.getBounds();
$("#loading").hide();
- $("#browse_map .geolink").show();
+ $("#browse_map .secondary-actions").show();
$("a[data-editor=remote]").click(function () {
return remoteEditHandler(bbox);
@@ -61,7 +61,7 @@ $(document).ready(function () {
zoom: true,
callback: function(extent) {
$("#loading").hide();
- $("#browse_map .geolink").show();
+ $("#browse_map .secondary-actions").show();
if (extent) {
$("a.bbox[data-editor=remote]").click(function () {
@@ -82,7 +82,4 @@ $(document).ready(function () {
}
});
}
-
- createMenu("area_edit", "area_edit_menu", "right");
- createMenu("object_edit", "object_edit_menu", "right");
});
diff --git a/app/assets/javascripts/menu.js b/app/assets/javascripts/menu.js
deleted file mode 100644
index a01fc39cc..000000000
--- a/app/assets/javascripts/menu.js
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Open a menu.
- */
-function openMenu(anchor, menu, align) {
- var anchorPosition = anchor.offset();
- var offset;
-
- if (align == "left") {
- offset = 0;
- } else if (align == "right") {
- offset = menu.outerWidth() - anchor.outerWidth();
- }
-
- menu.show();
-
- menu.offset({
- top: anchorPosition.top + anchor.outerHeight(),
- left: anchorPosition.left - offset
- });
-}
-
-/*
- * Setup a menu, triggered by hovering over an anchor for a given time.
- */
-function createMenu(anchorid, menuid, align) {
- var $anchor = $("#" + anchorid);
- var $arrow = $("#" + anchorid + " .menuicon");
- var $menu = $("#" + menuid);
- var $page = $(":not(#" + menuid + ", #" + anchorid + ")");
-
- function hide() {
- $menu.hide();
- $page.off("click", hide);
- }
-
- $arrow.click(function(e) {
- if ($anchor.is(":not(.disabled)")) {
- e.stopPropagation();
- e.preventDefault();
- if ($menu.is(":visible")) {
- $menu.hide();
- $page.off("click", hide);
- } else {
- openMenu($anchor, $menu.show(), align);
- $page.on("click", hide);
- }
- }
- });
-}
diff --git a/app/assets/stylesheets/common.css.scss b/app/assets/stylesheets/common.css.scss
index 0e03da6de..c2f642edc 100644
--- a/app/assets/stylesheets/common.css.scss
+++ b/app/assets/stylesheets/common.css.scss
@@ -202,6 +202,7 @@ h6:first-child {
.icon.close { background-position: -200px 0; }
.icon.check { background-position: -220px 0; }
.icon.note { background-position: -240px 0; }
+.icon.gear { background-position: -260px 0; }
/* Rules for links */
@@ -472,7 +473,11 @@ a.donate {
height: 30px;
border-bottom: 1px solid #ccc;
background: white;
- z-index: 100;
+ z-index: 1001;
+
+ .caret {
+ margin-top: 10px;
+ }
}
.site-edit #top-bar,
@@ -486,49 +491,57 @@ a.donate {
#tabnav {
height: 29px;
- margin-bottom:0;
- overflow: hidden;
- li {
- display: inline;
- }
- a, a:link, a:visited {
+ margin-bottom: 0;
+
+ > li {
float: left;
+
+ > * {
+ padding: 3px $lineheight/2;
+ }
+ }
+
+ a.tab {
+ display: inline-block;
font-weight: bold;
- padding: 3px $lineheight/2;
text-decoration: none;
color: #333;
- float: left;
- margin-right: 1px;
+
-webkit-transition: color 200ms ease-in;
-moz-transition: color 200ms ease-in;
-o-transition: color 200ms ease-in;
transition: color 200ms ease-in;
+
+ &:hover {
+ text-decoration: underline;
+ }
+ }
+
+ .disabled a {
+ color: #ccc;
+ cursor: default;
+
+ &:hover {
+ text-decoration: none;
+ }
+
+ .caret {
+ border-top-color: #ccc;
+ }
+ }
+
+ .dropdown {
+ height: 29px;
}
}
-.site-index #tabnav a#viewanchor,
-.site-edit #tabnav a#editanchor,
-.changeset-list #tabnav a#historyanchor {
- border-bottom: 1px solid #aaa;
+.site-index #view_tab,
+.site-edit #edit_tab,
+.changeset-list #history_tab {
background: #9ed485;
color: #000;
}
-#tabnav a:link:hover, #tabnav a:visited:hover {
- text-decoration: underline;
-}
-
-#tabnav a:link.disabled,
-#tabnav a:visited.disabled,
-#tabnav a:link:hover.disabled,
-#tabnav a:visited:hover.disabled {
- color: #ccc;
- cursor: default;
- &:hover {
- text-decoration: none;
- }
-}
-
/* Utility for styling notification numbers */
.count-number {
@@ -544,12 +557,52 @@ a.donate {
#greeting {
float: right;
- padding-top: 3px;
- margin-right: $lineheight/4;
-}
+ height: 100%;
-.greeting-bar-unread {
- font-weight: bold;
+ &.secondary-actions {
+ padding: 3px $lineheight/2;
+ }
+
+ &.dropdown {
+ background-color: #EEE;
+ &:hover {
+ background-color: #CCC;
+ }
+ }
+
+ img {
+ vertical-align: top;
+ border-radius: 2px 0 0 2px;
+ margin-right: 5px;
+ }
+
+ #inboxanchor {
+ display: inline-block;
+ position: relative;
+ height: 20px;
+ top: -2px;
+ margin: 0 2px 0 0;
+ padding: 0 5px 0 0;
+ border-radius: 2px;
+ }
+
+ .dropdown-toggle {
+ display: block;
+ padding: 3px 7px;
+ color: #000;
+ text-decoration: none;
+ }
+
+ .dropdown-menu {
+ left: auto;
+ right: 0;
+
+ .count-number {
+ float: right;
+ padding: 0 5px;
+ margin: 0;
+ }
+ }
}
/* Rules for the message shown in place of the map when javascript is disabled */
@@ -1292,11 +1345,8 @@ ul.results-list li { border-bottom: 1px solid #ccc; }
}
}
-#browse_map .geolink {
- display: none;
-}
-
#browse_map .secondary-actions {
+ display: none;
margin-bottom: $lineheight/2;
}
@@ -1891,7 +1941,7 @@ ul.secondary-actions {
display: inline-block;
margin-right: 60px;
}
- li {
+ > li {
display: block;
float: left;
list-style: none;
@@ -1906,6 +1956,10 @@ ul.secondary-actions {
margin-right: 0px;
}
}
+ .dropdown-menu {
+ left: auto;
+ right: 0;
+ }
}
/* Utility for managing inner content areas */
@@ -2292,6 +2346,134 @@ a.button {
background: #fff;
}
+/* Rules for dropdown menus */
+
+.dropdown {
+ position: relative;
+}
+
+.dropdown-toggle {
+ *margin-bottom: -3px;
+}
+
+.dropdown-toggle:active,
+.open .dropdown-toggle {
+ outline: 0;
+}
+
+.caret {
+ display: inline-block;
+ width: 0;
+ height: 0;
+ vertical-align: top;
+ border-top: 4px solid #000000;
+ border-right: 4px solid transparent;
+ border-left: 4px solid transparent;
+ content: "";
+}
+
+.dropdown .caret {
+ margin-top: 8px;
+ margin-left: 2px;
+}
+
+.dropdown-menu {
+ position: absolute;
+ top: 100%;
+ left: 0;
+ z-index: 1000;
+ display: none;
+ float: left;
+ min-width: 160px;
+ padding: 5px 0;
+ margin: 0;
+ list-style: none;
+ background-color: #ffffff;
+ border: 1px solid #ccc;
+ *border-right-width: 2px;
+ *border-bottom-width: 2px;
+ -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);
+ -moz-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);
+ box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);
+ -webkit-background-clip: padding-box;
+ -moz-background-clip: padding;
+ background-clip: padding-box;
+}
+
+.dropdown-menu.pull-right {
+ right: 0;
+ left: auto;
+}
+
+.dropdown-menu .divider {
+ *width: 100%;
+ height: 1px;
+ margin: 9px 1px;
+ *margin: -5px 0 5px;
+ overflow: hidden;
+ background-color: #e5e5e5;
+ border-bottom: 1px solid #ffffff;
+}
+
+.dropdown-menu > li > a {
+ display: block;
+ padding: 3px 10px;
+ clear: both;
+ font-weight: normal;
+ line-height: 20px;
+ color: #333333;
+ white-space: nowrap;
+}
+
+.dropdown-menu > li > a:hover,
+.dropdown-menu > li > a:focus,
+.dropdown-submenu:hover > a,
+.dropdown-submenu:focus > a {
+ color: #ffffff;
+ text-decoration: none;
+ background-color: #0081c2;
+}
+
+.dropdown-menu > .active > a,
+.dropdown-menu > .active > a:hover,
+.dropdown-menu > .active > a:focus {
+ color: #ffffff;
+ text-decoration: none;
+ background-color: #0081c2;
+ outline: 0;
+}
+
+.dropdown-menu > .disabled > a,
+.dropdown-menu > .disabled > a:hover,
+.dropdown-menu > .disabled > a:focus {
+ color: #999999;
+}
+
+.dropdown-menu > .disabled > a:hover,
+.dropdown-menu > .disabled > a:focus {
+ text-decoration: none;
+ cursor: default;
+ background-color: transparent;
+ background-image: none;
+}
+
+.open {
+ *z-index: 1000;
+}
+
+.open > .dropdown-menu {
+ display: block;
+}
+
+.dropdown-backdrop {
+ position: fixed;
+ top: 0;
+ right: 0;
+ bottom: 0;
+ left: 0;
+ z-index: 990;
+}
+
/* Rules for the "Welcome" page */
.site-welcome {
.center {
diff --git a/app/assets/stylesheets/print.css b/app/assets/stylesheets/print.css
index a74bc27fd..84efa0e2e 100644
--- a/app/assets/stylesheets/print.css
+++ b/app/assets/stylesheets/print.css
@@ -4,7 +4,6 @@
#tabnav,
#sidebar,
#permalink,
-#editmenu,
.leaflet-control {
display: none;
}
diff --git a/app/assets/stylesheets/small.css.scss b/app/assets/stylesheets/small.css.scss
index 3f9088311..419abeac4 100644
--- a/app/assets/stylesheets/small.css.scss
+++ b/app/assets/stylesheets/small.css.scss
@@ -84,13 +84,6 @@ h2, h3, h4 {
/* Rules for greeting bar in the top right corner */
-#greeting {
- position: absolute;
- right: 0;
- top: 0;
- background: none;
-}
-
#browse_map ul.secondary-actions {
float: right;
font-size: 10px;
@@ -267,4 +260,4 @@ p.search_results_entry {
.aside {
display: none;
}
-}
\ No newline at end of file
+}
diff --git a/app/views/browse/_map.html.erb b/app/views/browse/_map.html.erb
index 9b82753fb..ed703665d 100644
--- a/app/views/browse/_map.html.erb
+++ b/app/views/browse/_map.html.erb
@@ -35,28 +35,26 @@
<%= content_tag "div", "", :id => "small_map", :data => data %>
<%= t 'browse.map.loading' %>
-
- -
- <% if map.instance_of? Note -%>
- <%= link_to t("browse.map.larger.area"),
- root_path(:notes => "yes"),
- :id => "area_larger_map",
- :class => "geolink bbox" %>
- <% else -%>
- <%= link_to t("browse.map.larger.area"),
- root_path(:box => "yes"),
- :id => "area_larger_map",
- :class => "geolink bbox" %>
- <% end -%>
-
- -
- <%= link_to h(t("browse.map.edit.area")) + content_tag(:span, "▼", :class => "menuicon"),
- edit_path,
- :id => "area_edit",
- :data => { :editor => preferred_editor },
- :class => "geolink bbox" %>
-
-
+
+ -
+ <% if map.instance_of? Note -%>
+ <%= link_to t("browse.map.larger.area"),
+ root_path(:notes => "yes"),
+ :id => "area_larger_map",
+ :class => "geolink bbox" %>
+ <% else -%>
+ <%= link_to t("browse.map.larger.area"),
+ root_path(:box => "yes"),
+ :id => "area_larger_map",
+ :class => "geolink bbox" %>
+ <% end -%>
+
+ -
+ <%= render :partial => 'layouts/edit_menu',
+ :locals => { :link_text => t("browse.map.edit.area"),
+ :link_class => 'bbox' } %>
+
+
<% unless map.instance_of? Changeset %>
@@ -67,11 +65,9 @@
:class => "geolink object" %>
-
- <%= link_to h(t("browse.map.edit." + map.class.to_s.downcase)) + content_tag(:span, "▼", :class => "menuicon"),
- edit_path,
- :id => "object_edit",
- :data => { :editor => preferred_editor },
- :class => "geolink object" %>
+ <%= render :partial => 'layouts/edit_menu',
+ :locals => { :link_text => t("browse.map.edit." + map.class.to_s.downcase),
+ :link_class => 'object' } %>
<% end %>
@@ -80,25 +76,3 @@
<%= t 'browse.map.deleted' %>
<% end %>
-
-
-
-
diff --git a/app/views/layouts/_edit_menu.html.erb b/app/views/layouts/_edit_menu.html.erb
new file mode 100644
index 000000000..78c5dbb65
--- /dev/null
+++ b/app/views/layouts/_edit_menu.html.erb
@@ -0,0 +1,18 @@
+
diff --git a/app/views/layouts/_inbox.html.erb b/app/views/layouts/_inbox.html.erb
index fcaa5ae64..d4054dfaf 100644
--- a/app/views/layouts/_inbox.html.erb
+++ b/app/views/layouts/_inbox.html.erb
@@ -1,13 +1,3 @@
-<%=
- link_to(
- t("layouts.inbox_html",
- :count => @user.new_messages.size > 0 ?
- content_tag(
- :span, @user.new_messages.size, :class => "count-number"
- ) :
- ""
- ),
- inbox_path(:display_name => @user.display_name),
- :id => "inboxanchor"
- )
-%>
+
+ <%= user_thumbnail_tiny(@user, :size => 20, :width => 20, :height => 20) %><%= @user.new_messages.size %>
+
\ No newline at end of file
diff --git a/app/views/layouts/_user_menu.html.erb b/app/views/layouts/_user_menu.html.erb
new file mode 100644
index 000000000..ab7d955da
--- /dev/null
+++ b/app/views/layouts/_user_menu.html.erb
@@ -0,0 +1,28 @@
+
diff --git a/app/views/layouts/site.html.erb b/app/views/layouts/site.html.erb
index 3deffdde2..12b5b82c5 100644
--- a/app/views/layouts/site.html.erb
+++ b/app/views/layouts/site.html.erb
@@ -96,53 +96,25 @@
-
- <% if @user and @user.id %>
- - <%=link_to h(@user.display_name), user_path(:display_name => @user.display_name), :title => t('layouts.welcome_user_link_tooltip') %>
- - <%= yield :greeting %>
- - <%= render :partial => "layouts/inbox" %>
- - <%= link_to t('layouts.logout'), logout_path(:session => request.session_options[:id], :referer => request.fullpath), {:id => 'logoutanchor', :title => t('layouts.logout_tooltip')}%>
- <% else %>
- - <%= link_to t('layouts.log_in'), login_path(:referer => request.fullpath), {:id => 'loginanchor', :title => t('layouts.log_in_tooltip')} %>
- - <%= link_to t('layouts.sign_up'), user_new_path, {:id => 'registeranchor', :title => t('layouts.sign_up_tooltip')} %>
- <% end %>
-
+ <% if @user and @user.id %>
+ <%= render :partial => "layouts/user_menu" %>
+ <% else %>
+
+ - <%= link_to t('layouts.log_in'), login_path(:referer => request.fullpath), {:id => 'loginanchor', :title => t('layouts.log_in_tooltip')} %>
+ - <%= link_to t('layouts.sign_up'), user_new_path, {:id => 'registeranchor', :title => t('layouts.sign_up_tooltip')} %>
+
+ <% end %>
- - <%= link_to t('layouts.view'), root_path, {
- :id => 'viewanchor',
- :title => t('layouts.view_tooltip'),
- :class => 'geolink llz layers'
- } %>
- - <%= link_to h(t('layouts.edit')) + content_tag(:span, "▼", :class => "menuicon"), edit_path, {
- :id => 'editanchor',
- :title => t('javascripts.site.edit_tooltip'),
- :data => { :minzoom => 13, :editor => preferred_editor },
- :class => 'geolink llz object disabled'
- } %>
- - <%= link_to t('layouts.history'), browse_changesets_path, {
- :id => 'historyanchor',
- :data => { :minzoom => 11 },
- :title => t('javascripts.site.history_tooltip'),
- :class => 'geolink bbox'
- } %>
+ -
+ <%= link_to t('layouts.view'), root_path, :class => 'tab geolink llz layers' %>
+
-
+ <%= render :partial => 'layouts/edit_menu',
+ :locals => { :link_text => t('layouts.edit'), :link_class => 'llz object' }%>
+
-
+ <%= link_to t('layouts.history'), browse_changesets_path, :class => 'tab geolink bbox' %>
+
-
-
<%= render :partial => "layouts/flash", :locals => { :flash => flash } %>
<% if content_for? :heading %>
diff --git a/app/views/site/_home_link.html.erb b/app/views/site/_home_link.html.erb
index 979ae7681..e907b3fb1 100644
--- a/app/views/site/_home_link.html.erb
+++ b/app/views/site/_home_link.html.erb
@@ -6,7 +6,6 @@
:class => "set_position",
:data => { :lat => @user.home_lat,
:lon => @user.home_lon,
- :zoom => 15 },
- :title => t("layouts.home_tooltip") %>
+ :zoom => 15 } %>
<% end %>
<% end %>
diff --git a/config/locales/en.yml b/config/locales/en.yml
index 901e86359..a1e26baeb 100644
--- a/config/locales/en.yml
+++ b/config/locales/en.yml
@@ -996,16 +996,8 @@ en:
h1: OpenStreetMap
logo:
alt_text: OpenStreetMap logo
- welcome_user_link_tooltip: Your user page
- home: home
- home_tooltip: Go to home location
- inbox_html: "inbox %{count}"
- inbox_tooltip:
- zero: Your inbox contains no unread messages
- one: Your inbox contains 1 unread message
- other: Your inbox contains %{count} unread messages
- logout: logout
- logout_tooltip: "Log out"
+ home: Go to Home Location
+ logout: Logout
log_in: log in
log_in_tooltip: Log in with an existing account
sign_up: sign up
@@ -1294,7 +1286,7 @@ en:
message:
inbox:
title: "Inbox"
- my_inbox: "My inbox"
+ my_inbox: "My Inbox"
outbox: "outbox"
messages: "You have %{new_messages} and %{old_messages}"
new_messages:
@@ -1777,23 +1769,24 @@ en:
heading: "The user %{user} does not exist"
body: "Sorry, there is no user with the name %{user}. Please check your spelling, or maybe the link you clicked is wrong."
view:
- my diary: my diary
+ my diary: My Diary
new diary entry: new diary entry
- my edits: my edits
- my traces: my traces
- my notes: my map notes
- my settings: my settings
- my comments: my comments
+ my edits: My Edits
+ my traces: My Traces
+ my notes: My Notes
+ my profile: My Profile
+ my settings: My Settings
+ my comments: My Comments
oauth settings: oauth settings
- blocks on me: blocks on me
- blocks by me: blocks by me
- send message: send message
- diary: diary
- edits: edits
- traces: traces
- notes: map notes
- remove as friend: unfriend
- add as friend: add friend
+ blocks on me: Blocks on Me
+ blocks by me: Blocks by Me
+ send message: Send Message
+ diary: Diary
+ edits: Edits
+ traces: Traces
+ notes: Map Notes
+ remove as friend: Unfriend
+ add as friend: Add Friend
mapper since: "Mapper since:"
ago: "(%{time_in_words_ago} ago)"
ct status: "Contributor terms:"
@@ -1826,7 +1819,7 @@ en:
moderator: "Revoke moderator access"
block_history: "blocks received"
moderator_history: "blocks given"
- comments: "comments"
+ comments: "Comments"
create_block: "block this user"
activate_user: "activate this user"
deactivate_user: "deactivate this user"
@@ -2140,13 +2133,10 @@ en:
site:
edit_tooltip: Edit the map
edit_disabled_tooltip: Zoom in to edit the map
- edit_zoom_alert: You must zoom in to edit the map
history_tooltip: View edits for this area
history_disabled_tooltip: Zoom in to view edits for this area
- history_zoom_alert: You must zoom in to view edits for this area
createnote_tooltip: Add a note to the map
createnote_disabled_tooltip: Zoom in to add a note to the map
- createnote_zoom_alert: You must zoom in to add a note to the map
notes:
new:
intro: "In order to improve the map the information you enter is shown to other mappers, so please be as descriptive and precise as possible when moving the marker to the correct position and entering your note below."
diff --git a/vendor/assets/bootstrap/bootstrap.dropdown.js b/vendor/assets/bootstrap/bootstrap.dropdown.js
new file mode 100644
index 000000000..d04da5d7b
--- /dev/null
+++ b/vendor/assets/bootstrap/bootstrap.dropdown.js
@@ -0,0 +1,169 @@
+/* ============================================================
+ * bootstrap-dropdown.js v2.3.2
+ * http://getbootstrap.com/2.3.2/javascript.html#dropdowns
+ * ============================================================
+ * Copyright 2013 Twitter, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============================================================ */
+
+
+!function ($) {
+
+ "use strict"; // jshint ;_;
+
+
+ /* DROPDOWN CLASS DEFINITION
+ * ========================= */
+
+ var toggle = '[data-toggle=dropdown]'
+ , Dropdown = function (element) {
+ var $el = $(element).on('click.dropdown.data-api', this.toggle)
+ $('html').on('click.dropdown.data-api', function () {
+ $el.parent().removeClass('open')
+ })
+ }
+
+ Dropdown.prototype = {
+
+ constructor: Dropdown
+
+ , toggle: function (e) {
+ var $this = $(this)
+ , $parent
+ , isActive
+
+ if ($this.is('.disabled, :disabled')) return
+
+ $parent = getParent($this)
+
+ isActive = $parent.hasClass('open')
+
+ clearMenus()
+
+ if (!isActive) {
+ if ('ontouchstart' in document.documentElement) {
+ // if mobile we we use a backdrop because click events don't delegate
+ $('
').insertBefore($(this)).on('click', clearMenus)
+ }
+ $parent.toggleClass('open')
+ }
+
+ $this.focus()
+
+ return false
+ }
+
+ , keydown: function (e) {
+ var $this
+ , $items
+ , $active
+ , $parent
+ , isActive
+ , index
+
+ if (!/(38|40|27)/.test(e.keyCode)) return
+
+ $this = $(this)
+
+ e.preventDefault()
+ e.stopPropagation()
+
+ if ($this.is('.disabled, :disabled')) return
+
+ $parent = getParent($this)
+
+ isActive = $parent.hasClass('open')
+
+ if (!isActive || (isActive && e.keyCode == 27)) {
+ if (e.which == 27) $parent.find(toggle).focus()
+ return $this.click()
+ }
+
+ $items = $('[role=menu] li:not(.divider):visible a', $parent)
+
+ if (!$items.length) return
+
+ index = $items.index($items.filter(':focus'))
+
+ if (e.keyCode == 38 && index > 0) index-- // up
+ if (e.keyCode == 40 && index < $items.length - 1) index++ // down
+ if (!~index) index = 0
+
+ $items
+ .eq(index)
+ .focus()
+ }
+
+ }
+
+ function clearMenus() {
+ $('.dropdown-backdrop').remove()
+ $(toggle).each(function () {
+ getParent($(this)).removeClass('open')
+ })
+ }
+
+ function getParent($this) {
+ var selector = $this.attr('data-target')
+ , $parent
+
+ if (!selector) {
+ selector = $this.attr('href')
+ selector = selector && /#/.test(selector) && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7
+ }
+
+ $parent = selector && $(selector)
+
+ if (!$parent || !$parent.length) $parent = $this.parent()
+
+ return $parent
+ }
+
+
+ /* DROPDOWN PLUGIN DEFINITION
+ * ========================== */
+
+ var old = $.fn.dropdown
+
+ $.fn.dropdown = function (option) {
+ return this.each(function () {
+ var $this = $(this)
+ , data = $this.data('dropdown')
+ if (!data) $this.data('dropdown', (data = new Dropdown(this)))
+ if (typeof option == 'string') data[option].call($this)
+ })
+ }
+
+ $.fn.dropdown.Constructor = Dropdown
+
+
+ /* DROPDOWN NO CONFLICT
+ * ==================== */
+
+ $.fn.dropdown.noConflict = function () {
+ $.fn.dropdown = old
+ return this
+ }
+
+
+ /* APPLY TO STANDARD DROPDOWN ELEMENTS
+ * =================================== */
+
+ $(document)
+ .on('click.dropdown.data-api', clearMenus)
+ .on('click.dropdown.data-api', '.dropdown form', function (e) { e.stopPropagation() })
+ .on('click.dropdown.data-api' , toggle, Dropdown.prototype.toggle)
+ .on('keydown.dropdown.data-api', toggle + ', [role=menu]' , Dropdown.prototype.keydown)
+
+}(window.jQuery);