Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
David MacDonald
purr-data
Commits
d82ccc36
Commit
d82ccc36
authored
Jun 25, 2017
by
Jonathan Wilkes
Browse files
Merge branch 'fix-dropdown'
parents
5bfda305
774db790
Changes
2
Hide whitespace changes
Inline
Side-by-side
pd/nw/pd_canvas.js
View file @
d82ccc36
...
...
@@ -160,6 +160,8 @@ var canvas_events = (function() {
last_draggable_y
,
// last y
previous_state
=
"
none
"
,
/* last state, excluding explicit 'none' */
match_words_state
=
false
,
last_dropdown_menu_x
,
last_dropdown_menu_y
,
last_search_term
=
""
,
svg_view
=
document
.
getElementById
(
"
patchsvg
"
).
viewBox
.
baseVal
,
textbox
=
function
()
{
...
...
@@ -208,21 +210,44 @@ var canvas_events = (function() {
svg
.
setAttribute
(
"
height
"
,
h
);
},
dropdown_index_to_pd
=
function
(
elem
)
{
pdgui
.
pdsend
(
elem
.
getAttribute
(
"
data-callback
"
),
elem
.
querySelector
(
"
.highlighted
"
).
getAttribute
(
"
data-index
"
));
var
highlighted
=
elem
.
querySelector
(
"
.highlighted
"
);
if
(
highlighted
)
{
pdgui
.
pdsend
(
elem
.
getAttribute
(
"
data-callback
"
),
highlighted
.
getAttribute
(
"
data-index
"
));
}
},
dropdown_highlight
_elem
=
function
(
elem
)
{
dropdown_
clear_
highlight
=
function
()
{
var
container
=
document
.
querySelector
(
"
#dropdown_list
"
),
li_array
;
if
(
!
elem
.
classList
.
contains
(
"
highlighted
"
))
{
li_array
=
container
.
querySelectorAll
(
"
li
"
);
Array
.
prototype
.
forEach
.
call
(
li_array
,
function
(
e
)
{
e
.
classList
.
remove
(
"
highlighted
"
);
});
Array
.
prototype
.
forEach
.
call
(
li_array
,
function
(
e
)
{
e
.
classList
.
remove
(
"
highlighted
"
);
});
},
dropdown_highlight_elem
=
function
(
elem
,
scroll
)
{
var
container
=
document
.
querySelector
(
"
#dropdown_list
"
);
if
(
!
elem
.
classList
.
contains
(
"
highlighted
"
))
{
dropdown_clear_highlight
();
elem
.
classList
.
add
(
"
highlighted
"
);
// Make sure the highlighted element is in view
container
.
scrollTop
=
elem
.
offsetTop
+
elem
.
offsetHeight
-
container
.
clientHeight
;
if
(
scroll
)
{
if
(
elem
.
offsetTop
<
container
.
scrollTop
||
elem
.
offsetTop
+
elem
.
offsetHeight
>
container
.
scrollTop
+
container
.
offsetHeight
)
{
if
(
scroll
===
"
up
"
)
{
// we can't usse elem.scrollIntoView() here
// because it may also change the scrollbar on
// the document, which in turn could change the
// pageX/pageY, for the mousemove event, which
// in turn would make it impossible for us to
// filter out unnecessary mousemove calls
// elem.scrollIntoView();
container
.
scrollTop
=
elem
.
offsetTop
;
}
else
if
(
scroll
===
"
down
"
)
{
container
.
scrollTop
=
elem
.
offsetTop
+
elem
.
offsetHeight
-
container
.
clientHeight
;
}
}
}
}
},
events
=
{
...
...
@@ -494,13 +519,13 @@ var canvas_events = (function() {
iemgui_label_mouseup
:
function
(
evt
)
{
//pdgui.post("lifting the mousebutton on an iemgui label");
// Set last state (none doesn't count as a state)
//pdgui.post("previous state is " + canvas_events.get_previous_state());
//pdgui.post("previous state is "
// + canvas_events.get_previous_state());
canvas_events
[
canvas_events
.
get_previous_state
()]();
},
dropdown_menu_keydown
:
function
(
evt
)
{
var
select_elem
=
document
.
querySelector
(
"
#dropdown_list
"
),
li
;
pdgui
.
post
(
"
keycode is
"
+
evt
.
keyCode
);
switch
(
evt
.
keyCode
)
{
case
13
:
case
32
:
...
...
@@ -510,34 +535,43 @@ var canvas_events = (function() {
break
;
case
27
:
// escape
select_elem
.
style
.
setProperty
(
"
display
"
,
"
none
"
);
pdgui
.
post
(
"
canceled thing
"
);
canvas_events
.
normal
();
break
;
case
38
:
// up
li
=
select_elem
.
querySelector
(
"
.highlighted
"
);
li
=
li
.
previousElementSibling
||
li
.
parentElement
.
lastElementChild
;
dropdown_highlight_elem
(
li
);
dropdown_highlight_elem
(
li
,
"
up
"
);
evt
.
preventDefault
();
break
;
case
40
:
// down
li
=
select_elem
.
querySelector
(
"
.highlighted
"
);
li
=
li
.
nextElementSibling
||
li
.
parentElement
.
firstElementChild
;
dropdown_highlight_elem
(
li
);
dropdown_highlight_elem
(
li
,
"
down
"
);
evt
.
preventDefault
();
break
;
default
:
}
},
dropdown_menu_keypress
:
function
(
evt
)
{
var
li_nodes
=
document
.
querySelectorAll
(
"
#dropdown_list li
"
),
string_array
=
[],
highlighted
,
highlighted_index
,
match
,
offset
;
highlighted_index
=
+
document
.
querySelector
(
"
#dropdown_list .highlighted
"
)
.
getAttribute
(
"
data-index
"
);
offset
=
highlighted_index
+
1
;
highlighted
=
document
.
querySelector
(
"
#dropdown_list .highlighted
"
);
if
(
highlighted
)
{
highlighted_index
=
+
document
.
querySelector
(
"
#dropdown_list .highlighted
"
)
.
getAttribute
(
"
data-index
"
);
offset
=
highlighted_index
+
1
;
}
else
{
highlighted_index
=
1
;
offset
=
2
;
}
Array
.
prototype
.
forEach
.
call
(
li_nodes
,
function
(
e
,
i
,
a
)
{
var
s
=
a
[(
i
+
offset
)
%
a
.
length
];
string_array
.
push
(
s
.
textContent
.
trim
());
...
...
@@ -550,23 +584,49 @@ var canvas_events = (function() {
if
(
match
!==
undefined
)
{
match
=
(
match
+
offset
)
%
li_nodes
.
length
;
if
(
match
!==
highlighted_index
)
{
dropdown_highlight_elem
(
li_nodes
[
match
]);
dropdown_highlight_elem
(
li_nodes
[
match
],
match
<
highlighted_index
?
"
up
"
:
"
down
"
);
}
}
},
dropdown_menu_mousedown
:
function
(
evt
)
{
var
select_elem
=
document
.
querySelector
(
"
#dropdown_list
"
);
var
select_elem
=
document
.
querySelector
(
"
#dropdown_list
"
),
in_dropdown
=
evt
.
target
;
while
(
in_dropdown
)
{
if
(
in_dropdown
.
id
===
"
dropdown_list
"
)
{
break
;
}
in_dropdown
=
in_dropdown
.
parentNode
;
}
// Allow scrollbar click and drag without closing the menu
if
(
in_dropdown
&&
evt
.
pageX
-
select_elem
.
offsetLeft
>
select_elem
.
clientWidth
)
{
return
;
}
// Special case for OSX, where the scrollbar doesn't take
// up any extra space
if
(
nw
.
process
.
platform
===
"
darwin
"
&&
(
evt
.
target
.
id
===
"
dropdown_list
"
))
{
return
;
}
if
(
evt
.
target
.
parentNode
&&
evt
.
target
.
parentNode
.
parentNode
&&
evt
.
target
.
parentNode
.
parentNode
.
id
===
"
dropdown_list
"
)
{
dropdown_highlight_elem
(
evt
.
target
);
}
// This selects whatever item is highlighted even
// if we click outside the menu. Might be better to
// cancel in that case.
dropdown_index_to_pd
(
select_elem
);
select_elem
.
style
.
setProperty
(
"
display
"
,
"
none
"
);
canvas_events
.
normal
();
},
dropdown_menu_mouseup
:
function
(
evt
)
{
var
i
,
select_elem
;
// This can be triggered if the user keeps the mouse down
// to highlight an element and releases the mouse button to
// choose that element
if
(
evt
.
target
.
parentNode
&&
evt
.
target
.
parentNode
.
parentNode
&&
evt
.
target
.
parentNode
.
parentNode
.
id
===
"
dropdown_list
"
)
{
...
...
@@ -576,14 +636,33 @@ var canvas_events = (function() {
canvas_events
.
normal
();
}
},
dropdown_menu_mouseover
:
function
(
evt
)
{
var
li_array
;
if
(
evt
.
target
.
parentNode
&&
evt
.
target
.
parentNode
.
parentNode
&&
evt
.
target
.
parentNode
.
parentNode
.
id
===
"
dropdown_list
"
)
{
dropdown_highlight_elem
(
evt
.
target
);
dropdown_menu_wheel
:
function
(
evt
)
{
// Here we generate bogus mouse coords so that
// we can break through the filter below if we're
// using the mouse wheel to scroll in the list.
last_dropdown_menu_x
=
Number
.
MIN_VALUE
;
last_dropdown_menu_y
=
Number
.
MIN_VALUE
;
},
dropdown_menu_mousemove
:
function
(
evt
)
{
// For whatever reason, Chromium decides to trigger the
// mousemove/mouseenter/mouseover events if the element
// underneath it changes (or for mousemove, if the element
// moves at all). Unfortunately that means we have to track
// the mouse position the entire time to filter out the
// true mousemove events from the ones Chromium generates
// when a scroll event changes the element under the mouse.
if
(
evt
.
pageX
!==
last_dropdown_menu_x
||
evt
.
pageY
!==
last_dropdown_menu_y
)
{
if
(
evt
.
target
.
parentNode
&&
evt
.
target
.
parentNode
.
parentNode
&&
evt
.
target
.
parentNode
.
parentNode
.
id
===
"
dropdown_list
"
)
{
dropdown_highlight_elem
(
evt
.
target
);
}
else
{
dropdown_clear_highlight
();
}
}
// hide the dropdown menu <div> thingy
last_dropdown_menu_x
=
evt
.
pageX
;
last_dropdown_menu_y
=
evt
.
pageY
;
}
},
utils
=
{
...
...
@@ -840,9 +919,11 @@ var canvas_events = (function() {
this
.
none
();
document
.
addEventListener
(
"
mousedown
"
,
events
.
dropdown_menu_mousedown
,
false
);
document
.
addEventListener
(
"
mouseup
"
,
events
.
dropdown_menu_mouseup
,
false
);
document
.
addEventListener
(
"
mouseove
r
"
,
events
.
dropdown_menu_mouseove
r
,
false
);
document
.
addEventListener
(
"
mouse
m
ove
"
,
events
.
dropdown_menu_mouse
m
ove
,
false
);
document
.
addEventListener
(
"
keydown
"
,
events
.
dropdown_menu_keydown
,
false
);
document
.
addEventListener
(
"
keypress
"
,
events
.
dropdown_menu_keypress
,
false
);
document
.
querySelector
(
"
#dropdown_list
"
)
.
addEventListener
(
"
wheel
"
,
events
.
dropdown_menu_wheel
,
false
);
},
search
:
function
()
{
this
.
none
();
...
...
pd/nw/pdgui.js
View file @
d82ccc36
...
...
@@ -4596,7 +4596,13 @@ function dropdown_populate(cid, label_array, current_index) {
}
function
gui_dropdown_activate
(
cid
,
obj_tag
,
tag
,
current_index
,
font_size
,
state
,
label_array
)
{
var
g
,
select_elem
,
svg_view
;
var
g
,
select_elem
,
svg_view
,
g_bbox
,
doc_height
,
// document height, excluding the scrollbar
menu_height
,
// height of the list of elements inside the div
div_y
,
// position of div containing the dropdown menu
div_max
,
// max height of the div
scroll_y
,
offset_anchor
;
// top or bottom
// Annoying: obj_tag is just the "x"-prepended hex value for the object,
// and tag is the one from rtext_gettag that is used as our gobj id
if
(
patchwin
[
cid
])
{
...
...
@@ -4604,21 +4610,54 @@ function gui_dropdown_activate(cid, obj_tag, tag, current_index, font_size, stat
if
(
state
!==
0
)
{
svg_view
=
patchwin
[
cid
].
window
.
document
.
getElementById
(
"
patchsvg
"
)
.
viewBox
.
baseVal
;
dropdown_populate
(
cid
,
label_array
,
current_index
);
select_elem
=
patchwin
[
cid
]
.
window
.
document
.
querySelector
(
"
#dropdown_list
"
);
dropdown_populate
(
cid
,
label_array
,
current_index
);
// stick the obj_tag in a data field
select_elem
.
setAttribute
(
"
data-callback
"
,
obj_tag
);
select_elem
.
style
.
setProperty
(
"
max-height
"
,
(
patchwin
[
cid
].
window
.
innerHeight
-
g
.
getBoundingClientRect
().
bottom
-
5
)
+
"
px
"
);
// display the menu so we can measure it
g_bbox
=
g
.
getBoundingClientRect
();
// Measuring the document height is tricky-- the following
// method is the only reliable one I've found. And even here,
// if you display the select_elem as inline _before_ measuring
// the doc height, the result ends up being _smaller_. No idea.
doc_height
=
patchwin
[
cid
].
window
.
document
.
documentElement
.
clientHeight
;
// Now let's display the select_elem div so we can measure it
select_elem
.
style
.
setProperty
(
"
display
"
,
"
inline
"
);
menu_height
=
select_elem
.
querySelector
(
"
ol
"
)
.
getBoundingClientRect
().
height
;
scroll_y
=
patchwin
[
cid
].
window
.
scrollY
;
// If the area below the object is smaller than 75px, then
// display the menu above the object.
// If the entire menu won't fit below the object but _will_
// fit above it, display it above the object.
// If the menu needs a scrollbar, display it below the object
if
(
doc_height
-
g_bbox
.
bottom
<=
75
||
(
menu_height
>
doc_height
-
g_bbox
.
bottom
&&
menu_height
<=
g_bbox
.
top
))
{
// menu on top
offset_anchor
=
"
bottom
"
;
div_max
=
g_bbox
.
top
-
2
;
div_y
=
doc_height
-
(
g_bbox
.
top
+
scroll_y
);
}
else
{
// menu on bottom (possibly with scrollbar)
offset_anchor
=
"
top
"
;
div_max
=
doc_height
-
g_bbox
.
bottom
-
2
;
div_y
=
g_bbox
.
bottom
+
scroll_y
;
}
// set a max-height to force scrollbar if needed
select_elem
.
style
.
setProperty
(
"
max-height
"
,
div_max
+
"
px
"
);
select_elem
.
style
.
setProperty
(
"
left
"
,
(
elem_get_coords
(
g
).
x
-
svg_view
.
x
)
+
"
px
"
);
select_elem
.
style
.
setProperty
(
"
top
"
,
(
elem_get_coords
(
g
).
y
+
g
.
getBBox
().
height
-
svg_view
.
y
)
+
"
px
"
);
// Remove "top" and "bottom" props to keep state clean
select_elem
.
style
.
removeProperty
(
"
top
"
);
select_elem
.
style
.
removeProperty
(
"
bottom
"
);
// Now position the div relative to either the "top" or "bottom"
select_elem
.
style
.
setProperty
(
offset_anchor
,
div_y
+
"
px
"
);
select_elem
.
style
.
setProperty
(
"
font-size
"
,
pd_fontsize_to_gui_fontsize
(
font_size
)
+
"
px
"
);
select_elem
.
style
.
setProperty
(
"
min-width
"
,
g
.
getBBox
().
width
+
"
px
"
);
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment