123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152 |
- /**
- * @license
- * Visual Blocks Editor
- *
- * Copyright 2011 Google Inc.
- * https://developers.google.com/blockly/
- *
- * 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.
- */
- /**
- * @fileoverview Functionality for the right-click context menus.
- * @author fraser@google.com (Neil Fraser)
- */
- 'use strict';
- goog.provide('Blockly.ContextMenu');
- goog.require('goog.dom');
- goog.require('goog.events');
- goog.require('goog.style');
- goog.require('goog.ui.Menu');
- goog.require('goog.ui.MenuItem');
- /**
- * Which block is the context menu attached to?
- * @type {Blockly.Block}
- */
- Blockly.ContextMenu.currentBlock = null;
- /**
- * Construct the menu based on the list of options and show the menu.
- * @param {!Event} e Mouse event.
- * @param {!Array.<!Object>} options Array of menu options.
- * @param {boolean} rtl True if RTL, false if LTR.
- */
- Blockly.ContextMenu.show = function(e, options, rtl) {
- Blockly.WidgetDiv.show(Blockly.ContextMenu, rtl, null);
- if (!options.length) {
- Blockly.ContextMenu.hide();
- return;
- }
- /* Here's what one option object looks like:
- {text: 'Make It So',
- enabled: true,
- callback: Blockly.MakeItSo}
- */
- var menu = new goog.ui.Menu();
- menu.setRightToLeft(rtl);
- for (var i = 0, option; option = options[i]; i++) {
- var menuItem = new goog.ui.MenuItem(option.text);
- menuItem.setRightToLeft(rtl);
- menu.addChild(menuItem, true);
- menuItem.setEnabled(option.enabled);
- if (option.enabled) {
- goog.events.listen(menuItem, goog.ui.Component.EventType.ACTION,
- option.callback);
- menuItem.handleContextMenu = function(e) {
- // Right-clicking on menu option should count as a click.
- goog.events.dispatchEvent(this, goog.ui.Component.EventType.ACTION);
- };
- }
- }
- goog.events.listen(menu, goog.ui.Component.EventType.ACTION,
- Blockly.ContextMenu.hide);
- // Record windowSize and scrollOffset before adding menu.
- var windowSize = goog.dom.getViewportSize();
- var scrollOffset = goog.style.getViewportPageOffset(document);
- var div = Blockly.WidgetDiv.DIV;
- menu.render(div);
- var menuDom = menu.getElement();
- Blockly.addClass_(menuDom, 'blocklyContextMenu');
- // Prevent system context menu when right-clicking a Blockly context menu.
- Blockly.bindEventWithChecks_(menuDom, 'contextmenu', null, Blockly.noEvent);
- // Record menuSize after adding menu.
- var menuSize = goog.style.getSize(menuDom);
- // Position the menu.
- var x = e.clientX + scrollOffset.x;
- var y = e.clientY + scrollOffset.y;
- // Flip menu vertically if off the bottom.
- if (e.clientY + menuSize.height >= windowSize.height) {
- y -= menuSize.height;
- }
- // Flip menu horizontally if off the edge.
- if (rtl) {
- if (menuSize.width >= e.clientX) {
- x += menuSize.width;
- }
- } else {
- if (e.clientX + menuSize.width >= windowSize.width) {
- x -= menuSize.width;
- }
- }
- Blockly.WidgetDiv.position(x, y, windowSize, scrollOffset, rtl);
- menu.setAllowAutoFocus(true);
- // 1ms delay is required for focusing on context menus because some other
- // mouse event is still waiting in the queue and clears focus.
- setTimeout(function() {menuDom.focus();}, 1);
- Blockly.ContextMenu.currentBlock = null; // May be set by Blockly.Block.
- };
- /**
- * Hide the context menu.
- */
- Blockly.ContextMenu.hide = function() {
- Blockly.WidgetDiv.hideIfOwner(Blockly.ContextMenu);
- Blockly.ContextMenu.currentBlock = null;
- };
- /**
- * Create a callback function that creates and configures a block,
- * then places the new block next to the original.
- * @param {!Blockly.Block} block Original block.
- * @param {!Element} xml XML representation of new block.
- * @return {!Function} Function that creates a block.
- */
- Blockly.ContextMenu.callbackFactory = function(block, xml) {
- return function() {
- Blockly.Events.disable();
- try {
- var newBlock = Blockly.Xml.domToBlock(xml, block.workspace);
- // Move the new block next to the old block.
- var xy = block.getRelativeToSurfaceXY();
- if (block.RTL) {
- xy.x -= Blockly.SNAP_RADIUS;
- } else {
- xy.x += Blockly.SNAP_RADIUS;
- }
- xy.y += Blockly.SNAP_RADIUS * 2;
- newBlock.moveBy(xy.x, xy.y);
- } finally {
- Blockly.Events.enable();
- }
- if (Blockly.Events.isEnabled() && !newBlock.isShadow()) {
- Blockly.Events.fire(new Blockly.Events.Create(newBlock));
- }
- newBlock.select();
- };
- };
|