From 4c93896df3f63cbd0f803a9c86d15fa637d7800e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=96=9F=E9=85=8C=20=E9=B5=AC=E5=85=84?= Date: Fri, 14 Aug 2015 18:12:10 +0800 Subject: [PATCH] Initial commit --- .gitignore | 6 + README.md | 30 ++ botan-rebuild.py | 12 + botan-start.py | 75 +++ botanjs/__init__.py | 0 botanjs/classmap.py | 193 +++++++ botanjs/compressor/__init__.py | 0 botanjs/compressor/closure.py | 51 ++ botanjs/compressor/yui.py | 23 + botanjs/config.py | 5 + botanjs/service/__init__.py | 0 botanjs/service/jclassresv.py | 335 ++++++++++++ botanjs/service/jwork.py | 49 ++ .../Dandelian.CSSAnimations.MovieClip.html | 40 ++ .../test/System.Net.ClassLoader.html | 25 + .../templates/test/System.utils.IKey.html | 13 + botanjs/service/templates/test_list.html | 19 + botanjs/service/webapi.py | 72 +++ botanjs/src/Components/Console.css | 71 +++ botanjs/src/Components/Console.js | 177 +++++++ botanjs/src/Components/DockPanel.css | 34 ++ botanjs/src/Components/DockPanel.js | 54 ++ botanjs/src/Components/MessageBox.css | 62 +++ botanjs/src/Components/MessageBox.js | 91 ++++ botanjs/src/Components/Mouse/Clipboard.css | 5 + botanjs/src/Components/Mouse/Clipboard.js | 131 +++++ botanjs/src/Components/Mouse/ContextMenu.css | 54 ++ botanjs/src/Components/Mouse/ContextMenu.js | 495 ++++++++++++++++++ botanjs/src/Components/Mouse/_this.js | 3 + botanjs/src/Components/_this.js | 3 + .../src/Dandelion/CSSAnimations/MovieClip.css | 3 + .../src/Dandelion/CSSAnimations/MovieClip.js | 158 ++++++ botanjs/src/Dandelion/CSSAnimations/_this.css | 41 ++ botanjs/src/Dandelion/CSSAnimations/_this.js | 5 + botanjs/src/Dandelion/CSSReset.css | 43 ++ botanjs/src/Dandelion/CSSReset.js | 5 + botanjs/src/Dandelion/IDOMElement.js | 199 +++++++ botanjs/src/Dandelion/IDOMObject.js | 149 ++++++ botanjs/src/Dandelion/Swf/ExtAPI.css | 7 + botanjs/src/Dandelion/Swf/ExtAPI.js | 44 ++ botanjs/src/Dandelion/Swf/_this.css | 56 ++ botanjs/src/Dandelion/Swf/_this.js | 173 ++++++ botanjs/src/Dandelion/Window.js | 10 + botanjs/src/Dandelion/_this.js | 187 +++++++ botanjs/src/README.md | 64 +++ botanjs/src/System/Cycle/Trigger.js | 75 +++ botanjs/src/System/Cycle/_this.js | 108 ++++ botanjs/src/System/Debug.js | 46 ++ botanjs/src/System/Global.js | 16 + botanjs/src/System/Log.js | 46 ++ botanjs/src/System/Net/ClassLoader.js | 75 +++ botanjs/src/System/Net/_this.js | 141 +++++ botanjs/src/System/Policy/_this.js | 13 + botanjs/src/System/Tick.js | 50 ++ botanjs/src/System/_this.js | 3 + botanjs/src/System/utils/DataKey.js | 17 + botanjs/src/System/utils/EventKey.js | 19 + botanjs/src/System/utils/IKey.js | 49 ++ botanjs/src/System/utils/Perf.js | 49 ++ botanjs/src/System/utils/_this.js | 41 ++ botanjs/src/_this.js | 383 ++++++++++++++ botanjs/src/externs/BotanEvent.js | 16 + botanjs/src/externs/BotanJS.js | 18 + botanjs/src/externs/Components.MessageBox.js | 7 + ...Components.Mouse.Clipboard.SwfHelperObj.js | 9 + .../src/externs/Components.Mouse.Clipboard.js | 15 + .../externs/Components.Mouse.ContextMenu.js | 2 + botanjs/src/externs/Components.Mouse.js | 2 + botanjs/src/externs/Components.js | 2 + .../Dandelion.CSSAnimations.MovieClip.js | 14 + .../src/externs/Dandelion.CSSAnimations.js | 2 + botanjs/src/externs/Dandelion.IDOMElement.js | 23 + botanjs/src/externs/Dandelion.IDOMObject.js | 11 + botanjs/src/externs/Dandelion.Swf.ExtAPI.js | 5 + botanjs/src/externs/Dandelion.Swf.js | 7 + botanjs/src/externs/Dandelion.js | 38 ++ botanjs/src/externs/System.Cycle.Trigger.js | 11 + botanjs/src/externs/System.Cycle.js | 17 + botanjs/src/externs/System.Debug.js | 8 + botanjs/src/externs/System.Global.js | 8 + botanjs/src/externs/System.Log.js | 16 + botanjs/src/externs/System.Net.js | 11 + botanjs/src/externs/System.Policy.js | 5 + botanjs/src/externs/System.Tick.js | 13 + botanjs/src/externs/System.js | 2 + botanjs/src/externs/System.utils.DataKey.js | 4 + botanjs/src/externs/System.utils.EventKey.js | 10 + botanjs/src/externs/System.utils.IKey.js | 11 + botanjs/src/externs/System.utils.Perf.js | 8 + botanjs/src/externs/System.utils.js | 9 + cache/.keep | 0 logs/.keep | 0 settings.ini | 17 + 93 files changed, 4724 insertions(+) create mode 100644 .gitignore create mode 100755 botan-rebuild.py create mode 100755 botan-start.py create mode 100644 botanjs/__init__.py create mode 100644 botanjs/classmap.py create mode 100644 botanjs/compressor/__init__.py create mode 100755 botanjs/compressor/closure.py create mode 100755 botanjs/compressor/yui.py create mode 100755 botanjs/config.py create mode 100644 botanjs/service/__init__.py create mode 100644 botanjs/service/jclassresv.py create mode 100644 botanjs/service/jwork.py create mode 100644 botanjs/service/templates/test/Dandelian.CSSAnimations.MovieClip.html create mode 100644 botanjs/service/templates/test/System.Net.ClassLoader.html create mode 100644 botanjs/service/templates/test/System.utils.IKey.html create mode 100644 botanjs/service/templates/test_list.html create mode 100755 botanjs/service/webapi.py create mode 100644 botanjs/src/Components/Console.css create mode 100644 botanjs/src/Components/Console.js create mode 100644 botanjs/src/Components/DockPanel.css create mode 100644 botanjs/src/Components/DockPanel.js create mode 100644 botanjs/src/Components/MessageBox.css create mode 100644 botanjs/src/Components/MessageBox.js create mode 100644 botanjs/src/Components/Mouse/Clipboard.css create mode 100644 botanjs/src/Components/Mouse/Clipboard.js create mode 100644 botanjs/src/Components/Mouse/ContextMenu.css create mode 100644 botanjs/src/Components/Mouse/ContextMenu.js create mode 100644 botanjs/src/Components/Mouse/_this.js create mode 100644 botanjs/src/Components/_this.js create mode 100644 botanjs/src/Dandelion/CSSAnimations/MovieClip.css create mode 100644 botanjs/src/Dandelion/CSSAnimations/MovieClip.js create mode 100644 botanjs/src/Dandelion/CSSAnimations/_this.css create mode 100644 botanjs/src/Dandelion/CSSAnimations/_this.js create mode 100644 botanjs/src/Dandelion/CSSReset.css create mode 100644 botanjs/src/Dandelion/CSSReset.js create mode 100644 botanjs/src/Dandelion/IDOMElement.js create mode 100644 botanjs/src/Dandelion/IDOMObject.js create mode 100644 botanjs/src/Dandelion/Swf/ExtAPI.css create mode 100644 botanjs/src/Dandelion/Swf/ExtAPI.js create mode 100644 botanjs/src/Dandelion/Swf/_this.css create mode 100644 botanjs/src/Dandelion/Swf/_this.js create mode 100644 botanjs/src/Dandelion/Window.js create mode 100644 botanjs/src/Dandelion/_this.js create mode 100644 botanjs/src/README.md create mode 100644 botanjs/src/System/Cycle/Trigger.js create mode 100644 botanjs/src/System/Cycle/_this.js create mode 100644 botanjs/src/System/Debug.js create mode 100644 botanjs/src/System/Global.js create mode 100644 botanjs/src/System/Log.js create mode 100644 botanjs/src/System/Net/ClassLoader.js create mode 100644 botanjs/src/System/Net/_this.js create mode 100644 botanjs/src/System/Policy/_this.js create mode 100644 botanjs/src/System/Tick.js create mode 100644 botanjs/src/System/_this.js create mode 100644 botanjs/src/System/utils/DataKey.js create mode 100644 botanjs/src/System/utils/EventKey.js create mode 100644 botanjs/src/System/utils/IKey.js create mode 100644 botanjs/src/System/utils/Perf.js create mode 100644 botanjs/src/System/utils/_this.js create mode 100644 botanjs/src/_this.js create mode 100644 botanjs/src/externs/BotanEvent.js create mode 100644 botanjs/src/externs/BotanJS.js create mode 100644 botanjs/src/externs/Components.MessageBox.js create mode 100644 botanjs/src/externs/Components.Mouse.Clipboard.SwfHelperObj.js create mode 100644 botanjs/src/externs/Components.Mouse.Clipboard.js create mode 100644 botanjs/src/externs/Components.Mouse.ContextMenu.js create mode 100644 botanjs/src/externs/Components.Mouse.js create mode 100644 botanjs/src/externs/Components.js create mode 100644 botanjs/src/externs/Dandelion.CSSAnimations.MovieClip.js create mode 100644 botanjs/src/externs/Dandelion.CSSAnimations.js create mode 100644 botanjs/src/externs/Dandelion.IDOMElement.js create mode 100644 botanjs/src/externs/Dandelion.IDOMObject.js create mode 100644 botanjs/src/externs/Dandelion.Swf.ExtAPI.js create mode 100644 botanjs/src/externs/Dandelion.Swf.js create mode 100644 botanjs/src/externs/Dandelion.js create mode 100644 botanjs/src/externs/System.Cycle.Trigger.js create mode 100644 botanjs/src/externs/System.Cycle.js create mode 100644 botanjs/src/externs/System.Debug.js create mode 100644 botanjs/src/externs/System.Global.js create mode 100644 botanjs/src/externs/System.Log.js create mode 100644 botanjs/src/externs/System.Net.js create mode 100644 botanjs/src/externs/System.Policy.js create mode 100644 botanjs/src/externs/System.Tick.js create mode 100644 botanjs/src/externs/System.js create mode 100644 botanjs/src/externs/System.utils.DataKey.js create mode 100644 botanjs/src/externs/System.utils.EventKey.js create mode 100644 botanjs/src/externs/System.utils.IKey.js create mode 100644 botanjs/src/externs/System.utils.Perf.js create mode 100644 botanjs/src/externs/System.utils.js create mode 100644 cache/.keep create mode 100644 logs/.keep create mode 100644 settings.ini diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..19f98d7 --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +*~ +*.swp +*.pyc +__pycache__ +cache/* +logs/* diff --git a/README.md b/README.md index 27aa44c..b831f24 100644 --- a/README.md +++ b/README.md @@ -6,3 +6,33 @@ A working concept of Js/Css framework for web browsers - Python-like, class oriented syntax structure - Everything is merged into one file for that page - css class inheritance + +### Disclaimer +- This is a working concept. So it works on me. And may have a bunch of useless dependency. Use at your own risks! +- It requires Python 3! + + +### Documentation +- Will be added later + +### Prerequisties +#### For Service.WebAPI +- pip install Flask +- pip install Celery +- pip install redis +- pip install compressinja + +#### Environment varialbles +``` +PYTHONPATH= +``` + +#### For the compressor & cache, run: +``` +celery -A botanjs.service.jwork worker +``` + +#### For the API Serivces, run: +``` +./service/webapi.py +``` diff --git a/botan-rebuild.py b/botan-rebuild.py new file mode 100755 index 0000000..3c89c0a --- /dev/null +++ b/botan-rebuild.py @@ -0,0 +1,12 @@ +#!/usr/bin/env python3 +import os, sys +sys.path.append( os.path.abspath( "." ) ) + +from botanjs.service.jwork import app, JWork +from botanjs.config import Config as config + +bmap = os.path.join( config["Paths"]["Cache"], "botanjs", "bmap.xml" ) + +app.conf.update( BROKER_URL = config["BotanJS"]["CeleryBroker"] ) + +JWork.buildClassMap.delay( config["BotanJS"]["SrcDir"], bmap ) diff --git a/botan-start.py b/botan-start.py new file mode 100755 index 0000000..4e9fce3 --- /dev/null +++ b/botan-start.py @@ -0,0 +1,75 @@ +#!/usr/bin/env python3 + +import os, pwd, grp +from botanjs.config import Config as config + +def drop_privileges( uid_name='nobody', gid_name='nogroup' ): + # Get the uid/gid from the name + running_uid = pwd.getpwnam( uid_name ).pw_uid + running_gid = grp.getgrnam( gid_name ).gr_gid + + current_uid = os.getuid() + + if current_uid != 0: + if running_uid == current_uid: + return True + print( "Service must be started by root" ) + return False + + # Remove group privileges + os.setgroups([]) + + # Try setting the new uid/gid + os.setgid( running_gid ) + os.setuid( running_uid ) + + # Ensure a very conservative umask + old_umask = os.umask( 0o022 ) + + return True + +import shutil + +# Create the lock folder for celery +lockDir = "/var/run/celery" +os.makedirs( lockDir, exist_ok=True ) +shutil.chown( lockDir, config["Service"]["user"] ) + +# Imediately drop the root privilege +if drop_privileges( config["Service"]["user"], config["Service"]["group"] ) != True: + exit() + +import sys +from subprocess import Popen + +sys.path.append( os.path.abspath( "." ) ) + +from botanjs.service.webapi import WebAPI + +if __name__ == "__main__": + + jwork = "botanjs.service.jwork" + nodeName = "botanNode1" + + Popen([ + "celery" + , "multi" + , "restart" + , nodeName + , "-A" + , jwork + , "worker" + , "--pidfile=/var/run/celery/" + jwork + ".pid" + , "--logfile=" + os.path.join( config["Paths"]["Log"], jwork + ".log" ) + , "--workdir=" + config["Paths"]["Runtime"] + , "beat" + , "-l" + , "info" + ]).communicate() + + WebAPI( + jsCache = config["Paths"]["Cache"] + , jsRoot = config["BotanJS"]["SrcDir"] + , brokerURL = config["BotanJS"]["CeleryBroker"] + ) + diff --git a/botanjs/__init__.py b/botanjs/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/botanjs/classmap.py b/botanjs/classmap.py new file mode 100644 index 0000000..bb9b386 --- /dev/null +++ b/botanjs/classmap.py @@ -0,0 +1,193 @@ +#!/usr/bin/env python3 + +import os; +import re; +import sys; + +from xml.dom import minidom +from collections import defaultdict + +RegEx_N = re.compile( r""" + .* + __namespace + \s*\( + \s*(['"])([^\1]+)\1 + \s*\) + .* + """, re.X ) + +RegEx_I = re.compile( r""" + .* + __import + \s*\( + \s*(['"])([^\1]+)\1 + \s*\) + .* + """, re.X ) + +RegEx_V = re.compile( r""" + .* + ns + \s*\[ + \s*NS_INVOKE + \s*\] + \s*\( + \s*(['"])([^\1]+)\1 + \s*\) + .* + """, re.X ) + +RegEx_E = re.compile( r""" + .* + ns + \s*\[ + \s*NS_EXPORT + \s*\] + \s*\( + \s*EX_([A-Z_]+[A-Z]) + \s*, + \s*(['"])([^\1]+)\2 + \s*, + [^\)]+ + \s*\) + .* + """, re.X ) + +def classMeta( cf ): + ns = "" + imps = list() + exps = list() + for line in open( cf, "r" ): + + m = RegEx_N.match( line ) + if m: + ns = m.group(2) + continue + + m = RegEx_I.match( line ) + if m: + imps.append( m.group(2) ) + continue + + m = RegEx_V.match( line ) + if m: + imps.append( ns + "." + m.group(2) ) + continue + + m = RegEx_E.match( line ) + if m: + exps.append( [ m.group(1), m.group(3) ] ) + continue + + return [ ns, imps, exps ] + +def className( classFile ): + return ( os.path + .splitext( classFile )[0] + .replace( os.sep, "." ) + .replace( "._this", "" ) + .replace( "..BotanJS.", "" ) ) + +# __export types definition => nodeName +EX_CLASS = "class" +EX_FUNC = "method" +eDef = defaultdict( lambda: 'prop', { "CLASS": EX_CLASS, "FUNC": EX_FUNC } ) + +class ClassMap: + head = None + DOM = None + R = None + + def __init__( self, BotanRoot ): + self.R = BotanRoot + self.DOM = minidom.parseString( "" ) + head = os.path.join( self.R, "_this.js" ) + + def getNode( self, name, t = EX_CLASS ): + paths = name.split( "." ) + + currentNode = self.DOM.firstChild + + # Step down the path and create the path if necessary + for path in paths: + + l = currentNode.childNodes + for i in l: + if i.getAttribute( "name" ) == path: + currentNode = i + break + + if currentNode.getAttribute( "name" ) != path: + newNode = self.DOM.createElement( t ) + newNode.setAttribute( "name", path ) + currentNode.appendChild( newNode ) + currentNode = newNode + + return currentNode + + + + def skipFile( self, cf ): + + if os.path.splitext( cf )[1] == ".js": + if cf == self.head: + return True + return False + + return True; + + def drawMap( self, ns, ci, ce, cf ): + nsNode = self.getNode( ns ) + + # Source every: + # Since namespace may differ from file name + # ns.__export may export to a different level + # Source the exported val explicitly means + # exports only available when source file is imported + srcEvery = ( ns != className( cf ) ) + + cf = cf.replace( self.R, "" ) + + if not srcEvery: + nsNode.setAttribute( "src", cf ) + + for ex in ce: + _t = eDef[ ex[0] ] + cNode = self.getNode( ns + "." + ex[1], t = _t ) + + if srcEvery: + # The import is for the defined class + if _t == EX_CLASS: + for imp in ci: + impNode = self.DOM.createElement( "import" ) + impNode.appendChild( self.DOM.createTextNode( imp ) ) + cNode.appendChild( impNode ) + + cNode.setAttribute( "src", cf ) + + # the file dose not export classes + # Hence it import for itself + if not srcEvery: + for imp in ci: + impNode = self.DOM.createElement( "import" ) + impNode.appendChild( self.DOM.createTextNode( imp ) ) + nsNode.appendChild( impNode ) + + + def build( self ): + for root, dirs, files in os.walk( self.R ): + + if root == self.R: + dirs.remove("externs") + + for name in files: + classFile = os.path.join( root, name ) + + if self.skipFile( classFile ): + continue + + ns, ci, ce = classMeta( classFile ) + classFile = classFile.replace( self.R + os.path.sep, "" ) + self.drawMap( ns, ci, ce, classFile ) + return self.DOM.toxml() + diff --git a/botanjs/compressor/__init__.py b/botanjs/compressor/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/botanjs/compressor/closure.py b/botanjs/compressor/closure.py new file mode 100755 index 0000000..a36d87e --- /dev/null +++ b/botanjs/compressor/closure.py @@ -0,0 +1,51 @@ +#!/usr/bin/env python3 + +import os +from tempfile import NamedTemporaryFile + +COMPILER = "/opt/utils/closure.jar" + +if not os.path.isfile( COMPILER ): + raise Exception( "Compiler not found" ) + + +COMPILER_OPTIONS = [ + "--compilation_level ADVANCED_OPTIMIZATIONS" + , "--output_wrapper=\"(function(){%output%})();\"" +] + + +class Wrapper: + + C = None + # externs + E = "" + + def __init__( self ): + self.C = "java -jar "+ COMPILER + " " + " ".join( COMPILER_OPTIONS ) + + def scanExterns( self, sdir ): + for root, dirs, files in os.walk( sdir ): + # Split file extensions + files = list( os.path.splitext( x ) for x in files ) + files.sort() + for f in files: + files.remove( f ) if f[1] != ".js" else None + + self.E = " --externs " + " --externs ".join( + os.path.join( root, x ) + # join back extensions + for x in list( "".join( x ) for x in files ) + ) + break + + def compress( self, loc ): + content = "" + with open( loc, "rb" ) as f: + content = f.read() + + with NamedTemporaryFile() as f: + f.write( content[12:-5] ) + os.system( self.C + self.E + " --js " + f.name + " --js_output_file " + loc[:-3] + ".c.js" ) + + diff --git a/botanjs/compressor/yui.py b/botanjs/compressor/yui.py new file mode 100755 index 0000000..99341d6 --- /dev/null +++ b/botanjs/compressor/yui.py @@ -0,0 +1,23 @@ +#!/usr/bin/env python3 + +import os + +COMPILER = "/opt/utils/yuicompressor.jar" + +if not os.path.isfile( COMPILER ): + raise Exception( "Compiler not found" ) + +COMPILER_OPTIONS = [ + "--type css" +] + +class Wrapper: + + C = None + + def __init__( self ): + self.C = "java -jar " + COMPILER + " " + " ".join( COMPILER_OPTIONS ) + + def compress( self, loc ): + os.system( self.C + " " + loc + " -o " + loc[:-4] + ".c.css" ) + diff --git a/botanjs/config.py b/botanjs/config.py new file mode 100755 index 0000000..31eaaa7 --- /dev/null +++ b/botanjs/config.py @@ -0,0 +1,5 @@ +#!/usr/bin/env python3 +import configparser + +Config = configparser.ConfigParser( interpolation = configparser.ExtendedInterpolation() ) +Config.read( "settings.ini" ) diff --git a/botanjs/service/__init__.py b/botanjs/service/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/botanjs/service/jclassresv.py b/botanjs/service/jclassresv.py new file mode 100644 index 0000000..fca9931 --- /dev/null +++ b/botanjs/service/jclassresv.py @@ -0,0 +1,335 @@ + +import os +import re +import base64 +import zlib +import hashlib +import xml.etree.ElementTree as ET + +PY_SEP = os.path.sep + +def wrapScope( src ): + return "(function(){" + src + "})();" + +class Resolver: + resolved = None + + bMap = None + parentMap = None + + EX_PROP = "prop" + EX_FUNC = "method" + EX_CLASS = "class" + + def __init__( self, classMap ): + self.classMap = classMap + self._reload() + + def _reload( self ): + self.bMap = ET.parse( self.classMap ) + # ElementTree does not support Element.find( ".." ) + # Make a parent map to work around + self.parentMap = { c:p for p in self.bMap.iter() for c in p } + + self.resolved = [] + + def resource( self, elem ): + if "src" in elem.attrib: + return elem.attrib[ "src" ] + + parent = self.parentMap[ elem ] + + if parent != None: + return self.resource( parent ) + + def resolve( self, c, classList ): + self.resolved = [] + self.__resolve( c, classList ) + + def __resolve( self, c, classList ): + + lista = list( "[@name=\"" + x + "\"]" for x in c.split(".") ) + + fx = "/".join( self.EX_CLASS + x for x in lista[:-1] ) + + it = lista[-1] + # Test if class + elem = self.bMap.find( ".//" + fx + self.EX_CLASS + it ) + + if elem == None: + if fx != '': fx += "/" + + # Test if prop + elem = self.bMap.find( ".//" + fx + self.EX_PROP + it ) + + # test if func + if elem == None: + elem = self.bMap.find( ".//" + fx + self.EX_FUNC + it ) + + if elem == None: + raise LookupError( "No such class: " + c ) + + imports = self.parentMap[ elem ].findall( "import" ) + + else: + imports = elem.findall( "import" ) + + self.resolved.append( c ) + + for imp in imports: + if imp.text not in self.resolved: + self.__resolve( imp.text, classList ) + + classList.append([ c, elem ]) + +class BotanClassResolver: + R = "" + CR = None + + classMap = "" + flagCompress = True + returnHash = False + resv = None + + def __init__( self, jwork, BotanRoot, classMap, cacheRoot ): + + self.JWork = jwork; + self.R = os.path.abspath( BotanRoot ) + self.CR = os.path.abspath( cacheRoot ) + + os.makedirs( self.CR, 0o755, exist_ok = True ) + + if not os.path.exists( classMap ): + self.JWork.buildClassMap( self.R, classMap ) + + self.resv = Resolver( classMap ) + + def BotanFile( self, t ): + content = "" + with open( os.path.join( self.R, t ), "r" ) as f: + content = f.read() + + return content + + def BotanCache( self, t ): + content = "" + with open( t, "r" ) as f: + content = f.read() + + return content + + def cleanList( self, lista ): + olist = [] + for i in lista: + if i not in olist: + olist.append( i ) + return olist + + def jsLookup( self, classList, classFiles ): + for c in classList: + src = self.resv.resource( c[1] ) + + if src == None: + raise LookupError( "Cannot find src file for: " + c[0] ) + + if src not in classFiles: + classFiles.append( src ) + + def cssLookup( self, jsList, cssList ): + + for f in jsList: + possibleList = [] + + cssFile = os.path.splitext( f )[0] + ".css" + + if cssFile not in possibleList: + possibleList.append( cssFile ) + + f = f.split( PY_SEP ) + l = len( f ) + + for i in range( 1, l ): + cssFile = PY_SEP.join( x for x in f[:-i] ) + PY_SEP + "@_this.css" + if cssFile not in possibleList: + possibleList.append( cssFile ) + + possibleList.sort() + + for f in possibleList: + f = f.replace( "@_this.css", "_this.css" ) + if os.path.exists( os.path.join( self.R, f ) ): + cssList.append( f ) + + + def getCache( self, fileList, cName, mode ): + if self.CR == None: + return None + + md5 = hashlib.md5( bytearray( "".join( fileList ), "utf-8" ) ).hexdigest() + + cName[0] = oFHash = md5 + "." + mode + cFHash = md5 + ".c." + mode + + # Raw file + oFile = os.path.join( self.CR, oFHash ) + # Compressed file + cFile = os.path.join( self.CR, cFHash ) + + dates = list( + os.path.getmtime( os.path.join( self.R, x ) ) + if os.path.exists( os.path.join( self.R, x ) ) else -1 + for x in fileList + ) + + # Root file date + dates.append( os.path.getmtime( os.path.join( self.R, "_this.js" ) ) ); + + if self.useCache( cFile, dates ) and self.flagCompress == True: + return cFHash if self.returnHash else self.BotanCache( cFile ) + + elif self.useCache( oFile, dates ): + self.JWork.saveCache.delay( + oFile + # Content is None to initiate a compression + , None + , mode + , os.path.join( self.R, "externs" ) + ) + + return oFHash if self.returnHash else self.BotanCache( oFile ) + + def useCache( self, f, dList ): + if not os.path.exists( f ): + return False + + t = os.path.getmtime( f ) + + for i in dList: + if t < i: + return False + + return True + + def compileJs( self, cList, xList ): + md5 = [ None ] + + for x in xList: + cList.remove( x ) if x in cList else None + + cacheFile = self.getCache( cList, md5, "js" ) + + if cacheFile != None: + return cacheFile; + + # The root file + outputJs = self.BotanFile( "_this.js" ) + + + for f in cList: + path = ( + os.path.splitext( f )[0] + .replace( PY_SEP, "." ) + .replace( "._this", "" ) + ) + struct = ";BotanJS.define( \"" + path + "\" );" + + outputJs += struct + self.BotanFile( f ) + + outputJs = wrapScope( outputJs ) + + [ self.JWork.saveCache if self.returnHash else self.JWork.saveCache.delay ][0] ( + os.path.join( self.CR, md5[0] ) + , outputJs + , "js" + , os.path.join( self.R, "externs" ) + ) + + if self.returnHash: + return md5[0] + + return outputJs + + def compileCss( self, cList, xList ): + cssIList = [] + cssXList = [] + self.cssLookup( cList, cssIList ) + self.cssLookup( xList, cssXList ) + + cList = [] + xList = cssXList + + for x in cssIList: + cList.append( x ) if x not in xList else None + + md5 = [ None ] + cacheFile = self.getCache( cList, md5, "css" ) + + if cacheFile != None: + return cacheFile; + + outputCss = "" + + for f in self.cleanList( cList ): + outputCss += self.BotanFile( f ) + + [ self.JWork.saveCache if self.returnHash else self.JWork.saveCache.delay ][0] ( + os.path.join( self.CR, md5[0] ), outputCss, "css" + ) + + if self.returnHash: + return md5[0] + + return outputCss + + def getAPI( self, code, mode ): + self.flagCompress = True + # Should reload on debug mode only + self.resv._reload() + flag = mode[0] + requestAPIs = code + sp = "/" + + if flag == "o": + mode = mode[1:] + elif flag == "r": + mode = mode[1:] + self.flagCompress = False + else: + self.returnHash = True + requestAPIs = ( + # decode -> decompress -> split + zlib.decompress( base64.b64decode( code, None, True ) ) + .decode( "utf-8" ) + ) + sp = "," + + # strip malicious + requestAPIs = ( + requestAPIs + .replace( "[^A-Za-z\.\*" + re.escape( sp ) + " ]", "" ) + .split( sp ) + ) + + imports = [] + excludes = [] + + for apis in requestAPIs: + + if apis == None: continue + + classList = [] + lookupList = imports + + if apis[0] == "-": + apis = apis[1:] + lookupList = excludes + + self.resv.resolve( apis, classList ) + self.jsLookup( classList, lookupList ) + + if mode == "js": + return self.compileJs( imports, excludes ) + elif mode == "css": + return self.compileCss( imports, excludes ) + + raise TypeError( "Invalid mode: " + js ) diff --git a/botanjs/service/jwork.py b/botanjs/service/jwork.py new file mode 100644 index 0000000..a6e7546 --- /dev/null +++ b/botanjs/service/jwork.py @@ -0,0 +1,49 @@ +#!/usr/bin/env python3 +import os +from celery import Celery +from celery.utils.log import get_task_logger +from botanjs.compressor.closure import Wrapper as ClosureWrapper +from botanjs.compressor.yui import Wrapper as YUIWrapper +from botanjs.classmap import ClassMap + +app = Celery( "botanJWork" ) +log = get_task_logger( __name__ ) + +if os.path.exists( "settings.ini" ): + from botanjs.config import Config + app.conf.update( BROKER_URL = Config["BotanJS"]["CeleryBroker"] ) + +class JWork: + + @app.task() + def saveCache( location, content = None, mode = None, externs = "" ): + if content != None: + log.info( "Writing file(" + str( len( content ) ) + "): " + os.path.abspath( location ) ) + with open( location, "w" ) as f: + f.write( content ) + + if mode == "js": + JWork.compressJs.delay( location, externs ) + elif mode == "css": + JWork.compressCss.delay( location ) + + @app.task() + def compressJs( md5, externs ): + log.info( "Compress js: " + md5 ) + w = ClosureWrapper() + w.scanExterns( externs ) + w.compress( md5 ) + + @app.task() + def compressCss( md5 ): + log.info( "Compress css: " + md5 ) + w = YUIWrapper() + w.compress( md5 ) + + @app.task() + def buildClassMap( src, location ): + log.info( "Building Class Map" ) + c = ClassMap( src ) + + with open( location, "w" ) as f: + f.write( c.build() ) diff --git a/botanjs/service/templates/test/Dandelian.CSSAnimations.MovieClip.html b/botanjs/service/templates/test/Dandelian.CSSAnimations.MovieClip.html new file mode 100644 index 0000000..12bc6be --- /dev/null +++ b/botanjs/service/templates/test/Dandelian.CSSAnimations.MovieClip.html @@ -0,0 +1,40 @@ + + +Botan JS - Test + + + + + + + + + diff --git a/botanjs/service/templates/test/System.Net.ClassLoader.html b/botanjs/service/templates/test/System.Net.ClassLoader.html new file mode 100644 index 0000000..398e9b1 --- /dev/null +++ b/botanjs/service/templates/test/System.Net.ClassLoader.html @@ -0,0 +1,25 @@ + + +Botan JS - Test + + + + + + + + diff --git a/botanjs/service/templates/test/System.utils.IKey.html b/botanjs/service/templates/test/System.utils.IKey.html new file mode 100644 index 0000000..bedef20 --- /dev/null +++ b/botanjs/service/templates/test/System.utils.IKey.html @@ -0,0 +1,13 @@ + + +Botan JS - Test + + + + + + + diff --git a/botanjs/service/templates/test_list.html b/botanjs/service/templates/test_list.html new file mode 100644 index 0000000..4732e8b --- /dev/null +++ b/botanjs/service/templates/test_list.html @@ -0,0 +1,19 @@ + + +Botan JS - List of Tests + + +
+{% for d in data %}
+    {{ d }}
+    
+{% endfor %} +
+ + diff --git a/botanjs/service/webapi.py b/botanjs/service/webapi.py new file mode 100755 index 0000000..db3ef88 --- /dev/null +++ b/botanjs/service/webapi.py @@ -0,0 +1,72 @@ +#!/usr/bin/env python3 +from flask import Flask +from flask import Response +from flask import render_template +from botanjs.service.jclassresv import BotanClassResolver as JCResv +from botanjs.service.jwork import app as CeleryApp, JWork +import os + +class WebAPI: + + app = None + + BRoot = None + BMap = None + BCache = None + + def __init__( self, jsRoot = "../src", jsCache = "/tmp", brokerURL = None ): + + self.test_templates = os.path.join( + os.path.dirname( os.path.realpath( __file__ ) ) + , "templates" + , "test" + ) + + self.BRoot = os.path.abspath( jsRoot ) + self.BCache = os.path.join( jsCache, "botanjs" ) + self.BMap = os.path.join( self.BCache, "bmap.xml" ) + + if brokerURL != None: + CeleryApp.conf.update( BROKER_URL = brokerURL ) + + self.app = Flask( __name__, static_url_path = '', static_folder = self.BCache ) + self.app.jinja_env.add_extension( "compressinja.html.HtmlCompressor" ) + + self.app.add_url_rule( "/test" , view_func = self.r_test_list ) + self.app.add_url_rule( "/test/" , view_func = self.r_test ) + self.app.add_url_rule( "//" , view_func = self.api_request ) + + self.app.run( host="0.0.0.0" ) + + def r_test_list( self ): + for root, dirs, files in os.walk( self.test_templates ): + break + + files.sort() + files = ( os.path.splitext( x )[0] for x in files ) + + return render_template( "test_list.html", data = files ) + + def r_test( self, test_file ): + return render_template( os.path.join( "test", test_file + ".html" ) ) + + + def api_request( self, mode, code ): + try: + t = mode[1:] + if t == "js": + t = "application/javascript" + elif t == "css": + t = "text/css" + + srvHandler = JCResv( JWork, self.BRoot, self.BMap, self.BCache ) + return Response( srvHandler.getAPI( code, mode = mode ), mimetype = t ) + except LookupError as e: + return str(e), 404 + # except Exception as e: + # return str(e), 404 + + return "Invalid request", 404 + +if __name__ == "__main__": + WebAPI() diff --git a/botanjs/src/Components/Console.css b/botanjs/src/Components/Console.css new file mode 100644 index 0000000..625abb9 --- /dev/null +++ b/botanjs/src/Components/Console.css @@ -0,0 +1,71 @@ +.dbg_statusbar { +} + +.dbg_title { + padding-bottom: 0.2em; + float: left; +} + +.dbg_lastMsg { + float: left; + font-family: monospace; + color: #AAA; + font-size: 1em; + + white-space: nowrap; + max-width: 580px; + overflow: hidden; + text-overflow: ellipsis; +} + +.dbg_led { + position: absolute; + right: 0.5em; + + color: coral; + + font-size: 0.75em; + text-shadow: 0 0 2px; +} + +#dbg_led[error] { + color: red !important; +} + + +#time_stmp { + position: fixed; + bottom: 0; + right: 0; + font-size: 12px; + font-family: Arial,Helvetica,sans-serif; + padding: 0.5em; + background-color: rgba(0, 0, 0, 0.8); + color: white; +} + +#debugCons[expanded] { + top: 0 !important; +} + +#debugCons{ + z-index: 99; +} + +#debugWrap { + white-space: nowrap; +} + +#debugWrap textarea.response { + line-height: 1.2; + height: 350px; + padding: 0.2em; + + width: 800px; + color: #AAA; + background: #333; + outline: none; + border: none; + + font-family: monospace; +} diff --git a/botanjs/src/Components/Console.js b/botanjs/src/Components/Console.js new file mode 100644 index 0000000..0121d22 --- /dev/null +++ b/botanjs/src/Components/Console.js @@ -0,0 +1,177 @@ +(function(){ + // Logger + // log things. + var ns = __namespace( "Components" ); + + /** @type {System.utils.Perf} */ + var Perf = __import( "System.utils.Perf" ); + /** @type {System.Cycle} */ + var Cycle = __import( "System.Cycle" ); + /** @type {System.Cycle.Tick} */ + var sTick = __import( "System.Cycle.TICK" ); + /** @type {System.Global} */ + var _global = __import( "System.Global" ); + /** @type {System.Log} */ + var Log = __import( "System.Log" ); + /** @type {System.Debug} */ + var debug = __import( "System.Debug" ); + /** @type {Dandelion} */ + var Dand = __import( "Dandelion" ); + /** @type {Dandelion.IDOMElement} */ + var IDOMElement = __import( "Dandelion.IDOMElement" ); + /** @type {Components.DockPanel} */ + var DockPanel = __import( "Components.DockPanel" ); + + var objTreeView = function( obj, level, prepend ) + { + var c = ""; + for (var p in obj) + { + if(typeof(obj[p]) == "object") + { + c += + prepend + Array( level + 1 ).join(" ") + + p + ":\n" + + objTreeView( + obj[p] + , level + 2 + , 0 < level ? prepend : Array( prepend.length ).join(" ") + ); + } + else + { + c += prepend + Array(level + 1).join(" ") + p + ": " + obj[p] + "\n"; + } + } + return c; + }; + + var Console = function () + { + var stage = null + , response_txt = null + , lastMsg = null + , time_txt = null + , otop = "" + , cycle = 0 + , sampling = 500 + , led = null + + , ticking = function () { + if( debugEnv ) + { + time_txt.innerHTML = ( sTick.count - cycle ) + " cps, Sampling " + sampling + "ms"; + cycle = sTick.count; + if(led) led.style.color = "yellowgreen"; + } + } + + , writeLine = function ( dat, type ) + { + var res_txt = response_txt; + + res_txt.value += "\n" + ( dat = ( dat != undefined ? dat.toString() : "undefined" ) ); + + lastMsg.textContent = lastMsg.innerText = dat; + + // disabling color will make led blink since ticking is frequently setting the color to default + led.style.color = ""; + if( otop ) stage.style.top = otop; + res_txt.scrollTop = res_txt.scrollHeight; + } + + , writeError = function (dat) + { + writeLine( dat ); + led.setAttribute( "error", 1 ); + stage.setAttribute( "expanded", 1 ); + } + , LogHandle = function( mesg, type ) + { + if( type == Log.ERROR ) writeError( mesg ); + else writeLine( mesg ); + } + ; + + + response_txt = Dand.wrap('textarea', null, 'response'); + // Time stamp on the bottom right corner + time_txt = Dand.wrap('span', 'time_stmp'); + + // append child + document.body.appendChild(time_txt); + + response_txt.readOnly = true; + + stage = new DockPanel( + "debugCons" + , Dand.wrapc( + 'dbg_statusbar' + , [ + Dand.wrapc('dbg_title', "Debug Console(Press F9)") + , lastMsg = Dand.wrapc('dbg_lastMsg') + , led = Dand.wrap('div', 'dbg_led', 'dbg_led', '\u25CF') + ] + ) + , Dand.wrap( null, 'debugWrap', null, response_txt ) + , "dtop" + ); + + var istage = IDOMElement( stage ); + + Cycle.next( + function () + { + // get otop + otop = this.getDAttribute("top"); + }.bind( istage ) + ); + + var autoHide = function () { this.style.top = ""; }.bind(stage); + Cycle.perma('gTicker' + Perf.uuid, ticking, sampling); + Cycle.perma('gTicker' + Perf.uuid, autoHide, 3000); + debugEnv = true; + + ticking(); + + var f9Binding = function ( e ) + { + e = e || window.event; + if ( e.keyCode ) code = e.keyCode; + else if ( e.which ) code = e.which; + + if ( code == 120 ) + { + if( this.hasAttribute( "expanded" ) ) + { + this.removeAttribute( "expanded" ); + led.hasAttribute( "error" ) && led.removeAttribute( "error" ); + this.style.top = otop; + } + else + { + this.setAttribute( "expanded", "1" ); + } + } + }.bind( stage ); + + //Attach the var with the event = function + if(document.addEventListener) document.addEventListener('keydown', f9Binding, false); + else if(document.attachEvent) document.attachEvent('onkeydown', f9Binding); + else document.onkeydown = f9Binding; + + this.log = writeLine; + this.logError = writeError; + + Log.registerHandler( LogHandle ); + // This will output the debug info + if( window["debug_info"] ) + { + debug.Info( objTreeView( debug_info, 0, "[Server] " ) ); + } + }; + + __static_method( Console, "objTreeView", objTreeView ); + + ns[ NS_EXPORT ]( EX_CLASS, "Console", Console ); +})(); diff --git a/botanjs/src/Components/DockPanel.css b/botanjs/src/Components/DockPanel.css new file mode 100644 index 0000000..e5a5887 --- /dev/null +++ b/botanjs/src/Components/DockPanel.css @@ -0,0 +1,34 @@ +.right {text-align: right;} + +.window { + z-index: 99; + border: 1px darkgrey solid; + background: #222; +} + +.window > span { + display:-moz-inline-block; + display:-moz-inline-box; + display:inline-block; +} + +.titleBar { + font-family: custom-sans; + font-size: 1em; + padding: 0.3em 0.5em; + cursor: default; + color: white; +} + +div[class^="fdock"] { + position: fixed; + transition: all .5s ease-in-out; + -webkit-transition: all .5s ease-in-out; + -moz-transition: all .5s ease-in-out; +} + +div.dleft { left: 0; } +div.dtop { top: -100%; } +div.dright { right: 0; } +div.dbottom { bottom: 1.5em; } + diff --git a/botanjs/src/Components/DockPanel.js b/botanjs/src/Components/DockPanel.js new file mode 100644 index 0000000..ffbf92a --- /dev/null +++ b/botanjs/src/Components/DockPanel.js @@ -0,0 +1,54 @@ +(function(){ + var ns = __namespace( "Components" ); + + /** @type {System.Cycle} */ + var Cycle = __import( "System.Cycle" ); + /** @type {System.utils.DataKey} */ + var DataKey = __import( "System.utils.DataKey" ); + /** @type {Dandelion} */ + var Dand = __import( "Dandelion" ); + /** @type {Dandelion.IDOMElement} */ + var IDOMElement = __import( "Dandelion.IDOMElement" ); + + var DockPanel = function( w_id, w_title, w_content, align ) + { + var w_div = Dand.wrapc('window') + , w_titleBar = Dand.wrapc('titleBar', w_title) + ; + + if( align.indexOf('top') != -1 ) + { + w_div.appendChild( Dand.wrapc( 'contentPanel', w_content ) ); + w_div.appendChild( w_titleBar ); + w_div.style.position = "absolute"; + + Cycle.next(function () + { + w_div.style.transition = "none"; + w_div.style.top = -w_content.clientHeight + "px"; + IDOMElement( w_div ).setAttribute( new DataKey( "top", w_div.style.top ) ); + Cycle.next( function () { w_div.style.transition = ""; } ); + }); + } + else if( align.indexOf('bottom') != -1 ) + { + w_div.appendChild(w_titleBar); + w_div.appendChild( Dand.wrapc( 'contentPanel', w_content ) ); + + Cycle.next(function () + { + w_div.style.transition = "none"; + // w_div.style.bottom = String(w_content.clientHeight) + "px"; + // IDOMElement(w_div).addEventListeners(); + Cycle.next(function () { w_div.style.transition = ""; }); + }); + } + + w_div = Dand.wrap( null, w_id, 'fdock ' + align, w_div ); + + document.body.appendChild( w_div ); + return w_div; + }; + + ns[ NS_EXPORT ]( EX_CLASS, "DockPanel", DockPanel ); +})(); diff --git a/botanjs/src/Components/MessageBox.css b/botanjs/src/Components/MessageBox.css new file mode 100644 index 0000000..e8845cc --- /dev/null +++ b/botanjs/src/Components/MessageBox.css @@ -0,0 +1,62 @@ +.mbox_mask { + position: fixed; + width: 100%; + height: 100%; + top: 0; + left: 0; + background: rgba(0, 0, 0, 0.5); + z-index: 100; +} + +.mbox_body { + min-width: 350px; + min-height: 100px; + max-width: 800px; + max-height: 600px; + position: absolute; + background: #222; + + -moz-box-shadow: 0 0 10px black; + -webkit-box-shadow: 0 0 10px black; + box-shadow: 0 0 10px black; +} + +.mbox_titlebar { + font-size: 1.2em; + padding: 0.35em; + color: white; + background: #181818; +} + +.mbox_content { + min-height: 80px; + padding: 1em; + font-family: sans-serif; + color: white; + + /* + -moz-box-shadow: inset 0 10px 10px -10px black; + -webkit-box-shadow: inset 0 10px 10px -10px black; + box-shadow: inset 0 10px 10px -10px black; + */ +} + +.mbox_buttons { + text-align: right; + padding: 1em 0.5em; +} + +.mbox_button { + text-align: center; +} + +.mbox_button > span { + padding: 0.5em 1em; + margin: 0.2em; + color: white; + cursor: default; +} + +.mbox_button > span:hover { + background: orangered; +} \ No newline at end of file diff --git a/botanjs/src/Components/MessageBox.js b/botanjs/src/Components/MessageBox.js new file mode 100644 index 0000000..1d29cb5 --- /dev/null +++ b/botanjs/src/Components/MessageBox.js @@ -0,0 +1,91 @@ +(function(){ + var ns = __namespace( "Components" ); + + /** @type {System.Cycle} */ + var Trigger = __import( "System.Cycle.Trigger" ); + /** @type {Dandelion} */ + var Dand = __import( "Dandelion" ); + + // __import( "Dandelion.CSSAnimations" ); CSS_RESERVATION + + var MessageBox = function ( title, content, yes, no, handler ) + { + var _yes = Dand.wrap( + "span", null + , "mbox_button" + , Dand.wrap( "span", null, "comp flsf", yes || "OK" ) + ); + + // left right button + _yes.onclick = function() + { + // if handler is set + if( this.clickHandler ) this.clickHandler( true ); + document.body.removeChild( this.stage ); + this.stage = null; + }.bind( this ); + + if ( no ) + { + var _no = Dand.wrap( + "span", null + , "mbox_button" + , Dand.wrap( "span", null, "comp flsf", no ) + ); + + _no.onclick = function() + { + if( this.clickHandler ) this.clickHandler( false ); + document.body.removeChild( this.stage ); + this.stage = null; + }.bind( this ); + } + + + // set handler + if ( handler ) this.clickHandler = handler; + + this.stage = Dand.wrapc( + "mbox_mask" + , this.mbox = Dand.wrapc( + "mbox_body cubic500" + , [ + Dand.wrapc( "mbox_titlebar flsf", title ) + , Dand.wrapc( "mbox_content", content ) + , Dand.wrapc( "mbox_buttons", no ? [ _yes, _no ] : _yes ) + ] + ) + ); + }; + + MessageBox.prototype.setHandler = function( handler ) { this.clickHandler = handler }; + + MessageBox.prototype.show = function () + { + document.body.appendChild( this.stage ); + // Center the box + var m_style = this.mbox.style; + + m_style.transition = "none"; + m_style.top = m_style.left = "50%"; + m_style.marginLeft = String( -0.5 * this.mbox.clientWidth ) + "px"; + m_style.overflow = "hidden"; + m_style.minHeight = m_style.opacity = m_style.height = 0; + // The interval in firefox seems independent to etablishing element style + // using heightTriggers-hack instead + Trigger.height( + this.mbox, 0 + , function() + { + m_style.transition = m_style.minHeight = m_style.height = m_style.overflow = ""; + m_style.marginTop = String( -0.5 * this.mbox.clientHeight ) + "px"; + + m_style.opacity = 1; + }.bind( this ) + ); + + return this.stage; + }; + + ns[ NS_EXPORT ]( EX_CLASS, "MessageBox", MessageBox ); +})(); diff --git a/botanjs/src/Components/Mouse/Clipboard.css b/botanjs/src/Components/Mouse/Clipboard.css new file mode 100644 index 0000000..b1f3d45 --- /dev/null +++ b/botanjs/src/Components/Mouse/Clipboard.css @@ -0,0 +1,5 @@ +.ch_obj { + position: fixed; + /* 1-level higher than Context Menu*/ + z-index: 101; +} \ No newline at end of file diff --git a/botanjs/src/Components/Mouse/Clipboard.js b/botanjs/src/Components/Mouse/Clipboard.js new file mode 100644 index 0000000..73229d6 --- /dev/null +++ b/botanjs/src/Components/Mouse/Clipboard.js @@ -0,0 +1,131 @@ +(function(){ + var ns = __namespace( "Components.Mouse.Clipboard" ); + + /** @type {System.Global} */ + var Global = __import( "System.Global" ); + /** @type {System.Debug} */ + var debug = __import( "System.Debug" ); + /** @type {System.utils.Perf} */ + var Perf = __import( "System.utils.Perf" ); + /** @type {System.Cycle} */ + var Cycle = __import( "System.Cycle" ); + /** @type {Dandelion} */ + var Dand = __import( "Dandelion" ); + /** @type {Dandelion.Swf} */ + var Swf = __import( "Dandelion.Swf" ); + /** @type {Dandelion.Swf.ExtAPI} */ + var ExtAPI = __import( "Dandelion.Swf.ExtAPI" ); + + var stage + , helperAddress = "/assets/swf/iClipboard.swf" + , helperId + , cCallback + ; + + /** @type {Components.Mouse.Clipboard.SwfHelperObj */ + var clipboardHelper = null; + + var init = function () + { + if( stage ) return; + stage = Dand.wrapc('ch_obj no_transition no_transition_recursive'); + + if( Global.IE ) + { + document.body.appendChild(stage); + Cycle.next( + function (){ + stage.innerHTML = Swf.create( + helperAddress, 20, 20, helperId = Perf.uuid, 'always', 'transparent' + ); + } + ); + } + else + { + stage.appendChild( + Swf.create( + helperAddress, 20, 20, helperId = Perf.uuid, 'always', 'transparent' + ) + ); + + document.body.appendChild(stage); + } + + stage.style.visibility = "hidden"; + + ExtAPI.init(); + }; + + // Using onmouse properties since event needs to be unique. e.g. single handler + + // Capture mouse by trigger + var capture = function ( trigger, callback ) + { + cCallback = callback; + + document.onmousemove = function (e) + { + if( trigger() ) + { + Global.IE && (event || (event = e)); + stage.style.visibility = ""; + stage.style.left = ( e.pageX - 10 ) + "px"; + stage.style.top = ( e.pageY - 10 ) + "px"; + } + } + }; + + var setTextToCopy = function (textToCopy) + { + if( clipboardHelper && clipboardHelper.copy ) + { + clipboardHelper.copy( textToCopy ); + if( Global.debug && clipboardHelper.debug ) clipboardHelper.debug(); + } + else + { + // This will loop though cycle by cycle until the movie is ready + Cycle.next(function () { + clipboardHelper = Swf( helperId ); + setTextToCopy( textToCopy ); + }); + } + }; + + // Called by swf + var textCopied = function () + { + if( cCallback ) cCallback(); + + debug.Info( "[Clipboard] Text copied" ); + stage.style.visibility = "hidden"; + + // Release the focus on swf + clipboardHelper.blur(); + + document.onmousemove = null; + }; + + var onMouseOver = function ( callback ) + { + if( callback == undefined ) return stage.onmouseover; + stage.onmouseover = callback; + }; + + var onMouseOut = function ( callback ) + { + if( callback == undefined ) return stage.onmouseout; + stage.onmouseout = function () { + stage.style.visibility = "hidden"; + this._callback(); + }.bind({_callback: callback}); + }; + + ns[ NS_EXPORT ]( EX_FUNC, "init", init ); + ns[ NS_EXPORT ]( EX_FUNC, "setTextToCopy", setTextToCopy ); + ns[ NS_EXPORT ]( EX_FUNC, "capture", capture ); + ns[ NS_EXPORT ]( EX_VAR, "onMouseOver", onMouseOver ); + ns[ NS_EXPORT ]( EX_VAR, "onMouseOut", onMouseOut ); + ns[ NS_EXPORT ]( EX_FUNC, "_textCopied", textCopied ); +})(); diff --git a/botanjs/src/Components/Mouse/ContextMenu.css b/botanjs/src/Components/Mouse/ContextMenu.css new file mode 100644 index 0000000..887ecf5 --- /dev/null +++ b/botanjs/src/Components/Mouse/ContextMenu.css @@ -0,0 +1,54 @@ +.contextMenu { + display: none; + + cursor: default; + position: fixed; + /* 1 level higher than window */ + z-index: 100; + + min-width: 135px; + + font-size: 0.8em; + + font-family: sans-serif; +} + +.contextMenu ul > li { + padding: 0.8em 2em 0.8em 0.8em; + background: white; + position: relative; + + white-space: nowrap; +} + +.contextMenu ul > li:hover, .contextMenu ul > li[hover] { + background: #EEE; +} + +.contextMenu li > ul { + position: absolute; + top: 0; + min-width: 135px; + max-width: 200px; + left: 100%; +} + +.contextMenu li.expandable:after { + content: '\25b6'; + + position: absolute; + + width: 0.2em; + height: 100%; + + line-height: 0; + + top: 50%; + right: 1em; +} + +.contextMenu ul { + list-style-type: none; + background-color: white; + border: 1px solid #DDD; +} diff --git a/botanjs/src/Components/Mouse/ContextMenu.js b/botanjs/src/Components/Mouse/ContextMenu.js new file mode 100644 index 0000000..8a2a55a --- /dev/null +++ b/botanjs/src/Components/Mouse/ContextMenu.js @@ -0,0 +1,495 @@ +(function(){ + // Usage reference refers to Astroblog.AstroEdit.SiteLibrary::buildImageCanvas + var ns = __namespace( "Components.Mouse" ); + + /** @type {System.utils} */ + var utils = __import( "System.utils" ); + /** @type {System.utils.IKey} */ + var IKey = __import( "System.utils.IKey" ); + /** @type {System.utils.DataKey} */ + var DataKey = __import( "System.utils.DataKey" ); + /** @type {System.utils.EventKey} */ + var EventKey = __import( "System.utils.EventKey" ); + /** @type {System.Cycle} */ + var Cycle = __import( "System.Cycle" ); + /** @type {Dandelion} */ + var Dand = __import( "Dandelion" ); + /** @type {Dandelion.IDOMElement} */ + var IDOMElement = __import( "Dandelion.IDOMElement" ); + /** @type {Components.Mouse.Clipboard} */ + var Clipboard = __import( "Components.Mouse.Clipboard" ); + + + var ContextMenu = function ( target, items, whichButton, menuInsideTarget, overrides ) + { + if ( !target.id ) + throw new Error( "[ContextMenu] target's id is missing" ); + + if( !( items instanceof Array ) ) + throw new Error( "[ContextMenu] items is not an array" ); + + var stage = null + , mouseOnTarget = false + , mouseOnContext = false + , menuGroup = Dand.id("contextMenus") || ( + document.body.appendChild( Dand.wrap( null, "contextMenus", "compx" ) ) + ) + , targetParent + , temp, i, j + , _items = [] + + , getFuncOverride = function(prop) { return utils.objGetProp( overrides, prop, "Function" ); } + , getStrOverride = function(prop) { return utils.objGetProp( overrides, prop, "String" ); } + + , matchActions = function (element) + { + element = Dand.bubbleUp( element, isMenuItem ); + + for (i in _items) + { + // match attributes + if(element == _items[i].stage) + { + // perform action + return _items[i].key.handler(element); + } + } + return false; + } + + , isMenuItem = function(e) + { + if( e === document ) return false; + return IDOMElement(e).getDAttribute("menuItem"); + } + + , addMenuIdentifier = function(dataKey) + { + var d = new DataKey("menuItem", 1); + return dataKey ? [dataKey, d] : d; + } + + , contextMouseDown = function(event) + { + // IE is evil and doesn"t pass the event object + if (event == null) + event = window.event; + + // we assume we have a standards compliant browser, but check if we have IE + var target = event.target != null ? event.target : event.srcElement; + + // only show the context menu if the right mouse button is pressed + // and a hyperlink has been clicked (the code can be made more selective) + + if (event.button == 0) + matchActions(target) || hideMenu(); + else hideMenu(); + } + + , _chainHide = getFuncOverride("chainHide") + , _chainShow = getFuncOverride("chainShow") + , _hideMenu = getFuncOverride("hideMenu") + , hideMenu + + , _showMenu = getFuncOverride("showMenu") + , showMenu = function (event) + { + if (event == null) event = window.event; + // hide the menu first to avoid an "up-then-over" visual effect + if(_showMenu) + { + _showMenu(stage, event); + } + else + { + stage.style.display = "none"; + stage.style.left = event.clientX + "px"; + stage.style.top = event.clientY + "px"; + stage.style.display = "block"; + } + + if( hasCopyItem ) + { + Clipboard.capture(copyTrigger, hideMenu); + } + } + + , contextShow = function (event) + { + if(!mouseOnTarget) return false; + + showMenu(event); + return true; + } + + ,contextDelete = function () + { + targetParent.removeChild(stage); + } + + + , menuItems = [] + + , applyHover = function( elem ) + { + if( targetParent == elem ) return false; + + if( elem.nodeName == "LI" ) + { + elem.setAttribute( "hover", 1 ); + } + return true; + } + + , removeHover = function( elem ) + { + if( targetParent == elem ) return false; + + if( elem.nodeName == "LI" ) + { + elem.removeAttribute( "hover" ); + } + return true; + } + + , itemHover = function () + { + Dand.chainUpApply( this, applyHover ); + } + , itemOut = function () + { + Dand.chainUpApply( this, removeHover ); + } + , copyTrigger = function () { return mouseOverSwitch; } + + , mouseOverSwitch = false + , hasCopyItem = false + + , tryBindClipboard = function (target, evtKey) + { + // Event handler must return the string to copy + + if( evtKey.keyName.toUpperCase().indexOf("COPY") != -1 ) + { + Clipboard.init(); + // Handle clipboard events + hasCopyItem = true; + IDOMElement(target).addEventListeners( + [ + new EventKey("MouseOver", function () + { + mouseOverSwitch = true; + Clipboard.setTextToCopy( this.strcpy() ); + Clipboard.onMouseOver = itemHover.bind( this.stage ); + Clipboard.onMouseOut = itemOut.bind( this.stage ); + }.bind({ strcpy: evtKey.handler, stage: target }) + ) + + , new EventKey("MouseDown", function () + { + Clipboard.setTextToCopy( this.strcpy() ); + }.bind({ strcpy: evtKey.handler }) + ) + + , new EventKey("MouseOut", function () + { + mouseOverSwitch = false; + itemOut.bind(this)(); + }.bind( target ) + ) + ] + ); + return true; + } + return false + } + + , stepSubListeners = function (target) + { + var lockedOn = null, j, overedOn + , nodes = target.childNodes + ; + + // Collapse menu chain, each chain is a route + // Like dominoes + target.chainRoute = target.chainRoute || []; + + for(var i in nodes) + { + j = nodes[i]; + if(!(j && j.nodeType == 1)) continue; + + // If this item has a submenu item + if(j.lastChild.nodeType == 1) + { + target.chainRoute[target.chainRoute.length] = {menu: j.lastChild, next: stepSubListeners(j.lastChild)}; + } + + IDOMElement(j).addEventListener( + new EventKey("MouseOver", function () + { + // record "this (overed)" item + overedOn = this; + + var subItem = this.lastChild; + + Cycle.delay(function () + { + // Hide last displayed submenu if submenu is available + if(lockedOn && lockedOn != subItem) + { + _chainHide ? _chainHide(lockedOn) : (lockedOn.style.display = "none"); + // bind the chains into chain reactor + chainReactor.bind(lockedOn)(); + } + + // if mouse is still on "this (overed)" item + if(overedOn == this) + { + + // and if this item has sub item + if(subItem.nodeType == 1) + { + lockedOn = this.lastChild; + _chainShow ? _chainShow(subItem) : (subItem.style.display = ""); + } + } + }.bind(this), 300); + }.bind(j)) + ); + } + + return target.chainRoute.length ? chainReactor.bind(target) : null; + } + + , chainReactor = function () + { + if(this && this.chainRoute) + for(var i in this.chainRoute) + { + _chainHide ? _chainHide(this.chainRoute[i].menu) : (this.chainRoute[i].menu.style.display = "none"); + if(this.chainRoute[i].next) this.chainRoute[i].next(); + } + } + + , createSubMenu = function (obj) + { + if(!(obj.name || obj.items)) return Dand.wrapna("ul", addMenuIdentifier()); + + // Begin create submenu + var itemroot = Dand.wrapna("ul", addMenuIdentifier()) + , j = obj.items; + + for (var i in j) + { + + if(!(j[i] instanceof IKey)) + { + // step inside level + itemroot.appendChild(createSubMenu(j[i])); + continue; + } + + // Switch inside if this key has an id-ed event + var eKey = (j[i].keyValue instanceof EventKey) ? j[i].keyValue : j[i]; + + itemroot.appendChild( temp = Dand.wrap( "li", null, null, j[i].keyName, addMenuIdentifier(new DataKey("id", eKey.keyName))) ); + + // store EventKey & reference + _items[_items.length] = {key: eKey, stage: temp}; + + tryBindClipboard(temp, eKey); + } + + + // Datakey is set for matching action + var stage = Dand.wrap("li", null, "expandable", [ Dand.textNode(obj.name), itemroot ], addMenuIdentifier(new DataKey("id", obj.name))); + + // Set handler if available + if(obj.handler) + { + _items[_items.length] = {key: new EventKey(obj.name, obj.handler), stage: stage}; + } + else + { + // Prevent menu disappear when clicked + _items[_items.length] = {key: new EventKey(obj.name, function() { return true; }), stage: stage}; + } + + + _hideMenu ? _hideMenu(itemroot) : (itemroot.style.display = "none"); + + return stage; + }; + + for ( i in items ) + { + if ( ( j = items[i] ) ) + { + if(!(j instanceof IKey)) + { + menuItems[menuItems.length] = createSubMenu(j); + continue; + } + + // Switch inside if this key has an id-ed event + var eKey = (j.keyValue instanceof EventKey) ? j.keyValue : j; + temp = menuItems[menuItems.length] = Dand.wrapne("li", j.keyName, addMenuIdentifier(new DataKey("id", eKey.keyName))); + + // store EventKey & reference + _items[_items.length] = {key: eKey, stage: temp}; + + tryBindClipboard(temp, j); + } + } + + stage = Dand.wrap( + "div", null + , getStrOverride("class") || "contextMenu" + , temp = Dand.wrapne( "ul", menuItems, addMenuIdentifier() ) + ); + + var chain = stepSubListeners(temp); + var hideMenu = function () + { + _hideMenu ? _hideMenu( stage ) : ( stage.style.display = "none" ); + + // Root collapse chain + if( chain ) chain(); + }; + + if( menuInsideTarget && menuInsideTarget.nodeType == 1 ) + { + ( targetParent = menuInsideTarget ).appendChild(stage); + } + else + { + ( targetParent = menuGroup ).appendChild(stage); + } + + stage.zindex = 99; + + // Handle which button + i = temp = false; + if(whichButton == "both") i = temp = true; + else if (whichButton == "LMB") i = true; + else if (whichButton == "RMB") temp = true; + + if (i) + { + // Handle LMB + target.onclick = function (event) + { + if ( Dand.id( target.id ) ) + { + showMenu(event); + document.body.onmousedown = contextMouseDown; + } + cleanUpActionList(); + } + } + + // Register with RMB switch + registerBodyClickAction(contextMouseDown, contextShow, contextDelete, target.id, temp); + + temp = IDOMElement(target); + temp.addEventListener("MouseOver", function() { mouseOnTarget = true; }); + temp.addEventListener("MouseOut", function() { mouseOnTarget = false; }); + + temp = IDOMElement(stage); + temp.addEventListener("MouseOver", function() { mouseOnContext = true; }); + temp.addEventListener("MouseOut", function() { mouseOnContext = false; }); + + IDOMElement(document.body).addEventListener("ContextMenu", bodyOnContext); + + this.getItemByKey = function (key) + { + for (i in _items) + { + // match attributes + if(IDOMElement(_items[i].stage).getDAttribute("id") == key) + { + return _items[i]; + } + } + return false; + } + }; + + var bodyClickPairs = []; + + var bodyOnContext = function (event) + { + var i, j; + for (i in bodyClickPairs) + { + if ( Dand.id( ( j = bodyClickPairs[i] )._id ) ) + { + if(j._rmb && j._context(event)) + { + document.body.onmousedown = j._down; + + if( event && event.preventDefault ) event.preventDefault(); + return false; + } + } + else + { + // target lost + j._lost(); + delete bodyClickPairs[i]; + } + } + return true; + }; + + var cleanUpActionList = function () + { + var i, j; + for ( i in bodyClickPairs ) + { + if ( !Dand.id( ( j = bodyClickPairs[i] )._id ) ) + { + // target lost + j._lost(); + delete bodyClickPairs[i]; + } + } + }; + + var registerBodyClickAction = function ( _mousedown, _oncontext, _targetlost, id, _useRMB ) + { + var i = tryGetAction(id); + if(i) + { + // Remove previous menu + i._lost(); + // Perform update + i._down = _mousedown; + i._context = _oncontext; + i._lost = _targetlost; + i._rmb = _useRMB; + } + else + { + bodyClickPairs[bodyClickPairs.length] = { + _down: _mousedown, _context: _oncontext, _lost: _targetlost, _id: id, _rmb: _useRMB + }; + } + }; + + var tryGetAction = function (id) + { + for (i in bodyClickPairs) + { + if (bodyClickPairs[i]._id == id) + { + return bodyClickPairs[i]; + } + } + return false; + }; + + + ns[ NS_EXPORT ]( EX_CLASS, "ContextMenu", ContextMenu ); +})(); diff --git a/botanjs/src/Components/Mouse/_this.js b/botanjs/src/Components/Mouse/_this.js new file mode 100644 index 0000000..bcdd73d --- /dev/null +++ b/botanjs/src/Components/Mouse/_this.js @@ -0,0 +1,3 @@ +(function(){ + var ns = __namespace( "Components.Mouse" ); +})(); diff --git a/botanjs/src/Components/_this.js b/botanjs/src/Components/_this.js new file mode 100644 index 0000000..2c224e9 --- /dev/null +++ b/botanjs/src/Components/_this.js @@ -0,0 +1,3 @@ +(function(){ + var ns = __namespace( "Components" ); +})(); diff --git a/botanjs/src/Dandelion/CSSAnimations/MovieClip.css b/botanjs/src/Dandelion/CSSAnimations/MovieClip.css new file mode 100644 index 0000000..e223134 --- /dev/null +++ b/botanjs/src/Dandelion/CSSAnimations/MovieClip.css @@ -0,0 +1,3 @@ +.motion_block { + display: inline-block; +} \ No newline at end of file diff --git a/botanjs/src/Dandelion/CSSAnimations/MovieClip.js b/botanjs/src/Dandelion/CSSAnimations/MovieClip.js new file mode 100644 index 0000000..dccc0de --- /dev/null +++ b/botanjs/src/Dandelion/CSSAnimations/MovieClip.js @@ -0,0 +1,158 @@ +(function(){ + var ns = __namespace( "Dandelion.CSSAnimations" ); + + /** @type {System.utils.EventKey} */ + var EventKey = __import( "System.utils.EventKey" ); + /** @type {System.Cycle.Trigger} */ + var Trigger = __import( "System.Cycle.Trigger" ); + /** @type {Dandelion} */ + var Dand = __import( "Dandelion" ); + /** @type {Dandelion.IDOMElement} */ + var IDOMElement = __import( "Dandelion.IDOMElement" ); + + var MovieClip = function ( + __target + , __row, __col + , __width, __height + , frame, start + ) + { + if( frame == __row * __col ) frame = 0; + + var canvas = Dand.wrapc( "motion_block no_transition" ) + , r = __row - 1 + , c = __col - 1 + , w = __width + , h = __height + , i = 0, j = 0 + , k = 0, l = frame - 1 + ; + + var _next, _prev, _goto; + + if( frame ) + { + _next = function () + { + ( c < ++ i ) && ( ( i = 0 ) || ( ( r < ++ j ) && ( j = 0 ) ) ); + ( l < ++ k ) && ( i = j = k = 0 ); + }; + + _prev = function () + { + ( -- k < 0 ) && ( k = l ); + _goto( k ); + }; + + _goto = function ( f ) + { + for ( i = j = k = 0; 0 < f; f -- ) _next(); + }; + } + else + { + _next = function () + { + ( c < ++ i ) && ( ( i = 0 ) || ( ( r < ++ j ) && ( j = 0 ) ) ); + }; + + _prev = function () + { + ( -- i < 0 ) && ( ( i = c ) && ( ( -- j < 0 ) && ( j = r ) ) ); + }; + + _goto = function ( f ) + { + for ( i = j = k = 0; k < f; k ++ ) _next(); + }; + } + + canvas.style.backgroundImage = "url(" + __target + ")"; + canvas.style.width = w + "px"; + canvas.style.height = h + "px"; + canvas.style.backgroundPosition = "0px 0px"; + + var updateCanvas = function() + { + canvas.style.backgroundPosition = ( -i * w ) + "px " + ( -j * h ) + "px"; + }; + + // At 0 position + var at0 = function() { return ( i == 0 && j == 0 ) }; + + var obj = { + _next: function() { _next(); updateCanvas(); return at0(); } + , _prev: function() { _prev(); updateCanvas(); return at0(); } + , _goto: function( n ) { _goto( n ); updateCanvas(); } + }; + + this["stage"] = canvas; + this["nextFrame"] = this.nextFrame.bind( obj ); + this["prevFrame"] = this.prevFrame.bind( obj ); + this["gotoFrame"] = this.gotoFrame.bind( obj ); + }; + + MovieClip.prototype.nextFrame = function () + { + return this._next(); + }; + + MovieClip.prototype.prevFrame = function () + { + return this._prev(); + }; + + MovieClip.prototype.gotoFrame = function ( frameNumber ) + { + return this._goto( frameNumber ); + }; + + MovieClip.prototype.stage = null; + + /** @param {Dandelion.CSSAnimations.MovieClip} mc + * @param {Boolean} whenStatic + */ + var MouseOverMovie = function ( mc, whenStatic ) + { + if ( mc instanceof MovieClip ) + { + var canRegister = true; + var terminate = false; + + var registrar = function () { return mc.nextFrame() || terminate; }; + + var handler = function () + { + mc.gotoFrame( whenStatic ); + canRegister = true; + terminate = false; + }; + + var mouseOverHandler = function ( e ) + { + if( canRegister ) + { + canRegister = false; + mc.gotoFrame(0); + Trigger.register( registrar, handler, 33 ); + } + }; + + var mouseOutHandler = function ( e ) + { + if( !canRegister ) + terminate = true; + }; + + mc.gotoFrame( whenStatic ); + + IDOMElement( mc.stage ).addEventListeners([ + new EventKey( "MouseOver", mouseOverHandler ) + , new EventKey( "MouseOut", mouseOutHandler ) + ]); + } + }; + + ns[ NS_EXPORT ]( EX_CLASS, "MovieClip", MovieClip ); + ns[ NS_EXPORT ]( EX_FUNC, "MouseOverMovie", MouseOverMovie ); +})(); diff --git a/botanjs/src/Dandelion/CSSAnimations/_this.css b/botanjs/src/Dandelion/CSSAnimations/_this.css new file mode 100644 index 0000000..7603650 --- /dev/null +++ b/botanjs/src/Dandelion/CSSAnimations/_this.css @@ -0,0 +1,41 @@ +.comp, .compx * { + -webkit-transition: all .25s ease-out; + -moz-transition: all .25s ease-out; + -o-transition: all .25s ease-out; + transition: all .25s ease-out; +} + +.rcomp, .rcompx * { + -webkit-transition: none; + -moz-transition: none; + -o-transition: none; + transition: none; +} + +.cubic500 { + -webkit-transition: all 500ms cubic-bezier(0.215, 0.610, 0.355, 1.000); + -moz-transition: all 500ms cubic-bezier(0.215, 0.610, 0.355, 1.000); + -ms-transition: all 500ms cubic-bezier(0.215, 0.610, 0.355, 1.000); + -o-transition: all 500ms cubic-bezier(0.215, 0.610, 0.355, 1.000); + transition: all 500ms cubic-bezier(0.215, 0.610, 0.355, 1.000); /* easeOutCubic */ + + -webkit-transition-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000); + -moz-transition-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000); + -ms-transition-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000); + -o-transition-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000); + transition-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000); /* easeOutCubic */ +} + +.cubic200 { + -webkit-transition: all 200ms cubic-bezier(0.215, 0.610, 0.355, 1.000); + -moz-transition: all 200ms cubic-bezier(0.215, 0.610, 0.355, 1.000); + -ms-transition: all 200ms cubic-bezier(0.215, 0.610, 0.355, 1.000); + -o-transition: all 200ms cubic-bezier(0.215, 0.610, 0.355, 1.000); + transition: all 200ms cubic-bezier(0.215, 0.610, 0.355, 1.000); /* easeOutCubic */ + + -webkit-transition-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000); + -moz-transition-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000); + -ms-transition-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000); + -o-transition-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000); + transition-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000); /* easeOutCubic */ +} diff --git a/botanjs/src/Dandelion/CSSAnimations/_this.js b/botanjs/src/Dandelion/CSSAnimations/_this.js new file mode 100644 index 0000000..e4c99e6 --- /dev/null +++ b/botanjs/src/Dandelion/CSSAnimations/_this.js @@ -0,0 +1,5 @@ +/* +(function(){ + var ns = __namespace( "Dandelion.CSSAnimations" ); +})(); +*/ diff --git a/botanjs/src/Dandelion/CSSReset.css b/botanjs/src/Dandelion/CSSReset.css new file mode 100644 index 0000000..e90dc19 --- /dev/null +++ b/botanjs/src/Dandelion/CSSReset.css @@ -0,0 +1,43 @@ +html, body, div, span, applet, object, iframe, +h1, h2, h3, h4, h5, h6, p, blockquote, pre, +a, abbr, acronym, address, big, cite, code, +del, dfn, em, img, ins, kbd, q, s, samp, +small, strike, strong, tt, var, +b, u, i, center, +dl, dt, dd, ol, ul, li, +fieldset, form, label, legend, +table, caption, tbody, tfoot, thead, tr, th, td, +article, aside, canvas, details, embed, +figure, figcaption, footer, header, hgroup, +menu, nav, output, ruby, section, summary, +time, mark, audio, video { + margin: 0; + padding: 0; + border: 0; + font-size: 100%; + font: inherit; + vertical-align: baseline; +} +sup, sub { + vertical-align: baseline; + font-size: 80%; +} +article, aside, details, figcaption, figure, +footer, header, hgroup, menu, nav, section { + display: block; +} +ol, ul { + list-style: none; +} +blockquote, q { + quotes: none; +} +blockquote:before, blockquote:after, +q:before, q:after { + content: ''; + content: none; +} +table { + border-collapse: collapse; + border-spacing: 0; +} diff --git a/botanjs/src/Dandelion/CSSReset.js b/botanjs/src/Dandelion/CSSReset.js new file mode 100644 index 0000000..3f714e7 --- /dev/null +++ b/botanjs/src/Dandelion/CSSReset.js @@ -0,0 +1,5 @@ +/* +(function(){ + var ns = __namespace( "Dandelion.CSSReset" ); +})(); +*/ diff --git a/botanjs/src/Dandelion/IDOMElement.js b/botanjs/src/Dandelion/IDOMElement.js new file mode 100644 index 0000000..ccffbb7 --- /dev/null +++ b/botanjs/src/Dandelion/IDOMElement.js @@ -0,0 +1,199 @@ +(function(){ + var ns = __namespace( "Dandelion" ); + + /** @type {System.utils.IKey} */ + var IKey = __import( "System.utils.IKey" ); + /** @type {System.utils.Perf} */ + var Perf = __import( "System.utils.Perf" ); + + var wrap = ns[ NS_INVOKE ]( "wrap" ); + var IDOMObject = ns[ NS_INVOKE ]( "IDOMObject" ); + + // IDOMElement, augmented element wrapper utilizing IKeys + var IDOMElement = function (element, sw) + { + if (element instanceof IDOMElement) return element; + + if (sw) + { + IDOMObject.call( this, element, true ); + + this["getDAttribute"] = this.getDAttribute.bind(element); + + this["lootChildren"] = this.lootChildren.bind(element); + + this["foreach"] = this.foreach.bind(element); + this["reverseChild"] = this.reverseChild.bind(element); + this["first"] = this.first.bind(element); + this["last"] = this.last.bind(element); + this["contains"] = this.contains.bind(element); + + // Org values + this["style"] = element.style; + this["hasAttribute"] = function ( key ) { this.hasAttribute( key ); }.bind( element ); + this["removeAttribute"] = function ( key ) { this.removeAttribute( key ); }.bind( element ); + this["element"] = element; + + // Overrides + this["setAttribute"] = this.setAttribute.bind( element ); + } + else if ( element && element[ "nodeType" ] != undefined && element.nodeType == 1 ) + { + return new IDOMElement( element, true ); + } + else if( element === undefined ) + { + return new IDOMElement( wrap(), true ); + } + else + { + throw new Error( "[Dandelion.IDOMElement] Invalid argument" ); + } + return this; + }; + + __extends( IDOMElement, IDOMObject ); + + IDOMElement.prototype.setAttribute = function( k, v ) + { + if( k instanceof IKey ) + { + this.setAttribute( k.keyName, k.keyValue ); + } + else if( k instanceof Array ) + { + for ( var i in k ) + { + if ( k[i] instanceof IKey ) + { + this.setAttribute( k[i].keyName, k[i].keyValue ); + } + } + } + else + { + this.setAttribute( k, v ); + } + }; + + IDOMElement.prototype.lootChildren = function ( element ) + { + var _nodes = element.childNodes; + while(_nodes.length) + { + this.appendChild( element.removeChild( _nodes[0] ) ); + } + }; + + IDOMElement.prototype.getDAttribute = function(name) + { + var i = this.getAttribute("data-" + name); + return i && decodeURIComponent(i); + }; + + IDOMElement.prototype.foreach = function(type, callback) + { + var c = Array.apply( [], this.childNodes ), l = c.length; + for(var i = 0; i < l; i ++) + { + if (c[i].nodeType == type) + { + callback(c[i], this); + } + } + }; + + var matchNone = function() { return false; }; + var matchType = function( c, t ) { return c.nodeType == t; }; + var matchName = function( c, t ) { return c.nodeName == t; }; + + var getMatch = function( type ) + { + type = typeof( type ); + if( type == "number" ) return matchType; + else if( type == "string" ) return matchName; + + return matchNone; + }; + + IDOMElement.prototype.first = function ( type, callback ) + { + var c = this.childNodes; + var l = c.length; + var elem = null; + var tc = getMatch( type ); + + for( var i = 0; i < l; i ++ ) + { + if ( tc( c[i], type ) ) + { + if( callback === undefined || callback( c[i], this ) ) + { + elem = c[i]; + break; + } + } + } + + return elem; + }; + + IDOMElement.prototype.last = function ( type, callback ) + { + var c = this.childNodes; + var l = c.length - 1; + var elem = null; + var tc = getMatch( type ); + + for( var i = l; -1 < i ; i -- ) + { + if ( tc( c[i], type ) ) + { + if( callback === undefined || callback( c[i], this ) ) + { + elem = c[i]; + break; + } + } + } + + return elem; + }; + + IDOMElement.prototype.contains = function ( target ) + { + if( target.parentElement ) + { + if( target == this ) + { + return true; + } + return this.contains( target.parentElement ); + } + return false; + }; + + // attribute keys + IDOMElement.prototype.aKeys = function() + { + var ikeys = []; + var attrs = this.element.attributes; + var l = attrs.length; + for( var i = 0; i < l; i ++ ) + { + ikeys.push( new IKey( attrs[i].name, attrs[i].value ) ); + } + return ikeys; + }; + + IDOMElement.prototype.reverseChild = function() + { + var l = this.childNodes.length - 1; + while( -1 < -- l ) + { + this.appendChild( this.childNodes[l] ); + } + }; + + ns[ NS_EXPORT ]( EX_CLASS, "IDOMElement", IDOMElement ); +})(); diff --git a/botanjs/src/Dandelion/IDOMObject.js b/botanjs/src/Dandelion/IDOMObject.js new file mode 100644 index 0000000..e9c42a3 --- /dev/null +++ b/botanjs/src/Dandelion/IDOMObject.js @@ -0,0 +1,149 @@ +(function(){ + var ns = __namespace( "Dandelion" ); + /** @type {System.utils.EventKey} */ + var EventKey = __import( "System.utils.EventKey" ); + + var EvtsArr = function () { Array.call( this ); }; + + /** @param {System.utils.EventKey} e */ + EvtsArr.prototype.indexOf = function( e ) + { + var l = this.length; + for( var i = 0; i < l; i ++ ) + { + /** @type {System.utils.EventKey} */ + var evt = this[i]; + if( evt.type == e.type && evt.handler == e.handler ) + { + return i; + } + } + + return -1; + }; + + __extends( EvtsArr, Array ); + + var IDOMObject = function ( obj, sw ) + { + if ( obj instanceof IDOMObject ) return obj; + + if ( sw ) + { + this["addEventListener"] = this.addEventListener.bind(obj); + this["addEventListeners"] = this.addEventListeners.bind(this); + this["hasListener"] = this.hasListener.bind(obj); + this["removeEventListener"] = this.removeEventListener.bind(obj); + } + else if ( obj ) + { + return new IDOMObject( obj, true ); + } + else + { + throw new Error( "[Dandelion.IDOMObject] Invalid argument" ); + } + } + + IDOMObject.prototype.hasListener = function(e) + { + if( e instanceof EventKey + && this._events + && this._events.indexOf(e) != -1 + ) + { + return this._events[ this._events.indexOf(e) ]; + } + return null; + }; + + IDOMObject.prototype.addEventListener = function (event, handler) + { + var e; + if (typeof event == "string" && handler) + { + e = new EventKey(event, handler); + } + else if (event instanceof EventKey) + { + e = event; + } + else + { + return false; + } + + if ( this._events ) + { + if ( this._events.indexOf( e ) < 0 ) + { + this._events.push( e ); + } + else + { + return false; + } + } + else + { + this._events = new EvtsArr(); + this._events[0] = e; + } + + if( this.addEventListener ) + { + this.addEventListener( e.type, e.handler, false ); + } + // IE + else if( this.attachEvent ) + { + this.attachEvent('on' + e.type, e.handler); + } + else + { + this['on' + e.type] = e.handler; + } + return true; + }; + + IDOMObject.prototype.addEventListeners = function(evtKeys) + { + if(evtKeys instanceof Array) + { + for (var i in evtKeys) + { + this.addEventListener(evtKeys[i]); + } + } + }; + + IDOMObject.prototype.removeEventListener = function( e, handler ) + { + if( handler ) + { + e = new EventKey( e, handler ); + } + + if( this._events ) + { + delete this._events[ this._events.indexOf(e) ]; + } + + if( this.removeEventListener ) + { + this.removeEventListener( e.type, e.handler ); + } + // IE + else if( this.detachEvent ) + { + this.detachEvent( 'on' + e.type, e.handler ); + } + else + { + this['on' + e.type] = null; + } + }; + + ns[ NS_EXPORT ]( EX_CLASS, "IDOMObject", IDOMObject ); +})(); + diff --git a/botanjs/src/Dandelion/Swf/ExtAPI.css b/botanjs/src/Dandelion/Swf/ExtAPI.css new file mode 100644 index 0000000..d7913d9 --- /dev/null +++ b/botanjs/src/Dandelion/Swf/ExtAPI.css @@ -0,0 +1,7 @@ +#extAPIConsole { + -webkit-transition: all 0s; + -moz-transition: all 0s; + -ms-transition: all 0s; + -o-transition: all 0s; + transition: all 0s; +} \ No newline at end of file diff --git a/botanjs/src/Dandelion/Swf/ExtAPI.js b/botanjs/src/Dandelion/Swf/ExtAPI.js new file mode 100644 index 0000000..e29c3a5 --- /dev/null +++ b/botanjs/src/Dandelion/Swf/ExtAPI.js @@ -0,0 +1,44 @@ +(function(){ + var ns = __namespace( "Dandelion.Swf.ExtAPI" ); + /** @type {System.Debug} */ + var debug = __import( "System.Debug" ); + + var jsReady = false + , as = 0 + , cutConnection = false + + , watchDogTime = new Date().getTime() + , watchDogCounter = 0 + , lastCount = 0 + ; + + var ExtAPI = function () + { + // TODO + }; + + var isReady = function () { return jsReady; }; + + var init = function () + { + jsReady = true; + debug.Info( "[ExtAPI] " + new Date().toString() ); + }; + + var watch = function () + { + if( watchDogCounter - lastCount < 300 ) + { + lastCount = watchDogCounter; + } + else + { + cutConnection = true; + debug.Warning( "[ExtAPI] Console Disabled: possible hanging dectected." ) + } + watchDogTime = new Date().getTime(); + }; + + ns[ NS_EXPORT ]( EX_FUNC, "init", init ); + ns[ NS_EXPORT ]( EX_FUNC, "ready", isReady ); +})(); diff --git a/botanjs/src/Dandelion/Swf/_this.css b/botanjs/src/Dandelion/Swf/_this.css new file mode 100644 index 0000000..75a7f7c --- /dev/null +++ b/botanjs/src/Dandelion/Swf/_this.css @@ -0,0 +1,56 @@ +.swf_wrapper { + position: relative; + overflow: hidden; +} + +.swf_wrapper > div { + position: relative; + width: 100%; + height: 100%; +} + +.swf_inactive { + background: rgba(0, 0, 0, 0.2); + opacity: 1; +} + +.swf_inactive:hover { + opacity: 0.6; +} + +.swf_inactive > div { + width: 0; + height: 0; + border-top: 3.5em solid transparent; + border-bottom: 3.5em solid transparent; + border-left: 5em solid #FFF; + position: absolute; + + left: 50%; + top: 50%; + margin-top: -3.5em; + margin-left: -1.8em; +} + + /* title */ +.swf_caption { + bottom: 0; + + position: absolute; + + display: block; + width: 100%; + + color: white; + background: rgba(0, 0, 0, 0.8); + + padding: 0.2em; + + font-size: 2em; + + cursor: default; +} + +.swf_desc { + font-size: 60%; +} \ No newline at end of file diff --git a/botanjs/src/Dandelion/Swf/_this.js b/botanjs/src/Dandelion/Swf/_this.js new file mode 100644 index 0000000..0ea91f0 --- /dev/null +++ b/botanjs/src/Dandelion/Swf/_this.js @@ -0,0 +1,173 @@ +(function(){ + var ns = __namespace( "Dandelion" ); + + /** @type {System.utils} */ + var utils = __import( "System.utils" ); + /** @type {System.utils.IKey} */ + var IKey = __import( "System.utils.IKey" ); + /** @type {System.Policy} */ + var Policy = __import( "System.Policy" ); + /** @type {System.Debug} */ + var Dand = __import( "Dandelion" ); + + var IE = __import( "System.Global.IE" ); + + var s_current = {player: false, mask: false, stage: false, listener: false, sid: null}; + + var Swf = function (movieName) + { + if ( navigator.appName.indexOf("Microsoft") != -1 ) + { + return window[movieName]; + } + else + { + return document[movieName]; + } + }; + + var realize = function (id) + { + var movieElement = Dand.id('swfWrapper_' + id) + , swf_origin = Dand.wrap('a') + , _src = movieElement.getAttribute("value") + + swf_origin.href = _src; + + if( Policy.isAllowedOrigin( stf_origin.host ) ) { + swf_origin = "always"; + } else { + swf_origin = "never"; + } + + movieElement.onclick = ( IE ? createMovieIE : createMovie ).bind({ + sid: id + , src: _src + , width: movieElement.style.width + , height: movieElement.style.height + , s_stage:movieElement + , origin: swf_origin + }); + }; + + /* + var getCurrentMovie = function (args) + { + if ( window.ExtAPI ) + { + return thisMovie( s_current.sid ); + } + return null; + }; + */ + + var createMovieIE = function () + { + // Remove previous movie if exists + if(s_current.stage) + { + s_current.stage.firstChild.className = "swf_inactive"; + s_current.stage.firstChild.innerHTML = s_current.player; + s_current.stage.childNodes[1].style.bottom = ""; + s_current.stage.onclick = s_current.listener; + } + + this.s_stage.childNodes[1].style.bottom = "-2em"; + s_current.sid = "swf_" + this.sid; + + s_current.stage = this.s_stage; + s_current.player = this.s_stage.firstChild.innerHTML; + + this.s_stage.firstChild.className = "swf_active"; + this.s_stage.firstChild.innerHTML = makeStageIE(this.src, this.width, this.height, s_current.sid, this.origin); + + // Save event listener + s_current.listener = this.s_stage.onclick; + + // disable click event + this.s_stage.onclick = null; + }; + + var createMovie = function () + { + + // Remove previous movie if exists + if(s_current.stage) + { + s_current.stage.removeChild(s_current.player); + s_current.stage.firstChild.style.bottom = ""; + s_current.stage.insertBefore(mask, stage.firstChild); + s_current.stage.onclick = s_current.listener; + } + + + this.s_stage.childNodes[1].style.bottom = "-2em"; + s_current.sid = "swf_" + this.sid; + + // Remove mask + (s_current.stage = this.s_stage).removeChild(s_current.mask = this.s_stage.childNodes[0]); + + s_current.player = makeStage(this.src, this.width, this.height, s_current.sid, this.origin); + this.s_stage.appendChild(s_current.player); + + // Save event listener + s_current.listener = this.s_stage.onclick; + + // disable click event + this.s_stage.onclick = null; + + }; + + var makeStage = function (src, width, height, sid, origin, wmode) + { + return Dand.wrapna("embed", + [ + new IKey("src", src) + , new IKey("quality", "high") + , new IKey("bgcolor", "#869ca7") + , new IKey("width", width) + , new IKey("height", height) + , new IKey("name", sid) + , new IKey("align", "middle") + , new IKey("wmode", wmode || "direct") + , new IKey("play", "true") + , new IKey("loop", "false") + , new IKey("quality", "high") + , new IKey("allowScriptAccess", origin) + , new IKey("type", "application/x-shockwave-flash") + , new IKey("pluginspage", "http://www.macromedia.com/go/getflashplayer") + ] + ); + }; + + var makeStageIE = function (src, width, height, sid, origin, wmode) + { + return Dand.wrape( + Dand.wrapne('object', + [ + Dand.wrapna("param", [new IKey("name", "wmode"), new IKey("value", wmode || "direct")]) + , Dand.wrapna("param", [new IKey("name", "quality"), new IKey("value", "high")]) + , Dand.wrapna("param", [new IKey("name", "movie"), new IKey("value", src)]) + , Dand.wrapna("param", [new IKey("name", "bgcolor"), new IKey("value", "#869ca7")]) + , Dand.wrapna("param", [new IKey("name", "allowScriptAccess"), new IKey("value", origin)]) + ] + , + [ + new IKey("classid", "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000") + , new IKey("id", sid) + , new IKey("name", sid) + , new IKey("width", width) + , new IKey("height", height) + , new IKey("data", src) + , new IKey("type", "application/x-shockwave-flash") + , new IKey("codebase", "http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab") + ] + ) + ).innerHTML; + }; + + __static_method( Swf, "create", IE ? makeStageIE : makeStage ); + __static_method( Swf, "realize", realize ); + + ns[ NS_EXPORT ]( EX_CLASS, "Swf", Swf ); +})(); diff --git a/botanjs/src/Dandelion/Window.js b/botanjs/src/Dandelion/Window.js new file mode 100644 index 0000000..4873b37 --- /dev/null +++ b/botanjs/src/Dandelion/Window.js @@ -0,0 +1,10 @@ +(function(){ + var ns = __namespace( "Dandelion.Window" ); + + ns[ NS_EXPORT ]( EX_READONLY_GETTER , "scrollTop" , function() { return window.pageYOffset || document.documentElement.scrollTop; } ); + ns[ NS_EXPORT ]( EX_READONLY_GETTER , "scrollLeft" , function() { return window.pageXOffset || document.documentElement.scrollLeft; } ); + ns[ NS_EXPORT ]( EX_READONLY_GETTER , "scrollHeight" , function() { return window.scrollHeight || document.documentElement.scrollHeight } ); + ns[ NS_EXPORT ]( EX_READONLY_GETTER , "clientHeight" , function() { return window.clientHeight || document.documentElement.clientHeight; } ); + ns[ NS_EXPORT ]( EX_READONLY_GETTER , "scrollWidth" , function() { return window.scrollWidth || document.documentElement.scrollWidth } ); + ns[ NS_EXPORT ]( EX_READONLY_GETTER , "clientWidth" , function() { return window.clientWidth || document.documentElement.clientWidth; } ); +})(); diff --git a/botanjs/src/Dandelion/_this.js b/botanjs/src/Dandelion/_this.js new file mode 100644 index 0000000..5643a4c --- /dev/null +++ b/botanjs/src/Dandelion/_this.js @@ -0,0 +1,187 @@ +(function(){ + var ns = __namespace( "Dandelion" ); + var IE = __import( "System.Global.IE" ); + + /* @type {System.utils.IKey}*/ + var IKey = __import( "System.utils.IKey" ); + + /* @type {Dandelion.IDOMElement}*/ + var IDOMElement; + + var wrap = function ( wwith, id, wclass, elements, iKeys ) + { + var tmp = document.createElement( wwith || "div" ); + if( id ) tmp.id = id; + if( wclass ) + { + if( IE ) + { + tmp.className = wclass; + } + else + { + tmp.setAttribute( "class", wclass ); + } + } + + if ( iKeys ) + { + if ( iKeys instanceof Array ) + { + for (var i in iKeys) + { + tmp.setAttribute( iKeys[i].keyName, iKeys[i].keyValue ); + } + } + else if ( iKeys instanceof IKey ) + { + tmp.setAttribute( iKeys.keyName, iKeys.keyValue ); + } + } + + if( elements ) + { + // is array? + if(elements instanceof Array) + { + var l = elements.length; + for( var i = 0; i < l; i ++ ) + { + elements[i] && tmp.appendChild( elements[i] ); + } + } + // else if string + else if( typeof elements == "string" ) + { + tmp.appendChild(_createTextNode(elements)); + } + // else append child, do not do any error handling! + else if( elements ) + { + tmp.appendChild( elements ); + } + } + return tmp; + }; + + var wrapc = function ( aClass, elements, iKeys ) { + return wrap( false, false, aClass, elements, iKeys ); + }; + + // wrap element afters + var wrape = function ( elements, iKeys ) { + return wrap( false, false, false, elements, iKeys ); + }; + + // wrap name element after + var wrapne = function ( name, elements, iKeys ) { + return wrap(name, false, false, elements, iKeys); + }; + + // wrap name attirbutes after + var wrapna = function ( name, iKeys ) { + return wrap(name, false, false, false, iKeys); + }; + + var _createTextNode = function (s) + { + return document.createTextNode(s); + }; + + // Bubble up element if + var bubbleUp = function ( elem, condition ) + { + if( condition( elem ) ) return elem; + + return elem.parentNode && bubbleUp( elem.parentNode, condition ); + }; + + var chainUpApply = function( elem, func ) + { + if( !elem ) return; + + var chain = func( elem ); + + if( chain && elem.parentNode ) + { + chainUpApply( elem.parentNode, func ); + } + }; + + var id = function( name, idom ) + { + var elem = document.getElementById( name ); + if( !elem ) return elem; + + if( idom && runtimeImport() ) + { + return IDOMElement( elem ); + } + + return elem; + }; + + var elements = function( elem, idom ) + { + if( idom && runtimeImport() ) + { + var l = elem.length; + var ielem = []; + for( var i = 0; i < l; i ++ ) + { + ielem[i] = IDOMElement( elem[i] ); + } + return ielem; + } + + return elem; + }; + + var tag = function( name, idom, target ) + { + target = target === undefined ? document : target; + var elem = target.getElementsByTagName( name ); + return elements( elem, idom ); + }; + + var name = function( name, idom, target ) + { + target = target === undefined ? document : target; + var elem = target.getElementsByName( name ); + return elements( elem, idom ); + }; + + var getClass = function( name, idom, target ) + { + target = target === undefined ? document : target; + var elem = target.getElementsByClassName( name ); + return elements( elem, idom ); + }; + + var runtimeImport = function() + { + if( IDOMElement ) return true; + + try + { + var a = "Dandelion.IDOMElement"; + IDOMElement = __import( a ); + return true; + } + catch( e ) { } + return false; + }; + + ns[ NS_EXPORT ]( EX_FUNC, "wrap", wrap ); + ns[ NS_EXPORT ]( EX_FUNC, "wrapc", wrapc ); + ns[ NS_EXPORT ]( EX_FUNC, "wrape", wrape ); + ns[ NS_EXPORT ]( EX_FUNC, "wrapne", wrapne ); + ns[ NS_EXPORT ]( EX_FUNC, "wrapna", wrapna ); + ns[ NS_EXPORT ]( EX_FUNC, "textNode", _createTextNode ); + ns[ NS_EXPORT ]( EX_FUNC, "bubbleUp", bubbleUp ); + ns[ NS_EXPORT ]( EX_FUNC, "chainUpApply", chainUpApply ); + ns[ NS_EXPORT ]( EX_FUNC, "id", id ); + ns[ NS_EXPORT ]( EX_FUNC, "tag", tag ); + ns[ NS_EXPORT ]( EX_FUNC, "name", name ); + ns[ NS_EXPORT ]( EX_FUNC, "glass", getClass ); +})(); diff --git a/botanjs/src/README.md b/botanjs/src/README.md new file mode 100644 index 0000000..a6ed715 --- /dev/null +++ b/botanjs/src/README.md @@ -0,0 +1,64 @@ +Goals: + 1. Scalable + 2. Compressable ( Closure compiler with ADVANCED option ) + 3. Readable + 4. Only use 1 var in global scope, I.E. window.BotanJS + 5. Package like + +Predefined programming rules: +``` + __namespace + __import + __readOnly + __static_method + __extends + + ns = __namespace( ) + ns[ NS_INVOKE ]( ) + ns[ NS_EXPORT ]( , , ) + ns[ NS_TRIGGER ]( , ) +``` + +Usage: +``` + BotanJS.import( ) +``` + +BotanJS Class Map: +``` + + + + ALLOWED_ORIGIN + + + System.Global + + + + + + + + Dandelion.Swf.ExtAPI + + MY_CLASS_DEPENDENT_PROP + + ... + + + + +``` + +Css Inheritance: + Unlike js, which use classes only when __import is explicitly called. + Structure of css class are inherited by it's parent namespace +``` +Dandelion.Swf.ExtAPI.css +inherits from Dandelion.Swf.css +inherits from Dandelion.css +``` diff --git a/botanjs/src/System/Cycle/Trigger.js b/botanjs/src/System/Cycle/Trigger.js new file mode 100644 index 0000000..6d6529c --- /dev/null +++ b/botanjs/src/System/Cycle/Trigger.js @@ -0,0 +1,75 @@ +(function(){ + var ns = __namespace( "System.Cycle.Trigger" ); + + /** @type {System.Cycle} */ + var Cycle = __import( "System.Cycle" ); + + // trigger list + var tList = []; + var stepperId = -1; + + var stepper = function( args ) + { + var thisTime = new Date().getTime(); + for ( var i in tList ) + { + var f = tList[i]; + if( f && thisTime > f[2] ) + { + try + { + if( f[0]() ) + { + f[1](); + delete tList[i]; + } + else f[2] = thisTime + f[3]; + } + catch(e) + { + debug.Error(e); + delete tList[i]; + } + } + } + }; + + var registerTrigger = function ( trigger, handler, peekInt ) + { + tList[ tList.length ] = [ trigger, handler, new Date().getTime() + peekInt, peekInt ] + }; + + var heightTrigger = function ( __element, value, handler ) + { + var k = function () { + return ( this.a.clientHeight == this.b ); + }.bind({ a: __element, b: value }); + + registerTrigger( k, handler, 50 ); + }; + + var transitionTrigger = function (__style, value, handler) + { + var k = function () + { + return ( this.a.transition == this.b ); + }.bind({a: __style, b: value }); + registerTrigger( k, handler, 50 ); + }; + + var regTick = function( e ) + { + if( stepperId < 0 ) + { + stepperId = Cycle.TICK.putStepper( stepper ); + } + }; + + ns.addEventListener( "NS_IMPORT", regTick ); + + ns[ NS_EXPORT ]( EX_FUNC, "register", registerTrigger ); + ns[ NS_EXPORT ]( EX_FUNC, "transition", transitionTrigger ); + ns[ NS_EXPORT ]( EX_FUNC, "height", heightTrigger ); + + ns[ NS_TRIGGER ]( TGR_IMPORT, regTick ); +})(); diff --git a/botanjs/src/System/Cycle/_this.js b/botanjs/src/System/Cycle/_this.js new file mode 100644 index 0000000..f9431a1 --- /dev/null +++ b/botanjs/src/System/Cycle/_this.js @@ -0,0 +1,108 @@ +(function(){ + var ns = __namespace( "System.Cycle" ); + + /** @type {System.Tick} */ + var utils = __import( "System.utils" ); + /** @type {System.Tick} */ + var Tick = __import( "System.Tick" ); + /** @type {System.Debug} */ + var debug = __import( "System.Debug" ); + + var tList = []; + + var stepper = function() + { + var thisTime = new Date().getTime(); + // 0: Callback + // 1: scheduled run time + // 2: Permanent + // ( 3: id ) + // 4: interval + for ( var i in tList ) + { + var f = tList[i]; + if( f && thisTime > f[1] ) + { + try + { + f[0](); + } + catch(e) + { + debug.Error(e); + delete tList[i]; + continue; + } + + if( f[2] ) + { + delete tList[i]; + } + else + { + f[1] = thisTime + f[4]; + } + } + } + }; + + // Should bind "func" before register + var registerDelay = function (func, milliSec) + { + tList[ tList.length ] = [ func, new Date().getTime() + milliSec, true ]; + }; + + var registerPermanentTicker = function ( id, func, interval ) + { + for ( var i in tList ) + { + if( tList[i][3] == id ) + return false; + } + + tList[ tList.length ] = [ func, new Date().getTime() + interval, false, id, interval ]; + }; + + var deletePermanentTicker = function ( id ) + { + // 3: id + for ( var i in tList ) + { + if( tList[i][3] == id ) + delete tList[i]; + } + }; + + var next = function( func ) + { + tList[ tList.length ] = [ func, 0, true ]; + }; + + var ourTick = new Tick(); + ourTick.putStepper( stepper ); + + var gTickStart = function( e ) + { + e.target.removeEventListener( "NS_IMPORT", gTickStart ); + + var TICK = __import( "System.Cycle.TICK", true ); + + if( TICK != ourTick && TICK.started ) + { + debug.Info( "[System.Cycle] Global Tick exists" ); + ourTick = null; + return; + } + + debug.Info( "[System.Cycle] Creating global Tick" ); + ourTick.start(); + }; + + ns.addEventListener( "NS_IMPORT", gTickStart ); + + ns[ NS_EXPORT ]( EX_FUNC, "next", next ); + ns[ NS_EXPORT ]( EX_FUNC, "delay", registerDelay ); + ns[ NS_EXPORT ]( EX_FUNC, "perma", registerPermanentTicker ); + ns[ NS_EXPORT ]( EX_FUNC, "permaRemove", deletePermanentTicker ); + ns[ NS_EXPORT ]( EX_READONLY_GETTER, "TICK", function(){ return ourTick; } ); +})(); diff --git a/botanjs/src/System/Debug.js b/botanjs/src/System/Debug.js new file mode 100644 index 0000000..018da5c --- /dev/null +++ b/botanjs/src/System/Debug.js @@ -0,0 +1,46 @@ +(function(){ + var ns = __namespace( "System.Debug" ); + /** @type {System.Log} */ + var Log = __import( "System.Log" ); + /** @type {System.Global} */ + var _global = __import( "System.Global" ); + + var st_info = _global.debug; + var st_error = true; + + var Error = function( e ) + { + if( st_error ) + Log.writeLine( e.name + "\n\t" + e.message + "\n\t" + e.stack, Log.ERROR ); + }; + + var Info = function(e) + { + if( st_info ) + Log.writeLine( e, Log.INFO ); + }; + + var turnOff = function( what ) + { + if( what == "info" ) st_info = false; + else if( what == "error" ) st_error = false; + }; + + var turnOn = function( what ) + { + if( what == "info" ) st_info = true; + else if( what == "error" ) st_error = true; + }; + + /* {{{ Root log override */ + BotanJS.log.write = Info; + + while( !BotanJS.log.end() ) + Info( BotanJS.log.read() ); + /* End Root log override }}}*/ + + ns[ NS_EXPORT ]( EX_FUNC, "Error", Error ); + ns[ NS_EXPORT ]( EX_FUNC, "Info", Info ); + ns[ NS_EXPORT ]( EX_FUNC, "turnOff", turnOff ); + ns[ NS_EXPORT ]( EX_FUNC, "turnOn", turnOn ); +})(); diff --git a/botanjs/src/System/Global.js b/botanjs/src/System/Global.js new file mode 100644 index 0000000..3f262d6 --- /dev/null +++ b/botanjs/src/System/Global.js @@ -0,0 +1,16 @@ +(function(){ + var ns = __namespace( "System.Global" ); + + var debug = function() + { + return window[ "debugEnv" ] && window[ "debugEnv" ]; + }; + + // for IE < 10 + var IE = Boolean( document[ "all" ] ); + var ALLOWED_ORIGINS = window[ "allowed_origins" ] || []; + + ns[ NS_EXPORT ]( EX_READONLY_GETTER, "debug", debug ); + ns[ NS_EXPORT ]( EX_CONST, "IE", IE ); + ns[ NS_EXPORT ]( EX_CONST, "ALLOWED_ORIGINS", ALLOWED_ORIGINS ); +})(); diff --git a/botanjs/src/System/Log.js b/botanjs/src/System/Log.js new file mode 100644 index 0000000..f1f7433 --- /dev/null +++ b/botanjs/src/System/Log.js @@ -0,0 +1,46 @@ +(function(){ + var ns = __namespace( "System.Log" ); + var handler = []; + + var SYSTEM = 1; + var INFO = 16; + var ERROR = 32; + + var writeLine = function ( mesg, type ) + { + type = ( type === undefined ) ? INFO : type; + + var handled = false; + for( var i in handler ) + { + handler[i]( mesg, type ); + handled = true; + } + + if( !handled + && window[ "console" ] + && console.log + ) console.log( mesg ); + }; + + var registerHandler = function( func ) + { + var index = -1; + handler[ index = handler.length ] = func; + + return index; + }; + + var removeHandler = function( index ) + { + delete handler[ index ]; + }; + + ns[ NS_EXPORT ]( EX_FUNC, "writeLine", writeLine ); + ns[ NS_EXPORT ]( EX_FUNC, "registerHandler", registerHandler ); + ns[ NS_EXPORT ]( EX_FUNC, "removeHandler", removeHandler ); + + ns[ NS_EXPORT ]( EX_CONST, "INFO", INFO ); + ns[ NS_EXPORT ]( EX_CONST, "ERROR", ERROR ); + ns[ NS_EXPORT ]( EX_CONST, "SYSTEM", SYSTEM ); +})(); diff --git a/botanjs/src/System/Net/ClassLoader.js b/botanjs/src/System/Net/ClassLoader.js new file mode 100644 index 0000000..06223ae --- /dev/null +++ b/botanjs/src/System/Net/ClassLoader.js @@ -0,0 +1,75 @@ +(function(){ + var ns = __namespace( "System.Net" ); + var className = "ClassLoader"; + + /** @type {System.utils} */ + var utils = __import( "System.utils" ); + /** @type {System.utils.IKey} */ + var IKey = __import( "System.utils.IKey" ); + /** @type {Dandelion} */ + var Dand = __import( "Dandelion" ); + + var loadFile = function ( sapi, request, mode ) + { + var head = Dand.tag( "head" )[0]; + + // Add css + head.appendChild( + Dand.wrapna( + "link" + , IKey.quickDef( + "rel", "stylesheet" + , "type", "text/css" + , "href", sapi + mode + "css/" + request + ) + ) + ); + + // Add js + head.appendChild( + Dand.wrapna( + "script" + , IKey.quickDef( + "type", "text/javascript" + , "src", sapi + mode + "js/" + request + ) + ) + ); + + }; + + var Loader = function( sapi, mode ) + { + mode = ( mode === undefined ) ? "o" : mode; + + this.load = function( classes, handler ) + { + if( !classes.join ) classes = [ classes ]; + + var excludes = BotanJS.getDef(); + // Excludes + utils.objMap( excludes , function( v ) { return "-" + v; } ); + + var loadc = null; + var onLoad = function( e ) + { + if( classes.indexOf( e.data.name ) < 0 ) return; + handler( e.data.name ); + }; + + var sp = mode ? { 'o': '/', 'r': '/' }[ mode ] : ','; + + loadFile( + sapi + , classes.join( sp ) + sp + excludes.join( sp ) + , mode + ); + + BotanJS.addEventListener( "NS_INIT", onLoad ); + BotanJS.addEventListener( "NS_EXPORT", onLoad ); + }; + }; + + ns[ NS_EXPORT ]( EX_CLASS, "ClassLoader", Loader ); +})(); + diff --git a/botanjs/src/System/Net/_this.js b/botanjs/src/System/Net/_this.js new file mode 100644 index 0000000..89b8386 --- /dev/null +++ b/botanjs/src/System/Net/_this.js @@ -0,0 +1,141 @@ +(function(){ + var ns = __namespace( "System.Net" ); + /** @type {System.Debug} */ + var debug = __import( "System.Debug" ); + /** @type {Dandelion.IDOMObject} */ + var IDOMObject = __import( "Dandelion.IDOMObject" ); + + // Handles all http transfers + var getData = function (uri, handler, failedHandler) + { + var request = new XMLHttpRequest(); + debug.Info("[Net] GET: " + uri); + request.onreadystatechange = function() + { + /* + 0: request not initialized + 1: server connection established + 2: request received + 3: processing request + 4: request finished and response is ready + */ + if(request.readyState == 2) + { + debug.Info("[Net] GET R2:" + uri); + } + else if (request.readyState == 4) + { + debug.Info("[Net] GET R4:" + uri); + if (request.status == 200) + { + try + { + handler(request.responseText); + } + catch(e) + { + debug.Error(e); + failedHandler(null); + } + } + else + { + debug.Info("[Net] Status: " + request.status.toString()); + debug.Info(request.responseText); + failedHandler && failedHandler(null); + } + } + } + request.open("GET", uri, true); + request.send(); + }; + + var postFile = function (uri, data, handlers) + { + var request = new XMLHttpRequest() + , generalExchange = new IDOMObject( request ) + , uploadExchange = new IDOMObject( request.upload ) + ; + + if ( uploadExchange ) { + handlers.progress && uploadExchange.addEventListener("Progress", handlers.progress); + handlers.failed && uploadExchange.addEventListener("Error", handlers.failed); + } + + generalExchange.addEventListener("ReadyStateChange", function(e) { + if ( 4 == this.readyState ) { + handlers.complete && handlers.complete(request.responseText); + } + }); + + request.open("POST", uri, true); + // request.setRequestHeader("Content-Type", "multipart/form-data"); + request.send(data); + }; + + var postData = function (uri, data, handler, failedHandler) + { + var request = new XMLHttpRequest(); + // compile post string + data = compilePostData(data); + debug.Info("[Net] PostString: " + data); + request.onreadystatechange = function() + { + /* + 0: request not initialized + 1: server connection established + 2: request received + 3: processing request + 4: request finished and response is ready + */ + if(request.readyState == 2) + { + debug.Info("[Net] POST R2:" + uri); + } + else if (request.readyState == 4) + { + debug.Info("[Net] POST R4:" + uri); + if (request.status == 200) + { + try + { + var obj = JSON.parse(request.responseText); + obj.status ? handler(obj): failedHandler(obj); + } + catch(e) + { + debug.Error(e); + failedHandler(null); + } + } + else + { + debug.Info("[Net] Status: " + request.status.toString()); + debug.Info(request.responseText); + failedHandler(null); + } + } + }; + + request.open( "POST", uri ); + request.setRequestHeader( "Content-Type", "application/x-www-form-urlencoded" ); + request.send( data ); + }; + + var compilePostData = function (obj) + { + var postdata = "timestamp=" + new Date().getTime(); + for(var name in obj) + { + postdata += "&" + name + "=" + encodeURIComponent(obj[name]); + } + + return postdata; + }; + + ns[ NS_EXPORT ]( EX_FUNC, "getData", getData ); + ns[ NS_EXPORT ]( EX_FUNC, "postData", postData ); + ns[ NS_EXPORT ]( EX_FUNC, "postFile", postFile ); + // ns[ NS_EXPORT ]( EX_FUNC, "compilePostData", compilePostData ); +})(); + diff --git a/botanjs/src/System/Policy/_this.js b/botanjs/src/System/Policy/_this.js new file mode 100644 index 0000000..3ccef37 --- /dev/null +++ b/botanjs/src/System/Policy/_this.js @@ -0,0 +1,13 @@ +(function(){ + var ns = __namespace( "System.Policy" ); + + /** @type {System.Global} */ + var Global = __import( "System.Global" ); + + var isOriginAllowed = function( origin ) + { + return -1 < Global.ALLOWED_ORIGINS.indexOf( origin ); + }; + + ns[ NS_EXPORT ]( EX_FUNC, "isOriginAllowed", isOriginAllowed ); +})(); diff --git a/botanjs/src/System/Tick.js b/botanjs/src/System/Tick.js new file mode 100644 index 0000000..3951161 --- /dev/null +++ b/botanjs/src/System/Tick.js @@ -0,0 +1,50 @@ +(function(){ + var ns = __namespace( "System" ); + + var Tick = function() + { + // cycle counter + var nc = 0; + this.__started = false; + + this.loop = function() + { + for( var i in this.steppers ) + this.steppers[i](); + nc ++; + }; + + __readOnly( this, "count", function() { return nc; } ); + }; + + Tick.prototype.putStepper = function( stepperCallback ) + { + var l = this.steppers.length; + this.steppers[l] = stepperCallback; + return l; + }; + + Tick.prototype.start = function() + { + if( !this.__started ) + { + this.id = setInterval( this.loop.bind( this ), 0 ); + this.__started = true; + } + }; + + Tick.prototype.stop = function() + { + if( this.__started ) + { + this.__started = false; + clearInterval( this.id ); + } + }; + + Tick.prototype.steppers = []; + + __readOnly( Tick.prototype, "started", function() { return this.__started; } ); + + ns[ NS_EXPORT ]( EX_CLASS, "Tick", Tick ); +})(); diff --git a/botanjs/src/System/_this.js b/botanjs/src/System/_this.js new file mode 100644 index 0000000..4801f9e --- /dev/null +++ b/botanjs/src/System/_this.js @@ -0,0 +1,3 @@ +(function(){ + var ns = __namespace( "System" ) +})(); diff --git a/botanjs/src/System/utils/DataKey.js b/botanjs/src/System/utils/DataKey.js new file mode 100644 index 0000000..065a414 --- /dev/null +++ b/botanjs/src/System/utils/DataKey.js @@ -0,0 +1,17 @@ +(function(){ + var ns = __namespace( "System.utils" ); + var IKey = ns[ NS_INVOKE ]( "IKey" ); + // Data key + var DataKey = function ( name, value ) + { + IKey.call( + this + , "data-" + name + , value ? encodeURIComponent( String( value ) ) : "" + ); + }; + + __extends( DataKey, IKey ); + + ns[ NS_EXPORT ]( EX_CLASS, "DataKey", DataKey ); +})(); diff --git a/botanjs/src/System/utils/EventKey.js b/botanjs/src/System/utils/EventKey.js new file mode 100644 index 0000000..c43e4d5 --- /dev/null +++ b/botanjs/src/System/utils/EventKey.js @@ -0,0 +1,19 @@ +(function(){ + var ns = __namespace( "System.utils" ); + var IKey = ns[ NS_INVOKE ]( "IKey" ); + // Event key + var EventKey = function ( eventType, eventHandler ) + { + IKey.call( this, eventType, eventHandler ); + + this.type = eventType.toLowerCase(); + this.handler = eventHandler; + } + + __extends( EventKey, IKey ); + + EventKey.prototype.type = ""; + EventKey.prototype.handler = null; + + ns[ NS_EXPORT ]( EX_CLASS, "EventKey", EventKey ); +})(); diff --git a/botanjs/src/System/utils/IKey.js b/botanjs/src/System/utils/IKey.js new file mode 100644 index 0000000..7a3b641 --- /dev/null +++ b/botanjs/src/System/utils/IKey.js @@ -0,0 +1,49 @@ +(function(){ + var ns = __namespace( "System.utils" ); + var ClassName = "IKey"; + + ////// Class IKey + var IKey = function (name, value) + { + if ( name && ( typeof name != "string" ) ) return; + this.keyName = name; + + if( value instanceof IKey ) + { + this.keyValue = value; + } + else + { + this.keyValue = (value != undefined) ? String(value) : ""; + } + + this["keyName"] = this.keyName; + this["keyValue"] = this.keyValue; + }; + + IKey.prototype.keyName = ""; + IKey.prototype.keyValue = ""; + + var quickDef = function() + { + var l = arguments.length; + + if( l % 2 != 0 ) + { + ns[ NS_THROW ]( "Invalid Definition Count", ClassName ); + } + + var keys = []; + for( var i = 0; i < l; i += 2 ) + { + keys[ keys.length ] = new IKey( arguments[i], arguments[ i + 1 ] ); + } + + return keys; + }; + + __static_method( IKey, "quickDef", quickDef ); + + ns[ NS_EXPORT ]( EX_CLASS, "IKey", IKey ); + +})(); diff --git a/botanjs/src/System/utils/Perf.js b/botanjs/src/System/utils/Perf.js new file mode 100644 index 0000000..237ee47 --- /dev/null +++ b/botanjs/src/System/utils/Perf.js @@ -0,0 +1,49 @@ +(function(){ + // Performance Functions + var ns = __namespace( "System.utils.Perf" ); + + /** {{{ Fast UUID generator, RFC4122 version 4 compliant. + * author: Jeff Ward (jcward.com). + * license: MIT license + * link: http://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid-in-javascript/21963136#21963136 + **/ + var lut = []; + for ( var i=0; i < 256; i++ ) + { + lut[i] = ( i < 16 ? '0' : '' ) + ( i ).toString(16); + } + + var UUID = function() + { + var d0 = Math.random()*0xffffffff|0; + var d1 = Math.random()*0xffffffff|0; + var d2 = Math.random()*0xffffffff|0; + var d3 = Math.random()*0xffffffff|0; + return lut[d0&0xff]+lut[d0>>8&0xff]+lut[d0>>16&0xff]+lut[d0>>24&0xff]+'-'+ + lut[d1&0xff]+lut[d1>>8&0xff]+'-'+lut[d1>>16&0x0f|0x40]+lut[d1>>24&0xff]+'-'+ + lut[d2&0x3f|0x80]+lut[d2>>8&0xff]+'-'+lut[d2>>16&0xff]+lut[d2>>24&0xff]+ + lut[d3&0xff]+lut[d3>>8&0xff]+lut[d3>>16&0xff]+lut[d3>>24&0xff]; + }; + /* }}}*/ + + // Reverse an array using XOR swap + var Array_Reverse = function( array ) + { + var i = null; + var l = array.length; + var r = null; + for (i = 0, r = l - 1; i < r; i += 1, r -= 1) + { + var left = array[i]; + var right = array[r]; + left ^= right; + right ^= left; + left ^= right; + array[i] = left; + array[r] = right; + } + }; + + ns[ NS_EXPORT ]( EX_READONLY_GETTER, "uuid", UUID ); + ns[ NS_EXPORT ]( EX_FUNC, "ArrayReverse", Array_Reverse ); +})(); diff --git a/botanjs/src/System/utils/_this.js b/botanjs/src/System/utils/_this.js new file mode 100644 index 0000000..32ca158 --- /dev/null +++ b/botanjs/src/System/utils/_this.js @@ -0,0 +1,41 @@ +(function(){ + var ns = __namespace( "System.utils" ); + + // Get prop from obj if obj. is + var objGetProp = function ( obj, prop, type ) + { + if(obj && obj[prop]) + { + var t = obj[prop].constructor.toString().match(/function ([^\(]+)/); + if(t && t.length == 2 && t[1].toUpperCase() == type.toUpperCase()) + { + return obj[prop]; + } + } + return null; + }; + + var objSearch = function ( obj, cond, prop ) + { + for( var i in obj ) + { + if( cond( obj[i] ) ) + { + return obj[i][prop] || obj[i]; + } + } + return null; + }; + + var objMap = function( obj, callback ) + { + for( var i in obj ) + { + obj[i] = callback( obj[i] ); + } + }; + + ns[ NS_EXPORT ]( EX_FUNC, "objGetProp", objGetProp ); + ns[ NS_EXPORT ]( EX_FUNC, "objSearch", objSearch ); + ns[ NS_EXPORT ]( EX_FUNC, "objMap", objMap ); +})(); diff --git a/botanjs/src/_this.js b/botanjs/src/_this.js new file mode 100644 index 0000000..18a7c10 --- /dev/null +++ b/botanjs/src/_this.js @@ -0,0 +1,383 @@ +/*{{{ Shorthand Functions */ +var __extends = function( obj, target ) { + obj.prototype = Object.create( target.prototype ); + obj.prototype.constructor = obj; +}; +var __readOnly = function( prototype, name, callback ) +{ + Object.defineProperty( prototype, name, { + get: callback + , set: function( v ) { + throw new Error( "Setting a read-only property: " + this.p ); + }.bind( { p: name } ) + } ); +}; +var __getter = function( obj, name, callback ) +{ + Object.defineProperty( obj, name, { + get: callback + , set: function( v ) { + throw new Error( "Setting a read-only property: " + this.p ); + }.bind( { p: name } ) + } ); +}; +var __static_method = function( obj, name, callback ) +{ + Object.defineProperty( obj, name, { + get: function(){ return callback; } + , set: function( v ) { + throw new Error( "Setting a read-only property: " + this.p ); + }.bind( { p: name } ) + } ); +}; +var __const = __static_method; +/* End Shorthand Functions }}}*/ + +/*{{{ BotanEvent & EventDispatcher */ +var BotanEvent = function( name, data ) +{ + var __propagating = false; + var __propagated = false; + + __static_method( + this, "propagate" + , function() + { + if( !__propagated ) + { + __propagating = true; + } + __propagated = true; + } + ); + + __static_method( + this, "stopPropagating" + , function() + { + __propagating = false; + } + ); + + __const( this, "type", name ); + + __getter( + this, "propagating" + , function() + { + return __propagating; + } + ); + + __const( this, "data", data ); + + this.setTarget = function( target ) + { + __const( this, "target", target ); + this.setTarget = undefined; + }.bind( this ); +}; + +/** @constructor + * @extends EventTarget + **/ +var EventDispatcher = function() { + var events = {}; + var _self = this; + + var getStack = function( name ) + { + if( !events[ name ] ) events[ name ] = []; + return events[ name ]; + }; + + var _dispatch = function() + { + this.evt.propagate(); + for( var i in this.stack ) + { + if( this.evt.propagating ) + { + this.stack[ i ]( this.evt ); + } + } + this.evt.stopPropagating(); + }; + + this.addEventListener = function( type, handler ) + { + var stack = getStack( type ); + stack[ stack.length ] = handler; + }; + + this.removeEventListener = function( type, handler ) + { + var stack = getStack( type ); + var i = stack.indexOf( handler ); + if( i < 0 ) return; + delete stack[ i ]; + }; + + /** @type {Function} + * @param {BotanEvent} evt + */ + this.dispatchEvent = function( _evt ) + { + var _stack = getStack( _evt.type ); + if( _evt.setTarget ) _evt.setTarget( _self ); + // Dispatch the event asynchronously + setTimeout( _dispatch.bind({ evt: _evt, stack: _stack }), 0 ); + }; +}; + +/* End BotanEvent & EventDispatcher }}}*/ + +/** @type {Array} + * @extends {EventDispatcher} + */ +var NamespaceObj = function() { + EventDispatcher.call( this ); +}; + +NamespaceObj.prototype = new Array(); + +var packages = {}; +var _global = {}; +var _NSs = {}; +var _cacheIMP = {}; + +/*{{{ Constants */ +var EX_CONST = 0; +var EX_VAR = 1; +var EX_CLASS = 2; +var EX_FUNC = 3; + +var EX_READONLY_GETTER = 10; + +var NS_INVOKE = 0; +var NS_EXPORT = 1; +var NS_TRIGGER = 10; +var NS_THROW = 11; + +var TGR_IMPORT = 0; +/* End Constants }}}*/ + +/*{{{ Multi-instance handle */ +// Check if we are being imported 2nd time +// If yes, we get the instance and overload +// some core methods +var sGarden = window["BotanJS"]; + +/** @type {BotanJS} */ +var BotanJS = null; +var __namespace = null; +var __import = null; + +if( sGarden ) +{ + BotanJS = sGarden["sg"][0]; + __namespace = sGarden["sg"][1]; + __import = sGarden["sg"][2]; +} +/* End Multi-instance handle }}}*/ + +/*{{{ Root level bug-free handlers */ +BotanJS = BotanJS || (function() +{ + var i = 0; + var mesg = []; + var structures = []; + var edp = new EventDispatcher(); + + var log = {}; + log.write = function( m ) { mesg[ mesg.length ] = m; }; + __static_method( log, "read", function() { return mesg[ i ++ ]; } ); + __static_method( log, "end", function() { return ( mesg.length <= i ); } ); + + __const( edp, "log", log ); + + __static_method( edp, "define", function( f ) { structures[ structures.length ] = f; } ); + __static_method( edp, "getDef", function() { return structures.slice(); } ); + + return edp; +})(); +/* End Root level bug-free handlers }}}*/ + +/*{{{ Namespace declarator */ +__namespace = __namespace || function( ns ) +{ + if( _NSs[ ns ] ) return _NSs[ ns ]; + + var p = ns.split("."); + var l = p.length; + + var target = packages; + for( var i = 0; i < l; i ++ ) { + target[ p[i] ] = target[ p[i] ] || {}; + target = target[ p[i] ]; + } + + target.__TRIGGERS = []; + + nsObj = new NamespaceObj; + nsObj[ NS_EXPORT ] = function( type, name, obj ) + { + if( this.t[ name ] ) return; + this.t[ name ] = [ type, obj ]; + + /** @type {BotanEvent} */ + var evt = new BotanEvent( "NS_EXPORT", { + "name": this.n + "." + name + , "type": type + }); + + BotanJS.dispatchEvent( evt ); + + }.bind({ t: target, n: ns }); + + nsObj[ NS_INVOKE ] = function( target ) + { + if( !this.t[ target ] ) + { + throw new Error( + "[" + this.n + "] " + + "Invoke failed: " + target + " does not exists" + ); + } + + return this.t[ target ][1]; + }.bind({ t: target, n: ns }); + + nsObj[ NS_TRIGGER ] = function( code, func ) + { + this.__TRIGGERS[ code ] = func; + }.bind( target ); + + nsObj[ NS_THROW ] = function( message, subclass ) + { + subclass = subclass ? ( "." + subclass ) : ""; + throw new Error( + "[" + this.n + subclass + "] " + message + ); + }.bind({ n: ns }); + + /** @type {BotanEvent} */ + BotanJS.dispatchEvent( new BotanEvent( "NS_INIT", ns ) ); + return ( _NSs[ ns ] = nsObj ); +}; +/* End Namespace declarator }}}*/ + +/*{{{ Import operator */ +__import = __import || function( ns, noCache ) +{ + var nss = ns.replace( ".*", "" ); + if( _NSs[ nss ] ) + { + _NSs[ nss ].dispatchEvent( new BotanEvent( "NS_IMPORT", target ) ); + } + + // Read The Cache First + if( !noCache && _cacheIMP[ ns ] ) return _cacheIMP[ ns ]; + + var p = ns.split("."); + var l = p.length; + + var target = packages; + var wildcard = false; + for( var i = 0; i < l; i ++ ) + { + if( p[i] == "*" ) + { + wildcard = true; + break; + } + + target = target[ p[i] ]; + + if( !target ) + throw new Error( "No such class: " + ns ); + } + + if( target instanceof Array && p[i] != "*" ) + { + var rtarget = null; + if( target[0] == EX_READONLY_GETTER ) + { + rtarget = target[1](); + } + else + { + rtarget = target[1]; + } + + _cacheIMP[ ns ] = rtarget; + return rtarget; + } + + var nsObj = {}; + + for( var i in target ) + { + var j = target[i]; + if( j instanceof Array ) + { + if( wildcard && j[0] == EX_CLASS ) + { + nsObj[ i ] = j[1]; + } + else if( j[0] == EX_FUNC ) + { + nsObj[ i ] = j[1]; + } + else if( j[0] == EX_CONST ) + { + Object.defineProperty( nsObj, i, { + get: function() { + return this.t[ this.p ][1]; + }.bind( { p: i, t: target } ) + , set: function( v ) { + throw new Error( "Setting a read-only property: " + this.p ); + }.bind( { p: i } ) + }); + } + else if( j[0] == EX_VAR ) + { + Object.defineProperty( nsObj, i, { + get: function() { + return this.t[ this.p ][1](); + }.bind( { p: i, t: target } ) + , set: function( v ) { + this.t[ this.p ][1]( v ); + }.bind( { p: i, t: target } ) + }); + } + else if( j[0] == EX_READONLY_GETTER ) + { + Object.defineProperty( nsObj, i, { + get: j[1] + , set: function( v ) { + throw new Error( "Setting a read-only property: " + this.p ); + }.bind( { p: i } ) + }); + } + } + } + + _cacheIMP[ ns ] = nsObj; + return nsObj; +}; +/* End Import operator }}}*/ + +window["BotanJS"] = {}; +window["BotanJS"]["version"] = "0.2"; +window["BotanJS"]["codename"] = "Botanical framework.js"; +window["BotanJS"]["import"] = function( p ) +{ + try { return __import( p ); } + catch( e ) + { + if( sGarden ) return sGarden["import"]( p ); + throw e; + } +}; +window["BotanJS"]["sg"] = [ BotanJS, __namespace, __import ]; diff --git a/botanjs/src/externs/BotanEvent.js b/botanjs/src/externs/BotanEvent.js new file mode 100644 index 0000000..8da3ab0 --- /dev/null +++ b/botanjs/src/externs/BotanEvent.js @@ -0,0 +1,16 @@ +/** @constructor */ +var BotanEvent = function (){}; + +/** @type {object} */ +BotanEvent.data; + +/** @type {Function} */ +BotanEvent.propagate; +/** @type {Function} */ +BotanEvent.stopPropagating; + +/** @type {Boolean} */ +BotanEvent.propagating; + +/** @type {Function} */ +BotanEvent.setTarget; diff --git a/botanjs/src/externs/BotanJS.js b/botanjs/src/externs/BotanJS.js new file mode 100644 index 0000000..d695530 --- /dev/null +++ b/botanjs/src/externs/BotanJS.js @@ -0,0 +1,18 @@ +/** @constructor + * @implements {EventTarget} + **/ +var BotanJS = function() {}; + +/** @type {Function} */ +BotanJS.define; +/** @type {Function} */ +BotanJS.getDef; + +/** @type {Object} */ +BotanJS.log = {}; + /** @type {Function} */ + BotanJS.log.write; + /** @type {Function} */ + BotanJS.log.read; + /** @type {Function} */ + BotanJS.log.end; diff --git a/botanjs/src/externs/Components.MessageBox.js b/botanjs/src/externs/Components.MessageBox.js new file mode 100644 index 0000000..5dfea04 --- /dev/null +++ b/botanjs/src/externs/Components.MessageBox.js @@ -0,0 +1,7 @@ +/** @constructor */ +Components.MessageBox = function() {}; + +/** @type {Function} */ +Components.MessageBox.setHandler; +/** @type {Function} */ +Components.MessageBox.show; diff --git a/botanjs/src/externs/Components.Mouse.Clipboard.SwfHelperObj.js b/botanjs/src/externs/Components.Mouse.Clipboard.SwfHelperObj.js new file mode 100644 index 0000000..7431017 --- /dev/null +++ b/botanjs/src/externs/Components.Mouse.Clipboard.SwfHelperObj.js @@ -0,0 +1,9 @@ +/** @constructor */ +Components.Mouse.Clipboard.SwfHelperObj = function() {}; + +/** @type {Function} */ +Components.Mouse.Clipboard.SwfHelperObj.dummy; +/** @type {Function} */ +Components.Mouse.Clipboard.SwfHelperObj.debug; +/** @type {Function} */ +Components.Mouse.Clipboard.SwfHelperObj.copy; diff --git a/botanjs/src/externs/Components.Mouse.Clipboard.js b/botanjs/src/externs/Components.Mouse.Clipboard.js new file mode 100644 index 0000000..75ffc13 --- /dev/null +++ b/botanjs/src/externs/Components.Mouse.Clipboard.js @@ -0,0 +1,15 @@ +/** @constructor */ +Components.Mouse.Clipboard = function() {}; + +/** @type {Function} */ +Components.Mouse.Clipboard.init; +/** @type {Function} */ +Components.Mouse.Clipboard.setTextToCopy; +/** @type {Function} */ +Components.Mouse.Clipboard.onMouseOver; +/** @type {Function} */ +Components.Mouse.Clipboard.onMouseOut; +/** @type {Function} */ +Components.Mouse.Clipboard._textCopied; +/** @type {Function} */ +Components.Mouse.Clipboard.capture; diff --git a/botanjs/src/externs/Components.Mouse.ContextMenu.js b/botanjs/src/externs/Components.Mouse.ContextMenu.js new file mode 100644 index 0000000..5f04077 --- /dev/null +++ b/botanjs/src/externs/Components.Mouse.ContextMenu.js @@ -0,0 +1,2 @@ +/** @constructor */ +Components.Mouse.ContextMenu = function() {}; diff --git a/botanjs/src/externs/Components.Mouse.js b/botanjs/src/externs/Components.Mouse.js new file mode 100644 index 0000000..047fb9d --- /dev/null +++ b/botanjs/src/externs/Components.Mouse.js @@ -0,0 +1,2 @@ +/** @constructor */ +Components.Mouse = function() {}; diff --git a/botanjs/src/externs/Components.js b/botanjs/src/externs/Components.js new file mode 100644 index 0000000..e22d0fe --- /dev/null +++ b/botanjs/src/externs/Components.js @@ -0,0 +1,2 @@ +/** @constructor */ +var Components = function() {}; diff --git a/botanjs/src/externs/Dandelion.CSSAnimations.MovieClip.js b/botanjs/src/externs/Dandelion.CSSAnimations.MovieClip.js new file mode 100644 index 0000000..d7af28f --- /dev/null +++ b/botanjs/src/externs/Dandelion.CSSAnimations.MovieClip.js @@ -0,0 +1,14 @@ +/** @constructor */ +Dandelion.CSSAnimations.MovieClip = function (){}; + +/** @type {Function} */ +Dandelion.CSSAnimations.MovieClip.gotoFrame; +/** @type {Function} */ +Dandelion.CSSAnimations.MovieClip.prevFrame; +/** @type {Function} */ +Dandelion.CSSAnimations.MovieClip.nextFrame; +/** @type {Element} */ +Dandelion.CSSAnimations.MovieClip.stage; + +/** @type {Function} */ +Dandelion.CSSAnimations.MouseOverMovie; diff --git a/botanjs/src/externs/Dandelion.CSSAnimations.js b/botanjs/src/externs/Dandelion.CSSAnimations.js new file mode 100644 index 0000000..1324aa4 --- /dev/null +++ b/botanjs/src/externs/Dandelion.CSSAnimations.js @@ -0,0 +1,2 @@ +/** @constructor */ +Dandelion.CSSAnimations = function (){}; diff --git a/botanjs/src/externs/Dandelion.IDOMElement.js b/botanjs/src/externs/Dandelion.IDOMElement.js new file mode 100644 index 0000000..b00b4ec --- /dev/null +++ b/botanjs/src/externs/Dandelion.IDOMElement.js @@ -0,0 +1,23 @@ +/** @constructor */ +Dandelion.IDOMElement = function (){} + +/** @type {Function} */ +Dandelion.IDOMElement.getDAttribute; +/** @type {Function} */ +Dandelion.IDOMElement.setAttribute; +/** @type {Function} */ +Dandelion.IDOMElement.lootChildren; +/** @type {Function} */ +Dandelion.IDOMElement.foreach; +/** @type {Function} */ +Dandelion.IDOMElement.first; +/** @type {Function} */ +Dandelion.IDOMElement.last; +/** @type {Function} */ +Dandelion.IDOMElement.contains; +/** @type {Function} */ +Dandelion.IDOMElement.aKeys; +/** @type {Element} */ +Dandelion.IDOMElement.element; +/** @type {Element} */ +Dandelion.IDOMElement.reverseChild; diff --git a/botanjs/src/externs/Dandelion.IDOMObject.js b/botanjs/src/externs/Dandelion.IDOMObject.js new file mode 100644 index 0000000..d48a31c --- /dev/null +++ b/botanjs/src/externs/Dandelion.IDOMObject.js @@ -0,0 +1,11 @@ +/** @constructor */ +Dandelion.IDOMObject = function (){} + +/** @type {Function} */ +Dandelion.IDOMObject.addEventListener; +/** @type {Function} */ +Dandelion.IDOMObject.addEventListeners; +/** @type {Function} */ +Dandelion.IDOMObject.hasListener; +/** @type {Function} */ +Dandelion.IDOMObject.removeEventListener; diff --git a/botanjs/src/externs/Dandelion.Swf.ExtAPI.js b/botanjs/src/externs/Dandelion.Swf.ExtAPI.js new file mode 100644 index 0000000..2cceb3e --- /dev/null +++ b/botanjs/src/externs/Dandelion.Swf.ExtAPI.js @@ -0,0 +1,5 @@ +/** @constructor */ +Dandelion.Swf.ExtAPI = function (){} + +/** @type {Function} */ +Dandelion.Swf.ExtAPI.ready; diff --git a/botanjs/src/externs/Dandelion.Swf.js b/botanjs/src/externs/Dandelion.Swf.js new file mode 100644 index 0000000..27381f8 --- /dev/null +++ b/botanjs/src/externs/Dandelion.Swf.js @@ -0,0 +1,7 @@ +/** @constructor */ +Dandelion.Swf = function (){} + +/** @type {Function} */ +Dandelion.Swf.create; +/** @type {Function} */ +Dandelion.Swf.realize; diff --git a/botanjs/src/externs/Dandelion.js b/botanjs/src/externs/Dandelion.js new file mode 100644 index 0000000..9a6897b --- /dev/null +++ b/botanjs/src/externs/Dandelion.js @@ -0,0 +1,38 @@ +/** @constructor */ +var Dandelion = function (){} + +/** @type {Function} */ +Dandelion.wrap; + +/** @type {Function} */ +Dandelion.wrapc; + +/** @type {Function} */ +Dandelion.wrape; + +/** @type {Function} */ +Dandelion.wrapne; + +/** @type {Function} */ +Dandelion.wrapna; + +/** @type {Function} */ +Dandelion.textNode; + +/** @type {Function} */ +Dandelion.bubbleUp; + +/** @type {Function} */ +Dandelion.chainUpApply; + +/** @type {Function} */ +Dandelion.id; + +/** @type {Function} */ +Dandelion.tag; + +/** @type {Function} */ +Dandelion.name; + +/** @type {Function} */ +Dandelion.glass; diff --git a/botanjs/src/externs/System.Cycle.Trigger.js b/botanjs/src/externs/System.Cycle.Trigger.js new file mode 100644 index 0000000..6df930d --- /dev/null +++ b/botanjs/src/externs/System.Cycle.Trigger.js @@ -0,0 +1,11 @@ +/** @constructor */ +System.Cycle.Trigger = function (){} + +/** @type {Function} */ +System.Cycle.Trigger.register; + +/** @type {Function} */ +System.Cycle.Trigger.transition; + +/** @type {Function} */ +System.Cycle.Trigger.height; diff --git a/botanjs/src/externs/System.Cycle.js b/botanjs/src/externs/System.Cycle.js new file mode 100644 index 0000000..917267e --- /dev/null +++ b/botanjs/src/externs/System.Cycle.js @@ -0,0 +1,17 @@ +/** @constructor */ +System.Cycle = function (){} + +/** @type {Function} */ +System.Cycle.next; + +/** @type {Function} */ +System.Cycle.delay; + +/** @type {Function} */ +System.Cycle.perma; + +/** @type {Function} */ +System.Cycle.permaRemove; + +/** @type {System.Tick} */ +System.Cycle.TICK; diff --git a/botanjs/src/externs/System.Debug.js b/botanjs/src/externs/System.Debug.js new file mode 100644 index 0000000..da76ffb --- /dev/null +++ b/botanjs/src/externs/System.Debug.js @@ -0,0 +1,8 @@ +/** @constructor */ +System.Debug = function (){} + +/** @type {Function} */ +System.Debug.Info; + +/** @type {Function} */ +System.Debug.Error; diff --git a/botanjs/src/externs/System.Global.js b/botanjs/src/externs/System.Global.js new file mode 100644 index 0000000..4a725d0 --- /dev/null +++ b/botanjs/src/externs/System.Global.js @@ -0,0 +1,8 @@ +/** @constructor */ +System.Global = function (){} + +/** @type {Boolean} */ +System.Global.debug; + +/** @type {Boolean} */ +System.Global.IE; diff --git a/botanjs/src/externs/System.Log.js b/botanjs/src/externs/System.Log.js new file mode 100644 index 0000000..504d258 --- /dev/null +++ b/botanjs/src/externs/System.Log.js @@ -0,0 +1,16 @@ +/** @constructor */ +System.Log = function (){} + +/** @type {Function} */ +System.Log.writeLine; +/** @type {Function} */ +System.Log.registerHandler; +/** @type {Function} */ +System.Log.removeHandler; + +/** @type {const} */ +System.Log.ERROR; +/** @type {const} */ +System.Log.INFO; +/** @type {const} */ +System.Log.SYSTEM; diff --git a/botanjs/src/externs/System.Net.js b/botanjs/src/externs/System.Net.js new file mode 100644 index 0000000..b4277ac --- /dev/null +++ b/botanjs/src/externs/System.Net.js @@ -0,0 +1,11 @@ +/** @constructor */ +System.Net = function (){} + +/** @type {Function} */ +System.Net.getData; + +/** @type {Function} */ +System.Net.postFile; + +/** @type {Function} */ +System.Net.postData; diff --git a/botanjs/src/externs/System.Policy.js b/botanjs/src/externs/System.Policy.js new file mode 100644 index 0000000..647dd3d --- /dev/null +++ b/botanjs/src/externs/System.Policy.js @@ -0,0 +1,5 @@ +/** @constructor */ +System.Policy = function (){}; + +/** @type {Function} */ +System.Policy.isOriginAllowed; diff --git a/botanjs/src/externs/System.Tick.js b/botanjs/src/externs/System.Tick.js new file mode 100644 index 0000000..5deafd2 --- /dev/null +++ b/botanjs/src/externs/System.Tick.js @@ -0,0 +1,13 @@ +/** @constructor */ +System.Tick = function (){} + +/** @type {Function} */ +System.Tick.prototype.putStepper; + +/** @type {Function} */ +System.Tick.prototype.start; +/** @type {Function} */ +System.Tick.prototype.stop; + +/** @type {Array} */ +System.Tick.prototype.steppers; diff --git a/botanjs/src/externs/System.js b/botanjs/src/externs/System.js new file mode 100644 index 0000000..8d48ff7 --- /dev/null +++ b/botanjs/src/externs/System.js @@ -0,0 +1,2 @@ +/** @constructor */ +var System = function (){} diff --git a/botanjs/src/externs/System.utils.DataKey.js b/botanjs/src/externs/System.utils.DataKey.js new file mode 100644 index 0000000..2528085 --- /dev/null +++ b/botanjs/src/externs/System.utils.DataKey.js @@ -0,0 +1,4 @@ +/** @constructor + * @extends {System.utils.IKey} + */ +System.utils.DataKey = function (){} diff --git a/botanjs/src/externs/System.utils.EventKey.js b/botanjs/src/externs/System.utils.EventKey.js new file mode 100644 index 0000000..daac6d8 --- /dev/null +++ b/botanjs/src/externs/System.utils.EventKey.js @@ -0,0 +1,10 @@ +/** @constructor + * @extends {System.utils.IKey} + */ +System.utils.EventKey = function (){}; + +/** @type {String} */ +System.utils.EventKey.type; + +/** @type {Function} */ +System.utils.EventKey.handler; diff --git a/botanjs/src/externs/System.utils.IKey.js b/botanjs/src/externs/System.utils.IKey.js new file mode 100644 index 0000000..5957861 --- /dev/null +++ b/botanjs/src/externs/System.utils.IKey.js @@ -0,0 +1,11 @@ +/** @constructor */ +System.utils.IKey = function (){} + +/** @type {string} */ +System.utils.IKey.keyName; + +/** @type {object} */ +System.utils.IKey.keyValue; + +/** @type {Function} */ +System.utils.IKey.quickDef; diff --git a/botanjs/src/externs/System.utils.Perf.js b/botanjs/src/externs/System.utils.Perf.js new file mode 100644 index 0000000..756699f --- /dev/null +++ b/botanjs/src/externs/System.utils.Perf.js @@ -0,0 +1,8 @@ +/** @constructor */ +System.utils.Perf = function (){} + +/** @type {String} */ +System.utils.Perf.uuid; + +/** @type {Function} */ +System.utils.Perf.ArrayReverse; diff --git a/botanjs/src/externs/System.utils.js b/botanjs/src/externs/System.utils.js new file mode 100644 index 0000000..2c1eb90 --- /dev/null +++ b/botanjs/src/externs/System.utils.js @@ -0,0 +1,9 @@ +/** @constructor */ +System.utils = function (){} + +/** @type {Function} */ +System.utils.objGetProp; +/** @type {Function} */ +System.utils.objSearch; +/** @type {Function} */ +System.utils.objMap; diff --git a/cache/.keep b/cache/.keep new file mode 100644 index 0000000..e69de29 diff --git a/logs/.keep b/logs/.keep new file mode 100644 index 0000000..e69de29 diff --git a/settings.ini b/settings.ini new file mode 100644 index 0000000..65c8da3 --- /dev/null +++ b/settings.ini @@ -0,0 +1,17 @@ +[Paths] +SiteRoot = /var/www/botanjs +Runtime = ${SiteRoot} +Log = ${SiteRoot}/logs +Cache = ${SiteRoot}/cache + +[BotanJS] +SrcDir = ${Paths:Runtime}/botanjs/src + +REDIS_PASS = PASSWORD_FOR_REDIS_DB + +CeleryBroker = redis://:${REDIS_PASS}@123.123.123.123:1234/9 + + +[Service] +user = www-data +group = www-data