three-codeeditor
Version:
codeeditor for three.js
1,513 lines (1,346 loc) • 1.03 MB
JavaScript
// This THREEx helper makes it easy to handle the mouse events in your 3D scene
//
// * CHANGES NEEDED
// * handle drag/drop
// * notify events not object3D - like DOM
// * so single object with property
// * DONE bubling implement bubling/capturing
// * DONE implement event.stopPropagation()
// * DONE implement event.type = "click" and co
// * DONE implement event.target
//
// # Lets get started
//
// First you include it in your page
//
// ```<script src='threex.domevent.js'>< /script>```
//
// # use the object oriented api
//
// You bind an event like this
//
// ```mesh.on('click', function(object3d){ ... })```
//
// To unbind an event, just do
//
// ```mesh.off('click', function(object3d){ ... })```
//
// As an alternative, there is another naming closer DOM events.
// Pick the one you like, they are doing the same thing
//
// ```mesh.addEventListener('click', function(object3d){ ... })```
// ```mesh.removeEventListener('click', function(object3d){ ... })```
//
// # Supported Events
//
// Always in a effort to stay close to usual pratices, the events name are the same as in DOM.
// The semantic is the same too.
// Currently, the available events are
// [click, dblclick, mouseup, mousedown](http://www.quirksmode.org/dom/events/click.html),
// [mouseover and mouse out](http://www.quirksmode.org/dom/events/mouseover.html).
//
// # use the standalone api
//
// The object-oriented api modifies THREE.Object3D class.
// It is a global class, so it may be legitimatly considered unclean by some people.
// If this bother you, simply do ```THREEx.DomEvents.noConflict()``` and use the
// standalone API. In fact, the object oriented API is just a thin wrapper
// on top of the standalone API.
//
// First, you instanciate the object
//
// ```var domEvent = new THREEx.DomEvent();```
//
// Then you bind an event like this
//
// ```domEvent.bind(mesh, 'click', function(object3d){ object3d.scale.x *= 2; });```
//
// To unbind an event, just do
//
// ```domEvent.unbind(mesh, 'click', callback);```
//
//
// # Code
//
/** @namespace */
var THREEx = THREEx || {};
// # Constructor
THREEx.DomEvents = function(camera, domElement)
{
this._camera = camera || null;
this._domElement= domElement || document;
this._raycaster = new THREE.Raycaster();
this._selected = null;
this._boundObjs = {};
// Bind dom event for mouse and touch
var _this = this;
this._$onClick = function(){ _this._onClick.apply(_this, arguments); };
this._$onDblClick = function(){ _this._onDblClick.apply(_this, arguments); };
this._$onMouseMove = function(){ _this._onMouseMove.apply(_this, arguments); };
this._$onMouseDown = function(){ _this._onMouseDown.apply(_this, arguments); };
this._$onMouseUp = function(){ _this._onMouseUp.apply(_this, arguments); };
this._$onTouchMove = function(){ _this._onTouchMove.apply(_this, arguments); };
this._$onTouchStart = function(){ _this._onTouchStart.apply(_this, arguments); };
this._$onTouchEnd = function(){ _this._onTouchEnd.apply(_this, arguments); };
this._$onContextmenu = function(){ _this._onContextmenu.apply(_this, arguments); };
this._domElement.addEventListener( 'click' , this._$onClick , false );
this._domElement.addEventListener( 'dblclick' , this._$onDblClick , false );
this._domElement.addEventListener( 'mousemove' , this._$onMouseMove , false );
this._domElement.addEventListener( 'mousedown' , this._$onMouseDown , false );
this._domElement.addEventListener( 'mouseup' , this._$onMouseUp , false );
this._domElement.addEventListener( 'touchmove' , this._$onTouchMove , false );
this._domElement.addEventListener( 'touchstart' , this._$onTouchStart , false );
this._domElement.addEventListener( 'touchend' , this._$onTouchEnd , false );
this._domElement.addEventListener( 'contextmenu', this._$onContextmenu , false );
}
// # Destructor
THREEx.DomEvents.prototype.destroy = function()
{
// unBind dom event for mouse and touch
this._domElement.removeEventListener( 'click' , this._$onClick , false );
this._domElement.removeEventListener( 'dblclick' , this._$onDblClick , false );
this._domElement.removeEventListener( 'mousemove' , this._$onMouseMove , false );
this._domElement.removeEventListener( 'mousedown' , this._$onMouseDown , false );
this._domElement.removeEventListener( 'mouseup' , this._$onMouseUp , false );
this._domElement.removeEventListener( 'touchmove' , this._$onTouchMove , false );
this._domElement.removeEventListener( 'touchstart' , this._$onTouchStart , false );
this._domElement.removeEventListener( 'touchend' , this._$onTouchEnd , false );
this._domElement.removeEventListener( 'contextmenu' , this._$onContextmenu , false );
}
THREEx.DomEvents.eventNames = [
"click",
"dblclick",
"mouseover",
"mouseout",
"mousemove",
"mousedown",
"mouseup",
"contextmenu",
"touchstart",
"touchend"
];
THREEx.DomEvents.prototype._getRelativeMouseXY = function(domEvent){
var element = domEvent.target || domEvent.srcElement;
if (element.nodeType === 3) {
element = element.parentNode; // Safari fix -- see http://www.quirksmode.org/js/events_properties.html
}
//get the real position of an element relative to the page starting point (0, 0)
//credits go to brainjam on answering http://stackoverflow.com/questions/5755312/getting-mouse-position-relative-to-content-area-of-an-element
var elPosition = { x : 0 , y : 0};
var tmpElement = element;
//store padding
var style = getComputedStyle(tmpElement, null);
elPosition.y += parseInt(style.getPropertyValue("padding-top"), 10);
elPosition.x += parseInt(style.getPropertyValue("padding-left"), 10);
//add positions
do {
elPosition.x += tmpElement.offsetLeft;
elPosition.y += tmpElement.offsetTop;
style = getComputedStyle(tmpElement, null);
elPosition.x += parseInt(style.getPropertyValue("border-left-width"), 10);
elPosition.y += parseInt(style.getPropertyValue("border-top-width"), 10);
} while(tmpElement = tmpElement.offsetParent);
var elDimension = {
width : (element === window) ? window.innerWidth : element.offsetWidth,
height : (element === window) ? window.innerHeight : element.offsetHeight
};
return {
x : +((domEvent.pageX - elPosition.x) / elDimension.width ) * 2 - 1,
y : -((domEvent.pageY - elPosition.y) / elDimension.height) * 2 + 1
};
};
/********************************************************************************/
/* domevent context */
/********************************************************************************/
// handle domevent context in object3d instance
THREEx.DomEvents.prototype._objectCtxInit = function(object3d){
object3d._3xDomEvent = {};
}
THREEx.DomEvents.prototype._objectCtxDeinit = function(object3d){
delete object3d._3xDomEvent;
}
THREEx.DomEvents.prototype._objectCtxIsInit = function(object3d){
return object3d._3xDomEvent ? true : false;
}
THREEx.DomEvents.prototype._objectCtxGet = function(object3d){
return object3d._3xDomEvent;
}
/********************************************************************************/
/* */
/********************************************************************************/
/**
* Getter/Setter for camera
*/
THREEx.DomEvents.prototype.camera = function(value)
{
if( value ) this._camera = value;
return this._camera;
}
THREEx.DomEvents.prototype.bind = function(object3d, eventName, callback, useCapture)
{
console.assert( THREEx.DomEvents.eventNames.indexOf(eventName) !== -1, "not available events:"+eventName );
if( !this._objectCtxIsInit(object3d) ) this._objectCtxInit(object3d);
var objectCtx = this._objectCtxGet(object3d);
if( !objectCtx[eventName+'Handlers'] ) objectCtx[eventName+'Handlers'] = [];
objectCtx[eventName+'Handlers'].push({
callback : callback,
useCapture : useCapture
});
// add this object in this._boundObjs
if( this._boundObjs[eventName] === undefined ){
this._boundObjs[eventName] = [];
}
this._boundObjs[eventName].push(object3d);
}
THREEx.DomEvents.prototype.addEventListener = THREEx.DomEvents.prototype.bind
THREEx.DomEvents.prototype.unbind = function(object3d, eventName, callback, useCapture)
{
console.assert( THREEx.DomEvents.eventNames.indexOf(eventName) !== -1, "not available events:"+eventName );
if( !this._objectCtxIsInit(object3d) ) this._objectCtxInit(object3d);
var objectCtx = this._objectCtxGet(object3d);
if( !objectCtx[eventName+'Handlers'] ) objectCtx[eventName+'Handlers'] = [];
var handlers = objectCtx[eventName+'Handlers'];
for(var i = 0; i < handlers.length; i++){
var handler = handlers[i];
if( callback != handler.callback ) continue;
if( useCapture != handler.useCapture ) continue;
handlers.splice(i, 1)
break;
}
// from this object from this._boundObjs
var index = this._boundObjs[eventName].indexOf(object3d);
console.assert( index !== -1 );
this._boundObjs[eventName].splice(index, 1);
}
THREEx.DomEvents.prototype.removeEventListener = THREEx.DomEvents.prototype.unbind
THREEx.DomEvents.prototype._bound = function(eventName, object3d)
{
var objectCtx = this._objectCtxGet(object3d);
if( !objectCtx ) return false;
return objectCtx[eventName+'Handlers'] ? true : false;
}
/********************************************************************************/
/* onMove */
/********************************************************************************/
// # handle mousemove kind of events
THREEx.DomEvents.prototype._onMove = function(eventName, mouseX, mouseY, origDomEvent)
{
//console.log('eventName', eventName, 'boundObjs', this._boundObjs[eventName])
// get objects bound to this event
var boundObjs = this._boundObjs[eventName];
if( boundObjs === undefined || boundObjs.length === 0 ) return;
// compute the intersection
var vector = new THREE.Vector2();
// update the picking ray with the camera and mouse position
vector.set( mouseX, mouseY );
this._raycaster.setFromCamera( vector, this._camera );
var intersects = this._raycaster.intersectObjects( boundObjs );
var oldSelected = this._selected;
if( intersects.length > 0 ){
var notifyOver, notifyOut, notifyMove;
var intersect = intersects[ 0 ];
var newSelected = intersect.object;
this._selected = newSelected;
// if newSelected bound mousemove, notify it
notifyMove = this._bound('mousemove', newSelected);
if( oldSelected != newSelected ){
// if newSelected bound mouseenter, notify it
notifyOver = this._bound('mouseover', newSelected);
// if there is a oldSelect and oldSelected bound mouseleave, notify it
notifyOut = oldSelected && this._bound('mouseout', oldSelected);
}
}else{
// if there is a oldSelect and oldSelected bound mouseleave, notify it
notifyOut = oldSelected && this._bound('mouseout', oldSelected);
this._selected = null;
}
// notify mouseMove - done at the end with a copy of the list to allow callback to remove handlers
notifyMove && this._notify('mousemove', newSelected, origDomEvent, intersect);
// notify mouseEnter - done at the end with a copy of the list to allow callback to remove handlers
notifyOver && this._notify('mouseover', newSelected, origDomEvent, intersect);
// notify mouseLeave - done at the end with a copy of the list to allow callback to remove handlers
notifyOut && this._notify('mouseout' , oldSelected, origDomEvent, intersect);
}
/********************************************************************************/
/* onEvent */
/********************************************************************************/
// # handle click kind of events
THREEx.DomEvents.prototype._onEvent = function(eventName, mouseX, mouseY, origDomEvent)
{
//console.log('eventName', eventName, 'boundObjs', this._boundObjs[eventName])
// get objects bound to this event
var boundObjs = this._boundObjs[eventName];
if( boundObjs === undefined || boundObjs.length === 0 ) return;
// compute the intersection
var vector = new THREE.Vector2();
// update the picking ray with the camera and mouse position
vector.set( mouseX, mouseY );
this._raycaster.setFromCamera( vector, this._camera );
var intersects = this._raycaster.intersectObjects( boundObjs, true);
// if there are no intersections, return now
if( intersects.length === 0 ) return;
// init some variables
var intersect = intersects[0];
var object3d = intersect.object;
var objectCtx = this._objectCtxGet(object3d);
var objectParent = object3d.parent;
while ( typeof(objectCtx) == 'undefined' && objectParent )
{
objectCtx = this._objectCtxGet(objectParent);
objectParent = objectParent.parent;
}
if( !objectCtx ) return;
// notify handlers
this._notify(eventName, object3d, origDomEvent, intersect);
}
THREEx.DomEvents.prototype._notify = function(eventName, object3d, origDomEvent, intersect)
{
var objectCtx = this._objectCtxGet(object3d);
var handlers = objectCtx ? objectCtx[eventName+'Handlers'] : null;
// parameter check
console.assert(arguments.length === 4)
// do bubbling
if( !objectCtx || !handlers || handlers.length === 0 ){
object3d.parent && this._notify(eventName, object3d.parent, origDomEvent, intersect);
return;
}
// notify all handlers
var handlers = objectCtx[eventName+'Handlers'];
for(var i = 0; i < handlers.length; i++){
var handler = handlers[i];
var toPropagate = true;
handler.callback({
type : eventName,
target : object3d,
origDomEvent : origDomEvent,
intersect : intersect,
stopPropagation : function(){
toPropagate = false;
}
});
if( !toPropagate ) continue;
// do bubbling
if( handler.useCapture === false ){
object3d.parent && this._notify(eventName, object3d.parent, origDomEvent, intersect);
}
}
}
/********************************************************************************/
/* handle mouse events */
/********************************************************************************/
// # handle mouse events
THREEx.DomEvents.prototype._onMouseDown = function(event){ return this._onMouseEvent('mousedown', event); }
THREEx.DomEvents.prototype._onMouseUp = function(event){ return this._onMouseEvent('mouseup' , event); }
THREEx.DomEvents.prototype._onMouseEvent = function(eventName, domEvent)
{
var mouseCoords = this._getRelativeMouseXY(domEvent);
this._onEvent(eventName, mouseCoords.x, mouseCoords.y, domEvent);
}
THREEx.DomEvents.prototype._onMouseMove = function(domEvent)
{
var mouseCoords = this._getRelativeMouseXY(domEvent);
this._onMove('mousemove', mouseCoords.x, mouseCoords.y, domEvent);
this._onMove('mouseover', mouseCoords.x, mouseCoords.y, domEvent);
this._onMove('mouseout' , mouseCoords.x, mouseCoords.y, domEvent);
}
THREEx.DomEvents.prototype._onClick = function(event)
{
// TODO handle touch ?
this._onMouseEvent('click' , event);
}
THREEx.DomEvents.prototype._onDblClick = function(event)
{
// TODO handle touch ?
this._onMouseEvent('dblclick' , event);
}
THREEx.DomEvents.prototype._onContextmenu = function(event)
{
//TODO don't have a clue about how this should work with touch..
this._onMouseEvent('contextmenu' , event);
}
/********************************************************************************/
/* handle touch events */
/********************************************************************************/
// # handle touch events
THREEx.DomEvents.prototype._onTouchStart = function(event){ return this._onTouchEvent('touchstart', event); }
THREEx.DomEvents.prototype._onTouchEnd = function(event){ return this._onTouchEvent('touchend' , event); }
THREEx.DomEvents.prototype._onTouchMove = function(domEvent)
{
if( domEvent.touches.length != 1 ) return undefined;
domEvent.preventDefault();
var mouseX = +(domEvent.touches[ 0 ].pageX / window.innerWidth ) * 2 - 1;
var mouseY = -(domEvent.touches[ 0 ].pageY / window.innerHeight) * 2 + 1;
this._onMove('mousemove', mouseX, mouseY, domEvent);
this._onMove('mouseover', mouseX, mouseY, domEvent);
this._onMove('mouseout' , mouseX, mouseY, domEvent);
}
THREEx.DomEvents.prototype._onTouchEvent = function(eventName, domEvent)
{
if( domEvent.touches.length != 1 ) return undefined;
domEvent.preventDefault();
var mouseX = +(domEvent.touches[ 0 ].pageX / window.innerWidth ) * 2 - 1;
var mouseY = -(domEvent.touches[ 0 ].pageY / window.innerHeight) * 2 + 1;
this._onEvent(eventName, mouseX, mouseY, domEvent);
};
/* ***** BEGIN LICENSE BLOCK *****
* Distributed under the BSD license:
*
* Copyright (c) 2010, Ajax.org B.V.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Ajax.org B.V. nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* ***** END LICENSE BLOCK ***** */
/**
* Define a module along with a payload
* @param module a name for the payload
* @param payload a function to call with (require, exports, module) params
*/
(function() {
var ACE_NAMESPACE = "ace";
var global = (function() {
return this;
})();
if (!ACE_NAMESPACE && typeof requirejs !== "undefined")
return;
var _define = function(module, deps, payload) {
if (typeof module !== 'string') {
if (_define.original)
_define.original.apply(window, arguments);
else {
console.error('dropping module because define wasn\'t a string.');
console.trace();
}
return;
}
if (arguments.length == 2)
payload = deps;
if (!_define.modules) {
_define.modules = {};
_define.payloads = {};
}
_define.payloads[module] = payload;
_define.modules[module] = null;
};
/**
* Get at functionality ace.define()ed using the function above
*/
var _require = function(parentId, module, callback) {
if (Object.prototype.toString.call(module) === "[object Array]") {
var params = [];
for (var i = 0, l = module.length; i < l; ++i) {
var dep = lookup(parentId, module[i]);
if (!dep && _require.original)
return _require.original.apply(window, arguments);
params.push(dep);
}
if (callback) {
callback.apply(null, params);
}
}
else if (typeof module === 'string') {
var payload = lookup(parentId, module);
if (!payload && _require.original)
return _require.original.apply(window, arguments);
if (callback) {
callback();
}
return payload;
}
else {
if (_require.original)
return _require.original.apply(window, arguments);
}
};
var normalizeModule = function(parentId, moduleName) {
// normalize plugin requires
if (moduleName.indexOf("!") !== -1) {
var chunks = moduleName.split("!");
return normalizeModule(parentId, chunks[0]) + "!" + normalizeModule(parentId, chunks[1]);
}
// normalize relative requires
if (moduleName.charAt(0) == ".") {
var base = parentId.split("/").slice(0, -1).join("/");
moduleName = base + "/" + moduleName;
while(moduleName.indexOf(".") !== -1 && previous != moduleName) {
var previous = moduleName;
moduleName = moduleName.replace(/\/\.\//, "/").replace(/[^\/]+\/\.\.\//, "");
}
}
return moduleName;
};
/**
* Internal function to lookup moduleNames and resolve them by calling the
* definition function if needed.
*/
var lookup = function(parentId, moduleName) {
moduleName = normalizeModule(parentId, moduleName);
var module = _define.modules[moduleName];
if (!module) {
module = _define.payloads[moduleName];
if (typeof module === 'function') {
var exports = {};
var mod = {
id: moduleName,
uri: '',
exports: exports,
packaged: true
};
var req = function(module, callback) {
return _require(moduleName, module, callback);
};
var returnValue = module(req, exports, mod);
exports = returnValue || mod.exports;
_define.modules[moduleName] = exports;
delete _define.payloads[moduleName];
}
module = _define.modules[moduleName] = exports || module;
}
return module;
};
function exportAce(ns) {
var require = function(module, callback) {
return _require("", module, callback);
};
var root = global;
if (ns) {
if (!global[ns])
global[ns] = {};
root = global[ns];
}
if (!root.define || !root.define.packaged) {
_define.original = root.define;
root.define = _define;
root.define.packaged = true;
}
if (!root.require || !root.require.packaged) {
_require.original = root.require;
root.require = require;
root.require.packaged = true;
}
}
exportAce(ACE_NAMESPACE);
})();
ace.define("ace/lib/regexp",["require","exports","module"], function(require, exports, module) {
"use strict";
var real = {
exec: RegExp.prototype.exec,
test: RegExp.prototype.test,
match: String.prototype.match,
replace: String.prototype.replace,
split: String.prototype.split
},
compliantExecNpcg = real.exec.call(/()??/, "")[1] === undefined, // check `exec` handling of nonparticipating capturing groups
compliantLastIndexIncrement = function () {
var x = /^/g;
real.test.call(x, "");
return !x.lastIndex;
}();
if (compliantLastIndexIncrement && compliantExecNpcg)
return;
RegExp.prototype.exec = function (str) {
var match = real.exec.apply(this, arguments),
name, r2;
if ( typeof(str) == 'string' && match) {
if (!compliantExecNpcg && match.length > 1 && indexOf(match, "") > -1) {
r2 = RegExp(this.source, real.replace.call(getNativeFlags(this), "g", ""));
real.replace.call(str.slice(match.index), r2, function () {
for (var i = 1; i < arguments.length - 2; i++) {
if (arguments[i] === undefined)
match[i] = undefined;
}
});
}
if (this._xregexp && this._xregexp.captureNames) {
for (var i = 1; i < match.length; i++) {
name = this._xregexp.captureNames[i - 1];
if (name)
match[name] = match[i];
}
}
if (!compliantLastIndexIncrement && this.global && !match[0].length && (this.lastIndex > match.index))
this.lastIndex--;
}
return match;
};
if (!compliantLastIndexIncrement) {
RegExp.prototype.test = function (str) {
var match = real.exec.call(this, str);
if (match && this.global && !match[0].length && (this.lastIndex > match.index))
this.lastIndex--;
return !!match;
};
}
function getNativeFlags (regex) {
return (regex.global ? "g" : "") +
(regex.ignoreCase ? "i" : "") +
(regex.multiline ? "m" : "") +
(regex.extended ? "x" : "") + // Proposed for ES4; included in AS3
(regex.sticky ? "y" : "");
}
function indexOf (array, item, from) {
if (Array.prototype.indexOf) // Use the native array method if available
return array.indexOf(item, from);
for (var i = from || 0; i < array.length; i++) {
if (array[i] === item)
return i;
}
return -1;
}
});
ace.define("ace/lib/es5-shim",["require","exports","module"], function(require, exports, module) {
function Empty() {}
if (!Function.prototype.bind) {
Function.prototype.bind = function bind(that) { // .length is 1
var target = this;
if (typeof target != "function") {
throw new TypeError("Function.prototype.bind called on incompatible " + target);
}
var args = slice.call(arguments, 1); // for normal call
var bound = function () {
if (this instanceof bound) {
var result = target.apply(
this,
args.concat(slice.call(arguments))
);
if (Object(result) === result) {
return result;
}
return this;
} else {
return target.apply(
that,
args.concat(slice.call(arguments))
);
}
};
if(target.prototype) {
Empty.prototype = target.prototype;
bound.prototype = new Empty();
Empty.prototype = null;
}
return bound;
};
}
var call = Function.prototype.call;
var prototypeOfArray = Array.prototype;
var prototypeOfObject = Object.prototype;
var slice = prototypeOfArray.slice;
var _toString = call.bind(prototypeOfObject.toString);
var owns = call.bind(prototypeOfObject.hasOwnProperty);
var defineGetter;
var defineSetter;
var lookupGetter;
var lookupSetter;
var supportsAccessors;
if ((supportsAccessors = owns(prototypeOfObject, "__defineGetter__"))) {
defineGetter = call.bind(prototypeOfObject.__defineGetter__);
defineSetter = call.bind(prototypeOfObject.__defineSetter__);
lookupGetter = call.bind(prototypeOfObject.__lookupGetter__);
lookupSetter = call.bind(prototypeOfObject.__lookupSetter__);
}
if ([1,2].splice(0).length != 2) {
if(function() { // test IE < 9 to splice bug - see issue #138
function makeArray(l) {
var a = new Array(l+2);
a[0] = a[1] = 0;
return a;
}
var array = [], lengthBefore;
array.splice.apply(array, makeArray(20));
array.splice.apply(array, makeArray(26));
lengthBefore = array.length; //46
array.splice(5, 0, "XXX"); // add one element
lengthBefore + 1 == array.length
if (lengthBefore + 1 == array.length) {
return true;// has right splice implementation without bugs
}
}()) {//IE 6/7
var array_splice = Array.prototype.splice;
Array.prototype.splice = function(start, deleteCount) {
if (!arguments.length) {
return [];
} else {
return array_splice.apply(this, [
start === void 0 ? 0 : start,
deleteCount === void 0 ? (this.length - start) : deleteCount
].concat(slice.call(arguments, 2)))
}
};
} else {//IE8
Array.prototype.splice = function(pos, removeCount){
var length = this.length;
if (pos > 0) {
if (pos > length)
pos = length;
} else if (pos == void 0) {
pos = 0;
} else if (pos < 0) {
pos = Math.max(length + pos, 0);
}
if (!(pos+removeCount < length))
removeCount = length - pos;
var removed = this.slice(pos, pos+removeCount);
var insert = slice.call(arguments, 2);
var add = insert.length;
if (pos === length) {
if (add) {
this.push.apply(this, insert);
}
} else {
var remove = Math.min(removeCount, length - pos);
var tailOldPos = pos + remove;
var tailNewPos = tailOldPos + add - remove;
var tailCount = length - tailOldPos;
var lengthAfterRemove = length - remove;
if (tailNewPos < tailOldPos) { // case A
for (var i = 0; i < tailCount; ++i) {
this[tailNewPos+i] = this[tailOldPos+i];
}
} else if (tailNewPos > tailOldPos) { // case B
for (i = tailCount; i--; ) {
this[tailNewPos+i] = this[tailOldPos+i];
}
} // else, add == remove (nothing to do)
if (add && pos === lengthAfterRemove) {
this.length = lengthAfterRemove; // truncate array
this.push.apply(this, insert);
} else {
this.length = lengthAfterRemove + add; // reserves space
for (i = 0; i < add; ++i) {
this[pos+i] = insert[i];
}
}
}
return removed;
};
}
}
if (!Array.isArray) {
Array.isArray = function isArray(obj) {
return _toString(obj) == "[object Array]";
};
}
var boxedString = Object("a"),
splitString = boxedString[0] != "a" || !(0 in boxedString);
if (!Array.prototype.forEach) {
Array.prototype.forEach = function forEach(fun /*, thisp*/) {
var object = toObject(this),
self = splitString && _toString(this) == "[object String]" ?
this.split("") :
object,
thisp = arguments[1],
i = -1,
length = self.length >>> 0;
if (_toString(fun) != "[object Function]") {
throw new TypeError(); // TODO message
}
while (++i < length) {
if (i in self) {
fun.call(thisp, self[i], i, object);
}
}
};
}
if (!Array.prototype.map) {
Array.prototype.map = function map(fun /*, thisp*/) {
var object = toObject(this),
self = splitString && _toString(this) == "[object String]" ?
this.split("") :
object,
length = self.length >>> 0,
result = Array(length),
thisp = arguments[1];
if (_toString(fun) != "[object Function]") {
throw new TypeError(fun + " is not a function");
}
for (var i = 0; i < length; i++) {
if (i in self)
result[i] = fun.call(thisp, self[i], i, object);
}
return result;
};
}
if (!Array.prototype.filter) {
Array.prototype.filter = function filter(fun /*, thisp */) {
var object = toObject(this),
self = splitString && _toString(this) == "[object String]" ?
this.split("") :
object,
length = self.length >>> 0,
result = [],
value,
thisp = arguments[1];
if (_toString(fun) != "[object Function]") {
throw new TypeError(fun + " is not a function");
}
for (var i = 0; i < length; i++) {
if (i in self) {
value = self[i];
if (fun.call(thisp, value, i, object)) {
result.push(value);
}
}
}
return result;
};
}
if (!Array.prototype.every) {
Array.prototype.every = function every(fun /*, thisp */) {
var object = toObject(this),
self = splitString && _toString(this) == "[object String]" ?
this.split("") :
object,
length = self.length >>> 0,
thisp = arguments[1];
if (_toString(fun) != "[object Function]") {
throw new TypeError(fun + " is not a function");
}
for (var i = 0; i < length; i++) {
if (i in self && !fun.call(thisp, self[i], i, object)) {
return false;
}
}
return true;
};
}
if (!Array.prototype.some) {
Array.prototype.some = function some(fun /*, thisp */) {
var object = toObject(this),
self = splitString && _toString(this) == "[object String]" ?
this.split("") :
object,
length = self.length >>> 0,
thisp = arguments[1];
if (_toString(fun) != "[object Function]") {
throw new TypeError(fun + " is not a function");
}
for (var i = 0; i < length; i++) {
if (i in self && fun.call(thisp, self[i], i, object)) {
return true;
}
}
return false;
};
}
if (!Array.prototype.reduce) {
Array.prototype.reduce = function reduce(fun /*, initial*/) {
var object = toObject(this),
self = splitString && _toString(this) == "[object String]" ?
this.split("") :
object,
length = self.length >>> 0;
if (_toString(fun) != "[object Function]") {
throw new TypeError(fun + " is not a function");
}
if (!length && arguments.length == 1) {
throw new TypeError("reduce of empty array with no initial value");
}
var i = 0;
var result;
if (arguments.length >= 2) {
result = arguments[1];
} else {
do {
if (i in self) {
result = self[i++];
break;
}
if (++i >= length) {
throw new TypeError("reduce of empty array with no initial value");
}
} while (true);
}
for (; i < length; i++) {
if (i in self) {
result = fun.call(void 0, result, self[i], i, object);
}
}
return result;
};
}
if (!Array.prototype.reduceRight) {
Array.prototype.reduceRight = function reduceRight(fun /*, initial*/) {
var object = toObject(this),
self = splitString && _toString(this) == "[object String]" ?
this.split("") :
object,
length = self.length >>> 0;
if (_toString(fun) != "[object Function]") {
throw new TypeError(fun + " is not a function");
}
if (!length && arguments.length == 1) {
throw new TypeError("reduceRight of empty array with no initial value");
}
var result, i = length - 1;
if (arguments.length >= 2) {
result = arguments[1];
} else {
do {
if (i in self) {
result = self[i--];
break;
}
if (--i < 0) {
throw new TypeError("reduceRight of empty array with no initial value");
}
} while (true);
}
do {
if (i in this) {
result = fun.call(void 0, result, self[i], i, object);
}
} while (i--);
return result;
};
}
if (!Array.prototype.indexOf || ([0, 1].indexOf(1, 2) != -1)) {
Array.prototype.indexOf = function indexOf(sought /*, fromIndex */ ) {
var self = splitString && _toString(this) == "[object String]" ?
this.split("") :
toObject(this),
length = self.length >>> 0;
if (!length) {
return -1;
}
var i = 0;
if (arguments.length > 1) {
i = toInteger(arguments[1]);
}
i = i >= 0 ? i : Math.max(0, length + i);
for (; i < length; i++) {
if (i in self && self[i] === sought) {
return i;
}
}
return -1;
};
}
if (!Array.prototype.lastIndexOf || ([0, 1].lastIndexOf(0, -3) != -1)) {
Array.prototype.lastIndexOf = function lastIndexOf(sought /*, fromIndex */) {
var self = splitString && _toString(this) == "[object String]" ?
this.split("") :
toObject(this),
length = self.length >>> 0;
if (!length) {
return -1;
}
var i = length - 1;
if (arguments.length > 1) {
i = Math.min(i, toInteger(arguments[1]));
}
i = i >= 0 ? i : length - Math.abs(i);
for (; i >= 0; i--) {
if (i in self && sought === self[i]) {
return i;
}
}
return -1;
};
}
if (!Object.getPrototypeOf) {
Object.getPrototypeOf = function getPrototypeOf(object) {
return object.__proto__ || (
object.constructor ?
object.constructor.prototype :
prototypeOfObject
);
};
}
if (!Object.getOwnPropertyDescriptor) {
var ERR_NON_OBJECT = "Object.getOwnPropertyDescriptor called on a " +
"non-object: ";
Object.getOwnPropertyDescriptor = function getOwnPropertyDescriptor(object, property) {
if ((typeof object != "object" && typeof object != "function") || object === null)
throw new TypeError(ERR_NON_OBJECT + object);
if (!owns(object, property))
return;
var descriptor, getter, setter;
descriptor = { enumerable: true, configurable: true };
if (supportsAccessors) {
var prototype = object.__proto__;
object.__proto__ = prototypeOfObject;
var getter = lookupGetter(object, property);
var setter = lookupSetter(object, property);
object.__proto__ = prototype;
if (getter || setter) {
if (getter) descriptor.get = getter;
if (setter) descriptor.set = setter;
return descriptor;
}
}
descriptor.value = object[property];
return descriptor;
};
}
if (!Object.getOwnPropertyNames) {
Object.getOwnPropertyNames = function getOwnPropertyNames(object) {
return Object.keys(object);
};
}
if (!Object.create) {
var createEmpty;
if (Object.prototype.__proto__ === null) {
createEmpty = function () {
return { "__proto__": null };
};
} else {
createEmpty = function () {
var empty = {};
for (var i in empty)
empty[i] = null;
empty.constructor =
empty.hasOwnProperty =
empty.propertyIsEnumerable =
empty.isPrototypeOf =
empty.toLocaleString =
empty.toString =
empty.valueOf =
empty.__proto__ = null;
return empty;
}
}
Object.create = function create(prototype, properties) {
var object;
if (prototype === null) {
object = createEmpty();
} else {
if (typeof prototype != "object")
throw new TypeError("typeof prototype["+(typeof prototype)+"] != 'object'");
var Type = function () {};
Type.prototype = prototype;
object = new Type();
object.__proto__ = prototype;
}
if (properties !== void 0)
Object.defineProperties(object, properties);
return object;
};
}
function doesDefinePropertyWork(object) {
try {
Object.defineProperty(object, "sentinel", {});
return "sentinel" in object;
} catch (exception) {
}
}
if (Object.defineProperty) {
var definePropertyWorksOnObject = doesDefinePropertyWork({});
var definePropertyWorksOnDom = typeof document == "undefined" ||
doesDefinePropertyWork(document.createElement("div"));
if (!definePropertyWorksOnObject || !definePropertyWorksOnDom) {
var definePropertyFallback = Object.defineProperty;
}
}
if (!Object.defineProperty || definePropertyFallback) {
var ERR_NON_OBJECT_DESCRIPTOR = "Property description must be an object: ";
var ERR_NON_OBJECT_TARGET = "Object.defineProperty called on non-object: "
var ERR_ACCESSORS_NOT_SUPPORTED = "getters & setters can not be defined " +
"on this javascript engine";
Object.defineProperty = function defineProperty(object, property, descriptor) {
if ((typeof object != "object" && typeof object != "function") || object === null)
throw new TypeError(ERR_NON_OBJECT_TARGET + object);
if ((typeof descriptor != "object" && typeof descriptor != "function") || descriptor === null)
throw new TypeError(ERR_NON_OBJECT_DESCRIPTOR + descriptor);
if (definePropertyFallback) {
try {
return definePropertyFallback.call(Object, object, property, descriptor);
} catch (exception) {
}
}
if (owns(descriptor, "value")) {
if (supportsAccessors && (lookupGetter(object, property) ||
lookupSetter(object, property)))
{
var prototype = object.__proto__;
object.__proto__ = prototypeOfObject;
delete object[property];
object[property] = descriptor.value;
object.__proto__ = prototype;
} else {
object[property] = descriptor.value;
}
} else {
if (!supportsAccessors)
throw new TypeError(ERR_ACCESSORS_NOT_SUPPORTED);
if (owns(descriptor, "get"))
defineGetter(object, property, descriptor.get);
if (owns(descriptor, "set"))
defineSetter(object, property, descriptor.set);
}
return object;
};
}
if (!Object.defineProperties) {
Object.defineProperties = function defineProperties(object, properties) {
for (var property in properties) {
if (owns(properties, property))
Object.defineProperty(object, property, properties[property]);
}
return object;
};
}
if (!Object.seal) {
Object.seal = function seal(object) {
return object;
};
}
if (!Object.freeze) {
Object.freeze = function freeze(object) {
return object;
};
}
try {
Object.freeze(function () {});
} catch (exception) {
Object.freeze = (function freeze(freezeObject) {
return function freeze(object) {
if (typeof object == "function") {
return object;
} else {
return freezeObject(object);
}
};
})(Object.freeze);
}
if (!Object.preventExtensions) {
Object.preventExtensions = function preventExtensions(object) {
return object;
};
}
if (!Object.isSealed) {
Object.isSealed = function isSealed(object) {
return false;
};
}
if (!Object.isFrozen) {
Object.isFrozen = function isFrozen(object) {
return false;
};
}
if (!Object.isExtensible) {
Object.isExtensible = function isExtensible(object) {
if (Object(object) === object) {
throw new TypeError(); // TODO message
}
var name = '';
while (owns(object, name)) {
name += '?';
}
object[name] = true;
var returnValue = owns(object, name);
delete object[name];
return returnValue;
};
}
if (!Object.keys) {
var hasDontEnumBug = true,
dontEnums = [
"toString",
"toLocaleString",
"valueOf",
"hasOwnProperty",
"isPrototypeOf",
"propertyIsEnumerable",
"constructor"
],
dontEnumsLength = dontEnums.length;
for (var key in {"toString": null}) {
hasDontEnumBug = false;
}
Object.keys = function keys(object) {
if (
(typeof object != "object" && typeof object != "function") ||
object === null
) {
throw new TypeError("Object.keys called on a non-object");
}
var keys = [];
for (var name in object) {
if (owns(object, name)) {
keys.push(name);
}
}
if (hasDontEnumBug) {
for (var i = 0, ii = dontEnumsLength; i < ii; i++) {
var dontEnum = dontEnums[i];
if (owns(object, dontEnum)) {
keys.push(dontEnum);
}
}
}
return keys;
};
}
if (!Date.now) {
Date.now = function now() {
return new Date().getTime();
};
}
var ws = "\x09\x0A\x0B\x0C\x0D\x20\xA0\u1680\u180E\u2000\u2001\u2002\u2003" +
"\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u3000\u2028" +
"\u2029\uFEFF";
if (!String.prototype.trim || ws.trim()) {
ws = "[" + ws + "]";
var trimBeginRegexp = new RegExp("^" + ws + ws + "*"),
trimEndRegexp = new RegExp(ws + ws + "*$");
String.prototype.trim = function trim() {
return String(this).replace(trimBeginRegexp, "").replace(trimEndRegexp, "");
};
}
function toInteger(n) {
n = +n;
if (n !== n) { // isNaN
n = 0;
} else if (n !== 0 && n !== (1/0) && n !== -(1/0)) {
n = (n > 0 || -1) * Math.floor(Math.abs(n));
}
return n;
}
function isPrimitive(input) {
var type = typeof input;
return (
input === null ||
type === "undefined" ||
type === "boolean" ||
type === "number" ||
type === "string"
);
}
function toPrimitive(input) {
var val, valueOf, toString;
if (isPrimitive(input)) {
return input;
}
valueOf = input.valueOf;
if (typeof valueOf === "function") {
val = valueOf.call(input);
if (isPrimitive(val)) {
return val;
}
}
toString = input.toString;
if (typeof toString === "function") {
val = toString.call(input);
if (isPrimitive(val)) {
return val;
}
}
throw new TypeError();
}
var toObject = function (o) {
if (o == null) { // this matches both null and undefined
throw new TypeError("can't convert "+o+" to object");
}
return Object(o);
};
});
ace.define("ace/lib/fixoldbrowsers",["require","exports","module","ace/lib/regexp","ace/lib/es5-shim"], function(require, exports, module) {
"use strict";
require("./regexp");
require("./es5-shim");
});
ace.define("ace/lib/dom",["require","exports","module"], function(require, exports, module) {
"use strict";
var XHTML_NS = "http://www.w3.org/1999/xhtml";
exports.getDocumentHead = function(doc) {
if (!doc)
doc = document;
return doc.head || doc.getElementsByTagName("head")[0] || doc.documentElement;
}
exports.createElement = function(tag, ns) {
return document.createElementNS ?
document.createElementNS(ns || XHTML_NS, tag) :
document.createElement(tag);
};
exports.hasCssClass = function(el, name) {
var classes = (el.className || "").split(/\s+/g);
return classes.indexOf(name) !== -1;
};
exports.addCssClass = function(el, name) {
if (!exports.hasCssClass(el, name)) {
el.className += " " + name;
}
};
exports.removeCssClass = function(el, name) {
var classes = el.className.split(/\s+/g);
while (true) {
var index = classes.indexOf(name);
if (index == -1) {
break;
}
classes.splice(index, 1);
}
el.className = classes.join(" ");
};
exports.toggleCssClass = function(el, name) {
var classes = el.className.split(/\s+/g), add = true;
while (true) {
var index = classes.indexOf(name);
if (index == -1) {
break;
}
add = false;
classes.splice(index, 1);
}
if(add)
classes.push(name);
el.className = classes.join(" ");
return add;
};
exports.setCssClass = function(node, className, include) {
if (include) {
exports.addCssClass(node, className);
} else {
exports.removeCssClass(node, className);
}
};
exports.hasCssString = function(id, doc) {
var index = 0, sheets;
doc = doc || document;
if (doc.createStyleSheet && (sheets = doc.styleSheets)) {
while (index < sheets.length)
if (sheets[index++].owningElement.id === id) return true;
} else if ((sheets = doc.getElementsByTagName("style"))) {
while (index < sheets.length)
if (sheets[index++].id === id) return true;
}
return false;
};
exports.importCssString = function importCssString(cssText, id, doc) {
doc = doc || document;
if (id && exports.hasCssString(id, doc))
return null;
var style;
if (doc.createStyleSheet) {
style = doc.createStyleSheet();
style.cssText = cssText;
if (id)
style.owningElement.id = id;
} else {
style = doc.createElementNS
? doc.createElementNS(XHTML_NS, "style")
: doc.createElement("style");
style.appendChild(doc.createTextNode(cssText));
if (id)
style.id = id;