Author: jbeard Date: Wed Jun 30 02:08:05 2010 New Revision: 959165 URL: http://svn.apache.org/viewvc?rev=959165&view=rev Log: Created an SVG demo without the HTML context to see if this resolves the strange drag behaviour in Firefox.
Added: commons/sandbox/gsoc/2010/scxml-js/branches/SCXML-141-148/demo/drag-and-drop/drag-and-drop3.js (with props) commons/sandbox/gsoc/2010/scxml-js/branches/SCXML-141-148/demo/drag-and-drop/drag-and-drop3.svg (with props) Added: commons/sandbox/gsoc/2010/scxml-js/branches/SCXML-141-148/demo/drag-and-drop/drag-and-drop3.js URL: http://svn.apache.org/viewvc/commons/sandbox/gsoc/2010/scxml-js/branches/SCXML-141-148/demo/drag-and-drop/drag-and-drop3.js?rev=959165&view=auto ============================================================================== --- commons/sandbox/gsoc/2010/scxml-js/branches/SCXML-141-148/demo/drag-and-drop/drag-and-drop3.js (added) +++ commons/sandbox/gsoc/2010/scxml-js/branches/SCXML-141-148/demo/drag-and-drop/drag-and-drop3.js Wed Jun 30 02:08:05 2010 @@ -0,0 +1,662 @@ +function StatechartExecutionContext() { + + var self = this; //used in the rare occasions we call public functions from inside this class + //system variable declarations + var _event = { + name: undefined, + data: undefined + }, + _name = "", + _sessionid; + + var _x = { + _event: _event, + _name: _name, + _sessionid: _sessionid + }; + + //variable declarations relating to data model + var firstEvent, eventStamp, tDelta, rawNode, textNode; + + + //abstract state + + var AbstractState = new + function() { + //triggers are methods + + this.$default = function() {}; + + this.init = function() {}; + + this.mousedown = function() {}; + + this.mouseup = function() {}; + + this.mousemove = function() {}; + + + this.$default = function() {}; + } + + + //states + + + + var scxmlRoot = (function() { + + function scxmlRootConstructor() { + this.parent = AbstractState; + + this.initial = null; + + this.depth = 0; + + this.historyState = null; + + //these variables facilitate fast In predicate + this.isBasic = + + false; + + + this.toString = function() { + return "scxmlRoot" + } + + this.enterAction = function() { + + console.log("entering scxmlRoot"); + + } + + this.exitAction = function() { + + console.log("exiting scxmlRoot"); + + } + + + + + } + scxmlRootConstructor.prototype = AbstractState; + return new scxmlRootConstructor(); + })(); + + + + + + var scxmlRoot_initial = (function() { + + function scxmlRoot_initialConstructor() { + this.parent = scxmlRoot; + + this.initial = null; + + this.depth = 1; + + this.historyState = null; + + //these variables facilitate fast In predicate + this.isBasic = + + true; + + this.ancestors = [ + scxmlRoot + ]; + + this.parent.initial = this; //init parent's pointer to initial state + + this.toString = function() { + return "scxmlRoot_initial" + } + + this.enterAction = function() { + + console.log("entering scxmlRoot_initial"); + + } + + this.exitAction = function() { + + console.log("exiting scxmlRoot_initial"); + + } + + + + this.$default = function() { + + + hasTakenDefaultTransition = true; + + + //exit states + scxmlRoot_initial.exitAction(); + + + //transition action + + //enter states + initial_default.enterAction(); + + + //update configuration + + currentConfiguration = [ + initial_default + ]; + + + + //set whether preempted + + return; + scxmlRoot['$default'](); + } + + + + } + scxmlRoot_initialConstructor.prototype = scxmlRoot; + return new scxmlRoot_initialConstructor(); + })(); + + + + + + var initial_default = (function() { + + function initial_defaultConstructor() { + this.parent = scxmlRoot; + + this.initial = null; + + this.depth = 1; + + this.historyState = null; + + //these variables facilitate fast In predicate + this.isBasic = + + true; + + this.ancestors = [ + scxmlRoot + ]; + + + this.toString = function() { + return "initial_default" + } + + this.enterAction = function() { + + console.log("entering initial_default"); + + } + + this.exitAction = function() { + + console.log("exiting initial_default"); + + } + + + + this.init = function() { + + + + //exit states + initial_default.exitAction(); + + + //transition action + rawNode = _event.data.rawNode; + textNode = _event.data.textNode; + textNode.textContent = 'idle'; + + + //enter states + idle.enterAction(); + + + //update configuration + + currentConfiguration = [ + idle + ]; + + + + //set whether preempted + + return; + scxmlRoot['init'](); + } + + + + } + initial_defaultConstructor.prototype = scxmlRoot; + return new initial_defaultConstructor(); + })(); + + + + + + var idle = (function() { + + function idleConstructor() { + this.parent = scxmlRoot; + + this.initial = null; + + this.depth = 1; + + this.historyState = null; + + //these variables facilitate fast In predicate + this.isBasic = + + true; + + this.ancestors = [ + scxmlRoot + ]; + + + this.toString = function() { + return "idle" + } + + this.enterAction = function() { + + console.log("entering idle"); + + } + + this.exitAction = function() { + + console.log("exiting idle"); + + } + + + + this.mousedown = function() { + + + + //exit states + idle.exitAction(); + + + //transition action + firstEvent = _event.data; + eventStamp = _event.data; + textNode.textContent = 'dragging'; + + + //enter states + dragging.enterAction(); + + + //update configuration + + currentConfiguration = [ + dragging + ]; + + + + //set whether preempted + + return; + scxmlRoot['mousedown'](); + } + + + + } + idleConstructor.prototype = scxmlRoot; + return new idleConstructor(); + })(); + + + + + + var dragging = (function() { + + function draggingConstructor() { + this.parent = scxmlRoot; + + this.initial = null; + + this.depth = 1; + + this.historyState = null; + + //these variables facilitate fast In predicate + this.isBasic = + + true; + + this.ancestors = [ + scxmlRoot + ]; + + + this.toString = function() { + return "dragging" + } + + this.enterAction = function() { + + console.log("entering dragging"); + + } + + this.exitAction = function() { + + console.log("exiting dragging"); + + } + + + + this.mouseup = function() { + + + + //exit states + dragging.exitAction(); + + + //transition action + textNode.textContent = 'idle'; + + + //enter states + idle.enterAction(); + + + //update configuration + + currentConfiguration = [ + idle + ]; + + + + //set whether preempted + + return; + scxmlRoot['mouseup'](); + } + + + this.mousemove = function() { + + + + //exit states + dragging.exitAction(); + + + //transition action + tDelta = computeTDelta(eventStamp, _event.data); + + translate(rawNode, tDelta); + eventStamp = _event.data; + + + //enter states + dragging.enterAction(); + + + //update configuration + + currentConfiguration = [ + dragging + ]; + + + + //set whether preempted + + return; + scxmlRoot['mousemove'](); + } + + + + } + draggingConstructor.prototype = scxmlRoot; + return new draggingConstructor(); + })(); + + + + + //states enum for glass-box unit testing + + this._states = { + scxmlRoot_initial: scxmlRoot_initial, + initial_default: initial_default, + idle: idle, + dragging: dragging + } + + + + //trigger methods for synchronous interaction + + this.$default = function(data) { + if (isInStableState) { + runToCompletion("$default", data); + } else { + return undefined; + } + } + + + this.init = function(data) { + if (isInStableState) { + runToCompletion("init", data); + } else { + return undefined; + } + } + + + this.mousedown = function(data) { + if (isInStableState) { + runToCompletion("mousedown", data); + } else { + return undefined; + } + } + + + this.mouseup = function(data) { + if (isInStableState) { + runToCompletion("mouseup", data); + } else { + return undefined; + } + } + + + this.mousemove = function(data) { + if (isInStableState) { + runToCompletion("mousemove", data); + } else { + return undefined; + } + } + + + //initialization script + + function computeTDelta(oldEvent, newEvent) { + //summary:computes the offset between two events; to be later used with this.translate + var dx = newEvent.clientX - oldEvent.clientX; + var dy = newEvent.clientY - oldEvent.clientY; + + return { + 'dx': dx, + 'dy': dy + }; + } + + function translate(rawNode, tDelta) { + var tl = rawNode.transform.baseVal; + var t = tl.numberOfItems ? tl.getItem(0) : rawNode.ownerSVGElement.createSVGTransform(); + var m = t.matrix; + var newM = rawNode.ownerSVGElement.createSVGMatrix().translate(tDelta.dx, tDelta.dy).multiply(m); + t.setMatrix(newM); + tl.initialize(t); + return newM; + } + + + //initialization method + + this.initialize = function() { + currentConfiguration = [initial_default]; + runToCompletion(); + mainLoop(); + } + + + + //internal runtime functions + + function sortByDepthDeepToShallow(a, b) { + return b.depth - a.depth; + } + + + //start static boilerplate code + //static private member variables + var currentConfiguration = []; //current configuration + var innerEventQueue = []; //inner event queue + var outerEventQueue = []; //outer event queue + var isInStableState = true; + var isPreempted = false; + var hasTakenDefaultTransition = false; + var destroyed = false; + var mainLoopCallback = null; + + //static private member functions + + + function mainLoop() { + + if (!destroyed) { + //take an event from the current outer event queue + if (outerEventQueue.length && isInStableState) { + runToCompletion(outerEventQueue.shift(), outerEventQueue.shift()); + } + //call back + mainLoopCallback = window.setTimeout(function() { + mainLoop(); //FIXME: note that when calling mainloop this way, we won't have access to the "this" object. + //I don't think we ever use it though. Everything we need is private in function scope. + }, 100); + } + } + + function runToCompletion(e, data) { + isInStableState = false; + + if (e) { + innerEventQueue.push(e, data); + } + + do { + //take any available default transitions + microstep("$default"); + + if (!hasTakenDefaultTransition) { + + if (!innerEventQueue.length) { + //we have no more generated events, and no default transitions fired, so + //we are done, and have run to completion + break; + } else { + //microstep, then dequeue next event sending in event + microstep(innerEventQueue.shift(), innerEventQueue.shift()); + } + } else { + //he has taken a default transition, so reset the global variable to false and loop again + hasTakenDefaultTransition = false; + } + + } while (true) + + isInStableState = true; + } + + function microstep(e, data) { + currentConfiguration.forEach(function(state) { + if (!isPreempted) { + //we set the event as a global, rather than passing it into the function invocation as a parameter, + //because in cases of default events, the event object will be populated with previous event's data + if (e !== "$default") { + _event.name = e; + _event.data = data; + } + state[e](); + } + }); + + //reset the isPreempted flag + isPreempted = false; + } + + + this.destroy = function() { + //right now, this only disables timer and sets global destroyed variable to prevent future callbacks + window.clearTimeout(mainLoopCallback); + mainLoopCallback = null; + destroyed = true; + } + + + //this is for async communication + this.GEN = function(e, data) { + outerEventQueue.push(e, data); + } + + //this may or may not be something we want to expose, but for right now, we at least need it for testing + this.getCurrentConfiguration = function() { + //slice it to return a copy of the configuration rather than the conf itself + //this saves us all kinds of confusion involving references and stuff + return currentConfiguration.slice(); + } + + //public API for In predicate + this.$in = function(state) { + return In(state); + } + + //end static boilerplate code + + function In(state) { + state = typeof state == "string" ? self._states[state] : state; + + return state.isBasic ? currentConfiguration.indexOf(state) != -1 : currentConfiguration.some(function(s) { + return s.ancestors.indexOf(state) != -1; + }); + } + +} Propchange: commons/sandbox/gsoc/2010/scxml-js/branches/SCXML-141-148/demo/drag-and-drop/drag-and-drop3.js ------------------------------------------------------------------------------ svn:eol-style = native Added: commons/sandbox/gsoc/2010/scxml-js/branches/SCXML-141-148/demo/drag-and-drop/drag-and-drop3.svg URL: http://svn.apache.org/viewvc/commons/sandbox/gsoc/2010/scxml-js/branches/SCXML-141-148/demo/drag-and-drop/drag-and-drop3.svg?rev=959165&view=auto ============================================================================== --- commons/sandbox/gsoc/2010/scxml-js/branches/SCXML-141-148/demo/drag-and-drop/drag-and-drop3.svg (added) +++ commons/sandbox/gsoc/2010/scxml-js/branches/SCXML-141-148/demo/drag-and-drop/drag-and-drop3.svg Wed Jun 30 02:08:05 2010 @@ -0,0 +1,71 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +--> +<!-- +This demo illustrates mixing HTML, SVG, and SCXML content in a single compound +XML document. + +It also illustrates a fairly general technique, which would +allow authoring of SVG content with inline, declarative behavioural descriptions +using SCXML: +* the document is searched for scxml elements +* it compiles them locally to JavaScript, and then hooks up event listeners on the parent DOM node, + so that DOM events are sent to the state machine for processing +* the state machine is able to manipulate the DOM directly through executable content nodes +--> + +<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="100%" height="99%" id="svgRoot"> + <script type="application/ecmascript" xlink:href="drag-and-drop3.js"/> + <g id="groupToTranslate"> + <rect width="100" height="100" stroke="black" fill="red" id="rectToTranslate" /> + <text id="textToTranslate" /> + </g> + + <script><![CDATA[ + var resultText; + + //hook up minimal console api + if(typeof console == "undefined"){ + console = {}; + ["log","info","error","dirxml"].forEach(function(m){console[m] = console[m] || function(){} }); + } + + var svgRoot = document.getElementById("svgRoot"); + + var rectToTranslate = document.getElementById("rectToTranslate"); + var groupToTranslate = document.getElementById("groupToTranslate"); + var textToTranslate = document.getElementById("textToTranslate"); + + var compiledStatechartInstance = new StatechartExecutionContext(); + + //initialize + compiledStatechartInstance.initialize(); + + //pass in reference to rect + compiledStatechartInstance.init({rawNode:groupToTranslate,textNode:textToTranslate}); + + //hook up DOM events + ["mousedown","mouseup","mousemove"].forEach(function(eventName){ + groupToTranslate.addEventListener(eventName,compiledStatechartInstance[eventName],false); + }); + + //quick hack to ensure that mm events get captured by the rect + svgRoot.addEventListener("mousemove",compiledStatechartInstance["mousemove"],false); + + + ]]></script> +</svg> Propchange: commons/sandbox/gsoc/2010/scxml-js/branches/SCXML-141-148/demo/drag-and-drop/drag-and-drop3.svg ------------------------------------------------------------------------------ svn:eol-style = native