Incomplete attempt at converting to Polymer

feature/core
Sven Slootweg 9 years ago
parent 500afa8b18
commit ce10940e06

3
.gitignore vendored

@ -6,3 +6,6 @@ sasswatch.pid
node_modules
src/scss/*.css
src/scss/*.css.map
src/elements/*.css
src/elements/*.css.map
/bower_components/

@ -5,8 +5,6 @@ logger = require('morgan');
cookieParser = require('cookie-parser');
bodyParser = require('body-parser');
routes = require('./routes/index');
app = express();
app.set('views', path.join(__dirname, 'views'));
@ -18,8 +16,10 @@ app.use(bodyParser.json());
app.use(bodyParser.urlencoded());
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use("/bower_components", express.static(path.join(__dirname, 'bower_components')));
app.use('/', routes);
app.use "/", require("./routes/index")
app.use "/nodes", require("./routes/nodes")
app.use (req, res, next) ->
err = new Error("Not Found")

@ -0,0 +1,8 @@
{
"name": "openNG",
"dependencies": {
"platform": "Polymer/platform#~0.4.2",
"polymer": "Polymer/polymer#~0.5.5"
},
"devDependencies": {}
}

@ -16,6 +16,7 @@ var jade = require("gulp-jade");
var net = require("net");
var spy = require("through2-spy");
var webpack = require("gulp-webpack");
var named = require("vinyl-named");
function namedLog(name) {
return function gutilLog(log) {
@ -38,11 +39,6 @@ tasks = {
source: ["templateUtil.coffee"],
base: ".",
destination: "."
}, {
name: "elements",
source: ["./src/elements/**/*.coffee"],
base: "./src/elements",
destination: "./public/elements"
}
],
jade: [
@ -121,6 +117,20 @@ gulp.task('webpack', function(){
.pipe(gulp.dest("./public/js"));
});
gulp.task("webpack-elements", function() {
return gulp.src(["./src/elements/**/*.coffee"], {base: "./src/elements"})
.pipe(plumber())
.pipe(named())
.pipe(webpack({
watch: true,
module: {
loaders: [{ test: /\.coffee$/, loader: "coffee-loader" }]
},
resolve: { extensions: ["", ".web.coffee", ".web.js", ".coffee", ".js"] }
}))
.pipe(gulp.dest("./public/elements"));
});
function checkServerUp(){
setTimeout(function(){
var sock = new net.Socket();
@ -154,7 +164,7 @@ gulp.task('watch', function () {
global.isWatching = true;
livereload.listen();
gulp.watch(['./**/*.css', 'views/**/*.jade', '!views/client/**/*.jade', 'package.json']).on('change', livereload.changed);
gulp.watch(['public/views/**/*.html']).on('change', function() { livereload.changed("*"); }); // We need to explicitly reload everything here; Polymer doesn't do partial reloading
gulp.watch(['public/views/**/*.html', 'public/elements/**/*']).on('change', function() { livereload.changed("*"); }); // We need to explicitly reload everything here; Polymer doesn't do partial reloading
for (i in watchTasks) {
task = watchTasks[i];
@ -164,6 +174,6 @@ gulp.task('watch', function () {
nodemon({script: "./bin/www.coffee", ext: "coffee", delay: 500}).on("start", checkServerUp);
});
startupTasks.push("webpack", "watch");
startupTasks.push("webpack", "webpack-elements", "watch");
gulp.task('default', startupTasks);

@ -14,11 +14,13 @@
"express": "~4.2.0",
"express-promise-router": "0.0.6",
"gulp-remember": "^0.3.0",
"highland": "^2.4.0",
"jade": "~1.3.0",
"jquery": "^2.1.1",
"lodash": "^2.4.1",
"morgan": "~1.0.0",
"static-favicon": "~1.0.0"
"static-favicon": "~1.0.0",
"vinyl-named": "^1.1.0"
},
"devDependencies": {
"coffee-loader": "^0.7.2",

@ -0,0 +1,6 @@
i {
margin-right: 5px; }
button[type="submit"] {
background-color: #148C29;
color: white; }

@ -0,0 +1 @@
<link rel="import" href="/bower_components/polymer/polymer.html"/><polymer-element name="pn-button" constructor="pnButton" attributes="type icon label" noscript="noscript"><template><link rel="stylesheet" href="button.css"/><link rel="stylesheet" href="/stylesheets/pure-min.css"/><link rel="stylesheet" href="/stylesheets/font-awesome.min.css"/><button type="{{type}}" class="pure-button"><i class="fa fa-{{icon}}"></i>{{label}}</button></template></polymer-element>

@ -0,0 +1,2 @@
contents.main {
overflow: auto; }

@ -0,0 +1 @@
<link rel="import" href="/bower_components/polymer/polymer.html"/><polymer-element name="pn-frame" constructor="pnFrame"><template><link rel="stylesheet" href="frame.css"/><div id="polymerWrapper"><content select="pn-toolbar" class="docks"></content><content class="main"></content></div></template><script src="frame.js"></script></polymer-element>

@ -0,0 +1,58 @@
/******/ (function(modules) { // webpackBootstrap
/******/ // The module cache
/******/ var installedModules = {};
/******/
/******/ // The require function
/******/ function __webpack_require__(moduleId) {
/******/
/******/ // Check if module is in cache
/******/ if(installedModules[moduleId])
/******/ return installedModules[moduleId].exports;
/******/
/******/ // Create a new module (and put it into the cache)
/******/ var module = installedModules[moduleId] = {
/******/ exports: {},
/******/ id: moduleId,
/******/ loaded: false
/******/ };
/******/
/******/ // Execute the module function
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/
/******/ // Flag the module as loaded
/******/ module.loaded = true;
/******/
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }
/******/
/******/
/******/ // expose the modules object (__webpack_modules__)
/******/ __webpack_require__.m = modules;
/******/
/******/ // expose the module cache
/******/ __webpack_require__.c = installedModules;
/******/
/******/ // __webpack_public_path__
/******/ __webpack_require__.p = "";
/******/
/******/ // Load entry module and return exports
/******/ return __webpack_require__(0);
/******/ })
/************************************************************************/
/******/ ([
/* 0 */
/***/ function(module, exports, __webpack_require__) {
module.exports = __webpack_require__(1);
/***/ },
/* 1 */
/***/ function(module, exports, __webpack_require__) {
Polymer("pn-frame", {});
/***/ }
/******/ ])

@ -0,0 +1 @@
<link rel="import" href="/bower_components/polymer/polymer.html"/><polymer-element name="openng-router" constructor="ngRouter"><script src="router.js"></script></polymer-element>

File diff suppressed because it is too large Load Diff

@ -1 +0,0 @@
<div>Hi! Gah!</div>

@ -0,0 +1 @@
<link rel="import" href="/bower_components/polymer/polymer.html"/><polymer-element name="pn-toolbar" constructor="pnToolbar" attributes="dock align width height" noscript="noscript"><template><link rel="stylesheet" href="toolbar.css"/><content class="dock-{{dock}} align-{{align}}"></content></template></polymer-element>

@ -0,0 +1 @@
<link rel="import" href="/bower_components/polymer/polymer.html"/><polymer-element name="openng-window-manager" constructor="ngWindowManager"><script src="window-manager.js"></script></polymer-element>

File diff suppressed because it is too large Load Diff

@ -0,0 +1,115 @@
.noscroll {
overflow-x: hidden !important;
overflow-y: hidden !important; }
/* Common styling */
.wrapper {
position: absolute; }
.title {
-webkit-box-shadow: 5px 5px 10px #1a1a1a;
-moz-box-shadow: 5px 5px 10px #1a1a1a;
box-shadow: 5px 5px 10px #1a1a1a;
position: absolute;
z-index: 2;
left: 0px;
right: 0px;
top: 0px;
cursor: default;
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
border-top-left-radius: 10px;
border-top-right-radius: 10px;
height: 16px;
color: white;
font-size: 14px;
font-weight: bold;
padding: 4px;
padding-left: 7px;
border-top: 1px solid #959595;
border-right: 1px solid #959595;
border-left: 1px solid #959595;
background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, #525252), color-stop(1, #91acbe));
background-image: -moz-linear-gradient(center bottom, #525252 0%, #91acbe 100%);
filter: alpha(opacity=95);
opacity: 0.95; }
.outer {
-webkit-box-shadow: 5px 5px 10px #1a1a1a;
-moz-box-shadow: 5px 5px 10px #1a1a1a;
box-shadow: 5px 5px 10px #1a1a1a;
position: absolute;
z-index: 3;
left: 0px;
right: 0px;
bottom: 0px;
font-size: 13px;
top: 25px;
border-bottom: 1px solid gray;
border-right: 1px solid gray;
border-left: 1px solid gray;
background-color: #F7F7F0;
filter: alpha(opacity=95);
opacity: 0.95; }
.inner-wrapper {
position: absolute;
top: 0px;
bottom: 0px;
left: 0px;
right: 0px;
overflow-y: auto;
overflow-x: auto; }
.inner {
padding: 7px; }
.close {
float: right; }
.close a {
position: absolute;
right: 3px;
top: 2px;
display: block;
padding: 1px 4px;
text-decoration: none;
font-size: 12px;
border-radius: 5px;
color: white;
border: 1px solid #014D8C; }
.close a:hover {
background-color: #014D8C;
border: 1px solid white; }
.resizer {
position: absolute;
width: 12px;
height: 12px;
bottom: -6px;
right: -6px;
cursor: se-resize; }
/* Special states */
.focused .title {
border-top: 1px solid #6262FF;
border-right: 1px solid #6262FF;
border-left: 1px solid #6262FF;
background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, #0057b3), color-stop(1, #0099ff));
background-image: -moz-linear-gradient(center bottom, #0057b3 0%, #0099ff 100%);
filter: alpha(opacity=85);
opacity: 0.85; }
.dragged .title {
-webkit-box-shadow: none;
-moz-box-shadow: none;
box-shadow: none;
background-color: #0070D5;
background-image: none; }
.dragged .outer {
-webkit-box-shadow: none;
-moz-box-shadow: none;
box-shadow: none;
background: none; }
.dragged .inner {
visibility: hidden; }

@ -0,0 +1 @@
<link rel="import" href="/bower_components/polymer/polymer.html"/><link rel="import" href="/elements/router.html"/><polymer-element name="openng-window" constructor="ngWindow"><template><link rel="stylesheet" href="window.css"/><div id="polymerWrapper"><template if="{{visible}}"><div style="width: {{width}}px; height: {{height}}px; left: {{x}}px; top: {{y}}px; z-index: {{z}};" class="wrapper {{ {focused: focused, dragged: dragged} | tokenList }}"><div class="title"><div class="title-inner">{{ windowTitle }}</div><div class="close"><a href="#">X</a></div></div><div class="outer"><div class="inner-wrapper"><div class="inner"><!-- View goes here--><openng-router url="{{url}}" external-handler="{{_externalHandler}}"></openng-router></div></div><template if="{{resizable}}"><div class="resizer"></div></template></div></div></template></div></template><script src="window.js"></script></polymer-element>

@ -0,0 +1,284 @@
/******/ (function(modules) { // webpackBootstrap
/******/ // The module cache
/******/ var installedModules = {};
/******/
/******/ // The require function
/******/ function __webpack_require__(moduleId) {
/******/
/******/ // Check if module is in cache
/******/ if(installedModules[moduleId])
/******/ return installedModules[moduleId].exports;
/******/
/******/ // Create a new module (and put it into the cache)
/******/ var module = installedModules[moduleId] = {
/******/ exports: {},
/******/ id: moduleId,
/******/ loaded: false
/******/ };
/******/
/******/ // Execute the module function
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/
/******/ // Flag the module as loaded
/******/ module.loaded = true;
/******/
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }
/******/
/******/
/******/ // expose the modules object (__webpack_modules__)
/******/ __webpack_require__.m = modules;
/******/
/******/ // expose the module cache
/******/ __webpack_require__.c = installedModules;
/******/
/******/ // __webpack_public_path__
/******/ __webpack_require__.p = "";
/******/
/******/ // Load entry module and return exports
/******/ return __webpack_require__(0);
/******/ })
/************************************************************************/
/******/ ([
/* 0 */
/***/ function(module, exports, __webpack_require__) {
module.exports = __webpack_require__(4);
/***/ },
/* 1 */,
/* 2 */,
/* 3 */,
/* 4 */
/***/ function(module, exports, __webpack_require__) {
var RateLimitedCall, polymerDefer;
RateLimitedCall = __webpack_require__(5);
polymerDefer = __webpack_require__(6);
Polymer("openng-window", {
publish: {
windowTitle: "",
url: "",
x: 200,
y: 200,
z: 0,
width: 400,
height: 300,
resizable: true,
visible: true,
focused: false,
dragged: false,
focus: function() {
return polymerDefer((function(_this) {
return function() {
return _this._manager.focus(_this);
};
})(this));
}
},
_externalHandler: function(url, method, options) {
var blankWindow;
blankWindow = new ngWindow();
blankWindow.url = url;
return $(blankWindow).insertAfter($(this));
},
_findWindowManager: function() {
var result;
result = $(this).closest("openng-window-manager");
if (result.length > 0) {
return result[0];
} else {
return void 0;
}
},
_register: function() {
this._manager = this._findWindowManager();
if (this._manager != null) {
return polymerDefer((function(_this) {
return function() {
return _this._manager.add(_this);
};
})(this));
}
},
_unregister: function() {
if (this._manager != null) {
return this._manager.remove(this);
}
},
_hookMoveEvents: function() {
var moveCall, self;
self = this;
moveCall = new RateLimitedCall(60, function() {
self.x = this.x - self.dragOffsetX;
return self.y = this.y - self.dragOffsetY;
});
return this._shadowDOM.find(".title").on("mousedown", (function(_this) {
return function(event) {
var moveHandler;
$("body").attr("unselectable", "on").css("user-select", "none").on("selectstart.disableSelect", false);
_this.dragOffsetX = event.pageX - _this.x;
_this.dragOffsetY = event.pageY - _this.y;
moveHandler = function(event) {
return moveCall.call(function() {
this.x = event.pageX;
return this.y = event.pageY;
});
};
_this.dragged = true;
$(document).on("mousemove", moveHandler);
return $(document).one("mouseup", function(event) {
_this.dragged = false;
$(document).off("mousemove", moveHandler);
return $("body").attr("unselectable", "off").css("user-select", "text").off("selectstart.disableSelect");
});
};
})(this));
},
_hookResizeEvents: function() {
var resizeCall, self;
self = this;
resizeCall = new RateLimitedCall(60, function() {
self.width = this.x - self.resizeOffsetX - self.x;
return self.height = this.y - self.resizeOffsetY - self.y;
});
return this._shadowDOM.find(".resizer").on("mousedown", (function(_this) {
return function(event) {
var resizeHandler;
$("body").attr("unselectable", "on").css("user-select", "none").on("selectstart.disableSelect", false);
_this.resizeOffsetX = (event.pageX - _this.x) - _this.width;
_this.resizeOffsetY = (event.pageY - _this.y) - _this.height;
resizeHandler = function(event) {
return resizeCall.call(function() {
this.x = event.pageX;
return this.y = event.pageY;
});
};
_this.dragged = true;
$(document).on("mousemove", resizeHandler);
return $(document).one("mouseup", function(event) {
_this.dragged = false;
$(document).off("mousemove", resizeHandler);
return $("body").attr("unselectable", "off").css("user-select", "text").off("selectstart.disableSelect");
});
};
})(this));
},
_hookCloseButton: function() {
return this._shadowDOM.find(".close a").on("mousedown", function(event) {
return event.stopPropagation();
}).on("click", (function(_this) {
return function(event) {
return $(_this).remove();
};
})(this));
},
_hookFocus: function() {
return this._shadowDOM.find(".wrapper").on("mousedown", (function(_this) {
return function(event) {
return _this.focus();
};
})(this));
},
ready: function() {
this._externalHandler = this._externalHandler.bind(this);
return this._shadowDOM = $(this.$.polymerWrapper);
},
domReady: function() {
this._hookMoveEvents();
this._hookResizeEvents();
this._hookCloseButton();
this._hookFocus();
this._register();
return this.focus();
},
detached: function() {
return this._unregister();
},
urlChanged: function(oldValue, newValue) {
if (newValue !== "") {
return this._shadowDOM.find("openng-router")[0].navigate(newValue);
}
}
});
/***/ },
/* 5 */
/***/ function(module, exports, __webpack_require__) {
var RateLimitedCall;
module.exports = RateLimitedCall = (function() {
RateLimitedCall.prototype.loopRunning = false;
RateLimitedCall.prototype._lastFrame = Date.now();
function RateLimitedCall(fps, frameHandler) {
this.fps = fps;
this.frameHandler = frameHandler;
this._interval = 1000 / this.fps;
}
RateLimitedCall.prototype._loop = function() {
this.loopRunning = true;
return this._frame();
};
RateLimitedCall.prototype._frame = function() {
var delta, now;
now = Date.now();
delta = now - this._lastFrame;
if (delta > this._interval) {
if (this.callActivated) {
this.frameHandler.apply(this);
this.callActivated = false;
this._lastFrame = now - (delta % this._interval);
} else {
this.loopRunning = false;
}
}
if (this.loopRunning) {
return requestAnimationFrame(this._frame.bind(this));
}
};
RateLimitedCall.prototype._activateRateLimitedCall = function() {
this.callActivated = true;
if (!this.loopRunning) {
return this._loop();
}
};
RateLimitedCall.prototype.call = function(func) {
func.apply(this);
return this._activateRateLimitedCall();
};
return RateLimitedCall;
})();
/***/ },
/* 6 */
/***/ function(module, exports, __webpack_require__) {
module.exports = function(func) {
if (window.polymerReady) {
return func();
} else {
return $(window).on("polymer-ready", function(event) {
return func();
});
}
};
/***/ }
/******/ ])

@ -44,15 +44,83 @@
/* 0 */
/***/ function(module, exports, __webpack_require__) {
var OverlayDrawer, RateLimitedCall;
/* WEBPACK VAR INJECTION */(function(global) {var $, OverlayDrawer, RateLimitedCall;
OverlayDrawer = __webpack_require__(1);
global.$ = $ = __webpack_require__(3);
RateLimitedCall = __webpack_require__(2);
OverlayDrawer = __webpack_require__(2);
RateLimitedCall = __webpack_require__(1);
$(function() {
var overlayDrawer;
overlayDrawer = new OverlayDrawer($("canvas.overlay"));
return $(window).on("polymer-ready", function(event) {
return window.polymerReady = true;
});
});
/* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }())))
/***/ },
/* 1 */
/***/ function(module, exports, __webpack_require__) {
var RateLimitedCall;
module.exports = RateLimitedCall = (function() {
RateLimitedCall.prototype.loopRunning = false;
RateLimitedCall.prototype._lastFrame = Date.now();
function RateLimitedCall(fps, frameHandler) {
this.fps = fps;
this.frameHandler = frameHandler;
this._interval = 1000 / this.fps;
}
RateLimitedCall.prototype._loop = function() {
this.loopRunning = true;
return this._frame();
};
RateLimitedCall.prototype._frame = function() {
var delta, now;
now = Date.now();
delta = now - this._lastFrame;
if (delta > this._interval) {
if (this.callActivated) {
this.frameHandler.apply(this);
this.callActivated = false;
this._lastFrame = now - (delta % this._interval);
} else {
this.loopRunning = false;
}
}
if (this.loopRunning) {
return requestAnimationFrame(this._frame.bind(this));
}
};
RateLimitedCall.prototype._activateRateLimitedCall = function() {
this.callActivated = true;
if (!this.loopRunning) {
return this._loop();
}
};
RateLimitedCall.prototype.call = function(func) {
func.apply(this);
return this._activateRateLimitedCall();
};
return RateLimitedCall;
})();
/***/ },
/* 2 */
/***/ function(module, exports, __webpack_require__) {
var $, OverlayDrawer, OverlayLine,
@ -114,25 +182,27 @@
return window.requestAnimationFrame(this._drawFrame);
};
function OverlayDrawer($canvas) {
function OverlayDrawer(canvas) {
this.createLine = bind(this.createLine, this);
this.removeObject = bind(this.removeObject, this);
this._triggerDraw = bind(this._triggerDraw, this);
this._drawFrame = bind(this._drawFrame, this);
var $window, resizeHandler, self;
self = this;
this._targetCanvas = $canvas;
$canvas.css({
var resizeHandler;
this._targetCanvas = canvas;
canvas.css({
position: "absolute",
top: "0px",
left: "0px",
"z-index": "999999999",
"pointer-events": "none"
});
resizeHandler = function() {
return self._pendingWindowResize = [$window.width(), $window.height()];
};
$window = $(window).on("resize", resizeHandler);
resizeHandler = (function(_this) {
return function() {
_this._pendingWindowResize = [$(window).width(), $(window).height()];
return _this._triggerDraw();
};
})(this);
$(window).on("resize", resizeHandler);
resizeHandler();
}
@ -209,63 +279,6 @@
module.exports = OverlayDrawer;
/***/ },
/* 2 */
/***/ function(module, exports, __webpack_require__) {
var RateLimitedCall;
module.exports = RateLimitedCall = (function() {
RateLimitedCall.prototype.loopRunning = false;
RateLimitedCall.prototype._lastFrame = Date.now();
function RateLimitedCall(fps, frameHandler) {
this.fps = fps;
this.frameHandler = frameHandler;
this._interval = 1000 / this.fps;
}
RateLimitedCall.prototype._loop = function() {
this.loopRunning = true;
return this._frame();
};
RateLimitedCall.prototype._frame = function() {
var delta, now;
now = Date.now();
delta = now - this._lastFrame;
if (delta > this._interval) {
if (this.callActivated) {
this.frameHandler.apply(this);
this.callActivated = false;
this._lastFrame = now - (delta % this._interval);
} else {
this.loopRunning = false;
}
}
if (this.loopRunning) {
return requestAnimationFrame(this._frame.bind(this));
}
};
RateLimitedCall.prototype._activateRateLimitedCall = function() {
this.callActivated = true;
if (!this.loopRunning) {
return this._loop();
}
};
RateLimitedCall.prototype.call = function(func) {
func.apply(this);
return this._activateRateLimitedCall();
};
return RateLimitedCall;
})();
/***/ },
/* 3 */
/***/ function(module, exports, __webpack_require__) {

@ -6,4 +6,10 @@ router.get "/", (req, res) ->
router.get "/node/:uuid", (req, res) ->
res.json {"uuid": req.params.uuid}
router.get "/test1", (req, res) ->
res.send "test ONE <a href='/test2'>go to 2 instead</a> <a href='/test2' target='_blank'>or in a new window</a>"
router.get "/test2", (req, res) ->
res.send "test TWO <a href='/test1'>go to 1 instead</a> <a href='/test1' target='_blank'>or in a new window</a>"
module.exports = router

@ -0,0 +1,6 @@
router = require("express-promise-router")()
router.get "/create", (req, res) ->
res.render "nodes/create"
module.exports = router

@ -1,2 +1,10 @@
global.$ = $ = require "jquery"
OverlayDrawer = require "./lib/OverlayDrawer"
RateLimitedCall = require "./lib/RateLimitedCall"
$ ->
overlayDrawer = new OverlayDrawer($ "canvas.overlay")
$(window).on "polymer-ready", (event) ->
# This is for polymer-defer calls.
window.polymerReady = true

@ -45,21 +45,21 @@ class OverlayDrawer
window.requestAnimationFrame @_drawFrame
_triggerDraw: =>
window.requestAnimationFrame @_drawFrame
constructor: ($canvas) ->
self = this # Duct-tape to make the resize event work correctly
@_targetCanvas = $canvas
constructor: (canvas) ->
@_targetCanvas = canvas
$canvas.css
canvas.css
position: "absolute"
top: "0px"
left: "0px"
"z-index": "999999999"
"pointer-events": "none"
resizeHandler = ->
self._pendingWindowResize = [$window.width(), $window.height()]
resizeHandler = =>
@_pendingWindowResize = [$(window).width(), $(window).height()]
@_triggerDraw()
$window = $ window
$ window
.on "resize", resizeHandler
# Do an initial resize to make our canvas stretch across the screen

@ -0,0 +1,6 @@
module.exports = (func) ->
if window.polymerReady
func()
else
$(window).on "polymer-ready", (event) ->
func()

@ -0,0 +1,25 @@
mixin pmImport(name)
link(rel="import", href="/bower_components/#{name}/#{name}.html")
mixin pmImportPath(path)
link(rel="import", href="#{path}.html")
mixin pmStylesheet(name)
link(rel="stylesheet", href="#{name}.css")
mixin pmPureCSS
link(rel="stylesheet", href="/stylesheets/pure-min.css")
mixin pmFontAwesome
link(rel="stylesheet", href="/stylesheets/font-awesome.min.css")
mixin pmScript(name)
script(src="#{name}.js")
mixin pmIf(conditional)
template(if="{{#{conditional}}}")
block
mixin pmRepeat(collection)
template(repeat="{{#{collection}}}")
block

@ -0,0 +1,12 @@
include _polymer
+pmImport("polymer")
polymer-element(name="pn-button", constructor="pnButton", attributes="type icon label", noscript)
template
+pmStylesheet("button")
+pmPureCSS
+pmFontAwesome
button.pure-button(type="{{type}}")
i(class="fa fa-{{icon}}")
| {{label}}

@ -0,0 +1,10 @@
i
{
margin-right: 5px;
}
button[type="submit"]
{
background-color: #148C29;
color: white;
}

@ -0,0 +1 @@
Polymer "pn-frame", {}

@ -0,0 +1,12 @@
include _polymer
+pmImport("polymer")
polymer-element(name="pn-frame", constructor="pnFrame")
template
+pmStylesheet("frame")
#polymerWrapper
content.docks(select="pn-toolbar")
content.main
+pmScript("frame")

@ -0,0 +1,4 @@
contents.main
{
overflow: auto;
}

@ -0,0 +1,34 @@
__ = require "lodash"
Polymer "openng-router",
_lastNavigatedURL: ""
_lastNavigatedMethod: ""
publish:
url: ""
'external-handler': null
navigate: (url, method = "GET", options = {}) ->
if url == ""
return
options.type ?= method
$.ajax url, options
.done (data, textStatus, xhr) =>
$(this).html(data)
ready: ->
self = this
$(this)
.on "click", "a", (event) ->
event.preventDefault()
url = $(this).attr("href")
if $(this).attr("target") == "_blank" and self['external-handler']?
self['external-handler'](url)
else
self.navigate url
@navigate(@url)
urlChanged: (oldValue, newValue) ->
console.log "URL CHANGED", this.url, oldValue, newValue

@ -0,0 +1,6 @@
include _polymer
+pmImport("polymer")
polymer-element(name="openng-router", constructor="ngRouter")
+pmScript("router")

@ -1 +0,0 @@
div Hi! Gah!

@ -0,0 +1,8 @@
include _polymer
+pmImport("polymer")
polymer-element(name="pn-toolbar", constructor="pnToolbar", attributes="dock align width height", noscript)
template
+pmStylesheet("toolbar")
content(class="dock-{{dock}} align-{{align}}")

@ -0,0 +1,24 @@
__ = require "lodash"
Polymer "openng-window-manager",
_currentFocus: null
_currentZ: 1000
_windows: []
_unfocusAll: ->
for window in @_windows
window.focused = false
publish:
add: (window) ->
@_windows.push window
remove: (window) ->
@_windows = __(@_windows)
.without window
.value()
focus: (window) ->
if not window.focused
@_unfocusAll()
@_currentFocus = window
window.focused = true
window.z = (@_currentZ++)
ready: ->
#

@ -0,0 +1,6 @@
include _polymer
+pmImport("polymer")
polymer-element(name="openng-window-manager", constructor="ngWindowManager")
+pmScript("window-manager")

@ -0,0 +1,166 @@
RateLimitedCall = require "../coffee/lib/RateLimitedCall"
polymerDefer = require "../coffee/lib/polymer-defer"
Polymer "openng-window",
publish:
windowTitle: ""
url: ""
x: 200
y: 200
z: 0
width: 400
height: 300
resizable: true
visible: true
focused: false
dragged: false
focus: ->
polymerDefer =>
@_manager.focus(this)
_externalHandler: (url, method, options) ->
# FIXME: Do something with 'method' and 'options'?
blankWindow = new ngWindow()
blankWindow.url = url
$(blankWindow).insertAfter($(this))
_findWindowManager: ->
result = $(this).closest("openng-window-manager")
if result.length > 0
return result[0]
else
return undefined
_register: ->
@_manager = @_findWindowManager()
if @_manager?
polymerDefer =>
@_manager.add this
_unregister: ->
if @_manager?
@_manager.remove this
_hookMoveEvents: ->
self = this
moveCall = new RateLimitedCall 60, ->
self.x = @x - self.dragOffsetX
self.y = @y - self.dragOffsetY
@_shadowDOM
.find ".title"
.on "mousedown", (event) =>
# Disable text selection application-wide to prevent accidental selection while dragging
# FIXME: Are there more performant options for this?
# FIXME: Currently bugs out in Chrome on <input> - will select contents of those anyway.
$("body")
.attr "unselectable", "on"
.css "user-select", "none"
.on "selectstart.disableSelect", false
# Record drag offset (ie. coordinates of mouse relative to the top-left corner of the window)
@dragOffsetX = event.pageX - @x
@dragOffsetY = event.pageY - @y
# Actual window movement
moveHandler = (event) =>
moveCall.call ->
@x = event.pageX
@y = event.pageY
@dragged = true
$(document).on "mousemove", moveHandler
# Release-drag handling...
$(document).one "mouseup", (event) =>
# Disable dragging mode
@dragged = false
$(document).off "mousemove", moveHandler
# Re-enable text selection
$("body")
.attr "unselectable", "off"
.css "user-select", "text"
.off "selectstart.disableSelect"
_hookResizeEvents: ->
self = this
resizeCall = new RateLimitedCall 60, ->
self.width = @x - self.resizeOffsetX - self.x
self.height = @y - self.resizeOffsetY - self.y
@_shadowDOM
.find ".resizer"
.on "mousedown", (event) =>
# Disable text selection application-wide to prevent accidental selection while dragging
# FIXME: Are there more performant options for this?
# FIXME: Currently bugs out in Chrome on <input> - will select contents of those anyway.
$("body")
.attr "unselectable", "on"
.css "user-select", "none"
.on "selectstart.disableSelect", false
# Record drag offset (ie. coordinates of mouse relative to the top-left corner of the window)
@resizeOffsetX = (event.pageX - @x) - @width
@resizeOffsetY = (event.pageY - @y) - @height
# Actual window resizing
resizeHandler = (event) =>
resizeCall.call ->
@x = event.pageX
@y = event.pageY
@dragged = true
$(document).on "mousemove", resizeHandler
# Release-drag handling...
$(document).one "mouseup", (event) =>
# Disable dragging mode
@dragged = false
$(document).off "mousemove", resizeHandler
# Re-enable text selection
$("body")
.attr "unselectable", "off"
.css "user-select", "text"
.off "selectstart.disableSelect"
_hookCloseButton: ->
@_shadowDOM
.find ".close a"
.on "mousedown", (event) -> event.stopPropagation()
.on "click", (event) =>
$(this).remove()
_hookFocus: ->
@_shadowDOM
.find ".wrapper"
.on "mousedown", (event) =>
@focus()
ready: ->
@_externalHandler = @_externalHandler.bind(this)
@_shadowDOM = $(@$.polymerWrapper)
domReady: ->
@_hookMoveEvents()
@_hookResizeEvents()
@_hookCloseButton()
@_hookFocus()
@_register()
@focus()
detached: ->
@_unregister()
urlChanged: (oldValue, newValue) ->
if newValue != ""
@_shadowDOM
.find("openng-router")[0]
.navigate newValue

@ -0,0 +1,23 @@
include _polymer
+pmImport("polymer")
+pmImportPath("/elements/router")
polymer-element(name="openng-window", constructor="ngWindow")
template
+pmStylesheet("window")
#polymerWrapper
+pmIf("visible")
div(class="wrapper {{ {focused: focused, dragged: dragged} | tokenList }}", style="width: {{width}}px; height: {{height}}px; left: {{x}}px; top: {{y}}px; z-index: {{z}};")
.title
.title-inner {{ windowTitle }}
.close
a(href="#") X
.outer
.inner-wrapper
.inner
// View goes here
openng-router(url="{{url}}", external-handler="{{_externalHandler}}")
+pmIf("resizable")
.resizer
+pmScript("window")

@ -0,0 +1,181 @@
.noscroll
{
overflow-x: hidden !important;
overflow-y: hidden !important;
}
/* Common styling */
.wrapper
{
position: absolute;
}
@mixin shadow
{
-webkit-box-shadow: 5px 5px 10px #1a1a1a;
-moz-box-shadow: 5px 5px 10px #1a1a1a;
box-shadow: 5px 5px 10px #1a1a1a;
}
.title
{
@include shadow;
position: absolute;
z-index: 2;
left: 0px;
right: 0px;
top: 0px;
cursor: default;
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
border-top-left-radius: 10px;
border-top-right-radius: 10px;
height: 16px;
color: white;
font-size: 14px;
font-weight: bold;
padding: 4px;
padding-left: 7px;
border-top: 1px solid #959595;
border-right: 1px solid #959595;
border-left: 1px solid #959595;
background-image: -webkit-gradient(
linear,
left bottom,
left top,
color-stop(0, rgb(82,82,82)),
color-stop(1, rgb(145,172,190))
);
background-image: -moz-linear-gradient(
center bottom,
rgb(82,82,82) 0%,
rgb(145,172,190) 100%
);
filter:alpha(opacity=95);
opacity:0.95;
}
.outer
{
@include shadow;
position: absolute;
z-index: 3;
left: 0px;
right: 0px;
bottom: 0px;
font-size: 13px;
top: 25px;
border-bottom: 1px solid gray;
border-right: 1px solid gray;
border-left: 1px solid gray;
background-color: #F7F7F0;
filter:alpha(opacity=95);
opacity:0.95;
}
.inner-wrapper
{
position: absolute;
top: 0px;
bottom: 0px;
left: 0px;
right: 0px;
overflow-y: auto;
overflow-x: auto;
}
.inner
{
padding: 7px;
}
.close
{
float: right;
a
{
position: absolute;
right: 3px;
top: 2px;
display: block;
padding: 1px 4px;
text-decoration: none;
font-size: 12px;
border-radius: 5px;
color: white;
border: 1px solid #014D8C;
&:hover
{
background-color: #014D8C;
border: 1px solid white;
}
}
}
.resizer
{
position: absolute;
width: 12px;
height: 12px;
bottom: -6px;
right: -6px;
cursor: se-resize;
}
/* Special states */
.focused
{
.title
{
border-top: 1px solid #6262FF;
border-right: 1px solid #6262FF;
border-left: 1px solid #6262FF;
background-image: -webkit-gradient(
linear,
left bottom,
left top,
color-stop(0, rgb(0,87,179)),
color-stop(1, rgb(0,153,255))
);
background-image: -moz-linear-gradient(
center bottom,
rgb(0,87,179) 0%,
rgb(0,153,255) 100%
);
filter:alpha(opacity=85);
opacity:0.85;
}
}
@mixin noShadow
{
-webkit-box-shadow: none;
-moz-box-shadow: none;
box-shadow: none;
}
.dragged
{
.title
{
@include noShadow;
background-color: #0070D5;
background-image: none;
}
.outer
{
@include noShadow;
background: none;
}
.inner
{
visibility: hidden;
}
}

@ -1,5 +1,7 @@
include ../src/elements/_polymer
doctype html
html(ng-app="cryto.openng")
html
head
title OpenNG
link(rel='stylesheet', href='/stylesheets/pure-min.css')
@ -7,7 +9,12 @@ html(ng-app="cryto.openng")
link(rel='stylesheet', href='/stylesheets/font-awesome.min.css')
link(rel='stylesheet', href='/stylesheets/openng.css')
link(rel='stylesheet', href='http://fonts.googleapis.com/css?family=Istok+Web:400,700|Open+Sans:400,700|Varela+Round')
script(src="/js/bundled.js")
script(src="/bower_components/webcomponentsjs/webcomponents.min.js")
script(src="/js/bundle.js")
+pmImportPath("/elements/window")
+pmImportPath("/elements/window-manager")
+pmImportPath("/elements/frame")
+pmImportPath("/elements/button")
body(ng-controller="appController")
canvas.overlay
#mainToolbar
@ -20,4 +27,5 @@ html(ng-app="cryto.openng")
i.fa.fa-search
| Search
#logo OpenNG
window(ng-repeat="window in windows", title="{{window.data.title}}", start-x="{{window.data.x}}", start-y="{{window.data.y}}", width="{{window.data.width}}", height="{{window.data.height}}", resizable="{{window.data.resizable}}", initial-route="{{window.data.initialRoute}}")
openng-window-manager
openng-window(x=150, y=150, url="/nodes/create")

@ -0,0 +1,15 @@
title Create new node
form(method="post", action="/nodes/create")
pn-frame
pn-toolbar(dock="bottom", align="right")
pn-button(type="submit", label="Create", icon="check")
pn-form-section
pn-input(name="name", label="Name")
pn-autocomplete(name="type", label="Type")
pn-textarea(name="notes", label="Notes")
pn-form-section(name="Properties")
pn-input-spawner
pn-autocomplete.grouped(name="key[]", placeholder="Name")
pn-autocomplete.grouped(name="value[]", placeholder="Value")
Loading…
Cancel
Save