Subversion Repositories Applications.papyrus

Rev

Blame | Last modification | View Log | RSS feed

if(!dojo._hasResource["dijit.Menu"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dijit.Menu"] = true;
dojo.provide("dijit.Menu");

dojo.require("dijit._Widget");
dojo.require("dijit._Container");
dojo.require("dijit._Templated");

dojo.declare(
        "dijit.Menu",
        [dijit._Widget, dijit._Templated, dijit._KeyNavContainer],
{
        constructor: function() {
                this._bindings = [];
        },

        templateString:
                        '<table class="dijit dijitMenu dijitReset dijitMenuTable" waiRole="menu" dojoAttachEvent="onkeypress:_onKeyPress">' +
                                '<tbody class="dijitReset" dojoAttachPoint="containerNode"></tbody>'+
                        '</table>',

        // targetNodeIds: String[]
        //      Array of dom node ids of nodes to attach to.
        //      Fill this with nodeIds upon widget creation and it becomes context menu for those nodes.
        targetNodeIds: [],

        // contextMenuForWindow: Boolean
        //      if true, right clicking anywhere on the window will cause this context menu to open;
        //      if false, must specify targetNodeIds
        contextMenuForWindow: false,

        // parentMenu: Widget
        // pointer to menu that displayed me
        parentMenu: null,

        // popupDelay: Integer
        //      number of milliseconds before hovering (without clicking) causes the popup to automatically open
        popupDelay: 500,

        // _contextMenuWithMouse: Boolean
        //      used to record mouse and keyboard events to determine if a context
        //      menu is being opened with the keyboard or the mouse
        _contextMenuWithMouse: false,

        postCreate: function(){
                if(this.contextMenuForWindow){
                        this.bindDomNode(dojo.body());
                }else{
                        dojo.forEach(this.targetNodeIds, this.bindDomNode, this);
                }
                this.connectKeyNavHandlers([dojo.keys.UP_ARROW], [dojo.keys.DOWN_ARROW]);
        },

        startup: function(){
                dojo.forEach(this.getChildren(), function(child){ child.startup(); });
                this.startupKeyNavChildren();
        },

        onExecute: function(){
                // summary: attach point for notification about when a menu item has been executed
        },

        onCancel: function(/*Boolean*/ closeAll){
                // summary: attach point for notification about when the user cancels the current menu
        },

        _moveToPopup: function(/*Event*/ evt){
                if(this.focusedChild && this.focusedChild.popup && !this.focusedChild.disabled){
                        this.focusedChild._onClick(evt);
                }
        },

        _onKeyPress: function(/*Event*/ evt){
                // summary
                //      Handle keyboard based menu navigation.
                if(evt.ctrlKey || evt.altKey){ return; }

                switch(evt.keyCode){
                        case dojo.keys.RIGHT_ARROW:
                                this._moveToPopup(evt);
                                dojo.stopEvent(evt);
                                break;
                        case dojo.keys.LEFT_ARROW:
                                if(this.parentMenu){
                                        this.onCancel(false);
                                }else{
                                        dojo.stopEvent(evt);
                                }
                                break;
                }
        },

        onItemHover: function(/*MenuItem*/ item){
                this.focusChild(item);

                if(this.focusedChild.popup && !this.focusedChild.disabled && !this.hover_timer){
                        this.hover_timer = setTimeout(dojo.hitch(this, "_openPopup"), this.popupDelay);
                }
        },

        _onChildBlur: function(item){
                // Close all popups that are open and descendants of this menu
                dijit.popup.close(item.popup);
                item._blur();
                this._stopPopupTimer();
        },

        onItemUnhover: function(/*MenuItem*/ item){
        },

        _stopPopupTimer: function(){
                if(this.hover_timer){
                        clearTimeout(this.hover_timer);
                        this.hover_timer = null;
                }
        },

        _getTopMenu: function(){
                for(var top=this; top.parentMenu; top=top.parentMenu);
                return top;
        },

        onItemClick: function(/*Widget*/ item){
                // summary: user defined function to handle clicks on an item
                // summary: internal function for clicks
                if(item.disabled){ return false; }

                if(item.popup){
                        if(!this.is_open){
                                this._openPopup();
                        }
                }else{
                        // before calling user defined handler, close hierarchy of menus
                        // and restore focus to place it was when menu was opened
                        this.onExecute();

                        // user defined handler for click
                        item.onClick();
                }
        },

        // thanks burstlib!
        _iframeContentWindow: function(/* HTMLIFrameElement */iframe_el) {
                //      summary
                //      returns the window reference of the passed iframe
                var win = dijit.getDocumentWindow(dijit.Menu._iframeContentDocument(iframe_el)) ||
                        // Moz. TODO: is this available when defaultView isn't?
                        dijit.Menu._iframeContentDocument(iframe_el)['__parent__'] ||
                        (iframe_el.name && document.frames[iframe_el.name]) || null;
                return win;     //      Window
        },

        _iframeContentDocument: function(/* HTMLIFrameElement */iframe_el){
                //      summary
                //      returns a reference to the document object inside iframe_el
                var doc = iframe_el.contentDocument // W3
                        || (iframe_el.contentWindow && iframe_el.contentWindow.document) // IE
                        || (iframe_el.name && document.frames[iframe_el.name] && document.frames[iframe_el.name].document)
                        || null;
                return doc;     //      HTMLDocument
        },

        bindDomNode: function(/*String|DomNode*/ node){
                // summary: attach menu to given node
                node = dojo.byId(node);

                //TODO: this is to support context popups in Editor.  Maybe this shouldn't be in dijit.Menu
                var win = dijit.getDocumentWindow(node.ownerDocument);
                if(node.tagName.toLowerCase()=="iframe"){
                        win = this._iframeContentWindow(node);
                        node = dojo.withGlobal(win, dojo.body);
                }

                // to capture these events at the top level,
                // attach to document, not body
                var cn = (node == dojo.body() ? dojo.doc : node);

                node[this.id] = this._bindings.push([
                        dojo.connect(cn, "oncontextmenu", this, "_openMyself"),
                        dojo.connect(cn, "onkeydown", this, "_contextKey"),
                        dojo.connect(cn, "onmousedown", this, "_contextMouse")
                ]);
        },

        unBindDomNode: function(/*String|DomNode*/ nodeName){
                // summary: detach menu from given node
                var node = dojo.byId(nodeName);
                var bid = node[this.id]-1, b = this._bindings[bid];
                dojo.forEach(b, dojo.disconnect);
                delete this._bindings[bid];
        },

        _contextKey: function(e){
                this._contextMenuWithMouse = false;
                if (e.keyCode == dojo.keys.F10) {
                        dojo.stopEvent(e);
                        if (e.shiftKey && e.type=="keydown") {
                                // FF: copying the wrong property from e will cause the system
                                // context menu to appear in spite of stopEvent. Don't know
                                // exactly which properties cause this effect.
                                var _e = { target: e.target, pageX: e.pageX, pageY: e.pageY };
                                _e.preventDefault = _e.stopPropagation = function(){};
                                // IE: without the delay, focus work in "open" causes the system
                                // context menu to appear in spite of stopEvent.
                                window.setTimeout(dojo.hitch(this, function(){ this._openMyself(_e); }), 1);
                        }
                }
        },

        _contextMouse: function(e){
                this._contextMenuWithMouse = true;
        },

        _openMyself: function(/*Event*/ e){
                // summary:
                //              Internal function for opening myself when the user
                //              does a right-click or something similar

                dojo.stopEvent(e);

                // Get coordinates.
                // if we are opening the menu with the mouse or on safari open
                // the menu at the mouse cursor
                // (Safari does not have a keyboard command to open the context menu
                // and we don't currently have a reliable way to determine
                // _contextMenuWithMouse on Safari)
                var x,y;
                if(dojo.isSafari || this._contextMenuWithMouse){
                        x=e.pageX;
                        y=e.pageY;
                }else{
                        // otherwise open near e.target
                        var coords = dojo.coords(e.target, true);
                        x = coords.x + 10;
                        y = coords.y + 10;
                }

                var self=this;
                var savedFocus = dijit.getFocus(this);
                function closeAndRestoreFocus(){
                        // user has clicked on a menu or popup
                        dijit.focus(savedFocus);
                        dijit.popup.close(self);
                }
                dijit.popup.open({
                        popup: this,
                        x: x,
                        y: y,
                        onExecute: closeAndRestoreFocus,
                        onCancel: closeAndRestoreFocus,
                        orient: this.isLeftToRight() ? 'L' : 'R'
                });
                this.focus();

                this._onBlur = function(){
                        // Usually the parent closes the child widget but if this is a context
                        // menu then there is no parent
                        dijit.popup.close(this);
                        // don't try to restore focus; user has clicked another part of the screen
                        // and set focus there
                }
        },

        onOpen: function(/*Event*/ e){
                // summary
                //              Open menu relative to the mouse
                this.isShowingNow = true;
        },

        onClose: function(){
                // summary: callback when this menu is closed
                this._stopPopupTimer();
                this.parentMenu = null;
                this.isShowingNow = false;
                this.currentPopup = null;
                if(this.focusedChild){
                        this._onChildBlur(this.focusedChild);
                        this.focusedChild = null;
                }
        },

        _openPopup: function(){
                // summary: open the popup to the side of the current menu item
                this._stopPopupTimer();
                var from_item = this.focusedChild;
                var popup = from_item.popup;

                if(popup.isShowingNow){ return; }
                popup.parentMenu = this;
                var self = this;
                dijit.popup.open({
                        parent: this,
                        popup: popup,
                        around: from_item.arrowCell,
                        orient: this.isLeftToRight() ? {'TR': 'TL', 'TL': 'TR'} : {'TL': 'TR', 'TR': 'TL'},
                        onCancel: function(){
                                // called when the child menu is canceled
                                dijit.popup.close(popup);
                                from_item.focus();      // put focus back on my node
                                self.currentPopup = null;
                        }
                });

                this.currentPopup = popup;

                if(popup.focus){
                        popup.focus();
                }
        }
}
);

dojo.declare(
        "dijit.MenuItem",
        [dijit._Widget, dijit._Templated, dijit._Contained],
{
        // summary
        //      A line item in a Menu2

        // Make 3 columns
        //   icon, label, and expand arrow (BiDi-dependent) indicating sub-menu
        templateString:
                 '<tr class="dijitReset dijitMenuItem"'
                +'dojoAttachEvent="onmouseenter:_onHover,onmouseleave:_onUnhover,ondijitclick:_onClick">'
                +'<td class="dijitReset"><div class="dijitMenuItemIcon ${iconClass}" dojoAttachPoint="iconNode" ></div></td>'
                +'<td tabIndex="-1" class="dijitReset dijitMenuItemLabel" dojoAttachPoint="containerNode" waiRole="menuitem"></td>'
                +'<td class="dijitReset" dojoAttachPoint="arrowCell">'
                        +'<div class="dijitMenuExpand" dojoAttachPoint="expand" style="display:none">'
                        +'<span class="dijitInline dijitArrowNode dijitMenuExpandInner">+</span>'
                        +'</div>'
                +'</td>'
                +'</tr>',

        // label: String
        //      menu text
        label: '',

        // iconClass: String
        //      class to apply to div in button to make it display an icon
        iconClass: "",

        // disabled: Boolean
        //  if true, the menu item is disabled
        //  if false, the menu item is enabled
        disabled: false,

        postCreate: function(){
                dojo.setSelectable(this.domNode, false);
                this.setDisabled(this.disabled);
                if(this.label){
                        this.containerNode.innerHTML=this.label;
                }
        },

        _onHover: function(){
                // summary: callback when mouse is moved onto menu item
                this.getParent().onItemHover(this);
        },

        _onUnhover: function(){
                // summary: callback when mouse is moved off of menu item
                // if we are unhovering the currently selected item
                // then unselect it
                this.getParent().onItemUnhover(this);
        },

        _onClick: function(evt){
                this.getParent().onItemClick(this);
                dojo.stopEvent(evt);
        },

        onClick: function() {
                // summary
                //      User defined function to handle clicks
        },

        focus: function(){
                dojo.addClass(this.domNode, 'dijitMenuItemHover');
                try{
                        dijit.focus(this.containerNode);
                }catch(e){
                        // this throws on IE (at least) in some scenarios
                }
        },

        _blur: function(){
                dojo.removeClass(this.domNode, 'dijitMenuItemHover');
        },

        setDisabled: function(/*Boolean*/ value){
                // summary: enable or disable this menu item
                this.disabled = value;
                dojo[value ? "addClass" : "removeClass"](this.domNode, 'dijitMenuItemDisabled');
                dijit.setWaiState(this.containerNode, 'disabled', value ? 'true' : 'false');
        }
});

dojo.declare(
        "dijit.PopupMenuItem",
        dijit.MenuItem,
{
        _fillContent: function(){
                // my inner HTML contains both the menu item text and a popup widget, like
                // <div dojoType="dijit.PopupMenuItem">
                //              <span>pick me</span>
                //              <popup> ... </popup>
                // </div>
                // the first part holds the menu item text and the second part is the popup
                if(this.srcNodeRef){
                        var nodes = dojo.query("*", this.srcNodeRef);
                        dijit.PopupMenuItem.superclass._fillContent.call(this, nodes[0]);

                        // save pointer to srcNode so we can grab the drop down widget after it's instantiated
                        this.dropDownContainer = this.srcNodeRef;
                }
        },

        startup: function(){
                // we didn't copy the dropdown widget from the this.srcNodeRef, so it's in no-man's
                // land now.  move it to document.body.
                if(!this.popup){
                        var node = dojo.query("[widgetId]", this.dropDownContainer)[0];
                        this.popup = dijit.byNode(node);
                }
                dojo.body().appendChild(this.popup.domNode);

                this.popup.domNode.style.display="none";
                dojo.addClass(this.expand, "dijitMenuExpandEnabled");
                dojo.style(this.expand, "display", "");
                dijit.setWaiState(this.containerNode, "haspopup", "true");
        }
});

dojo.declare(
        "dijit.MenuSeparator",
        [dijit._Widget, dijit._Templated, dijit._Contained],
{
        // summary
        //      A line between two menu items

        templateString: '<tr class="dijitMenuSeparator"><td colspan=3>'
                        +'<div class="dijitMenuSeparatorTop"></div>'
                        +'<div class="dijitMenuSeparatorBottom"></div>'
                        +'</td></tr>',

        postCreate: function(){
                dojo.setSelectable(this.domNode, false);
        },
        
        isFocusable: function(){
                // summary:
                //              over ride to always return false
                return false;
        }
});

}