@@ -3,14 +3,10 @@ | |||
<head> | |||
<title>test</title> | |||
<link rel="stylesheet" href="styles.css"> | |||
<script src="../../src/client/plugins/require.js" data-main="js/app"></script> | |||
<script src="plugins/require.js" data-main="js/app"></script> | |||
</head> | |||
<body> | |||
<div class="left"> | |||
<canvas class="canvas"></canvas> | |||
</div> | |||
<div class="right"> | |||
</div> | |||
<canvas class="canvas"></canvas> | |||
<div class="ui-container"></div> | |||
</body> | |||
</html> |
@@ -2,7 +2,10 @@ require.config({ | |||
baseUrl: '', | |||
waitSeconds: 120, | |||
paths: { | |||
'jquery': '../../src/client/plugins/jquery.min', | |||
'jquery': 'plugins/jquery.min', | |||
'text': 'plugins/text', | |||
'html': 'plugins/html', | |||
'css': 'plugins/css' | |||
}, | |||
shim: { | |||
'jquery': { | |||
@@ -12,7 +15,7 @@ require.config({ | |||
}); | |||
require([ | |||
'../../src/client/js/misc/helpers', | |||
'js/helpers', | |||
'jquery', | |||
'js/main' | |||
], function ( | |||
@@ -10,6 +10,8 @@ define([ | |||
defaultDistanceInc: 60, | |||
defaultAngle: Math.PI / 2, | |||
defaultAngleInc: Math.PI / 8, | |||
gridSize: 30 | |||
gridSize: 30, | |||
scrollSpeed: 0.5 | |||
}; | |||
}); |
@@ -1,18 +1,20 @@ | |||
define([ | |||
'js/tplNode' | |||
'js/tplNode', | |||
'js/events' | |||
], function ( | |||
tplNode | |||
tplNode, | |||
events | |||
) { | |||
return { | |||
links: [], | |||
nodes: [], | |||
selected: null, | |||
init: function () { | |||
events.on('onAreaSelect', this.events.onAreaSelect.bind(this)); | |||
this.actions.addNode.call(this, { | |||
x: 23, | |||
y: 14 | |||
x: 100, | |||
y: 100 | |||
}); | |||
}, | |||
@@ -22,21 +24,34 @@ define([ | |||
callAction: function (action, options = {}) { | |||
var node = options.node || this.findNode(options.x, options.y); | |||
if ((action == 'addNode') && (options.shiftDown)) | |||
action = 'moveNode'; | |||
options.node = node; | |||
this.actions[action].call(this, options); | |||
return !this.actions[action].call(this, options); | |||
}, | |||
getSelected: function (single) { | |||
var selected = this.nodes.filter(n => n.selected); | |||
if ((single) && (selected.length != 1)) | |||
return null; | |||
if (single) | |||
return selected[0]; | |||
else | |||
return selected; | |||
}, | |||
actions: { | |||
selectNode: function (options) { | |||
if (this.selected) | |||
this.selected.selected = false; | |||
if ( | |||
(!options.node) || | |||
(!this.nodes.some(n => ((n.selected) && (n == options.node)))) | |||
) | |||
this.nodes.forEach(n => (n.selected = false)); | |||
if (options.node) | |||
options.node.selected = true; | |||
this.selected = options.node; | |||
return !options.node; | |||
}, | |||
addNode: function (options) { | |||
@@ -50,9 +65,11 @@ define([ | |||
connectNode: function (options) { | |||
var node = options.node; | |||
if (!node) | |||
return; | |||
return true; | |||
if (this.selected) { | |||
var singleSelected = this.getSelected(true); | |||
if (singleSelected) { | |||
if (options.shiftDown) { | |||
this.links.spliceWhere(l => ( | |||
( | |||
@@ -60,45 +77,82 @@ define([ | |||
(l.to == node) | |||
) && | |||
( | |||
(l.from == this.selected) || | |||
(l.to == this.selected) | |||
(l.from == singleSelected) || | |||
(l.to == singleSelected) | |||
) && | |||
(node != this.selected) | |||
(node != singleSelected) | |||
)); | |||
} else { | |||
this.links.push({ | |||
from: this.selected, | |||
from: singleSelected, | |||
to: node | |||
}); | |||
} | |||
this.callAction('selectNode'); | |||
return this.callAction('selectNode'); | |||
} else { | |||
this.callAction('selectNode', { | |||
return this.callAction('selectNode', { | |||
node: node | |||
}) | |||
} | |||
}, | |||
moveNode: function (options) { | |||
if (!this.selected) | |||
return; | |||
var selected = this.getSelected(); | |||
if (!selected.length) { | |||
selected = this.findNode(options.x, options.y); | |||
if (!selected) | |||
return true; | |||
this.callAction('selectNode', { | |||
node: selected | |||
}); | |||
} | |||
this.selected.pos.x = options.x; | |||
this.selected.pos.y = options.y; | |||
selected.forEach(function (s) { | |||
s.pos.x = options.x; | |||
s.pos.y = options.y; | |||
}); | |||
}, | |||
deleteNode: function (options) { | |||
var selected = this.getSelected(true); | |||
this.nodes.spliceWhere(n => (n == selected)); | |||
this.links.spliceWhere(n => ((n.from == selected) || (n.to == selected))); | |||
selected.selected = false; | |||
}, | |||
recolorNode: function () { | |||
if (!this.selected) | |||
return; | |||
var selected = this.getSelected(true); | |||
if (!selected) | |||
return true; | |||
this.selected.color = (this.selected.color + 1) % 4; | |||
selected.color = (selected.color + 1) % 4; | |||
}, | |||
resizeNode: function () { | |||
if (!this.selected) | |||
return; | |||
var selected = this.getSelected(true); | |||
if (!selected) | |||
return true; | |||
selected.size = (selected.size + 1) % 3; | |||
} | |||
}, | |||
events: { | |||
onAreaSelect: function (from, to) { | |||
this.nodes.forEach(n => (n.selected = false)); | |||
for (var i = from.x; i <= to.x; i++) { | |||
for (var j = from.y; j <= to.y; j++) { | |||
var node = this.findNode(i, j); | |||
if (!node) | |||
continue; | |||
node.selected = true; | |||
} | |||
} | |||
this.selected.size = (this.selected.size + 1) % 3; | |||
console.log(this.getSelected()); | |||
} | |||
} | |||
}; | |||
@@ -0,0 +1,113 @@ | |||
Array.prototype.firstIndex = function (callback, thisArg) { | |||
var T = thisArg; | |||
var O = Object(this); | |||
var len = O.length >>> 0; | |||
var k = 0; | |||
while (k < len) { | |||
var kValue; | |||
if (k in O) { | |||
kValue = O[k]; | |||
if (callback.call(T, kValue, k, O)) | |||
return k; | |||
} | |||
k++; | |||
} | |||
return -1; | |||
}; | |||
Array.prototype.spliceWhere = function (callback, thisArg) { | |||
var T = thisArg; | |||
var O = Object(this); | |||
var len = O.length >>> 0; | |||
var k = 0; | |||
while (k < len) { | |||
var kValue; | |||
if (k in O) { | |||
kValue = O[k]; | |||
if (callback.call(T, kValue, k, O)) { | |||
O.splice(k, 1); | |||
k--; | |||
} | |||
} | |||
k++; | |||
} | |||
}; | |||
Array.prototype.spliceFirstWhere = function (callback, thisArg) { | |||
var T = thisArg; | |||
var O = Object(this); | |||
var len = O.length >>> 0; | |||
var k = 0; | |||
while (k < len) { | |||
var kValue; | |||
if (k in O) { | |||
kValue = O[k]; | |||
if (callback.call(T, kValue, k, O)) { | |||
O.splice(k, 1); | |||
return kValue; | |||
} | |||
} | |||
k++; | |||
} | |||
}; | |||
window._ = { | |||
create: function () { | |||
var result = {}; | |||
[].slice.call(arguments).forEach(function (a) { | |||
$.extend(true, result, a); | |||
}); | |||
return result; | |||
}, | |||
get2dArray: function (w, h, def) { | |||
def = def || 0; | |||
var result = []; | |||
for (var i = 0; i < w; i++) { | |||
var inner = []; | |||
for (var j = 0; j < h; j++) { | |||
if (def == 'array') | |||
inner.push([]); | |||
else | |||
inner.push(def); | |||
} | |||
result.push(inner); | |||
} | |||
return result; | |||
}, | |||
randWeighted: function (weights) { | |||
var sample = []; | |||
weights.forEach(function (w, i) { | |||
for (var j = 0; j < w; j++) { | |||
sample.push(i); | |||
} | |||
}); | |||
return sample[~~(Math.random() * sample.length)]; | |||
} | |||
}; | |||
define([ | |||
], function ( | |||
) { | |||
return window._; | |||
}); |
@@ -25,9 +25,9 @@ define([ | |||
mouse: { | |||
button: null, | |||
x: 0, | |||
y: 0 | |||
y: 0, | |||
raw: null | |||
}, | |||
mouseRaw: null, | |||
keys: {}, | |||
@@ -38,7 +38,8 @@ define([ | |||
$('canvas') | |||
.on('mousedown', this.events.mouse.onMouseDown.bind(this)) | |||
.on('mouseup', this.events.mouse.onMouseUp.bind(this)) | |||
.on('mousemove', this.events.mouse.onMouseMove.bind(this)); | |||
.on('mousemove', this.events.mouse.onMouseMove.bind(this)) | |||
.on('mousewheel', this.events.mouse.onMouseWheel.bind(this)); | |||
}, | |||
resetKeys: function () { | |||
@@ -60,10 +61,10 @@ define([ | |||
}, | |||
isKeyDown: function (key, noConsume) { | |||
isKeyDown: function (key, consume) { | |||
var down = this.keys[key]; | |||
if (down != null) { | |||
if (noConsume) | |||
if (!consume) | |||
return true; | |||
else { | |||
this.keys[key] = 2; | |||
@@ -126,17 +127,18 @@ define([ | |||
return; | |||
var button = e.button; | |||
this.mouse.button = null; | |||
this.mouse.down = false; | |||
events.emit('onMouseUp', this.mouse); | |||
this.mouse.button = null; | |||
}, | |||
onMouseMove: function (e) { | |||
if (e) | |||
this.mouseRaw = e; | |||
this.mouse.raw = e; | |||
else | |||
e = this.mouseRaw; | |||
e = this.mouse.raw; | |||
if (!e) | |||
return; | |||
@@ -145,10 +147,19 @@ define([ | |||
if ((!el.hasClass('canvas')) || (el.hasClass('blocking'))) | |||
return; | |||
this.mouse.x = ~~((e.offsetX + renderer.pos.x + 40) / constants.gridSize) | |||
this.mouse.y = ~~((e.offsetY + renderer.pos.y + 40) / constants.gridSize) | |||
var x = ~~((e.offsetX + renderer.pos.x) / constants.gridSize); | |||
var y = ~~((e.offsetY + renderer.pos.y) / constants.gridSize); | |||
this.mouse.x = x; | |||
this.mouse.y = y; | |||
events.emit('onMouseMove', this.mouse); | |||
}, | |||
onMouseWheel: function (e) { | |||
events.emit('onMouseWheel', { | |||
delta: (e.originalEvent.deltaY > 0) ? 1 : -1 | |||
}); | |||
} | |||
} | |||
} | |||
@@ -2,12 +2,14 @@ define([ | |||
'js/events', | |||
'js/generator', | |||
'js/renderer', | |||
'js/input' | |||
'js/input', | |||
'ui/factory.js' | |||
], function ( | |||
events, | |||
generator, | |||
renderer, | |||
input | |||
input, | |||
uiFactory | |||
) { | |||
return { | |||
init: function () { | |||
@@ -15,9 +17,15 @@ define([ | |||
renderer.init(); | |||
input.init(); | |||
events.on('onMouseDown', this.events.onMouseDown.bind(this)); | |||
events.on('onMouseDown', this.events.onMouseDown.bind(this, true)); | |||
events.on('onMouseUp', this.events.onMouseDown.bind(this, false)); | |||
events.on('onMouseMove', this.events.onMouseMove.bind(this)); | |||
events.on('onMouseWheel', this.events.onMouseWheel.bind(this)); | |||
events.on('onKeyDown', this.events.onKeyDown.bind(this)); | |||
uiFactory.build('nodeInfo'); | |||
renderer.center(generator.nodes[0]); | |||
this.render(); | |||
}, | |||
@@ -29,27 +37,69 @@ define([ | |||
}, | |||
events: { | |||
onMouseDown: function (e) { | |||
onMouseDown: function (isDown, e) { | |||
var success = false; | |||
if ((input.isKeyDown('shift')) && (e.button == 2)) { | |||
success = true; | |||
if (e.down) | |||
events.emit('onStartAreaSelect', e); | |||
else | |||
events.emit('onEndAreaSelect', e); | |||
} else if (isDown) { | |||
var action = ([ | |||
'addNode', | |||
'connectNode', | |||
'selectNode' | |||
])[e.button]; | |||
success = generator.callAction(action, { | |||
x: e.x, | |||
y: e.y, | |||
shiftDown: input.isKeyDown('shift') | |||
}); | |||
} else if ((!isDown) && (e.button != 1)) | |||
generator.callAction('selectNode', {}); | |||
if ((!isDown) || (!success)) | |||
renderer.pan(e.raw, isDown ? 'down' : 'up'); | |||
renderer.makeDirty(); | |||
}, | |||
onMouseMove: function (e) { | |||
if ((!e.down) || (e.button != 2) || (input.isKeyDown('shift'))) | |||
return; | |||
if (generator.callAction('moveNode', { | |||
x: e.x, | |||
y: e.y | |||
})) | |||
return; | |||
renderer.pan(e.raw, 'move'); | |||
}, | |||
onMouseWheel: function (e) { | |||
var action = ([ | |||
'addNode', | |||
'selectNode', | |||
'connectNode' | |||
])[e.button]; | |||
'resizeNode', | |||
'recolorNode' | |||
])[(e.delta > 0) ? 1 : 0]; | |||
if (!action) | |||
return; | |||
generator.callAction(action, { | |||
x: e.x, | |||
y: e.y, | |||
shiftDown: input.isKeyDown('shift') | |||
}); | |||
generator.callAction(action, {}); | |||
renderer.makeDirty(); | |||
}, | |||
onKeyDown: function (key) { | |||
var action = ({ | |||
s: 'resizeNode', | |||
c: 'recolorNode' | |||
d: 'deleteNode' | |||
})[key]; | |||
if (!action) | |||
return; | |||
generator.callAction(action, {}); | |||
@@ -9,6 +9,8 @@ define([ | |||
canvas: null, | |||
ctx: null, | |||
panOrigin: null, | |||
screen: { | |||
w: 0, | |||
h: 0 | |||
@@ -19,6 +21,8 @@ define([ | |||
y: 0 | |||
}, | |||
oldPos: null, | |||
mouse: { | |||
x: 0, | |||
y: 0 | |||
@@ -27,9 +31,9 @@ define([ | |||
dirty: true, | |||
init: function () { | |||
this.canvas = $('canvas')[0]; | |||
this.screen.w = this.canvas.width = $('.left').width(); | |||
this.screen.h = this.canvas.height = $('.left').height(); | |||
this.canvas = $('.canvas')[0]; | |||
this.screen.w = this.canvas.width = $('body').width(); | |||
this.screen.h = this.canvas.height = $('body').height(); | |||
this.ctx = this.canvas.getContext('2d'); | |||
this.ctx.lineWidth = constants.lineWidth; | |||
@@ -40,16 +44,27 @@ define([ | |||
}); | |||
events.on('onMouseMove', this.events.onMouseMove.bind(this)); | |||
events.on('onStartAreaSelect', this.events.onStartAreaSelect.bind(this)); | |||
events.on('onEndAreaSelect', this.events.onEndAreaSelect.bind(this)); | |||
}, | |||
center: function (node) { | |||
this.pos.x = ~~(node.pos.x * constants.gridSize) + (constants.blockSize / 2) - (this.screen.w / 2); | |||
this.pos.y = ~~(node.pos.y * constants.gridSize) + (constants.blockSize / 2) - (this.screen.h / 2); | |||
this.ctx.translate(-this.pos.x, -this.pos.y); | |||
this.makeDirty(); | |||
}, | |||
pan: function (e, event) { | |||
var action = ({ | |||
down: 'onPanStart', | |||
up: 'onPanEnd', | |||
move: 'onPan' | |||
})[event]; | |||
this.events[action].call(this, e); | |||
}, | |||
makeDirty: function () { | |||
this.dirty = true; | |||
}, | |||
@@ -75,7 +90,11 @@ define([ | |||
renderers: { | |||
clear: function () { | |||
this.ctx.clearRect(this.pos.x, this.pos.y, this.screen.w, this.screen.h); | |||
var pos = this.oldPos || this.pos; | |||
this.ctx.clearRect(0, 0, this.screen.w, this.screen.h); | |||
delete this.oldPos; | |||
}, | |||
grid: function () { | |||
@@ -83,20 +102,28 @@ define([ | |||
var ctx = this.ctx; | |||
var mouse = this.mouse; | |||
var w = this.screen.w / gridSize; | |||
var h = this.screen.h / gridSize; | |||
var gapSize = (constants.blockSize - 4) / 2; | |||
var x = ~~(this.pos.x / gridSize) - (this.pos.x / gridSize); | |||
var y = ~~(this.pos.y / gridSize) - (this.pos.y / gridSize); | |||
w = ~~(this.screen.w / gridSize); | |||
h = ~~(this.screen.h / gridSize); | |||
ctx.fillStyle = '#3c3f4c'; | |||
for (var i = 0; i < w; i++) { | |||
for (var j = 0; j < h; j++) { | |||
if ((mouse.x == i) && (mouse.y == j)) { | |||
ctx.fillStyle = '#ff6942'; | |||
ctx.fillRect((i * gridSize) - 25, (j * gridSize) - 25, 9, 9); | |||
ctx.fillStyle = '#3c3f4c'; | |||
} else | |||
ctx.fillRect((i * gridSize) - 23, (j * gridSize) - 23, 5, 5); | |||
for (var i = x; i < w; i++) { | |||
for (var j = y; j < h; j++) { | |||
ctx.fillRect((i * gridSize) + gapSize, (j * gridSize) + gapSize, 4, 4); | |||
} | |||
} | |||
ctx.fillStyle = '#ff0000'; | |||
ctx.fillRect( | |||
(this.mouse.x * constants.gridSize) - this.pos.x + (gapSize / 1), | |||
(this.mouse.y * constants.gridSize) - this.pos.y + (gapSize / 1), | |||
8, | |||
8 | |||
); | |||
}, | |||
node: function (node) { | |||
@@ -111,8 +138,8 @@ define([ | |||
constants.blockSize * 2, | |||
constants.blockSize * 3 | |||
])[node.size]; | |||
var x = (node.pos.x * constants.gridSize) - ((size - constants.blockSize) / 2); | |||
var y = (node.pos.y * constants.gridSize) - ((size - constants.blockSize) / 2); | |||
var x = (node.pos.x * constants.gridSize) - ((size - constants.blockSize) / 2) - this.pos.x; | |||
var y = (node.pos.y * constants.gridSize) - ((size - constants.blockSize) / 2) - this.pos.y; | |||
this.ctx.fillRect(x, y, size, size); | |||
@@ -126,11 +153,11 @@ define([ | |||
var ctx = this.ctx; | |||
var halfSize = constants.blockSize / 2; | |||
var fromX = (fromNode.pos.x * constants.gridSize) + halfSize; | |||
var fromY = (fromNode.pos.y * constants.gridSize) + halfSize; | |||
var fromX = (fromNode.pos.x * constants.gridSize) + halfSize - this.pos.x; | |||
var fromY = (fromNode.pos.y * constants.gridSize) + halfSize - this.pos.y; | |||
var toX = (toNode.pos.x * constants.gridSize) + halfSize; | |||
var toY = (toNode.pos.y * constants.gridSize) + halfSize; | |||
var toX = (toNode.pos.x * constants.gridSize) + halfSize - this.pos.x; | |||
var toY = (toNode.pos.y * constants.gridSize) + halfSize - this.pos.y; | |||
ctx.strokeStyle = '#69696e'; | |||
ctx.beginPath(); | |||
@@ -142,12 +169,6 @@ define([ | |||
}, | |||
events: { | |||
onClick: function (e) { | |||
generator.onClick(e.button, ~~((e.clientX + this.pos.x + 40) / constants.gridSize) - 1, ~~((e.clientY + this.pos.y + 40) / constants.gridSize) - 1); | |||
e.preventDefault(); | |||
return false; | |||
}, | |||
onMouseMove: function (pos) { | |||
if ((this.mouse.x == pos.x) && (this.mouse.y == pos.y)) | |||
return; | |||
@@ -157,6 +178,49 @@ define([ | |||
y: pos.y | |||
}; | |||
this.makeDirty(); | |||
}, | |||
onPanStart: function (e) { | |||
this.panOrigin = { | |||
x: e.clientX, | |||
y: e.clientY | |||
}; | |||
}, | |||
onPan: function (e) { | |||
if (!this.panOrigin) | |||
return; | |||
if (!this.oldPos) { | |||
this.oldPos = { | |||
x: this.pos.x, | |||
y: this.pos.y | |||
}; | |||
} | |||
this.pos.x += (this.panOrigin.x - e.clientX) * constants.scrollSpeed; | |||
this.pos.y += (this.panOrigin.y - e.clientY) * constants.scrollSpeed; | |||
this.panOrigin = { | |||
x: e.clientX, | |||
y: e.clientY | |||
}; | |||
}, | |||
onPanEnd: function (e) { | |||
this.panOrigin = null; | |||
}, | |||
onStartAreaSelect: function (e) { | |||
this.areaSelectOrigin = { | |||
x: e.x, | |||
y: e.y | |||
}; | |||
}, | |||
onEndAreaSelect: function (e) { | |||
events.emit('onAreaSelect', this.areaSelectOrigin, e); | |||
this.areaSelectOrigin = null; | |||
} | |||
} | |||
}; | |||
@@ -0,0 +1,174 @@ | |||
/* | |||
* Require-CSS RequireJS css! loader plugin | |||
* 0.1.8 | |||
* Guy Bedford 2014 | |||
* MIT | |||
*/ | |||
/* | |||
* | |||
* Usage: | |||
* require(['css!./mycssFile']); | |||
* | |||
* Tested and working in (up to latest versions as of March 2013): | |||
* Android | |||
* iOS 6 | |||
* IE 6 - 10 | |||
* Chome 3 - 26 | |||
* Firefox 3.5 - 19 | |||
* Opera 10 - 12 | |||
* | |||
* browserling.com used for virtual testing environment | |||
* | |||
* Credit to B Cavalier & J Hann for the IE 6 - 9 method, | |||
* refined with help from Martin Cermak | |||
* | |||
* Sources that helped along the way: | |||
* - https://developer.mozilla.org/en-US/docs/Browser_detection_using_the_user_agent | |||
* - http://www.phpied.com/when-is-a-stylesheet-really-loaded/ | |||
* - https://github.com/cujojs/curl/blob/master/src/curl/plugin/css.js | |||
* | |||
*/ | |||
define(function() { | |||
//>>excludeStart('excludeRequireCss', pragmas.excludeRequireCss) | |||
if (typeof window == 'undefined') | |||
return { | |||
load: function(n, r, load) { | |||
load() | |||
} | |||
}; | |||
var head = document.getElementsByTagName('head')[0]; | |||
var engine = window.navigator.userAgent.match(/Trident\/([^ ;]*)|AppleWebKit\/([^ ;]*)|Opera\/([^ ;]*)|rv\:([^ ;]*)(.*?)Gecko\/([^ ;]*)|MSIE\s([^ ;]*)|AndroidWebKit\/([^ ;]*)/) || 0; | |||
// use <style> @import load method (IE < 9, Firefox < 18) | |||
var useImportLoad = false; | |||
// set to false for explicit <link> load checking when onload doesn't work perfectly (webkit) | |||
var useOnload = true; | |||
// trident / msie | |||
if (engine[1] || engine[7]) | |||
useImportLoad = parseInt(engine[1]) < 6 || parseInt(engine[7]) <= 9; | |||
// webkit | |||
else if (engine[2] || engine[8]) | |||
useOnload = false; | |||
// gecko | |||
else if (engine[4]) | |||
useImportLoad = parseInt(engine[4]) < 18; | |||
//>>excludeEnd('excludeRequireCss') | |||
//main api object | |||
var cssAPI = {}; | |||
//>>excludeStart('excludeRequireCss', pragmas.excludeRequireCss) | |||
cssAPI.pluginBuilder = './css-builder'; | |||
// <style> @import load method | |||
var curStyle, curSheet; | |||
var createStyle = function() { | |||
curStyle = document.createElement('style'); | |||
head.appendChild(curStyle); | |||
curSheet = curStyle.styleSheet || curStyle.sheet; | |||
} | |||
var ieCnt = 0; | |||
var ieLoads = []; | |||
var ieCurCallback; | |||
var createIeLoad = function(url) { | |||
curSheet.addImport(url); | |||
curStyle.onload = function() { | |||
processIeLoad() | |||
}; | |||
ieCnt++; | |||
if (ieCnt == 31) { | |||
createStyle(); | |||
ieCnt = 0; | |||
} | |||
} | |||
var processIeLoad = function() { | |||
ieCurCallback(); | |||
var nextLoad = ieLoads.shift(); | |||
if (!nextLoad) { | |||
ieCurCallback = null; | |||
return; | |||
} | |||
ieCurCallback = nextLoad[1]; | |||
createIeLoad(nextLoad[0]); | |||
} | |||
var importLoad = function(url, callback) { | |||
if (!curSheet || !curSheet.addImport) | |||
createStyle(); | |||
if (curSheet && curSheet.addImport) { | |||
// old IE | |||
if (ieCurCallback) { | |||
ieLoads.push([url, callback]); | |||
} else { | |||
createIeLoad(url); | |||
ieCurCallback = callback; | |||
} | |||
} else { | |||
// old Firefox | |||
curStyle.textContent = '@import "' + url + '";'; | |||
var loadInterval = setInterval(function() { | |||
try { | |||
curStyle.sheet.cssRules; | |||
clearInterval(loadInterval); | |||
callback(); | |||
} catch (e) {} | |||
}, 10); | |||
} | |||
} | |||
// <link> load method | |||
var linkLoad = function(url, callback) { | |||
var link = document.createElement('link'); | |||
link.type = 'text/css'; | |||
link.rel = 'stylesheet'; | |||
if (useOnload) { | |||
link.onload = function() { | |||
link.onload = function() {}; | |||
// for style dimensions queries, a short delay can still be necessary | |||
setTimeout(callback, 7); | |||
} | |||
} else { | |||
var loadInterval = setInterval(function() { | |||
for (var i = 0; i < document.styleSheets.length; i++) { | |||
var sheet = document.styleSheets[i]; | |||
if (sheet.href == link.href) { | |||
clearInterval(loadInterval); | |||
return callback(); | |||
} | |||
} | |||
}, 10); | |||
} | |||
link.href = url; | |||
head.appendChild(link); | |||
} | |||
//>>excludeEnd('excludeRequireCss') | |||
cssAPI.normalize = function(name, normalize) { | |||
if (name.substr(name.length - 4, 4) == '.css') | |||
name = name.substr(0, name.length - 4); | |||
return normalize(name); | |||
} | |||
//>>excludeStart('excludeRequireCss', pragmas.excludeRequireCss) | |||
cssAPI.load = function(cssId, req, load, config) { | |||
(useImportLoad ? importLoad : linkLoad)(req.toUrl(cssId + '.css'), load); | |||
} | |||
//>>excludeEnd('excludeRequireCss') | |||
return cssAPI; | |||
}); |
@@ -0,0 +1,123 @@ | |||
define(['text'], function(textPlugin) { | |||
var buildText = {}; | |||
return { | |||
load: function(name, req, onLoad, config) { | |||
var self = this, | |||
file = name, | |||
segments = file.split('/'); | |||
// If the module name does not have an extension, append the default one | |||
if (segments[segments.length - 1].lastIndexOf('.') == -1) { | |||
file += '.html'; | |||
} | |||
textPlugin.get(req.toUrl(file), function(html) { | |||
for (var option in config.config.html) { | |||
if (option in self.transform) { | |||
html = self.transform[option](config.config.html[option], html); | |||
} | |||
} | |||
if (config.isBuild) { | |||
buildText[name] = textPlugin.jsEscape(html); | |||
} | |||
onLoad(html); | |||
}, onLoad.error); | |||
}, | |||
write: function(pluginName, moduleName, write) { | |||
if (buildText.hasOwnProperty(moduleName)) { | |||
var name = "'" + pluginName + "!" + moduleName + "'", | |||
text = "function () {return '" + buildText[moduleName] + "';}"; | |||
write("define(" + name + ", " + text + ");\n"); | |||
} | |||
}, | |||
transform: { | |||
comments: function(action, html) { | |||
if (action === 'strip') { | |||
return html.replace(/<!--(.|[\n\r])*?-->/gm, ''); | |||
} else { | |||
return html; | |||
} | |||
}, | |||
whitespaceBetweenTags: function(action, html) { | |||
var pattern = />[\n\r\s]+</gm; | |||
if (action === 'strip') { | |||
return html.replace(pattern, '><'); | |||
} else if (action === 'collapse') { | |||
return html.replace(pattern, '> <'); | |||
} else { | |||
return html; | |||
} | |||
}, | |||
whitespaceBetweenTagsAndText: function(action, html) { | |||
var afterTagPattern = />[\n\r\s]+/gm, | |||
beforeTagPattern = /[\n\r\s]+</gm; | |||
if (action === 'strip') { | |||
return html.replace(afterTagPattern, '>').replace(beforeTagPattern, '<'); | |||
} else if (action === 'collapse') { | |||
return html.replace(afterTagPattern, '> ').replace(beforeTagPattern, ' <'); | |||
} else { | |||
return html; | |||
} | |||
}, | |||
whitespaceWithinTags: function(action, html) { | |||
if (action === 'collapse') { | |||
var tagPattern = /<([^>"']*?|"[^"]*?"|'[^']*?')+>/g, | |||
attrPattern = /([^\0\n\r\s"'>\/=]+)(?:\s*(=)\s*([^\n\r\s"'=><`]+|"[^"]*"|'[^']*'))?/gi, | |||
lastIndex = 0, | |||
result = '', | |||
match, | |||
tag; | |||
while ((match = tagPattern.exec(html)) !== null) { | |||
// Copy text between the beginning of this match and the end of the last one | |||
result += html.substring(lastIndex, match.index); | |||
tag = match[0]; | |||
if (/^<[^\/]/.test(tag)) { // It's a start tag | |||
var attrs = tag.match(attrPattern), | |||
start = attrs.shift(), | |||
end = /\/>$/.test(tag) ? '/>' : '>'; | |||
result += start + attrs.map(function(attr) { | |||
return attr.replace(attrPattern, ' $1$2$3'); | |||
}).join('') + end; | |||
} else { // It's an end tag | |||
result += tag.replace(/[\n\r\s]+/g, ''); | |||
} | |||
lastIndex = tagPattern.lastIndex; | |||
} | |||
return result + html.substring(lastIndex); | |||
} else { | |||
return html; | |||
} | |||
} | |||
} | |||
}; | |||
}); |
@@ -0,0 +1,72 @@ | |||
/** @license | |||
* RequireJS plugin for loading JSON files | |||
* - depends on Text plugin and it was HEAVILY "inspired" by it as well. | |||
* Author: Miller Medeiros | |||
* Version: 0.4.0 (2014/04/10) | |||
* Released under the MIT license | |||
*/ | |||
define(['text'], function(text){ | |||
var CACHE_BUST_QUERY_PARAM = 'bust', | |||
CACHE_BUST_FLAG = '!bust', | |||
jsonParse = (typeof JSON !== 'undefined' && typeof JSON.parse === 'function')? JSON.parse : function(val){ | |||
return eval('('+ val +')'); //quick and dirty | |||
}, | |||
buildMap = {}; | |||
function cacheBust(url){ | |||
url = url.replace(CACHE_BUST_FLAG, ''); | |||
url += (url.indexOf('?') < 0)? '?' : '&'; | |||
return url + CACHE_BUST_QUERY_PARAM +'='+ Math.round(2147483647 * Math.random()); | |||
} | |||
//API | |||
return { | |||
load : function(name, req, onLoad, config) { | |||
if (( config.isBuild && (config.inlineJSON === false || name.indexOf(CACHE_BUST_QUERY_PARAM +'=') !== -1)) || (req.toUrl(name).indexOf('empty:') === 0)) { | |||
//avoid inlining cache busted JSON or if inlineJSON:false | |||
//and don't inline files marked as empty! | |||
onLoad(null); | |||
} else { | |||
text.get(req.toUrl(name), function(data){ | |||
var parsed; | |||
if (config.isBuild) { | |||
buildMap[name] = data; | |||
onLoad(data); | |||
} else { | |||
try { | |||
parsed = jsonParse(data); | |||
} catch (e) { | |||
onLoad.error(e); | |||
} | |||
onLoad(parsed); | |||
} | |||
}, | |||
onLoad.error, { | |||
accept: 'application/json' | |||
} | |||
); | |||
} | |||
}, | |||
normalize : function (name, normalize) { | |||
// used normalize to avoid caching references to a "cache busted" request | |||
if (name.indexOf(CACHE_BUST_FLAG) !== -1) { | |||
name = cacheBust(name); | |||
} | |||
// resolve any relative paths | |||
return normalize(name); | |||
}, | |||
//write method based on RequireJS official text plugin by James Burke | |||
//https://github.com/jrburke/requirejs/blob/master/text.js | |||
write : function(pluginName, moduleName, write){ | |||
if(moduleName in buildMap){ | |||
var content = buildMap[moduleName]; | |||
write('define("'+ pluginName +'!'+ moduleName +'", function(){ return '+ content +';});\n'); | |||
} | |||
} | |||
}; | |||
}); |
@@ -0,0 +1,391 @@ | |||
/** | |||
* @license RequireJS text 2.0.14 Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved. | |||
* Available via the MIT or new BSD license. | |||
* see: http://github.com/requirejs/text for details | |||
*/ | |||
/*jslint regexp: true */ | |||
/*global require, XMLHttpRequest, ActiveXObject, | |||
define, window, process, Packages, | |||
java, location, Components, FileUtils */ | |||
define(['module'], function (module) { | |||
'use strict'; | |||
var text, fs, Cc, Ci, xpcIsWindows, | |||
progIds = ['Msxml2.XMLHTTP', 'Microsoft.XMLHTTP', 'Msxml2.XMLHTTP.4.0'], | |||
xmlRegExp = /^\s*<\?xml(\s)+version=[\'\"](\d)*.(\d)*[\'\"](\s)*\?>/im, | |||
bodyRegExp = /<body[^>]*>\s*([\s\S]+)\s*<\/body>/im, | |||
hasLocation = typeof location !== 'undefined' && location.href, | |||
defaultProtocol = hasLocation && location.protocol && location.protocol.replace(/\:/, ''), | |||
defaultHostName = hasLocation && location.hostname, | |||
defaultPort = hasLocation && (location.port || undefined), | |||
buildMap = {}, | |||
masterConfig = (module.config && module.config()) || {}; | |||
text = { | |||
version: '2.0.14', | |||
strip: function (content) { | |||
//Strips <?xml ...?> declarations so that external SVG and XML | |||
//documents can be added to a document without worry. Also, if the string | |||
//is an HTML document, only the part inside the body tag is returned. | |||
if (content) { | |||
content = content.replace(xmlRegExp, ""); | |||
var matches = content.match(bodyRegExp); | |||
if (matches) { | |||
content = matches[1]; | |||
} | |||
} else { | |||
content = ""; | |||
} | |||
return content; | |||
}, | |||
jsEscape: function (content) { | |||
return content.replace(/(['\\])/g, '\\$1') | |||
.replace(/[\f]/g, "\\f") | |||
.replace(/[\b]/g, "\\b") | |||
.replace(/[\n]/g, "\\n") | |||
.replace(/[\t]/g, "\\t") | |||
.replace(/[\r]/g, "\\r") | |||
.replace(/[\u2028]/g, "\\u2028") | |||
.replace(/[\u2029]/g, "\\u2029"); | |||
}, | |||
createXhr: masterConfig.createXhr || function () { | |||
//Would love to dump the ActiveX crap in here. Need IE 6 to die first. | |||
var xhr, i, progId; | |||
if (typeof XMLHttpRequest !== "undefined") { | |||
return new XMLHttpRequest(); | |||
} else if (typeof ActiveXObject !== "undefined") { | |||
for (i = 0; i < 3; i += 1) { | |||
progId = progIds[i]; | |||
try { | |||
xhr = new ActiveXObject(progId); | |||
} catch (e) {} | |||
if (xhr) { | |||
progIds = [progId]; // so faster next time | |||
break; | |||
} | |||
} | |||
} | |||
return xhr; | |||
}, | |||
/** | |||
* Parses a resource name into its component parts. Resource names | |||
* look like: module/name.ext!strip, where the !strip part is | |||
* optional. | |||
* @param {String} name the resource name | |||
* @returns {Object} with properties "moduleName", "ext" and "strip" | |||
* where strip is a boolean. | |||
*/ | |||
parseName: function (name) { | |||
var modName, ext, temp, | |||
strip = false, | |||
index = name.lastIndexOf("."), | |||
isRelative = name.indexOf('./') === 0 || | |||
name.indexOf('../') === 0; | |||
if (index !== -1 && (!isRelative || index > 1)) { | |||
modName = name.substring(0, index); | |||
ext = name.substring(index + 1); | |||
} else { | |||
modName = name; | |||
} | |||
temp = ext || modName; | |||
index = temp.indexOf("!"); | |||
if (index !== -1) { | |||
//Pull off the strip arg. | |||
strip = temp.substring(index + 1) === "strip"; | |||
temp = temp.substring(0, index); | |||
if (ext) { | |||
ext = temp; | |||
} else { | |||
modName = temp; | |||
} | |||
} | |||
return { | |||
moduleName: modName, | |||
ext: ext, | |||
strip: strip | |||
}; | |||
}, | |||
xdRegExp: /^((\w+)\:)?\/\/([^\/\\]+)/, | |||
/** | |||
* Is an URL on another domain. Only works for browser use, returns | |||
* false in non-browser environments. Only used to know if an | |||
* optimized .js version of a text resource should be loaded | |||
* instead. | |||
* @param {String} url | |||
* @returns Boolean | |||
*/ | |||
useXhr: function (url, protocol, hostname, port) { | |||
var uProtocol, uHostName, uPort, | |||
match = text.xdRegExp.exec(url); | |||
if (!match) { | |||
return true; | |||
} | |||
uProtocol = match[2]; | |||
uHostName = match[3]; | |||
uHostName = uHostName.split(':'); | |||
uPort = uHostName[1]; | |||
uHostName = uHostName[0]; | |||
return (!uProtocol || uProtocol === protocol) && | |||
(!uHostName || uHostName.toLowerCase() === hostname.toLowerCase()) && | |||
((!uPort && !uHostName) || uPort === port); | |||
}, | |||
finishLoad: function (name, strip, content, onLoad) { | |||
content = strip ? text.strip(content) : content; | |||
if (masterConfig.isBuild) { | |||
buildMap[name] = content; | |||
} | |||
onLoad(content); | |||
}, | |||
load: function (name, req, onLoad, config) { | |||
//Name has format: some.module.filext!strip | |||
//The strip part is optional. | |||
//if strip is present, then that means only get the string contents | |||
//inside a body tag in an HTML string. For XML/SVG content it means | |||
//removing the <?xml ...?> declarations so the content can be inserted | |||
//into the current doc without problems. | |||
// Do not bother with the work if a build and text will | |||
// not be inlined. | |||
if (config && config.isBuild && !config.inlineText) { | |||
onLoad(); | |||
return; | |||
} | |||
masterConfig.isBuild = config && config.isBuild; | |||
var parsed = text.parseName(name), | |||
nonStripName = parsed.moduleName + | |||
(parsed.ext ? '.' + parsed.ext : ''), | |||
url = req.toUrl(nonStripName), | |||
useXhr = (masterConfig.useXhr) || | |||
text.useXhr; | |||
// Do not load if it is an empty: url | |||
if (url.indexOf('empty:') === 0) { | |||
onLoad(); | |||
return; | |||
} | |||
//Load the text. Use XHR if possible and in a browser. | |||
if (!hasLocation || useXhr(url, defaultProtocol, defaultHostName, defaultPort)) { | |||
text.get(url, function (content) { | |||
text.finishLoad(name, parsed.strip, content, onLoad); | |||
}, function (err) { | |||
if (onLoad.error) { | |||
onLoad.error(err); | |||
} | |||
}); | |||
} else { | |||
//Need to fetch the resource across domains. Assume | |||
//the resource has been optimized into a JS module. Fetch | |||
//by the module name + extension, but do not include the | |||
//!strip part to avoid file system issues. | |||
req([nonStripName], function (content) { | |||
text.finishLoad(parsed.moduleName + '.' + parsed.ext, | |||
parsed.strip, content, onLoad); | |||
}); | |||
} | |||
}, | |||
write: function (pluginName, moduleName, write, config) { | |||
if (buildMap.hasOwnProperty(moduleName)) { | |||
var content = text.jsEscape(buildMap[moduleName]); | |||
write.asModule(pluginName + "!" + moduleName, | |||
"define(function () { return '" + | |||
content + | |||
"';});\n"); | |||
} | |||
}, | |||
writeFile: function (pluginName, moduleName, req, write, config) { | |||
var parsed = text.parseName(moduleName), | |||
extPart = parsed.ext ? '.' + parsed.ext : '', | |||
nonStripName = parsed.moduleName + extPart, | |||
//Use a '.js' file name so that it indicates it is a | |||
//script that can be loaded across domains. | |||
fileName = req.toUrl(parsed.moduleName + extPart) + '.js'; | |||
//Leverage own load() method to load plugin value, but only | |||
//write out values that do not have the strip argument, | |||
//to avoid any potential issues with ! in file names. | |||
text.load(nonStripName, req, function (value) { | |||
//Use own write() method to construct full module value. | |||
//But need to create shell that translates writeFile's | |||
//write() to the right interface. | |||
var textWrite = function (contents) { | |||
return write(fileName, contents); | |||
}; | |||
textWrite.asModule = function (moduleName, contents) { | |||
return write.asModule(moduleName, fileName, contents); | |||
}; | |||
text.write(pluginName, nonStripName, textWrite, config); | |||
}, config); | |||
} | |||
}; | |||
if (masterConfig.env === 'node' || (!masterConfig.env && | |||
typeof process !== "undefined" && | |||
process.versions && | |||
!!process.versions.node && | |||
!process.versions['node-webkit'] && | |||
!process.versions['atom-shell'])) { | |||
//Using special require.nodeRequire, something added by r.js. | |||
fs = require.nodeRequire('fs'); | |||
text.get = function (url, callback, errback) { | |||
try { | |||
var file = fs.readFileSync(url, 'utf8'); | |||
//Remove BOM (Byte Mark Order) from utf8 files if it is there. | |||
if (file[0] === '\uFEFF') { | |||
file = file.substring(1); | |||
} | |||
callback(file); | |||
} catch (e) { | |||
if (errback) { | |||
errback(e); | |||
} | |||
} | |||
}; | |||
} else if (masterConfig.env === 'xhr' || (!masterConfig.env && | |||
text.createXhr())) { | |||
text.get = function (url, callback, errback, headers) { | |||
var xhr = text.createXhr(), header; | |||
xhr.open('GET', url, true); | |||
//Allow plugins direct access to xhr headers | |||
if (headers) { | |||
for (header in headers) { | |||
if (headers.hasOwnProperty(header)) { | |||
xhr.setRequestHeader(header.toLowerCase(), headers[header]); | |||
} | |||
} | |||
} | |||
//Allow overrides specified in config | |||
if (masterConfig.onXhr) { | |||
masterConfig.onXhr(xhr, url); | |||
} | |||
xhr.onreadystatechange = function (evt) { | |||
var status, err; | |||
//Do not explicitly handle errors, those should be | |||
//visible via console output in the browser. | |||
if (xhr.readyState === 4) { | |||
status = xhr.status || 0; | |||
if (status > 399 && status < 600) { | |||
//An http 4xx or 5xx error. Signal an error. | |||
err = new Error(url + ' HTTP status: ' + status); | |||
err.xhr = xhr; | |||
if (errback) { | |||
errback(err); | |||
} | |||
} else { | |||
callback(xhr.responseText); | |||
} | |||
if (masterConfig.onXhrComplete) { | |||
masterConfig.onXhrComplete(xhr, url); | |||
} | |||
} | |||
}; | |||
xhr.send(null); | |||
}; | |||
} else if (masterConfig.env === 'rhino' || (!masterConfig.env && | |||
typeof Packages !== 'undefined' && typeof java !== 'undefined')) { | |||
//Why Java, why is this so awkward? | |||
text.get = function (url, callback) { | |||
var stringBuffer, line, | |||
encoding = "utf-8", | |||
file = new java.io.File(url), | |||
lineSeparator = java.lang.System.getProperty("line.separator"), | |||
input = new java.io.BufferedReader(new java.io.InputStreamReader(new java.io.FileInputStream(file), encoding)), | |||
content = ''; | |||
try { | |||
stringBuffer = new java.lang.StringBuffer(); | |||
line = input.readLine(); | |||
// Byte Order Mark (BOM) - The Unicode Standard, version 3.0, page 324 | |||
// http://www.unicode.org/faq/utf_bom.html | |||
// Note that when we use utf-8, the BOM should appear as "EF BB BF", but it doesn't due to this bug in the JDK: | |||
// http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4508058 | |||
if (line && line.length() && line.charAt(0) === 0xfeff) { | |||
// Eat the BOM, since we've already found the encoding on this file, | |||
// and we plan to concatenating this buffer with others; the BOM should | |||
// only appear at the top of a file. | |||
line = line.substring(1); | |||
} | |||
if (line !== null) { | |||
stringBuffer.append(line); | |||
} | |||
while ((line = input.readLine()) !== null) { | |||
stringBuffer.append(lineSeparator); | |||
stringBuffer.append(line); | |||
} | |||
//Make sure we return a JavaScript string and not a Java string. | |||
content = String(stringBuffer.toString()); //String | |||
} finally { | |||
input.close(); | |||
} | |||
callback(content); | |||
}; | |||
} else if (masterConfig.env === 'xpconnect' || (!masterConfig.env && | |||
typeof Components !== 'undefined' && Components.classes && | |||
Components.interfaces)) { | |||
//Avert your gaze! | |||
Cc = Components.classes; | |||
Ci = Components.interfaces; | |||
Components.utils['import']('resource://gre/modules/FileUtils.jsm'); | |||
xpcIsWindows = ('@mozilla.org/windows-registry-key;1' in Cc); | |||
text.get = function (url, callback) { | |||
var inStream, convertStream, fileObj, | |||
readData = {}; | |||
if (xpcIsWindows) { | |||
url = url.replace(/\//g, '\\'); | |||
} | |||
fileObj = new FileUtils.File(url); | |||
//XPCOM, you so crazy | |||
try { | |||
inStream = Cc['@mozilla.org/network/file-input-stream;1'] | |||
.createInstance(Ci.nsIFileInputStream); | |||
inStream.init(fileObj, 1, 0, false); | |||
convertStream = Cc['@mozilla.org/intl/converter-input-stream;1'] | |||
.createInstance(Ci.nsIConverterInputStream); | |||
convertStream.init(inStream, "utf-8", inStream.available(), | |||
Ci.nsIConverterInputStream.DEFAULT_REPLACEMENT_CHARACTER); | |||
convertStream.readString(inStream.available(), readData); | |||
convertStream.close(); | |||
inStream.close(); | |||
callback(readData.value); | |||
} catch (e) { | |||
throw new Error((fileObj && fileObj.path || '') + ': ' + e); | |||
} | |||
}; | |||
} | |||
return text; | |||
}); |
@@ -1,4 +1,5 @@ | |||
html, body { | |||
width: 100vw; | |||
height: 100vh; | |||
} | |||
@@ -9,36 +10,6 @@ body { | |||
overflow: hidden; | |||
} | |||
.left, .right { | |||
float: left; | |||
height: 100%; | |||
} | |||
.left { | |||
width: 85%; | |||
} | |||
.right { | |||
width: 15%; | |||
background-color: #373041; | |||
} | |||
.right .id { | |||
width: 100%; | |||
text-align: center; | |||
padding: 10px; | |||
color: #fafcfc; | |||
font-size: 36px; | |||
} | |||
.right .command { | |||
width: 100%; | |||
text-align: center; | |||
padding: 10px; | |||
color: #fafcfc; | |||
font-size: 24px; | |||
} | |||
.right .id:before { | |||
content: 'id: '; | |||
.canvas, .ui-container { | |||
position: absolute; | |||
} |
@@ -0,0 +1,69 @@ | |||
define([ | |||
'ui/uiBase' | |||
], function ( | |||
uiBase | |||
) { | |||
return { | |||
uis: [], | |||
root: '', | |||
init: function (root) { | |||
if (root) | |||
this.root = root + '/'; | |||
}, | |||
build: function (type, options) { | |||
var className = 'ui' + type[0].toUpperCase() + type.substr(1); | |||
var el = $('.' + className); | |||
if (el.length > 0) | |||
return; | |||
this.getTemplate(type, options); | |||
$(window).on('resize', this.onResize.bind(this)); | |||
}, | |||
getTemplate: function (type, options) { | |||
require([this.root + 'ui/templates/' + type + '/' + type], this.onGetTemplate.bind(this, options)); | |||
}, | |||
onGetTemplate: function (options, template) { | |||
var ui = _.create(uiBase, template); | |||
ui.setOptions(options); | |||
ui.render(); | |||
ui.el.data('ui', ui); | |||
this.uis.push(ui); | |||
}, | |||
onResize: function () { | |||
this.uis.forEach(function (ui) { | |||
if (ui.centered) | |||
ui.center(); | |||
else if ((ui.centeredX) || (ui.centeredY)) | |||
ui.center(ui.centeredX, ui.centeredY); | |||
}, this); | |||
}, | |||
onKeyDown: function (key) { | |||
if (key == 'esc') { | |||
this.uis.forEach(function (u) { | |||
if (!u.modal) | |||
return; | |||
u.hide(); | |||
}); | |||
$('.uiOverlay').hide(); | |||
} | |||
}, | |||
update: function () { | |||
var uis = this.uis; | |||
var uLen = uis.length; | |||
for (var i = 0; i < uLen; i++) { | |||
var u = uis[i]; | |||
if (u.update) | |||
u.update(); | |||
} | |||
} | |||
}; | |||
}); |
@@ -0,0 +1,13 @@ | |||
define([ | |||
'html!./template' | |||
], function ( | |||
template | |||
) { | |||
return { | |||
tpl: template, | |||
postRender: function () { | |||
} | |||
} | |||
}); |
@@ -0,0 +1,8 @@ | |||
<div class="uiInventory"> | |||
<div class="heading"> | |||
<div class="heading-text">Node Info</div> | |||
</div> | |||
<div class="content"> | |||
</div> | |||
</div> |
@@ -0,0 +1,153 @@ | |||
define([ | |||
'js/events' | |||
], function ( | |||
events | |||
) { | |||
return { | |||
centeredX: false, | |||
centeredY: false, | |||
el: null, | |||
options: null, | |||
shown: true, | |||
eventCallbacks: {}, | |||
render: function () { | |||
var container = '.ui-container'; | |||
if (this.container) | |||
container += ' > ' + this.container; | |||
this.el = $(this.tpl) | |||
.appendTo(container) | |||
.data('ui', this); | |||
this.el.on('mouseenter', this.onMouseEnter.bind(this, true)); | |||
this.el.on('mouseleave', this.onMouseEnter.bind(this, false)); | |||
if (this.modal) | |||
this.el.addClass('modal'); | |||
this.postRender && this.postRender(); | |||
if (this.centered) { | |||
this.centeredX = true; | |||
this.centeredY = true; | |||
} | |||
if ((this.centeredX) || (this.centeredY)) | |||
this.center(this.centeredX, this.centeredY); | |||
this.shown = this.el.is(':visible'); | |||
}, | |||
onMouseEnter: function (enter) { | |||
events.emit('onUiHover', enter); | |||
}, | |||
setOptions: function (options) { | |||
this.options = options; | |||
}, | |||
on: function (el, event, callback) { | |||
if (typeof (el) == 'string') | |||
el = this.find(el); | |||
else | |||
el = $(el); | |||
el.on(event, function () { | |||
var args = [].slice.call(arguments, 1); | |||
args.splice(0, 0, event); | |||
callback.apply(null, args); | |||
}); | |||
}, | |||
find: function (selector) { | |||
return this.el.find(selector); | |||
}, | |||
center: function (x, y) { | |||
if (x == null) | |||
x = true; | |||
if (y == null) | |||
y = true; | |||
this.centeredX = x; | |||
this.centeredY = y; | |||
var el = this.el; | |||
var pat = el.parent(); | |||
var posX = ~~((pat.width() / 2) - (el.width() / 2)) - 10; | |||
var posY = ~~((pat.height() / 2) - (el.height() / 2)) - 10; | |||
el.css('position', 'absolute'); | |||
if (x) | |||
el.css('left', posX); | |||
if (y) | |||
el.css('top', posY); | |||
}, | |||
show: function () { | |||
if (this.modal) | |||
$('.modal').hide(); | |||
this.shown = true; | |||
this.el.show(); | |||
}, | |||
hide: function () { | |||
if (this.beforeHide) | |||
this.beforeHide(); | |||
this.shown = false; | |||
this.el.hide(); | |||
}, | |||
destroy: function () { | |||
this.offEvents(); | |||
if (this.beforeDestroy) | |||
this.beforeDestroy(); | |||
this.el.remove(); | |||
}, | |||
val: function (selector) { | |||
return this.find(selector).val(); | |||
}, | |||
setDisabled: function (isDisabled) { | |||
this.el.removeClass('disabled') | |||
if (isDisabled) | |||
this.el.addClass('disabled'); | |||
}, | |||
onEvent: function (event, callback) { | |||
var list = this.eventCallbacks[event] || (this.eventCallbacks[event] = []); | |||
var eventCallback = events.on(event, callback); | |||
list.push(eventCallback); | |||
return eventCallback; | |||
}, | |||
offEvent: function (eventCallback) { | |||
for (var e in this.eventCallbacks) { | |||
this.eventCallbacks[e].forEach(function (c) { | |||
if (c == eventCallback) | |||
events.off(e, c); | |||
}, this); | |||
} | |||
}, | |||
offEvents: function () { | |||
for (var e in this.eventCallbacks) { | |||
this.eventCallbacks[e].forEach(function (c) { | |||
events.off(e, c); | |||
}, this); | |||
} | |||
} | |||
}; | |||
}); |