1- import Path from "@/util/path" ;
2- import behaviorShim from "@/util/behavior-shim" ;
31import Utils from "@/components/dropdowns/utils" ;
2+ import behaviorShim from "@/util/behavior-shim" ;
3+ import { createElementFromHtml } from "@/util/dom" ;
4+ import Path from "@/util/path" ;
45
56function init ( ) {
67 generateJumplistAccessors ( ) ;
78 generateDropdowns ( ) ;
89}
10+ function generateDropdownChevron ( element ) {
11+ const isFirefox = navigator . userAgent . indexOf ( "Firefox" ) !== - 1 ;
12+ // Firefox adds unwanted lines when copying buttons in text, so use a span instead
13+ const dropdownChevron = document . createElement ( isFirefox ? "span" : "button" ) ;
14+ dropdownChevron . className = "jenkins-menu-dropdown-chevron" ;
15+ dropdownChevron . dataset . href = element . href ;
16+ dropdownChevron . addEventListener ( "click" , ( event ) => {
17+ event . preventDefault ( ) ;
18+ } ) ;
19+ element . appendChild ( dropdownChevron ) ;
20+ }
921
1022/*
1123 * Appends a ⌄ button at the end of links which support jump lists
1224 */
1325function generateJumplistAccessors ( ) {
1426 behaviorShim . specify ( "A.model-link" , "-jumplist-" , 999 , ( link ) => {
15- const isFirefox = navigator . userAgent . indexOf ( "Firefox" ) !== - 1 ;
16- // Firefox adds unwanted lines when copying buttons in text, so use a span instead
17- const dropdownChevron = document . createElement (
18- isFirefox ? "span" : "button" ,
19- ) ;
20- dropdownChevron . className = "jenkins-menu-dropdown-chevron" ;
21- dropdownChevron . dataset . href = link . href ;
22- dropdownChevron . addEventListener ( "click" , ( event ) => {
23- event . preventDefault ( ) ;
24- } ) ;
25- link . appendChild ( dropdownChevron ) ;
27+ generateDropdownChevron ( link ) ;
2628 } ) ;
2729}
2830
@@ -37,74 +39,12 @@ function generateDropdowns() {
3739 ( element ) =>
3840 Utils . generateDropdown (
3941 element ,
40- ( instance ) => {
41- if ( element . items ) {
42- instance . setContent ( Utils . generateDropdownItems ( element . items ) ) ;
43- return ;
44- }
45-
46- const href = element . href ;
47-
48- const hasModelLink = element . classList . contains (
49- "hoverable-model-link" ,
50- ) ;
51- const hasChildrenLink = element . classList . contains (
52- "hoverable-children-model-link" ,
53- ) ;
54-
55- const sections = {
56- model : null ,
57- children : null ,
58- } ;
59-
60- const fetchSection = function ( urlSuffix ) {
61- return fetch ( Path . combinePath ( href , urlSuffix ) )
62- . then ( ( response ) => response . json ( ) )
63- . then ( ( json ) => {
64- const items = mapChildrenItemsToDropdownItems ( json . items ) ;
65- const section = document . createElement ( "div" ) ;
66- section . appendChild ( Utils . generateDropdownItems ( items ) ) ;
67- return section ;
68- } ) ;
69- } ;
70-
71- const promises = [ ] ;
72-
73- if ( hasModelLink ) {
74- promises . push (
75- fetchSection ( "contextMenu" ) . then ( ( section ) => {
76- sections . model = section ;
77- } ) ,
78- ) ;
79- }
80-
81- if ( hasChildrenLink ) {
82- promises . push (
83- fetchSection ( "childrenContextMenu" ) . then ( ( section ) => {
84- sections . children = section ;
85- } ) ,
86- ) ;
87- }
88-
89- Promise . all ( promises )
90- . then ( ( ) => {
91- const container = document . createElement ( "div" ) ;
92- container . className = "jenkins-dropdown__split-container" ;
93- if ( sections . model ) {
94- container . appendChild ( sections . model ) ;
95- }
96- if ( sections . children ) {
97- container . appendChild ( sections . children ) ;
98- }
99- instance . setContent ( container ) ;
100- } )
101- . catch ( ( error ) => {
102- console . log ( `Dropdown fetch failed: ${ error } ` ) ;
103- } )
104- . finally ( ( ) => {
105- instance . loaded = true ;
106- } ) ;
107- } ,
42+ createDropdownContent (
43+ element ,
44+ element . classList . contains ( "hoverable-model-link" ) ,
45+ element . classList . contains ( "hoverable-children-model-link" ) ,
46+ element . href ,
47+ ) ,
10848 element . items != null ,
10949 {
11050 trigger : "mouseenter" ,
@@ -115,6 +55,29 @@ function generateDropdowns() {
11555 ) ,
11656 ) ;
11757
58+ behaviorShim . specify (
59+ ".dropdown-indicator" ,
60+ "-clickable-dropdown-" ,
61+ 1000 ,
62+ ( element ) =>
63+ Utils . generateDropdown (
64+ element ,
65+ createDropdownContent (
66+ element ,
67+ element . getAttribute ( "data-model" ) ,
68+ element . getAttribute ( "data-children" ) ,
69+ element . getAttribute ( "data-href" ) ,
70+ ) ,
71+ element . items != null ,
72+ {
73+ trigger : "click focus" ,
74+ offset : [ - 16 , 10 ] ,
75+ animation : "tooltip" ,
76+ touch : false ,
77+ } ,
78+ ) ,
79+ ) ;
80+
11881 behaviorShim . specify (
11982 "li.children, .jenkins-jumplist-link, #menuSelector, .jenkins-menu-dropdown-chevron" ,
12083 "-dropdown-" ,
@@ -147,6 +110,86 @@ function generateDropdowns() {
147110 ) ;
148111}
149112
113+ function createDropdownContent ( element , hasModelLink , hasChildrenLink , href ) {
114+ return ( instance ) => {
115+ if ( element . items ) {
116+ instance . setContent ( Utils . generateDropdownItems ( element . items ) ) ;
117+ return ;
118+ }
119+ const sections = {
120+ model : null ,
121+ children : null ,
122+ } ;
123+
124+ const fetchSection = function ( urlSuffix ) {
125+ return fetch ( Path . combinePath ( href , urlSuffix ) )
126+ . then ( ( response ) => response . json ( ) )
127+ . then ( ( json ) => {
128+ const items = Utils . generateDropdownItems (
129+ mapChildrenItemsToDropdownItems ( json . items ) ,
130+ ) ;
131+ return items ;
132+ } ) ;
133+ } ;
134+
135+ const promises = [ ] ;
136+
137+ if ( hasModelLink === "true" ) {
138+ promises . push (
139+ fetchSection ( "contextMenu" ) . then ( ( section ) => {
140+ const dContainer = section ;
141+ dContainer . prepend (
142+ createElementFromHtml (
143+ `<p class="jenkins-dropdown__heading">Actions</p>` ,
144+ ) ,
145+ ) ;
146+ sections . model = dContainer ;
147+ } ) ,
148+ ) ;
149+ }
150+
151+ if ( hasChildrenLink === "true" ) {
152+ promises . push (
153+ fetchSection ( "childrenContextMenu" ) . then ( ( section ) => {
154+ const dContainer = section ;
155+ // add a header for the section
156+ dContainer . prepend (
157+ createElementFromHtml (
158+ `<p class="jenkins-dropdown__heading">Navigation</p>` ,
159+ ) ,
160+ ) ;
161+ sections . children = dContainer ;
162+ } ) ,
163+ ) ;
164+ }
165+
166+ Promise . all ( promises )
167+ . then ( ( ) => {
168+ const container = document . createElement ( "div" ) ;
169+ container . className = "jenkins-dropdown__split-container" ;
170+ if ( sections . model && ! sections . children ) {
171+ container . appendChild ( sections . model ) ;
172+ } else if ( ! sections . model && sections . children ) {
173+ container . appendChild ( sections . children ) ;
174+ } else if ( sections . model && sections . children ) {
175+ // use the first dropdown and add the second dropdowns choices this way the a11y stays intact
176+ const dropbox = sections . model ;
177+ Array . from ( sections . children . children ) . forEach ( ( item ) => {
178+ dropbox . appendChild ( item ) ;
179+ } ) ;
180+ container . appendChild ( dropbox ) ;
181+ }
182+ instance . setContent ( container ) ;
183+ } )
184+ . catch ( ( error ) => {
185+ console . log ( `Dropdown fetch failed: ${ error } ` ) ;
186+ } )
187+ . finally ( ( ) => {
188+ instance . loaded = true ;
189+ } ) ;
190+ } ;
191+ }
192+
150193/*
151194 * Generates the contents for the dropdown
152195 */
0 commit comments