diff --git a/pd/nw/pd_canvas.js b/pd/nw/pd_canvas.js
index e0eadc4495b388fa0af28c818f3fc1446ae1ae1d..db54bda82cc9a561b3f0fe2187b9920661862f20 100644
--- a/pd/nw/pd_canvas.js
+++ b/pd/nw/pd_canvas.js
@@ -11,94 +11,6 @@ pdgui.skin.apply(window);
 
 var l = pdgui.get_local_string;
 
-function close_save_dialog() {
-    document.getElementById("save_before_quit").close();
-}
-
-function text_to_normalized_svg_path(text) {
-    text = text.slice(4).trim()  // draw
-               .slice(4).trim()  // path
-               .slice(1).trim()  // d
-               .slice(1).trim(); // =
-    if (text.slice(0, 1) === '"') {
-        text = text.slice(1);
-    }
-    if (text.slice(-1) === '"') {
-        text = text.slice(0, -1);
-    }
-    text = pdgui.parse_svg_path(text);
-    return "draw path " + text.reduce(function (prev, curr) {
-        return prev.concat(curr)
-    }).join(" ");
-}
-
-function text_to_fudi(text) {
-    text = text.trim();
-    // special case for draw path d="arbitrary path string" ...
-    if (text.search(/^draw\s+path\s+d\s*=\s*"/) !== -1) {
-        text = text_to_normalized_svg_path(text);
-    }
-    text = text.replace(/(\$[0-9]+)/g, "\\$1");    // escape dollar signs
-    text = text.replace(/(\$@)/g, "\\$@");         // escape special $@ sign
-    text = text.replace(/(?!\\)(,|;)/g, " \\$1 "); // escape "," and ";"
-    text = text.replace(/\u0020+/g, " ");          // filter consecutive ascii32
-    return text;
-}
-
-// Convert a string (FUDI message) to an array of strings small enough
-// to fit in Pd's socketreceiver buffer of 4096 bytes
-function string_to_array_of_chunks(msg) {
-    var chunk_max = 1024,
-        max_pd_string = 1000,
-        left,
-        in_array = [],
-        out_array = [];
-    if (msg.length <= chunk_max) {
-        out_array.push([msg]);
-    } else {
-        in_array = msg.split(/[\s\n]/); // split on newlines or spaces
-        while (in_array.length) {
-            left = in_array.slice(); // make a copy of in_array
-            if (left.toString().length > chunk_max) {
-                while (1) {
-                    if (left.length < 2) {
-                        pdgui.post("Warning: string truncated:");
-                        pdgui.post(left.toString().
-                            match(/............................../g).join("\n")
-                        );
-                        break;
-                    }
-                    left = left.splice(0, left.length >> 1);
-                    if (left.toString().length <= chunk_max) {
-                        break;
-                    }
-                }
-            }
-            // might need a check here for max_pd_string to warn
-            // user if a string is going to get truncated. (That's
-            // what max_pd_string is for above.)
-            out_array.push(left);
-            in_array = in_array.splice(left.length);
-        }
-    }
-    return out_array;
-}
-
-// Super-simplistic guess at whether the string from the clipboard
-// starts with Pd code. This is just meant as a convenience so that
-// stuff in the copy buffer that obviously isn't Pd code doesn't get
-// in the way when editing.
-function might_be_a_pd_file(stuff_from_clipboard) {
-    var text = stuff_from_clipboard.trim(),
-        one = text.charAt(0),
-        two = text.charAt(1);
-    return (one === "#" && (two === "N" || two === "X"));
-}
-
-function permission_to_paste_from_external_clipboard() {
-    return global.confirm(l("canvas.paste_clipboard_prompt"));
-}
-
 function nw_window_focus_callback(name) {
     pdgui.set_focused_patchwin(name);
     // on OSX, update the menu on focus
@@ -124,24 +36,6 @@ function nw_window_zoom(name, delta) {
     }
 }
 
-// These three functions need to be inside canvas_events closure
-function canvas_find_whole_word(elem) {
-    canvas_events.match_words(elem.checked);
-}
-
-function canvas_find_blur() {
-    canvas_events.normal();
-}
-
-function canvas_find_focus() {
-    var state = canvas_events.get_state();
-    canvas_events.search();
-}
-
-function canvas_find_reset() {
-    canvas_events.find_reset();
-}
-
 var canvas_events = (function() {
     var name,
         state,
@@ -180,6 +74,89 @@ var canvas_events = (function() {
                 return 0;
             }
         },
+        text_to_normalized_svg_path = function(text) {
+            text = text.slice(4).trim()  // draw
+                       .slice(4).trim()  // path
+                       .slice(1).trim()  // d
+                       .slice(1).trim(); // =
+            if (text.slice(0, 1) === '"') {
+                text = text.slice(1);
+            }
+            if (text.slice(-1) === '"') {
+                text = text.slice(0, -1);
+            }
+            text = pdgui.parse_svg_path(text);
+            return "draw path " + text.reduce(function (prev, curr) {
+                return prev.concat(curr)
+            }).join(" ");
+        },
+        text_to_fudi = function(text) {
+            text = text.trim();
+            // special case for draw path d="arbitrary path string" ...
+            if (text.search(/^draw\s+path\s+d\s*=\s*"/) !== -1) {
+                text = text_to_normalized_svg_path(text);
+            }
+            // escape dollar signs
+            text = text.replace(/(\$[0-9]+)/g, "\\$1");
+
+            // escape special $@ sign
+            text = text.replace(/(\$@)/g, "\\$@");
+
+            // escape "," and ";"
+            text = text.replace(/(?!\\)(,|;)/g, " \\$1 ");
+
+            // filter consecutive ascii32
+            text = text.replace(/\u0020+/g, " ");
+            return text;
+        },
+        string_to_array_of_chunks = function(msg) {
+        // Convert a string (FUDI message) to an array of strings small enough
+        // to fit in Pd's socketreceiver buffer of 4096 bytes
+            var chunk_max = 1024,
+                max_pd_string = 1000,
+                left,
+                in_array = [],
+                out_array = [];
+            if (msg.length <= chunk_max) {
+                out_array.push([msg]);
+            } else {
+                in_array = msg.split(/[\s\n]/); // split on newlines or spaces
+                while (in_array.length) {
+                    left = in_array.slice(); // make a copy of in_array
+                    if (left.toString().length > chunk_max) {
+                        while (1) {
+                            if (left.length < 2) {
+                                pdgui.post("Warning: string truncated:");
+                                pdgui.post(left.toString().
+                                    match(/............................../g).join("\n")
+                                );
+                                break;
+                            }
+                            left = left.splice(0, left.length >> 1);
+                            if (left.toString().length <= chunk_max) {
+                                break;
+                            }
+                        }
+                    }
+                    // might need a check here for max_pd_string to warn
+                    // user if a string is going to get truncated. (That's
+                    // what max_pd_string is for above.)
+                    out_array.push(left);
+                    in_array = in_array.splice(left.length);
+                }
+            }
+            return out_array;
+        },
+        might_be_a_pd_file = function(stuff_from_clipboard) {
+            // Super-simplistic guess at whether the string from the clipboard
+            // starts with Pd code. This is just meant as a convenience so that
+            // stuff in the copy buffer that obviously isn't Pd code doesn't get
+            // in the way when editing.
+            var text = stuff_from_clipboard.trim(),
+                one = text.charAt(0),
+                two = text.charAt(1);
+            return (one === "#" && (two === "N" || two === "X"));
+        },
         grow_svg_for_element= function(elem) {
             // See if an element overflows the svg bbox, and
             // enlarge the svg to accommodate it.
@@ -675,7 +652,6 @@ var canvas_events = (function() {
         }
     ;
 
-
     return {
         none: function() {
             var evt_name, prop;
@@ -692,7 +668,7 @@ var canvas_events = (function() {
             }
         },
         normal: function() {
-            this.none();
+            canvas_events.none();
 
             document.addEventListener("mousemove", events.mousemove, false);
             document.addEventListener("keydown", events.keydown, false);
@@ -719,14 +695,14 @@ var canvas_events = (function() {
             // The exception is my_canvas, which is weird because the visible
             // rectangle extends past the bbox that it reports to Pd.
             // Unfortunately that means a lot of work to treat it separately.
-            this.none();
+            canvas_events.none();
             document.addEventListener("mousemove",
                 events.iemgui_label_mousemove, false);
             document.addEventListener("mouseup",
                 events.iemgui_label_mouseup, false);
         },
         text: function() {
-            this.none();
+            canvas_events.none();
 
             document.addEventListener("mousemove", events.text_mousemove, false);
             document.addEventListener("keydown", events.text_keydown, false);
@@ -739,8 +715,8 @@ var canvas_events = (function() {
             set_edit_menu_modals(false);
         },
         floating_text: function() {
-            this.none();
-            this.text();
+            canvas_events.none();
+            canvas_events.text();
             document.removeEventListener("mousedown", events.text_mousedown, false);
             document.removeEventListener("mouseup", events.text_mouseup, false);
             document.removeEventListener("keypress", events.text_keypress, false);
@@ -752,7 +728,7 @@ var canvas_events = (function() {
             set_edit_menu_modals(false);
         },
         dropdown_menu: function() {
-            this.none();
+            canvas_events.none();
             document.addEventListener("mousedown", events.dropdown_menu_mousedown, false);
             document.addEventListener("mouseup", events.dropdown_menu_mouseup, false);
             document.addEventListener("mousemove", events.dropdown_menu_mousemove, false);
@@ -762,7 +738,7 @@ var canvas_events = (function() {
                 .addEventListener("wheel", events.dropdown_menu_wheel, false);
         },
         search: function() {
-            this.none();
+            canvas_events.none();
             document.addEventListener("keydown", events.find_keydown, false);
             state = "search";
         },
@@ -810,6 +786,9 @@ var canvas_events = (function() {
             pdgui.pdsend(name, "dirty 0");
             pdgui.pdsend(cid, "menuclose", force);
         },
+        close_save_dialog: function() {
+            document.getElementById("save_before_quit").close();
+        },
         init: function() {
             document.getElementById("saveDialog")
                 .setAttribute("nwworkingdir", pdgui.get_pwd());
@@ -939,7 +918,7 @@ var canvas_events = (function() {
                 }, false
             );
             document.querySelector("#canvas_find_text")
-                .addEventListener("focusin", canvas_find_focus, false
+                .addEventListener("focusin", canvas_events.search, false
             );
 
             // disable drag and drop for the time being
@@ -955,7 +934,7 @@ var canvas_events = (function() {
             document.querySelector("#canvas_find_text").placeholder =
                 l("canvas.find.placeholder");
             document.querySelector("#canvas_find_text").addEventListener("blur",
-                canvas_find_blur, false
+                canvas_events.normal, false
             );
             document.querySelector("#canvas_find_button")
                 .addEventListener("click", events.find_click
@@ -1163,11 +1142,6 @@ function canvas_paste_from_clipboard(name, clipboard_data)
         return;
     }
 
-    // Maybe we want a warning prompt here? Then uncomment the line below. I
-    // disabled this for now, as the paste-from-clipboard command now has its
-    // own menu option, so presumably the user knows what he's doing. -ag
-    //if (!permission_to_paste_from_external_clipboard()) return;
-
     // clear the buffer
     pdgui.pdsend(name, "copyfromexternalbuffer");
     pd_message = "";