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