Browse Source

fix: normlaize @click.right and @click.middle

fix #7020
Evan You 8 years ago
parent
commit
daed1e7355

+ 1 - 12
src/compiler/codegen/events.js

@@ -41,18 +41,7 @@ export function genHandlers (
 ): string {
   let res = isNative ? 'nativeOn:{' : 'on:{'
   for (const name in events) {
-    const handler = events[name]
-    // #5330: warn click.right, since right clicks do not actually fire click events.
-    if (process.env.NODE_ENV !== 'production' &&
-      name === 'click' &&
-      handler && handler.modifiers && handler.modifiers.right
-    ) {
-      warn(
-        `Use "contextmenu" instead of "click.right" since right clicks ` +
-        `do not actually fire "click" events.`
-      )
-    }
-    res += `"${name}":${genHandler(name, handler)},`
+    res += `"${name}":${genHandler(name, events[name])},`
   }
   return res.slice(0, -1) + '}'
 }

+ 27 - 6
src/compiler/helpers.js

@@ -1,5 +1,6 @@
 /* @flow */
 
+import { emptyObject } from 'shared/util'
 import { parseFilters } from './parser/filter-parser'
 
 export function baseWarn (msg: string) {
@@ -42,39 +43,59 @@ export function addHandler (
   important?: boolean,
   warn?: Function
 ) {
+  modifiers = modifiers || emptyObject
   // warn prevent and passive modifier
   /* istanbul ignore if */
   if (
     process.env.NODE_ENV !== 'production' && warn &&
-    modifiers && modifiers.prevent && modifiers.passive
+    modifiers.prevent && modifiers.passive
   ) {
     warn(
       'passive and prevent can\'t be used together. ' +
       'Passive handler can\'t prevent default event.'
     )
   }
+
   // check capture modifier
-  if (modifiers && modifiers.capture) {
+  if (modifiers.capture) {
     delete modifiers.capture
     name = '!' + name // mark the event as captured
   }
-  if (modifiers && modifiers.once) {
+  if (modifiers.once) {
     delete modifiers.once
     name = '~' + name // mark the event as once
   }
   /* istanbul ignore if */
-  if (modifiers && modifiers.passive) {
+  if (modifiers.passive) {
     delete modifiers.passive
     name = '&' + name // mark the event as passive
   }
+
+  // normalize click.right and click.middle since they don't actually fire
+  // this is technically browser-specific, but at least for now browsers are
+  // the only target envs that have right/middle clicks.
+  if (name === 'click') {
+    if (modifiers.right) {
+      name = 'contextmenu'
+      delete modifiers.right
+    } else if (modifiers.middle) {
+      name = 'mouseup'
+    }
+  }
+
   let events
-  if (modifiers && modifiers.native) {
+  if (modifiers.native) {
     delete modifiers.native
     events = el.nativeEvents || (el.nativeEvents = {})
   } else {
     events = el.events || (el.events = {})
   }
-  const newHandler = { value, modifiers }
+
+  const newHandler: any = { value }
+  if (modifiers !== emptyObject) {
+    newHandler.modifiers = modifiers
+  }
+
   const handlers = events[name]
   /* istanbul ignore if */
   if (Array.isArray(handlers)) {

+ 0 - 2
src/core/util/lang.js

@@ -1,7 +1,5 @@
 /* @flow */
 
-export const emptyObject = Object.freeze({})
-
 /**
  * Check if a string starts with $ or _
  */

+ 2 - 0
src/shared/util.js

@@ -1,5 +1,7 @@
 /* @flow */
 
+export const emptyObject = Object.freeze({})
+
 // these helpers produces better vm code in JS engines due to their
 // explicitness and function inlining
 export function isUndef (v: any): boolean %checks {

+ 18 - 4
test/unit/features/directives/on.spec.js

@@ -693,13 +693,27 @@ describe('Directive v-on', () => {
     expect(prevented).toBe(true)
   })
 
-  it('should warn click.right', () => {
-    new Vue({
+  it('should transform click.right to contextmenu', () => {
+    const spy = jasmine.createSpy('click.right')
+    const vm = new Vue({
       template: `<div @click.right="foo"></div>`,
-      methods: { foo () {} }
+      methods: { foo: spy }
     }).$mount()
 
-    expect(`Use "contextmenu" instead`).toHaveBeenWarned()
+    triggerEvent(vm.$el, 'contextmenu')
+    expect(spy).toHaveBeenCalled()
+  })
+
+  it('should transform click.middle to mouseup', () => {
+    const spy = jasmine.createSpy('click.middle')
+    const vm = new Vue({
+      template: `<div @click.middle="foo"></div>`,
+      methods: { foo: spy }
+    }).$mount()
+    triggerEvent(vm.$el, 'mouseup', e => { e.button = 0 })
+    expect(spy).not.toHaveBeenCalled()
+    triggerEvent(vm.$el, 'mouseup', e => { e.button = 1 })
+    expect(spy).toHaveBeenCalled()
   })
 
   it('object syntax (no argument)', () => {