/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* See LICENSE.txt included in this distribution for the specific
* language governing permissions and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at LICENSE.txt.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
* Portions Copyright 2011, 2012, Jens Elkner.
*/
YUI.add('symbols-panel', function(Y) {
"use strict";
var L = Y.Lang, BB = 'boundingBox',
RESIZE='resize', KEYDOWN = 'keydown', MOUSEUP = 'mouseup',
TOP = 'top', BOTTOM = 'bottom', RIGHT = 'right', LEFT='left',
PWIDTH = 'pWidth', PHEIGHT = 'pHeight', PMARGIN = 'pMargin',
HEIGHT = 'height', WIDTH = 'width', VISIBLE = 'visible';
var getClassName = Y.ClassNameManager.getClassName;
var panel = Y.Base.create('SymbolsPanel', Y.Widget,
[Y.WidgetStdMod, Y.WidgetPosition, Y.WidgetStack, Y.WidgetAutohide,
Y.WidgetButtons],
{ // instance members
BOUNDING_TEMPLATE : '<div id="symbolsBB"></div>',
CONTENT_TEMPLATE : '<div id="symbolsCB"></div>',
// private helpers
_getTop : function() { /* get optimal y position */
var h = Y.one('#whole_header');
return h.getY() + h.get('offsetHeight') + this.get(PMARGIN)[TOP];
},
_getLeft : function() { /* get optimal x position */
return Y.DOM.winWidth() - this.get(WIDTH)
- this.get(PMARGIN)[RIGHT] - Y.DOM.getScrollbarWidth();
},
_getHeight: function() { /* get optimal height */
var h = Y.DOM.winHeight() - this._getTop() - this.get(PMARGIN)[BOTTOM];
if (h > this.get(PHEIGHT)) {
h = this.get(PHEIGHT);
} else if (h < 50) {
h = 50;
}
return h;
},
_adjustPosition : function() {
var t, sbw = Y.DOM.getScrollbarWidth(), //assume same for vert/horiz
w = this.get(WIDTH), h = this.get(HEIGHT)
var right = Y.DOM.winWidth() - sbw - this.get(PMARGIN)[RIGHT],
bottom = Y.DOM.winHeight() - sbw - this.get(PMARGIN)[BOTTOM];
// assure a minimum size of 50x50
if (w < 50) {
w = this.get(PWIDTH);
this.set(WIDTH, w);
}
if (h < 50) {
h = this.get(PHEIGHT);
this.set(HEIGHT, h);
}
// at least a part of the head should be visible for dragging
t = this.get('y');
if (t < 0 || bottom < 30) {
this.set('y', 0);
} else if (t + 30 > bottom) {
this.set('y', bottom - 30);
}
t = this.get('x');
if (t + w < 50 || right < 50) { // 50 because of the close button
this.set('x', 50 - w);
} else if (t + 50 > right) {
this.set('x', right - 50);
}
},
// public
initializer : function(config) {
config || (config = {});
this.plug(Y.Plugin.Drag);
this._listener = {};
var bb = this.get(BB);
var that = this;
this._listener[MOUSEUP] = bb.on(MOUSEUP, function(e) {
if (e.target == this) {
that._fillHeight();
};
});
this.set(HEIGHT, this._getHeight());
this.set(WIDTH, this.get(PWIDTH));
this.set('xy', [ this._getLeft(), this._getTop() ]);
if (Y.UA.safari > 0) {
bb.setStyle(RESIZE, 'none'); /* safari does stupid things */
}
this.dd.addHandle(this._stdModNode.one('#symbolsHd'));
},
/**
* Hide the panel. It is different from just setting the 'visible'
* property: unneeded listeners are removed from the panel after it
* has been hidden.
* @Override
*/
hide : function() {
this.set(VISIBLE, false);
if (this._listener[KEYDOWN]) {
Y.detach(this._listener[KEYDOWN]);
this._listener[KEYDOWN] = null;
}
if (this._listener[RESIZE]) {
Y.detach(this._listener[RESIZE]);
this._listener[RESIZE] = null;
}
},
/**
* Show the panel. It is different from just setting the 'visible'
* property: adjusts the position of the panel if necessary, syncs the
* height of the fillSection (default: body) and adds additional
* listeners before making it visible.
* @Override
*/
show : function() {
var that = this;
if (!this.get(VISIBLE)) {
// a little hack for people who wanna play with resize
this._listener[KEYDOWN] = Y.on(KEYDOWN, function(e) {
if (e.keyCode !== 20) { /* scrollLock */
return false;
}
var bb = that.get(BB);
var style = bb.getStyle('overflow');
style = (style === 'scroll') ? 'hidden' : 'scroll';
bb.setStyle('overflow', style);
style = bb.getStyle(RESIZE);
if (style != 'both') {
bb.setStyle(RESIZE, 'both');
}
});
this._listener[RESIZE] = Y.on(RESIZE, function(e) {
that._adjustPosition();
that._fillHeight();
});
this._adjustPosition();
this._fillHeight();
}
this.set(VISIBLE, true);
},
BUTTONS : {
close: {
label : 'Close',
action : 'hide',
section : 'header',
classNames : getClassName('button', 'close')
}
},
}, {
// static
ATTRS: {
buttons : {
value : ['close']
},
/* @attribute {Integer} preferred width of the panel */
pWidth : {
value: 240,
validator: L.isNumber
},
/* @attribute {Integer} preferred height of the panel */
pHeight : {
value: 480,
validator: L.isNumber
},
/* @attribute {} preferred distance of the panel incl. margins to
* its "container" - used for positioning only. Invalid values are
* treated as 0. */
pMargin : {
value: { top: 10, right: 10, bottom: 10, left: 10 },
_setter: function (margin) {
if (L.isNumber(margin)) {
return { top: margin, right: margin, bottom: margin, left: margin };
}
if (L.isArray(margin)) {
return {
top : L.isNumber(margin[0]) || 0,
right : L.isNumber(margin[1]) || 0,
bottom : L.isNumber(margin[2]) || 0,
left : L.isNumber(margin[3]) || 0
};
}
if (L.isObject) {
return {
top : L.isNumber(margin[0]) || 0,
right : L.isNumber(margin[1]) || 0,
bottom : L.isNumber(margin[2]) || 0,
left : L.isNumber(margin[3]) || 0
}
}
return { top: 0, right: 0, bottom: 0, left: 0 };
}
},
/* @attribute {Integer} CSS z-index value */
zIndex : {
value: 100
}
},
/**
* Create a node suitable to be used as <var>srcNode</var> aka content
* box for an instance of SymbolPanel. The format for the symbolClass
* parameter is as follows:
* <pre>
* symbolClass = '[' Section[','Section]*']'
* Section = '[' SectionName',' CssClassName',' '[' Entry[',' Entry]* ']'']'
* Entry = '[' SymbolName',' LineNumber ']'
* *Name = &lt;String&gt;
* *Number = &lt;Integer&gt;
* </pre>
* @param symbolClass symbol classes to use to create the body of the
* panel.
* @param title the text to show in the head of the content box.
* @return a non-<code>null</code> node.
*/
createSrcNode : function(symbolClass, title) {
var Escape = Y.Escape;
symbolClass || (symbolClass = []);
title || (title = 'All Symbols');
var contents = "<div id='symbolsCB'>"
+ "<div id='symbolsHd' class='yui3-widget-hd'><h3>" + title
+ "</h3></div>"
+ "<div id='symbols' class='yui3-widget-bd'>";
for ( var i = 0; i < symbolClass.length; i++) {
var symbol_class = symbolClass[i];
var class_name = symbol_class[1];
var symbols = symbol_class[2];
contents += "<h4>" + symbol_class[0] + "</h4><ul>";
for ( var j = 0; j < symbols.length; j++) {
contents += "<li><a href='#" + symbols[j][1]
+ "' class='" + class_name + "'>"
+ Escape.html(symbols[j][0]) + "</a></li>";
}
contents += "</ul>"
}
contents += "</div>"
+ "<div id='symbolsFt' class='yui3-widget-ft'></div></div>"
return Y.Node.create(contents);
}
});
Y.SymbolsPanel = panel;
}, '3.5.0pr2', {
requires: ['widget', 'widget-autohide', 'widget-buttons',
'widget-position', 'widget-stack', 'widget-stdmod',
'dd-plugin', 'escape']
});