First tech demo
parent
b50db6394e
commit
7a2a3d89d8
@ -0,0 +1,36 @@
|
|||||||
|
# authored
|
||||||
|
|
||||||
|
A modular framework for building authoring tools.
|
||||||
|
|
||||||
|
Originally developed for [Adivix](https://github.com/Adivix), but usable for any kind of (2D) authoring tool project.
|
||||||
|
|
||||||
|
## Demo
|
||||||
|
|
||||||
|
[Here.](http://cryto.net/~joepie91/authored-test/test/test.html) No performance optimizations carried out yet, and very rough around the edges still, so Chrome is probably a better choice.
|
||||||
|
|
||||||
|
## Current state
|
||||||
|
|
||||||
|
__Not__ production-ready. Still under development. The plugins will eventually be put into their own repository.
|
||||||
|
|
||||||
|
## Plugins
|
||||||
|
|
||||||
|
* Core (stage, scenes, objects - not actually a plugin)
|
||||||
|
* Layers
|
||||||
|
* Object type - text
|
||||||
|
* Object type - image
|
||||||
|
|
||||||
|
## UI plugins
|
||||||
|
|
||||||
|
* Scene panel
|
||||||
|
* Layer panel
|
||||||
|
* Object panel
|
||||||
|
* Properties panel
|
||||||
|
* HTML renderer
|
||||||
|
|
||||||
|
## Utilities
|
||||||
|
|
||||||
|
* `dom-wait`; queues a function call for when the DOM has loaded, where necessary.
|
||||||
|
* `apply-property-map`; utility for mapping values to DOM element properties.
|
||||||
|
* `split-filter`; like `.filter`, but returns both a matching and non-matching array.
|
||||||
|
* `distance-from`; calculates direct distance between two points, used for the drag threshold in the HTML renderer.
|
||||||
|
|
@ -0,0 +1,6 @@
|
|||||||
|
#!/usr/bin/env node
|
||||||
|
|
||||||
|
st = require("st");
|
||||||
|
http = require("http");
|
||||||
|
|
||||||
|
http.createServer(st({path: process.cwd(), cache: false})).listen(5555)
|
@ -0,0 +1,146 @@
|
|||||||
|
var gulp = require('gulp');
|
||||||
|
|
||||||
|
/* CoffeeScript compile deps */
|
||||||
|
var path = require('path');
|
||||||
|
var rename = require('gulp-rename');
|
||||||
|
var livereload = require('gulp-livereload');
|
||||||
|
var webpack = require("gulp-webpack");
|
||||||
|
var sass = require("gulp-sass");
|
||||||
|
var gutil = require('gulp-util');
|
||||||
|
var cache = require('gulp-cached');
|
||||||
|
var remember = require('gulp-remember');
|
||||||
|
var plumber = require('gulp-plumber');
|
||||||
|
var nodemon = require("gulp-nodemon");
|
||||||
|
var jade = require("gulp-jade");
|
||||||
|
var net = require("net");
|
||||||
|
var spy = require("through2-spy");
|
||||||
|
|
||||||
|
|
||||||
|
function namedLog(name) {
|
||||||
|
return function gutilLog(log) {
|
||||||
|
gc = gutil.colors;
|
||||||
|
|
||||||
|
items = ["[- " + gc.magenta(name) + " -]"];
|
||||||
|
|
||||||
|
for(i in arguments) {
|
||||||
|
items.push(arguments[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
gutil.log.apply(null, items);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks = {
|
||||||
|
jade: [
|
||||||
|
{
|
||||||
|
name: "test",
|
||||||
|
source: ["./test/test.jade"],
|
||||||
|
base: "./test/",
|
||||||
|
destination: "./test/"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
sass: [
|
||||||
|
{
|
||||||
|
name: "test",
|
||||||
|
source: ["./test/style.scss"],
|
||||||
|
base: "./test/",
|
||||||
|
destination: "./test/"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
function concatName(type, name) {
|
||||||
|
return type + "-" + name;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var type in tasks) {
|
||||||
|
var subTasks = tasks[type];
|
||||||
|
|
||||||
|
for (var i in subTasks) {
|
||||||
|
var subTask = subTasks[i];
|
||||||
|
|
||||||
|
(function(type, subTask) {
|
||||||
|
var taskName = concatName(type, subTask.name);
|
||||||
|
|
||||||
|
gulp.task(taskName, function() {
|
||||||
|
var processor;
|
||||||
|
|
||||||
|
switch(type) {
|
||||||
|
case "jade":
|
||||||
|
processor = jade(/*{locals: require("./templateUtil")}*/);
|
||||||
|
break;
|
||||||
|
case "sass":
|
||||||
|
processor = sass();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return gulp.src(subTask.source, {base: subTask.base})
|
||||||
|
.pipe(plumber())
|
||||||
|
.pipe(cache(taskName))
|
||||||
|
.pipe(processor.on('error', gutil.log))
|
||||||
|
.pipe(spy.obj(namedLog(taskName)))
|
||||||
|
.pipe(remember(taskName))
|
||||||
|
.pipe(gulp.dest(subTask.destination));
|
||||||
|
});
|
||||||
|
})(type, subTask);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function checkServerUp(){
|
||||||
|
setTimeout(function(){
|
||||||
|
var sock = new net.Socket();
|
||||||
|
sock.setTimeout(50);
|
||||||
|
sock.on("connect", function(){
|
||||||
|
console.log("Triggering page reload...");
|
||||||
|
livereload.changed("*");
|
||||||
|
sock.destroy();
|
||||||
|
})
|
||||||
|
.on("timeout", checkServerUp)
|
||||||
|
.on("error", checkServerUp)
|
||||||
|
.connect(5555);
|
||||||
|
}, 70);
|
||||||
|
}
|
||||||
|
|
||||||
|
var startupTasks = [];
|
||||||
|
var watchTasks = [];
|
||||||
|
|
||||||
|
for (var type in tasks) {
|
||||||
|
var subTasks = tasks[type];
|
||||||
|
|
||||||
|
for (var i in subTasks) {
|
||||||
|
var subTask = subTasks[i];
|
||||||
|
var taskName = concatName(type, subTask.name);
|
||||||
|
startupTasks.push(taskName);
|
||||||
|
watchTasks.push([subTask, taskName]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
gulp.task('webpack', function(){
|
||||||
|
return gulp.src("./test/test.js")
|
||||||
|
.pipe(webpack({
|
||||||
|
watch: true,
|
||||||
|
module: {
|
||||||
|
loaders: [{ test: /\.coffee$/, loader: "coffee-loader" }]
|
||||||
|
},
|
||||||
|
resolve: { extensions: ["", ".web.coffee", ".web.js", ".coffee", ".js"] }
|
||||||
|
}))
|
||||||
|
.pipe(rename("test-bundle.js"))
|
||||||
|
.pipe(gulp.dest("./test/"));
|
||||||
|
});
|
||||||
|
|
||||||
|
gulp.task('watch', function () {
|
||||||
|
global.isWatching = true;
|
||||||
|
livereload.listen();
|
||||||
|
gulp.watch(['./test/*.js', './test/*.html', './test/*.css']).on('change', livereload.changed);
|
||||||
|
|
||||||
|
for (i in watchTasks) {
|
||||||
|
task = watchTasks[i];
|
||||||
|
gulp.watch(task[0].source, [task[1]]);
|
||||||
|
}
|
||||||
|
|
||||||
|
nodemon({script: "./bin/www", ext: "js", delay: 500}).on("start", checkServerUp);
|
||||||
|
});
|
||||||
|
|
||||||
|
startupTasks.push("webpack", "watch");
|
||||||
|
|
||||||
|
gulp.task('default', startupTasks);
|
@ -0,0 +1 @@
|
|||||||
|
module.exports = require "./lib"
|
@ -0,0 +1,11 @@
|
|||||||
|
module.exports = (map, object, domElement) ->
|
||||||
|
Object.keys(map).forEach (key) ->
|
||||||
|
if typeof map[key] == "function"
|
||||||
|
valueFunc = map[key]
|
||||||
|
|
||||||
|
object.on "changed:#{key}", (val) ->
|
||||||
|
[targetName, actualValue] = valueFunc(val)
|
||||||
|
domElement.css targetName, actualValue
|
||||||
|
else
|
||||||
|
object.on "changed:#{key}", (val) ->
|
||||||
|
domElement.css map[key], val
|
@ -0,0 +1,5 @@
|
|||||||
|
module.exports = (x1, y1, x2, y2) ->
|
||||||
|
deltaX = Math.abs(x2 - x1)
|
||||||
|
deltaY = Math.abs(y2 - y1)
|
||||||
|
|
||||||
|
return Math.sqrt((deltaX ** 2) + (deltaY ** 2))
|
@ -0,0 +1,31 @@
|
|||||||
|
$ = require "jquery"
|
||||||
|
|
||||||
|
domInitialized = false
|
||||||
|
queue = []
|
||||||
|
|
||||||
|
$ ->
|
||||||
|
domInitialized = true
|
||||||
|
|
||||||
|
queue.forEach ([thisArg, func, args]) ->
|
||||||
|
console.log args
|
||||||
|
func.apply(thisArg, args)
|
||||||
|
|
||||||
|
queue = []
|
||||||
|
|
||||||
|
domWait = (thisArg, func, args) ->
|
||||||
|
if domInitialized
|
||||||
|
func.apply(thisArg, args)
|
||||||
|
else
|
||||||
|
queue.push [thisArg, func, args]
|
||||||
|
|
||||||
|
domWait.func = (func) ->
|
||||||
|
return ->
|
||||||
|
args = []
|
||||||
|
|
||||||
|
# This is needed to avoid killing the optimizer.
|
||||||
|
for i in [0...arguments.length]
|
||||||
|
args[i] = arguments[i]
|
||||||
|
|
||||||
|
domWait(this, func, args)
|
||||||
|
|
||||||
|
module.exports = domWait
|
@ -0,0 +1,102 @@
|
|||||||
|
$ = require "jquery"
|
||||||
|
applyPropertyMap = require "./apply-property-map"
|
||||||
|
distanceFrom = require "./distance-from"
|
||||||
|
|
||||||
|
moveThreshold = 5
|
||||||
|
|
||||||
|
textPropertyMap =
|
||||||
|
fontFamily: "fontFamily"
|
||||||
|
fontSize: (val) -> ["fontSize", "#{val}px"]
|
||||||
|
fontColor: "color"
|
||||||
|
bold: (val) -> console.log("bold", val); ["fontWeight", (if val then "bold" else "normal")]
|
||||||
|
italic: (val) -> ["fontStyle", (if val then "italic" else "normal")]
|
||||||
|
|
||||||
|
attachRenderer = (jqObject) ->
|
||||||
|
renderer =
|
||||||
|
stage: this
|
||||||
|
jqObject: jqObject
|
||||||
|
|
||||||
|
console.log renderer.stage
|
||||||
|
|
||||||
|
renderer.stage.on "scene:added", (scene) ->
|
||||||
|
scene.on "object:created", (object) ->
|
||||||
|
if object.type == "text"
|
||||||
|
domElement = $("<div></div>")
|
||||||
|
|
||||||
|
object.on "changed:text", (text) ->
|
||||||
|
domElement.text(text)
|
||||||
|
|
||||||
|
object.on "changed:html", (html) ->
|
||||||
|
domElement.html(html)
|
||||||
|
|
||||||
|
applyPropertyMap textPropertyMap, object, domElement
|
||||||
|
else if object.type == "image"
|
||||||
|
domElement = $("<img>")
|
||||||
|
|
||||||
|
object.on "changed:source", (source) ->
|
||||||
|
domElement.attr "src", source
|
||||||
|
|
||||||
|
domElement.appendTo jqObject
|
||||||
|
domElement.addClass "rendererObject"
|
||||||
|
domElement.data "uuid", object.uuid
|
||||||
|
domElement.data "scene-uuid", scene.uuid
|
||||||
|
|
||||||
|
object.domElement = domElement
|
||||||
|
|
||||||
|
domElement.on "mousedown", (event) ->
|
||||||
|
scene.setActiveObject(object.uuid)
|
||||||
|
event.preventDefault()
|
||||||
|
event.stopPropagation()
|
||||||
|
|
||||||
|
element = $(this)
|
||||||
|
|
||||||
|
dragging = false
|
||||||
|
startPosition = x: event.pageX, y: event.pageY
|
||||||
|
startOffset = x: (event.pageX - element.offset().left), y: (event.pageY - element.offset().top)
|
||||||
|
|
||||||
|
$(document).one "mouseup", (event) ->
|
||||||
|
$(document).off "mousemove.htmlRenderer"
|
||||||
|
|
||||||
|
$(document).on "mousemove.htmlRenderer", (event) ->
|
||||||
|
if distanceFrom(startPosition.x, startPosition.y, event.pageX, event.pageY) >= moveThreshold
|
||||||
|
dragging = true
|
||||||
|
|
||||||
|
if dragging
|
||||||
|
# FIXME: Set properties on the object instead
|
||||||
|
object.x = (event.pageX - startOffset.x)
|
||||||
|
object.y = (event.pageY - startOffset.y)
|
||||||
|
|
||||||
|
object.on "changed:x", (x) ->
|
||||||
|
domElement.offset left: x
|
||||||
|
|
||||||
|
object.on "changed:y", (y) ->
|
||||||
|
domElement.offset top: y
|
||||||
|
|
||||||
|
scene.on "object:switched", (object) ->
|
||||||
|
renderer.jqObject
|
||||||
|
.find ".rendererObject"
|
||||||
|
.removeClass "activated"
|
||||||
|
.filter (i, obj) -> ($(obj).data("uuid") == object.uuid)
|
||||||
|
.addClass "activated"
|
||||||
|
|
||||||
|
scene.on "object:removed", (object) ->
|
||||||
|
object.domElement.remove()
|
||||||
|
|
||||||
|
renderer.stage.on "scene:switched", (scene) ->
|
||||||
|
renderer.jqObject
|
||||||
|
.find ".rendererObject"
|
||||||
|
.hide()
|
||||||
|
.filter (i, obj) -> $(obj).data("scene-uuid") == scene.uuid
|
||||||
|
.show()
|
||||||
|
|
||||||
|
return renderer
|
||||||
|
|
||||||
|
API = (stage) ->
|
||||||
|
return {
|
||||||
|
attach: attachRenderer.bind(stage)
|
||||||
|
}
|
||||||
|
|
||||||
|
API.meta =
|
||||||
|
name: "htmlRenderer"
|
||||||
|
|
||||||
|
module.exports = API
|
@ -0,0 +1,186 @@
|
|||||||
|
uuid = require "uuid"
|
||||||
|
EventEmitter = require("events").EventEmitter
|
||||||
|
splitFilter = require "../lib/split-filter"
|
||||||
|
|
||||||
|
sceneNameIncrement = 1
|
||||||
|
objectNameIncrement = 1
|
||||||
|
|
||||||
|
class AuthoredObject extends EventEmitter
|
||||||
|
constructor: (@scene, options = {}) ->
|
||||||
|
@uuid = uuid.v4()
|
||||||
|
@_props = {}
|
||||||
|
@propMeta = {}
|
||||||
|
|
||||||
|
@registerInternalProperty "visible", true
|
||||||
|
@registerInternalProperty "editorVisible", true
|
||||||
|
@registerInternalProperty "editorFaded", false
|
||||||
|
|
||||||
|
if not options.name?
|
||||||
|
name = "Object #{objectNameIncrement++}"
|
||||||
|
else
|
||||||
|
name = options.name
|
||||||
|
|
||||||
|
@registerInternalProperty "name", name
|
||||||
|
@registerInternalProperty "type"
|
||||||
|
|
||||||
|
@registerProperty "x", type: "numeric"
|
||||||
|
@registerProperty "y", type: "numeric"
|
||||||
|
|
||||||
|
if options.type?
|
||||||
|
@type = options.type
|
||||||
|
|
||||||
|
registerInternalProperty: (propName, defaultValue) ->
|
||||||
|
@registerProperty(propName, null)
|
||||||
|
|
||||||
|
if defaultValue?
|
||||||
|
this[propName] = defaultValue
|
||||||
|
|
||||||
|
registerProperty: (propName, propMeta) ->
|
||||||
|
Object.defineProperty this, propName,
|
||||||
|
enumerable: true
|
||||||
|
get: => @_props[propName]
|
||||||
|
set: (value) =>
|
||||||
|
@_props[propName] = value
|
||||||
|
@emit "changed:#{propName}", @_props[propName], this
|
||||||
|
@emit "changed", propName, @_props[propName], this
|
||||||
|
|
||||||
|
# Explicitly allow specifying `null` for propMeta to avoid propMeta; this is used for internal properties.
|
||||||
|
if propMeta == undefined
|
||||||
|
@propMeta[propName] = {}
|
||||||
|
else if propMeta != null
|
||||||
|
@propMeta[propName] = propMeta
|
||||||
|
|
||||||
|
class AuthoredScene extends EventEmitter
|
||||||
|
constructor: (@stage, options = {}) ->
|
||||||
|
@uuid = uuid.v4()
|
||||||
|
@objects = {}
|
||||||
|
@orderedObjects = []
|
||||||
|
@activeObject = null
|
||||||
|
@_ignoredProperties = ["orderedObjects"]
|
||||||
|
|
||||||
|
if not options.name?
|
||||||
|
@name = "Scene #{sceneNameIncrement++}"
|
||||||
|
else
|
||||||
|
@name = options.name
|
||||||
|
|
||||||
|
_startAddObject: (object) ->
|
||||||
|
@objects[object.uuid] = object
|
||||||
|
@orderedObjects.push object
|
||||||
|
object.scene = this
|
||||||
|
|
||||||
|
_endAddObject: (object) ->
|
||||||
|
@emit "object:added", object
|
||||||
|
|
||||||
|
setName: (name) ->
|
||||||
|
@name = name
|
||||||
|
|
||||||
|
createObject: (options = {}) ->
|
||||||
|
newObject = new AuthoredObject(this, options)
|
||||||
|
@_startAddObject(newObject)
|
||||||
|
|
||||||
|
if options.autoActivate ? true
|
||||||
|
process.nextTick =>
|
||||||
|
@setActiveObject newObject.uuid
|
||||||
|
|
||||||
|
@emit "object:created", newObject
|
||||||
|
@_endAddObject(newObject)
|
||||||
|
|
||||||
|
addObject: (object) ->
|
||||||
|
@_startAddObject(object)
|
||||||
|
@_endAddObject(object)
|
||||||
|
|
||||||
|
removeObject: (uuid) ->
|
||||||
|
objectIndex = @orderedObjects.indexOf(@objects[uuid])
|
||||||
|
|
||||||
|
delete @objects[uuid]
|
||||||
|
|
||||||
|
[@orderedObjects, removedObjects] = splitFilter @orderedObjects, (object) ->
|
||||||
|
object.uuid != uuid
|
||||||
|
|
||||||
|
removedObjects.forEach (object) =>
|
||||||
|
@emit "object:removed", object
|
||||||
|
|
||||||
|
if objectIndex == 0
|
||||||
|
newActiveIndex = 0
|
||||||
|
else
|
||||||
|
newActiveIndex = objectIndex - 1
|
||||||
|
|
||||||
|
@setActiveObject(@orderedObjects[newActiveIndex]?.uuid)
|
||||||
|
|
||||||
|
getActiveObject: ->
|
||||||
|
return @objects[@activeObject]
|
||||||
|
|
||||||
|
setActiveObject: (uuid) ->
|
||||||
|
@activeObject = uuid
|
||||||
|
@emit "object:switched", @objects[uuid]
|
||||||
|
|
||||||
|
getObjectNameIncrement: ->
|
||||||
|
return objectNameIncrement++
|
||||||
|
|
||||||
|
|
||||||
|
module.exports = class AuthoredStage extends EventEmitter
|
||||||
|
constructor: (options = {}) ->
|
||||||
|
@plugins = []
|
||||||
|
@scenes = {}
|
||||||
|
@orderedScenes = []
|
||||||
|
@activeScene = null
|
||||||
|
|
||||||
|
process.nextTick =>
|
||||||
|
# Initial scene
|
||||||
|
@createScene()
|
||||||
|
|
||||||
|
use: (plugin) ->
|
||||||
|
pluginMeta = plugin.meta
|
||||||
|
|
||||||
|
# Verify that all dependencies exist...
|
||||||
|
if Array.isArray pluginMeta.dependencies
|
||||||
|
pluginMeta.dependencies.forEach (dep) =>
|
||||||
|
if not @plugins[dep]?
|
||||||
|
# FIXME: DependencyError
|
||||||
|
throw new Error "Unmet dependency: `#{pluginMeta.name}` requires `#{dep}`"
|
||||||
|
else if typeof pluginMeta.dependencies == "function"
|
||||||
|
pluginMeta.dependencies(this)
|
||||||
|
|
||||||
|
pluginAPI = plugin(this)
|
||||||
|
|
||||||
|
# In case of misbehaving plugins...
|
||||||
|
pluginAPI ?= {}
|
||||||
|
|
||||||
|
@plugins[pluginMeta.name] = pluginAPI
|
||||||
|
|
||||||
|
createScene: (options = {}) ->
|
||||||
|
newScene = new AuthoredScene(this, options)
|
||||||
|
@scenes[newScene.uuid] = newScene
|
||||||
|
@orderedScenes.push newScene
|
||||||
|
|
||||||
|
if options.autoActivate ? true
|
||||||
|
process.nextTick =>
|
||||||
|
@setActiveScene newScene.uuid
|
||||||
|
|
||||||
|
@emit "scene:added", newScene
|
||||||
|
|
||||||
|
removeScene: (uuid) ->
|
||||||
|
sceneIndex = @orderedScenes.indexOf(@scenes[uuid])
|
||||||
|
|
||||||
|
delete @scenes[uuid]
|
||||||
|
|
||||||
|
[@orderedScenes, removedScenes] = splitFilter @orderedScenes, (scene) ->
|
||||||
|
scene.uuid != uuid
|
||||||
|
|
||||||
|
removedScenes.forEach (scene) =>
|
||||||
|
@emit "scene:removed", scene
|
||||||
|
|
||||||
|
if sceneIndex == 0
|
||||||
|
newActiveIndex = 0
|
||||||
|
else
|
||||||
|
newActiveIndex = sceneIndex - 1
|
||||||
|
|
||||||
|
@setActiveScene(@orderedScenes[newActiveIndex]?.uuid)
|
||||||
|
|
||||||
|
getActiveScene: ->
|
||||||
|
return @scenes[@activeScene]
|
||||||
|
|
||||||
|
setActiveScene: (uuid) ->
|
||||||
|
@activeScene = uuid
|
||||||
|
@emit "scene:switched", @scenes[uuid]
|
||||||
|
|
@ -0,0 +1,87 @@
|
|||||||
|
$ = require "jquery"
|
||||||
|
domWait = require "../lib/dom-wait"
|
||||||
|
|
||||||
|
# Layer panel functions
|
||||||
|
createLayerItem = (uuid, name, sceneUuid) ->
|
||||||
|
list = @jqObject.find "ul.layerList"
|
||||||
|
|
||||||
|
$("<li></li>")
|
||||||
|
.appendTo list
|
||||||
|
.data "uuid", uuid
|
||||||
|
.data "scene-uuid", sceneUuid
|
||||||
|
.text name
|
||||||
|
|
||||||
|
removeLayerItem = (uuid) ->
|
||||||
|
@jqObject
|
||||||
|
.find "ul.layerList li"
|
||||||
|
.filter (i, li) -> $(li).data("uuid") == uuid
|
||||||
|
.remove()
|
||||||
|
|
||||||
|
switchLayerItem = (uuid) ->
|
||||||
|
@jqObject
|
||||||
|
.find "ul.layerList li"
|
||||||
|
.removeClass "selected"
|
||||||
|
.filter (i, li) -> $(li).data("uuid") == uuid
|
||||||
|
.addClass "selected"
|
||||||
|
|
||||||
|
# API methods
|
||||||
|
attachLayerPanel = (jqObject) ->
|
||||||
|
panel =
|
||||||
|
stage: this
|
||||||
|
jqObject: jqObject
|
||||||
|
createLayerItem: domWait.func(createLayerItem)
|
||||||
|
removeLayerItem: domWait.func(removeLayerItem)
|
||||||
|
switchLayerItem: domWait.func(switchLayerItem)
|
||||||
|
|
||||||
|
panel.stage.on "scene:added", (scene) ->
|
||||||
|
scene.on "layer:added", (layer) ->
|
||||||
|
panel.createLayerItem(layer.uuid, layer.name, scene.uuid)
|
||||||
|
# FIXME: For now assumes that we automatically activate the new layer.
|
||||||
|
panel.switchLayerItem(layer.uuid)
|
||||||
|
|
||||||
|
scene.on "layer:removed", (layer) ->
|
||||||
|
panel.removeLayerItem(layer.uuid)
|
||||||
|
|
||||||
|
scene.on "layer:switched", (layer) ->
|
||||||
|
if layer?
|
||||||
|
panel.switchLayerItem(layer.uuid)
|
||||||
|
|
||||||
|
panel.stage.on "scene:switched", (scene) ->
|
||||||
|
jqObject
|
||||||
|
.find "ul.layerList li"
|
||||||
|
.hide()
|
||||||
|
.filter (i, li) -> $(li).data("scene-uuid") == scene.uuid
|
||||||
|
.show()
|
||||||
|
|
||||||
|
if activeLayer = scene.getActiveLayer?()
|
||||||
|
panel.switchLayerItem activeLayer.uuid
|
||||||
|
|
||||||
|
jqObject
|
||||||
|
.find ".action-addLayer"
|
||||||
|
.on "click", (event) ->
|
||||||
|
activeScene = panel.stage.getActiveScene()
|
||||||
|
activeScene.createLayer()
|
||||||
|
|
||||||
|
jqObject
|
||||||
|
.find ".action-removeLayer"
|
||||||
|
.on "click", (event) ->
|
||||||
|
targetUuid = panel.stage.getActiveScene().getActiveLayer().uuid
|
||||||
|
panel.stage.getActiveScene().removeLayer targetUuid
|
||||||
|
|
||||||
|
jqObject
|
||||||
|
.find "ul.layerList"
|
||||||
|
.on "mousedown", "li", (event) ->
|
||||||
|
targetUuid = $(this).data "uuid"
|
||||||
|
panel.stage.getActiveScene().setActiveLayer targetUuid
|
||||||
|
|
||||||
|
# Public API
|
||||||
|
API = (stage) ->
|
||||||
|
return {
|
||||||
|
attach: attachLayerPanel.bind(stage)
|
||||||
|
}
|
||||||
|
|
||||||
|
API.meta =
|
||||||
|
name: "layerPanel"
|
||||||
|
dependencies: ["layers"]
|
||||||
|
|
||||||
|
module.exports = API
|
@ -0,0 +1,106 @@
|
|||||||
|
uuid = require "uuid"
|
||||||
|
splitFilter = require "../lib/split-filter"
|
||||||
|
|
||||||
|
nameIncrement = 1
|
||||||
|
|
||||||
|
# Scene methods
|
||||||
|
createLayer = (options = {}) ->
|
||||||
|
if not options.name?
|
||||||
|
name = "Layer #{nameIncrement++}"
|
||||||
|
else
|
||||||
|
name = options.name
|
||||||
|
|
||||||
|
newUuid = uuid.v4()
|
||||||
|
|
||||||
|
layerObject =
|
||||||
|
name: name
|
||||||
|
uuid: newUuid
|
||||||
|
scene: this
|
||||||
|
|
||||||
|
@layers[newUuid] = layerObject
|
||||||
|
@orderedLayers.push layerObject
|
||||||
|
|
||||||
|
if options.autoActivate ? true
|
||||||
|
@setActiveLayer(newUuid)
|
||||||
|
|
||||||
|
@emit "layer:added", layerObject
|
||||||
|
|
||||||
|
return layerObject
|
||||||
|
|
||||||
|
removeLayer = (uuid) ->
|
||||||
|
# FIXME: Edge-case: removing the last layer in a scene?
|
||||||
|
layerIndex = @orderedLayers.indexOf(@layers[uuid])
|
||||||
|
|
||||||
|
delete @layers[uuid]
|
||||||
|
|
||||||
|
[@orderedLayers, removedLayers] = splitFilter @orderedLayers, (layer) ->
|
||||||
|
layer.uuid != uuid
|
||||||
|
|
||||||
|
removedLayers.forEach (layerObject) =>
|
||||||
|
@emit "layer:removed", layerObject
|
||||||
|
|
||||||
|
# Remove all the objects on this layer as well...
|
||||||
|
@orderedObjects
|
||||||
|
.filter (object) -> object.layer == uuid
|
||||||
|
.forEach (object) => @removeObject(object.uuid)
|
||||||
|
|
||||||
|
if layerIndex == 0
|
||||||
|
newActiveIndex = 0
|
||||||
|
else
|
||||||
|
newActiveIndex = layerIndex - 1
|
||||||
|
|
||||||
|
@setActiveLayer(@orderedLayers[newActiveIndex]?.uuid)
|
||||||
|
|
||||||
|
setActiveLayer = (uuid) ->
|
||||||
|
@activeLayer = uuid
|
||||||
|
|
||||||
|
@orderedObjects.forEach (object) ->
|
||||||
|
object.editorFaded = (object.layer != uuid)
|
||||||
|
|
||||||
|
@emit "layer:switched", @layers[uuid]
|
||||||
|
|
||||||
|
getActiveLayer = ->
|
||||||
|
return @layers[@activeLayer]
|
||||||
|
|
||||||
|
# Object methods
|
||||||
|
setLayer = (uuid) ->
|
||||||
|
@emit "layer:switched", @scene.layers[uuid]
|
||||||
|
@layer = uuid
|
||||||
|
|
||||||
|
# Setup function
|
||||||
|
API = (stage) ->
|
||||||
|
stage.on "scene:added", (scene) ->
|
||||||
|
scene._ignoredProperties.push "orderedLayers"
|
||||||
|
|
||||||
|
scene.layers = {}
|
||||||
|
scene.orderedLayers = []
|
||||||
|
|
||||||
|
scene.createLayer = createLayer
|
||||||
|
scene.removeLayer = removeLayer
|
||||||
|
scene.setActiveLayer = setActiveLayer
|
||||||
|
scene.getActiveLayer = getActiveLayer
|
||||||
|
|
||||||
|
scene.on "object:added", (object) ->
|
||||||
|
object.layer = scene.activeLayer
|
||||||
|
object.setLayer = setLayer
|
||||||
|
|
||||||
|
scene.on "object:switched", (object) ->
|
||||||
|
if object.layer?
|
||||||
|
scene.setActiveLayer(object.layer)
|
||||||
|
|
||||||
|
process.nextTick ->
|
||||||
|
# Default first layer
|
||||||
|
scene.createLayer()
|
||||||
|
|
||||||
|
stage.on "scene:removed", (scene) ->
|
||||||
|
scene.orderedLayers.forEach (layer) ->
|
||||||
|
scene.removeLayer(layer.uuid)
|
||||||
|
|
||||||
|
return {}
|
||||||
|
|
||||||
|
API.meta =
|
||||||
|
name: "layers"
|
||||||
|
|
||||||
|
module.exports = API
|
||||||
|
|
||||||
|
# SPEC: list modifier for reordering the objects according to their layer...?
|
@ -0,0 +1,96 @@
|
|||||||
|
$ = require "jquery"
|
||||||
|
domWait = require "../lib/dom-wait"
|
||||||
|
|
||||||
|
# Scene panel functions
|
||||||
|
createObjectItem = (uuid, name, sceneUuid) ->
|
||||||
|
list = @jqObject.find "ul.objectList"
|
||||||
|
|
||||||
|
$("<li></li>")
|
||||||
|
.appendTo list
|
||||||
|
.data "uuid", uuid
|
||||||
|
.data "scene-uuid", sceneUuid
|
||||||
|
.text name
|
||||||
|
|
||||||
|
removeObjectItem = (uuid) ->
|
||||||
|
@jqObject
|
||||||
|
.find "ul.objectList li"
|
||||||
|
.filter (i, li) -> $(li).data("uuid") == uuid
|
||||||
|
.remove()
|
||||||
|
|
||||||
|
switchObjectItem = (uuid) ->
|
||||||
|
@jqObject
|
||||||
|
.find "ul.objectList li"
|
||||||
|
.removeClass "selected"
|
||||||
|
.filter (i, li) -> $(li).data("uuid") == uuid
|
||||||
|
.addClass "selected"
|
||||||
|
|
||||||
|
# API methods
|
||||||
|
attachObjectPanel = (jqObject) ->
|
||||||
|
panel =
|
||||||
|
stage: this
|
||||||
|
jqObject: jqObject
|
||||||
|
createObjectItem: domWait.func(createObjectItem)
|
||||||
|
removeObjectItem: domWait.func(removeObjectItem)
|
||||||
|
switchObjectItem: domWait.func(switchObjectItem)
|
||||||
|
|
||||||
|
panel.stage.on "scene:added", (scene) ->
|
||||||
|
|
||||||
|
scene.on "object:added", (object) ->
|
||||||
|
domElement = panel.createObjectItem(object.uuid, object.name, scene.uuid)
|
||||||
|
# FIXME: For now assumes that we automatically activate the new object.
|
||||||
|
panel.switchObjectItem(object.uuid)
|
||||||
|
|
||||||
|
object.on "changed:editorFaded", (faded) ->
|
||||||
|
if faded
|
||||||
|
domElement.addClass "faded"
|
||||||
|
else
|
||||||
|
domElement.removeClass "faded"
|
||||||
|
|
||||||
|
scene.on "object:removed", (object) ->
|
||||||
|
panel.removeObjectItem(object.uuid)
|
||||||
|
|
||||||
|
scene.on "object:switched", (object) ->
|
||||||
|
panel.switchObjectItem(object.uuid)
|
||||||
|
|
||||||
|
panel.stage.on "scene:switched", (scene) ->
|
||||||
|
jqObject
|
||||||
|
.find "ul.objectList li"
|
||||||
|
.hide()
|
||||||
|
.filter (i, li) -> $(li).data("scene-uuid") == scene.uuid
|
||||||
|
.show()
|
||||||
|
|
||||||
|
if activeObject = scene.getActiveObject?()
|
||||||
|
panel.switchObjectItem activeObject.uuid
|
||||||
|
|
||||||
|
jqObject
|
||||||
|
.find ".action-addObject"
|
||||||
|
.on "click", (event) ->
|
||||||
|
activeScene = panel.stage.getActiveScene()
|
||||||
|
objectType = $(this).data("type")
|
||||||
|
objectName = "Object (#{objectType}) #{activeScene.getObjectNameIncrement()}"
|
||||||
|
newObject = activeScene.createObject(type: objectType, name: objectName)
|
||||||
|
|
||||||
|
jqObject
|
||||||
|
.find ".action-removeObject"
|
||||||
|
.on "click", (event) ->
|
||||||
|
activeScene = panel.stage.getActiveScene()
|
||||||
|
targetUuid = activeScene.getActiveObject().uuid
|
||||||
|
newObject = activeScene.removeObject(targetUuid)
|
||||||
|
|
||||||
|
jqObject
|
||||||
|
.find "ul.objectList"
|
||||||
|
.on "mousedown", "li", (event) ->
|
||||||
|
targetUuid = $(this).data "uuid"
|
||||||
|
activeScene = panel.stage.getActiveScene()
|
||||||
|
activeScene.setActiveObject targetUuid
|
||||||
|
|
||||||
|
# Public API
|
||||||
|
API = (stage) ->
|
||||||
|
return {
|
||||||
|
attach: attachObjectPanel.bind(stage)
|
||||||
|
}
|
||||||
|
|
||||||
|
API.meta =
|
||||||
|
name: "objectPanel"
|
||||||
|
|
||||||
|
module.exports = API
|
@ -0,0 +1,17 @@
|
|||||||
|
attributes =
|
||||||
|
source:
|
||||||
|
type: "string"
|
||||||
|
|
||||||
|
API = (stage) ->
|
||||||
|
stage.on "scene:added", (scene) ->
|
||||||
|
scene.on "object:created", (object) ->
|
||||||
|
if object.type == "image"
|
||||||
|
Object.keys(attributes).forEach (propName) ->
|
||||||
|
object.registerProperty propName, attributes[propName]
|
||||||
|
|
||||||
|
return {}
|
||||||
|
|
||||||
|
API.meta =
|
||||||
|
name: "objectTypeImage"
|
||||||
|
|
||||||
|
module.exports = API
|
@ -0,0 +1,32 @@
|
|||||||
|
attributes =
|
||||||
|
text:
|
||||||
|
type: "string"
|
||||||
|
html:
|
||||||
|
type: "html"
|
||||||
|
fontFamily:
|
||||||
|
type: "font"
|
||||||
|
fontSize:
|
||||||
|
type: "numeric"
|
||||||
|
bold:
|
||||||
|
type: "boolean"
|
||||||
|
italic:
|
||||||
|
type: "boolean"
|
||||||
|
fontColor:
|
||||||
|
type: "color"
|
||||||
|
|
||||||
|
API = (stage) ->
|
||||||
|
stage.on "scene:added", (scene) ->
|
||||||
|
scene.on "object:created", (object) ->
|
||||||
|
if object.type == "text"
|
||||||
|
Object.keys(attributes).forEach (propName) ->
|
||||||
|
object.registerProperty propName, attributes[propName]
|
||||||
|
|
||||||
|
process.nextTick ->
|
||||||
|
object.text = "Text goes here"
|
||||||
|
|
||||||
|
return {}
|
||||||
|
|
||||||
|
API.meta =
|
||||||
|
name: "objectTypeText"
|
||||||
|
|
||||||
|
module.exports = API
|
@ -0,0 +1,101 @@
|
|||||||
|
$ = require "jquery"
|
||||||
|
domWait = require "../lib/dom-wait"
|
||||||
|
|
||||||
|
lockTimeout = 500
|
||||||
|
|
||||||
|
# Property panel functions
|
||||||
|
createPropertyItem = (name, type) ->
|
||||||
|
list = @jqObject.find "div.propertyList"
|
||||||
|
object = @stage.getActiveScene().getActiveObject()
|
||||||
|
|
||||||
|
# To prevent our changes from echoing
|
||||||
|
lastValue = null
|
||||||
|
|
||||||
|
domElement = $("<div class='property'><label></label></div>")
|
||||||
|
.data "property", name
|
||||||
|
.data "type", type
|
||||||
|
.appendTo list
|
||||||
|
|
||||||
|
domElement
|
||||||
|
.children "label"
|
||||||
|
.text name
|
||||||
|
|
||||||
|
setValue = (value) ->
|
||||||
|
if value == lastValue
|
||||||
|
return
|
||||||
|
|
||||||
|
lastValue = value
|
||||||
|
|
||||||
|
property = domElement.data("property")
|
||||||
|
object[property] = value
|
||||||
|
|
||||||
|
if type == "boolean"
|
||||||
|
# Checkboxes want to be special.
|
||||||
|
inputElement = $("<input type='checkbox'>")
|
||||||
|
|
||||||
|
inputElement
|
||||||
|
.prop "checked", object[name]
|
||||||
|
.on "change", (event) ->
|
||||||
|
setValue $(this).is ":checked"
|
||||||
|
|
||||||
|
object.on "changed:#{name}", (value) ->
|
||||||
|
if value == lastValue
|
||||||
|
return
|
||||||
|
|
||||||
|
lastValue = value
|
||||||
|
inputElement.prop "checked", value
|
||||||
|
else
|
||||||
|
inputElement = switch type
|
||||||
|
when "numeric"
|
||||||
|
$("<input type='numeric'>")
|
||||||
|
when "text"
|
||||||
|
$("<input type='text'>")
|
||||||
|
else
|
||||||
|
$("<input type='text'>")
|
||||||
|
|
||||||
|
inputElement
|
||||||
|
.val object[name]
|
||||||
|
.on "change input propertychange", (event) ->
|
||||||
|
setValue $(this).val()
|
||||||
|
|
||||||
|
object.on "changed:#{name}", (value) ->
|
||||||
|
if value == lastValue
|
||||||
|
return
|
||||||
|
|
||||||
|
lastValue = value
|
||||||
|
inputElement.val(value)
|
||||||
|
|
||||||
|
inputElement.appendTo domElement
|
||||||
|
|
||||||
|
removePropertyItems = (uuid) ->
|
||||||
|
@jqObject
|
||||||
|
.find "div.propertyList .property"
|
||||||
|
.remove()
|
||||||
|
|
||||||
|
# API methods
|
||||||
|
attachPropertyPanel = (jqObject) ->
|
||||||
|
panel =
|
||||||
|
stage: this
|
||||||
|
jqObject: jqObject
|
||||||
|
createPropertyItem: domWait.func(createPropertyItem)
|
||||||
|
removePropertyItems: domWait.func(removePropertyItems)
|
||||||
|
|
||||||
|
panel.stage.on "scene:added", (scene) ->
|
||||||
|
scene.on "object:switched", (object) ->
|
||||||
|
panel.removePropertyItems()
|
||||||
|
|
||||||
|
Object.keys(object.propMeta).forEach (property) ->
|
||||||
|
meta = object.propMeta[property]
|
||||||
|
console.log property, meta
|
||||||
|
panel.createPropertyItem property, meta.type
|
||||||
|
|
||||||
|
# Public API
|
||||||
|
API = (stage) ->
|
||||||
|
return {
|
||||||
|
attach: attachPropertyPanel.bind(stage)
|
||||||
|
}
|
||||||
|
|
||||||
|
API.meta =
|
||||||
|
name: "propertyPanel"
|
||||||
|
|
||||||
|
module.exports = API
|
@ -0,0 +1,72 @@
|
|||||||
|
$ = require "jquery"
|
||||||
|
domWait = require "../lib/dom-wait"
|
||||||
|
|
||||||
|
# Scene panel functions
|
||||||
|
createSceneItem = (uuid, name) ->
|
||||||
|
list = @jqObject.find "ul.sceneList"
|
||||||
|
|
||||||
|
$("<li></li>")
|
||||||
|
.appendTo list
|
||||||
|
.data "uuid", uuid
|
||||||
|
.text name
|
||||||
|
|
||||||
|
removeSceneItem = (uuid) ->
|
||||||
|
@jqObject
|
||||||
|
.find "ul.sceneList li"
|
||||||
|
.filter (i, li) -> $(li).data("uuid") == uuid
|
||||||
|
.remove()
|
||||||
|
|
||||||
|
switchSceneItem = (uuid) ->
|
||||||
|
@jqObject
|
||||||
|
.find "ul.sceneList li"
|
||||||
|
.removeClass "selected"
|
||||||
|
.filter (i, li) -> $(li).data("uuid") == uuid
|
||||||
|
.addClass "selected"
|
||||||
|
|
||||||
|
# API methods
|
||||||
|
attachScenePanel = (jqObject) ->
|
||||||
|
panel =
|
||||||
|
stage: this
|
||||||
|
jqObject: jqObject
|
||||||
|
createSceneItem: domWait.func(createSceneItem)
|
||||||
|
removeSceneItem: domWait.func(removeSceneItem)
|
||||||
|
switchSceneItem: domWait.func(switchSceneItem)
|
||||||
|
|
||||||
|
panel.stage.on "scene:added", (scene) ->
|
||||||
|
panel.createSceneItem(scene.uuid, scene.name)
|
||||||
|
# FIXME: For now assumes that we automatically activate the new scene.
|
||||||
|
panel.switchSceneItem(scene.uuid)
|
||||||
|
|
||||||
|
panel.stage.on "scene:removed", (scene) ->
|
||||||
|
panel.removeSceneItem(scene.uuid)
|
||||||
|
|
||||||
|
panel.stage.on "scene:switched", (scene) ->
|
||||||
|
panel.switchSceneItem(scene.uuid)
|
||||||
|
|
||||||
|
jqObject
|
||||||
|
.find ".action-addScene"
|
||||||
|
.on "click", (event) ->
|
||||||
|
activeScene = panel.stage.createScene()
|
||||||
|
|
||||||
|
jqObject
|
||||||
|
.find ".action-removeScene"
|
||||||
|
.on "click", (event) ->
|
||||||
|
targetUuid = panel.stage.getActiveScene().uuid
|
||||||
|
panel.stage.removeScene targetUuid
|
||||||
|
|
||||||
|
jqObject
|
||||||
|
.find "ul.sceneList"
|
||||||
|
.on "mousedown", "li", (event) ->
|
||||||
|
targetUuid = $(this).data "uuid"
|
||||||
|
panel.stage.setActiveScene targetUuid
|
||||||
|
|
||||||
|
# Public API
|
||||||
|
API = (stage) ->
|
||||||
|
return {
|
||||||
|
attach: attachScenePanel.bind(stage)
|
||||||
|
}
|
||||||
|
|
||||||
|
API.meta =
|
||||||
|
name: "scenePanel"
|
||||||
|
|
||||||
|
module.exports = API
|
@ -0,0 +1,11 @@
|
|||||||
|
module.exports = (array, filterFunc) ->
|
||||||
|
matches = []
|
||||||
|
nonMatches = []
|
||||||
|
|
||||||
|
array.forEach (item, i) ->
|
||||||
|
if filterFunc(item, i)
|
||||||
|
matches.push item
|
||||||
|
else
|
||||||
|
nonMatches.push item
|
||||||
|
|
||||||
|
return [matches, nonMatches]
|
@ -0,0 +1,39 @@
|
|||||||
|
{
|
||||||
|
"name": "authored",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "A modular framework for building authoring tools.",
|
||||||
|
"main": "index.js",
|
||||||
|
"scripts": {
|
||||||
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
|
},
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "git://github.com/joepie91/node-authored"
|
||||||
|
},
|
||||||
|
"keywords": [
|
||||||
|
"authoring"
|
||||||
|
],
|
||||||
|
"author": "Sven Slootweg",
|
||||||
|
"license": "WTFPL",
|
||||||
|
"dependencies": {
|
||||||
|
"jquery": "^2.1.3",
|
||||||
|
"uuid": "^2.0.1"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"coffee-loader": "^0.7.2",
|
||||||
|
"coffee-script": "^1.9.1",
|
||||||
|
"gulp": "~3.8.0",
|
||||||
|
"gulp-cached": "~0.0.3",
|
||||||
|
"gulp-jade": "^0.7.0",
|
||||||
|
"gulp-livereload": "~2.1.0",
|
||||||
|
"gulp-nodemon": "~1.0.4",
|
||||||
|
"gulp-plumber": "~0.6.3",
|
||||||
|
"gulp-remember": "~0.3.0",
|
||||||
|
"gulp-rename": "~1.2.0",
|
||||||
|
"gulp-sass": "^1.3.3",
|
||||||
|
"gulp-util": "~2.2.17",
|
||||||
|
"gulp-webpack": "^1.2.0",
|
||||||
|
"through2-spy": "^1.2.0",
|
||||||
|
"st": "^0.5.2"
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,23 @@
|
|||||||
|
class A
|
||||||
|
constructor: ->
|
||||||
|
|
||||||
|
someMethod: ->
|
||||||
|
console.log "a"
|
||||||
|
|
||||||
|
someOtherMethod: ->
|
||||||
|
console.log "2"
|
||||||
|
|
||||||
|
b = new A()
|
||||||
|
b.someMethod()
|
||||||
|
|
||||||
|
c = Object.create(b)
|
||||||
|
|
||||||
|
c.someMethod = ->
|
||||||
|
console.log "derp"
|
||||||
|
|
||||||
|
c.someMethod()
|
||||||
|
b.someMethod()
|
||||||
|
|
||||||
|
d = Object.create(c)
|
||||||
|
d.someMethod()
|
||||||
|
d.someOtherMethod()
|
@ -0,0 +1,89 @@
|
|||||||
|
body {
|
||||||
|
font-family: sans-serif; }
|
||||||
|
body .main {
|
||||||
|
position: absolute;
|
||||||
|
left: 0px;
|
||||||
|
top: 0px;
|
||||||
|
bottom: 0px;
|
||||||
|
right: 260px; }
|
||||||
|
body .main .notice {
|
||||||
|
padding: 8px;
|
||||||
|
margin: 16px;
|
||||||
|
border: 1px solid red;
|
||||||
|
background-color: #ffdada; }
|
||||||
|
body .main .renderer {
|
||||||
|
background-color: lightgoldenrodyellow;
|
||||||
|
width: 800px;
|
||||||
|
height: 600px; }
|
||||||
|
body .main .renderer .rendererObject {
|
||||||
|
position: absolute;
|
||||||
|
cursor: default; }
|
||||||
|
body .main .renderer .rendererObject.activated {
|
||||||
|
outline: 1px dashed #720000;
|
||||||
|
cursor: move; }
|
||||||
|
body .sidebar {
|
||||||
|
position: absolute;
|
||||||
|
top: 0px;
|
||||||
|
bottom: 0px;
|
||||||
|
right: 0px;
|
||||||
|
width: 260px;
|
||||||
|
background-color: antiquewhite;
|
||||||
|
border-left: 1px solid gray; }
|
||||||
|
body .sidebar section h1 {
|
||||||
|
font-size: 17px;
|
||||||
|
font-weight: bold;
|
||||||
|
padding: 5px 7px;
|
||||||
|
margin: 0px;
|
||||||
|
background-color: #45674d;
|
||||||
|
color: white; }
|
||||||
|
body .sidebar section .action {
|
||||||
|
margin-left: 8px;
|
||||||
|
margin-top: 8px;
|
||||||
|
font-size: 13px;
|
||||||
|
border: 1px solid black;
|
||||||
|
background-color: white;
|
||||||
|
font-weight: bold;
|
||||||
|
padding: 3px 7px; }
|
||||||
|
body .sidebar section .action:hover {
|
||||||
|
background-color: #dddddd; }
|
||||||
|
body .sidebar section .toolbar {
|
||||||
|
border-bottom: 1px solid black;
|
||||||
|
background-color: white; }
|
||||||
|
body .sidebar section .toolbar .action {
|
||||||
|
border: 0px;
|
||||||
|
margin: 0px;
|
||||||
|
border-right: 1px solid black; }
|
||||||
|
body .sidebar section .layers ul, body .sidebar section .scenes ul, body .sidebar section .objects ul {
|
||||||
|
padding-left: 0px;
|
||||||
|
margin: 0px 0px 8px 0px;
|
||||||
|
border-bottom: 1px solid black;
|
||||||
|
background-color: azure; }
|
||||||
|
body .sidebar section .layers ul li, body .sidebar section .scenes ul li, body .sidebar section .objects ul li {
|
||||||
|
list-style-type: none;
|
||||||
|
padding: 3px 5px;
|
||||||
|
font-size: 14px; }
|
||||||
|
body .sidebar section .layers ul li.selected, body .sidebar section .scenes ul li.selected, body .sidebar section .objects ul li.selected {
|
||||||
|
background-color: #caf5f5;
|
||||||
|
color: red;
|
||||||
|
font-weight: bold; }
|
||||||
|
body .sidebar section .layers ul li.faded, body .sidebar section .scenes ul li.faded, body .sidebar section .objects ul li.faded {
|
||||||
|
color: gray; }
|
||||||
|
body .sidebar section .layers ul, body .sidebar section .scenes ul, body .sidebar section .objects ul, body .sidebar section .properties ul {
|
||||||
|
height: 100px;
|
||||||
|
overflow: auto; }
|
||||||
|
body .sidebar section .properties .property {
|
||||||
|
margin-bottom: 2px; }
|
||||||
|
body .sidebar section .properties .property:before, body .sidebar section .properties .property:after {
|
||||||
|
content: " ";
|
||||||
|
display: table; }
|
||||||
|
body .sidebar section .properties .property:after {
|
||||||
|
clear: both; }
|
||||||
|
body .sidebar section .properties .property label {
|
||||||
|
display: block;
|
||||||
|
float: left;
|
||||||
|
width: 90px;
|
||||||
|
padding: 3px 5px;
|
||||||
|
font-size: 14px;
|
||||||
|
background-color: #e2d2bd; }
|
||||||
|
body .sidebar section .properties .property input {
|
||||||
|
max-width: 150px; }
|
@ -0,0 +1,168 @@
|
|||||||
|
body
|
||||||
|
{
|
||||||
|
font-family: sans-serif;
|
||||||
|
|
||||||
|
.main
|
||||||
|
{
|
||||||
|
position: absolute;
|
||||||
|
left: 0px;
|
||||||
|
top: 0px;
|
||||||
|
bottom: 0px;
|
||||||
|
right: 260px;
|
||||||
|
|
||||||
|
.notice
|
||||||
|
{
|
||||||
|
padding: 8px;
|
||||||
|
margin: 16px;
|
||||||
|
border: 1px solid red;
|
||||||
|
background-color: #ffdada;
|
||||||
|
}
|
||||||
|
|
||||||
|
.renderer
|
||||||
|
{
|
||||||
|
background-color: lightgoldenrodyellow;
|
||||||
|
width: 800px;
|
||||||
|
height: 600px;
|
||||||
|
|
||||||
|
.rendererObject
|
||||||
|
{
|
||||||
|
position: absolute;
|
||||||
|
cursor: default;
|
||||||
|
|
||||||
|
&.activated
|
||||||
|
{
|
||||||
|
outline: 1px dashed #720000;
|
||||||
|
cursor: move;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar
|
||||||
|
{
|
||||||
|
position: absolute;
|
||||||
|
top: 0px;
|
||||||
|
bottom: 0px;
|
||||||
|
right: 0px;
|
||||||
|
width: 260px;
|
||||||
|
background-color: antiquewhite;
|
||||||
|
border-left: 1px solid gray;
|
||||||
|
|
||||||
|
section
|
||||||
|
{
|
||||||
|
|
||||||
|
h1
|
||||||
|
{
|
||||||
|
font-size: 17px;
|
||||||
|
font-weight: bold;
|
||||||
|
padding: 5px 7px;
|
||||||
|
margin: 0px;
|
||||||
|
background-color: #45674d;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.action
|
||||||
|
{
|
||||||
|
margin-left: 8px;
|
||||||
|
margin-top: 8px;
|
||||||
|
font-size: 13px;
|
||||||
|
border: 1px solid black;
|
||||||
|
background-color: white;
|
||||||
|
font-weight: bold;
|
||||||
|
padding: 3px 7px;
|
||||||
|
|
||||||
|
&:hover
|
||||||
|
{
|
||||||
|
background-color: #dddddd;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.toolbar
|
||||||
|
{
|
||||||
|
border-bottom: 1px solid black;
|
||||||
|
background-color: white;
|
||||||
|
|
||||||
|
.action
|
||||||
|
{
|
||||||
|
border: 0px;
|
||||||
|
margin: 0px;
|
||||||
|
|
||||||
|
border-right: 1px solid black;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.layers, .scenes, .objects
|
||||||
|
{
|
||||||
|
ul
|
||||||
|
{
|
||||||
|
padding-left: 0px;
|
||||||
|
margin: 0px 0px 8px 0px;
|
||||||
|
border-bottom: 1px solid black;
|
||||||
|
background-color: azure;
|
||||||
|
|
||||||
|
li
|
||||||
|
{
|
||||||
|
list-style-type: none;
|
||||||
|
padding: 3px 5px;
|
||||||
|
font-size: 14px;
|
||||||
|
|
||||||
|
&.selected
|
||||||
|
{
|
||||||
|
background-color: #caf5f5;
|
||||||
|
color: red;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.faded
|
||||||
|
{
|
||||||
|
color: gray;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.layers, .scenes, .objects, .properties
|
||||||
|
{
|
||||||
|
ul
|
||||||
|
{
|
||||||
|
height: 100px;
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.properties
|
||||||
|
{
|
||||||
|
.property
|
||||||
|
{
|
||||||
|
margin-bottom: 2px;
|
||||||
|
|
||||||
|
&:before, &:after
|
||||||
|
{
|
||||||
|
content: " ";
|
||||||
|
display: table;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:after
|
||||||
|
{
|
||||||
|
clear: both;
|
||||||
|
}
|
||||||
|
|
||||||
|
label
|
||||||
|
{
|
||||||
|
display: block;
|
||||||
|
float: left;
|
||||||
|
width: 90px;
|
||||||
|
padding: 3px 5px;
|
||||||
|
font-size: 14px;
|
||||||
|
background-color: #e2d2bd;
|
||||||
|
}
|
||||||
|
|
||||||
|
input
|
||||||
|
{
|
||||||
|
max-width: 150px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1 @@
|
|||||||
|
<html><head><script src="test-bundle.js"></script><link rel="stylesheet" href="style.css"/></head><body><div class="main"><div class="notice"><strong>This demo is <em>not</em> representative of the final functionality or design!</strong> This is a technical demo, purely for the purpose of displaying some of the functionality that could be implemented. The authoring tool is intentionally a small, modular framework that allows for implementing pretty much <em>any</em> kind of functionality.</div><div class="renderer"></div></div><div class="sidebar"><section id="scenes"><h1>Scenes</h1><div class="scenes"><div class="toolbar"><button class="action action-addScene">Add scene</button><button class="action action-removeScene">Remove scene</button></div><ul class="sceneList"></ul></div></section><section id="layers"><h1>Layers</h1><div class="layers"><div class="toolbar"><button class="action action-addLayer">Add layer</button><button class="action action-removeLayer">Remove layer</button></div><ul class="layerList"></ul></div></section><section id="objects"><h1>Objects</h1><div class="objects"><div class="toolbar"><!-- button.action.action-addObject Add object--><button data-type="text" class="action action-addObject">+ Text</button><button data-type="image" class="action action-addObject">+ Image</button><button data-type="video" class="action action-addObject">+ Video</button><button class="action action-removeObject">Remove</button></div><ul class="objectList"></ul></div></section><section id="properties"><h1>Properties</h1><div class="properties"><div class="propertyList"></div></div></section></div></body></html>
|
@ -0,0 +1,42 @@
|
|||||||
|
html
|
||||||
|
head
|
||||||
|
script(src="test-bundle.js")
|
||||||
|
link(rel="stylesheet", href="style.css")
|
||||||
|
body
|
||||||
|
.main
|
||||||
|
.notice
|
||||||
|
strong This demo is <em>not</em> representative of the final functionality or design!
|
||||||
|
| This is a technical demo, purely for the purpose of displaying some of the functionality that could be implemented. The authoring tool is intentionally a small, modular framework that allows for implementing pretty much <em>any</em> kind of functionality.
|
||||||
|
.renderer
|
||||||
|
.sidebar
|
||||||
|
section#scenes
|
||||||
|
h1 Scenes
|
||||||
|
div.scenes
|
||||||
|
.toolbar
|
||||||
|
button.action.action-addScene Add scene
|
||||||
|
button.action.action-removeScene Remove scene
|
||||||
|
ul.sceneList
|
||||||
|
|
||||||
|
section#layers
|
||||||
|
h1 Layers
|
||||||
|
div.layers
|
||||||
|
.toolbar
|
||||||
|
button.action.action-addLayer Add layer
|
||||||
|
button.action.action-removeLayer Remove layer
|
||||||
|
ul.layerList
|
||||||
|
|
||||||
|
section#objects
|
||||||
|
h1 Objects
|
||||||
|
div.objects
|
||||||
|
.toolbar
|
||||||
|
// button.action.action-addObject Add object
|
||||||
|
button.action.action-addObject(data-type="text") + Text
|
||||||
|
button.action.action-addObject(data-type="image") + Image
|
||||||
|
button.action.action-addObject(data-type="video") + Video
|
||||||
|
button.action.action-removeObject Remove
|
||||||
|
ul.objectList
|
||||||
|
|
||||||
|
section#properties
|
||||||
|
h1 Properties
|
||||||
|
div.properties
|
||||||
|
div.propertyList
|
@ -0,0 +1,20 @@
|
|||||||
|
var authored = require("../lib/");
|
||||||
|
var $ = require("jquery");
|
||||||
|
|
||||||
|
var stage = new authored();
|
||||||
|
stage.use(require("../lib/layers"));
|
||||||
|
stage.use(require("../lib/layer-panel"));
|
||||||
|
stage.use(require("../lib/scene-panel"));
|
||||||
|
stage.use(require("../lib/object-panel"));
|
||||||
|
stage.use(require("../lib/property-panel"));
|
||||||
|
stage.use(require("../lib/object-type-text"));
|
||||||
|
stage.use(require("../lib/object-type-image"));
|
||||||
|
stage.use(require("../lib/html-renderer"));
|
||||||
|
|
||||||
|
$(function(){
|
||||||
|
stage.plugins.layerPanel.attach($(".layers"));
|
||||||
|
stage.plugins.scenePanel.attach($(".scenes"));
|
||||||
|
stage.plugins.objectPanel.attach($(".objects"));
|
||||||
|
stage.plugins.propertyPanel.attach($(".properties"));
|
||||||
|
stage.plugins.htmlRenderer.attach($(".renderer"));
|
||||||
|
});
|
Loading…
Reference in New Issue