/** * This file is part of the TYPO3 CMS project. * * It is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License, either version 2 * of the License, or any later version. * * For the full copyright and license information, please read the * LICENSE.txt file that was distributed with this source code. * * The TYPO3 project - inspiring people to share! */ Element.addMethods({ pngHack: function(element) { element = $(element); var transparentGifPath = 'clear.gif'; // If there is valid element, it is an image and the image file ends with png: if (Object.isElement(element) && element.tagName === 'IMG' && element.src.endsWith('.png')) { var alphaImgSrc = element.src; var sizingMethod = 'scale'; element.src = transparentGifPath; } if (alphaImgSrc) { element.style.filter = 'progid:DXImageTransform.Microsoft.AlphaImageLoader(src="#{alphaImgSrc}",sizingMethod="#{sizingMethod}")'.interpolate( { alphaImgSrc: alphaImgSrc, sizingMethod: sizingMethod }); } return element; } }); var IECompatibility = Class.create({ /** * initializes the compatibility class */ initialize: function() { Event.observe(document, 'dom:loaded', function() { $$('input[type="checkbox"]').invoke('addClassName', 'checkbox'); }.bind(this)); Event.observe(window, 'load', function() { if (Prototype.Browser.IE) { var version = parseFloat(navigator.appVersion.split(';')[1].strip().split(' ')[1]); if (version === 6) { $$('img').each(function(img) { img.pngHack(); }); $$('#typo3-menu li ul li').each(function(li) { li.setStyle({height: '21px'}); }); } } }); } }); if (Prototype.Browser.IE) { var TYPO3IECompatibilty = new IECompatibility(); } /** * This file is part of the TYPO3 CMS project. * * It is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License, either version 2 * of the License, or any later version. * * For the full copyright and license information, please read the * LICENSE.txt file that was distributed with this source code. * * The TYPO3 project - inspiring people to share! */ /** * Javascript functions regarding the clickmenu * relies on the javascript library "prototype" */ /** * new clickmenu code to make an AJAX call and render the * AJAX result in a layer next to the mouse cursor */ var Clickmenu = { clickURL: 'alt_clickmenu.php', ajax: true, // \TYPO3\CMS\Backend\Template\DocumentTemplate::isCMLayers mousePos: { X: null, Y: null }, delayClickMenuHide: false, /** * main function, called from most clickmenu links * @param table table from where info should be fetched * @param uid the UID of the item * @param listFr list Frame? * @param enDisItems Items to disable / enable * @param backPath TYPO3 backPath * @param addParams additional params * @return nothing */ show: function(table, uid, listFr, enDisItems, backPath, addParams) { var params = 'table=' + encodeURIComponent(table) + '&uid=' + uid + '&listFr=' + listFr + '&enDisItems=' + enDisItems + '&backPath=' + backPath + '&addParams=' + addParams; this.callURL(params); }, /** * switch function that either makes an AJAX call * or loads the request in the top frame * * @param params parameters added to the URL * @return nothing */ callURL: function(params) { if (this.ajax && Ajax.getTransport()) { // run with AJAX params += '&ajax=1'; var call = new Ajax.Request(this.clickURL, { method: 'get', parameters: params, onComplete: function(xhr) { var response = xhr.responseXML; if (!response.getElementsByTagName('data')[0]) { var res = params.match(/&reloadListFrame=(0|1|2)(&|$)/); var reloadListFrame = parseInt(res[1], 0); if (reloadListFrame) { var doc = reloadListFrame != 2 ? top.content.list_frame : top.content; doc.location.reload(true); } return; } var menu = response.getElementsByTagName('data')[0].getElementsByTagName('clickmenu')[0]; var data = menu.getElementsByTagName('htmltable')[0].firstChild.data; var level = menu.getElementsByTagName('cmlevel')[0].firstChild.data; this.populateData(data, level); }.bind(this) }); } }, /** * fills the clickmenu with content and displays it correctly * depending on the mouse position * @param data the data that will be put in the menu * @param level the depth of the clickmenu */ populateData: function(data, level) { if (!$('contentMenu0')) { this.addClickmenuItem(); } level = parseInt(level, 10) || 0; var obj = $('contentMenu' + level); if (obj && (level === 0 || Element.visible('contentMenu' + (level-1)))) { obj.innerHTML = data; var x = this.mousePos.X; var y = this.mousePos.Y; var dimsWindow = document.viewport.getDimensions(); dimsWindow.width = dimsWindow.width-20; // saving margin for scrollbars var dims = Element.getDimensions(obj); // dimensions for the clickmenu var offset = document.viewport.getScrollOffsets(); var relative = { X: this.mousePos.X - offset.left, Y: this.mousePos.Y - offset.top }; // adjusting the Y position of the layer to fit it into the window frame // if there is enough space above then put it upwards, // otherwise adjust it to the bottom of the window if (dimsWindow.height - dims.height < relative.Y) { if (relative.Y > dims.height) { y -= (dims.height - 10); } else { y += (dimsWindow.height - dims.height - relative.Y); } } // adjusting the X position like Y above, but align it to the left side of the viewport if it does not fit completely if (dimsWindow.width - dims.width < relative.X) { if (relative.X > dims.width) { x -= (dims.width - 10); } else if ((dimsWindow.width - dims.width - relative.X) < offset.left) { x = offset.left; } else { x += (dimsWindow.width - dims.width - relative.X); } } obj.style.left = x + 'px'; obj.style.top = y + 'px'; Element.show(obj); } if (/MSIE5/.test(navigator.userAgent)) { this._toggleSelectorBoxes('hidden'); } }, /** * event handler function that saves the actual position of the mouse * in the Clickmenu object * @param event the event object */ calcMousePosEvent: function(event) { if (!event) { event = window.event; } this.mousePos.X = Event.pointerX(event); this.mousePos.Y = Event.pointerY(event); this.mouseOutFromMenu('contentMenu0'); this.mouseOutFromMenu('contentMenu1'); }, /** * hides a visible menu if the mouse has moved outside * of the object * @param obj the object to hide * @result nothing */ mouseOutFromMenu: function(obj) { obj = $(obj); if (obj && Element.visible(obj) && !Position.within(obj, this.mousePos.X, this.mousePos.Y)) { this.hide(obj); if (/MSIE5/.test(navigator.userAgent) && obj.id === 'contentMenu0') { this._toggleSelectorBoxes('visible'); } } else if (obj && Element.visible(obj)) { this.delayClickMenuHide = true; } }, /** * hides a clickmenu * * @param obj the clickmenu object to hide * @result nothing */ hide: function(obj) { this.delayClickMenuHide = false; window.setTimeout(function() { if (!Clickmenu.delayClickMenuHide) { Element.hide(obj); } }, 500); }, /** * hides all clickmenus */ hideAll: function() { this.hide('contentMenu0'); this.hide('contentMenu1'); }, /** * hides / displays all selector boxes in a page, fixes an IE 5 selector problem * originally by Michiel van Leening * * @param action hide (= "hidden") or show (= "visible") * @result nothing */ _toggleSelectorBoxes: function(action) { for (var i = 0; i < document.forms.length; i++) { for (var j = 0; j < document.forms[i].elements.length; j++) { if (document.forms[i].elements[j].type == 'select-one') { document.forms[i].elements[j].style.visibility = action; } } } }, /** * manipulates the DOM to add the divs needed for clickmenu at the bottom of the
-tag * * @return nothing */ addClickmenuItem: function() { var code = ''; var insert = new Insertion.Bottom(document.getElementsByTagName('body')[0], code); } } // register mouse movement inside the document Event.observe(document, 'mousemove', Clickmenu.calcMousePosEvent.bindAsEventListener(Clickmenu), true); // @deprecated: Deprecated functions since 4.2, here for compatibility, remove in 4.4+ // ## BEGIN ## // Still used in Core: typo3/alt_clickmenu.php::linkItem() function showClickmenu_raw(url) { var parts = url.split('?'); if (parts.length === 2) { Clickmenu.clickURL = parts[0]; Clickmenu.callURL(parts[1]); } else { Clickmenu.callURL(url); } } function showClickmenu_noajax(url) { Clickmenu.ajax = false; showClickmenu_raw(url); } function setLayerObj(tableData, cmLevel) { Clickmenu.populateData(tableData, cmLevel); } function hideEmpty() { Clickmenu.hideAll(); return false; } function hideSpecific(level) { if (level === 0 || level === 1) { Clickmenu.hide('contentMenu'+level); } } function showHideSelectorBoxes(action) { toggleSelectorBoxes(action); } // ## END ## /** * This file is part of the TYPO3 CMS project. * * It is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License, either version 2 * of the License, or any later version. * * For the full copyright and license information, please read the * LICENSE.txt file that was distributed with this source code. * * The TYPO3 project - inspiring people to share! */ Ext.ns('TYPO3.Components', 'TYPO3.Components.Tree'); /** * TYPO3window - General TYPO3 tree component */ TYPO3.Components.Tree = {}; TYPO3.Components.Tree.StandardTreeItemData = []; TYPO3.Components.Tree.StandardTree = function(config) { var conf = Ext.apply({ header: false, width: 280, rootVisible: false, useArrows: false, lines: true, autoScroll: true, containerScroll: true, exclusiveSelectedKey: null, stateful: true, filterOptionStartsWith: true, countSelectedNodes: 0, loader: new Ext.tree.TreeLoader({ preloadChildren: true, clearOnLoad: false }), root: new Ext.tree.AsyncTreeNode({ text: TYPO3.l10n.localize('tcatree'), id: 'root', expanded: true, children: TYPO3.Components.Tree.StandardTreeItemData[config.id] }), collapseFirst: false, listeners: { 'checkchange': function(checkedNode, checked) { if (Ext.isFunction(this.checkChangeHandler)) { this.checkChangeHandler.call(this, checkedNode, checked); } }, scope: this } }, config); TYPO3.Components.Tree.StandardTree.superclass.constructor.call(this, conf); }; Ext.extend(TYPO3.Components.Tree.StandardTree, Ext.tree.TreePanel, { initComponent: function() { // prepare hidden input field (make sure only comma separated uids are present) var selected = Ext.fly('treeinput' + this.id).dom.value.split(','); for (var i = 0; i < selected.length; i++) { var value = selected[i].split('|'); selected[i] = value[0]; } Ext.fly('treeinput' + this.id).dom.value = selected.join(','); Ext.apply(this, { tbar: this.initialConfig.showHeader ? TYPO3.Components.Tree.Toolbar([], this) : null }); TYPO3.Components.Tree.StandardTree.superclass.initComponent.call(this); }, filterTree: function(filterText) { var text = filterText.getValue(); Ext.each(this.hiddenNodes, function(node) { node.ui.show(); node.ui.removeClass('bgColor6'); }); if (!text) { this.filter.clear(); return; } this.expandAll(); var regText = (this.filterOptionStartsWith ? '^' : '') + Ext.escapeRe(text); var re = new RegExp(regText, 'i'); // hide empty nodes that weren't filtered this.hiddenNodes = []; var me = this; this.root.cascade(function(node) { if (node.ui.ctNode.offsetHeight < 3) { if (!re.test(node.text)) { node.ui.hide(); me.hiddenNodes.push(node); } else { node.ui.addClass('bgColor6'); } } }, this); } }); TYPO3.Components.Tree.Toolbar = function(items, scope) { items = items || []; items.push([ ' ', { iconCls: 't3-icon t3-icon-actions t3-icon-actions-system t3-icon-system-tree-search-open', menu: { items: [ { text: TYPO3.l10n.localize('tcatree.filter.startsWith'), checked: true, group: 'searchStartsWith', handler: function(item) { scope.filterOptionStartsWith = true; scope.filterTree(scope.getTopToolbar().getComponent('filterText')); }, scope: scope }, { text: TYPO3.l10n.localize('tcatree.filter.contains'), checked: false, group: 'searchStartsWith', handler: function(item) { scope.filterOptionStartsWith = false; scope.filterTree(scope.getTopToolbar().getComponent('filterText')); }, scope: scope } ] } }, new Ext.form.TextField({ width: 150, emptyText: TYPO3.l10n.localize('tcatree.findItem'), enableKeyEvents: true, itemId: 'filterText', listeners:{ render: function(f) { this.filter = new Ext.tree.TreeFilter(this, { clearBlank: true, autoClear: true }); }, keydown: { fn: scope.filterTree, buffer: 350, scope: scope }, scope: scope } }), '->', { iconCls: 't3-icon t3-icon-apps t3-icon-apps-tcatree t3-icon-tcatree-select-recursive', tooltip: TYPO3.lang['tcatree.enableRecursiveSelection'], enableToggle: true, disable: scope.tcaSelectRecursive, toggleHandler: function(btn, state) { this.tcaSelectRecursive = state; }, scope: scope }, { iconCls: 'icon-expand-all', tooltip: TYPO3.l10n.localize('tcatree.expandAll'), handler: function() { this.root.expand(true); }, scope: scope }, { iconCls: 'icon-collapse-all', tooltip: TYPO3.l10n.localize('tcatree.collapseAll'), handler: function() { this.root.collapse(true); }, scope: scope } ]); return items; }; TYPO3.Components.Tree.EmptySelectionModel = new Ext.tree.DefaultSelectionModel({ select: Ext.emptyFn }) TYPO3.Components.Tree.TcaCheckChangeHandler = function(checkedNode, checked) { var exclusiveKeys = this.tcaExclusiveKeys.split(','), uid = '' + checkedNode.attributes.uid, selected = Ext.fly('treeinput' + this.id).dom.value.length ? Ext.fly('treeinput' + this.id).dom.value.split(',') : []; this.suspendEvents(); if (this.tcaExclusiveKeys.length) { if (checked === true && exclusiveKeys.indexOf(uid) > -1) { // this key is exclusive, so uncheck all others this.root.cascade(function(node) { if (node !== checkedNode && node.attributes.checked) { node.attributes.checked = false; node.ui.toggleCheck(false); } }); this.exclusiveSelectedKey = uid; } else if (checked === true && exclusiveKeys.indexOf(uid) === -1 && !Ext.isEmpty(this.exclusiveSelectedKey)) { // this key is exclusive, so uncheck all others this.root.cascade(function(node) { if (exclusiveKeys.indexOf('' + node.attributes.uid) > -1) { node.attributes.checked = false; node.ui.toggleCheck(false); } }); this.exclusiveSelectedKey = null; } } if (checked === true && this.countSelectedNodes >= this.tcaMaxItems) { checkedNode.attributes.checked = false; checkedNode.getUI().toggleCheck(false); this.resumeEvents(); return false; } if (checked) { checkedNode.getUI().addClass('complete'); } else { checkedNode.getUI().removeClass('complete'); } // if recursive selection is asked, hand over selection if(this.tcaSelectRecursive) { checkedNode.cascade(function(node) { node.attributes.checked = checkedNode.attributes.checked; node.ui.toggleCheck(checkedNode.attributes.checked); }) } this.root.cascade(function(node) { if (node.ui.isChecked()) { if (selected.indexOf(node.attributes.uid) < 0) { selected.push(node.attributes.uid) } } else { var index = selected.indexOf(node.attributes.uid); if (index >= 0) { selected.splice(index, 1); } } }); this.countSelectedNodes = selected.length; Ext.fly('treeinput' + this.id).dom.value = selected.join(','); eval(this.onChange); this.resumeEvents(); }; /** * This file is part of the TYPO3 CMS project. * * It is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License, either version 2 * of the License, or any later version. * * For the full copyright and license information, please read the * LICENSE.txt file that was distributed with this source code. * * The TYPO3 project - inspiring people to share! */ /** * javascript functions regarding the "dyntabmenu" used throughout the TYPO3 backend */ var DTM_array = DTM_array || []; // if tabs are used in a popup window the array might not exists if (!top.DTM_currentTabs) { top.DTM_currentTabs = []; } function DTM_activate(idBase,index,doToogle) { // Check, whether the given index really exists if (!document.getElementById(idBase+'-'+index+'-MENU')) { // force the index to be the first one in case of saved settings are not valid anymore index = 1; } // Hiding all: if (DTM_array[idBase]) { for(var cnt = 0; cnt < DTM_array[idBase].length; cnt++) { if (DTM_array[idBase][cnt] !== idBase + '-' + index) { document.getElementById(DTM_array[idBase][cnt]+'-DIV').style.display = 'none'; // Only Overriding when Tab not disabled if (document.getElementById(DTM_array[idBase][cnt]+'-MENU').attributes.getNamedItem('class').nodeValue !== 'disabled') { document.getElementById(DTM_array[idBase][cnt]+'-MENU').attributes.getNamedItem('class').nodeValue = 'tab'; } } } } // Showing one: if (document.getElementById(idBase+'-'+index+'-DIV')) { if (doToogle && document.getElementById(idBase+'-'+index+'-DIV').style.display === 'block') { document.getElementById(idBase+'-'+index+'-DIV').style.display = 'none'; document.getElementById(idBase+'-'+index+'-MENU').attributes.getNamedItem('class').nodeValue = 'tab'; top.DTM_currentTabs[idBase] = -1; } else { document.getElementById(idBase+'-'+index+'-DIV').style.display = 'block'; document.getElementById(idBase+'-'+index+'-MENU').attributes.getNamedItem('class').nodeValue = 'tabact'; top.DTM_currentTabs[idBase] = index; } } document.getElementById(idBase+'-'+index+'-MENU').attributes.getNamedItem('class').nodeValue = 'tabact'; } function DTM_toggle(idBase,index,isInit) { // Showing one: if (document.getElementById(idBase+'-'+index+'-DIV')) { if (document.getElementById(idBase+'-'+index+'-DIV').style.display === 'block') { document.getElementById(idBase+'-'+index+'-DIV').style.display = 'none'; if (isInit) { document.getElementById(idBase+'-'+index+'-MENU').attributes.getNamedItem('class').nodeValue = 'tab'; } top.DTM_currentTabs[idBase+'-'+index] = 0; } else { document.getElementById(idBase+'-'+index+'-DIV').style.display = 'block'; if (isInit) { document.getElementById(idBase+'-'+index+'-MENU').attributes.getNamedItem('class').nodeValue = 'tabact'; } top.DTM_currentTabs[idBase+'-'+index] = 1; } } } /** * * MD5 (Message-Digest Algorithm) * http://www.webtoolkit.info/ * **/ function MD5(string) { function RotateLeft(lValue, iShiftBits) { return (lValue<The zone is defined using top
, right
, bottom
,
* left
, width
and height
options which specify
* the bounds of the zone in a similar manner to the CSS style properties of those names.
This class encapsulates an absolute area of the document bounded by a list of points.
* @constructor * Create a new Polygon * @param {Object} points An Array of[n,n]
point specification Arrays, or
* an Array of Ext.lib.Points, or an HtmlElement, or an Ext.lib.Region.
*/
Ext.lib.Polygon = Ext.extend(Ext.lib.Region, {
constructor: function(points) {
var i, l, el;
if (l = points.length) {
if (points[0].x) {
for (i = 0; i < l; i++) {
points[i] = [ points[i].x, points[i].y ];
}
}
this.points = points;
} else {
if (el = Ext.get(points)) {
points = Ext.lib.Region.getRegion(el.dom);
}
if (points instanceof Ext.lib.Region) {
this.points = [
[points.left, points.top],
[points.right, points.top],
[points.right, points.bottom],
[points.left, points.bottom]
];
}
}
},
/**
* Returns a new Polygon translated by the specified X
and Y
increments.
* @param xDelta {Number} The X
translation increment.
* @param xDelta {Number} The Y
translation increment.
* @return {Polygon} The resulting Polygon.
*/
translate: function(xDelta, yDelta) {
var r = [], p = this.points, l = p.length, i;
for (i = 0; i < l; i++) {
r[i] = [ p[i][0] + xDelta, p[i][1] + yDelta ];
}
return new Ext.lib.Polygon(r);
},
/**
* Returns the area of this Polygon.
*/
getArea: function() {
var p = this.points, l = p.length, area = 0, i, j = 0;
for (i = 0; i < l; i++) {
j++;
if (j == l) {
j = 0;
}
area += (p[i][0] + p[j][0]) * (p[i][1] - p[j][1]);
}
return area * 0.5;
},
/**
* Returns true
if this Polygon contains the specified point. Thanks
* to http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html for the algorithm.
* @param pt {Point|Number} Either an Ext.lib.Point object, or the X
coordinate to test.
* @param py {Number} Optional. If the first parameter was an X
coordinate, this is the Y
coordinate.
*/
contains: function(pt, py) {
var f = (arguments.length == 1),
testX = f ? pt.x : pt,
testY = f ? pt.y : py,
p = this.points,
nvert = p.length,
j = nvert - 1,
i, j, c = false;
for (i = 0; i < nvert; j = i++) {
if ( ((p[i][1] > testY) != (p[j][1] > testY)) &&
(testX < (p[j][0]-p[i][0]) * (testY-p[i][1]) / (p[j][1]-p[i][1]) + p[i][0])) {
c = !c;
}
}
return c;
}
});
/**
* @class Ext.Resizable
* @extends Ext.util.Observable
* This is an override of Ext.Resizable to make usage of the Ex.ux.EventZone
* Applies virtual drag handles to an element to make it resizable.
*Here is the list of valid resize handles:
*Value Description ------ ------------------- 'n' north 's' south 'e' east 'w' west 'nw' northwest 'sw' southwest 'se' southeast 'ne' northeast 'all' all*
Here's an example showing the creation of a typical Resizable:
*
var resizer = new Ext.Resizable('element-id', {
handles: 'all',
minWidth: 200,
minHeight: 100,
maxWidth: 500,
maxHeight: 400,
pinned: true
});
resizer.on('resize', myHandler);
* To hide a particular handle, set its display to none in CSS, or through script:
* resizer.east.setDisplayed(false);
{@link #dynamic}==true
). Defaults to 0.
*/
heightIncrement : 0,
/**
* @cfg {Number} widthIncrement The increment to snap the width resize in pixels
* (only applies if {@link #dynamic}==true
). Defaults to 0.
*/
widthIncrement : 0,
/**
* @cfg {Number} minHeight The minimum height for the element (defaults to 5)
*/
minHeight : 5,
/**
* @cfg {Number} minWidth The minimum width for the element (defaults to 5)
*/
minWidth : 5,
/**
* @cfg {Number} maxHeight The maximum height for the element (defaults to 10000)
*/
maxHeight : 10000,
/**
* @cfg {Number} maxWidth The maximum width for the element (defaults to 10000)
*/
maxWidth : 10000,
/**
* @cfg {Number} minX The minimum x for the element (defaults to 0)
*/
minX: 0,
/**
* @cfg {Number} minY The minimum x for the element (defaults to 0)
*/
minY: 0,
/**
* @cfg {Boolean} pinned True to ensure that the resize handles are always visible, false to display them only when the
* user mouses over the resizable borders. This is only applied at config time. (defaults to false)
*/
pinned : false,
/**
* @cfg {Boolean} preserveRatio True to preserve the original ratio between height
* and width during resize (defaults to false)
*/
preserveRatio : false,
/**
* @cfg {Ext.lib.Region} resizeRegion Constrain the resize to a particular region
*/
/**
* Perform a manual resize and fires the 'resize' event.
* @param {Number} width
* @param {Number} height
*/
resizeTo : function(width, height){
this.el.setSize(width, height);
this.fireEvent('resize', this, width, height, null);
},
// private
startSizing : function(e, handle){
this.fireEvent('beforeresize', this, e);
if(this.enabled){ // 2nd enabled check in case disabled before beforeresize handler
e.stopEvent();
Ext.getDoc().on({
scope: this,
mousemove: this.onMouseMove,
mouseup: {
fn: this.onMouseUp,
single: true,
scope: this
}
});
Ext.getBody().addClass('ux-resizable-handle-' + handle.position);
this.resizing = true;
this.startBox = this.el.getBox();
this.startPoint = e.getXY();
this.offsets = [(this.startBox.x + this.startBox.width) - this.startPoint[0],
(this.startBox.y + this.startBox.height) - this.startPoint[1]];
if(this.constrainTo) {
var ct = Ext.get(this.constrainTo);
this.resizeRegion = ct.getRegion().adjust(
ct.getFrameWidth('t'),
ct.getFrameWidth('l'),
-ct.getFrameWidth('b'),
-ct.getFrameWidth('r')
);
}
this.proxy.setStyle('visibility', 'hidden'); // workaround display none
this.proxy.show();
this.proxy.setBox(this.startBox);
if(!this.dynamic){
this.proxy.setStyle('visibility', 'visible');
}
}
},
// private
onMouseDown : function(handle, e){
if(this.enabled && !this.activeHandle){
e.stopEvent();
this.activeHandle = handle;
this.startSizing(e, handle);
}
},
// private
onMouseUp : function(e){
Ext.getBody().removeClass('ux-resizable-handle-' + this.activeHandle.position)
.un('mousemove', this.onMouseMove, this);
var size = this.resizeElement();
this.resizing = false;
this.handleOut(this.activeHandle);
this.proxy.hide();
this.fireEvent('resize', this, size.width, size.height, e);
this.activeHandle = null;
},
// private
snap : function(value, inc, min){
if(!inc || !value){
return value;
}
var newValue = value;
var m = value % inc;
if(m > 0){
if(m > (inc/2)){
newValue = value + (inc-m);
}else{
newValue = value - m;
}
}
return Math.max(min, newValue);
},
/**
* Performs resizing of the associated Element. This method is called internally by this * class, and should not be called by user code.
*If a Resizable is being used to resize an Element which encapsulates a more complex UI * component such as a Panel, this method may be overridden by specifying an implementation * as a config option to provide appropriate behaviour at the end of the resize operation on * mouseup, for example resizing the Panel, and relaying the Panel's content.
*The new area to be resized to is available by examining the state of the {@link #proxy} * Element. Example:
new Ext.Panel({
title: 'Resize me',
x: 100,
y: 100,
renderTo: Ext.getBody(),
floating: true,
frame: true,
width: 400,
height: 200,
listeners: {
render: function(p) {
new Ext.Resizable(p.getEl(), {
handles: 'all',
pinned: true,
transparent: true,
resizeElement: function() {
var box = this.proxy.getBox();
p.updateBox(box);
if (p.layout) {
p.doLayout();
}
return box;
}
});
}
}
}).show();
*/
resizeElement : function(){
var box = this.proxy.getBox();
if(this.updateBox){
this.el.setBox(box, false, this.animate, this.duration, null, this.easing);
}else{
this.el.setSize(box.width, box.height, this.animate, this.duration, null, this.easing);
}
if(!this.dynamic){
this.proxy.hide();
}
return box;
},
// private
constrain : function(v, diff, m, mx){
if(v - diff < m){
diff = v - m;
}else if(v - diff > mx){
diff = v - mx;
}
return diff;
},
// private
onMouseMove : function(e){
if(this.enabled && this.activeHandle){
try{// try catch so if something goes wrong the user doesn't get hung
if(this.resizeRegion && !this.resizeRegion.contains(e.getPoint())) {
return;
}
//var curXY = this.startPoint;
var curSize = this.curSize || this.startBox,
x = this.startBox.x, y = this.startBox.y,
ox = x,
oy = y,
w = curSize.width,
h = curSize.height,
ow = w,
oh = h,
mw = this.minWidth,
mh = this.minHeight,
mxw = this.maxWidth,
mxh = this.maxHeight,
wi = this.widthIncrement,
hi = this.heightIncrement,
eventXY = e.getXY(),
diffX = -(this.startPoint[0] - Math.max(this.minX, eventXY[0])),
diffY = -(this.startPoint[1] - Math.max(this.minY, eventXY[1])),
pos = this.activeHandle.position,
tw,
th;
switch(pos){
case 'east':
w += diffX;
w = Math.min(Math.max(mw, w), mxw);
break;
case 'south':
h += diffY;
h = Math.min(Math.max(mh, h), mxh);
break;
case 'southeast':
w += diffX;
h += diffY;
w = Math.min(Math.max(mw, w), mxw);
h = Math.min(Math.max(mh, h), mxh);
break;
case 'north':
diffY = this.constrain(h, diffY, mh, mxh);
y += diffY;
h -= diffY;
break;
case 'west':
diffX = this.constrain(w, diffX, mw, mxw);
x += diffX;
w -= diffX;
break;
case 'northeast':
w += diffX;
w = Math.min(Math.max(mw, w), mxw);
diffY = this.constrain(h, diffY, mh, mxh);
y += diffY;
h -= diffY;
break;
case 'northwest':
diffX = this.constrain(w, diffX, mw, mxw);
diffY = this.constrain(h, diffY, mh, mxh);
y += diffY;
h -= diffY;
x += diffX;
w -= diffX;
break;
case 'southwest':
diffX = this.constrain(w, diffX, mw, mxw);
h += diffY;
h = Math.min(Math.max(mh, h), mxh);
x += diffX;
w -= diffX;
break;
}
var sw = this.snap(w, wi, mw);
var sh = this.snap(h, hi, mh);
if(sw != w || sh != h){
switch(pos){
case 'northeast':
y -= sh - h;
break;
case 'north':
y -= sh - h;
break;
case 'southwest':
x -= sw - w;
break;
case 'west':
x -= sw - w;
break;
case 'northwest':
x -= sw - w;
y -= sh - h;
break;
}
w = sw;
h = sh;
}
if(this.preserveRatio){
switch(pos){
case 'southeast':
case 'east':
h = oh * (w/ow);
h = Math.min(Math.max(mh, h), mxh);
w = ow * (h/oh);
break;
case 'south':
w = ow * (h/oh);
w = Math.min(Math.max(mw, w), mxw);
h = oh * (w/ow);
break;
case 'northeast':
w = ow * (h/oh);
w = Math.min(Math.max(mw, w), mxw);
h = oh * (w/ow);
break;
case 'north':
tw = w;
w = ow * (h/oh);
w = Math.min(Math.max(mw, w), mxw);
h = oh * (w/ow);
x += (tw - w) / 2;
break;
case 'southwest':
h = oh * (w/ow);
h = Math.min(Math.max(mh, h), mxh);
tw = w;
w = ow * (h/oh);
x += tw - w;
break;
case 'west':
th = h;
h = oh * (w/ow);
h = Math.min(Math.max(mh, h), mxh);
y += (th - h) / 2;
tw = w;
w = ow * (h/oh);
x += tw - w;
break;
case 'northwest':
tw = w;
th = h;
h = oh * (w/ow);
h = Math.min(Math.max(mh, h), mxh);
w = ow * (h/oh);
y += th - h;
x += tw - w;
break;
}
}
this.proxy.setBounds(x, y, w, h);
if(this.dynamic){
this.resizeElement();
}
}catch(ex){}
}
},
// private
handleOver : function(handle){
if(this.enabled){
Ext.getBody().addClass('ux-resizable-handle-' + handle.position);
}
},
// private
handleOut : function(handle){
if(!this.resizing){
Ext.getBody().removeClass('ux-resizable-handle-' + handle.position);
}
},
/**
* Returns the element this component is bound to.
* @return {Ext.Element}
*/
getEl : function(){
return this.el;
},
/**
* Destroys this resizable. If the element was wrapped and
* removeEl is not true then the element remains.
* @param {Boolean} removeEl (optional) true to remove the element from the DOM
*/
destroy : function(removeEl){
Ext.destroy(this.dd, this.proxy);
this.proxy = null;
var ps = Ext.Resizable.positions;
for(var k in ps){
if(typeof ps[k] != 'function' && this[ps[k]]){
this[ps[k]].destroy();
}
}
if(removeEl){
this.el.update('');
Ext.destroy(this.el);
this.el = null;
}
this.purgeListeners();
},
syncHandleHeight : function(){
var h = this.el.getHeight(true);
if(this.west.el){
this.west.el.setHeight(h);
}
if(this.east.el){
this.east.el.setHeight(h);
}
}
});
// private
// hash to map config positions to true positions
Ext.Resizable.positions = {
n: 'north', s: 'south', e: 'east', w: 'west', se: 'southeast', sw: 'southwest', nw: 'northwest', ne: 'northeast'
};
Ext.Resizable.cfg = {
north: {left: 7, right: -7, height: 7},
south: {left: 7, right: -7, top: -7},
east: {top: 7, bottom: -7, left: -7},
west: {top: 7, bottom: -7, width: 7},
southeast: {top: -7, left: -7},
southwest: {top: -7, width: 7},
northwest: {height: 7, width: 7},
northeast: {left: -7, height: 7}
};
// private
Ext.Resizable.Handle = function(rz, pos){
this.position = pos;
this.rz = rz;
var cfg = Ext.Resizable.cfg[pos] || Ext.Resizable.cfg[Ext.Resizable.positions[pos]];
this.ez = new Ext.ux.EventZone(Ext.apply({
position: pos,
el: rz.el
}, cfg));
this.ez.on({
mousedown: this.onMouseDown,
mouseenter: this.onMouseOver,
mouseleave: this.onMouseOut,
scope: this
});
};
// private
Ext.Resizable.Handle.prototype = {
cursor: 'move',
// private
afterResize : function(rz){
// do nothing
},
// private
onMouseDown : function(e){
this.rz.onMouseDown(this, e);
},
// private
onMouseOver : function(e){
this.rz.handleOver(this, e);
},
// private
onMouseOut : function(e){
this.rz.handleOut(this, e);
},
// private
destroy : function(){
Ext.destroy(this.el);
this.el = null;
}
};
/**
*
* Ext.ux.elasticTextArea Extension Class for Ext 3.x Library
*
* @author Steffen Kamper
*
* @license Ext.ux.elasticTextArea is licensed under the terms of
* the Open Source LGPL 3.0 license. Commercial use is permitted to the extent
* that the code/component(s) do NOT become part of another Open Source or Commercially
* licensed development library or toolkit without explicit permission.
*
* License details: http://www.gnu.org/licenses/lgpl.html
*
*/
Ext.ux.elasticTextArea = function(){
var defaultConfig = function(){
return {
minHeight : 0
,maxHeight : 0
,growBy: 12
}
}
var processOptions = function(config){
var o = defaultConfig();
var options = {};
Ext.apply(options, config, o);
return options;
}
return {
div : null
,applyTo: function(elementId, options){
var el = Ext.get(elementId);
var width = el.getWidth();
var height = el.getHeight();
var styles = el.getStyles('padding-top', 'padding-bottom', 'padding-left', 'padding-right', 'line-height', 'font-size', 'font-family', 'font-weight');
if(! this.div){
var options = processOptions(options);
this.div = Ext.DomHelper.append(Ext.getBody() || document.body, {
'id':elementId + '-preview-div'
,'tag' : 'div'
,'background': 'red'
,'style' : 'position: absolute; top: -100000px; left: -100000px;'
}, true)
Ext.DomHelper.applyStyles(this.div, styles);
el.on('keyup', function() {
this.applyTo(elementId, options);
}, this);
}
this.div.setWidth(parseInt(el.getStyle('width')));
//replace \n with