Compare commits
1 Commits
tags/PROD
...
tags/Last1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
973a54719f |
5
mozilla/js/src/liveconnect/MANIFEST
Normal file
@@ -0,0 +1,5 @@
|
||||
# This is a list of local files which get copied to the mozilla:dist directory
|
||||
#
|
||||
|
||||
jsjava.h
|
||||
nsILiveconnect.h
|
||||
89
mozilla/js/src/liveconnect/Makefile
Normal file
@@ -0,0 +1,89 @@
|
||||
#!gmake
|
||||
#
|
||||
# The contents of this file are subject to the Netscape Public License
|
||||
# Version 1.0 (the "NPL"); you may not use this file except in
|
||||
# compliance with the NPL. You may obtain a copy of the NPL at
|
||||
# http://www.mozilla.org/NPL/
|
||||
#
|
||||
# Software distributed under the NPL is distributed on an "AS IS" basis,
|
||||
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
||||
# for the specific language governing rights and limitations under the
|
||||
# NPL.
|
||||
#
|
||||
# The Initial Developer of this code under the NPL is Netscape
|
||||
# Communications Corporation. Portions created by Netscape are
|
||||
# Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
||||
# Reserved.
|
||||
|
||||
|
||||
|
||||
DEPTH = ../../..
|
||||
|
||||
include $(DEPTH)/config/config.mk
|
||||
|
||||
ifdef NSJVM
|
||||
DIRS = classes
|
||||
endif
|
||||
|
||||
MODULE = java
|
||||
LIBRARY_NAME = jsj
|
||||
|
||||
REQUIRES = java js applet nspr img util layer xpcom
|
||||
|
||||
CSRCS = jsj.c \
|
||||
jsj_JSObject.c \
|
||||
jsj_JavaArray.c \
|
||||
jsj_JavaClass.c \
|
||||
jsj_JavaMember.c \
|
||||
jsj_JavaObject.c \
|
||||
jsj_JavaPackage.c \
|
||||
jsj_array.c \
|
||||
jsj_class.c \
|
||||
jsj_convert.c \
|
||||
jsj_field.c \
|
||||
jsj_hash.c \
|
||||
jsj_method.c \
|
||||
jsj_utils.c \
|
||||
nsCLiveconnect.c \
|
||||
nsCLiveconnectFactory.c
|
||||
|
||||
|
||||
LLIBS=$(LIBNSPR) $(DIST)/lib/js$(MOZ_BITS)$(VERSION_NUMBER).lib \
|
||||
$(DIST)/lib/xpcom32.lib
|
||||
|
||||
|
||||
ifdef NSJVM
|
||||
JNI_GEN = netscape.javascript.JSObject netscape.javascript.JSException
|
||||
endif
|
||||
|
||||
EXPORTS = jsjava.h \
|
||||
$(JNI_GEN_DIR)/netscape_javascript_JSObject.h \
|
||||
$(JNI_GEN_DIR)/netscape_javascript_JSException.h \
|
||||
nsILiveconnect.h \
|
||||
$(NULL)
|
||||
|
||||
|
||||
|
||||
include $(DEPTH)/config/rules.mk
|
||||
|
||||
######################################################################
|
||||
|
||||
# Generate jsj_nodl.c (so that you can check it in)
|
||||
# These make rules only works on IRIX...sigh
|
||||
|
||||
ifeq ($(OS_ARCH),IRIX)
|
||||
jsj_nodl.c: $(OBJDIR)/stubs.o Makefile $(DEPTH)/config/nodl.pl
|
||||
rm -f $@
|
||||
$(PERL) $(DEPTH)/config/nodl.pl "jsj_nodl_tab" \
|
||||
`nm -Bn $(OBJDIR)/stubs.o | egrep Java_.*_stub | awk '{print $$3;}'` > $@
|
||||
endif
|
||||
|
||||
ifdef JAVA_OR_OJI
|
||||
$(OBJDIR)/stubs.o: \
|
||||
$(JNI_GEN_DIR)/netscape_javascript_JSObject.c \
|
||||
$(JNI_GEN_DIR)/netscape_javascript_JSException.c \
|
||||
$(NULL)
|
||||
else
|
||||
$(OBJDIR)/stubs.o:
|
||||
endif
|
||||
|
||||
90
mozilla/js/src/liveconnect/Makefile.in
Normal file
@@ -0,0 +1,90 @@
|
||||
#!gmake
|
||||
#
|
||||
# The contents of this file are subject to the Netscape Public License
|
||||
# Version 1.0 (the "NPL"); you may not use this file except in
|
||||
# compliance with the NPL. You may obtain a copy of the NPL at
|
||||
# http://www.mozilla.org/NPL/
|
||||
#
|
||||
# Software distributed under the NPL is distributed on an "AS IS" basis,
|
||||
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
||||
# for the specific language governing rights and limitations under the
|
||||
# NPL.
|
||||
#
|
||||
# The Initial Developer of this code under the NPL is Netscape
|
||||
# Communications Corporation. Portions created by Netscape are
|
||||
# Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
||||
# Reserved.
|
||||
|
||||
|
||||
|
||||
DEPTH = ../../..
|
||||
topsrcdir = @top_srcdir@
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
include $(topsrcdir)/config/config.mk
|
||||
|
||||
ifdef NSJVM
|
||||
DIRS = classes
|
||||
endif
|
||||
|
||||
|
||||
MODULE = java
|
||||
LIBRARY_NAME = jsj
|
||||
|
||||
REQUIRES = java js applet nspr img util layer xpcom caps oji plugin
|
||||
|
||||
CSRCS = jsj.c \
|
||||
jsj_JSObject.c \
|
||||
jsj_JavaArray.c \
|
||||
jsj_JavaClass.c \
|
||||
jsj_JavaMember.c \
|
||||
jsj_JavaObject.c \
|
||||
jsj_JavaPackage.c \
|
||||
jsj_array.c \
|
||||
jsj_class.c \
|
||||
jsj_convert.c \
|
||||
jsj_field.c \
|
||||
jsj_hash.c \
|
||||
jsj_method.c \
|
||||
jsj_utils.c
|
||||
nsCLiveconnect.c \
|
||||
nsCLiveconnectFactory.c
|
||||
|
||||
|
||||
ifdef NSJVM
|
||||
JNI_GEN = netscape.javascript.JSObject netscape.javascript.JSException
|
||||
endif
|
||||
|
||||
EXPORTS = $(srcdir)/jsjava.h \
|
||||
$(srcdir)/$(JNI_GEN_DIR)/netscape_javascript_JSObject.h \
|
||||
$(srcdir)/$(JNI_GEN_DIR)/netscape_javascript_JSException.h \
|
||||
$(NULL)
|
||||
|
||||
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
||||
######################################################################
|
||||
|
||||
# Generate jsj_nodl.c (so that you can check it in)
|
||||
# These make rules only works on IRIX...sigh
|
||||
|
||||
ifeq ($(OS_ARCH),IRIX)
|
||||
jsj_nodl.c: $(OBJDIR)/stubs.o Makefile $(topsrcdir)/config/nodl.pl
|
||||
rm -f $@
|
||||
$(PERL) $(topsrcdir)/config/nodl.pl "jsj_nodl_tab" \
|
||||
`nm -Bn $(OBJDIR)/stubs.o | egrep Java_.*_stub | awk '{print $$3;}'` > $@
|
||||
endif
|
||||
|
||||
ifdef JAVA_OR_OJI
|
||||
$(OBJDIR)/stubs.o: \
|
||||
$(JRI_GEN_DIR)/netscape_javascript_JSObject.c \
|
||||
$(JRI_GEN_DIR)/netscape_javascript_JSException.c \
|
||||
$(NULL)
|
||||
else
|
||||
$(OBJDIR)/stubs.o:
|
||||
endif
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
/* DO NOT EDIT THIS FILE - it is machine generated */
|
||||
#include "jni.h"
|
||||
|
||||
/* Header for class netscape_javascript_JSException */
|
||||
|
||||
#ifndef _Included_netscape_javascript_JSException
|
||||
#define _Included_netscape_javascript_JSException
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
102
mozilla/js/src/liveconnect/_jni/netscape_javascript_JSObject.h
Normal file
@@ -0,0 +1,102 @@
|
||||
/* DO NOT EDIT THIS FILE - it is machine generated */
|
||||
#include "jni.h"
|
||||
|
||||
/* Header for class netscape_javascript_JSObject */
|
||||
|
||||
#ifndef _Included_netscape_javascript_JSObject
|
||||
#define _Included_netscape_javascript_JSObject
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
/*
|
||||
* Class: netscape_javascript_JSObject
|
||||
* Method: initClass
|
||||
* Signature: ()V
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_netscape_javascript_JSObject_initClass
|
||||
(JNIEnv *, jclass);
|
||||
|
||||
/*
|
||||
* Class: netscape_javascript_JSObject
|
||||
* Method: getMember
|
||||
* Signature: (Ljava/lang/String;)Ljava/lang/Object;
|
||||
*/
|
||||
JNIEXPORT jobject JNICALL Java_netscape_javascript_JSObject_getMember
|
||||
(JNIEnv *, jobject, jstring);
|
||||
|
||||
/*
|
||||
* Class: netscape_javascript_JSObject
|
||||
* Method: getSlot
|
||||
* Signature: (I)Ljava/lang/Object;
|
||||
*/
|
||||
JNIEXPORT jobject JNICALL Java_netscape_javascript_JSObject_getSlot
|
||||
(JNIEnv *, jobject, jint);
|
||||
|
||||
/*
|
||||
* Class: netscape_javascript_JSObject
|
||||
* Method: setMember
|
||||
* Signature: (Ljava/lang/String;Ljava/lang/Object;)V
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_netscape_javascript_JSObject_setMember
|
||||
(JNIEnv *, jobject, jstring, jobject);
|
||||
|
||||
/*
|
||||
* Class: netscape_javascript_JSObject
|
||||
* Method: setSlot
|
||||
* Signature: (ILjava/lang/Object;)V
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_netscape_javascript_JSObject_setSlot
|
||||
(JNIEnv *, jobject, jint, jobject);
|
||||
|
||||
/*
|
||||
* Class: netscape_javascript_JSObject
|
||||
* Method: removeMember
|
||||
* Signature: (Ljava/lang/String;)V
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_netscape_javascript_JSObject_removeMember
|
||||
(JNIEnv *, jobject, jstring);
|
||||
|
||||
/*
|
||||
* Class: netscape_javascript_JSObject
|
||||
* Method: call
|
||||
* Signature: (Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/Object;
|
||||
*/
|
||||
JNIEXPORT jobject JNICALL Java_netscape_javascript_JSObject_call
|
||||
(JNIEnv *, jobject, jstring, jobjectArray);
|
||||
|
||||
/*
|
||||
* Class: netscape_javascript_JSObject
|
||||
* Method: eval
|
||||
* Signature: (Ljava/lang/String;)Ljava/lang/Object;
|
||||
*/
|
||||
JNIEXPORT jobject JNICALL Java_netscape_javascript_JSObject_eval
|
||||
(JNIEnv *, jobject, jstring);
|
||||
|
||||
/*
|
||||
* Class: netscape_javascript_JSObject
|
||||
* Method: toString
|
||||
* Signature: ()Ljava/lang/String;
|
||||
*/
|
||||
JNIEXPORT jstring JNICALL Java_netscape_javascript_JSObject_toString
|
||||
(JNIEnv *, jobject);
|
||||
|
||||
/*
|
||||
* Class: netscape_javascript_JSObject
|
||||
* Method: getWindow
|
||||
* Signature: (Ljava/applet/Applet;)Lnetscape/javascript/JSObject;
|
||||
*/
|
||||
JNIEXPORT jobject JNICALL Java_netscape_javascript_JSObject_getWindow
|
||||
(JNIEnv *, jclass, jobject);
|
||||
|
||||
/*
|
||||
* Class: netscape_javascript_JSObject
|
||||
* Method: finalize
|
||||
* Signature: ()V
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_netscape_javascript_JSObject_finalize
|
||||
(JNIEnv *, jobject);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
65
mozilla/js/src/liveconnect/classes/Makefile
Normal file
@@ -0,0 +1,65 @@
|
||||
#!gmake
|
||||
#
|
||||
# The contents of this file are subject to the Netscape Public License
|
||||
# Version 1.0 (the "NPL"); you may not use this file except in
|
||||
# compliance with the NPL. You may obtain a copy of the NPL at
|
||||
# http://www.mozilla.org/NPL/
|
||||
#
|
||||
# Software distributed under the NPL is distributed on an "AS IS" basis,
|
||||
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
||||
# for the specific language governing rights and limitations under the
|
||||
# NPL.
|
||||
#
|
||||
# The Initial Developer of this code under the NPL is Netscape
|
||||
# Communications Corporation. Portions created by Netscape are
|
||||
# Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
||||
# Reserved.
|
||||
|
||||
|
||||
|
||||
DEPTH = ../../../..
|
||||
|
||||
MODULE = java
|
||||
|
||||
#
|
||||
# the idea is that the install phase for those modules will
|
||||
# make their own signed jar files
|
||||
# there are some exceptions here that we deal with
|
||||
# stuff in modules and in ns/js/jsj
|
||||
#
|
||||
JMODS = netscape/javascript netscape/javascript/adapters
|
||||
|
||||
#
|
||||
# JDIRS is dependant on JAVA_DESTPATH in config/rules.m[a]k.
|
||||
# Be sure to touch that directory if you add a new directory to
|
||||
# JDIRS, or else it will not build. FIXME
|
||||
#
|
||||
JDIRS = $(JMODS)
|
||||
|
||||
JAR_JSJ = jsj10.jar
|
||||
JAR_JSJ_CLASSES = $(JMODS)
|
||||
|
||||
#
|
||||
# jars to build at install time
|
||||
#
|
||||
JARS = $(JAR_JSJ)
|
||||
|
||||
include $(DEPTH)/config/rules.mk
|
||||
|
||||
JAVA_SOURCEPATH = $(DEPTH)/js/src/liveconnect/classes
|
||||
|
||||
doc::
|
||||
$(JAVADOC) -d $(DIST)/doc netscape.javascript
|
||||
|
||||
natives_list:: FORCE
|
||||
rm -rf $@
|
||||
find . -name "*.class" -print | sed 's@\./\(.*\)\.class$$@\1@' | \
|
||||
sed 's@/@.@g' | xargs $(JVH) -natives | sort > $@
|
||||
|
||||
check_natives:: natives_list
|
||||
rm -f found_natives
|
||||
nm -B ../$(OBJDIR)/*.o \
|
||||
| egrep "Java.*_stub" | awk '{ print $$3; }' | sort > found_natives
|
||||
diff found_natives natives_list
|
||||
|
||||
FORCE:
|
||||
70
mozilla/js/src/liveconnect/classes/Makefile.in
Normal file
@@ -0,0 +1,70 @@
|
||||
#!gmake
|
||||
#
|
||||
# The contents of this file are subject to the Netscape Public License
|
||||
# Version 1.0 (the "NPL"); you may not use this file except in
|
||||
# compliance with the NPL. You may obtain a copy of the NPL at
|
||||
# http://www.mozilla.org/NPL/
|
||||
#
|
||||
# Software distributed under the NPL is distributed on an "AS IS" basis,
|
||||
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
||||
# for the specific language governing rights and limitations under the
|
||||
# NPL.
|
||||
#
|
||||
# The Initial Developer of this code under the NPL is Netscape
|
||||
# Communications Corporation. Portions created by Netscape are
|
||||
# Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
||||
# Reserved.
|
||||
|
||||
|
||||
|
||||
DEPTH = ../../../..
|
||||
topsrcdir = @top_srcdir@
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
MODULE = java
|
||||
|
||||
#
|
||||
# the idea is that the install phase for those modules will
|
||||
# make their own signed jar files
|
||||
# there are some exceptions here that we deal with
|
||||
# stuff in modules and in ns/js/jsj
|
||||
#
|
||||
JMODS = netscape/javascript netscape/javascript/adapters
|
||||
|
||||
#
|
||||
# JDIRS is dependant on JAVA_DESTPATH in config/rules.m[a]k.
|
||||
# Be sure to touch that directory if you add a new directory to
|
||||
# JDIRS, or else it will not build. FIXME
|
||||
#
|
||||
JDIRS = $(JMODS)
|
||||
|
||||
JAR_JSJ = jsj10.jar
|
||||
JAR_JSJ_CLASSES = $(JMODS)
|
||||
|
||||
#
|
||||
# jars to build at install time
|
||||
#
|
||||
JARS = $(JAR_JSJ)
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
||||
JAVA_SOURCEPATH = $(topsrcdir)/js/src/liveconnect/classes
|
||||
|
||||
doc::
|
||||
$(JAVADOC) -d $(DIST)/doc netscape.javascript
|
||||
|
||||
natives_list:: FORCE
|
||||
rm -rf $@
|
||||
find . -name "*.class" -print | sed 's@\./\(.*\)\.class$$@\1@' | \
|
||||
sed 's@/@.@g' | xargs $(JVH) -natives | sort > $@
|
||||
|
||||
check_natives:: natives_list
|
||||
rm -f found_natives
|
||||
nm -B ../$(OBJDIR)/*.o \
|
||||
| egrep "Java.*_stub" | awk '{ print $$3; }' | sort > found_natives
|
||||
diff found_natives natives_list
|
||||
|
||||
FORCE:
|
||||
78
mozilla/js/src/liveconnect/classes/makefile.win
Normal file
@@ -0,0 +1,78 @@
|
||||
#!gmake
|
||||
#
|
||||
# The contents of this file are subject to the Netscape Public License
|
||||
# Version 1.0 (the "NPL"); you may not use this file except in
|
||||
# compliance with the NPL. You may obtain a copy of the NPL at
|
||||
# http://www.mozilla.org/NPL/
|
||||
#
|
||||
# Software distributed under the NPL is distributed on an "AS IS" basis,
|
||||
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
||||
# for the specific language governing rights and limitations under the
|
||||
# NPL.
|
||||
#
|
||||
# The Initial Developer of this code under the NPL is Netscape
|
||||
# Communications Corporation. Portions created by Netscape are
|
||||
# Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
||||
# Reserved.
|
||||
|
||||
IGNORE_MANIFEST=1
|
||||
#
|
||||
|
||||
#//------------------------------------------------------------------------
|
||||
#//
|
||||
#// Makefile to build the JavaScript-Java tree
|
||||
#//
|
||||
#//------------------------------------------------------------------------
|
||||
|
||||
DEPTH = ..\..\..\..
|
||||
|
||||
JAVA_SOURCEPATH=$(DEPTH)\js\src\liveconnect\classes
|
||||
|
||||
#//------------------------------------------------------------------------
|
||||
#//
|
||||
#// Define the files necessary to build the target (ie. OBJS)
|
||||
#//
|
||||
#//------------------------------------------------------------------------
|
||||
include <$(DEPTH)\config\config.mak>
|
||||
|
||||
JMOZ = \
|
||||
netscape/javascript \
|
||||
$(NULL)
|
||||
|
||||
|
||||
all::
|
||||
|
||||
MODULE=java
|
||||
JMODS=netscape/javascript
|
||||
!ifdef JAVA_OR_NSJVM
|
||||
JDIRS=$(JMODS)
|
||||
JAR_JSJ_CLASSES=$(JMODS)
|
||||
JAR_NAME = jsj10.jar
|
||||
!endif
|
||||
|
||||
include <$(DEPTH)\config\rules.mak>
|
||||
|
||||
!ifdef JAVA_OR_NSJVM
|
||||
install::
|
||||
cd $(JAVA_DESTPATH)
|
||||
@echo +++ building/updating $(JAR_NAME)
|
||||
-for %i in ($(JAR_JSJ_CLASSES:/=\)) do @$(ZIP_PROG) $(ZIP_FLAGS) $(JAR_NAME) %i\*.class
|
||||
cd $(MAKEDIR)
|
||||
|
||||
!ifdef REGENERATE
|
||||
install::
|
||||
cd $(JAVA_DESTPATH)
|
||||
@echo +++ updating $(DEPTH)\nav-java\stubs\classes\$(JAR_NAME) for checkin
|
||||
-for %i in ($(JAR_JSJ_CLASSES:/=\)) do @$(ZIP_PROG) $(ZIP_FLAGS) ..\..\nav-java\stubs\classes\$(JAR_NAME) %i\*.class
|
||||
cd $(MAKEDIR)
|
||||
!endif
|
||||
!endif
|
||||
|
||||
javadoc:
|
||||
-mkdir $(XPDIST)\javadoc 2> NUL
|
||||
echo $(JAVADOC) -sourcepath . -d $(XPDIST)\javadoc $(JDIRS:/=.)
|
||||
$(JAVADOC) -sourcepath . -d $(XPDIST)\javadoc $(JDIRS:/=.)
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
/* Insert copyright and license here 19** */
|
||||
|
||||
package netscape.javascript;
|
||||
|
||||
/**
|
||||
* JSException is an exception which is thrown when JavaScript code
|
||||
* returns an error.
|
||||
*/
|
||||
|
||||
public
|
||||
class JSException extends Exception {
|
||||
String filename;
|
||||
int lineno;
|
||||
String source;
|
||||
int tokenIndex;
|
||||
|
||||
/**
|
||||
* Constructs a JSException without a detail message.
|
||||
* A detail message is a String that describes this particular exception.
|
||||
*/
|
||||
public JSException() {
|
||||
super();
|
||||
filename = "unknown";
|
||||
lineno = 0;
|
||||
source = "";
|
||||
tokenIndex = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a JSException with a detail message.
|
||||
* A detail message is a String that describes this particular exception.
|
||||
* @param s the detail message
|
||||
*/
|
||||
public JSException(String s) {
|
||||
super(s);
|
||||
filename = "unknown";
|
||||
lineno = 0;
|
||||
source = "";
|
||||
tokenIndex = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a JSException with a detail message and all the
|
||||
* other info that usually comes with a JavaScript error.
|
||||
* @param s the detail message
|
||||
*/
|
||||
public JSException(String s, String filename, int lineno,
|
||||
String source, int tokenIndex) {
|
||||
super(s);
|
||||
this.filename = filename;
|
||||
this.lineno = lineno;
|
||||
this.source = source;
|
||||
this.tokenIndex = tokenIndex;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,150 @@
|
||||
/* -*- Mode: C; tab-width: 4; -*- */
|
||||
|
||||
/* Insert copyright and license here 19** */
|
||||
|
||||
/* more doc todo:
|
||||
* threads
|
||||
* gc
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
package netscape.javascript;
|
||||
|
||||
import java.applet.Applet;
|
||||
|
||||
/**
|
||||
* JSObject allows Java to manipulate objects that are
|
||||
* defined in JavaScript.
|
||||
* Values passed from Java to JavaScript are converted as
|
||||
* follows:<ul>
|
||||
* <li>JSObject is converted to the original JavaScript object
|
||||
* <li>Any other Java object is converted to a JavaScript wrapper,
|
||||
* which can be used to access methods and fields of the java object.
|
||||
* Converting this wrapper to a string will call the toString method
|
||||
* on the original object, converting to a number will call the
|
||||
* floatValue method if possible and fail otherwise. Converting
|
||||
* to a boolean will try to call the booleanValue method in the
|
||||
* same way.
|
||||
* <li>Java arrays are wrapped with a JavaScript object that understands
|
||||
* array.length and array[index]
|
||||
* <li>A Java boolean is converted to a JavaScript boolean
|
||||
* <li>Java byte, char, short, int, long, float, and double are converted
|
||||
* to JavaScript numbers
|
||||
* </ul>
|
||||
* Values passed from JavaScript to Java are converted as follows:<ul>
|
||||
* <li>objects which are wrappers around java objects are unwrapped
|
||||
* <li>other objects are wrapped with a JSObject
|
||||
* <li>strings, numbers and booleans are converted to String, Float,
|
||||
* and Boolean objects respectively
|
||||
* </ul>
|
||||
* This means that all JavaScript values show up as some kind
|
||||
* of java.lang.Object in Java. In order to make much use of them,
|
||||
* you will have to cast them to the appropriate subclass of Object,
|
||||
* e.g. <code>(String) window.getMember("name");</code> or
|
||||
* <code>(JSObject) window.getMember("document");</code>.
|
||||
*/
|
||||
public final class JSObject {
|
||||
/* the internal object data */
|
||||
private int internal;
|
||||
|
||||
/**
|
||||
* initialize
|
||||
*/
|
||||
private static native void initClass();
|
||||
static {
|
||||
// On MRJ, this property won't exist, because the library is preloaded.
|
||||
String liveConnectLibrary = System.getProperty("netscape.jsj.dll", null);
|
||||
if (liveConnectLibrary != null) {
|
||||
System.loadLibrary(liveConnectLibrary);
|
||||
initClass();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* it is illegal to construct a JSObject manually
|
||||
*/
|
||||
private JSObject(int jsobj_addr) {
|
||||
internal = jsobj_addr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a named member of a JavaScript object.
|
||||
* Equivalent to "this.<i>name</i>" in JavaScript.
|
||||
*/
|
||||
public native Object getMember(String name);
|
||||
|
||||
/**
|
||||
* Retrieves an indexed member of a JavaScript object.
|
||||
* Equivalent to "this[<i>index</i>]" in JavaScript.
|
||||
*/
|
||||
// public Object getMember(int index) { return getSlot(index); }
|
||||
public native Object getSlot(int index);
|
||||
|
||||
/**
|
||||
* Sets a named member of a JavaScript object.
|
||||
* Equivalent to "this.<i>name</i> = <i>value</i>" in JavaScript.
|
||||
*/
|
||||
public native void setMember(String name, Object value);
|
||||
|
||||
/**
|
||||
* Sets an indexed member of a JavaScript object.
|
||||
* Equivalent to "this[<i>index</i>] = <i>value</i>" in JavaScript.
|
||||
*/
|
||||
// public void setMember(int index, Object value) {
|
||||
// setSlot(index, value);
|
||||
// }
|
||||
public native void setSlot(int index, Object value);
|
||||
|
||||
/**
|
||||
* Removes a named member of a JavaScript object.
|
||||
*/
|
||||
public native void removeMember(String name);
|
||||
|
||||
/**
|
||||
* Calls a JavaScript method.
|
||||
* Equivalent to "this.<i>methodName</i>(<i>args</i>[0], <i>args</i>[1], ...)" in JavaScript.
|
||||
*/
|
||||
public native Object call(String methodName, Object args[]);
|
||||
|
||||
/**
|
||||
* Evaluates a JavaScript expression. The expression is a string
|
||||
* of JavaScript source code which will be evaluated in the context
|
||||
* given by "this".
|
||||
*/
|
||||
public native Object eval(String s);
|
||||
|
||||
/**
|
||||
* Converts a JSObject to a String.
|
||||
*/
|
||||
public native String toString();
|
||||
|
||||
// should use some sort of identifier rather than String
|
||||
// is "property" the right word?
|
||||
// native String[] listProperties();
|
||||
|
||||
|
||||
/**
|
||||
* get a JSObject for the window containing the given applet
|
||||
*/
|
||||
public static native JSObject getWindow(Applet applet);
|
||||
|
||||
/**
|
||||
* Finalization decrements the reference count on the corresponding
|
||||
* JavaScript object.
|
||||
*/
|
||||
protected native void finalize();
|
||||
|
||||
/**
|
||||
* Override java.lang.Object.equals() because identity is not preserved
|
||||
* with instances of JSObject.
|
||||
*/
|
||||
public boolean equals(Object obj) {
|
||||
JSObject jsobj;
|
||||
|
||||
if (!(obj instanceof JSObject))
|
||||
return false;
|
||||
jsobj = (JSObject)obj;
|
||||
return (internal == jsobj.internal);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.0 (the "NPL"); you may not use this file except in
|
||||
* compliance with the NPL. You may obtain a copy of the NPL at
|
||||
* http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
||||
* for the specific language governing rights and limitations under the
|
||||
* NPL.
|
||||
*
|
||||
* The Initial Developer of this code under the NPL is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
||||
* Reserved.
|
||||
*/
|
||||
/* ** */
|
||||
/**
|
||||
* The JSProxy interface allows applets and plugins to
|
||||
* share javascript contexts.
|
||||
*/
|
||||
|
||||
package netscape.javascript;
|
||||
import java.applet.Applet;
|
||||
|
||||
public interface JSProxy {
|
||||
Object getMember(JSObject jso, String name);
|
||||
Object getSlot(JSObject jso, int index);
|
||||
void setMember(JSObject jso, String name, Object value);
|
||||
void setSlot(JSObject jso, int index, Object value);
|
||||
void removeMember(JSObject jso, String name);
|
||||
Object call(JSObject jso, String methodName, Object args[]);
|
||||
Object eval(JSObject jso, String s);
|
||||
String toString(JSObject jso);
|
||||
JSObject getWindow(Applet applet);
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package netscape.javascript;
|
||||
|
||||
/**
|
||||
* Runs a JavaScript object with a run() method in a separate thread.
|
||||
*/
|
||||
public class JSRunnable implements Runnable {
|
||||
private JSObject runnable;
|
||||
|
||||
public JSRunnable(JSObject runnable) {
|
||||
this.runnable = runnable;
|
||||
synchronized(this) {
|
||||
new Thread(this).start();
|
||||
try {
|
||||
this.wait();
|
||||
} catch (InterruptedException ie) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void run() {
|
||||
try {
|
||||
runnable.call("run", null);
|
||||
synchronized(this) {
|
||||
notifyAll();
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
System.err.println(t);
|
||||
t.printStackTrace(System.err);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.0 (the "NPL"); you may not use this file except in
|
||||
* compliance with the NPL. You may obtain a copy of the NPL at
|
||||
* http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
||||
* for the specific language governing rights and limitations under the
|
||||
* NPL.
|
||||
*
|
||||
* The Initial Developer of this code under the NPL is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
||||
* Reserved.
|
||||
*/
|
||||
/* ** */
|
||||
|
||||
package netscape.javascript;
|
||||
import java.io.*;
|
||||
|
||||
public class JSUtil {
|
||||
|
||||
/* Return the stack trace of an exception or error as a String */
|
||||
public static String getStackTrace(Throwable t) {
|
||||
ByteArrayOutputStream captureStream;
|
||||
PrintStream p;
|
||||
|
||||
captureStream = new ByteArrayOutputStream();
|
||||
p = new PrintStream(captureStream);
|
||||
|
||||
t.printStackTrace(p);
|
||||
p.flush();
|
||||
|
||||
return captureStream.toString();
|
||||
}
|
||||
}
|
||||
876
mozilla/js/src/liveconnect/jsj.c
Normal file
@@ -0,0 +1,876 @@
|
||||
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.0 (the "License"); you may not use this file except in
|
||||
* compliance with the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
* the License for the specific language governing rights and limitations
|
||||
* under the License.
|
||||
*
|
||||
* The Original Code is Mozilla Communicator client code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are Copyright (C) 1998
|
||||
* Netscape Communications Corporation. All Rights Reserved.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is part of the Java-vendor-neutral implementation of LiveConnect
|
||||
*
|
||||
* It contains the top-level initialization code and the implementation of the
|
||||
* public API.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "jsj_private.h" /* LiveConnect internals */
|
||||
#include "jsjava.h" /* LiveConnect external API */
|
||||
|
||||
/*
|
||||
* At certain times during initialization, there may be no JavaScript context
|
||||
* available to direct error reports to, in which case the error messages
|
||||
* are sent to this function. The caller is responsible for free'ing
|
||||
* the js_error_msg argument.
|
||||
*/
|
||||
static void
|
||||
report_java_initialization_error(JNIEnv *jEnv, const char *js_error_msg)
|
||||
{
|
||||
const char *error_msg, *java_error_msg;
|
||||
|
||||
java_error_msg = NULL;
|
||||
#if 0 /* This can never work here, because jsj_GetJavaErrorMessage relies on
|
||||
jlThrowable_toString which is set up by the initialization that calls
|
||||
this function. */
|
||||
if (jEnv) {
|
||||
java_error_msg = jsj_GetJavaErrorMessage(jEnv);
|
||||
(*jEnv)->ExceptionClear(jEnv);
|
||||
}
|
||||
#endif
|
||||
if (java_error_msg) {
|
||||
error_msg = PR_smprintf("initialization error: %s (%s)\n",
|
||||
js_error_msg, java_error_msg);
|
||||
free((void*)java_error_msg);
|
||||
} else {
|
||||
error_msg = PR_smprintf("initialization error: %s\n",
|
||||
js_error_msg);
|
||||
}
|
||||
|
||||
jsj_LogError(error_msg);
|
||||
}
|
||||
|
||||
/*
|
||||
* Opaque JVM handles to Java classes and methods required for Java reflection.
|
||||
* These are computed and cached during initialization.
|
||||
*/
|
||||
|
||||
jclass jlObject; /* java.lang.Object */
|
||||
jclass jlrMethod; /* java.lang.reflect.Method */
|
||||
jclass jlrField; /* java.lang.reflect.Field */
|
||||
jclass jlVoid; /* java.lang.Void */
|
||||
jclass jlrConstructor; /* java.lang.reflect.Constructor */
|
||||
jclass jlThrowable; /* java.lang.Throwable */
|
||||
jclass jlSystem; /* java.lang.System */
|
||||
jclass jlClass; /* java.lang.Class */
|
||||
jclass jlBoolean; /* java.lang.Boolean */
|
||||
jclass jlDouble; /* java.lang.Double */
|
||||
jclass jlString; /* java.lang.String */
|
||||
jclass njJSObject; /* netscape.javascript.JSObject */
|
||||
jclass njJSException; /* netscape.javascript.JSException */
|
||||
jclass njJSUtil; /* netscape.javascript.JSUtil */
|
||||
|
||||
jmethodID jlClass_getMethods; /* java.lang.Class.getMethods() */
|
||||
jmethodID jlClass_getConstructors; /* java.lang.Class.getConstructors() */
|
||||
jmethodID jlClass_getFields; /* java.lang.Class.getFields() */
|
||||
jmethodID jlClass_getName; /* java.lang.Class.getName() */
|
||||
jmethodID jlClass_getComponentType; /* java.lang.Class.getComponentType() */
|
||||
jmethodID jlClass_getModifiers; /* java.lang.Class.getModifiers() */
|
||||
jmethodID jlClass_isArray; /* java.lang.Class.isArray() */
|
||||
|
||||
jmethodID jlrMethod_getName; /* java.lang.reflect.Method.getName() */
|
||||
jmethodID jlrMethod_getParameterTypes; /* java.lang.reflect.Method.getParameterTypes() */
|
||||
jmethodID jlrMethod_getReturnType; /* java.lang.reflect.Method.getReturnType() */
|
||||
jmethodID jlrMethod_getModifiers; /* java.lang.reflect.Method.getModifiers() */
|
||||
|
||||
jmethodID jlrConstructor_getParameterTypes; /* java.lang.reflect.Constructor.getParameterTypes() */
|
||||
jmethodID jlrConstructor_getModifiers; /* java.lang.reflect.Constructor.getModifiers() */
|
||||
|
||||
jmethodID jlrField_getName; /* java.lang.reflect.Field.getName() */
|
||||
jmethodID jlrField_getType; /* java.lang.reflect.Field.getType() */
|
||||
jmethodID jlrField_getModifiers; /* java.lang.reflect.Field.getModifiers() */
|
||||
|
||||
jmethodID jlBoolean_Boolean; /* java.lang.Boolean constructor */
|
||||
jmethodID jlBoolean_booleanValue; /* java.lang.Boolean.booleanValue() */
|
||||
jmethodID jlDouble_Double; /* java.lang.Double constructor */
|
||||
jmethodID jlDouble_doubleValue; /* java.lang.Double.doubleValue() */
|
||||
|
||||
jmethodID jlThrowable_toString; /* java.lang.Throwable.toString() */
|
||||
jmethodID jlThrowable_getMessage; /* java.lang.Throwable.getMessage() */
|
||||
|
||||
jmethodID jlSystem_identityHashCode; /* java.lang.System.identityHashCode() */
|
||||
|
||||
jobject jlVoid_TYPE; /* java.lang.Void.TYPE value */
|
||||
|
||||
jmethodID njJSException_JSException; /* netscape.javascript.JSexception constructor */
|
||||
jmethodID njJSObject_JSObject; /* netscape.javascript.JSObject constructor */
|
||||
jmethodID njJSUtil_getStackTrace; /* netscape.javascript.JSUtil.getStackTrace() */
|
||||
jfieldID njJSObject_internal; /* netscape.javascript.JSObject.internal */
|
||||
jfieldID njJSException_lineno; /* netscape.javascript.JSException.lineno */
|
||||
jfieldID njJSException_tokenIndex; /* netscape.javascript.JSException.tokenIndex */
|
||||
jfieldID njJSException_source; /* netscape.javascript.JSException.source */
|
||||
jfieldID njJSException_filename; /* netscape.javascript.JSException.filename */
|
||||
|
||||
/* Obtain a reference to a Java class */
|
||||
#define LOAD_CLASS(qualified_name, class) \
|
||||
{ \
|
||||
jclass _##class = (*jEnv)->FindClass(jEnv, #qualified_name); \
|
||||
if (_##class == 0) { \
|
||||
(*jEnv)->ExceptionClear(jEnv); \
|
||||
report_java_initialization_error(jEnv, \
|
||||
"Can't load class " #qualified_name); \
|
||||
return JS_FALSE; \
|
||||
} \
|
||||
class = (*jEnv)->NewGlobalRef(jEnv, _##class); \
|
||||
}
|
||||
|
||||
/* Obtain a methodID reference to a Java method or constructor */
|
||||
#define _LOAD_METHOD(qualified_class, method, mvar, signature, class, is_static)\
|
||||
if (is_static) { \
|
||||
class##_##mvar = \
|
||||
(*jEnv)->GetStaticMethodID(jEnv, class, #method, signature); \
|
||||
} else { \
|
||||
class##_##mvar = \
|
||||
(*jEnv)->GetMethodID(jEnv, class, #method, signature); \
|
||||
} \
|
||||
if (class##_##mvar == 0) { \
|
||||
report_java_initialization_error(jEnv, \
|
||||
"Can't get mid for " #qualified_class "." #method "()"); \
|
||||
return JS_FALSE; \
|
||||
}
|
||||
|
||||
/* Obtain a methodID reference to a Java instance method */
|
||||
#define LOAD_METHOD(qualified_class, method, signature, class) \
|
||||
_LOAD_METHOD(qualified_class, method, method, signature, class, JS_FALSE)
|
||||
|
||||
/* Obtain a methodID reference to a Java static method */
|
||||
#define LOAD_STATIC_METHOD(qualified_class, method, signature, class) \
|
||||
_LOAD_METHOD(qualified_class, method, method, signature, class, JS_TRUE)
|
||||
|
||||
/* Obtain a methodID reference to a Java constructor */
|
||||
#define LOAD_CONSTRUCTOR(qualified_class, method, signature, class) \
|
||||
_LOAD_METHOD(qualified_class,<init>, method, signature, class, JS_FALSE)
|
||||
|
||||
/* Obtain a fieldID reference to a Java instance or static field */
|
||||
#define _LOAD_FIELDID(qualified_class, field, signature, class, is_static) \
|
||||
if (is_static) { \
|
||||
class##_##field = (*jEnv)->GetStaticFieldID(jEnv, class, #field, signature);\
|
||||
} else { \
|
||||
class##_##field = (*jEnv)->GetFieldID(jEnv, class, #field, signature);\
|
||||
} \
|
||||
if (class##_##field == 0) { \
|
||||
report_java_initialization_error(jEnv, \
|
||||
"Can't get fid for " #qualified_class "." #field); \
|
||||
return JS_FALSE; \
|
||||
}
|
||||
|
||||
/* Obtain a fieldID reference to a Java instance field */
|
||||
#define LOAD_FIELDID(qualified_class, field, signature, class) \
|
||||
_LOAD_FIELDID(qualified_class, field, signature, class, JS_FALSE)
|
||||
|
||||
/* Obtain the value of a static field in a Java class */
|
||||
#define LOAD_FIELD_VAL(qualified_class, field, signature, class, type) \
|
||||
{ \
|
||||
jfieldID field_id; \
|
||||
field_id = (*jEnv)->GetStaticFieldID(jEnv, class, #field, signature);\
|
||||
if (field_id == 0) { \
|
||||
report_java_initialization_error(jEnv, \
|
||||
"Can't get fid for " #qualified_class "." #field); \
|
||||
return JS_FALSE; \
|
||||
} \
|
||||
class##_##field = \
|
||||
(*jEnv)->GetStatic##type##Field(jEnv, class, field_id); \
|
||||
if (class##_##field == 0) { \
|
||||
report_java_initialization_error(jEnv, \
|
||||
"Can't read static field " #qualified_class "." #field); \
|
||||
return JS_FALSE; \
|
||||
} \
|
||||
}
|
||||
|
||||
/* Obtain the value of a static field in a Java class, which is known to
|
||||
contain an object value. */
|
||||
#define LOAD_FIELD_OBJ(qualified_class, field, signature, class) \
|
||||
LOAD_FIELD_VAL(qualified_class, field, signature, class, Object); \
|
||||
class##_##field = (*jEnv)->NewGlobalRef(jEnv, class##_##field);
|
||||
|
||||
/*
|
||||
* Load the Java classes, and the method and field descriptors required for Java reflection.
|
||||
* Returns JS_TRUE on success, JS_FALSE on failure.
|
||||
*/
|
||||
static JSBool
|
||||
init_java_VM_reflection(JSJavaVM *jsjava_vm, JNIEnv *jEnv)
|
||||
{
|
||||
/* Load Java system classes and method, including java.lang.reflect classes */
|
||||
LOAD_CLASS(java/lang/Object, jlObject);
|
||||
LOAD_CLASS(java/lang/Class, jlClass);
|
||||
LOAD_CLASS(java/lang/reflect/Method, jlrMethod);
|
||||
LOAD_CLASS(java/lang/reflect/Constructor, jlrConstructor);
|
||||
LOAD_CLASS(java/lang/reflect/Field, jlrField);
|
||||
LOAD_CLASS(java/lang/Throwable, jlThrowable);
|
||||
LOAD_CLASS(java/lang/System, jlSystem);
|
||||
LOAD_CLASS(java/lang/Boolean, jlBoolean);
|
||||
LOAD_CLASS(java/lang/Double, jlDouble);
|
||||
LOAD_CLASS(java/lang/String, jlString);
|
||||
LOAD_CLASS(java/lang/Void, jlVoid);
|
||||
|
||||
LOAD_METHOD(java.lang.Class, getMethods, "()[Ljava/lang/reflect/Method;",jlClass);
|
||||
LOAD_METHOD(java.lang.Class, getConstructors, "()[Ljava/lang/reflect/Constructor;",jlClass);
|
||||
LOAD_METHOD(java.lang.Class, getFields, "()[Ljava/lang/reflect/Field;", jlClass);
|
||||
LOAD_METHOD(java.lang.Class, getName, "()Ljava/lang/String;", jlClass);
|
||||
LOAD_METHOD(java.lang.Class, isArray, "()Z", jlClass);
|
||||
LOAD_METHOD(java.lang.Class, getComponentType, "()Ljava/lang/Class;", jlClass);
|
||||
LOAD_METHOD(java.lang.Class, getModifiers, "()I", jlClass);
|
||||
|
||||
LOAD_METHOD(java.lang.reflect.Method, getName, "()Ljava/lang/String;", jlrMethod);
|
||||
LOAD_METHOD(java.lang.reflect.Method, getParameterTypes, "()[Ljava/lang/Class;", jlrMethod);
|
||||
LOAD_METHOD(java.lang.reflect.Method, getReturnType, "()Ljava/lang/Class;", jlrMethod);
|
||||
LOAD_METHOD(java.lang.reflect.Method, getModifiers, "()I", jlrMethod);
|
||||
|
||||
LOAD_METHOD(java.lang.reflect.Constructor, getParameterTypes, "()[Ljava/lang/Class;", jlrConstructor);
|
||||
LOAD_METHOD(java.lang.reflect.Constructor, getModifiers, "()I", jlrConstructor);
|
||||
|
||||
LOAD_METHOD(java.lang.reflect.Field, getName, "()Ljava/lang/String;", jlrField);
|
||||
LOAD_METHOD(java.lang.reflect.Field, getType, "()Ljava/lang/Class;", jlrField);
|
||||
LOAD_METHOD(java.lang.reflect.Field, getModifiers, "()I", jlrField);
|
||||
|
||||
LOAD_METHOD(java.lang.Throwable, toString, "()Ljava/lang/String;", jlThrowable);
|
||||
LOAD_METHOD(java.lang.Throwable, getMessage, "()Ljava/lang/String;", jlThrowable);
|
||||
|
||||
LOAD_METHOD(java.lang.Double, doubleValue, "()D", jlDouble);
|
||||
|
||||
LOAD_METHOD(java.lang.Boolean, booleanValue, "()Z", jlBoolean);
|
||||
|
||||
LOAD_STATIC_METHOD(java.lang.System, identityHashCode, "(Ljava/lang/Object;)I", jlSystem);
|
||||
|
||||
LOAD_CONSTRUCTOR(java.lang.Boolean, Boolean, "(Z)V", jlBoolean);
|
||||
LOAD_CONSTRUCTOR(java.lang.Double, Double, "(D)V", jlDouble);
|
||||
|
||||
LOAD_FIELD_OBJ(java.lang.Void, TYPE, "Ljava/lang/Class;", jlVoid);
|
||||
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
#if XP_MAC
|
||||
|
||||
/**
|
||||
* Workaround for the fact that MRJ loads a different instance of the shared library.
|
||||
*/
|
||||
|
||||
#include "netscape_javascript_JSObject.h"
|
||||
|
||||
static JSObject_RegisterNativeMethods(JNIEnv* jEnv)
|
||||
{
|
||||
// Manually load the required native methods.
|
||||
static JNINativeMethod nativeMethods[] = {
|
||||
"initClass", "()V", (void*)&Java_netscape_javascript_JSObject_initClass,
|
||||
"getMember", "(Ljava/lang/String;)Ljava/lang/Object;", (void*)&Java_netscape_javascript_JSObject_getMember,
|
||||
"getSlot", "(I)Ljava/lang/Object;", (void*)&Java_netscape_javascript_JSObject_getSlot,
|
||||
"setMember", "(Ljava/lang/String;Ljava/lang/Object;)V", (void*)&Java_netscape_javascript_JSObject_setMember,
|
||||
"setSlot", "(ILjava/lang/Object;)V", (void*)&Java_netscape_javascript_JSObject_setSlot,
|
||||
"removeMember", "(Ljava/lang/String;)V", (void*)&Java_netscape_javascript_JSObject_removeMember,
|
||||
"call", "(Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/Object;", (void*)&Java_netscape_javascript_JSObject_call,
|
||||
"eval", "(Ljava/lang/String;)Ljava/lang/Object;", (void*)&Java_netscape_javascript_JSObject_eval,
|
||||
|
||||
"toString", "()Ljava/lang/String;", (void*)&Java_netscape_javascript_JSObject_toString,
|
||||
"getWindow", "(Ljava/applet/Applet;)Lnetscape/javascript/JSObject;", (void*)&Java_netscape_javascript_JSObject_getWindow,
|
||||
"finalize", "()V", (void*)&Java_netscape_javascript_JSObject_finalize,
|
||||
/* "equals", "(Ljava/lang/Object;)Z", (void*)&Java_netscape_javascript_JSObject_equals */
|
||||
};
|
||||
(*jEnv)->RegisterNatives(jEnv, njJSObject, nativeMethods, sizeof(nativeMethods) / sizeof(JNINativeMethod));
|
||||
if ((*jEnv)->ExceptionOccurred(jEnv)) {
|
||||
report_java_initialization_error(jEnv, "Couldn't initialize JSObject native methods.");
|
||||
(*jEnv)->ExceptionClear(jEnv);
|
||||
}
|
||||
/* call the initClass method, since we nailed the static initializer for testing. */
|
||||
Java_netscape_javascript_JSObject_initClass(jEnv, njJSObject);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* Load Netscape-specific Java extension classes, methods, and fields */
|
||||
static JSBool
|
||||
init_netscape_java_classes(JSJavaVM *jsjava_vm, JNIEnv *jEnv)
|
||||
{
|
||||
LOAD_CLASS(netscape/javascript/JSObject, njJSObject);
|
||||
LOAD_CLASS(netscape/javascript/JSException, njJSException);
|
||||
LOAD_CLASS(netscape/javascript/JSUtil, njJSUtil);
|
||||
|
||||
#if XP_MAC
|
||||
JSObject_RegisterNativeMethods(jEnv);
|
||||
#endif
|
||||
|
||||
LOAD_CONSTRUCTOR(netscape.javascript.JSObject,
|
||||
JSObject, "(I)V", njJSObject);
|
||||
LOAD_CONSTRUCTOR(netscape.javascript.JSException,
|
||||
JSException, "(Ljava/lang/String;Ljava/lang/String;ILjava/lang/String;I)V",
|
||||
njJSException);
|
||||
LOAD_FIELDID(netscape.javascript.JSObject,
|
||||
internal, "I", njJSObject);
|
||||
LOAD_FIELDID(netscape.javascript.JSException,
|
||||
lineno, "I", njJSException);
|
||||
LOAD_FIELDID(netscape.javascript.JSException,
|
||||
tokenIndex, "I", njJSException);
|
||||
LOAD_FIELDID(netscape.javascript.JSException,
|
||||
source, "Ljava/lang/String;", njJSException);
|
||||
LOAD_FIELDID(netscape.javascript.JSException,
|
||||
filename, "Ljava/lang/String;", njJSException);
|
||||
|
||||
LOAD_STATIC_METHOD(netscape.javascript.JSUtil,
|
||||
getStackTrace, "(Ljava/lang/Throwable;)Ljava/lang/String;",
|
||||
njJSUtil);
|
||||
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
JSJavaVM *jsjava_vm_list = NULL;
|
||||
|
||||
/*
|
||||
* Called once per Java VM, this function initializes the classes, fields, and
|
||||
* methods required for Java reflection. If java_vm is NULL, a new Java VM is
|
||||
* created, using the provided classpath in addition to any default classpath.
|
||||
* The classpath argument is ignored, however, if java_vm_arg is non-NULL.
|
||||
*/
|
||||
JSJavaVM *
|
||||
JSJ_ConnectToJavaVM(SystemJavaVM *java_vm_arg, void* initargs)
|
||||
{
|
||||
SystemJavaVM* java_vm;
|
||||
JSJavaVM *jsjava_vm;
|
||||
JNIEnv *jEnv;
|
||||
|
||||
PR_ASSERT(JSJ_callbacks);
|
||||
PR_ASSERT(JSJ_callbacks->attach_current_thread);
|
||||
PR_ASSERT(JSJ_callbacks->detach_current_thread);
|
||||
PR_ASSERT(JSJ_callbacks->get_java_vm);
|
||||
|
||||
jsjava_vm = (JSJavaVM*)malloc(sizeof(JSJavaVM));
|
||||
if (!jsjava_vm)
|
||||
return NULL;
|
||||
memset(jsjava_vm, 0, sizeof(JSJavaVM));
|
||||
|
||||
java_vm = java_vm_arg;
|
||||
|
||||
/* If a Java VM was passed in, try to attach to it on the current thread. */
|
||||
if (java_vm) {
|
||||
jEnv = JSJ_callbacks->attach_current_thread(java_vm);
|
||||
if (jEnv == NULL) {
|
||||
jsj_LogError("Failed to attach to Java VM thread\n");
|
||||
free(jsjava_vm);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
else {
|
||||
PRBool ok;
|
||||
PR_ASSERT(JSJ_callbacks->create_java_vm);
|
||||
PR_ASSERT(JSJ_callbacks->destroy_java_vm);
|
||||
|
||||
ok = JSJ_callbacks->create_java_vm(&java_vm, &jEnv, initargs);
|
||||
if (!ok || java_vm == NULL) {
|
||||
jsj_LogError("Failed to create Java VM\n");
|
||||
free(jsjava_vm);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Remember that we created the VM so that we know to destroy it later */
|
||||
jsjava_vm->jsj_created_java_vm = JS_TRUE;
|
||||
}
|
||||
|
||||
jsjava_vm->java_vm = java_vm;
|
||||
jsjava_vm->main_thread_env = jEnv;
|
||||
|
||||
/* Load the Java classes, and the method and field descriptors required for
|
||||
Java reflection. */
|
||||
if (!init_java_VM_reflection(jsjava_vm, jEnv)) {
|
||||
JSJ_DisconnectFromJavaVM(jsjava_vm);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* JVM initialization for netscape.javascript.JSObject is performed
|
||||
* independently of the other classes that are initialized in
|
||||
* init_java_VM_reflection, because we allow it to fail. In the case
|
||||
* of failure, LiveConnect is still operative, but only when calling
|
||||
* from JS to Java and not vice-versa.
|
||||
*/
|
||||
init_netscape_java_classes(jsjava_vm, jEnv);
|
||||
|
||||
/* Put this VM on the list of all created VMs */
|
||||
jsjava_vm->next = jsjava_vm_list;
|
||||
jsjava_vm_list = jsjava_vm;
|
||||
|
||||
return jsjava_vm;
|
||||
}
|
||||
|
||||
JSJCallbacks *JSJ_callbacks = NULL;
|
||||
|
||||
/* Called once to set up callbacks for all instances of LiveConnect */
|
||||
void
|
||||
JSJ_Init(JSJCallbacks *callbacks)
|
||||
{
|
||||
PR_ASSERT(callbacks);
|
||||
JSJ_callbacks = callbacks;
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize the provided JSContext by setting up the JS classes necessary for
|
||||
* reflection and by defining JavaPackage objects for the default Java packages
|
||||
* as properties of global_obj. Additional packages may be pre-defined by
|
||||
* setting the predefined_packages argument. (Pre-defining a Java package at
|
||||
* initialization time is not necessary, but it will make package lookup faster
|
||||
* and, more importantly, will avoid unnecessary network accesses if classes
|
||||
* are being loaded over the network.)
|
||||
*/
|
||||
JSBool
|
||||
JSJ_InitJSContext(JSContext *cx, JSObject *global_obj,
|
||||
JavaPackageDef *predefined_packages)
|
||||
{
|
||||
/* Initialize the JavaScript classes used for reflection */
|
||||
if (!jsj_init_JavaObject(cx, global_obj))
|
||||
return JS_FALSE;
|
||||
|
||||
/* if (!jsj_init_JavaMember(cx, global_obj))
|
||||
return JS_FALSE; */
|
||||
|
||||
if (!jsj_init_JavaPackage(cx, global_obj, predefined_packages))
|
||||
return JS_FALSE;
|
||||
|
||||
if (!jsj_init_JavaClass(cx, global_obj))
|
||||
return JS_FALSE;
|
||||
|
||||
if (!jsj_init_JavaArray(cx, global_obj))
|
||||
return JS_FALSE;
|
||||
|
||||
if (!jsj_init_JavaMember(cx, global_obj))
|
||||
return JS_FALSE;
|
||||
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
/* Eliminate a reference to a Java class */
|
||||
#define UNLOAD_CLASS(qualified_name, class) \
|
||||
if (class) { \
|
||||
(*jEnv)->DeleteGlobalRef(jEnv, class); \
|
||||
class = NULL; \
|
||||
}
|
||||
|
||||
/*
|
||||
* This routine severs the connection to a Java VM, freeing all related resources.
|
||||
* It shouldn't be called until the global scope has been cleared in all related
|
||||
* JSContexts (so that all LiveConnect objects are finalized) and a JavaScript
|
||||
* GC is performed. Otherwise, accessed to free'ed memory could result.
|
||||
*/
|
||||
void
|
||||
JSJ_DisconnectFromJavaVM(JSJavaVM *jsjava_vm)
|
||||
{
|
||||
JNIEnv *jEnv;
|
||||
SystemJavaVM *java_vm;
|
||||
JSJavaVM *j, **jp;
|
||||
|
||||
java_vm = jsjava_vm->java_vm;
|
||||
jEnv = jsjava_vm->main_thread_env;
|
||||
|
||||
/* Drop all references to Java objects and classes */
|
||||
jsj_DiscardJavaObjReflections(jEnv);
|
||||
jsj_DiscardJavaClassReflections(jEnv);
|
||||
|
||||
if (jsjava_vm->jsj_created_java_vm) {
|
||||
(void)JSJ_callbacks->destroy_java_vm(java_vm, jEnv);
|
||||
} else {
|
||||
UNLOAD_CLASS(java/lang/Object, jlObject);
|
||||
UNLOAD_CLASS(java/lang/Class, jlClass);
|
||||
UNLOAD_CLASS(java/lang/reflect/Method, jlrMethod);
|
||||
UNLOAD_CLASS(java/lang/reflect/Constructor, jlrConstructor);
|
||||
UNLOAD_CLASS(java/lang/reflect/Field, jlrField);
|
||||
UNLOAD_CLASS(java/lang/Throwable, jlThrowable);
|
||||
UNLOAD_CLASS(java/lang/System, jlSystem);
|
||||
UNLOAD_CLASS(java/lang/Boolean, jlBoolean);
|
||||
UNLOAD_CLASS(java/lang/Double, jlDouble);
|
||||
UNLOAD_CLASS(java/lang/String, jlString);
|
||||
UNLOAD_CLASS(java/lang/Void, jlVoid);
|
||||
UNLOAD_CLASS(netscape/javascript/JSObject, njJSObject);
|
||||
UNLOAD_CLASS(netscape/javascript/JSException, njJSException);
|
||||
UNLOAD_CLASS(netscape/javascript/JSUtil, njJSUtil);
|
||||
}
|
||||
|
||||
|
||||
/* Remove this VM from the list of all JSJavaVM objects. */
|
||||
for (jp = &jsjava_vm_list; (j = *jp) != NULL; jp = &j->next) {
|
||||
if (j == jsjava_vm) {
|
||||
*jp = jsjava_vm->next;
|
||||
break;
|
||||
}
|
||||
}
|
||||
PR_ASSERT(j);
|
||||
|
||||
free(jsjava_vm);
|
||||
}
|
||||
|
||||
static JSJavaThreadState *thread_list = NULL;
|
||||
|
||||
static JSJavaThreadState *
|
||||
new_jsjava_thread_state(JSJavaVM *jsjava_vm, const char *thread_name, JNIEnv *jEnv)
|
||||
{
|
||||
JSJavaThreadState *jsj_env;
|
||||
|
||||
jsj_env = (JSJavaThreadState *)malloc(sizeof(JSJavaThreadState));
|
||||
if (!jsj_env)
|
||||
return NULL;
|
||||
memset(jsj_env, 0, sizeof(JSJavaThreadState));
|
||||
|
||||
jsj_env->jEnv = jEnv;
|
||||
jsj_env->jsjava_vm = jsjava_vm;
|
||||
if (thread_name)
|
||||
jsj_env->name = strdup(thread_name);
|
||||
|
||||
/* THREADSAFETY - need to protect against races */
|
||||
jsj_env->next = thread_list;
|
||||
thread_list = jsj_env;
|
||||
|
||||
return jsj_env;
|
||||
}
|
||||
|
||||
static JSJavaThreadState *
|
||||
find_jsjava_thread(JNIEnv *jEnv)
|
||||
{
|
||||
JSJavaThreadState *e, **p, *jsj_env;
|
||||
jsj_env = NULL;
|
||||
|
||||
/* THREADSAFETY - need to protect against races in manipulating the thread list */
|
||||
|
||||
/* Search for the thread state among the list of all created
|
||||
LiveConnect threads */
|
||||
for (p = &thread_list; (e = *p) != NULL; p = &(e->next)) {
|
||||
if (e->jEnv == jEnv) {
|
||||
jsj_env = e;
|
||||
*p = jsj_env->next;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Move a found thread to head of list for faster search next time. */
|
||||
if (jsj_env)
|
||||
thread_list = jsj_env;
|
||||
|
||||
return jsj_env;
|
||||
}
|
||||
|
||||
PR_IMPLEMENT(JSJavaThreadState *)
|
||||
JSJ_AttachCurrentThreadToJava(JSJavaVM *jsjava_vm, const char *name, JNIEnv **java_envp)
|
||||
{
|
||||
JNIEnv *jEnv;
|
||||
SystemJavaVM *java_vm;
|
||||
JSJavaThreadState *jsj_env;
|
||||
|
||||
/* Try to attach a Java thread to the current native thread */
|
||||
java_vm = jsjava_vm->java_vm;
|
||||
jEnv = JSJ_callbacks->attach_current_thread(java_vm);
|
||||
if (jEnv == NULL)
|
||||
return NULL;
|
||||
|
||||
/* If we found an existing thread state, just return it. */
|
||||
jsj_env = find_jsjava_thread(jEnv);
|
||||
if (jsj_env)
|
||||
return jsj_env;
|
||||
|
||||
/* Create a new wrapper around the thread/VM state */
|
||||
jsj_env = new_jsjava_thread_state(jsjava_vm, name, jEnv);
|
||||
|
||||
if (java_envp)
|
||||
*java_envp = jEnv;
|
||||
return jsj_env;
|
||||
}
|
||||
|
||||
static JSJavaVM *
|
||||
map_java_vm_to_jsjava_vm(SystemJavaVM *java_vm)
|
||||
{
|
||||
JSJavaVM *v;
|
||||
for (v = jsjava_vm_list; v; v = v->next) {
|
||||
if (v->java_vm == java_vm)
|
||||
return v;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Unfortunately, there's no standard means to associate any private data with
|
||||
* a JNI thread environment, so we need to use the Java environment pointer as
|
||||
* the key in a lookup table that maps it to a JSJavaThreadState structure,
|
||||
* where we store all our per-thread private data. If no existing thread state
|
||||
* is found, a new one is created.
|
||||
*
|
||||
* If an error occurs, returns NULL and sets the errp argument to an error
|
||||
* message, which the caller is responsible for free'ing.
|
||||
*/
|
||||
JSJavaThreadState *
|
||||
jsj_MapJavaThreadToJSJavaThreadState(JNIEnv *jEnv, char **errp)
|
||||
{
|
||||
JSJavaThreadState *jsj_env;
|
||||
SystemJavaVM *java_vm;
|
||||
JSJavaVM *jsjava_vm;
|
||||
|
||||
/* If we found an existing thread state, just return it. */
|
||||
jsj_env = find_jsjava_thread(jEnv);
|
||||
if (jsj_env)
|
||||
return jsj_env;
|
||||
|
||||
/* No one set up a LiveConnect thread state for a given Java thread.
|
||||
Invoke the callback to create one on-the-fly. */
|
||||
|
||||
/* First, figure out which Java VM is calling us */
|
||||
java_vm = JSJ_callbacks->get_java_vm(jEnv);
|
||||
if (jsjava_vm == NULL)
|
||||
return NULL;
|
||||
|
||||
/* Get our private JavaVM data */
|
||||
jsjava_vm = map_java_vm_to_jsjava_vm(java_vm);
|
||||
if (!jsjava_vm) {
|
||||
*errp = PR_smprintf("Total weirdness: No JSJavaVM wrapper ever created "
|
||||
"for JavaVM 0x%08x", java_vm);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
jsj_env = new_jsjava_thread_state(jsjava_vm, NULL, jEnv);
|
||||
if (!jsj_env)
|
||||
return NULL;
|
||||
|
||||
return jsj_env;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function is used to specify a particular JSContext as *the* JavaScript
|
||||
* execution environment to be used when LiveConnect is accessed from the given
|
||||
* Java thread, i.e. by using one of the methods of netscape.javascript.JSObject.
|
||||
* (There can only be one such JS context for a given Java thread. To
|
||||
* multiplex JSContexts among a single thread, this function must be called
|
||||
* before Java is invoked on that thread.) The return value is the previous
|
||||
* context associated with the given Java thread.
|
||||
*/
|
||||
PR_IMPLEMENT(JSContext *)
|
||||
JSJ_SetDefaultJSContextForJavaThread(JSContext *cx, JSJavaThreadState *jsj_env)
|
||||
{
|
||||
JSContext *old_context;
|
||||
old_context = jsj_env->cx;
|
||||
jsj_env->cx = cx;
|
||||
return old_context;
|
||||
}
|
||||
|
||||
PR_IMPLEMENT(JSBool)
|
||||
JSJ_DetachCurrentThreadFromJava(JSJavaThreadState *jsj_env)
|
||||
{
|
||||
SystemJavaVM *java_vm;
|
||||
JNIEnv* jEnv;
|
||||
JSJavaThreadState *e, **p;
|
||||
|
||||
/* Disassociate the current native thread from its corresponding Java thread */
|
||||
java_vm = jsj_env->jsjava_vm->java_vm;
|
||||
jEnv = jsj_env->jEnv;
|
||||
if (!JSJ_callbacks->detach_current_thread(java_vm, jEnv))
|
||||
return JS_FALSE;
|
||||
|
||||
/* Destroy the LiveConnect execution environment passed in */
|
||||
jsj_ClearPendingJSErrors(jsj_env);
|
||||
|
||||
/* THREADSAFETY - need to protect against races */
|
||||
for (p = &thread_list; (e = *p) != NULL; p = &(e->next)) {
|
||||
if (e == jsj_env) {
|
||||
*p = jsj_env->next;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
free(jsj_env);
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
JSBool
|
||||
JSJ_ConvertJavaObjectToJSValue(JSContext *cx, jobject java_obj, jsval *vp)
|
||||
{
|
||||
JNIEnv *jEnv;
|
||||
|
||||
/* Get the Java per-thread environment pointer for this JSContext */
|
||||
jsj_MapJSContextToJSJThread(cx, &jEnv);
|
||||
if (!jEnv)
|
||||
return JS_FALSE;
|
||||
|
||||
return jsj_ConvertJavaObjectToJSValue(cx, jEnv, java_obj, vp);
|
||||
}
|
||||
|
||||
/*===========================================================================*/
|
||||
|
||||
#ifndef MOZILLA_CLIENT
|
||||
|
||||
/* The convenience functions below present a complete, but simplified
|
||||
LiveConnect API which is designed to handle the special case of a single
|
||||
Java-VM, single-threaded operation, and use of only one JSContext. */
|
||||
|
||||
/* We can get away with global variables in our single-threaded,
|
||||
single-JSContext case. */
|
||||
static JSJavaVM * the_jsj_vm = NULL;
|
||||
static JSContext * the_cx = NULL;
|
||||
static JSJavaThreadState * the_jsj_thread = NULL;
|
||||
static JSObject * the_global_js_obj = NULL;
|
||||
|
||||
/* Trivial implementation of callback function */
|
||||
static JSJavaThreadState *
|
||||
default_map_js_context_to_jsj_thread(JSContext *cx, char **errp)
|
||||
{
|
||||
return the_jsj_thread;
|
||||
}
|
||||
|
||||
/* Trivial implementation of callback function */
|
||||
static JSContext *
|
||||
default_map_jsj_thread_to_js_context(JSJavaThreadState *jsj_env, JNIEnv *jEnv, char **errp)
|
||||
{
|
||||
return the_cx;
|
||||
}
|
||||
|
||||
/* Trivial implementation of callback function */
|
||||
static JSObject *
|
||||
default_map_java_object_to_js_object(JNIEnv *jEnv, jobject hint, char **errp)
|
||||
{
|
||||
return the_global_js_obj;
|
||||
}
|
||||
|
||||
static PRBool PR_CALLBACK
|
||||
default_create_java_vm(SystemJavaVM* *jvm, JNIEnv* *initialEnv, void* initargs)
|
||||
{
|
||||
jint err;
|
||||
const char* user_classpath = (const char*)initargs;
|
||||
|
||||
/* No Java VM supplied, so create our own */
|
||||
JDK1_1InitArgs vm_args;
|
||||
|
||||
/* Magic constant indicates JRE version 1.1 */
|
||||
vm_args.version = 0x00010001;
|
||||
JNI_GetDefaultJavaVMInitArgs(&vm_args);
|
||||
|
||||
/* Prepend the classpath argument to the default JVM classpath */
|
||||
if (user_classpath) {
|
||||
#ifdef XP_UNIX
|
||||
const char *full_classpath = PR_smprintf("%s:%s", user_classpath, vm_args.classpath);
|
||||
#else
|
||||
const char *full_classpath = PR_smprintf("%s;%s", user_classpath, vm_args.classpath);
|
||||
#endif
|
||||
if (!full_classpath) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
vm_args.classpath = (char*)full_classpath;
|
||||
}
|
||||
|
||||
err = JNI_CreateJavaVM((JavaVM**)jvm, initialEnv, &vm_args);
|
||||
return err == 0;
|
||||
}
|
||||
|
||||
static PRBool PR_CALLBACK
|
||||
default_destroy_java_vm(SystemJavaVM* jvm, JNIEnv* initialEnv)
|
||||
{
|
||||
JavaVM* java_vm = (JavaVM*)jvm;
|
||||
jint err = (*java_vm)->DestroyJavaVM(java_vm);
|
||||
return err == 0;
|
||||
}
|
||||
|
||||
static JNIEnv* PR_CALLBACK
|
||||
default_attach_current_thread(SystemJavaVM* jvm)
|
||||
{
|
||||
JavaVM* java_vm = (JavaVM*)jvm;
|
||||
JNIEnv* env = NULL;
|
||||
jint err = (*java_vm)->AttachCurrentThread(java_vm, &env, NULL);
|
||||
return env;
|
||||
}
|
||||
|
||||
static PRBool PR_CALLBACK
|
||||
default_detach_current_thread(SystemJavaVM* jvm, JNIEnv* env)
|
||||
{
|
||||
JavaVM* java_vm = (JavaVM*)jvm;
|
||||
/* assert that env is the JNIEnv of the current thread */
|
||||
jint err = (*java_vm)->DetachCurrentThread(java_vm);
|
||||
return err == 0;
|
||||
}
|
||||
|
||||
static SystemJavaVM* PR_CALLBACK
|
||||
default_get_java_vm(JNIEnv* env)
|
||||
{
|
||||
JavaVM* java_vm = NULL;
|
||||
jint err = (*env)->GetJavaVM(env, &java_vm);
|
||||
return (SystemJavaVM*)java_vm;
|
||||
}
|
||||
|
||||
/* Trivial implementations of callback functions */
|
||||
JSJCallbacks jsj_default_callbacks = {
|
||||
default_map_jsj_thread_to_js_context,
|
||||
default_map_js_context_to_jsj_thread,
|
||||
default_map_java_object_to_js_object,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
default_create_java_vm,
|
||||
default_destroy_java_vm,
|
||||
default_attach_current_thread,
|
||||
default_detach_current_thread,
|
||||
default_get_java_vm
|
||||
};
|
||||
|
||||
/*
|
||||
* Initialize the provided JSContext by setting up the JS classes necessary for
|
||||
* reflection and by defining JavaPackage objects for the default Java packages
|
||||
* as properties of global_obj. If java_vm is NULL, a new Java VM is
|
||||
* created, using the provided classpath in addition to any default classpath.
|
||||
* The classpath argument is ignored, however, if java_vm is non-NULL.
|
||||
*/
|
||||
JSBool
|
||||
JSJ_SimpleInit(JSContext *cx, JSObject *global_obj, SystemJavaVM *java_vm, const char *classpath)
|
||||
{
|
||||
JNIEnv *jEnv;
|
||||
|
||||
PR_ASSERT(!the_jsj_vm);
|
||||
the_jsj_vm = JSJ_ConnectToJavaVM(java_vm, (void*)classpath);
|
||||
if (!the_jsj_vm)
|
||||
return JS_FALSE;
|
||||
|
||||
JSJ_Init(&jsj_default_callbacks);
|
||||
|
||||
if (!JSJ_InitJSContext(cx, global_obj, NULL))
|
||||
goto error;
|
||||
the_cx = cx;
|
||||
the_global_js_obj = global_obj;
|
||||
|
||||
the_jsj_thread = JSJ_AttachCurrentThreadToJava(the_jsj_vm, "main thread", &jEnv);
|
||||
if (!the_jsj_thread)
|
||||
goto error;
|
||||
JSJ_SetDefaultJSContextForJavaThread(cx, the_jsj_thread);
|
||||
return JS_TRUE;
|
||||
|
||||
error:
|
||||
JSJ_SimpleShutdown();
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Free up all LiveConnect resources. Destroy the Java VM if it was
|
||||
* created by LiveConnect.
|
||||
*/
|
||||
PR_IMPLEMENT(void)
|
||||
JSJ_SimpleShutdown()
|
||||
{
|
||||
PR_ASSERT(the_jsj_vm);
|
||||
JSJ_DisconnectFromJavaVM(the_jsj_vm);
|
||||
the_jsj_vm = NULL;
|
||||
the_cx = NULL;
|
||||
the_global_js_obj = NULL;
|
||||
the_jsj_thread = NULL;
|
||||
}
|
||||
|
||||
#endif /* MOZILLA_CLIENT */
|
||||
76
mozilla/js/src/liveconnect/jsj1640.rc
Normal file
@@ -0,0 +1,76 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.0 (the "NPL"); you may not use this file except in
|
||||
* compliance with the NPL. You may obtain a copy of the NPL at
|
||||
* http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
||||
* for the specific language governing rights and limitations under the
|
||||
* NPL.
|
||||
*
|
||||
* The Initial Developer of this code under the NPL is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
||||
* Reserved.
|
||||
*/
|
||||
|
||||
// Version stamp for this .DLL
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include <ver.h>
|
||||
|
||||
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
|
||||
FILEVERSION 4 // major, minor, release (alpha 1), build #
|
||||
|
||||
PRODUCTVERSION 4
|
||||
|
||||
FILEFLAGSMASK 0
|
||||
|
||||
FILEFLAGS 0 // final version
|
||||
|
||||
FILEOS VOS_DOS_WINDOWS16
|
||||
|
||||
FILETYPE VFT_DLL
|
||||
|
||||
FILESUBTYPE 0 // not used
|
||||
|
||||
BEGIN
|
||||
|
||||
BLOCK "StringFileInfo"
|
||||
|
||||
BEGIN
|
||||
|
||||
BLOCK "040904E4" // Lang=US English, CharSet=Windows Multilingual
|
||||
|
||||
BEGIN
|
||||
|
||||
VALUE "CompanyName", "Netscape Communications Corporation\0"
|
||||
|
||||
VALUE "FileDescription", "Netscape 16-bit JavaScript-Java Module\0"
|
||||
|
||||
VALUE "FileVersion", "4.0\0"
|
||||
|
||||
VALUE "InternalName", "JSJ1640\0"
|
||||
|
||||
VALUE "LegalCopyright", "Copyright Netscape Communications. 1994-96\0"
|
||||
|
||||
VALUE "LegalTrademarks", "Netscape, Mozilla\0"
|
||||
|
||||
VALUE "OriginalFilename","JSJ1640.DLL\0"
|
||||
|
||||
VALUE "ProductName", "NETSCAPE\0"
|
||||
|
||||
VALUE "ProductVersion", "4.0\0"
|
||||
|
||||
END
|
||||
|
||||
END
|
||||
|
||||
END
|
||||
|
||||
1243
mozilla/js/src/liveconnect/jsj_JSObject.c
Normal file
403
mozilla/js/src/liveconnect/jsj_JavaArray.c
Normal file
@@ -0,0 +1,403 @@
|
||||
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.0 (the "License"); you may not use this file except in
|
||||
* compliance with the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
* the License for the specific language governing rights and limitations
|
||||
* under the License.
|
||||
*
|
||||
* The Original Code is Mozilla Communicator client code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are Copyright (C) 1998
|
||||
* Netscape Communications Corporation. All Rights Reserved.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is part of the Java-vendor-neutral implementation of LiveConnect
|
||||
*
|
||||
* It contains the definition of the JavaScript JavaArray class.
|
||||
* Instances of JavaArray are used to reflect Java arrays.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "jsj_private.h" /* LiveConnect internals */
|
||||
|
||||
/* Shorthands for ASCII (7-bit) decimal and hex conversion. */
|
||||
#define JS7_ISDEC(c) (((c) >= '0') && ((c) <= '9'))
|
||||
#define JS7_UNDEC(c) ((c) - '0')
|
||||
|
||||
/*
|
||||
* Convert any jsval v to an integer jsval if ToString(v)
|
||||
* contains a base-10 integer that fits into 31 bits.
|
||||
* Otherwise return v.
|
||||
*/
|
||||
static jsval
|
||||
try_convert_to_jsint(JSContext *cx, jsval idval)
|
||||
{
|
||||
const jschar *cp;
|
||||
JSString *jsstr;
|
||||
|
||||
jsstr = JS_ValueToString(cx, idval);
|
||||
if (!jsstr)
|
||||
return idval;
|
||||
|
||||
cp = JS_GetStringChars(jsstr);
|
||||
if (JS7_ISDEC(*cp)) {
|
||||
jsuint index = JS7_UNDEC(*cp++);
|
||||
jsuint oldIndex = 0;
|
||||
jsuint c = 0;
|
||||
if (index != 0) {
|
||||
while (JS7_ISDEC(*cp)) {
|
||||
oldIndex = index;
|
||||
c = JS7_UNDEC(*cp);
|
||||
index = 10*index + c;
|
||||
cp++;
|
||||
}
|
||||
}
|
||||
if (*cp == 0 &&
|
||||
(oldIndex < (JSVAL_INT_MAX / 10) ||
|
||||
(oldIndex == (JSVAL_INT_MAX / 10) && c < (JSVAL_INT_MAX % 10)))) {
|
||||
return INT_TO_JSVAL(index);
|
||||
}
|
||||
}
|
||||
return idval;
|
||||
}
|
||||
|
||||
|
||||
static JSBool
|
||||
access_java_array_element(JSContext *cx,
|
||||
JNIEnv *jEnv,
|
||||
JSObject *obj,
|
||||
jsid id,
|
||||
jsval *vp,
|
||||
JSBool do_assignment)
|
||||
{
|
||||
jsval idval;
|
||||
jarray java_array;
|
||||
JavaClassDescriptor *class_descriptor;
|
||||
JavaObjectWrapper *java_wrapper;
|
||||
jsize array_length, index;
|
||||
JavaSignature *array_component_signature;
|
||||
|
||||
/* printf("In JavaArray_getProperty\n"); */
|
||||
|
||||
java_wrapper = JS_GetPrivate(cx, obj);
|
||||
if (!java_wrapper) {
|
||||
const char *property_name;
|
||||
if (JS_IdToValue(cx, id, &idval) && JSVAL_IS_STRING(idval) &&
|
||||
(property_name = JS_GetStringBytes(JSVAL_TO_STRING(idval))) != NULL) {
|
||||
if (!strcmp(property_name, "constructor")) {
|
||||
*vp = JSVAL_VOID;
|
||||
return JS_TRUE;
|
||||
}
|
||||
}
|
||||
JS_ReportError(cx, "illegal operation on JavaArray prototype object");
|
||||
return JS_FALSE;
|
||||
}
|
||||
class_descriptor = java_wrapper->class_descriptor;
|
||||
java_array = java_wrapper->java_obj;
|
||||
|
||||
PR_ASSERT(class_descriptor->type == JAVA_SIGNATURE_ARRAY);
|
||||
|
||||
JS_IdToValue(cx, id, &idval);
|
||||
|
||||
if (!JSVAL_IS_INT(idval))
|
||||
idval = try_convert_to_jsint(cx, idval);
|
||||
|
||||
if (!JSVAL_IS_INT(idval)) {
|
||||
/*
|
||||
* Usually, properties of JavaArray objects are indexed by integers, but
|
||||
* Java arrays also inherit all the methods of java.lang.Object, so a
|
||||
* string-valued property is also possible.
|
||||
*/
|
||||
if (JSVAL_IS_STRING(idval)) {
|
||||
const char *member_name;
|
||||
|
||||
member_name = JS_GetStringBytes(JSVAL_TO_STRING(idval));
|
||||
|
||||
if (do_assignment) {
|
||||
JSVersion version = JS_GetVersion(cx);
|
||||
|
||||
if (!JSVERSION_IS_ECMA(version)) {
|
||||
|
||||
JS_ReportError(cx, "Attempt to write to invalid Java array "
|
||||
"element \"%s\"", member_name);
|
||||
return JS_FALSE;
|
||||
} else {
|
||||
*vp = JSVAL_VOID;
|
||||
return JS_TRUE;
|
||||
}
|
||||
} else {
|
||||
if (!strcmp(member_name, "length")) {
|
||||
array_length = jsj_GetJavaArrayLength(cx, jEnv, java_array);
|
||||
if (array_length < 0)
|
||||
return JS_FALSE;
|
||||
if (vp)
|
||||
*vp = INT_TO_JSVAL(array_length);
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
/* Check to see if we're reflecting a Java array method */
|
||||
return JavaObject_getPropertyById(cx, obj, id, vp);
|
||||
}
|
||||
}
|
||||
|
||||
JS_ReportError(cx, "invalid Java array index expression");
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
index = JSVAL_TO_INT(idval);
|
||||
|
||||
#if 0
|
||||
array_length = jsj_GetJavaArrayLength(cx, jEnv, java_array);
|
||||
if (array_length < 0)
|
||||
return JS_FALSE;
|
||||
|
||||
/* Just let Java throw an exception instead of checking array bounds here */
|
||||
if (index < 0 || index >= array_length) {
|
||||
JS_ReportError(cx, "Java array index %d out of range", index);
|
||||
return JS_FALSE;
|
||||
}
|
||||
#endif
|
||||
|
||||
array_component_signature = class_descriptor->array_component_signature;
|
||||
|
||||
if (!vp)
|
||||
return JS_TRUE;
|
||||
|
||||
if (do_assignment) {
|
||||
return jsj_SetJavaArrayElement(cx, jEnv, java_array, index,
|
||||
array_component_signature, *vp);
|
||||
} else {
|
||||
return jsj_GetJavaArrayElement(cx, jEnv, java_array, index,
|
||||
array_component_signature, vp);
|
||||
}
|
||||
}
|
||||
|
||||
PR_STATIC_CALLBACK(JSBool)
|
||||
JavaArray_getPropertyById(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
|
||||
{
|
||||
JNIEnv *jEnv;
|
||||
jsj_MapJSContextToJSJThread(cx, &jEnv);
|
||||
if (!jEnv)
|
||||
return JS_FALSE;
|
||||
return access_java_array_element(cx, jEnv, obj, id, vp, JS_FALSE);
|
||||
}
|
||||
|
||||
PR_STATIC_CALLBACK(JSBool)
|
||||
JavaArray_setPropertyById(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
|
||||
{
|
||||
JNIEnv *jEnv;
|
||||
jsj_MapJSContextToJSJThread(cx, &jEnv);
|
||||
if (!jEnv)
|
||||
return JS_FALSE;
|
||||
return access_java_array_element(cx, jEnv, obj, id, vp, JS_TRUE);
|
||||
}
|
||||
|
||||
static JSBool
|
||||
JavaArray_lookupProperty(JSContext *cx, JSObject *obj, jsid id,
|
||||
JSObject **objp, JSProperty **propp
|
||||
#if defined JS_THREADSAFE && defined DEBUG
|
||||
, const char *file, uintN line
|
||||
#endif
|
||||
)
|
||||
{
|
||||
JNIEnv *jEnv;
|
||||
jsj_MapJSContextToJSJThread(cx, &jEnv);
|
||||
if (!jEnv)
|
||||
return JS_FALSE;
|
||||
|
||||
return access_java_array_element(cx, jEnv, obj, id, NULL, JS_FALSE);
|
||||
}
|
||||
|
||||
static JSBool
|
||||
JavaArray_defineProperty(JSContext *cx, JSObject *obj, jsid id, jsval value,
|
||||
JSPropertyOp getter, JSPropertyOp setter,
|
||||
uintN attrs, JSProperty **propp)
|
||||
{
|
||||
JS_ReportError(cx, "Cannot define a new property in a JavaArray");
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
static JSBool
|
||||
JavaArray_getAttributes(JSContext *cx, JSObject *obj, jsid id,
|
||||
JSProperty *prop, uintN *attrsp)
|
||||
{
|
||||
/* We don't maintain JS property attributes for Java class members */
|
||||
*attrsp = JSPROP_PERMANENT|JSPROP_ENUMERATE;
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
static JSBool
|
||||
JavaArray_setAttributes(JSContext *cx, JSObject *obj, jsid id,
|
||||
JSProperty *prop, uintN *attrsp)
|
||||
{
|
||||
/* We don't maintain JS property attributes for Java class members */
|
||||
if (*attrsp != (JSPROP_PERMANENT|JSPROP_ENUMERATE)) {
|
||||
PR_ASSERT(0);
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
/* Silently ignore all setAttribute attempts */
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
static JSBool
|
||||
JavaArray_deleteProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
|
||||
{
|
||||
JSVersion version = JS_GetVersion(cx);
|
||||
|
||||
*vp = JSVAL_FALSE;
|
||||
|
||||
if (!JSVERSION_IS_ECMA(version)) {
|
||||
JS_ReportError(cx, "Properties of JavaArray objects may not be deleted");
|
||||
return JS_FALSE;
|
||||
} else {
|
||||
/* Attempts to delete permanent properties are silently ignored
|
||||
by ECMAScript. */
|
||||
return JS_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
static JSBool
|
||||
JavaArray_defaultValue(JSContext *cx, JSObject *obj, JSType type, jsval *vp)
|
||||
{
|
||||
/* printf("In JavaArray_defaultValue()\n"); */
|
||||
return JavaObject_convert(cx, obj, JSTYPE_STRING, vp);
|
||||
}
|
||||
|
||||
static JSBool
|
||||
JavaArray_newEnumerate(JSContext *cx, JSObject *obj, JSIterateOp enum_op,
|
||||
jsval *statep, jsid *idp)
|
||||
{
|
||||
JavaObjectWrapper *java_wrapper;
|
||||
JNIEnv *jEnv;
|
||||
jsize array_length, index;
|
||||
|
||||
java_wrapper = JS_GetPrivate(cx, obj);
|
||||
/* Check for prototype object */
|
||||
if (!java_wrapper) {
|
||||
*statep = JSVAL_NULL;
|
||||
if (idp)
|
||||
*idp = INT_TO_JSVAL(0);
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
/* Get the Java per-thread environment pointer for this JSContext */
|
||||
jsj_MapJSContextToJSJThread(cx, &jEnv);
|
||||
if (!jEnv)
|
||||
return JS_FALSE;
|
||||
|
||||
array_length = jsj_GetJavaArrayLength(cx, jEnv, java_wrapper->java_obj);
|
||||
if (array_length < 0)
|
||||
return JS_FALSE;
|
||||
|
||||
switch(enum_op) {
|
||||
case JSENUMERATE_INIT:
|
||||
*statep = INT_TO_JSVAL(0);
|
||||
|
||||
if (idp)
|
||||
*idp = INT_TO_JSVAL(array_length);
|
||||
return JS_TRUE;
|
||||
|
||||
case JSENUMERATE_NEXT:
|
||||
index = JSVAL_TO_INT(*statep);
|
||||
if (index < array_length) {
|
||||
JS_ValueToId(cx, INT_TO_JSVAL(index), idp);
|
||||
index++;
|
||||
*statep = INT_TO_JSVAL(index);
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
/* Fall through ... */
|
||||
|
||||
case JSENUMERATE_DESTROY:
|
||||
*statep = JSVAL_NULL;
|
||||
return JS_TRUE;
|
||||
|
||||
default:
|
||||
PR_ASSERT(0);
|
||||
return JS_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
static JSBool
|
||||
JavaArray_checkAccess(JSContext *cx, JSObject *obj, jsid id,
|
||||
JSAccessMode mode, jsval *vp, uintN *attrsp)
|
||||
{
|
||||
switch (mode) {
|
||||
case JSACC_WATCH:
|
||||
JS_ReportError(cx, "Cannot place watchpoints on JavaArray object properties");
|
||||
return JS_FALSE;
|
||||
|
||||
case JSACC_IMPORT:
|
||||
JS_ReportError(cx, "Cannot export a JavaArray object's properties");
|
||||
return JS_FALSE;
|
||||
|
||||
default:
|
||||
return JS_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
JSObjectOps JavaArray_ops = {
|
||||
/* Mandatory non-null function pointer members. */
|
||||
NULL, /* newObjectMap */
|
||||
NULL, /* destroyObjectMap */
|
||||
JavaArray_lookupProperty,
|
||||
JavaArray_defineProperty,
|
||||
JavaArray_getPropertyById, /* getProperty */
|
||||
JavaArray_setPropertyById, /* setProperty */
|
||||
JavaArray_getAttributes,
|
||||
JavaArray_setAttributes,
|
||||
JavaArray_deleteProperty,
|
||||
JavaArray_defaultValue,
|
||||
JavaArray_newEnumerate,
|
||||
JavaArray_checkAccess,
|
||||
|
||||
/* Optionally non-null members start here. */
|
||||
NULL, /* thisObject */
|
||||
NULL, /* dropProperty */
|
||||
NULL, /* call */
|
||||
NULL, /* construct */
|
||||
NULL, /* xdrObject */
|
||||
NULL /* hasInstance */
|
||||
};
|
||||
|
||||
static JSObjectOps *
|
||||
JavaArray_getObjectOps(JSContext *cx, JSClass *clazz)
|
||||
{
|
||||
return &JavaArray_ops;
|
||||
}
|
||||
|
||||
JSClass JavaArray_class = {
|
||||
"JavaArray", JSCLASS_HAS_PRIVATE,
|
||||
NULL, NULL, NULL, NULL,
|
||||
NULL, NULL, JavaObject_convert, JavaObject_finalize,
|
||||
JavaArray_getObjectOps,
|
||||
};
|
||||
|
||||
extern PR_IMPORT_DATA(JSObjectOps) js_ObjectOps;
|
||||
|
||||
|
||||
/* Initialize the JS JavaArray class */
|
||||
JSBool
|
||||
jsj_init_JavaArray(JSContext *cx, JSObject *global_obj)
|
||||
{
|
||||
JavaArray_ops.newObjectMap = js_ObjectOps.newObjectMap;
|
||||
JavaArray_ops.destroyObjectMap = js_ObjectOps.destroyObjectMap;
|
||||
|
||||
if (!JS_InitClass(cx, global_obj,
|
||||
0, &JavaArray_class, 0, 0,
|
||||
0, 0, 0, 0))
|
||||
return JS_FALSE;
|
||||
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
586
mozilla/js/src/liveconnect/jsj_JavaClass.c
Normal file
@@ -0,0 +1,586 @@
|
||||
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.0 (the "License"); you may not use this file except in
|
||||
* compliance with the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
* the License for the specific language governing rights and limitations
|
||||
* under the License.
|
||||
*
|
||||
* The Original Code is Mozilla Communicator client code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are Copyright (C) 1998
|
||||
* Netscape Communications Corporation. All Rights Reserved.
|
||||
*/
|
||||
|
||||
/* This file is part of the Java-vendor-neutral implementation of LiveConnect
|
||||
*
|
||||
* It contains the native code implementation of JS's JavaClass class.
|
||||
*
|
||||
* A JavaClass is JavaScript's representation of a Java class.
|
||||
* Its parent JS object is always a JavaPackage object. A JavaClass is not an
|
||||
* exact reflection of Java's corresponding java.lang.Class object. Rather,
|
||||
* the properties of a JavaClass are the static methods and properties of the
|
||||
* corresponding Java class.
|
||||
*
|
||||
* Note that there is no runtime equivalent to the JavaClass class in Java.
|
||||
* (Although there are instances of java.lang.String and there are static
|
||||
* methods of java.lang.String that can be invoked, there's no such thing as
|
||||
* a first-class object that can be referenced simply as "java.lang.String".)
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "jsj_private.h" /* LiveConnect internals */
|
||||
|
||||
static JSBool
|
||||
JavaClass_convert(JSContext *cx, JSObject *obj, JSType type, jsval *vp)
|
||||
{
|
||||
char *name;
|
||||
JSString *str;
|
||||
|
||||
JavaClassDescriptor *class_descriptor;
|
||||
|
||||
class_descriptor = JS_GetPrivate(cx, obj);
|
||||
if (!class_descriptor)
|
||||
return JS_FALSE;
|
||||
|
||||
switch(type) {
|
||||
|
||||
|
||||
case JSTYPE_STRING:
|
||||
/* Convert '/' to '.' so that it looks like Java language syntax. */
|
||||
if (!class_descriptor->name)
|
||||
break;
|
||||
name = PR_smprintf("[JavaClass %s]", class_descriptor->name);
|
||||
if (!name) {
|
||||
JS_ReportOutOfMemory(cx);
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
str = JS_NewString(cx, name, strlen(name));
|
||||
if (!str) {
|
||||
free(name);
|
||||
/* It's not necessary to call JS_ReportOutOfMemory(), as
|
||||
JS_NewString() will do so on failure. */
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
*vp = STRING_TO_JSVAL(str);
|
||||
return JS_TRUE;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
static JSBool
|
||||
lookup_static_member_by_id(JSContext *cx, JNIEnv *jEnv, JSObject *obj,
|
||||
JavaClassDescriptor **class_descriptorp,
|
||||
jsid id, JavaMemberDescriptor **memberp)
|
||||
{
|
||||
jsval idval;
|
||||
JavaMemberDescriptor *member_descriptor;
|
||||
const char *member_name;
|
||||
JavaClassDescriptor *class_descriptor;
|
||||
|
||||
class_descriptor = JS_GetPrivate(cx, obj);
|
||||
if (!class_descriptor) {
|
||||
*class_descriptorp = NULL;
|
||||
*memberp = NULL;
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
if (class_descriptorp)
|
||||
*class_descriptorp = class_descriptor;
|
||||
|
||||
member_descriptor = jsj_LookupJavaStaticMemberDescriptorById(cx, jEnv, class_descriptor, id);
|
||||
if (!member_descriptor) {
|
||||
JS_IdToValue(cx, id, &idval);
|
||||
if (!JSVAL_IS_STRING(idval)) {
|
||||
JS_ReportError(cx, "invalid JavaClass property expression. "
|
||||
"(methods and fields of a JavaClass object can only be identified by their name)");
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
member_name = JS_GetStringBytes(JSVAL_TO_STRING(idval));
|
||||
|
||||
/* Why do we have to do this ? */
|
||||
if (!strcmp(member_name, "prototype")) {
|
||||
*memberp = NULL;
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
JS_ReportError(cx, "Java class %s has no public static field or method named \"%s\"",
|
||||
class_descriptor->name, member_name);
|
||||
return JS_FALSE;
|
||||
}
|
||||
if (memberp)
|
||||
*memberp = member_descriptor;
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
PR_STATIC_CALLBACK(JSBool)
|
||||
JavaClass_getPropertyById(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
|
||||
{
|
||||
jsval idval;
|
||||
jclass java_class;
|
||||
const char *member_name;
|
||||
JavaClassDescriptor *class_descriptor;
|
||||
JavaMemberDescriptor *member_descriptor;
|
||||
JNIEnv *jEnv;
|
||||
|
||||
/* printf("In JavaClass_getProperty\n"); */
|
||||
|
||||
/* Get the Java per-thread environment pointer for this JSContext */
|
||||
jsj_MapJSContextToJSJThread(cx, &jEnv);
|
||||
if (!jEnv)
|
||||
return JS_FALSE;
|
||||
|
||||
if (!lookup_static_member_by_id(cx, jEnv, obj, &class_descriptor, id, &member_descriptor))
|
||||
return JS_FALSE;
|
||||
if (!member_descriptor) {
|
||||
*vp = JSVAL_VOID;
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
java_class = class_descriptor->java_class;
|
||||
|
||||
if (member_descriptor->field) {
|
||||
if (!member_descriptor->methods) {
|
||||
return jsj_GetJavaFieldValue(cx, jEnv, member_descriptor->field, java_class, vp);
|
||||
} else {
|
||||
PR_ASSERT(0);
|
||||
}
|
||||
} else {
|
||||
JSFunction *function;
|
||||
|
||||
/* TODO - eliminate JSFUN_BOUND_METHOD */
|
||||
JS_IdToValue(cx, id, &idval);
|
||||
member_name = JS_GetStringBytes(JSVAL_TO_STRING(idval));
|
||||
function = JS_NewFunction(cx, jsj_JavaStaticMethodWrapper, 0,
|
||||
JSFUN_BOUND_METHOD, obj, member_name);
|
||||
if (!function)
|
||||
return JS_FALSE;
|
||||
|
||||
*vp = OBJECT_TO_JSVAL(JS_GetFunctionObject(function));
|
||||
}
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
PR_STATIC_CALLBACK(JSBool)
|
||||
JavaClass_setPropertyById(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
|
||||
{
|
||||
jclass java_class;
|
||||
const char *member_name;
|
||||
JavaClassDescriptor *class_descriptor;
|
||||
JavaMemberDescriptor *member_descriptor;
|
||||
jsval idval;
|
||||
JNIEnv *jEnv;
|
||||
|
||||
/* printf("In JavaClass_setProperty\n"); */
|
||||
|
||||
/* Get the Java per-thread environment pointer for this JSContext */
|
||||
jsj_MapJSContextToJSJThread(cx, &jEnv);
|
||||
if (!jEnv)
|
||||
return JS_FALSE;
|
||||
|
||||
if (!lookup_static_member_by_id(cx, jEnv, obj, &class_descriptor, id, &member_descriptor))
|
||||
return JS_FALSE;
|
||||
|
||||
/* Check for the case where there is a method with the given name, but no field
|
||||
with that name */
|
||||
if (!member_descriptor->field)
|
||||
goto no_such_field;
|
||||
|
||||
/* Silently fail if field value is final (immutable), as required by ECMA spec */
|
||||
if (member_descriptor->field->modifiers & ACC_FINAL)
|
||||
return JS_TRUE;
|
||||
|
||||
java_class = class_descriptor->java_class;
|
||||
return jsj_SetJavaFieldValue(cx, jEnv, member_descriptor->field, java_class, *vp);
|
||||
|
||||
no_such_field:
|
||||
JS_IdToValue(cx, id, &idval);
|
||||
member_name = JS_GetStringBytes(JSVAL_TO_STRING(idval));
|
||||
JS_ReportError(cx, "No static field named \"%s\" in Java class %s",
|
||||
member_name, class_descriptor->name);
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Free the private native data associated with the JavaPackage object.
|
||||
*/
|
||||
PR_STATIC_CALLBACK(void)
|
||||
JavaClass_finalize(JSContext *cx, JSObject *obj)
|
||||
{
|
||||
JNIEnv *jEnv;
|
||||
|
||||
JavaClassDescriptor *class_descriptor = JS_GetPrivate(cx, obj);
|
||||
if (!class_descriptor)
|
||||
return;
|
||||
|
||||
/* Get the Java per-thread environment pointer for this JSContext */
|
||||
jsj_MapJSContextToJSJThread(cx, &jEnv);
|
||||
if (!jEnv)
|
||||
return;
|
||||
|
||||
/* printf("Finalizing %s\n", class_descriptor->name); */
|
||||
jsj_ReleaseJavaClassDescriptor(cx, jEnv, class_descriptor);
|
||||
}
|
||||
|
||||
|
||||
static JSBool
|
||||
JavaClass_lookupProperty(JSContext *cx, JSObject *obj, jsid id,
|
||||
JSObject **objp, JSProperty **propp
|
||||
#if defined JS_THREADSAFE && defined DEBUG
|
||||
, const char *file, uintN line
|
||||
#endif
|
||||
)
|
||||
{
|
||||
JNIEnv *jEnv;
|
||||
JSErrorReporter old_reporter;
|
||||
|
||||
/* printf("In JavaClass_lookupProperty()\n"); */
|
||||
|
||||
/* Get the Java per-thread environment pointer for this JSContext */
|
||||
jsj_MapJSContextToJSJThread(cx, &jEnv);
|
||||
if (!jEnv)
|
||||
return JS_FALSE;
|
||||
|
||||
old_reporter = JS_SetErrorReporter(cx, NULL);
|
||||
if (lookup_static_member_by_id(cx, jEnv, obj, NULL, id, NULL)) {
|
||||
*objp = obj;
|
||||
*propp = (JSProperty*)1;
|
||||
} else {
|
||||
*objp = NULL;
|
||||
*propp = NULL;
|
||||
}
|
||||
|
||||
JS_SetErrorReporter(cx, old_reporter);
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
static JSBool
|
||||
JavaClass_defineProperty(JSContext *cx, JSObject *obj, jsid id, jsval value,
|
||||
JSPropertyOp getter, JSPropertyOp setter,
|
||||
uintN attrs, JSProperty **propp)
|
||||
{
|
||||
JS_ReportError(cx, "Cannot define a new property in a JavaClass");
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
static JSBool
|
||||
JavaClass_getAttributes(JSContext *cx, JSObject *obj, jsid id,
|
||||
JSProperty *prop, uintN *attrsp)
|
||||
{
|
||||
/* We don't maintain JS property attributes for Java class members */
|
||||
*attrsp = JSPROP_PERMANENT|JSPROP_ENUMERATE;
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
static JSBool
|
||||
JavaClass_setAttributes(JSContext *cx, JSObject *obj, jsid id,
|
||||
JSProperty *prop, uintN *attrsp)
|
||||
{
|
||||
/* We don't maintain JS property attributes for Java class members */
|
||||
if (*attrsp != (JSPROP_PERMANENT|JSPROP_ENUMERATE)) {
|
||||
PR_ASSERT(0);
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
/* Silently ignore all setAttribute attempts */
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
static JSBool
|
||||
JavaClass_deleteProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
|
||||
{
|
||||
JSVersion version = JS_GetVersion(cx);
|
||||
|
||||
*vp = JSVAL_FALSE;
|
||||
|
||||
if (!JSVERSION_IS_ECMA(version)) {
|
||||
JS_ReportError(cx, "Properties of JavaClass objects may not be deleted");
|
||||
return JS_FALSE;
|
||||
} else {
|
||||
/* Attempts to delete permanent properties are silently ignored
|
||||
by ECMAScript. */
|
||||
return JS_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
static JSBool
|
||||
JavaClass_defaultValue(JSContext *cx, JSObject *obj, JSType type, jsval *vp)
|
||||
{
|
||||
/* printf("In JavaClass_defaultValue()\n"); */
|
||||
return JavaClass_convert(cx, obj, JSTYPE_STRING, vp);
|
||||
}
|
||||
|
||||
static JSBool
|
||||
JavaClass_newEnumerate(JSContext *cx, JSObject *obj, JSIterateOp enum_op,
|
||||
jsval *statep, jsid *idp)
|
||||
{
|
||||
JavaMemberDescriptor *member_descriptor;
|
||||
JavaClassDescriptor *class_descriptor;
|
||||
JNIEnv *jEnv;
|
||||
|
||||
class_descriptor = JS_GetPrivate(cx, obj);
|
||||
|
||||
/* Check for prototype JavaClass object */
|
||||
if (!class_descriptor) {
|
||||
*statep = JSVAL_NULL;
|
||||
if (idp)
|
||||
*idp = INT_TO_JSVAL(0);
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
switch(enum_op) {
|
||||
case JSENUMERATE_INIT:
|
||||
/* Get the Java per-thread environment pointer for this JSContext */
|
||||
jsj_MapJSContextToJSJThread(cx, &jEnv);
|
||||
if (!jEnv)
|
||||
return JS_FALSE;
|
||||
member_descriptor = jsj_GetClassStaticMembers(cx, jEnv, class_descriptor);
|
||||
*statep = PRIVATE_TO_JSVAL(member_descriptor);
|
||||
if (idp)
|
||||
*idp = INT_TO_JSVAL(class_descriptor->num_instance_members);
|
||||
return JS_TRUE;
|
||||
|
||||
case JSENUMERATE_NEXT:
|
||||
member_descriptor = JSVAL_TO_PRIVATE(*statep);
|
||||
if (member_descriptor) {
|
||||
*idp = member_descriptor->id;
|
||||
*statep = PRIVATE_TO_JSVAL(member_descriptor->next);
|
||||
return JS_TRUE;
|
||||
}
|
||||
/* Fall through ... */
|
||||
|
||||
case JSENUMERATE_DESTROY:
|
||||
*statep = JSVAL_NULL;
|
||||
return JS_TRUE;
|
||||
|
||||
default:
|
||||
PR_ASSERT(0);
|
||||
return JS_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
static JSBool
|
||||
JavaClass_checkAccess(JSContext *cx, JSObject *obj, jsid id,
|
||||
JSAccessMode mode, jsval *vp, uintN *attrsp)
|
||||
{
|
||||
switch (mode) {
|
||||
case JSACC_WATCH:
|
||||
JS_ReportError(cx, "Cannot place watchpoints on JavaClass object properties");
|
||||
return JS_FALSE;
|
||||
|
||||
case JSACC_IMPORT:
|
||||
JS_ReportError(cx, "Cannot export a JavaClass object's properties");
|
||||
return JS_FALSE;
|
||||
|
||||
default:
|
||||
return JS_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Implement the JavaScript instanceof operator for JavaClass objects by using
|
||||
* the equivalent Java instanceof operation.
|
||||
*/
|
||||
static JSBool
|
||||
JavaClass_hasInstance(JSContext *cx, JSObject *obj, jsval candidate_jsval,
|
||||
JSBool *has_instancep)
|
||||
{
|
||||
JavaClassDescriptor *class_descriptor;
|
||||
JavaObjectWrapper *java_wrapper;
|
||||
JSClass *js_class;
|
||||
JSBool has_instance;
|
||||
JSObject *candidate_obj;
|
||||
jclass java_class;
|
||||
jobject java_obj;
|
||||
JNIEnv *jEnv;
|
||||
|
||||
has_instance = JS_FALSE;
|
||||
class_descriptor = JS_GetPrivate(cx, obj);
|
||||
if (!class_descriptor) {
|
||||
JS_ReportError(cx, "illegal operation on JavaClass prototype object");
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Make sure that the thing to the left of the instanceof operator is a
|
||||
* Java object.
|
||||
*/
|
||||
if (!JSVAL_IS_OBJECT(candidate_jsval))
|
||||
goto done;
|
||||
candidate_obj = JSVAL_TO_OBJECT(candidate_jsval);
|
||||
js_class = JS_GetClass(candidate_obj);
|
||||
if ((js_class != &JavaObject_class) && (js_class != &JavaArray_class))
|
||||
goto done;
|
||||
|
||||
java_class = class_descriptor->java_class;
|
||||
java_wrapper = JS_GetPrivate(cx, candidate_obj);
|
||||
if (!java_wrapper) {
|
||||
JS_ReportError(cx, "illegal operation on prototype object");
|
||||
return JS_FALSE;
|
||||
}
|
||||
java_obj = java_wrapper->java_obj;
|
||||
/* Get JNI pointer */
|
||||
jsj_MapJSContextToJSJThread(cx, &jEnv);
|
||||
has_instance = (*jEnv)->IsInstanceOf(jEnv, java_obj, java_class);
|
||||
|
||||
done:
|
||||
*has_instancep = has_instance;
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
JSObjectOps JavaClass_ops = {
|
||||
/* Mandatory non-null function pointer members. */
|
||||
NULL, /* newObjectMap */
|
||||
NULL, /* destroyObjectMap */
|
||||
JavaClass_lookupProperty,
|
||||
JavaClass_defineProperty,
|
||||
JavaClass_getPropertyById, /* getProperty */
|
||||
JavaClass_setPropertyById, /* setProperty */
|
||||
JavaClass_getAttributes,
|
||||
JavaClass_setAttributes,
|
||||
JavaClass_deleteProperty,
|
||||
JavaClass_defaultValue,
|
||||
JavaClass_newEnumerate,
|
||||
JavaClass_checkAccess,
|
||||
|
||||
/* Optionally non-null members start here. */
|
||||
NULL, /* thisObject */
|
||||
NULL, /* dropProperty */
|
||||
jsj_JavaConstructorWrapper, /* call */
|
||||
jsj_JavaConstructorWrapper, /* construct */
|
||||
NULL, /* xdrObject */
|
||||
JavaClass_hasInstance, /* hasInstance */
|
||||
};
|
||||
|
||||
static JSObjectOps *
|
||||
JavaClass_getObjectOps(JSContext *cx, JSClass *clazz)
|
||||
{
|
||||
return &JavaClass_ops;
|
||||
}
|
||||
|
||||
JSClass JavaClass_class = {
|
||||
"JavaClass", JSCLASS_HAS_PRIVATE,
|
||||
NULL, NULL, NULL, NULL,
|
||||
NULL, NULL, JavaClass_convert, JavaClass_finalize,
|
||||
JavaClass_getObjectOps,
|
||||
};
|
||||
|
||||
static JSObject *
|
||||
jsj_new_JavaClass(JSContext *cx, JNIEnv *jEnv, JSObject* parent_obj,
|
||||
JavaClassDescriptor *class_descriptor)
|
||||
{
|
||||
JSObject *JavaClass_obj;
|
||||
|
||||
JavaClass_obj = JS_NewObject(cx, &JavaClass_class, 0, parent_obj);
|
||||
if (!JavaClass_obj)
|
||||
return NULL;
|
||||
|
||||
JS_SetPrivate(cx, JavaClass_obj, (void *)class_descriptor);
|
||||
|
||||
#ifdef DEBUG
|
||||
/* printf("JavaClass \'%s\' created\n", class_descriptor->name); */
|
||||
#endif
|
||||
|
||||
return JavaClass_obj;
|
||||
}
|
||||
|
||||
JSObject *
|
||||
jsj_define_JavaClass(JSContext *cx, JNIEnv *jEnv, JSObject* parent_obj,
|
||||
const char *simple_class_name,
|
||||
jclass java_class)
|
||||
{
|
||||
JavaClassDescriptor *class_descriptor;
|
||||
JSObject *JavaClass_obj;
|
||||
|
||||
class_descriptor = jsj_GetJavaClassDescriptor(cx, jEnv, java_class);
|
||||
if (!class_descriptor)
|
||||
return NULL;
|
||||
|
||||
JavaClass_obj = jsj_new_JavaClass(cx, jEnv, parent_obj, class_descriptor);
|
||||
if (!JavaClass_obj)
|
||||
return NULL;
|
||||
|
||||
if (!JS_DefineProperty(cx, parent_obj, simple_class_name,
|
||||
OBJECT_TO_JSVAL(JavaClass_obj), 0, 0,
|
||||
JSPROP_PERMANENT|JSPROP_READONLY|JSPROP_ENUMERATE))
|
||||
return NULL;
|
||||
return JavaClass_obj;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* The getClass() native JS method is defined as a property of the global
|
||||
* object. Given a JavaObject it returns the corresponding JavaClass. This
|
||||
* is useful for accessing static methods and fields.
|
||||
*
|
||||
* js> getClass(new java.lang.String("foo"))
|
||||
* [JavaClass java.lang.String]
|
||||
*/
|
||||
static JSBool
|
||||
getClass(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
|
||||
{
|
||||
JSObject *obj_arg, *JavaClass_obj;
|
||||
JavaObjectWrapper *java_wrapper;
|
||||
JavaClassDescriptor *class_descriptor;
|
||||
JNIEnv *jEnv;
|
||||
|
||||
jsj_MapJSContextToJSJThread(cx, &jEnv);
|
||||
if (!jEnv)
|
||||
return JS_FALSE;
|
||||
|
||||
if (argc != 1 ||
|
||||
!JSVAL_IS_OBJECT(argv[0]) ||
|
||||
!(obj_arg = JSVAL_TO_OBJECT(argv[0])) ||
|
||||
(!JS_InstanceOf(cx, obj_arg, &JavaObject_class, 0) &&
|
||||
!JS_InstanceOf(cx, obj_arg, &JavaArray_class, 0))) {
|
||||
JS_ReportError(cx, "getClass expects a Java object argument");
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
java_wrapper = JS_GetPrivate(cx, obj_arg);
|
||||
if (!java_wrapper) {
|
||||
JS_ReportError(cx, "getClass called on prototype object");
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
class_descriptor = java_wrapper->class_descriptor;
|
||||
|
||||
JavaClass_obj = jsj_new_JavaClass(cx, jEnv, NULL, class_descriptor);
|
||||
if (!JavaClass_obj)
|
||||
return JS_FALSE;
|
||||
*rval = OBJECT_TO_JSVAL(JavaClass_obj);
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
extern PR_IMPORT_DATA(JSObjectOps) js_ObjectOps;
|
||||
|
||||
JSBool
|
||||
jsj_init_JavaClass(JSContext *cx, JSObject *global_obj)
|
||||
{
|
||||
JavaClass_ops.newObjectMap = js_ObjectOps.newObjectMap;
|
||||
JavaClass_ops.destroyObjectMap = js_ObjectOps.destroyObjectMap;
|
||||
|
||||
/* Define JavaClass class */
|
||||
if (!JS_InitClass(cx, global_obj, 0, &JavaClass_class, 0, 0, 0, 0, 0, 0))
|
||||
return JS_FALSE;
|
||||
|
||||
if (!JS_DefineFunction(cx, global_obj, "getClass", getClass, 0,
|
||||
JSPROP_READONLY))
|
||||
return JS_FALSE;
|
||||
|
||||
return jsj_InitJavaClassReflectionsTable();
|
||||
}
|
||||
|
||||
134
mozilla/js/src/liveconnect/jsj_JavaMember.c
Normal file
@@ -0,0 +1,134 @@
|
||||
/* -*- Mode: C; tab-width: 8 -*-
|
||||
* Copyright (C) 1998 Netscape Communications Corporation, All Rights Reserved.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is part of the Java-vendor-neutral implementation of LiveConnect
|
||||
*
|
||||
* It contains the native code implementation of JS's JavaMember class.
|
||||
* JavaMember's are a strange beast required only to handle the special case
|
||||
* of a public field and a public method that appear in the same class and
|
||||
* have the same name. When such a field/method is used in Java, the compiler
|
||||
* can statically determine from context whether the field or the method is
|
||||
* being referenced, but that is not possible with JavaScript. For example:
|
||||
*
|
||||
* ambiguousVal = javaObj.fieldOrMethod; // ambiguousVal is a JavaMember object
|
||||
* a = ambiguousVal(); // ambiguousVal used as a method value
|
||||
* b = ambiguousVal + 4; // ambiguousVal used as a field value
|
||||
*
|
||||
* A JavaMember instance carries both the captured value of the Java field and
|
||||
* the method value until the context that the value is to be used in is known,
|
||||
* at which point conversion forces the use of one or the other.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "jsj_private.h" /* LiveConnect internals */
|
||||
|
||||
/* Private, native portion of a JavaMember */
|
||||
typedef struct JavaMethodOrFieldValue {
|
||||
jsval method_val;
|
||||
jsval field_val;
|
||||
} JavaMethodOrFieldValue;
|
||||
|
||||
JSObject *
|
||||
jsj_CreateJavaMember(JSContext *cx, jsval method_val, jsval field_val)
|
||||
{
|
||||
JavaMethodOrFieldValue *member_val;
|
||||
JSObject *JavaMember_obj;
|
||||
|
||||
member_val = (JavaMethodOrFieldValue *)JS_malloc(cx, sizeof(*member_val));
|
||||
if (!member_val)
|
||||
return NULL;
|
||||
|
||||
JavaMember_obj = JS_NewObject(cx, &JavaMember_class, 0, 0);
|
||||
if (!JavaMember_obj) {
|
||||
JS_free(cx, member_val);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
JS_SetPrivate(cx, JavaMember_obj, (void *)member_val);
|
||||
member_val->method_val = method_val;
|
||||
JS_AddRoot(cx, &member_val->method_val);
|
||||
member_val->field_val = field_val;
|
||||
if (JSVAL_IS_GCTHING(field_val))
|
||||
JS_AddRoot(cx, &member_val->field_val);
|
||||
|
||||
return JavaMember_obj;
|
||||
}
|
||||
|
||||
static void
|
||||
JavaMember_finalize(JSContext *cx, JSObject *obj)
|
||||
{
|
||||
JavaMethodOrFieldValue *member_val;
|
||||
JNIEnv *jEnv;
|
||||
|
||||
jsj_MapJSContextToJSJThread(cx, &jEnv);
|
||||
if (!jEnv)
|
||||
return;
|
||||
|
||||
member_val = JS_GetPrivate(cx, obj);
|
||||
if (!member_val)
|
||||
return;
|
||||
JS_RemoveRoot(cx, &member_val->method_val);
|
||||
if (JSVAL_IS_GCTHING(member_val->method_val))
|
||||
JS_RemoveRoot(cx, &member_val->method_val);
|
||||
JS_free(cx, member_val);
|
||||
}
|
||||
|
||||
static JSBool
|
||||
JavaMember_convert(JSContext *cx, JSObject *obj, JSType type, jsval *vp)
|
||||
{
|
||||
JavaMethodOrFieldValue *member_val;
|
||||
|
||||
member_val = JS_GetPrivate(cx, obj);
|
||||
if (!member_val) {
|
||||
if (type == JSTYPE_OBJECT) {
|
||||
*vp = OBJECT_TO_JSVAL(obj);
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
JS_ReportError(cx, "illegal operation on JavaObject prototype object");
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case JSTYPE_VOID:
|
||||
case JSTYPE_STRING:
|
||||
case JSTYPE_NUMBER:
|
||||
case JSTYPE_BOOLEAN:
|
||||
case JSTYPE_OBJECT:
|
||||
*vp = member_val->field_val;
|
||||
return JS_TRUE;
|
||||
|
||||
case JSTYPE_FUNCTION:
|
||||
*vp = member_val->method_val;
|
||||
return JS_TRUE;
|
||||
|
||||
default:
|
||||
PR_ASSERT(0);
|
||||
return JS_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
JSClass JavaMember_class = {
|
||||
"JavaMember", JSCLASS_HAS_PRIVATE,
|
||||
JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
|
||||
JS_EnumerateStub, JS_ResolveStub,
|
||||
JavaMember_convert, JavaMember_finalize
|
||||
};
|
||||
|
||||
extern PR_IMPORT_DATA(JSObjectOps) js_ObjectOps;
|
||||
|
||||
JSBool
|
||||
jsj_init_JavaMember(JSContext *cx, JSObject *global_obj)
|
||||
{
|
||||
if (!JS_InitClass(cx, global_obj,
|
||||
0, &JavaMember_class, 0, 0,
|
||||
0, 0,
|
||||
0, 0))
|
||||
return JS_FALSE;
|
||||
|
||||
return JS_TRUE;
|
||||
}
|
||||
686
mozilla/js/src/liveconnect/jsj_JavaObject.c
Normal file
@@ -0,0 +1,686 @@
|
||||
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.0 (the "License"); you may not use this file except in
|
||||
* compliance with the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
* the License for the specific language governing rights and limitations
|
||||
* under the License.
|
||||
*
|
||||
* The Original Code is Mozilla Communicator client code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are Copyright (C) 1998
|
||||
* Netscape Communications Corporation. All Rights Reserved.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is part of the Java-vendor-neutral implementation of LiveConnect
|
||||
*
|
||||
* It contains the native code implementation of JS's JavaObject class.
|
||||
*
|
||||
* An instance of JavaObject is the JavaScript reflection of a Java object.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "jsj_private.h" /* LiveConnect internals */
|
||||
#include "jsj_hash.h" /* Hash table with Java object as key */
|
||||
|
||||
|
||||
/*
|
||||
* This is a hash table that maps from Java objects to JS objects.
|
||||
* It is used to ensure that the same JS object is obtained when a Java
|
||||
* object is reflected more than once, so that JS object equality tests
|
||||
* work in the expected manner, i.e. the "==" and "===" operators.
|
||||
*
|
||||
* The table entry keys are Java objects (of type jobject) and the entry values
|
||||
* are JSObject pointers. Because the jobject type is an opaque handle and
|
||||
* not necessarily a pointer, the hashing and key comparison functions must
|
||||
* invoke the appropriate JVM functions.
|
||||
*
|
||||
* When the corresponding JS object instance is finalized, the entry is
|
||||
* removed from the table, and a Java GC root for the Java object is removed.
|
||||
*/
|
||||
static JSJHashTable *java_obj_reflections = NULL;
|
||||
|
||||
#ifdef JS_THREADSAFE
|
||||
static PRMonitor *java_obj_reflections_monitor = NULL;
|
||||
#endif
|
||||
|
||||
static JSBool
|
||||
init_java_obj_reflections_table()
|
||||
{
|
||||
java_obj_reflections =
|
||||
JSJ_NewHashTable(512, jsj_HashJavaObject, jsj_JavaObjectComparator,
|
||||
NULL, NULL, NULL);
|
||||
if (!java_obj_reflections)
|
||||
return JS_FALSE;
|
||||
|
||||
#ifdef JS_THREADSAFE
|
||||
java_obj_reflections_monitor = PR_NewNamedMonitor("java_obj_reflections");
|
||||
if (!java_obj_reflections_monitor) {
|
||||
PR_HashTableDestroy(java_obj_reflections);
|
||||
return JS_FALSE;
|
||||
}
|
||||
#endif
|
||||
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
JSObject *
|
||||
jsj_WrapJavaObject(JSContext *cx,
|
||||
JNIEnv *jEnv,
|
||||
jobject java_obj,
|
||||
jclass java_class)
|
||||
{
|
||||
JSJHashNumber hash_code;
|
||||
JSClass *js_class;
|
||||
JSObject *js_wrapper_obj;
|
||||
JavaObjectWrapper *java_wrapper;
|
||||
JavaClassDescriptor *class_descriptor;
|
||||
JSJHashEntry *he, **hep;
|
||||
|
||||
js_wrapper_obj = NULL;
|
||||
|
||||
hash_code = jsj_HashJavaObject((void*)java_obj, (void*)jEnv);
|
||||
|
||||
#ifdef JS_THREADSAFE
|
||||
PR_EnterMonitor(java_obj_reflections_monitor);
|
||||
#endif
|
||||
|
||||
hep = JSJ_HashTableRawLookup(java_obj_reflections,
|
||||
hash_code, java_obj, (void*)jEnv);
|
||||
he = *hep;
|
||||
if (he) {
|
||||
js_wrapper_obj = (JSObject *)he->value;
|
||||
if (js_wrapper_obj)
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* No existing reflection found. Construct a new one */
|
||||
class_descriptor = jsj_GetJavaClassDescriptor(cx, jEnv, java_class);
|
||||
if (!class_descriptor)
|
||||
goto done;
|
||||
if (class_descriptor->type == JAVA_SIGNATURE_ARRAY) {
|
||||
js_class = &JavaArray_class;
|
||||
} else {
|
||||
PR_ASSERT(class_descriptor->type == JAVA_SIGNATURE_CLASS);
|
||||
js_class = &JavaObject_class;
|
||||
}
|
||||
|
||||
/* Create new JS object to reflect Java object */
|
||||
js_wrapper_obj = JS_NewObject(cx, js_class, NULL, NULL);
|
||||
if (!js_wrapper_obj)
|
||||
goto done;
|
||||
|
||||
/* Create private, native portion of JavaObject */
|
||||
java_wrapper =
|
||||
(JavaObjectWrapper *)JS_malloc(cx, sizeof(JavaObjectWrapper));
|
||||
if (!java_wrapper) {
|
||||
jsj_ReleaseJavaClassDescriptor(cx, jEnv, class_descriptor);
|
||||
goto done;
|
||||
}
|
||||
JS_SetPrivate(cx, js_wrapper_obj, java_wrapper);
|
||||
java_wrapper->class_descriptor = class_descriptor;
|
||||
|
||||
java_obj = (*jEnv)->NewGlobalRef(jEnv, java_obj);
|
||||
java_wrapper->java_obj = java_obj;
|
||||
if (!java_obj)
|
||||
goto out_of_memory;
|
||||
|
||||
/* Add the JavaObject to the hash table */
|
||||
he = JSJ_HashTableRawAdd(java_obj_reflections, hep, hash_code,
|
||||
java_obj, js_wrapper_obj, (void*)jEnv);
|
||||
if (!he) {
|
||||
(*jEnv)->DeleteGlobalRef(jEnv, java_obj);
|
||||
goto out_of_memory;
|
||||
}
|
||||
|
||||
done:
|
||||
#ifdef JS_THREADSAFE
|
||||
PR_ExitMonitor(java_obj_reflections_monitor);
|
||||
#endif
|
||||
|
||||
return js_wrapper_obj;
|
||||
|
||||
out_of_memory:
|
||||
/* No need to free js_wrapper_obj, as it will be finalized by GC. */
|
||||
JS_ReportOutOfMemory(cx);
|
||||
js_wrapper_obj = NULL;
|
||||
goto done;
|
||||
}
|
||||
|
||||
static void
|
||||
remove_java_obj_reflection_from_hashtable(jobject java_obj, JNIEnv *jEnv)
|
||||
{
|
||||
JSJHashNumber hash_code;
|
||||
JSJHashEntry *he, **hep;
|
||||
|
||||
hash_code = jsj_HashJavaObject((void*)java_obj, (void*)jEnv);
|
||||
|
||||
#ifdef JS_THREADSAFE
|
||||
PR_EnterMonitor(java_obj_reflections_monitor);
|
||||
#endif
|
||||
|
||||
hep = JSJ_HashTableRawLookup(java_obj_reflections, hash_code,
|
||||
java_obj, (void*)jEnv);
|
||||
he = *hep;
|
||||
|
||||
PR_ASSERT(he);
|
||||
if (he)
|
||||
JSJ_HashTableRawRemove(java_obj_reflections, hep, he, (void*)jEnv);
|
||||
|
||||
#ifdef JS_THREADSAFE
|
||||
PR_ExitMonitor(java_obj_reflections_monitor);
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
JavaObject_finalize(JSContext *cx, JSObject *obj)
|
||||
{
|
||||
JavaObjectWrapper *java_wrapper;
|
||||
jobject java_obj;
|
||||
JNIEnv *jEnv;
|
||||
|
||||
jsj_MapJSContextToJSJThread(cx, &jEnv);
|
||||
if (!jEnv)
|
||||
return;
|
||||
|
||||
java_wrapper = JS_GetPrivate(cx, obj);
|
||||
if (!java_wrapper)
|
||||
return;
|
||||
java_obj = java_wrapper->java_obj;
|
||||
|
||||
if (java_obj) {
|
||||
remove_java_obj_reflection_from_hashtable(java_obj, jEnv);
|
||||
(*jEnv)->DeleteGlobalRef(jEnv, java_obj);
|
||||
}
|
||||
jsj_ReleaseJavaClassDescriptor(cx, jEnv, java_wrapper->class_descriptor);
|
||||
JS_free(cx, java_wrapper);
|
||||
}
|
||||
|
||||
/* Trivial helper for jsj_DiscardJavaObjReflections(), below */
|
||||
static PRIntn
|
||||
enumerate_remove_java_obj(JSJHashEntry *he, PRIntn i, void *arg)
|
||||
{
|
||||
JNIEnv *jEnv = (JNIEnv*)arg;
|
||||
jobject java_obj;
|
||||
JavaObjectWrapper *java_wrapper;
|
||||
JSObject *java_wrapper_obj;
|
||||
|
||||
java_wrapper_obj = (JSObject *)he->value;
|
||||
java_wrapper = JS_GetPrivate(NULL, java_wrapper_obj);
|
||||
java_obj = java_wrapper->java_obj;
|
||||
(*jEnv)->DeleteGlobalRef(jEnv, java_obj);
|
||||
java_wrapper->java_obj = NULL;
|
||||
return HT_ENUMERATE_REMOVE;
|
||||
}
|
||||
|
||||
/* This shutdown routine discards all JNI references to Java objects
|
||||
that have been reflected into JS, even if there are still references
|
||||
to them from JS. */
|
||||
void
|
||||
jsj_DiscardJavaObjReflections(JNIEnv *jEnv)
|
||||
{
|
||||
if (java_obj_reflections) {
|
||||
JSJ_HashTableEnumerateEntries(java_obj_reflections,
|
||||
enumerate_remove_java_obj,
|
||||
(void*)jEnv);
|
||||
JSJ_HashTableDestroy(java_obj_reflections);
|
||||
java_obj_reflections = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
PR_CALLBACK JSBool
|
||||
JavaObject_convert(JSContext *cx, JSObject *obj, JSType type, jsval *vp)
|
||||
{
|
||||
JavaObjectWrapper *java_wrapper;
|
||||
JavaClassDescriptor *class_descriptor;
|
||||
jobject java_obj;
|
||||
JNIEnv *jEnv;
|
||||
|
||||
/* Get the Java per-thread environment pointer for this JSContext */
|
||||
jsj_MapJSContextToJSJThread(cx, &jEnv);
|
||||
if (!jEnv)
|
||||
return JS_FALSE;
|
||||
|
||||
java_wrapper = JS_GetPrivate(cx, obj);
|
||||
if (!java_wrapper) {
|
||||
if (type == JSTYPE_OBJECT) {
|
||||
*vp = OBJECT_TO_JSVAL(obj);
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
JS_ReportError(cx, "illegal operation on JavaObject prototype object");
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
java_obj = java_wrapper->java_obj;
|
||||
class_descriptor = java_wrapper->class_descriptor;
|
||||
|
||||
switch (type) {
|
||||
case JSTYPE_OBJECT:
|
||||
*vp = OBJECT_TO_JSVAL(obj);
|
||||
return JS_TRUE;
|
||||
|
||||
case JSTYPE_FUNCTION:
|
||||
JS_ReportError(cx, "can't convert Java object to function");
|
||||
return JS_FALSE;
|
||||
|
||||
case JSTYPE_VOID:
|
||||
case JSTYPE_STRING:
|
||||
/* Either extract a C-string from the java.lang.String object
|
||||
or call the Java toString() method */
|
||||
return jsj_ConvertJavaObjectToJSString(cx, jEnv, class_descriptor, java_obj, vp);
|
||||
|
||||
case JSTYPE_NUMBER:
|
||||
/* Call Java doubleValue() method, if applicable */
|
||||
return jsj_ConvertJavaObjectToJSNumber(cx, jEnv, class_descriptor, java_obj, vp);
|
||||
|
||||
case JSTYPE_BOOLEAN:
|
||||
/* Call booleanValue() method, if applicable */
|
||||
return jsj_ConvertJavaObjectToJSBoolean(cx, jEnv, class_descriptor, java_obj, vp);
|
||||
|
||||
default:
|
||||
PR_ASSERT(0);
|
||||
return JS_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
static JSBool
|
||||
lookup_member_by_id(JSContext *cx, JNIEnv *jEnv, JSObject *obj,
|
||||
JavaObjectWrapper **java_wrapperp,
|
||||
jsid id,
|
||||
JavaMemberDescriptor **member_descriptorp)
|
||||
{
|
||||
jsval idval;
|
||||
JavaObjectWrapper *java_wrapper;
|
||||
JavaMemberDescriptor *member_descriptor;
|
||||
const char *member_name, *property_name;
|
||||
JavaClassDescriptor *class_descriptor;
|
||||
|
||||
java_wrapper = JS_GetPrivate(cx, obj);
|
||||
if (!java_wrapper) {
|
||||
if (JS_IdToValue(cx, id, &idval) && JSVAL_IS_STRING(idval) &&
|
||||
(property_name = JS_GetStringBytes(JSVAL_TO_STRING(idval))) != NULL) {
|
||||
if (!strcmp(property_name, "constructor")) {
|
||||
*java_wrapperp = NULL;
|
||||
*member_descriptorp = NULL;
|
||||
return JS_TRUE;
|
||||
}
|
||||
}
|
||||
JS_ReportError(cx, "illegal operation on JavaObject prototype object");
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
class_descriptor = java_wrapper->class_descriptor;
|
||||
PR_ASSERT(class_descriptor->type == JAVA_SIGNATURE_CLASS ||
|
||||
class_descriptor->type == JAVA_SIGNATURE_ARRAY);
|
||||
|
||||
member_descriptor = jsj_LookupJavaMemberDescriptorById(cx, jEnv, class_descriptor, id);
|
||||
if (!member_descriptor) {
|
||||
JS_IdToValue(cx, id, &idval);
|
||||
if (!JSVAL_IS_STRING(idval)) {
|
||||
JS_ReportError(cx, "invalid JavaObject property expression. "
|
||||
"(methods and field properties of a JavaObject object can only be strings)");
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
member_name = JS_GetStringBytes(JSVAL_TO_STRING(idval));
|
||||
|
||||
JS_ReportError(cx, "Java class %s has no public instance field or "
|
||||
"method named \"%s\"",
|
||||
class_descriptor->name, member_name);
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
/* Success. Handle the multiple return values */
|
||||
if (java_wrapperp)
|
||||
*java_wrapperp = java_wrapper;
|
||||
if (member_descriptorp)
|
||||
*member_descriptorp = member_descriptor;
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
PR_CALLBACK JSBool
|
||||
JavaObject_getPropertyById(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
|
||||
{
|
||||
jobject java_obj;
|
||||
JavaMemberDescriptor *member_descriptor;
|
||||
JavaObjectWrapper *java_wrapper;
|
||||
JNIEnv *jEnv;
|
||||
JSObject *funobj;
|
||||
jsval field_val, method_val;
|
||||
JSBool success;
|
||||
|
||||
/* printf("In JavaObject_getProperty\n"); */
|
||||
|
||||
/* Get the Java per-thread environment pointer for this JSContext */
|
||||
jsj_MapJSContextToJSJThread(cx, &jEnv);
|
||||
if (!jEnv)
|
||||
return JS_FALSE;
|
||||
|
||||
if (!lookup_member_by_id(cx, jEnv, obj, &java_wrapper, id, &member_descriptor))
|
||||
return JS_FALSE;
|
||||
|
||||
/* Handle access to "constructor" property of prototype object with
|
||||
silent failure. */
|
||||
if (!member_descriptor) {
|
||||
*vp = JSVAL_VOID;
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
java_obj = java_wrapper->java_obj;
|
||||
field_val = method_val = JSVAL_VOID;
|
||||
|
||||
/* If a field member, get the value of the field */
|
||||
if (member_descriptor->field) {
|
||||
success = jsj_GetJavaFieldValue(cx, jEnv, member_descriptor->field, java_obj, &field_val);
|
||||
if (!success)
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
/* If a method member, build a wrapper around the Java method */
|
||||
if (member_descriptor->methods) {
|
||||
/* Create a function object with this JavaObject as its parent, so that
|
||||
JSFUN_BOUND_METHOD binds it as the default 'this' for the function. */
|
||||
funobj = JS_CloneFunctionObject(cx, member_descriptor->invoke_func_obj, obj);
|
||||
if (!funobj)
|
||||
return JS_FALSE;
|
||||
method_val = OBJECT_TO_JSVAL(funobj);
|
||||
}
|
||||
|
||||
#if TEST_JAVAMEMBER
|
||||
/* Always create a JavaMember object, even though it's inefficient */
|
||||
obj = jsj_CreateJavaMember(cx, method_val, field_val);
|
||||
if (!obj)
|
||||
return JS_FALSE;
|
||||
*vp = OBJECT_TO_JSVAL(obj);
|
||||
#else /* !TEST_JAVAMEMBER */
|
||||
|
||||
if (member_descriptor->field) {
|
||||
if (!member_descriptor->methods) {
|
||||
/* Return value of Java field */
|
||||
*vp = field_val;
|
||||
} else {
|
||||
/* Handle special case of access to a property that could refer
|
||||
to either a Java field or a method that share the same name.
|
||||
In Java, such ambiguity is not possible because the compiler
|
||||
can statically determine which is being accessed. */
|
||||
obj = jsj_CreateJavaMember(cx, method_val, field_val);
|
||||
if (!obj)
|
||||
return JS_FALSE;
|
||||
*vp = OBJECT_TO_JSVAL(obj);
|
||||
}
|
||||
|
||||
} else {
|
||||
/* Return wrapper around Java method */
|
||||
*vp = method_val;
|
||||
}
|
||||
|
||||
#endif /* !TEST_JAVAMEMBER */
|
||||
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
PR_STATIC_CALLBACK(JSBool)
|
||||
JavaObject_setPropertyById(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
|
||||
{
|
||||
jobject java_obj;
|
||||
const char *member_name;
|
||||
JavaObjectWrapper *java_wrapper;
|
||||
JavaClassDescriptor *class_descriptor;
|
||||
JavaMemberDescriptor *member_descriptor;
|
||||
jsval idval;
|
||||
JNIEnv *jEnv;
|
||||
|
||||
/* printf("In JavaObject_setProperty\n"); */
|
||||
|
||||
/* Get the Java per-thread environment pointer for this JSContext */
|
||||
jsj_MapJSContextToJSJThread(cx, &jEnv);
|
||||
if (!jEnv)
|
||||
return JS_FALSE;
|
||||
|
||||
if (!lookup_member_by_id(cx, jEnv, obj, &java_wrapper, id, &member_descriptor))
|
||||
return JS_FALSE;
|
||||
|
||||
/* Check for the case where there is a method with the give name, but no field
|
||||
with that name */
|
||||
if (!member_descriptor->field)
|
||||
goto no_such_field;
|
||||
|
||||
/* Silently fail if field value is final (immutable), as required by ECMA spec */
|
||||
if (member_descriptor->field->modifiers & ACC_FINAL)
|
||||
return JS_TRUE;
|
||||
|
||||
java_obj = java_wrapper->java_obj;
|
||||
return jsj_SetJavaFieldValue(cx, jEnv, member_descriptor->field, java_obj, *vp);
|
||||
|
||||
no_such_field:
|
||||
JS_IdToValue(cx, id, &idval);
|
||||
member_name = JS_GetStringBytes(JSVAL_TO_STRING(idval));
|
||||
class_descriptor = java_wrapper->class_descriptor;
|
||||
JS_ReportError(cx, "No instance field named \"%s\" in Java class %s",
|
||||
member_name, class_descriptor->name);
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
static JSBool
|
||||
JavaObject_lookupProperty(JSContext *cx, JSObject *obj, jsid id,
|
||||
JSObject **objp, JSProperty **propp
|
||||
#if defined JS_THREADSAFE && defined DEBUG
|
||||
, const char *file, uintN line
|
||||
#endif
|
||||
)
|
||||
{
|
||||
JNIEnv *jEnv;
|
||||
JSErrorReporter old_reporter;
|
||||
|
||||
/* printf("In JavaObject_lookupProperty()\n"); */
|
||||
|
||||
/* Get the Java per-thread environment pointer for this JSContext */
|
||||
jsj_MapJSContextToJSJThread(cx, &jEnv);
|
||||
if (!jEnv)
|
||||
return JS_FALSE;
|
||||
|
||||
old_reporter = JS_SetErrorReporter(cx, NULL);
|
||||
if (lookup_member_by_id(cx, jEnv, obj, NULL, id, NULL)) {
|
||||
*objp = obj;
|
||||
*propp = (JSProperty*)1;
|
||||
} else {
|
||||
*objp = NULL;
|
||||
*propp = NULL;
|
||||
}
|
||||
|
||||
JS_SetErrorReporter(cx, old_reporter);
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
static JSBool
|
||||
JavaObject_defineProperty(JSContext *cx, JSObject *obj, jsid id, jsval value,
|
||||
JSPropertyOp getter, JSPropertyOp setter,
|
||||
uintN attrs, JSProperty **propp)
|
||||
{
|
||||
JS_ReportError(cx, "Cannot define a new property in a JavaObject");
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
static JSBool
|
||||
JavaObject_getAttributes(JSContext *cx, JSObject *obj, jsid id,
|
||||
JSProperty *prop, uintN *attrsp)
|
||||
{
|
||||
/* We don't maintain JS property attributes for Java class members */
|
||||
*attrsp = JSPROP_PERMANENT|JSPROP_ENUMERATE;
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
static JSBool
|
||||
JavaObject_setAttributes(JSContext *cx, JSObject *obj, jsid id,
|
||||
JSProperty *prop, uintN *attrsp)
|
||||
{
|
||||
/* We don't maintain JS property attributes for Java class members */
|
||||
if (*attrsp != (JSPROP_PERMANENT|JSPROP_ENUMERATE)) {
|
||||
PR_ASSERT(0);
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
/* Silently ignore all setAttribute attempts */
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
static JSBool
|
||||
JavaObject_deleteProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
|
||||
{
|
||||
JSVersion version = JS_GetVersion(cx);
|
||||
|
||||
*vp = JSVAL_FALSE;
|
||||
|
||||
if (!JSVERSION_IS_ECMA(version)) {
|
||||
JS_ReportError(cx, "Properties of JavaObject objects may not be deleted");
|
||||
return JS_FALSE;
|
||||
} else {
|
||||
/* Attempts to delete permanent properties are silently ignored
|
||||
by ECMAScript. */
|
||||
return JS_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
static JSBool
|
||||
JavaObject_defaultValue(JSContext *cx, JSObject *obj, JSType type, jsval *vp)
|
||||
{
|
||||
/* printf("In JavaObject_defaultValue()\n"); */
|
||||
return JavaObject_convert(cx, obj, type, vp);
|
||||
}
|
||||
|
||||
static JSBool
|
||||
JavaObject_newEnumerate(JSContext *cx, JSObject *obj, JSIterateOp enum_op,
|
||||
jsval *statep, jsid *idp)
|
||||
{
|
||||
JavaObjectWrapper *java_wrapper;
|
||||
JavaMemberDescriptor *member_descriptor;
|
||||
JavaClassDescriptor *class_descriptor;
|
||||
JNIEnv *jEnv;
|
||||
|
||||
java_wrapper = JS_GetPrivate(cx, obj);
|
||||
/* Check for prototype object */
|
||||
if (!java_wrapper) {
|
||||
*statep = JSVAL_NULL;
|
||||
if (idp)
|
||||
*idp = INT_TO_JSVAL(0);
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
class_descriptor = java_wrapper->class_descriptor;
|
||||
|
||||
switch(enum_op) {
|
||||
case JSENUMERATE_INIT:
|
||||
|
||||
/* Get the Java per-thread environment pointer for this JSContext */
|
||||
jsj_MapJSContextToJSJThread(cx, &jEnv);
|
||||
if (!jEnv)
|
||||
return JS_FALSE;
|
||||
|
||||
member_descriptor = jsj_GetClassInstanceMembers(cx, jEnv, class_descriptor);
|
||||
*statep = PRIVATE_TO_JSVAL(member_descriptor);
|
||||
if (idp)
|
||||
*idp = INT_TO_JSVAL(class_descriptor->num_instance_members);
|
||||
return JS_TRUE;
|
||||
|
||||
case JSENUMERATE_NEXT:
|
||||
member_descriptor = JSVAL_TO_PRIVATE(*statep);
|
||||
if (member_descriptor) {
|
||||
*idp = member_descriptor->id;
|
||||
*statep = PRIVATE_TO_JSVAL(member_descriptor->next);
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
/* Fall through ... */
|
||||
|
||||
case JSENUMERATE_DESTROY:
|
||||
*statep = JSVAL_NULL;
|
||||
return JS_TRUE;
|
||||
|
||||
default:
|
||||
PR_ASSERT(0);
|
||||
return JS_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
static JSBool
|
||||
JavaObject_checkAccess(JSContext *cx, JSObject *obj, jsid id,
|
||||
JSAccessMode mode, jsval *vp, uintN *attrsp)
|
||||
{
|
||||
switch (mode) {
|
||||
case JSACC_WATCH:
|
||||
JS_ReportError(cx, "Cannot place watchpoints on JavaObject object properties");
|
||||
return JS_FALSE;
|
||||
|
||||
case JSACC_IMPORT:
|
||||
JS_ReportError(cx, "Cannot export a JavaObject object's properties");
|
||||
return JS_FALSE;
|
||||
|
||||
default:
|
||||
return JS_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
JSObjectOps JavaObject_ops = {
|
||||
/* Mandatory non-null function pointer members. */
|
||||
NULL, /* newObjectMap */
|
||||
NULL, /* destroyObjectMap */
|
||||
JavaObject_lookupProperty,
|
||||
JavaObject_defineProperty,
|
||||
JavaObject_getPropertyById, /* getProperty */
|
||||
JavaObject_setPropertyById, /* setProperty */
|
||||
JavaObject_getAttributes,
|
||||
JavaObject_setAttributes,
|
||||
JavaObject_deleteProperty,
|
||||
JavaObject_defaultValue,
|
||||
JavaObject_newEnumerate,
|
||||
JavaObject_checkAccess,
|
||||
|
||||
/* Optionally non-null members start here. */
|
||||
NULL, /* thisObject */
|
||||
NULL, /* dropProperty */
|
||||
NULL, /* call */
|
||||
NULL, /* construct */
|
||||
NULL, /* xdrObject */
|
||||
NULL, /* hasInstance */
|
||||
};
|
||||
|
||||
static JSObjectOps *
|
||||
JavaObject_getObjectOps(JSContext *cx, JSClass *clazz)
|
||||
{
|
||||
return &JavaObject_ops;
|
||||
}
|
||||
|
||||
JSClass JavaObject_class = {
|
||||
"JavaObject", JSCLASS_HAS_PRIVATE,
|
||||
NULL, NULL, NULL, NULL,
|
||||
NULL, NULL, JavaObject_convert, JavaObject_finalize,
|
||||
JavaObject_getObjectOps,
|
||||
};
|
||||
|
||||
extern PR_IMPORT_DATA(JSObjectOps) js_ObjectOps;
|
||||
|
||||
|
||||
JSBool
|
||||
jsj_init_JavaObject(JSContext *cx, JSObject *global_obj)
|
||||
{
|
||||
JavaObject_ops.newObjectMap = js_ObjectOps.newObjectMap;
|
||||
JavaObject_ops.destroyObjectMap = js_ObjectOps.destroyObjectMap;
|
||||
|
||||
if (!JS_InitClass(cx, global_obj,
|
||||
0, &JavaObject_class, 0, 0,
|
||||
0, 0,
|
||||
0, 0))
|
||||
return JS_FALSE;
|
||||
|
||||
return init_java_obj_reflections_table();
|
||||
}
|
||||
500
mozilla/js/src/liveconnect/jsj_JavaPackage.c
Normal file
@@ -0,0 +1,500 @@
|
||||
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.0 (the "License"); you may not use this file except in
|
||||
* compliance with the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
* the License for the specific language governing rights and limitations
|
||||
* under the License.
|
||||
*
|
||||
* The Original Code is Mozilla Communicator client code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are Copyright (C) 1998
|
||||
* Netscape Communications Corporation. All Rights Reserved.
|
||||
*/
|
||||
|
||||
/* This file is part of the Java-vendor-neutral implementation of LiveConnect
|
||||
*
|
||||
* It contains the native code implementation of the JavaPackage class.
|
||||
*
|
||||
* A JavaPackage is JavaScript's representation of a Java package. The
|
||||
* JavaPackage object contains only a string, which is the path to the package,
|
||||
* e.g. "java/lang". The JS properties of a JavaPackage are either nested packages
|
||||
* or a JavaClass object, which represents the path to a Java class.
|
||||
*
|
||||
* Note that there is no equivalent to a JavaPackage object in Java. Example:
|
||||
* Although there are instances of java.lang.String and there are static methods
|
||||
* of java.lang.String that can be invoked, there's no such thing as a java.lang
|
||||
* object in Java that exists at run time.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "jsj_private.h" /* LiveConnect internals */
|
||||
#include "jsjava.h"
|
||||
|
||||
|
||||
JSClass JavaPackage_class; /* Forward declaration */
|
||||
|
||||
/*
|
||||
* The native part of a JavaPackage object. It gets stored in the object's
|
||||
* private slot.
|
||||
*/
|
||||
typedef struct {
|
||||
const char * path; /* e.g. "java/lang" or NULL if top level package */
|
||||
int flags; /* e.g. PKG_SYSTEM, PKG_CLASS */
|
||||
} JavaPackage_Private;
|
||||
|
||||
static JSObject *
|
||||
define_JavaPackage(JSContext *cx, JSObject *parent_obj,
|
||||
const char *obj_name, const char *path, int flags)
|
||||
{
|
||||
JSObject *package_obj;
|
||||
JavaPackage_Private *package;
|
||||
|
||||
package_obj = JS_DefineObject(cx, parent_obj, obj_name, &JavaPackage_class, 0,
|
||||
JSPROP_PERMANENT | JSPROP_READONLY);
|
||||
if (!package_obj)
|
||||
return NULL;
|
||||
|
||||
/* Attach private, native data to the JS object */
|
||||
package = (JavaPackage_Private *)JS_malloc(cx, sizeof(JavaPackage_Private));
|
||||
JS_SetPrivate(cx, package_obj, (void *)package);
|
||||
if (path)
|
||||
package->path = JS_strdup(cx, path);
|
||||
else
|
||||
package->path = "";
|
||||
|
||||
package->flags = flags;
|
||||
|
||||
/* Check for OOM */
|
||||
if (!package->path) {
|
||||
JS_DeleteProperty(cx, parent_obj, obj_name);
|
||||
JS_free(cx, package);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return package_obj;
|
||||
}
|
||||
|
||||
/* JavaPackage uses standard JS getProperty */
|
||||
|
||||
/*
|
||||
* Don't allow user-defined properties to be set on Java package objects, e.g.
|
||||
* it is illegal to write "java.lang.myProperty = 4". We probably could relax
|
||||
* this restriction, but it's potentially confusing and not clearly useful.
|
||||
*/
|
||||
static JSBool
|
||||
JavaPackage_setProperty(JSContext *cx, JSObject *obj, jsval slot, jsval *vp)
|
||||
{
|
||||
JavaPackage_Private *package = JS_GetPrivate(cx, obj);
|
||||
if (!package) {
|
||||
JS_ReportError(cx, "illegal attempt to add property to "
|
||||
"JavaPackage prototype object");
|
||||
return JS_FALSE;
|
||||
}
|
||||
JS_ReportError(cx, "You may not add properties to a JavaPackage object");
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
static JSBool quiet_resolve_failure;
|
||||
|
||||
/*
|
||||
* Resolve a component name to be either the name of a class or a package.
|
||||
*/
|
||||
static JSBool
|
||||
JavaPackage_resolve(JSContext *cx, JSObject *obj, jsval id)
|
||||
{
|
||||
JavaPackage_Private *package;
|
||||
JSBool ok = JS_TRUE;
|
||||
jclass jclazz;
|
||||
char *subPath, *newPath;
|
||||
const char *path;
|
||||
JNIEnv *jEnv;
|
||||
|
||||
package = (JavaPackage_Private *)JS_GetPrivate(cx, obj);
|
||||
if (!package)
|
||||
return JS_TRUE;
|
||||
|
||||
if (!JSVAL_IS_STRING(id))
|
||||
return JS_TRUE;
|
||||
subPath = JS_GetStringBytes(JSVAL_TO_STRING(id));
|
||||
|
||||
/*
|
||||
* There will be an attempt to invoke the toString() method when producing
|
||||
* the string representation of a JavaPackage. When this occurs, avoid
|
||||
* creating a bogus toString package. (This means that no one can ever
|
||||
* create a package with the simple name "toString", but we'll live with
|
||||
* that limitation.)
|
||||
*/
|
||||
if (!strcmp(subPath, "toString"))
|
||||
return JS_FALSE;
|
||||
|
||||
path = package->path;
|
||||
newPath = PR_smprintf("%s%s%s", path, (path[0] ? "/" : ""), subPath);
|
||||
if (!newPath) {
|
||||
JS_ReportOutOfMemory(cx);
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
jsj_MapJSContextToJSJThread(cx, &jEnv);
|
||||
if (!jEnv)
|
||||
return JS_FALSE;
|
||||
|
||||
/*
|
||||
Unfortunately, Java provides no way to find out whether a particular
|
||||
name is a package or not. The only way to tell is to try to load the
|
||||
name as a class file and, if that fails, assume it's a package. This
|
||||
makes things work as expected for the most part, but it has three
|
||||
noticeable problems that keep coming up:
|
||||
|
||||
- You can refer to a package like java.lang.i.buried.paul without
|
||||
generating a complaint. Of course, you'll never be able to refer to
|
||||
any classes through it.
|
||||
|
||||
- An annoying consequence of the above is that misspelling a class name
|
||||
results in a cryptic error about packages.
|
||||
|
||||
- In a browser context, i.e. where applets are involved, figuring out
|
||||
whether something is a class may require looking for it over the net
|
||||
using the current classloader. This means that the first time you
|
||||
refer to java.lang.System in a js context, there will be an attempt
|
||||
to search for [[DOCBASE]]/java.class on the server.
|
||||
|
||||
A solution is to explicitly tell jsjava the names of all the (local)
|
||||
packages on the CLASSPATH. (Not implemented yet.)
|
||||
|
||||
*/
|
||||
jclazz = (*jEnv)->FindClass(jEnv, newPath);
|
||||
if (jclazz) {
|
||||
JSObject *newClass;
|
||||
|
||||
newClass = jsj_define_JavaClass(cx, jEnv, obj, subPath, jclazz);
|
||||
if (!newClass) {
|
||||
ok = JS_FALSE;
|
||||
goto out;
|
||||
}
|
||||
} else {
|
||||
|
||||
/* We assume that any failed attempt to load a class is because it
|
||||
doesn't exist. If we wanted to do a better job, we would check
|
||||
the exception type and make sure that it's NoClassDefFoundError */
|
||||
(*jEnv)->ExceptionClear(jEnv);
|
||||
|
||||
/* beard: this has to be done here, so built-in classes will be defined. */
|
||||
/* Painful hack for pre_define_java_packages() */
|
||||
if (quiet_resolve_failure) {
|
||||
ok = JS_FALSE;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* If there's no class of the given name, then we must be referring to
|
||||
* a package. However, don't allow bogus sub-packages of pre-defined
|
||||
* system packages to be created.
|
||||
*/
|
||||
if (JS_InstanceOf(cx, obj, &JavaPackage_class, NULL)) {
|
||||
JavaPackage_Private *package;
|
||||
|
||||
package = JS_GetPrivate(cx, obj);
|
||||
if (package->flags & PKG_SYSTEM) {
|
||||
char *msg, *cp;
|
||||
|
||||
msg = PR_smprintf("No Java system package with name \"%s\" was identified "
|
||||
"and no Java class with that name exists either",
|
||||
newPath);
|
||||
|
||||
/* Check for OOM */
|
||||
if (msg) {
|
||||
/* Convert package of form "java/lang" to "java.lang" */
|
||||
for (cp = msg; *cp != '\0'; cp++)
|
||||
if (*cp == '/')
|
||||
*cp = '.';
|
||||
JS_ReportError(cx, msg);
|
||||
free((char*)msg);
|
||||
}
|
||||
|
||||
ok = JS_FALSE;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
if (!define_JavaPackage(cx, obj, subPath, newPath, 0)) {
|
||||
ok = JS_FALSE;
|
||||
goto out;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
/* printf("JavaPackage \'%s\' created\n", newPath); */
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
out:
|
||||
free(newPath);
|
||||
return ok;
|
||||
}
|
||||
|
||||
static JSBool
|
||||
JavaPackage_convert(JSContext *cx, JSObject *obj, JSType type, jsval *vp)
|
||||
{
|
||||
JSString *str;
|
||||
char *name, *cp;
|
||||
|
||||
JavaPackage_Private *package = JS_GetPrivate(cx, obj);
|
||||
if (!package) {
|
||||
fprintf(stderr, "JavaPackage_resolve: no private data!\n");
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
|
||||
/* Pretty-printing of JavaPackage */
|
||||
case JSTYPE_VOID: /* Default value */
|
||||
case JSTYPE_NUMBER:
|
||||
case JSTYPE_STRING:
|
||||
/* Convert '/' to '.' so that it looks like Java language syntax. */
|
||||
if (!package->path)
|
||||
break;
|
||||
name = PR_smprintf("[JavaPackage %s]", package->path);
|
||||
if (!name) {
|
||||
JS_ReportOutOfMemory(cx);
|
||||
return JS_FALSE;
|
||||
}
|
||||
for (cp = name; *cp != '\0'; cp++)
|
||||
if (*cp == '/')
|
||||
*cp = '.';
|
||||
str = JS_NewString(cx, name, strlen(name));
|
||||
if (!str) {
|
||||
free(name);
|
||||
/* It's not necessary to call JS_ReportOutOfMemory(), as
|
||||
JS_NewString() will do so on failure. */
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
*vp = STRING_TO_JSVAL(str);
|
||||
break;
|
||||
|
||||
case JSTYPE_OBJECT:
|
||||
*vp = OBJECT_TO_JSVAL(obj);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Free the private native data associated with the JavaPackage object.
|
||||
*/
|
||||
static void
|
||||
JavaPackage_finalize(JSContext *cx, JSObject *obj)
|
||||
{
|
||||
JavaPackage_Private *package = JS_GetPrivate(cx, obj);
|
||||
if (!package)
|
||||
return;
|
||||
|
||||
if (package->path)
|
||||
JS_free(cx, (char *)package->path);
|
||||
JS_free(cx, package);
|
||||
}
|
||||
|
||||
/*
|
||||
* The definition of the JavaPackage class
|
||||
*/
|
||||
JSClass JavaPackage_class = {
|
||||
"JavaPackage", JSCLASS_HAS_PRIVATE,
|
||||
JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JavaPackage_setProperty,
|
||||
JS_EnumerateStub, JavaPackage_resolve,
|
||||
JavaPackage_convert, JavaPackage_finalize
|
||||
};
|
||||
|
||||
JavaPackageDef
|
||||
standard_java_packages[] = {
|
||||
{"java", NULL, PKG_USER},
|
||||
{"java.applet", NULL, PKG_USER},
|
||||
{"java.awt", NULL, PKG_USER},
|
||||
{"java.awt.datatransfer",
|
||||
NULL, PKG_SYSTEM},
|
||||
{"java.awt.event", NULL, PKG_SYSTEM},
|
||||
{"java.awt.image", NULL, PKG_SYSTEM},
|
||||
{"java.awt.peer", NULL, PKG_SYSTEM},
|
||||
{"java.beans", NULL, PKG_USER},
|
||||
{"java.io", NULL, PKG_SYSTEM},
|
||||
{"java.lang", NULL, PKG_USER},
|
||||
{"java.lang.reflect", NULL, PKG_SYSTEM},
|
||||
{"java.math", NULL, PKG_SYSTEM},
|
||||
{"java.net", NULL, PKG_USER},
|
||||
{"java.rmi", NULL, PKG_USER},
|
||||
{"java.rmi.dgc", NULL, PKG_USER},
|
||||
{"java.rmi.user", NULL, PKG_USER},
|
||||
{"java.rmi.registry", NULL, PKG_USER},
|
||||
{"java.rmi.server", NULL, PKG_USER},
|
||||
{"java.security", NULL, PKG_USER},
|
||||
{"java.security.acl", NULL, PKG_SYSTEM},
|
||||
{"java.security.interfaces",
|
||||
NULL, PKG_SYSTEM},
|
||||
{"java.sql", NULL, PKG_USER},
|
||||
{"java.text", NULL, PKG_USER},
|
||||
{"java.text.resources", NULL, PKG_SYSTEM},
|
||||
{"java.util", NULL, PKG_USER},
|
||||
{"java.util.zip", NULL, PKG_SYSTEM},
|
||||
|
||||
{"netscape", NULL, PKG_USER},
|
||||
{"netscape.applet", NULL, PKG_SYSTEM},
|
||||
{"netscape.application",NULL, PKG_SYSTEM},
|
||||
{"netscape.debug", NULL, PKG_SYSTEM},
|
||||
{"netscape.javascript", NULL, PKG_SYSTEM},
|
||||
{"netscape.ldap", NULL, PKG_SYSTEM},
|
||||
{"netscape.misc", NULL, PKG_SYSTEM},
|
||||
{"netscape.net", NULL, PKG_SYSTEM},
|
||||
{"netscape.plugin", NULL, PKG_SYSTEM},
|
||||
{"netscape.util", NULL, PKG_SYSTEM},
|
||||
{"netscape.secfile", NULL, PKG_SYSTEM},
|
||||
{"netscape.security", NULL, PKG_SYSTEM},
|
||||
{"netscape.WAI", NULL, PKG_SYSTEM},
|
||||
|
||||
{"sun", NULL, PKG_USER},
|
||||
{"Packages", "", PKG_USER},
|
||||
|
||||
{NULL, NULL, 0}
|
||||
};
|
||||
|
||||
/*
|
||||
* Pre-define a hierarchy of JavaPackage objects.
|
||||
* Pre-defining a Java package at initialization time is not necessary, but
|
||||
* it will make package lookup faster and, more importantly, will avoid
|
||||
* unnecessary network accesses if classes are being loaded over the network.
|
||||
*/
|
||||
static JSBool
|
||||
pre_define_java_packages(JSContext *cx, JSObject *global_obj,
|
||||
JavaPackageDef *predefined_packages)
|
||||
{
|
||||
JSBool package_exists;
|
||||
JSObject *parent_obj;
|
||||
JavaPackageDef *package_def;
|
||||
char *simple_name, *cp, *package_name, *path;
|
||||
int flags;
|
||||
|
||||
if (!predefined_packages)
|
||||
return JS_TRUE;
|
||||
|
||||
/* Iterate over all pre-defined Java packages */
|
||||
for (package_def = predefined_packages; package_def->name; package_def++) {
|
||||
package_name = path = NULL;
|
||||
|
||||
parent_obj = global_obj;
|
||||
package_name = strdup(package_def->name);
|
||||
if (!package_name)
|
||||
goto out_of_memory;
|
||||
|
||||
/* Walk the chain of JavaPackage objects to get to the parent of the
|
||||
rightmost sub-package in the fully-qualified package name. */
|
||||
for (simple_name = strtok(package_name, "."); 1; simple_name = strtok(NULL, ".")) {
|
||||
jsval v;
|
||||
|
||||
if (!simple_name) {
|
||||
JS_ReportError(cx, "Package %s defined twice ?", package_name);
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Check to see if the sub-package already exists */
|
||||
quiet_resolve_failure = JS_TRUE;
|
||||
package_exists = JS_LookupProperty(cx, parent_obj, simple_name, &v) && JSVAL_IS_OBJECT(v);
|
||||
quiet_resolve_failure = JS_FALSE;
|
||||
|
||||
if (package_exists) {
|
||||
parent_obj = JSVAL_TO_OBJECT(v);
|
||||
continue;
|
||||
} else {
|
||||
/* New package objects should only be created at the terminal
|
||||
sub-package in a fully-qualified package-name */
|
||||
if (strtok(NULL, ".")) {
|
||||
JS_ReportError(cx, "Illegal predefined package definition for %s",
|
||||
package_def->name);
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (package_def->path) {
|
||||
path = strdup(package_def->path);
|
||||
if (!path)
|
||||
goto out_of_memory;
|
||||
} else {
|
||||
|
||||
/*
|
||||
* The default path is specified, so create it from the
|
||||
* fully-qualified package name.
|
||||
*/
|
||||
path = strdup(package_def->name);
|
||||
if (!path)
|
||||
goto out_of_memory;
|
||||
/* Transform package name, e.g. "java.lang" ==> "java/lang" */
|
||||
for (cp = path; *cp != '\0'; cp++) {
|
||||
if (*cp == '.')
|
||||
*cp = '/';
|
||||
}
|
||||
}
|
||||
flags = package_def->flags;
|
||||
parent_obj = define_JavaPackage(cx, parent_obj, simple_name, path, flags);
|
||||
if (!parent_obj)
|
||||
goto error;
|
||||
|
||||
free(path);
|
||||
break;
|
||||
}
|
||||
}
|
||||
free(package_name);
|
||||
}
|
||||
return JS_TRUE;
|
||||
|
||||
out_of_memory:
|
||||
JS_ReportOutOfMemory(cx);
|
||||
|
||||
error:
|
||||
JS_FREE_IF(cx, package_name);
|
||||
JS_FREE_IF(cx, path);
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
static JSBool
|
||||
JavaPackage_toString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
|
||||
jsval *rval)
|
||||
{
|
||||
if (!JS_InstanceOf(cx, obj, &JavaPackage_class, argv))
|
||||
return JS_FALSE;
|
||||
return JavaPackage_convert(cx, obj, JSTYPE_STRING, rval);
|
||||
}
|
||||
|
||||
static JSFunctionSpec JavaPackage_methods[] = {
|
||||
{"toString", JavaPackage_toString, 0},
|
||||
{0}
|
||||
};
|
||||
|
||||
/*
|
||||
* One-time initialization for the JavaPackage class. (This is not
|
||||
* run once per thread, rather it's run once for a given JSContext.)
|
||||
*/
|
||||
JSBool
|
||||
jsj_init_JavaPackage(JSContext *cx, JSObject *global_obj,
|
||||
JavaPackageDef *additional_predefined_packages) {
|
||||
|
||||
/* Define JavaPackage class */
|
||||
if (!JS_InitClass(cx, global_obj, 0, &JavaPackage_class,
|
||||
0, 0, 0, JavaPackage_methods, 0, 0))
|
||||
return JS_FALSE;
|
||||
|
||||
/* Add top-level packages, e.g. : java, netscape, sun */
|
||||
if (!pre_define_java_packages(cx, global_obj, standard_java_packages))
|
||||
return JS_FALSE;
|
||||
if (!pre_define_java_packages(cx, global_obj, additional_predefined_packages))
|
||||
return JS_FALSE;
|
||||
|
||||
return JS_TRUE;
|
||||
}
|
||||
180
mozilla/js/src/liveconnect/jsj_array.c
Normal file
@@ -0,0 +1,180 @@
|
||||
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.0 (the "License"); you may not use this file except in
|
||||
* compliance with the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
* the License for the specific language governing rights and limitations
|
||||
* under the License.
|
||||
*
|
||||
* The Original Code is Mozilla Communicator client code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are Copyright (C) 1998
|
||||
* Netscape Communications Corporation. All Rights Reserved.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is part of the Java-vendor-neutral implementation of LiveConnect
|
||||
*
|
||||
* It contains the code for reading and writing elements of a Java array.
|
||||
*/
|
||||
|
||||
#include "jsj_private.h" /* LiveConnect internals */
|
||||
|
||||
/*
|
||||
* Read the Java value at a given index into a Java array and convert it
|
||||
* to a JS value. The array_component_signature describes the type of
|
||||
* the resulting Java value, which can be a primitive type or an object type.
|
||||
* More specifically it can be an array type in the case of multidimensional
|
||||
* arrays.
|
||||
*/
|
||||
JSBool
|
||||
jsj_GetJavaArrayElement(JSContext *cx, JNIEnv *jEnv, jarray java_array, jsize index,
|
||||
JavaSignature *array_component_signature,
|
||||
jsval *vp)
|
||||
{
|
||||
jvalue java_value;
|
||||
JavaSignatureChar component_type;
|
||||
|
||||
#define GET_ELEMENT_FROM_PRIMITIVE_JAVA_ARRAY(Type,member) \
|
||||
(*jEnv)->Get##Type##ArrayRegion(jEnv, java_array, index, 1, \
|
||||
&java_value.member); \
|
||||
if ((*jEnv)->ExceptionOccurred(jEnv)) { \
|
||||
jsj_ReportJavaError(cx, jEnv, "Error reading element of " \
|
||||
"Java primitive array"); \
|
||||
return JS_FALSE; \
|
||||
}
|
||||
|
||||
component_type = array_component_signature->type;
|
||||
switch(component_type) {
|
||||
case JAVA_SIGNATURE_BYTE:
|
||||
GET_ELEMENT_FROM_PRIMITIVE_JAVA_ARRAY(Byte,b);
|
||||
break;
|
||||
|
||||
case JAVA_SIGNATURE_CHAR:
|
||||
GET_ELEMENT_FROM_PRIMITIVE_JAVA_ARRAY(Char,c);
|
||||
break;
|
||||
|
||||
case JAVA_SIGNATURE_SHORT:
|
||||
GET_ELEMENT_FROM_PRIMITIVE_JAVA_ARRAY(Short,s);
|
||||
break;
|
||||
|
||||
case JAVA_SIGNATURE_INT:
|
||||
GET_ELEMENT_FROM_PRIMITIVE_JAVA_ARRAY(Int,i);
|
||||
break;
|
||||
|
||||
case JAVA_SIGNATURE_BOOLEAN:
|
||||
GET_ELEMENT_FROM_PRIMITIVE_JAVA_ARRAY(Boolean,z);
|
||||
break;
|
||||
|
||||
case JAVA_SIGNATURE_LONG:
|
||||
GET_ELEMENT_FROM_PRIMITIVE_JAVA_ARRAY(Long,j);
|
||||
break;
|
||||
|
||||
case JAVA_SIGNATURE_FLOAT:
|
||||
GET_ELEMENT_FROM_PRIMITIVE_JAVA_ARRAY(Float,f);
|
||||
break;
|
||||
|
||||
case JAVA_SIGNATURE_DOUBLE:
|
||||
GET_ELEMENT_FROM_PRIMITIVE_JAVA_ARRAY(Double,d);
|
||||
break;
|
||||
|
||||
case JAVA_SIGNATURE_CLASS:
|
||||
case JAVA_SIGNATURE_ARRAY:
|
||||
java_value.l = (*jEnv)->GetObjectArrayElement(jEnv, java_array, index);
|
||||
if ((*jEnv)->ExceptionOccurred(jEnv)) {
|
||||
jsj_ReportJavaError(cx, jEnv, "Error reading Java object array");
|
||||
return JS_FALSE;
|
||||
}
|
||||
break;
|
||||
|
||||
#undef GET_ELEMENT_FROM_PRIMITIVE_JAVA_ARRAY
|
||||
default:
|
||||
PR_ASSERT(0); /* Unknown java type signature */
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
return jsj_ConvertJavaValueToJSValue(cx, jEnv, array_component_signature, &java_value, vp);
|
||||
}
|
||||
|
||||
JSBool
|
||||
jsj_SetJavaArrayElement(JSContext *cx, JNIEnv *jEnv, jarray java_array, jsize index,
|
||||
JavaSignature *array_component_signature,
|
||||
jsval js_val)
|
||||
{
|
||||
int dummy_cost;
|
||||
jvalue java_value;
|
||||
JavaSignatureChar component_type;
|
||||
JSBool is_local_ref;
|
||||
|
||||
if (!jsj_ConvertJSValueToJavaValue(cx, jEnv, js_val, array_component_signature,
|
||||
&dummy_cost, &java_value, &is_local_ref))
|
||||
return JS_FALSE;
|
||||
|
||||
#define SET_ELEMENT_FROM_PRIMITIVE_JAVA_ARRAY(Type,member) \
|
||||
(*jEnv)->Set##Type##ArrayRegion(jEnv, java_array, index, 1, \
|
||||
&java_value.member); \
|
||||
if ((*jEnv)->ExceptionOccurred(jEnv)) { \
|
||||
jsj_ReportJavaError(cx, jEnv, "Error assigning to element of " \
|
||||
"Java primitive array"); \
|
||||
return JS_FALSE; \
|
||||
}
|
||||
|
||||
component_type = array_component_signature->type;
|
||||
switch(component_type) {
|
||||
case JAVA_SIGNATURE_BYTE:
|
||||
SET_ELEMENT_FROM_PRIMITIVE_JAVA_ARRAY(Byte,b);
|
||||
break;
|
||||
|
||||
case JAVA_SIGNATURE_CHAR:
|
||||
SET_ELEMENT_FROM_PRIMITIVE_JAVA_ARRAY(Char,c);
|
||||
break;
|
||||
|
||||
case JAVA_SIGNATURE_SHORT:
|
||||
SET_ELEMENT_FROM_PRIMITIVE_JAVA_ARRAY(Short,s);
|
||||
break;
|
||||
|
||||
case JAVA_SIGNATURE_INT:
|
||||
SET_ELEMENT_FROM_PRIMITIVE_JAVA_ARRAY(Int,i);
|
||||
break;
|
||||
|
||||
case JAVA_SIGNATURE_BOOLEAN:
|
||||
SET_ELEMENT_FROM_PRIMITIVE_JAVA_ARRAY(Boolean,z);
|
||||
break;
|
||||
|
||||
case JAVA_SIGNATURE_LONG:
|
||||
SET_ELEMENT_FROM_PRIMITIVE_JAVA_ARRAY(Long,j);
|
||||
break;
|
||||
|
||||
case JAVA_SIGNATURE_FLOAT:
|
||||
SET_ELEMENT_FROM_PRIMITIVE_JAVA_ARRAY(Float,f);
|
||||
break;
|
||||
|
||||
case JAVA_SIGNATURE_DOUBLE:
|
||||
SET_ELEMENT_FROM_PRIMITIVE_JAVA_ARRAY(Double,d);
|
||||
break;
|
||||
|
||||
case JAVA_SIGNATURE_CLASS:
|
||||
case JAVA_SIGNATURE_ARRAY:
|
||||
(*jEnv)->SetObjectArrayElement(jEnv, java_array, index, java_value.l);
|
||||
if (is_local_ref) \
|
||||
(*jEnv)->DeleteLocalRef(jEnv, java_value.l);
|
||||
if ((*jEnv)->ExceptionOccurred(jEnv)) {
|
||||
jsj_ReportJavaError(cx, jEnv, "Error assigning to Java object array");
|
||||
return JS_FALSE;
|
||||
}
|
||||
break;
|
||||
|
||||
#undef SET_ELEMENT_FROM_PRIMITIVE_JAVA_ARRAY
|
||||
default:
|
||||
PR_ASSERT(0); /* Unknown java type signature */
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
605
mozilla/js/src/liveconnect/jsj_class.c
Normal file
@@ -0,0 +1,605 @@
|
||||
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.0 (the "License"); you may not use this file except in
|
||||
* compliance with the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
* the License for the specific language governing rights and limitations
|
||||
* under the License.
|
||||
*
|
||||
* The Original Code is Mozilla Communicator client code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are Copyright (C) 1998
|
||||
* Netscape Communications Corporation. All Rights Reserved.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is part of the Java-vendor-neutral implementation of LiveConnect
|
||||
*
|
||||
* It contains the code that constructs and manipulates JavaClassDescriptor
|
||||
* structs, which are the native wrappers for Java classes.
|
||||
* JavaClassDescriptors are used to describe the signatures of methods and
|
||||
* fields. There is a JavaClassDescriptor associated with the reflection of
|
||||
* each Java Object.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "jsj_private.h" /* LiveConnect internals */
|
||||
#include "jsj_hash.h" /* Hash tables */
|
||||
|
||||
/* A one-to-one mapping between all referenced java.lang.Class objects and
|
||||
their corresponding JavaClassDescriptor objects */
|
||||
static JSJHashTable *java_class_reflections;
|
||||
|
||||
/*
|
||||
* Given a JVM handle to a java.lang.Class object, malloc a C-string
|
||||
* containing the UTF8 encoding of the fully qualified name of the class.
|
||||
* It's the caller's responsibility to free the returned string.
|
||||
*
|
||||
* If an error occurs, NULL is returned and the error reporter called.
|
||||
*/
|
||||
const char *
|
||||
jsj_GetJavaClassName(JSContext *cx, JNIEnv *jEnv, jclass java_class)
|
||||
{
|
||||
jstring java_class_name_jstr;
|
||||
const char *java_class_name;
|
||||
|
||||
/* Get java.lang.String object containing class name */
|
||||
java_class_name_jstr =
|
||||
(*jEnv)->CallObjectMethod(jEnv, java_class, jlClass_getName);
|
||||
|
||||
|
||||
if (!java_class_name_jstr)
|
||||
goto error;
|
||||
|
||||
/* Convert to UTF8 encoding and copy */
|
||||
java_class_name = jsj_DupJavaStringUTF(cx, jEnv, java_class_name_jstr);
|
||||
if (!java_class_name)
|
||||
return NULL;
|
||||
|
||||
return java_class_name;
|
||||
|
||||
error:
|
||||
jsj_UnexpectedJavaError(cx, jEnv, "Can't get Java class name using"
|
||||
"java.lang.Class.getName()");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert in-place a string of the form "java.lang.String" into "java/lang/String".
|
||||
* Though the former style is conventionally used by Java programmers, the latter is
|
||||
* what the JNI functions require.
|
||||
*/
|
||||
void
|
||||
jsj_MakeJNIClassname(char * class_name)
|
||||
{
|
||||
char * c;
|
||||
for (c = class_name; *c; c++)
|
||||
if (*c == '.')
|
||||
*c = '/';
|
||||
}
|
||||
|
||||
/*
|
||||
* Classify an instance of java.lang.Class as either one of the primitive
|
||||
* types, e.g. int, char, etc., as an array type or as a non-array object type
|
||||
* (subclass of java.lang.Object) by returning the appropriate enum member.
|
||||
*
|
||||
*/
|
||||
static JavaSignatureChar
|
||||
get_signature_type(JSContext *cx, JavaClassDescriptor *class_descriptor)
|
||||
{
|
||||
JavaSignatureChar type;
|
||||
const char *java_class_name;
|
||||
|
||||
/* Get UTF8 encoding of class name */
|
||||
java_class_name = class_descriptor->name;
|
||||
PR_ASSERT(java_class_name);
|
||||
if (!java_class_name)
|
||||
return JAVA_SIGNATURE_UNKNOWN;
|
||||
|
||||
if (!strcmp(java_class_name, "byte"))
|
||||
type = JAVA_SIGNATURE_BYTE;
|
||||
else if (!strcmp(java_class_name, "char"))
|
||||
type = JAVA_SIGNATURE_CHAR;
|
||||
else if (!strcmp(java_class_name, "float"))
|
||||
type = JAVA_SIGNATURE_FLOAT;
|
||||
else if (!strcmp(java_class_name, "double"))
|
||||
type = JAVA_SIGNATURE_DOUBLE;
|
||||
else if (!strcmp(java_class_name, "int"))
|
||||
type = JAVA_SIGNATURE_INT;
|
||||
else if (!strcmp(java_class_name, "long"))
|
||||
type = JAVA_SIGNATURE_LONG;
|
||||
else if (!strcmp(java_class_name, "short"))
|
||||
type = JAVA_SIGNATURE_SHORT;
|
||||
else if (!strcmp(java_class_name, "boolean"))
|
||||
type = JAVA_SIGNATURE_BOOLEAN;
|
||||
else if (!strcmp(java_class_name, "void"))
|
||||
type = JAVA_SIGNATURE_VOID;
|
||||
else
|
||||
/* Well, I guess it's a Java class, then. */
|
||||
type = JAVA_SIGNATURE_CLASS;
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
static JSBool
|
||||
is_java_array_class(JNIEnv *jEnv, jclass java_class)
|
||||
{
|
||||
return (*jEnv)->CallBooleanMethod(jEnv, java_class, jlClass_isArray);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the class of a Java array's component type. This is not the same
|
||||
* as the array's element type. For example, the component type of an array
|
||||
* of type SomeType[][][] is SomeType[][], but its element type is SomeType.
|
||||
*
|
||||
* If an error occurs, NULL is returned and an error reported.
|
||||
*/
|
||||
static jclass
|
||||
get_java_array_component_class(JSContext *cx, JNIEnv *jEnv, jclass java_class)
|
||||
{
|
||||
jclass result;
|
||||
result = (*jEnv)->CallObjectMethod(jEnv, java_class, jlClass_getComponentType);
|
||||
if (!result) {
|
||||
jsj_UnexpectedJavaError(cx, jEnv,
|
||||
"Can't get Java array component class using "
|
||||
"java.lang.Class.getComponentType()");
|
||||
return NULL;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Given a Java class, fill in the signature structure that describes the class.
|
||||
* If an error occurs, JS_FALSE is returned and the error reporter called.
|
||||
*/
|
||||
static JSBool
|
||||
compute_java_class_signature(JSContext *cx, JNIEnv *jEnv, JavaSignature *signature)
|
||||
{
|
||||
jclass java_class = signature->java_class;
|
||||
|
||||
if (is_java_array_class(jEnv, java_class)) {
|
||||
jclass component_class;
|
||||
|
||||
signature->type = JAVA_SIGNATURE_ARRAY;
|
||||
|
||||
component_class = get_java_array_component_class(cx, jEnv, java_class);
|
||||
if (!component_class)
|
||||
return JS_FALSE;
|
||||
|
||||
signature->array_component_signature =
|
||||
jsj_GetJavaClassDescriptor(cx, jEnv, component_class);
|
||||
if (!signature->array_component_signature)
|
||||
return JS_FALSE;
|
||||
} else {
|
||||
signature->type = get_signature_type(cx, signature);
|
||||
}
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert a JavaSignature object into a string format as used by
|
||||
* the JNI functions, e.g. java.lang.Object ==> "Ljava/lang/Object;"
|
||||
* The caller is responsible for freeing the resulting string.
|
||||
*
|
||||
* If an error is encountered, NULL is returned and an error reported.
|
||||
*/
|
||||
const char *
|
||||
jsj_ConvertJavaSignatureToString(JSContext *cx, JavaSignature *signature)
|
||||
{
|
||||
char *sig;
|
||||
|
||||
if (signature->type == JAVA_SIGNATURE_CLASS) {
|
||||
/* A non-array object class */
|
||||
sig = PR_smprintf("L%s;", signature->name);
|
||||
if (sig)
|
||||
jsj_MakeJNIClassname(sig);
|
||||
|
||||
} else if (signature->type == JAVA_SIGNATURE_ARRAY) {
|
||||
/* An array class */
|
||||
const char *component_signature_string;
|
||||
|
||||
component_signature_string =
|
||||
jsj_ConvertJavaSignatureToString(cx, signature->array_component_signature);
|
||||
if (!component_signature_string)
|
||||
return NULL;
|
||||
sig = PR_smprintf("[%s", component_signature_string);
|
||||
JS_free(cx, (char*)component_signature_string);
|
||||
|
||||
} else {
|
||||
/* A primitive class */
|
||||
sig = PR_smprintf("%c", (char)signature->type);
|
||||
}
|
||||
|
||||
if (!sig) {
|
||||
JS_ReportOutOfMemory(cx);
|
||||
return NULL;
|
||||
}
|
||||
return sig;
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert a JavaSignature object into a human-readable string format as seen
|
||||
* in Java source files, e.g. "byte", or "int[][]" or "java.lang.String".
|
||||
* The caller is responsible for freeing the resulting string.
|
||||
*
|
||||
* If an error is encountered, NULL is returned and an error reported.
|
||||
*/
|
||||
const char *
|
||||
jsj_ConvertJavaSignatureToHRString(JSContext *cx,
|
||||
JavaSignature *signature)
|
||||
{
|
||||
char *sig;
|
||||
JavaSignature *acs;
|
||||
|
||||
if (signature->type == JAVA_SIGNATURE_ARRAY) {
|
||||
/* An array class */
|
||||
const char *component_signature_string;
|
||||
acs = signature->array_component_signature;
|
||||
component_signature_string =
|
||||
jsj_ConvertJavaSignatureToHRString(cx, acs);
|
||||
if (!component_signature_string)
|
||||
return NULL;
|
||||
sig = PR_smprintf("%s[]", component_signature_string);
|
||||
JS_free(cx, (char*)component_signature_string);
|
||||
|
||||
} else {
|
||||
/* A primitive class or a non-array object class */
|
||||
sig = JS_strdup(cx, signature->name);
|
||||
}
|
||||
|
||||
if (!sig) {
|
||||
JS_ReportOutOfMemory(cx);
|
||||
return NULL;
|
||||
}
|
||||
return sig;
|
||||
}
|
||||
|
||||
static void
|
||||
destroy_java_member_descriptor(JSContext *cx, JNIEnv *jEnv, JavaMemberDescriptor *member_descriptor)
|
||||
{
|
||||
JavaMethodSpec *method, *next_method;
|
||||
if (member_descriptor->field)
|
||||
jsj_DestroyFieldSpec(cx, jEnv, member_descriptor->field);
|
||||
|
||||
method = member_descriptor->methods;
|
||||
while (method) {
|
||||
next_method = method->next;
|
||||
jsj_DestroyMethodSpec(cx, jEnv, method);
|
||||
method = next_method;
|
||||
}
|
||||
|
||||
if (member_descriptor->invoke_func_obj)
|
||||
JS_RemoveRoot(cx, &member_descriptor->invoke_func_obj);
|
||||
}
|
||||
|
||||
static void
|
||||
destroy_class_member_descriptors(JSContext *cx, JNIEnv *jEnv, JavaMemberDescriptor *member_descriptor)
|
||||
{
|
||||
JavaMemberDescriptor *next_member;
|
||||
|
||||
while (member_descriptor) {
|
||||
next_member = member_descriptor->next;
|
||||
destroy_java_member_descriptor(cx, jEnv, member_descriptor);
|
||||
member_descriptor = next_member;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
destroy_class_descriptor(JSContext *cx, JNIEnv *jEnv, JavaClassDescriptor *class_descriptor)
|
||||
{
|
||||
JS_FREE_IF(cx, (char *)class_descriptor->name);
|
||||
if (class_descriptor->java_class) {
|
||||
JSJ_HashTableRemove(java_class_reflections,
|
||||
class_descriptor->java_class, (void*)jEnv);
|
||||
(*jEnv)->DeleteGlobalRef(jEnv, class_descriptor->java_class);
|
||||
}
|
||||
|
||||
if (class_descriptor->array_component_signature)
|
||||
jsj_ReleaseJavaClassDescriptor(cx, jEnv, class_descriptor->array_component_signature);
|
||||
|
||||
destroy_class_member_descriptors(cx, jEnv, class_descriptor->instance_members);
|
||||
destroy_class_member_descriptors(cx, jEnv, class_descriptor->static_members);
|
||||
destroy_class_member_descriptors(cx, jEnv, class_descriptor->constructors);
|
||||
JS_free(cx, class_descriptor);
|
||||
}
|
||||
|
||||
static JavaClassDescriptor *
|
||||
new_class_descriptor(JSContext *cx, JNIEnv *jEnv, jclass java_class)
|
||||
{
|
||||
JavaClassDescriptor *class_descriptor;
|
||||
|
||||
class_descriptor = (JavaClassDescriptor *)JS_malloc(cx, sizeof(JavaClassDescriptor));
|
||||
if (!class_descriptor)
|
||||
return NULL;
|
||||
memset(class_descriptor, 0, sizeof(JavaClassDescriptor));
|
||||
|
||||
class_descriptor->name = jsj_GetJavaClassName(cx, jEnv, java_class);
|
||||
if (!class_descriptor->name)
|
||||
goto error;
|
||||
|
||||
java_class = (*jEnv)->NewGlobalRef(jEnv, java_class);
|
||||
if (!java_class) {
|
||||
jsj_UnexpectedJavaError(cx, jEnv, "Unable to reference Java class");
|
||||
goto error;
|
||||
}
|
||||
class_descriptor->java_class = java_class;
|
||||
|
||||
if (!compute_java_class_signature(cx, jEnv, class_descriptor))
|
||||
goto error;
|
||||
|
||||
class_descriptor->modifiers =
|
||||
(*jEnv)->CallIntMethod(jEnv, java_class, jlClass_getModifiers);
|
||||
class_descriptor->ref_count = 1;
|
||||
|
||||
if (!JSJ_HashTableAdd(java_class_reflections, java_class, class_descriptor,
|
||||
(void*)jEnv))
|
||||
goto error;
|
||||
|
||||
return class_descriptor;
|
||||
|
||||
error:
|
||||
destroy_class_descriptor(cx, jEnv, class_descriptor);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Trivial helper for jsj_DiscardJavaClassReflections(), below */
|
||||
static PRIntn
|
||||
enumerate_remove_java_class(JSJHashEntry *he, PRIntn i, void *arg)
|
||||
{
|
||||
JNIEnv *jEnv = (JNIEnv*)arg;
|
||||
jclass java_class;
|
||||
JavaClassDescriptor *class_descriptor;
|
||||
|
||||
class_descriptor = (JavaClassDescriptor*)he->value;
|
||||
|
||||
java_class = class_descriptor->java_class;
|
||||
(*jEnv)->DeleteGlobalRef(jEnv, java_class);
|
||||
class_descriptor->java_class = NULL;
|
||||
|
||||
return HT_ENUMERATE_REMOVE;
|
||||
}
|
||||
|
||||
/* This shutdown routine discards all JNI references to Java objects
|
||||
that have been reflected into JS, even if there are still references
|
||||
to them from JS. */
|
||||
void
|
||||
jsj_DiscardJavaClassReflections(JNIEnv *jEnv)
|
||||
{
|
||||
if (java_class_reflections) {
|
||||
JSJ_HashTableEnumerateEntries(java_class_reflections,
|
||||
enumerate_remove_java_class,
|
||||
(void*)jEnv);
|
||||
JSJ_HashTableDestroy(java_class_reflections);
|
||||
java_class_reflections = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
extern JavaClassDescriptor *
|
||||
jsj_GetJavaClassDescriptor(JSContext *cx, JNIEnv *jEnv, jclass java_class)
|
||||
{
|
||||
JavaClassDescriptor *class_descriptor;
|
||||
class_descriptor = JSJ_HashTableLookup(java_class_reflections,
|
||||
(const void *)java_class,
|
||||
(void*)jEnv);
|
||||
if (!class_descriptor)
|
||||
return new_class_descriptor(cx, jEnv, java_class);
|
||||
|
||||
PR_ASSERT(class_descriptor->ref_count > 0);
|
||||
class_descriptor->ref_count++;
|
||||
return class_descriptor;
|
||||
}
|
||||
|
||||
void
|
||||
jsj_ReleaseJavaClassDescriptor(JSContext *cx, JNIEnv *jEnv, JavaClassDescriptor *class_descriptor)
|
||||
{
|
||||
if (!--class_descriptor->ref_count)
|
||||
destroy_class_descriptor(cx, jEnv, class_descriptor);
|
||||
}
|
||||
|
||||
static JSBool
|
||||
reflect_java_methods_and_fields(JSContext *cx,
|
||||
JNIEnv *jEnv,
|
||||
JavaClassDescriptor *class_descriptor,
|
||||
JSBool reflect_statics_only)
|
||||
{
|
||||
JavaMemberDescriptor *member_descriptor;
|
||||
|
||||
if (reflect_statics_only)
|
||||
class_descriptor->static_members_reflected = JS_TRUE;
|
||||
else
|
||||
class_descriptor->instance_members_reflected = JS_TRUE;
|
||||
|
||||
if (!jsj_ReflectJavaMethods(cx, jEnv, class_descriptor, reflect_statics_only))
|
||||
return JS_FALSE;
|
||||
if (!jsj_ReflectJavaFields(cx, jEnv, class_descriptor, reflect_statics_only))
|
||||
return JS_FALSE;
|
||||
|
||||
if (reflect_statics_only) {
|
||||
member_descriptor = class_descriptor->static_members;
|
||||
while (member_descriptor) {
|
||||
class_descriptor->num_static_members++;
|
||||
member_descriptor = member_descriptor->next;
|
||||
}
|
||||
} else {
|
||||
member_descriptor = class_descriptor->instance_members;
|
||||
while (member_descriptor) {
|
||||
class_descriptor->num_instance_members++;
|
||||
member_descriptor = member_descriptor->next;
|
||||
}
|
||||
}
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
JavaMemberDescriptor *
|
||||
jsj_GetClassStaticMembers(JSContext *cx,
|
||||
JNIEnv *jEnv,
|
||||
JavaClassDescriptor *class_descriptor)
|
||||
{
|
||||
if (!class_descriptor->static_members_reflected)
|
||||
reflect_java_methods_and_fields(cx, jEnv, class_descriptor, JS_TRUE);
|
||||
return class_descriptor->static_members;
|
||||
}
|
||||
|
||||
JavaMemberDescriptor *
|
||||
jsj_GetClassInstanceMembers(JSContext *cx,
|
||||
JNIEnv *jEnv,
|
||||
JavaClassDescriptor *class_descriptor)
|
||||
{
|
||||
if (!class_descriptor->instance_members_reflected)
|
||||
reflect_java_methods_and_fields(cx, jEnv, class_descriptor, JS_FALSE);
|
||||
return class_descriptor->instance_members;
|
||||
}
|
||||
|
||||
JavaMemberDescriptor *
|
||||
jsj_LookupJavaStaticMemberDescriptorById(JSContext *cx,
|
||||
JNIEnv *jEnv,
|
||||
JavaClassDescriptor *class_descriptor,
|
||||
jsid id)
|
||||
{
|
||||
JavaMemberDescriptor *member_descriptor;
|
||||
|
||||
member_descriptor = jsj_GetClassStaticMembers(cx, jEnv, class_descriptor);
|
||||
while (member_descriptor) {
|
||||
if (id == member_descriptor->id)
|
||||
return member_descriptor;
|
||||
member_descriptor = member_descriptor->next;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
JavaMemberDescriptor *
|
||||
jsj_GetJavaStaticMemberDescriptor(JSContext *cx,
|
||||
JNIEnv *jEnv,
|
||||
JavaClassDescriptor *class_descriptor,
|
||||
jstring member_name_jstr)
|
||||
{
|
||||
JavaMemberDescriptor *member_descriptor;
|
||||
jsid id;
|
||||
|
||||
if (!JavaStringToId(cx, jEnv, member_name_jstr, &id))
|
||||
return NULL;
|
||||
|
||||
member_descriptor = jsj_LookupJavaStaticMemberDescriptorById(cx, jEnv, class_descriptor, id);
|
||||
if (member_descriptor)
|
||||
return member_descriptor;
|
||||
|
||||
member_descriptor = JS_malloc(cx, sizeof(JavaMemberDescriptor));
|
||||
if (!member_descriptor)
|
||||
return NULL;
|
||||
memset(member_descriptor, 0, sizeof(JavaMemberDescriptor));
|
||||
|
||||
member_descriptor->name = jsj_DupJavaStringUTF(cx, jEnv, member_name_jstr);
|
||||
if (!member_descriptor->name) {
|
||||
JS_free(cx, member_descriptor);
|
||||
return NULL;
|
||||
}
|
||||
member_descriptor->id = id;
|
||||
|
||||
member_descriptor->next = class_descriptor->static_members;
|
||||
class_descriptor->static_members = member_descriptor;
|
||||
|
||||
return member_descriptor;
|
||||
}
|
||||
|
||||
JavaMemberDescriptor *
|
||||
jsj_GetJavaClassConstructors(JSContext *cx,
|
||||
JavaClassDescriptor *class_descriptor)
|
||||
{
|
||||
JavaMemberDescriptor *member_descriptor;
|
||||
|
||||
if (class_descriptor->constructors)
|
||||
return class_descriptor->constructors;
|
||||
|
||||
member_descriptor = JS_malloc(cx, sizeof(JavaMemberDescriptor));
|
||||
if (!member_descriptor)
|
||||
return NULL;
|
||||
memset(member_descriptor, 0, sizeof(JavaMemberDescriptor));
|
||||
|
||||
member_descriptor->name = JS_strdup(cx, "<init>");
|
||||
if (!member_descriptor->name) {
|
||||
JS_free(cx, member_descriptor);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
class_descriptor->constructors = member_descriptor;
|
||||
|
||||
return member_descriptor;
|
||||
}
|
||||
|
||||
JavaMemberDescriptor *
|
||||
jsj_LookupJavaClassConstructors(JSContext *cx, JNIEnv *jEnv,
|
||||
JavaClassDescriptor *class_descriptor)
|
||||
{
|
||||
if (!class_descriptor->static_members_reflected)
|
||||
reflect_java_methods_and_fields(cx, jEnv, class_descriptor, JS_TRUE);
|
||||
return class_descriptor->constructors;
|
||||
}
|
||||
|
||||
JavaMemberDescriptor *
|
||||
jsj_LookupJavaMemberDescriptorById(JSContext *cx, JNIEnv *jEnv,
|
||||
JavaClassDescriptor *class_descriptor,
|
||||
jsid id)
|
||||
{
|
||||
JavaMemberDescriptor *member_descriptor;
|
||||
|
||||
member_descriptor = jsj_GetClassInstanceMembers(cx, jEnv, class_descriptor);
|
||||
while (member_descriptor) {
|
||||
if (id == member_descriptor->id)
|
||||
return member_descriptor;
|
||||
member_descriptor = member_descriptor->next;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
JavaMemberDescriptor *
|
||||
jsj_GetJavaMemberDescriptor(JSContext *cx,
|
||||
JNIEnv *jEnv,
|
||||
JavaClassDescriptor *class_descriptor,
|
||||
jstring member_name_jstr)
|
||||
{
|
||||
JavaMemberDescriptor *member_descriptor;
|
||||
jsid id;
|
||||
|
||||
if (!JavaStringToId(cx, jEnv, member_name_jstr, &id))
|
||||
return NULL;
|
||||
|
||||
member_descriptor = jsj_LookupJavaMemberDescriptorById(cx, jEnv, class_descriptor, id);
|
||||
if (member_descriptor)
|
||||
return member_descriptor;
|
||||
|
||||
member_descriptor = JS_malloc(cx, sizeof(JavaMemberDescriptor));
|
||||
if (!member_descriptor)
|
||||
return NULL;
|
||||
memset(member_descriptor, 0, sizeof(JavaMemberDescriptor));
|
||||
|
||||
member_descriptor->name = jsj_DupJavaStringUTF(cx, jEnv, member_name_jstr);
|
||||
if (!member_descriptor->name) {
|
||||
JS_free(cx, member_descriptor);
|
||||
return NULL;
|
||||
}
|
||||
member_descriptor->id = id;
|
||||
|
||||
member_descriptor->next = class_descriptor->instance_members;
|
||||
class_descriptor->instance_members = member_descriptor;
|
||||
|
||||
return member_descriptor;
|
||||
}
|
||||
|
||||
JSBool
|
||||
jsj_InitJavaClassReflectionsTable()
|
||||
{
|
||||
java_class_reflections =
|
||||
JSJ_NewHashTable(64, jsj_HashJavaObject, jsj_JavaObjectComparator,
|
||||
NULL, NULL, NULL);
|
||||
|
||||
if (!java_class_reflections)
|
||||
return JS_FALSE;
|
||||
return JS_TRUE;
|
||||
}
|
||||
806
mozilla/js/src/liveconnect/jsj_convert.c
Normal file
@@ -0,0 +1,806 @@
|
||||
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.0 (the "License"); you may not use this file except in
|
||||
* compliance with the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
* the License for the specific language governing rights and limitations
|
||||
* under the License.
|
||||
*
|
||||
* The Original Code is Mozilla Communicator client code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are Copyright (C) 1998
|
||||
* Netscape Communications Corporation. All Rights Reserved.
|
||||
*/
|
||||
|
||||
/* This file is part of the Java-vendor-neutral implementation of LiveConnect
|
||||
*
|
||||
* Below is the code that converts between Java and JavaScript values of all
|
||||
* types.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "jsj_private.h" /* LiveConnect internals */
|
||||
|
||||
/* Floating-point double utilities, stolen from jsnum.h */
|
||||
#ifdef IS_LITTLE_ENDIAN
|
||||
#define JSDOUBLE_HI32(x) (((uint32 *)&(x))[1])
|
||||
#define JSDOUBLE_LO32(x) (((uint32 *)&(x))[0])
|
||||
#else
|
||||
#define JSDOUBLE_HI32(x) (((uint32 *)&(x))[0])
|
||||
#define JSDOUBLE_LO32(x) (((uint32 *)&(x))[1])
|
||||
#endif
|
||||
#define JSDOUBLE_HI32_SIGNBIT 0x80000000
|
||||
#define JSDOUBLE_HI32_EXPMASK 0x7ff00000
|
||||
#define JSDOUBLE_HI32_MANTMASK 0x000fffff
|
||||
|
||||
#define JSDOUBLE_IS_NaN(x) \
|
||||
((JSDOUBLE_HI32(x) & JSDOUBLE_HI32_EXPMASK) == JSDOUBLE_HI32_EXPMASK && \
|
||||
(JSDOUBLE_LO32(x) || (JSDOUBLE_HI32(x) & JSDOUBLE_HI32_MANTMASK)))
|
||||
|
||||
#define JSDOUBLE_IS_INFINITE(x) \
|
||||
((JSDOUBLE_HI32(x) & ~JSDOUBLE_HI32_SIGNBIT) == JSDOUBLE_HI32_EXPMASK && \
|
||||
!JSDOUBLE_LO32(x))
|
||||
|
||||
static JSBool
|
||||
convert_js_obj_to_JSObject_wrapper(JSContext *cx, JNIEnv *jEnv, JSObject *js_obj,
|
||||
JavaSignature *signature,
|
||||
int *cost, jobject *java_value)
|
||||
{
|
||||
if (!njJSObject) {
|
||||
if (java_value)
|
||||
JS_ReportError(cx, "Couldn't convert JavaScript object to an "
|
||||
"instance of netscape.javascript.JSObject "
|
||||
"because that class could not be loaded.");
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
if (!(*jEnv)->IsAssignableFrom(jEnv, njJSObject, signature->java_class))
|
||||
return JS_FALSE;
|
||||
|
||||
if (!java_value)
|
||||
return JS_TRUE;
|
||||
|
||||
*java_value = jsj_WrapJSObject(cx, jEnv, js_obj);
|
||||
|
||||
return (*java_value != NULL);
|
||||
}
|
||||
|
||||
jstring
|
||||
jsj_ConvertJSStringToJavaString(JSContext *cx, JNIEnv *jEnv, JSString *js_str)
|
||||
{
|
||||
jstring result;
|
||||
result = (*jEnv)->NewString(jEnv, JS_GetStringChars(js_str),
|
||||
JS_GetStringLength(js_str));
|
||||
if (!result) {
|
||||
jsj_UnexpectedJavaError(cx, jEnv, "Couldn't construct instance "
|
||||
"of java.lang.String");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert a JS value to an instance of java.lang.Object or one of its subclasses,
|
||||
* performing any necessary type coercion. If non-trivial coercion is required,
|
||||
* the cost value is incremented. If the java_value pass-by-reference argument
|
||||
* is non-NULL, the resulting Java value is stored there.
|
||||
*
|
||||
* Returns JS_TRUE if the conversion is possible, JS_FALSE otherwise
|
||||
*/
|
||||
JSBool
|
||||
jsj_ConvertJSValueToJavaObject(JSContext *cx, JNIEnv *jEnv, jsval v, JavaSignature *signature,
|
||||
int *cost, jobject *java_value, JSBool *is_local_refp)
|
||||
{
|
||||
JSString *jsstr;
|
||||
jclass target_java_class;
|
||||
|
||||
PR_ASSERT(signature->type == JAVA_SIGNATURE_CLASS ||
|
||||
signature->type == JAVA_SIGNATURE_ARRAY);
|
||||
|
||||
/* Initialize to default case, in which no new Java object is
|
||||
synthesized to perform the conversion and, therefore, no JNI local
|
||||
references are being held. */
|
||||
*is_local_refp = JS_FALSE;
|
||||
|
||||
/* Get the Java type of the target value */
|
||||
target_java_class = signature->java_class;
|
||||
|
||||
if (JSVAL_IS_OBJECT(v)) {
|
||||
JSObject *js_obj = JSVAL_TO_OBJECT(v);
|
||||
|
||||
/* JS null is always assignable to a Java object */
|
||||
if (!js_obj) {
|
||||
if (java_value)
|
||||
*java_value = NULL;
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
if (JS_InstanceOf(cx, js_obj, &JavaObject_class, 0) ||
|
||||
JS_InstanceOf(cx, js_obj, &JavaArray_class, 0)) {
|
||||
|
||||
/* The source value is a Java object wrapped inside a JavaScript
|
||||
object. Unwrap the JS object and return the original Java
|
||||
object if it's class makes it assignment-compatible with the
|
||||
target class using Java's assignability rules. */
|
||||
JavaObjectWrapper *java_wrapper = JS_GetPrivate(cx, js_obj);
|
||||
jobject java_obj = java_wrapper->java_obj;
|
||||
|
||||
if ((*jEnv)->IsInstanceOf(jEnv, java_obj, target_java_class)) {
|
||||
if (java_value)
|
||||
*java_value = java_obj;
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
#ifdef LIVECONNECT_IMPROVEMENTS
|
||||
/* Don't allow wrapped Java objects to be converted to strings */
|
||||
goto conversion_error;
|
||||
#else
|
||||
/* Fall through, to attempt conversion to a Java string */
|
||||
#endif
|
||||
|
||||
} else if (JS_InstanceOf(cx, js_obj, &JavaClass_class, 0)) {
|
||||
/* We're dealing with the reflection of a Java class */
|
||||
JavaClassDescriptor *java_class_descriptor = JS_GetPrivate(cx, js_obj);
|
||||
|
||||
/* Check if target type is java.lang.Class class */
|
||||
if ((*jEnv)->IsAssignableFrom(jEnv, jlClass, target_java_class)) {
|
||||
if (java_value)
|
||||
*java_value = java_class_descriptor->java_class;
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
/* Check if target type is netscape.javascript.JSObject wrapper class */
|
||||
if (convert_js_obj_to_JSObject_wrapper(cx, jEnv, js_obj, signature, cost, java_value)) {
|
||||
if (*java_value)
|
||||
*is_local_refp = JS_TRUE;
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
/* Fall through, to attempt conversion to a Java string */
|
||||
|
||||
} else if (JS_InstanceOf(cx, js_obj, &JavaMember_class, 0)) {
|
||||
|
||||
if (!JS_ConvertValue(cx, v, JSTYPE_OBJECT, &v))
|
||||
return JS_FALSE;
|
||||
return jsj_ConvertJSValueToJavaObject(cx, jEnv, v, signature, cost,
|
||||
java_value, is_local_refp);
|
||||
|
||||
} else {
|
||||
/* Otherwise, see if the target type is the netscape.javascript.JSObject
|
||||
wrapper class or one of its subclasses, in which case a
|
||||
reference is passed to the original JS object by wrapping it
|
||||
inside an instance of netscape.javascript.JSObject */
|
||||
if (convert_js_obj_to_JSObject_wrapper(cx, jEnv, js_obj, signature, cost, java_value)) {
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
/* Fall through, to attempt conversion to a Java string */
|
||||
}
|
||||
|
||||
} else if (JSVAL_IS_NUMBER(v)) {
|
||||
/* JS numbers, integral or not, can be converted to instances of java.lang.Double */
|
||||
if ((*jEnv)->IsAssignableFrom(jEnv, jlDouble, target_java_class)) {
|
||||
if (java_value) {
|
||||
jsdouble d;
|
||||
if (!JS_ValueToNumber(cx, v, &d))
|
||||
goto conversion_error;
|
||||
*java_value = (*jEnv)->NewObject(jEnv, jlDouble, jlDouble_Double, d);
|
||||
if (*java_value) {
|
||||
*is_local_refp = JS_TRUE;
|
||||
} else {
|
||||
jsj_UnexpectedJavaError(cx, jEnv,
|
||||
"Couldn't construct instance of java.lang.Double");
|
||||
return JS_FALSE;
|
||||
}
|
||||
}
|
||||
#ifdef LIVECONNECT_IMPROVEMENTS
|
||||
(*cost)++;
|
||||
#endif
|
||||
return JS_TRUE;
|
||||
}
|
||||
/* Fall through, to attempt conversion to a java.lang.String ... */
|
||||
|
||||
} else if (JSVAL_IS_BOOLEAN(v)) {
|
||||
/* JS boolean values can be converted to instances of java.lang.Boolean */
|
||||
if ((*jEnv)->IsAssignableFrom(jEnv, jlBoolean, target_java_class)) {
|
||||
if (java_value) {
|
||||
JSBool b;
|
||||
if (!JS_ValueToBoolean(cx, v, &b))
|
||||
goto conversion_error;
|
||||
*java_value =
|
||||
(*jEnv)->NewObject(jEnv, jlBoolean, jlBoolean_Boolean, b);
|
||||
if (*java_value) {
|
||||
*is_local_refp = JS_TRUE;
|
||||
} else {
|
||||
jsj_UnexpectedJavaError(cx, jEnv, "Couldn't construct instance "
|
||||
"of java.lang.Boolean");
|
||||
return JS_FALSE;
|
||||
}
|
||||
}
|
||||
#ifdef LIVECONNECT_IMPROVEMENTS
|
||||
(*cost)++;
|
||||
#endif
|
||||
return JS_TRUE;
|
||||
}
|
||||
/* Fall through, to attempt conversion to a java.lang.String ... */
|
||||
}
|
||||
|
||||
/* If no other conversion is possible, see if the target type is java.lang.String */
|
||||
if ((*jEnv)->IsAssignableFrom(jEnv, jlString, target_java_class)) {
|
||||
#ifdef LIVECONNECT_IMPROVEMENTS
|
||||
JSBool is_string = JSVAL_IS_STRING(v);
|
||||
#endif
|
||||
|
||||
/* Convert to JS string, if necessary, and then to a Java Unicode string */
|
||||
jsstr = JS_ValueToString(cx, v);
|
||||
if (jsstr) {
|
||||
if (java_value) {
|
||||
*java_value = jsj_ConvertJSStringToJavaString(cx, jEnv, jsstr);
|
||||
if (*java_value) {
|
||||
*is_local_refp = JS_TRUE;
|
||||
} else {
|
||||
return JS_FALSE;
|
||||
}
|
||||
}
|
||||
#ifdef LIVECONNECT_IMPROVEMENTS
|
||||
if (!is_string)
|
||||
(*cost)++;
|
||||
#endif
|
||||
return JS_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
conversion_error:
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
/* Valid ranges for Java numeric types */
|
||||
#define jbyte_MAX_VALUE 127.0
|
||||
#define jbyte_MIN_VALUE -128.0
|
||||
#define jchar_MAX_VALUE 65535.0
|
||||
#define jchar_MIN_VALUE 0.0
|
||||
#define jshort_MAX_VALUE 32767.0
|
||||
#define jshort_MIN_VALUE -32768.0
|
||||
#define jint_MAX_VALUE 2147483647.0
|
||||
#define jint_MIN_VALUE -2147483648.0
|
||||
#define jlong_MAX_VALUE 9223372036854775807.0
|
||||
#define jlong_MIN_VALUE -9223372036854775808.0
|
||||
|
||||
/* Utility macro for jsj_ConvertJSValueToJavaValue(), below */
|
||||
#define JSVAL_TO_INTEGRAL_JVALUE(type_name, member_name, member_type, jsval, java_value) \
|
||||
if (!JSVAL_IS_NUMBER(v)) { \
|
||||
if (!JS_ConvertValue(cx, v, JSTYPE_NUMBER, &v)) \
|
||||
goto conversion_error; \
|
||||
(*cost)++; \
|
||||
} \
|
||||
{ \
|
||||
member_type member_name; \
|
||||
\
|
||||
if (JSVAL_IS_INT(v)) { \
|
||||
jsint ival = JSVAL_TO_INT(v); \
|
||||
member_name = (member_type) ival; \
|
||||
\
|
||||
/* Check to see if the jsval's magnitude is too large to be \
|
||||
representable in the target java type */ \
|
||||
if (member_name != ival) \
|
||||
goto numeric_conversion_error; \
|
||||
} else { \
|
||||
jdouble dval = *JSVAL_TO_DOUBLE(v); \
|
||||
\
|
||||
/* NaN becomes zero when converted to integral value */ \
|
||||
if (JSDOUBLE_IS_NaN(dval)) \
|
||||
member_name = 0; \
|
||||
\
|
||||
/* Unrepresentably large numbers, including infinities, */ \
|
||||
/* cause an error. */ \
|
||||
else if ((dval > member_type ## _MAX_VALUE) || \
|
||||
(dval < member_type ## _MIN_VALUE)) { \
|
||||
goto numeric_conversion_error; \
|
||||
} else \
|
||||
member_name = (member_type) dval; \
|
||||
\
|
||||
/* Don't allow a non-integral number to be converted \
|
||||
to an integral type */ \
|
||||
/* Actually, we have to allow this for LC1 compatibility */ \
|
||||
/* if ((jdouble)member_name != dval) \
|
||||
(*cost)++; */ \
|
||||
} \
|
||||
if (java_value) \
|
||||
java_value->member_name = member_name; \
|
||||
}
|
||||
|
||||
#if XP_MAC
|
||||
|
||||
/* on MRJ jlong is typedef'd to wide, which is a struct. */
|
||||
#include <Math64.h>
|
||||
|
||||
static jsint jlong_to_jsint(jlong lvalue)
|
||||
{
|
||||
SInt64 val = WideToSInt64(lvalue);
|
||||
return S32Set(val);
|
||||
}
|
||||
|
||||
static jlong jsint_to_jlong(jsint ivalue)
|
||||
{
|
||||
SInt64 val = S64Set(ivalue);
|
||||
wide wval =SInt64ToWide(val);
|
||||
return *(jlong*)&wval;
|
||||
}
|
||||
|
||||
static jdouble jlong_to_jdouble(jlong lvalue)
|
||||
{
|
||||
SInt64 val = WideToSInt64(lvalue);
|
||||
return SInt64ToLongDouble(val);
|
||||
}
|
||||
|
||||
static jlong jdouble_to_jlong(jdouble dvalue)
|
||||
{
|
||||
SInt64 val = LongDoubleToSInt64(dvalue);
|
||||
wide wval = SInt64ToWide(val);
|
||||
return *(jlong*)&wval;
|
||||
}
|
||||
|
||||
/* Mac utility macro for jsj_ConvertJSValueToJavaValue(), below */
|
||||
#define JSVAL_TO_JLONG_JVALUE(member_name, member_type, jsvalue, java_value) \
|
||||
if (!JSVAL_IS_NUMBER(jsvalue)) { \
|
||||
if (!JS_ConvertValue(cx, jsvalue, JSTYPE_NUMBER, &jsvalue)) \
|
||||
goto conversion_error; \
|
||||
(*cost)++; \
|
||||
} \
|
||||
{ \
|
||||
member_type member_name; \
|
||||
\
|
||||
if (JSVAL_IS_INT(jsvalue)) { \
|
||||
jsint ival = JSVAL_TO_INT(jsvalue); \
|
||||
member_name = jsint_to_jlong(ival); \
|
||||
\
|
||||
} else { \
|
||||
jdouble dval = *JSVAL_TO_DOUBLE(jsvalue); \
|
||||
\
|
||||
/* NaN becomes zero when converted to integral value */ \
|
||||
if (JSDOUBLE_IS_NaN(dval)) \
|
||||
member_name = jsint_to_jlong(0); \
|
||||
\
|
||||
/* Unrepresentably large numbers, including infinities, */ \
|
||||
/* cause an error. */ \
|
||||
else if ((dval > member_type ## _MAX_VALUE) || \
|
||||
(dval < member_type ## _MIN_VALUE)) { \
|
||||
goto numeric_conversion_error; \
|
||||
} else \
|
||||
member_name = jdouble_to_jlong(dval); \
|
||||
\
|
||||
/* Don't allow a non-integral number to be converted \
|
||||
to an integral type */ \
|
||||
/* Actually, we have to allow this for LC1 compatibility */ \
|
||||
/*if (jlong_to_jdouble(member_name) != dval) \
|
||||
(*cost)++;*/ \
|
||||
} \
|
||||
if (java_value) \
|
||||
java_value->member_name = member_name; \
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#define jlong_to_jdouble(lvalue) ((jdouble) lvalue)
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Convert a JS value to a Java value of the given type signature. The cost
|
||||
* variable is incremented if coercion is required, e.g. the source value is
|
||||
* a string, but the target type is a boolean.
|
||||
*
|
||||
* Returns JS_FALSE if no conversion is possible, either because the jsval has
|
||||
* a type that is wholly incompatible with the Java value, or because a scalar
|
||||
* jsval can't be represented in a variable of the target type without loss of
|
||||
* precision, e.g. the source value is "4.2" but the destination type is byte.
|
||||
* If conversion is not possible and java_value is non-NULL, the JS error
|
||||
* reporter is called with an appropriate message.
|
||||
*/
|
||||
JSBool
|
||||
jsj_ConvertJSValueToJavaValue(JSContext *cx, JNIEnv *jEnv, jsval v,
|
||||
JavaSignature *signature,
|
||||
int *cost, jvalue *java_value, JSBool *is_local_refp)
|
||||
{
|
||||
JavaSignatureChar type;
|
||||
JSBool success = JS_FALSE;
|
||||
|
||||
/* Initialize to default case, in which no new Java object is
|
||||
synthesized to perform the conversion and, therefore, no JNI local
|
||||
references are being held. */
|
||||
*is_local_refp = JS_FALSE;
|
||||
|
||||
type = signature->type;
|
||||
switch (type) {
|
||||
case JAVA_SIGNATURE_BOOLEAN:
|
||||
if (!JSVAL_IS_BOOLEAN(v)) {
|
||||
if (!JS_ConvertValue(cx, v, JSTYPE_BOOLEAN, &v))
|
||||
goto conversion_error;
|
||||
(*cost)++;
|
||||
}
|
||||
if (java_value)
|
||||
java_value->z = (jboolean)(JSVAL_TO_BOOLEAN(v) == JS_TRUE);
|
||||
break;
|
||||
|
||||
case JAVA_SIGNATURE_SHORT:
|
||||
JSVAL_TO_INTEGRAL_JVALUE(short, s, jshort, v, java_value);
|
||||
break;
|
||||
|
||||
case JAVA_SIGNATURE_BYTE:
|
||||
JSVAL_TO_INTEGRAL_JVALUE(byte, b, jbyte, v, java_value);
|
||||
break;
|
||||
|
||||
case JAVA_SIGNATURE_CHAR:
|
||||
/* A one-character string can be converted into a character */
|
||||
if (JSVAL_IS_STRING(v) && (JS_GetStringLength(JSVAL_TO_STRING(v)) == 1)) {
|
||||
v = INT_TO_JSVAL(*JS_GetStringChars(JSVAL_TO_STRING(v)));
|
||||
}
|
||||
JSVAL_TO_INTEGRAL_JVALUE(char, c, jchar, v, java_value);
|
||||
break;
|
||||
|
||||
case JAVA_SIGNATURE_INT:
|
||||
JSVAL_TO_INTEGRAL_JVALUE(int, i, jint, v, java_value);
|
||||
break;
|
||||
|
||||
case JAVA_SIGNATURE_LONG:
|
||||
#if XP_MAC
|
||||
JSVAL_TO_JLONG_JVALUE(j, jlong, v, java_value);
|
||||
#else
|
||||
JSVAL_TO_INTEGRAL_JVALUE(long, j, jlong, v, java_value);
|
||||
#endif
|
||||
break;
|
||||
|
||||
case JAVA_SIGNATURE_FLOAT:
|
||||
if (!JSVAL_IS_NUMBER(v)) {
|
||||
if (!JS_ConvertValue(cx, v, JSTYPE_NUMBER, &v))
|
||||
goto conversion_error;
|
||||
(*cost)++;
|
||||
}
|
||||
if (java_value) {
|
||||
if (JSVAL_IS_INT(v))
|
||||
java_value->f = (jfloat) JSVAL_TO_INT(v);
|
||||
else
|
||||
java_value->f = (jfloat) *JSVAL_TO_DOUBLE(v);
|
||||
}
|
||||
break;
|
||||
|
||||
case JAVA_SIGNATURE_DOUBLE:
|
||||
if (!JSVAL_IS_NUMBER(v)) {
|
||||
if (!JS_ConvertValue(cx, v, JSTYPE_NUMBER, &v))
|
||||
goto conversion_error;
|
||||
(*cost)++;
|
||||
}
|
||||
if (java_value) {
|
||||
if (JSVAL_IS_INT(v))
|
||||
java_value->d = (jdouble) JSVAL_TO_INT(v);
|
||||
else
|
||||
java_value->d = (jdouble) *JSVAL_TO_DOUBLE(v);
|
||||
}
|
||||
break;
|
||||
|
||||
case JAVA_SIGNATURE_CLASS:
|
||||
case JAVA_SIGNATURE_ARRAY:
|
||||
if (!jsj_ConvertJSValueToJavaObject(cx, jEnv, v, signature, cost,
|
||||
&java_value->l, is_local_refp))
|
||||
goto conversion_error;
|
||||
break;
|
||||
|
||||
default:
|
||||
PR_ASSERT(0);
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
/* Success */
|
||||
return JS_TRUE;
|
||||
|
||||
numeric_conversion_error:
|
||||
success = JS_TRUE;
|
||||
/* Fall through ... */
|
||||
|
||||
conversion_error:
|
||||
|
||||
if (java_value) {
|
||||
const char *jsval_string;
|
||||
JSString *jsstr;
|
||||
|
||||
jsval_string = NULL;
|
||||
jsstr = JS_ValueToString(cx, v);
|
||||
if (jsstr)
|
||||
jsval_string = JS_GetStringBytes(jsstr);
|
||||
if (!jsval_string)
|
||||
jsval_string = "";
|
||||
|
||||
JS_ReportError(cx, "Unable to convert JavaScript value %s to "
|
||||
"Java value of type %s",
|
||||
jsval_string, signature->name);
|
||||
return JS_FALSE;
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
/*
|
||||
* A utility routine to create a JavaScript Unicode string from a
|
||||
* java.lang.String (Unicode) string.
|
||||
*/
|
||||
JSString *
|
||||
jsj_ConvertJavaStringToJSString(JSContext *cx, JNIEnv *jEnv, jstring java_str)
|
||||
{
|
||||
JSString *js_str;
|
||||
jboolean is_copy;
|
||||
const jchar *ucs2_str;
|
||||
jchar *copy_ucs2_str;
|
||||
jsize ucs2_str_len, num_bytes;
|
||||
|
||||
ucs2_str_len = (*jEnv)->GetStringLength(jEnv, java_str);
|
||||
ucs2_str = (*jEnv)->GetStringChars(jEnv, java_str, &is_copy);
|
||||
if (!ucs2_str) {
|
||||
jsj_UnexpectedJavaError(cx, jEnv,
|
||||
"Unable to extract native Unicode from Java string");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
js_str = NULL;
|
||||
|
||||
/* The string data passed into JS_NewUCString() is
|
||||
not copied, so make a copy of the Unicode character vector. */
|
||||
num_bytes = ucs2_str_len * sizeof(jchar);
|
||||
copy_ucs2_str = (jchar*)JS_malloc(cx, num_bytes);
|
||||
if (!copy_ucs2_str)
|
||||
goto done;
|
||||
memcpy(copy_ucs2_str, ucs2_str, num_bytes);
|
||||
|
||||
js_str = JS_NewUCString(cx, (jschar*)copy_ucs2_str, ucs2_str_len);
|
||||
|
||||
done:
|
||||
(*jEnv)->ReleaseStringChars(jEnv, java_str, ucs2_str);
|
||||
return js_str;
|
||||
}
|
||||
|
||||
/*
|
||||
* Attempt to obtain a JS string representation of a Java object.
|
||||
* The java_obj argument must be of type java.lang.Object or a subclass.
|
||||
* If java_obj is a Java string, it's value is simply extracted and
|
||||
* copied into a JS string. Otherwise, the toString() method is called
|
||||
* on java_obj.
|
||||
*/
|
||||
JSBool
|
||||
jsj_ConvertJavaObjectToJSString(JSContext *cx,
|
||||
JNIEnv *jEnv,
|
||||
JavaClassDescriptor *class_descriptor,
|
||||
jobject java_obj, jsval *vp)
|
||||
{
|
||||
JSString *js_str;
|
||||
jstring java_str;
|
||||
jmethodID toString;
|
||||
|
||||
/* Create a Java string, unless java_obj is already a java.lang.String */
|
||||
if ((*jEnv)->IsInstanceOf(jEnv, java_obj, jlString)) {
|
||||
java_str = java_obj;
|
||||
} else {
|
||||
jclass java_class;
|
||||
|
||||
java_class = class_descriptor->java_class;
|
||||
toString = (*jEnv)->GetMethodID(jEnv, java_class, "toString",
|
||||
"()Ljava/lang/String;");
|
||||
if (!toString) {
|
||||
/* All Java objects have a toString method */
|
||||
jsj_UnexpectedJavaError(cx, jEnv, "No toString() method for class %s!",
|
||||
class_descriptor->name);
|
||||
return JS_FALSE;
|
||||
}
|
||||
java_str = (*jEnv)->CallObjectMethod(jEnv, java_obj, toString);
|
||||
if (!java_str) {
|
||||
jsj_ReportJavaError(cx, jEnv, "toString() method failed");
|
||||
return JS_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Extract Unicode from java.lang.String instance and convert to JS string */
|
||||
js_str = jsj_ConvertJavaStringToJSString(cx, jEnv, java_str);
|
||||
if (!js_str)
|
||||
return JS_FALSE;
|
||||
|
||||
*vp = STRING_TO_JSVAL(js_str);
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert a Java object to a number by attempting to call the
|
||||
* doubleValue() method on a Java object to get a double result.
|
||||
* This usually only works on instances of java.lang.Double, but the code
|
||||
* is generalized to work with any Java object that supports this method.
|
||||
*
|
||||
* Returns JS_TRUE if the call was successful.
|
||||
* Returns JS_FALSE if conversion is not possible or an error occurs.
|
||||
*/
|
||||
JSBool
|
||||
jsj_ConvertJavaObjectToJSNumber(JSContext *cx, JNIEnv *jEnv,
|
||||
JavaClassDescriptor *class_descriptor,
|
||||
jobject java_obj, jsval *vp)
|
||||
{
|
||||
jdouble d;
|
||||
jmethodID doubleValue;
|
||||
jclass java_class;
|
||||
|
||||
java_class = class_descriptor->java_class;
|
||||
doubleValue = (*jEnv)->GetMethodID(jEnv, java_class, "doubleValue", "()D");
|
||||
if (!doubleValue) {
|
||||
/* There is no doubleValue() method for the object. Try toString()
|
||||
instead and the JS engine will attempt to convert the result to
|
||||
a number. */
|
||||
(*jEnv)->ExceptionClear(jEnv);
|
||||
return jsj_ConvertJavaObjectToJSString(cx, jEnv, class_descriptor,
|
||||
java_obj, vp);
|
||||
}
|
||||
|
||||
d = (*jEnv)->CallDoubleMethod(jEnv, java_obj, doubleValue);
|
||||
if ((*jEnv)->ExceptionOccurred(jEnv)) {
|
||||
jsj_UnexpectedJavaError(cx, jEnv, "doubleValue() method failed");
|
||||
return JS_FALSE;
|
||||
}
|
||||
return JS_NewDoubleValue(cx, d, vp);
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert a Java object to a boolean by attempting to call the
|
||||
* booleanValue() method on a Java object to get a boolean result.
|
||||
* This usually only works on instances of java.lang.Boolean, but the code
|
||||
* is generalized to work with any Java object that supports this method.
|
||||
*
|
||||
* Returns JS_TRUE if the call was successful.
|
||||
* Returns JS_FALSE if conversion is not possible or an error occurs.
|
||||
*/
|
||||
extern JSBool
|
||||
jsj_ConvertJavaObjectToJSBoolean(JSContext *cx, JNIEnv *jEnv,
|
||||
JavaClassDescriptor *class_descriptor,
|
||||
jobject java_obj, jsval *vp)
|
||||
{
|
||||
jboolean b;
|
||||
jmethodID booleanValue;
|
||||
jclass java_class;
|
||||
|
||||
/* Null converts to false. */
|
||||
if (!java_obj) {
|
||||
*vp = JSVAL_FALSE;
|
||||
return JS_TRUE;
|
||||
}
|
||||
java_class = class_descriptor->java_class;
|
||||
booleanValue = (*jEnv)->GetMethodID(jEnv, java_obj, "booleanValue", "()Z");
|
||||
|
||||
/* Non-null Java object does not have a booleanValue() method, so
|
||||
it converts to true. */
|
||||
if (!booleanValue) {
|
||||
(*jEnv)->ExceptionClear(jEnv);
|
||||
*vp = JSVAL_TRUE;
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
b = (*jEnv)->CallBooleanMethod(jEnv, java_obj, booleanValue);
|
||||
if ((*jEnv)->ExceptionOccurred(jEnv)) {
|
||||
jsj_UnexpectedJavaError(cx, jEnv, "booleanValue() method failed");
|
||||
return JS_FALSE;
|
||||
}
|
||||
*vp = BOOLEAN_TO_JSVAL(b);
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Reflect a Java object into a JS value. The source object, java_obj, must
|
||||
* be of type java.lang.Object or a subclass and may, therefore, be an array.
|
||||
*/
|
||||
JSBool
|
||||
jsj_ConvertJavaObjectToJSValue(JSContext *cx, JNIEnv *jEnv,
|
||||
jobject java_obj, jsval *vp)
|
||||
{
|
||||
jclass java_class;
|
||||
JSObject *js_obj;
|
||||
|
||||
/* A null in Java-land is also null in JS */
|
||||
if (!java_obj) {
|
||||
*vp = JSVAL_NULL;
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
java_class = (*jEnv)->GetObjectClass(jEnv, java_obj);
|
||||
|
||||
/*
|
||||
* If it's an instance of netscape.javascript.JSObject, i.e. a wrapper
|
||||
* around a JS object that has been passed into the Java world, unwrap
|
||||
* it to obtain the original JS object.
|
||||
*/
|
||||
if (njJSObject && (*jEnv)->IsInstanceOf(jEnv, java_obj, njJSObject)) {
|
||||
#ifdef PRESERVE_JSOBJECT_IDENTITY
|
||||
js_obj = (JSObject *)((*jEnv)->GetIntField(jEnv, java_obj, njJSObject_internal));
|
||||
#else
|
||||
js_obj = jsj_UnwrapJSObjectWrapper(jEnv, java_obj);
|
||||
#endif
|
||||
PR_ASSERT(js_obj);
|
||||
if (!js_obj)
|
||||
return JS_FALSE;
|
||||
*vp = OBJECT_TO_JSVAL(js_obj);
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Instances of java.lang.String are wrapped so we can call methods on
|
||||
* them, but they convert to a JS string if used in a string context.
|
||||
*/
|
||||
/* TODO - let's get rid of this annoying "feature" */
|
||||
|
||||
/* otherwise, wrap it inside a JavaObject */
|
||||
js_obj = jsj_WrapJavaObject(cx, jEnv, java_obj, java_class);
|
||||
if (!js_obj)
|
||||
return JS_FALSE;
|
||||
*vp = OBJECT_TO_JSVAL(js_obj);
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert a Java value (primitive or object) to a JS value.
|
||||
*
|
||||
* This is usually an infallible operation, but JS_FALSE is returned
|
||||
* on an out-of-memory condition and the error reporter is called.
|
||||
*/
|
||||
JSBool
|
||||
jsj_ConvertJavaValueToJSValue(JSContext *cx, JNIEnv *jEnv,
|
||||
JavaSignature *signature,
|
||||
jvalue *java_value,
|
||||
jsval *vp)
|
||||
{
|
||||
int32 ival32;
|
||||
|
||||
switch (signature->type) {
|
||||
case JAVA_SIGNATURE_VOID:
|
||||
*vp = JSVAL_VOID;
|
||||
return JS_TRUE;
|
||||
|
||||
case JAVA_SIGNATURE_BYTE:
|
||||
*vp = INT_TO_JSVAL((jsint)java_value->b);
|
||||
return JS_TRUE;
|
||||
|
||||
case JAVA_SIGNATURE_CHAR:
|
||||
*vp = INT_TO_JSVAL((jsint)java_value->c);
|
||||
return JS_TRUE;
|
||||
|
||||
case JAVA_SIGNATURE_SHORT:
|
||||
*vp = INT_TO_JSVAL((jsint)java_value->s);
|
||||
return JS_TRUE;
|
||||
|
||||
case JAVA_SIGNATURE_INT:
|
||||
ival32 = java_value->i;
|
||||
if (INT_FITS_IN_JSVAL(ival32)) {
|
||||
*vp = INT_TO_JSVAL((jsint) ival32);
|
||||
return JS_TRUE;
|
||||
} else {
|
||||
return JS_NewDoubleValue(cx, ival32, vp);
|
||||
}
|
||||
|
||||
case JAVA_SIGNATURE_BOOLEAN:
|
||||
*vp = BOOLEAN_TO_JSVAL((JSBool) java_value->z);
|
||||
return JS_TRUE;
|
||||
|
||||
case JAVA_SIGNATURE_LONG:
|
||||
return JS_NewDoubleValue(cx, jlong_to_jdouble(java_value->j), vp);
|
||||
|
||||
case JAVA_SIGNATURE_FLOAT:
|
||||
return JS_NewDoubleValue(cx, java_value->f, vp);
|
||||
|
||||
case JAVA_SIGNATURE_DOUBLE:
|
||||
return JS_NewDoubleValue(cx, java_value->d, vp);
|
||||
|
||||
case JAVA_SIGNATURE_CLASS:
|
||||
case JAVA_SIGNATURE_ARRAY:
|
||||
return jsj_ConvertJavaObjectToJSValue(cx, jEnv, java_value->l, vp);
|
||||
|
||||
default:
|
||||
PR_ASSERT(0);
|
||||
return JS_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
383
mozilla/js/src/liveconnect/jsj_field.c
Normal file
@@ -0,0 +1,383 @@
|
||||
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.0 (the "License"); you may not use this file except in
|
||||
* compliance with the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
* the License for the specific language governing rights and limitations
|
||||
* under the License.
|
||||
*
|
||||
* The Original Code is Mozilla Communicator client code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are Copyright (C) 1998
|
||||
* Netscape Communications Corporation. All Rights Reserved.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is part of the Java-vendor-neutral implementation of LiveConnect
|
||||
*
|
||||
* It contains the code used to reflect Java fields as properties of
|
||||
* JavaObject objects and the code to access those fields.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "jsj_private.h" /* LiveConnect internals */
|
||||
|
||||
/*
|
||||
* Add a single field, described by java_field, to the JavaMemberDescriptor
|
||||
* named by field_name within the given JavaClassDescriptor.
|
||||
*
|
||||
* Returns JS_TRUE on success. Otherwise, returns JS_FALSE and reports an error.
|
||||
*/
|
||||
static JSBool
|
||||
add_java_field_to_class_descriptor(JSContext *cx,
|
||||
JNIEnv *jEnv,
|
||||
JavaClassDescriptor *class_descriptor,
|
||||
jstring field_name_jstr,
|
||||
jobject java_field, /* a java.lang.reflect.Field */
|
||||
jint modifiers)
|
||||
{
|
||||
jclass fieldType;
|
||||
jfieldID fieldID;
|
||||
jclass java_class;
|
||||
|
||||
JSBool is_static_field;
|
||||
JavaMemberDescriptor *member_descriptor = NULL;
|
||||
const char *sig_cstr = NULL;
|
||||
const char *field_name = NULL;
|
||||
JavaSignature *signature = NULL;
|
||||
JavaFieldSpec *field_spec = NULL;
|
||||
|
||||
is_static_field = modifiers & ACC_STATIC;
|
||||
if (is_static_field) {
|
||||
member_descriptor = jsj_GetJavaStaticMemberDescriptor(cx, jEnv, class_descriptor, field_name_jstr);
|
||||
} else {
|
||||
member_descriptor = jsj_GetJavaMemberDescriptor(cx, jEnv, class_descriptor, field_name_jstr);
|
||||
}
|
||||
if (!member_descriptor)
|
||||
goto error;
|
||||
|
||||
field_spec = (JavaFieldSpec*)JS_malloc(cx, sizeof(JavaFieldSpec));
|
||||
if (!field_spec)
|
||||
goto error;
|
||||
|
||||
field_spec->modifiers = modifiers;
|
||||
|
||||
/* Get the Java class corresponding to the type of the field */
|
||||
fieldType = (*jEnv)->CallObjectMethod(jEnv, java_field, jlrField_getType);
|
||||
if (!fieldType) {
|
||||
jsj_UnexpectedJavaError(cx, jEnv,
|
||||
"Unable to determine type of field using"
|
||||
" java.lang.reflect.Field.getType()");
|
||||
goto error;
|
||||
}
|
||||
|
||||
signature = jsj_GetJavaClassDescriptor(cx, jEnv, fieldType);
|
||||
if (!signature)
|
||||
goto error;
|
||||
field_spec->signature = signature;
|
||||
|
||||
field_name = jsj_DupJavaStringUTF(cx, jEnv, field_name_jstr);
|
||||
if (!field_name)
|
||||
goto error;
|
||||
field_spec->name = field_name;
|
||||
|
||||
/* Compute the JNI-style (string-based) signature of the field type */
|
||||
sig_cstr = jsj_ConvertJavaSignatureToString(cx, signature);
|
||||
if (!sig_cstr)
|
||||
goto error;
|
||||
|
||||
/* Compute the JNI fieldID and cache it for quick field access */
|
||||
java_class = class_descriptor->java_class;
|
||||
if (is_static_field)
|
||||
fieldID = (*jEnv)->GetStaticFieldID(jEnv, java_class, field_name, sig_cstr);
|
||||
else
|
||||
fieldID = (*jEnv)->GetFieldID(jEnv, java_class, field_name, sig_cstr);
|
||||
if (!fieldID) {
|
||||
jsj_UnexpectedJavaError(cx, jEnv,
|
||||
"Can't get Java field ID for class %s, field %s (sig=%s)",
|
||||
class_descriptor->name, field_name, sig_cstr);
|
||||
goto error;
|
||||
}
|
||||
field_spec->fieldID = fieldID;
|
||||
|
||||
JS_free(cx, (char*)sig_cstr);
|
||||
|
||||
member_descriptor->field = field_spec;
|
||||
|
||||
/* Success */
|
||||
return JS_TRUE;
|
||||
|
||||
error:
|
||||
if (field_spec) {
|
||||
JS_FREE_IF(cx, (char*)field_spec->name);
|
||||
JS_free(cx, field_spec);
|
||||
}
|
||||
JS_FREE_IF(cx, (char*)sig_cstr);
|
||||
if (signature)
|
||||
jsj_ReleaseJavaClassDescriptor(cx, jEnv, signature);
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Free up a JavaFieldSpec and all its resources.
|
||||
*/
|
||||
void
|
||||
jsj_DestroyFieldSpec(JSContext *cx, JNIEnv *jEnv, JavaFieldSpec *field)
|
||||
{
|
||||
JS_FREE_IF(cx, (char*)field->name);
|
||||
jsj_ReleaseJavaClassDescriptor(cx, jEnv, field->signature);
|
||||
JS_free(cx, field);
|
||||
}
|
||||
|
||||
/*
|
||||
* Add a JavaMemberDescriptor to the collection of members in class_descriptor
|
||||
* for every public field of the identified Java class. (A separate collection
|
||||
* is kept in class_descriptor for static and instance members.)
|
||||
* If reflect_only_static_fields is set, instance fields are not reflected. If
|
||||
* it isn't set, only instance fields are reflected and static fields are not
|
||||
* reflected.
|
||||
*
|
||||
* Returns JS_TRUE on success. Otherwise, returns JS_FALSE and reports an error.
|
||||
*/
|
||||
JSBool
|
||||
jsj_ReflectJavaFields(JSContext *cx, JNIEnv *jEnv, JavaClassDescriptor *class_descriptor,
|
||||
JSBool reflect_only_static_fields)
|
||||
{
|
||||
int i;
|
||||
JSBool ok;
|
||||
jint modifiers;
|
||||
jobject java_field;
|
||||
jstring field_name_jstr;
|
||||
jarray joFieldArray;
|
||||
jsize num_fields;
|
||||
jclass java_class;
|
||||
|
||||
/* Get a java array of java.lang.reflect.Field objects, by calling
|
||||
java.lang.Class.getFields(). */
|
||||
java_class = class_descriptor->java_class;
|
||||
joFieldArray = (*jEnv)->CallObjectMethod(jEnv, java_class, jlClass_getFields);
|
||||
if (!joFieldArray) {
|
||||
jsj_UnexpectedJavaError(cx, jEnv,
|
||||
"Can't determine Java object's fields "
|
||||
"using java.lang.Class.getFields()");
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
/* Iterate over the class fields */
|
||||
num_fields = (*jEnv)->GetArrayLength(jEnv, joFieldArray);
|
||||
for (i = 0; i < num_fields; i++) {
|
||||
|
||||
/* Get the i'th reflected field */
|
||||
java_field = (*jEnv)->GetObjectArrayElement(jEnv, joFieldArray, i);
|
||||
if (!java_field) {
|
||||
jsj_UnexpectedJavaError(cx, jEnv, "Can't access a Field[] array");
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
/* Get the field modifiers, e.g. static, public, private, etc. */
|
||||
modifiers = (*jEnv)->CallIntMethod(jEnv, java_field, jlrField_getModifiers);
|
||||
if ((*jEnv)->ExceptionOccurred(jEnv)) {
|
||||
jsj_UnexpectedJavaError(cx, jEnv,
|
||||
"Can't access a Field's modifiers using"
|
||||
"java.lang.reflect.Field.getModifiers()");
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
/* Don't allow access to private or protected Java fields. */
|
||||
if (!(modifiers & ACC_PUBLIC))
|
||||
continue;
|
||||
|
||||
/* Reflect all instance fields or all static fields, but not both */
|
||||
if (reflect_only_static_fields != ((modifiers & ACC_STATIC) != 0))
|
||||
continue;
|
||||
|
||||
/* Determine the unqualified name of the field */
|
||||
field_name_jstr = (*jEnv)->CallObjectMethod(jEnv, java_field, jlrField_getName);
|
||||
if (!field_name_jstr) {
|
||||
jsj_UnexpectedJavaError(cx, jEnv,
|
||||
"Can't obtain a Field's name"
|
||||
"java.lang.reflect.Field.getName()");
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
/* Add a JavaFieldSpec object to the JavaClassDescriptor */
|
||||
ok = add_java_field_to_class_descriptor(cx, jEnv, class_descriptor, field_name_jstr,
|
||||
java_field, modifiers);
|
||||
if (!ok)
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
/* Success */
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read the value of a Java field and return it as a JavaScript value.
|
||||
* If the field is static, then java_obj is a Java class, otherwise
|
||||
* it's a Java instance object.
|
||||
*
|
||||
* Returns JS_TRUE on success. Otherwise, returns JS_FALSE and reports an error.
|
||||
*/
|
||||
JSBool
|
||||
jsj_GetJavaFieldValue(JSContext *cx, JNIEnv *jEnv, JavaFieldSpec *field_spec,
|
||||
jobject java_obj, jsval *vp)
|
||||
{
|
||||
JSBool is_static_field;
|
||||
jvalue java_value;
|
||||
JavaSignature *signature;
|
||||
JavaSignatureChar field_type;
|
||||
jfieldID fieldID = field_spec->fieldID;
|
||||
|
||||
is_static_field = field_spec->modifiers & ACC_STATIC;
|
||||
|
||||
#define GET_JAVA_FIELD(Type,member) \
|
||||
PR_BEGIN_MACRO \
|
||||
if (is_static_field) \
|
||||
java_value.member = \
|
||||
(*jEnv)->GetStatic##Type##Field(jEnv, java_obj, fieldID); \
|
||||
else \
|
||||
java_value.member = \
|
||||
(*jEnv)->Get##Type##Field(jEnv, java_obj, fieldID); \
|
||||
if ((*jEnv)->ExceptionOccurred(jEnv)) { \
|
||||
jsj_UnexpectedJavaError(cx, jEnv, "Error reading Java field"); \
|
||||
return JS_FALSE; \
|
||||
} \
|
||||
PR_END_MACRO
|
||||
|
||||
signature = field_spec->signature;
|
||||
field_type = signature->type;
|
||||
switch(field_type) {
|
||||
case JAVA_SIGNATURE_BYTE:
|
||||
GET_JAVA_FIELD(Byte,b);
|
||||
break;
|
||||
|
||||
case JAVA_SIGNATURE_CHAR:
|
||||
GET_JAVA_FIELD(Char,c);
|
||||
break;
|
||||
|
||||
case JAVA_SIGNATURE_SHORT:
|
||||
GET_JAVA_FIELD(Short,s);
|
||||
break;
|
||||
|
||||
case JAVA_SIGNATURE_INT:
|
||||
GET_JAVA_FIELD(Int,i);
|
||||
break;
|
||||
|
||||
case JAVA_SIGNATURE_BOOLEAN:
|
||||
GET_JAVA_FIELD(Boolean,z);
|
||||
break;
|
||||
|
||||
case JAVA_SIGNATURE_LONG:
|
||||
GET_JAVA_FIELD(Long,j);
|
||||
break;
|
||||
|
||||
case JAVA_SIGNATURE_FLOAT:
|
||||
GET_JAVA_FIELD(Float,f);
|
||||
break;
|
||||
|
||||
case JAVA_SIGNATURE_DOUBLE:
|
||||
GET_JAVA_FIELD(Double,d);
|
||||
break;
|
||||
|
||||
case JAVA_SIGNATURE_CLASS:
|
||||
case JAVA_SIGNATURE_ARRAY:
|
||||
GET_JAVA_FIELD(Object,l);
|
||||
break;
|
||||
|
||||
#undef GET_JAVA_FIELD
|
||||
default:
|
||||
PR_ASSERT(0); /* Unknown java type signature */
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
return jsj_ConvertJavaValueToJSValue(cx, jEnv, signature, &java_value, vp);
|
||||
}
|
||||
|
||||
JSBool
|
||||
jsj_SetJavaFieldValue(JSContext *cx, JNIEnv *jEnv, JavaFieldSpec *field_spec,
|
||||
jclass java_obj, jsval js_val)
|
||||
{
|
||||
JSBool is_static_field, is_local_ref;
|
||||
int dummy_cost;
|
||||
jvalue java_value;
|
||||
JavaSignature *signature;
|
||||
JavaSignatureChar field_type;
|
||||
jfieldID fieldID = field_spec->fieldID;
|
||||
|
||||
is_static_field = field_spec->modifiers & ACC_STATIC;
|
||||
|
||||
#define SET_JAVA_FIELD(Type,member) \
|
||||
PR_BEGIN_MACRO \
|
||||
if (is_static_field) { \
|
||||
(*jEnv)->SetStatic##Type##Field(jEnv, java_obj, fieldID, \
|
||||
java_value.member); \
|
||||
} else { \
|
||||
(*jEnv)->Set##Type##Field(jEnv, java_obj, fieldID,java_value.member);\
|
||||
} \
|
||||
if ((*jEnv)->ExceptionOccurred(jEnv)) { \
|
||||
jsj_UnexpectedJavaError(cx, jEnv, "Error assigning to Java field"); \
|
||||
return JS_FALSE; \
|
||||
} \
|
||||
PR_END_MACRO
|
||||
|
||||
signature = field_spec->signature;
|
||||
if (!jsj_ConvertJSValueToJavaValue(cx, jEnv, js_val, signature, &dummy_cost,
|
||||
&java_value, &is_local_ref))
|
||||
return JS_FALSE;
|
||||
|
||||
field_type = signature->type;
|
||||
switch(field_type) {
|
||||
case JAVA_SIGNATURE_BYTE:
|
||||
SET_JAVA_FIELD(Byte,b);
|
||||
break;
|
||||
|
||||
case JAVA_SIGNATURE_CHAR:
|
||||
SET_JAVA_FIELD(Char,c);
|
||||
break;
|
||||
|
||||
case JAVA_SIGNATURE_SHORT:
|
||||
SET_JAVA_FIELD(Short,s);
|
||||
break;
|
||||
|
||||
case JAVA_SIGNATURE_INT:
|
||||
SET_JAVA_FIELD(Int,i);
|
||||
break;
|
||||
|
||||
case JAVA_SIGNATURE_BOOLEAN:
|
||||
SET_JAVA_FIELD(Boolean,z);
|
||||
break;
|
||||
|
||||
case JAVA_SIGNATURE_LONG:
|
||||
SET_JAVA_FIELD(Long,j);
|
||||
break;
|
||||
|
||||
case JAVA_SIGNATURE_FLOAT:
|
||||
SET_JAVA_FIELD(Float,f);
|
||||
break;
|
||||
|
||||
case JAVA_SIGNATURE_DOUBLE:
|
||||
SET_JAVA_FIELD(Double,d);
|
||||
break;
|
||||
|
||||
case JAVA_SIGNATURE_CLASS:
|
||||
case JAVA_SIGNATURE_ARRAY:
|
||||
SET_JAVA_FIELD(Object,l);
|
||||
if (is_local_ref)
|
||||
(*jEnv)->DeleteLocalRef(jEnv, java_value.l);
|
||||
break;
|
||||
|
||||
#undef SET_JAVA_FIELD
|
||||
default:
|
||||
PR_ASSERT(0); /* Unknown java type signature */
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
return JS_TRUE;
|
||||
}
|
||||
487
mozilla/js/src/liveconnect/jsj_hash.c
Normal file
@@ -0,0 +1,487 @@
|
||||
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.0 (the "License"); you may not use this file except in
|
||||
* compliance with the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
* the License for the specific language governing rights and limitations
|
||||
* under the License.
|
||||
*
|
||||
* The Original Code is Mozilla Communicator client code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are Copyright (C) 1998
|
||||
* Netscape Communications Corporation. All Rights Reserved.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This is a copy of the NSPR hash-table library, but it has been slightly
|
||||
* modified to allow an additional argument to be passed into the hash
|
||||
* key-comparision function. This is used to maintain thread-safety by
|
||||
* passing in a JNIEnv pointer to the key-comparison function rather
|
||||
* than storing it in a global. All types,function names, etc. have
|
||||
* been renamed from their original NSPR names to protect the innocent.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "jsj_hash.h"
|
||||
#include "prtypes.h"
|
||||
#ifdef NSPR20
|
||||
# include "prlog.h"
|
||||
# include "prbit.h"
|
||||
#else
|
||||
# include "prassert.h"
|
||||
#endif
|
||||
|
||||
/* Compute the number of buckets in ht */
|
||||
#define NBUCKETS(ht) (1 << (JSJ_HASH_BITS - (ht)->shift))
|
||||
|
||||
/* The smallest table has 16 buckets */
|
||||
#define MINBUCKETSLOG2 4
|
||||
#define MINBUCKETS (1 << MINBUCKETSLOG2)
|
||||
|
||||
/* Compute the maximum entries given n buckets that we will tolerate, ~90% */
|
||||
#define OVERLOADED(n) ((n) - ((n) >> 3))
|
||||
|
||||
/* Compute the number of entries below which we shrink the table by half */
|
||||
#define UNDERLOADED(n) (((n) > MINBUCKETS) ? ((n) >> 2) : 0)
|
||||
|
||||
/*
|
||||
** Stubs for default hash allocator ops.
|
||||
*/
|
||||
static void *
|
||||
DefaultAllocTable(void *pool, size_t size)
|
||||
{
|
||||
#if defined(XP_MAC)
|
||||
#pragma unused (pool)
|
||||
#endif
|
||||
|
||||
return malloc(size);
|
||||
}
|
||||
|
||||
static void
|
||||
DefaultFreeTable(void *pool, void *item)
|
||||
{
|
||||
#if defined(XP_MAC)
|
||||
#pragma unused (pool)
|
||||
#endif
|
||||
|
||||
free(item);
|
||||
}
|
||||
|
||||
static JSJHashEntry *
|
||||
DefaultAllocEntry(void *pool, const void *key)
|
||||
{
|
||||
#if defined(XP_MAC)
|
||||
#pragma unused (pool,key)
|
||||
#endif
|
||||
|
||||
return malloc(sizeof(JSJHashEntry));
|
||||
}
|
||||
|
||||
static void
|
||||
DefaultFreeEntry(void *pool, JSJHashEntry *he, PRUintn flag)
|
||||
{
|
||||
#if defined(XP_MAC)
|
||||
#pragma unused (pool)
|
||||
#endif
|
||||
|
||||
if (flag == HT_FREE_ENTRY)
|
||||
free(he);
|
||||
}
|
||||
|
||||
static JSJHashAllocOps defaultHashAllocOps = {
|
||||
DefaultAllocTable, DefaultFreeTable,
|
||||
DefaultAllocEntry, DefaultFreeEntry
|
||||
};
|
||||
|
||||
PR_IMPLEMENT(JSJHashTable *)
|
||||
JSJ_NewHashTable(PRUint32 n, JSJHashFunction keyHash,
|
||||
JSJHashComparator keyCompare, JSJHashComparator valueCompare,
|
||||
JSJHashAllocOps *allocOps, void *allocPriv)
|
||||
{
|
||||
JSJHashTable *ht;
|
||||
PRUint32 nb;
|
||||
|
||||
if (n <= MINBUCKETS) {
|
||||
n = MINBUCKETSLOG2;
|
||||
} else {
|
||||
n = PR_CeilingLog2(n);
|
||||
if ((PRInt32)n < 0)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!allocOps) allocOps = &defaultHashAllocOps;
|
||||
|
||||
ht = (*allocOps->allocTable)(allocPriv, sizeof *ht);
|
||||
if (!ht)
|
||||
return 0;
|
||||
memset(ht, 0, sizeof *ht);
|
||||
ht->shift = JSJ_HASH_BITS - n;
|
||||
n = 1 << n;
|
||||
#if defined(XP_PC) && !defined(_WIN32)
|
||||
if (n > 16000) {
|
||||
(*allocOps->freeTable)(allocPriv, ht);
|
||||
return 0;
|
||||
}
|
||||
#endif /* WIN16 */
|
||||
nb = n * sizeof(JSJHashEntry *);
|
||||
ht->buckets = (*allocOps->allocTable)(allocPriv, nb);
|
||||
if (!ht->buckets) {
|
||||
(*allocOps->freeTable)(allocPriv, ht);
|
||||
return 0;
|
||||
}
|
||||
memset(ht->buckets, 0, nb);
|
||||
|
||||
ht->keyHash = keyHash;
|
||||
ht->keyCompare = keyCompare;
|
||||
ht->valueCompare = valueCompare;
|
||||
ht->allocOps = allocOps;
|
||||
ht->allocPriv = allocPriv;
|
||||
return ht;
|
||||
}
|
||||
|
||||
PR_IMPLEMENT(void)
|
||||
JSJ_HashTableDestroy(JSJHashTable *ht)
|
||||
{
|
||||
PRUint32 i, n;
|
||||
JSJHashEntry *he, *next;
|
||||
JSJHashAllocOps *allocOps = ht->allocOps;
|
||||
void *allocPriv = ht->allocPriv;
|
||||
|
||||
n = NBUCKETS(ht);
|
||||
for (i = 0; i < n; i++) {
|
||||
for (he = ht->buckets[i]; he; he = next) {
|
||||
next = he->next;
|
||||
(*allocOps->freeEntry)(allocPriv, he, HT_FREE_ENTRY);
|
||||
}
|
||||
}
|
||||
#ifdef DEBUG
|
||||
memset(ht->buckets, 0xDB, n * sizeof ht->buckets[0]);
|
||||
#endif
|
||||
(*allocOps->freeTable)(allocPriv, ht->buckets);
|
||||
#ifdef DEBUG
|
||||
memset(ht, 0xDB, sizeof *ht);
|
||||
#endif
|
||||
(*allocOps->freeTable)(allocPriv, ht);
|
||||
}
|
||||
|
||||
/*
|
||||
** Multiplicative hash, from Knuth 6.4.
|
||||
*/
|
||||
#define GOLDEN_RATIO 0x9E3779B9U
|
||||
|
||||
PR_IMPLEMENT(JSJHashEntry **)
|
||||
JSJ_HashTableRawLookup(JSJHashTable *ht, JSJHashNumber keyHash, const void *key, void *arg)
|
||||
{
|
||||
JSJHashEntry *he, **hep, **hep0;
|
||||
JSJHashNumber h;
|
||||
|
||||
#ifdef HASHMETER
|
||||
ht->nlookups++;
|
||||
#endif
|
||||
h = keyHash * GOLDEN_RATIO;
|
||||
h >>= ht->shift;
|
||||
hep = hep0 = &ht->buckets[h];
|
||||
while ((he = *hep) != 0) {
|
||||
if (he->keyHash == keyHash && (*ht->keyCompare)(key, he->key, arg)) {
|
||||
/* Move to front of chain if not already there */
|
||||
if (hep != hep0) {
|
||||
*hep = he->next;
|
||||
he->next = *hep0;
|
||||
*hep0 = he;
|
||||
}
|
||||
return hep0;
|
||||
}
|
||||
hep = &he->next;
|
||||
#ifdef HASHMETER
|
||||
ht->nsteps++;
|
||||
#endif
|
||||
}
|
||||
return hep;
|
||||
}
|
||||
|
||||
PR_IMPLEMENT(JSJHashEntry *)
|
||||
JSJ_HashTableRawAdd(JSJHashTable *ht, JSJHashEntry **hep,
|
||||
JSJHashNumber keyHash, const void *key, void *value,
|
||||
void *arg)
|
||||
{
|
||||
PRUint32 i, n;
|
||||
JSJHashEntry *he, *next, **oldbuckets;
|
||||
PRUint32 nb;
|
||||
|
||||
/* Grow the table if it is overloaded */
|
||||
n = NBUCKETS(ht);
|
||||
if (ht->nentries >= OVERLOADED(n)) {
|
||||
#ifdef HASHMETER
|
||||
ht->ngrows++;
|
||||
#endif
|
||||
ht->shift--;
|
||||
oldbuckets = ht->buckets;
|
||||
#if defined(XP_PC) && !defined(_WIN32)
|
||||
if (2 * n > 16000)
|
||||
return 0;
|
||||
#endif /* WIN16 */
|
||||
nb = 2 * n * sizeof(JSJHashEntry *);
|
||||
ht->buckets = (*ht->allocOps->allocTable)(ht->allocPriv, nb);
|
||||
if (!ht->buckets) {
|
||||
ht->buckets = oldbuckets;
|
||||
return 0;
|
||||
}
|
||||
memset(ht->buckets, 0, nb);
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
for (he = oldbuckets[i]; he; he = next) {
|
||||
next = he->next;
|
||||
hep = JSJ_HashTableRawLookup(ht, he->keyHash, he->key, arg);
|
||||
PR_ASSERT(*hep == 0);
|
||||
he->next = 0;
|
||||
*hep = he;
|
||||
}
|
||||
}
|
||||
#ifdef DEBUG
|
||||
memset(oldbuckets, 0xDB, n * sizeof oldbuckets[0]);
|
||||
#endif
|
||||
(*ht->allocOps->freeTable)(ht->allocPriv, oldbuckets);
|
||||
hep = JSJ_HashTableRawLookup(ht, keyHash, key, arg);
|
||||
}
|
||||
|
||||
/* Make a new key value entry */
|
||||
he = (*ht->allocOps->allocEntry)(ht->allocPriv, key);
|
||||
if (!he)
|
||||
return 0;
|
||||
he->keyHash = keyHash;
|
||||
he->key = key;
|
||||
he->value = value;
|
||||
he->next = *hep;
|
||||
*hep = he;
|
||||
ht->nentries++;
|
||||
return he;
|
||||
}
|
||||
|
||||
PR_IMPLEMENT(JSJHashEntry *)
|
||||
JSJ_HashTableAdd(JSJHashTable *ht, const void *key, void *value, void *arg)
|
||||
{
|
||||
JSJHashNumber keyHash;
|
||||
JSJHashEntry *he, **hep;
|
||||
|
||||
keyHash = (*ht->keyHash)(key, arg);
|
||||
hep = JSJ_HashTableRawLookup(ht, keyHash, key, arg);
|
||||
if ((he = *hep) != 0) {
|
||||
/* Hit; see if values match */
|
||||
if ((*ht->valueCompare)(he->value, value, arg)) {
|
||||
/* key,value pair is already present in table */
|
||||
return he;
|
||||
}
|
||||
if (he->value)
|
||||
(*ht->allocOps->freeEntry)(ht->allocPriv, he, HT_FREE_VALUE);
|
||||
he->value = value;
|
||||
return he;
|
||||
}
|
||||
return JSJ_HashTableRawAdd(ht, hep, keyHash, key, value, arg);
|
||||
}
|
||||
|
||||
PR_IMPLEMENT(void)
|
||||
JSJ_HashTableRawRemove(JSJHashTable *ht, JSJHashEntry **hep, JSJHashEntry *he, void *arg)
|
||||
{
|
||||
PRUint32 i, n;
|
||||
JSJHashEntry *next, **oldbuckets;
|
||||
PRUint32 nb;
|
||||
|
||||
*hep = he->next;
|
||||
(*ht->allocOps->freeEntry)(ht->allocPriv, he, HT_FREE_ENTRY);
|
||||
|
||||
/* Shrink table if it's underloaded */
|
||||
n = NBUCKETS(ht);
|
||||
if (--ht->nentries < UNDERLOADED(n)) {
|
||||
#ifdef HASHMETER
|
||||
ht->nshrinks++;
|
||||
#endif
|
||||
ht->shift++;
|
||||
oldbuckets = ht->buckets;
|
||||
nb = n * sizeof(JSJHashEntry*) / 2;
|
||||
ht->buckets = (*ht->allocOps->allocTable)(ht->allocPriv, nb);
|
||||
if (!ht->buckets) {
|
||||
ht->buckets = oldbuckets;
|
||||
return;
|
||||
}
|
||||
memset(ht->buckets, 0, nb);
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
for (he = oldbuckets[i]; he; he = next) {
|
||||
next = he->next;
|
||||
hep = JSJ_HashTableRawLookup(ht, he->keyHash, he->key, arg);
|
||||
PR_ASSERT(*hep == 0);
|
||||
he->next = 0;
|
||||
*hep = he;
|
||||
}
|
||||
}
|
||||
#ifdef DEBUG
|
||||
memset(oldbuckets, 0xDB, n * sizeof oldbuckets[0]);
|
||||
#endif
|
||||
(*ht->allocOps->freeTable)(ht->allocPriv, oldbuckets);
|
||||
}
|
||||
}
|
||||
|
||||
PR_IMPLEMENT(PRBool)
|
||||
JSJ_HashTableRemove(JSJHashTable *ht, const void *key, void *arg)
|
||||
{
|
||||
JSJHashNumber keyHash;
|
||||
JSJHashEntry *he, **hep;
|
||||
|
||||
keyHash = (*ht->keyHash)(key, arg);
|
||||
hep = JSJ_HashTableRawLookup(ht, keyHash, key, arg);
|
||||
if ((he = *hep) == 0)
|
||||
return PR_FALSE;
|
||||
|
||||
/* Hit; remove element */
|
||||
JSJ_HashTableRawRemove(ht, hep, he, arg);
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
PR_IMPLEMENT(void *)
|
||||
JSJ_HashTableLookup(JSJHashTable *ht, const void *key, void *arg)
|
||||
{
|
||||
JSJHashNumber keyHash;
|
||||
JSJHashEntry *he, **hep;
|
||||
|
||||
keyHash = (*ht->keyHash)(key, arg);
|
||||
hep = JSJ_HashTableRawLookup(ht, keyHash, key, arg);
|
||||
if ((he = *hep) != 0) {
|
||||
return he->value;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Iterate over the entries in the hash table calling func for each
|
||||
** entry found. Stop if "f" says to (return value & PR_ENUMERATE_STOP).
|
||||
** Return a count of the number of elements scanned.
|
||||
*/
|
||||
PR_IMPLEMENT(int)
|
||||
JSJ_HashTableEnumerateEntries(JSJHashTable *ht, JSJHashEnumerator f, void *arg)
|
||||
{
|
||||
JSJHashEntry *he, **hep;
|
||||
PRUint32 i, nbuckets;
|
||||
int rv, n = 0;
|
||||
JSJHashEntry *todo = 0;
|
||||
|
||||
nbuckets = NBUCKETS(ht);
|
||||
for (i = 0; i < nbuckets; i++) {
|
||||
hep = &ht->buckets[i];
|
||||
while ((he = *hep) != 0) {
|
||||
rv = (*f)(he, n, arg);
|
||||
n++;
|
||||
if (rv & (HT_ENUMERATE_REMOVE | HT_ENUMERATE_UNHASH)) {
|
||||
*hep = he->next;
|
||||
if (rv & HT_ENUMERATE_REMOVE) {
|
||||
he->next = todo;
|
||||
todo = he;
|
||||
}
|
||||
} else {
|
||||
hep = &he->next;
|
||||
}
|
||||
if (rv & HT_ENUMERATE_STOP) {
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
hep = &todo;
|
||||
while ((he = *hep) != 0) {
|
||||
JSJ_HashTableRawRemove(ht, hep, he, arg);
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
#ifdef HASHMETER
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
|
||||
PR_IMPLEMENT(void)
|
||||
JSJ_HashTableDumpMeter(JSJHashTable *ht, JSJHashEnumerator dump, FILE *fp)
|
||||
{
|
||||
double mean, variance;
|
||||
PRUint32 nchains, nbuckets;
|
||||
PRUint32 i, n, maxChain, maxChainLen;
|
||||
JSJHashEntry *he;
|
||||
|
||||
variance = 0;
|
||||
nchains = 0;
|
||||
maxChainLen = 0;
|
||||
nbuckets = NBUCKETS(ht);
|
||||
for (i = 0; i < nbuckets; i++) {
|
||||
he = ht->buckets[i];
|
||||
if (!he)
|
||||
continue;
|
||||
nchains++;
|
||||
for (n = 0; he; he = he->next)
|
||||
n++;
|
||||
variance += n * n;
|
||||
if (n > maxChainLen) {
|
||||
maxChainLen = n;
|
||||
maxChain = i;
|
||||
}
|
||||
}
|
||||
mean = (double)ht->nentries / nchains;
|
||||
variance = fabs(variance / nchains - mean * mean);
|
||||
|
||||
fprintf(fp, "\nHash table statistics:\n");
|
||||
fprintf(fp, " number of lookups: %u\n", ht->nlookups);
|
||||
fprintf(fp, " number of entries: %u\n", ht->nentries);
|
||||
fprintf(fp, " number of grows: %u\n", ht->ngrows);
|
||||
fprintf(fp, " number of shrinks: %u\n", ht->nshrinks);
|
||||
fprintf(fp, " mean steps per hash: %g\n", (double)ht->nsteps
|
||||
/ ht->nlookups);
|
||||
fprintf(fp, "mean hash chain length: %g\n", mean);
|
||||
fprintf(fp, " standard deviation: %g\n", sqrt(variance));
|
||||
fprintf(fp, " max hash chain length: %u\n", maxChainLen);
|
||||
fprintf(fp, " max hash chain: [%u]\n", maxChain);
|
||||
|
||||
for (he = ht->buckets[maxChain], i = 0; he; he = he->next, i++)
|
||||
if ((*dump)(he, i, fp) != HT_ENUMERATE_NEXT)
|
||||
break;
|
||||
}
|
||||
#endif /* HASHMETER */
|
||||
|
||||
PR_IMPLEMENT(int)
|
||||
JSJ_HashTableDump(JSJHashTable *ht, JSJHashEnumerator dump, FILE *fp)
|
||||
{
|
||||
int count;
|
||||
|
||||
count = JSJ_HashTableEnumerateEntries(ht, dump, fp);
|
||||
#ifdef HASHMETER
|
||||
JSJ_HashTableDumpMeter(ht, dump, fp);
|
||||
#endif
|
||||
return count;
|
||||
}
|
||||
|
||||
PR_IMPLEMENT(JSJHashNumber)
|
||||
JSJ_HashString(const void *key)
|
||||
{
|
||||
JSJHashNumber h;
|
||||
const unsigned char *s;
|
||||
|
||||
h = 0;
|
||||
for (s = key; *s; s++)
|
||||
h = (h >> 28) ^ (h << 4) ^ *s;
|
||||
return h;
|
||||
}
|
||||
|
||||
PR_IMPLEMENT(int)
|
||||
JSJ_CompareStrings(const void *v1, const void *v2)
|
||||
{
|
||||
return strcmp(v1, v2) == 0;
|
||||
}
|
||||
|
||||
PR_IMPLEMENT(int)
|
||||
JSJ_CompareValues(const void *v1, const void *v2)
|
||||
{
|
||||
return v1 == v2;
|
||||
}
|
||||
141
mozilla/js/src/liveconnect/jsj_hash.h
Normal file
@@ -0,0 +1,141 @@
|
||||
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.0 (the "License"); you may not use this file except in
|
||||
* compliance with the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
* the License for the specific language governing rights and limitations
|
||||
* under the License.
|
||||
*
|
||||
* The Original Code is Mozilla Communicator client code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are Copyright (C) 1998
|
||||
* Netscape Communications Corporation. All Rights Reserved.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This is a copy of the NSPR hash-table library, but it has been slightly
|
||||
* modified to allow an additional argument to be passed into the hash
|
||||
* key-comparision function. This is used to maintain thread-safety by
|
||||
* passing in a JNIEnv pointer to the key-comparison function rather
|
||||
* than storing it in a global. All types,function names, etc. have
|
||||
* been renamed from their original NSPR names to protect the innocent.
|
||||
*/
|
||||
|
||||
#ifndef jsj_hash_h___
|
||||
#define jsj_hash_h___
|
||||
/*
|
||||
* API to portable hash table code.
|
||||
*/
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include "prtypes.h"
|
||||
|
||||
PR_BEGIN_EXTERN_C
|
||||
|
||||
typedef struct JSJHashEntry JSJHashEntry;
|
||||
typedef struct JSJHashTable JSJHashTable;
|
||||
typedef PRUint32 JSJHashNumber;
|
||||
#define JSJ_HASH_BITS 32
|
||||
typedef JSJHashNumber (*JSJHashFunction)(const void *key, void *arg);
|
||||
typedef PRIntn (*JSJHashComparator)(const void *v1, const void *v2, void *arg);
|
||||
typedef PRIntn (*JSJHashEnumerator)(JSJHashEntry *he, PRIntn i, void *arg);
|
||||
|
||||
/* Flag bits in JSJHashEnumerator's return value */
|
||||
#define HT_ENUMERATE_NEXT 0 /* continue enumerating entries */
|
||||
#define HT_ENUMERATE_STOP 1 /* stop enumerating entries */
|
||||
#define HT_ENUMERATE_REMOVE 2 /* remove and free the current entry */
|
||||
#define HT_ENUMERATE_UNHASH 4 /* just unhash the current entry */
|
||||
|
||||
typedef struct JSJHashAllocOps {
|
||||
void * (*allocTable)(void *pool, size_t size);
|
||||
void (*freeTable)(void *pool, void *item);
|
||||
JSJHashEntry * (*allocEntry)(void *pool, const void *key);
|
||||
void (*freeEntry)(void *pool, JSJHashEntry *he, PRUintn flag);
|
||||
} JSJHashAllocOps;
|
||||
|
||||
#define HT_FREE_VALUE 0 /* just free the entry's value */
|
||||
#define HT_FREE_ENTRY 1 /* free value and entire entry */
|
||||
|
||||
struct JSJHashEntry {
|
||||
JSJHashEntry *next; /* hash chain linkage */
|
||||
JSJHashNumber keyHash; /* key hash function result */
|
||||
const void *key; /* ptr to opaque key */
|
||||
void *value; /* ptr to opaque value */
|
||||
};
|
||||
|
||||
struct JSJHashTable {
|
||||
JSJHashEntry **buckets; /* vector of hash buckets */
|
||||
PRUint32 nentries; /* number of entries in table */
|
||||
PRUint32 shift; /* multiplicative hash shift */
|
||||
JSJHashFunction keyHash; /* key hash function */
|
||||
JSJHashComparator keyCompare; /* key comparison function */
|
||||
JSJHashComparator valueCompare; /* value comparison function */
|
||||
JSJHashAllocOps *allocOps; /* allocation operations */
|
||||
void *allocPriv; /* allocation private data */
|
||||
#ifdef HASHMETER
|
||||
PRUint32 nlookups; /* total number of lookups */
|
||||
PRUint32 nsteps; /* number of hash chains traversed */
|
||||
PRUint32 ngrows; /* number of table expansions */
|
||||
PRUint32 nshrinks; /* number of table contractions */
|
||||
#endif
|
||||
};
|
||||
|
||||
/*
|
||||
* Create a new hash table.
|
||||
* If allocOps is null, use default allocator ops built on top of malloc().
|
||||
*/
|
||||
PR_EXTERN(JSJHashTable *)
|
||||
JSJ_NewHashTable(PRUint32 n, JSJHashFunction keyHash,
|
||||
JSJHashComparator keyCompare, JSJHashComparator valueCompare,
|
||||
JSJHashAllocOps *allocOps, void *allocPriv);
|
||||
|
||||
PR_EXTERN(void)
|
||||
JSJ_HashTableDestroy(JSJHashTable *ht);
|
||||
|
||||
/* Low level access methods */
|
||||
PR_EXTERN(JSJHashEntry **)
|
||||
JSJ_HashTableRawLookup(JSJHashTable *ht, JSJHashNumber keyHash, const void *key, void *arg);
|
||||
|
||||
PR_EXTERN(JSJHashEntry *)
|
||||
JSJ_HashTableRawAdd(JSJHashTable *ht, JSJHashEntry **hep, JSJHashNumber keyHash,
|
||||
const void *key, void *value, void *arg);
|
||||
|
||||
PR_EXTERN(void)
|
||||
JSJ_HashTableRawRemove(JSJHashTable *ht, JSJHashEntry **hep, JSJHashEntry *he, void *arg);
|
||||
|
||||
/* Higher level access methods */
|
||||
PR_EXTERN(JSJHashEntry *)
|
||||
JSJ_HashTableAdd(JSJHashTable *ht, const void *key, void *value, void *arg);
|
||||
|
||||
PR_EXTERN(PRBool)
|
||||
JSJ_HashTableRemove(JSJHashTable *ht, const void *key, void *arg);
|
||||
|
||||
PR_EXTERN(PRIntn)
|
||||
JSJ_HashTableEnumerateEntries(JSJHashTable *ht, JSJHashEnumerator f, void *arg);
|
||||
|
||||
PR_EXTERN(void *)
|
||||
JSJ_HashTableLookup(JSJHashTable *ht, const void *key, void *arg);
|
||||
|
||||
PR_EXTERN(PRIntn)
|
||||
JSJ_HashTableDump(JSJHashTable *ht, JSJHashEnumerator dump, FILE *fp);
|
||||
|
||||
/* General-purpose C string hash function. */
|
||||
PR_EXTERN(JSJHashNumber)
|
||||
JSJ_HashString(const void *key);
|
||||
|
||||
/* Compare strings using strcmp(), return true if equal. */
|
||||
PR_EXTERN(int)
|
||||
JSJ_CompareStrings(const void *v1, const void *v2);
|
||||
|
||||
/* Stub function just returns v1 == v2 */
|
||||
PR_EXTERN(PRIntn)
|
||||
JSJ_CompareValues(const void *v1, const void *v2);
|
||||
|
||||
PR_END_EXTERN_C
|
||||
|
||||
#endif /* jsj_hash_h___ */
|
||||
1164
mozilla/js/src/liveconnect/jsj_method.c
Normal file
552
mozilla/js/src/liveconnect/jsj_private.h
Normal file
@@ -0,0 +1,552 @@
|
||||
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.0 (the "License"); you may not use this file except in
|
||||
* compliance with the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
* the License for the specific language governing rights and limitations
|
||||
* under the License.
|
||||
*
|
||||
* The Original Code is Mozilla Communicator client code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are Copyright (C) 1998
|
||||
* Netscape Communications Corporation. All Rights Reserved.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is part of the Java-vendor-neutral implementation of LiveConnect
|
||||
*
|
||||
* Declarations of private (internal) functions/data/types for
|
||||
* JavaScript <==> Java communication.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _JSJAVA_PVT_H
|
||||
#define _JSJAVA_PVT_H
|
||||
|
||||
#include "prtypes.h"
|
||||
|
||||
/* NSPR1 compatibility definitions */
|
||||
#ifdef NSPR20
|
||||
# include "prprf.h"
|
||||
# include "prlog.h"
|
||||
# include "plhash.h" /* NSPR hash-tables */
|
||||
#else
|
||||
# include "prprintf.h"
|
||||
# include "prassert.h"
|
||||
# include "prhash.h" /* NSPR hash-tables */
|
||||
# define PRHashNumber prhashcode
|
||||
#endif
|
||||
|
||||
#ifdef XP_MAC
|
||||
# include "prosdep.h"
|
||||
#endif
|
||||
|
||||
#include "jsj_hash.h" /* Hash tables */
|
||||
#include "jni.h" /* Java Native Interface */
|
||||
#include "jsapi.h" /* JavaScript engine API */
|
||||
#include "jsjava.h" /* LiveConnect public API */
|
||||
|
||||
|
||||
/*************************** Type Declarations ******************************/
|
||||
|
||||
/* Forward type declarations */
|
||||
typedef struct JavaMemberDescriptor JavaMemberDescriptor;
|
||||
typedef struct JavaMethodSpec JavaMethodSpec;
|
||||
typedef struct JavaClassDescriptor JavaClassDescriptor;
|
||||
typedef struct JavaClassDescriptor JavaSignature;
|
||||
typedef struct CapturedJSError CapturedJSError;
|
||||
typedef struct JavaMemberVal JavaMemberVal;
|
||||
|
||||
/*
|
||||
* This enum uses the same character encoding used by the JDK to encode
|
||||
* Java type signatures, but the enum is easier to debug/compile with.
|
||||
*/
|
||||
typedef enum {
|
||||
JAVA_SIGNATURE_ARRAY = '[',
|
||||
JAVA_SIGNATURE_BYTE = 'B',
|
||||
JAVA_SIGNATURE_CHAR = 'C',
|
||||
JAVA_SIGNATURE_CLASS = 'L',
|
||||
JAVA_SIGNATURE_FLOAT = 'F',
|
||||
JAVA_SIGNATURE_DOUBLE = 'D',
|
||||
JAVA_SIGNATURE_INT = 'I',
|
||||
JAVA_SIGNATURE_LONG = 'J',
|
||||
JAVA_SIGNATURE_SHORT = 'S',
|
||||
JAVA_SIGNATURE_VOID = 'V',
|
||||
JAVA_SIGNATURE_BOOLEAN = 'Z',
|
||||
JAVA_SIGNATURE_UNKNOWN = 0
|
||||
} JavaSignatureChar;
|
||||
|
||||
/* The signature of a Java method consists of the signatures of all its
|
||||
arguments and its return type signature. */
|
||||
typedef struct JavaMethodSignature {
|
||||
jsize num_args; /* Length of arg_signatures array */
|
||||
JavaSignature ** arg_signatures; /* Array of argument signatures */
|
||||
JavaSignature * return_val_signature; /* Return type signature */
|
||||
} JavaMethodSignature;
|
||||
|
||||
/* A descriptor for the reflection of a single Java field */
|
||||
typedef struct JavaFieldSpec {
|
||||
jfieldID fieldID; /* JVM opaque access handle for field */
|
||||
JavaSignature * signature; /* Java type of field */
|
||||
int modifiers; /* Bitfield indicating field qualifiers */
|
||||
const char * name; /* UTF8; TODO - Should support Unicode field names */
|
||||
} JavaFieldSpec;
|
||||
|
||||
/* A descriptor for the reflection of a single Java method.
|
||||
Each overloaded method has a separate corresponding JavaMethodSpec. */
|
||||
struct JavaMethodSpec {
|
||||
jmethodID methodID; /* JVM opaque access handle for method */
|
||||
JavaMethodSignature signature;
|
||||
const char * name; /* UTF8; TODO - Should support Unicode method names */
|
||||
JavaMethodSpec * next; /* next method in chain of overloaded methods */
|
||||
};
|
||||
|
||||
/*
|
||||
* A descriptor for the reflection of a single member of a Java object.
|
||||
* This can represent one or more Java methods and/or a single field.
|
||||
* (When there is more than one method attached to a single JavaMemberDescriptor
|
||||
* they are overloaded methods sharing the same simple name.) This same
|
||||
* descriptor type is used for both static or instance members.
|
||||
*/
|
||||
struct JavaMemberDescriptor {
|
||||
const char * name; /* simple name of field and/or method */
|
||||
jsid id; /* hashed name for quick JS property lookup */
|
||||
JavaFieldSpec * field; /* field with the given name, if any */
|
||||
JavaMethodSpec * methods; /* Overloaded methods which share the same name, if any */
|
||||
JavaMemberDescriptor * next; /* next descriptor in same defining class */
|
||||
JSObject * invoke_func_obj; /* If non-null, JSFunction obj to invoke method */
|
||||
};
|
||||
|
||||
/* This is the native portion of a reflected Java class */
|
||||
struct JavaClassDescriptor {
|
||||
const char * name; /* Name of class, e.g. "java/lang/Byte" */
|
||||
JavaSignatureChar type; /* class category: primitive type, object, array */
|
||||
jclass java_class; /* Opaque JVM handle to corresponding java.lang.Class */
|
||||
int num_instance_members;
|
||||
int num_static_members;
|
||||
JSBool instance_members_reflected;
|
||||
JavaMemberDescriptor * instance_members;
|
||||
JSBool static_members_reflected;
|
||||
JavaMemberDescriptor * static_members;
|
||||
JavaMemberDescriptor * constructors;
|
||||
int modifiers; /* Class declaration qualifiers,
|
||||
e.g. abstract, private */
|
||||
int ref_count; /* # of references to this struct */
|
||||
JavaSignature * array_component_signature; /* Only non-NULL for array classes */
|
||||
};
|
||||
|
||||
/* This is the native portion of a reflected Java method or field */
|
||||
struct JavaMemberVal {
|
||||
jsval field_val; /* Captured value of Java field */
|
||||
jsval invoke_method_func_val; /* JSFunction wrapper around Java method invoker */
|
||||
JavaMemberDescriptor * descriptor;
|
||||
JavaMemberVal * next;
|
||||
};
|
||||
|
||||
/* This is the native portion of a reflected Java object */
|
||||
typedef struct JavaObjectWrapper {
|
||||
jobject java_obj; /* Opaque JVM ref to Java object */
|
||||
JavaClassDescriptor * class_descriptor; /* Java class info */
|
||||
} JavaObjectWrapper;
|
||||
|
||||
/* These are definitions of the Java class/method/field modifier bits.
|
||||
These really shouldn't be hard-coded here. Rather,
|
||||
they should be read from java.lang.reflect.Modifier */
|
||||
#define ACC_PUBLIC 0x0001 /* visible to everyone */
|
||||
#define ACC_STATIC 0x0008 /* instance variable is static */
|
||||
#define ACC_FINAL 0x0010 /* no further subclassing,overriding */
|
||||
#define ACC_INTERFACE 0x0200 /* class is an interface */
|
||||
#define ACC_ABSTRACT 0x0400 /* no definition provided */
|
||||
|
||||
/* A JSJavaVM structure must be created for each Java VM that is accessed
|
||||
via LiveConnect */
|
||||
struct JSJavaVM {
|
||||
/* TODO - all LiveConnect global variables should be migrated into this
|
||||
structure in order to allow more than one LiveConnect-enabled
|
||||
Java VM to exist within the same process. */
|
||||
SystemJavaVM * java_vm;
|
||||
JNIEnv * main_thread_env; /* Main-thread Java environment */
|
||||
JSBool jsj_created_java_vm;
|
||||
int num_attached_threads;
|
||||
JSJavaVM * next; /* next VM among all created VMs */
|
||||
};
|
||||
|
||||
/* Per-thread state that encapsulates the connection to the Java VM */
|
||||
struct JSJavaThreadState {
|
||||
const char * name; /* Thread name, for debugging */
|
||||
JSJavaVM * jsjava_vm; /* All per-JVM state */
|
||||
JNIEnv * jEnv; /* Per-thread opaque handle to Java VM */
|
||||
CapturedJSError * pending_js_errors; /* JS errors to be thrown as Java exceptions */
|
||||
JSContext * cx; /* current JS context for thread */
|
||||
JSJavaThreadState * next; /* next thread state among all created threads */
|
||||
};
|
||||
|
||||
struct JavaToJSSavedState {
|
||||
JSErrorReporter error_reporter;
|
||||
JSJavaThreadState* java_jsj_env;
|
||||
};
|
||||
typedef struct JavaToJSSavedState JavaToJSSavedState;
|
||||
|
||||
|
||||
|
||||
/******************************** Globals ***********************************/
|
||||
|
||||
extern JSJCallbacks *JSJ_callbacks;
|
||||
|
||||
/* JavaScript classes that reflect Java objects */
|
||||
extern JSClass JavaObject_class;
|
||||
extern JSClass JavaArray_class;
|
||||
extern JSClass JavaClass_class;
|
||||
extern JSClass JavaMember_class;
|
||||
|
||||
/*
|
||||
* Opaque JVM handles to Java classes, methods and objects required for
|
||||
* Java reflection. These are computed and cached during initialization.
|
||||
* TODO: These should be moved inside the JSJavaVM struct
|
||||
*/
|
||||
extern jclass jlObject; /* java.lang.Object */
|
||||
extern jclass jlrConstructor; /* java.lang.reflect.Constructor */
|
||||
extern jclass jlThrowable; /* java.lang.Throwable */
|
||||
extern jclass jlSystem; /* java.lang.System */
|
||||
extern jclass jlClass; /* java.lang.Class */
|
||||
extern jclass jlBoolean; /* java.lang.Boolean */
|
||||
extern jclass jlDouble; /* java.lang.Double */
|
||||
extern jclass jlString; /* java.lang.String */
|
||||
extern jclass njJSObject; /* netscape.javascript.JSObject */
|
||||
extern jclass njJSException; /* netscape.javascript.JSException */
|
||||
extern jclass njJSUtil; /* netscape.javascript.JSUtil */
|
||||
|
||||
extern jmethodID jlClass_getMethods; /* java.lang.Class.getMethods() */
|
||||
extern jmethodID jlClass_getConstructors; /* java.lang.Class.getConstructors() */
|
||||
extern jmethodID jlClass_getFields; /* java.lang.Class.getFields() */
|
||||
extern jmethodID jlClass_getName; /* java.lang.Class.getName() */
|
||||
extern jmethodID jlClass_getComponentType; /* java.lang.Class.getComponentType() */
|
||||
extern jmethodID jlClass_getModifiers; /* java.lang.Class.getModifiers() */
|
||||
extern jmethodID jlClass_isArray; /* java.lang.Class.isArray() */
|
||||
|
||||
extern jmethodID jlrMethod_getName; /* java.lang.reflect.Method.getName() */
|
||||
extern jmethodID jlrMethod_getParameterTypes; /* java.lang.reflect.Method.getParameterTypes() */
|
||||
extern jmethodID jlrMethod_getReturnType; /* java.lang.reflect.Method.getReturnType() */
|
||||
extern jmethodID jlrMethod_getModifiers; /* java.lang.reflect.Method.getModifiers() */
|
||||
|
||||
extern jmethodID jlrConstructor_getParameterTypes; /* java.lang.reflect.Constructor.getParameterTypes() */
|
||||
extern jmethodID jlrConstructor_getModifiers; /* java.lang.reflect.Constructor.getModifiers() */
|
||||
|
||||
extern jmethodID jlrField_getName; /* java.lang.reflect.Field.getName() */
|
||||
extern jmethodID jlrField_getType; /* java.lang.reflect.Field.getType() */
|
||||
extern jmethodID jlrField_getModifiers; /* java.lang.reflect.Field.getModifiers() */
|
||||
|
||||
extern jmethodID jlThrowable_getMessage; /* java.lang.Throwable.getMessage() */
|
||||
extern jmethodID jlThrowable_toString; /* java.lang.Throwable.toString() */
|
||||
|
||||
extern jmethodID jlBoolean_Boolean; /* java.lang.Boolean constructor */
|
||||
extern jmethodID jlBoolean_booleanValue; /* java.lang.Boolean.booleanValue() */
|
||||
extern jmethodID jlDouble_Double; /* java.lang.Double constructor */
|
||||
extern jmethodID jlDouble_doubleValue; /* java.lang.Double.doubleValue() */
|
||||
|
||||
extern jmethodID jlSystem_identityHashCode; /* java.lang.System.identityHashCode() */
|
||||
|
||||
extern jobject jlVoid_TYPE; /* java.lang.Void.TYPE value */
|
||||
|
||||
extern jmethodID njJSException_JSException; /* netscape.javascipt.JSexception constructor */
|
||||
extern jmethodID njJSObject_JSObject; /* netscape.javascript.JSObject constructor */
|
||||
extern jmethodID njJSUtil_getStackTrace; /* netscape.javascript.JSUtil.getStackTrace() */
|
||||
extern jfieldID njJSObject_internal; /* netscape.javascript.JSObject.internal */
|
||||
extern jfieldID njJSException_lineno; /* netscape.javascript.JSException.lineno */
|
||||
extern jfieldID njJSException_tokenIndex; /* netscape.javascript.JSException.tokenIndex */
|
||||
extern jfieldID njJSException_source; /* netscape.javascript.JSException.source */
|
||||
extern jfieldID njJSException_filename; /* netscape.javascript.JSException.filename */
|
||||
|
||||
|
||||
/**************** Java <==> JS conversions and Java types *******************/
|
||||
extern JSBool
|
||||
jsj_ComputeJavaClassSignature(JSContext *cx,
|
||||
JavaSignature *signature,
|
||||
jclass java_class);
|
||||
|
||||
extern const char *
|
||||
jsj_ConvertJavaSignatureToString(JSContext *cx, JavaSignature *signature);
|
||||
extern const char *
|
||||
jsj_ConvertJavaSignatureToHRString(JSContext *cx,
|
||||
JavaSignature *signature);
|
||||
extern JavaMethodSignature *
|
||||
jsj_InitJavaMethodSignature(JSContext *cx, JNIEnv *jEnv, jobject method,
|
||||
JavaMethodSignature *method_signature);
|
||||
|
||||
extern const char *
|
||||
jsj_ConvertJavaMethodSignatureToString(JSContext *cx,
|
||||
JavaMethodSignature *method_signature);
|
||||
extern const char *
|
||||
jsj_ConvertJavaMethodSignatureToHRString(JSContext *cx,
|
||||
const char *method_name,
|
||||
JavaMethodSignature *method_signature);
|
||||
extern void
|
||||
jsj_PurgeJavaMethodSignature(JSContext *cx, JNIEnv *jEnv, JavaMethodSignature *signature);
|
||||
|
||||
extern JSBool
|
||||
jsj_ConvertJSValueToJavaValue(JSContext *cx, JNIEnv *jEnv, jsval v, JavaSignature *signature,
|
||||
int *cost, jvalue *java_value, JSBool *is_local_refp);
|
||||
extern JSBool
|
||||
jsj_ConvertJSValueToJavaObject(JSContext *cx, JNIEnv *jEnv, jsval v, JavaSignature *signature,
|
||||
int *cost, jobject *java_value, JSBool *is_local_refp);
|
||||
extern jstring
|
||||
jsj_ConvertJSStringToJavaString(JSContext *cx, JNIEnv *jEnv, JSString *js_str);
|
||||
|
||||
extern JSBool
|
||||
jsj_ConvertJavaValueToJSValue(JSContext *cx, JNIEnv *jEnv, JavaSignature *signature,
|
||||
jvalue *java_value, jsval *vp);
|
||||
extern JSBool
|
||||
jsj_ConvertJavaObjectToJSValue(JSContext *cx, JNIEnv *jEnv,
|
||||
jobject java_obj, jsval *vp);
|
||||
|
||||
extern JSString *
|
||||
jsj_ConvertJavaStringToJSString(JSContext *cx, JNIEnv *jEnv, jstring java_str);
|
||||
|
||||
extern JSBool
|
||||
jsj_ConvertJavaObjectToJSString(JSContext *cx, JNIEnv *jEnv,
|
||||
JavaClassDescriptor *class_descriptor,
|
||||
jobject java_obj, jsval *vp);
|
||||
extern JSBool
|
||||
jsj_ConvertJavaObjectToJSNumber(JSContext *cx, JNIEnv *jEnv,
|
||||
JavaClassDescriptor *class_descriptor,
|
||||
jobject java_obj, jsval *vp);
|
||||
extern JSBool
|
||||
jsj_ConvertJavaObjectToJSBoolean(JSContext *cx, JNIEnv *jEnv,
|
||||
JavaClassDescriptor *class_descriptor,
|
||||
jobject java_obj, jsval *vp);
|
||||
extern JSJavaThreadState *
|
||||
jsj_enter_js(JNIEnv *jEnv, jobject java_wrapper_obj,
|
||||
JSContext **cxp, JSObject **js_objp, JavaToJSSavedState* saved_state);
|
||||
extern JSBool
|
||||
jsj_exit_js(JSContext *cx, JSJavaThreadState *jsj_env, JavaToJSSavedState* original_state);
|
||||
|
||||
extern JavaClassDescriptor *
|
||||
jsj_get_jlObject_descriptor(JSContext *cx, JNIEnv *jEnv);
|
||||
|
||||
extern JSBool
|
||||
jsj_remove_js_obj_reflection_from_hashtable(JSContext *cx, JSObject *js_obj);
|
||||
|
||||
extern JSBool
|
||||
jsj_init_js_obj_reflections_table();
|
||||
|
||||
/************************ Java package reflection **************************/
|
||||
extern JSBool
|
||||
jsj_init_JavaPackage(JSContext *, JSObject *,
|
||||
JavaPackageDef *predefined_packages);
|
||||
|
||||
/************************* Java class reflection ***************************/
|
||||
extern JSBool
|
||||
jsj_init_JavaClass(JSContext *cx, JSObject *global_obj);
|
||||
|
||||
extern void
|
||||
jsj_DiscardJavaClassReflections(JNIEnv *jEnv);
|
||||
|
||||
extern const char *
|
||||
jsj_GetJavaClassName(JSContext *cx, JNIEnv *jEnv, jclass java_class);
|
||||
|
||||
extern JavaClassDescriptor *
|
||||
jsj_GetJavaClassDescriptor(JSContext *cx, JNIEnv *jEnv, jclass java_class);
|
||||
|
||||
extern void
|
||||
jsj_ReleaseJavaClassDescriptor(JSContext *cx, JNIEnv *jEnv, JavaClassDescriptor *class_descriptor);
|
||||
|
||||
extern JSObject *
|
||||
jsj_define_JavaClass(JSContext *cx, JNIEnv *jEnv, JSObject *obj,
|
||||
const char *unqualified_class_name,
|
||||
jclass jclazz);
|
||||
|
||||
extern JavaMemberDescriptor *
|
||||
jsj_GetJavaMemberDescriptor(JSContext *cx,
|
||||
JNIEnv *jEnv,
|
||||
JavaClassDescriptor *class_descriptor,
|
||||
jstring member_name);
|
||||
|
||||
extern JavaMemberDescriptor *
|
||||
jsj_LookupJavaMemberDescriptorById(JSContext *cx, JNIEnv *jEnv,
|
||||
JavaClassDescriptor *class_descriptor,
|
||||
jsid id);
|
||||
|
||||
extern JavaMemberDescriptor *
|
||||
jsj_LookupJavaStaticMemberDescriptorById(JSContext *cx, JNIEnv *jEnv,
|
||||
JavaClassDescriptor *class_descriptor,
|
||||
jsid id);
|
||||
|
||||
extern JavaMemberDescriptor *
|
||||
jsj_GetJavaStaticMemberDescriptor(JSContext *cx, JNIEnv *jEnv,
|
||||
JavaClassDescriptor *class_descriptor,
|
||||
jstring member_name);
|
||||
|
||||
extern JavaMemberDescriptor *
|
||||
jsj_GetJavaClassConstructors(JSContext *cx,
|
||||
JavaClassDescriptor *class_descriptor);
|
||||
|
||||
extern JavaMemberDescriptor *
|
||||
jsj_LookupJavaClassConstructors(JSContext *cx, JNIEnv *jEnv,
|
||||
JavaClassDescriptor *class_descriptor);
|
||||
|
||||
extern JavaMemberDescriptor *
|
||||
jsj_GetClassInstanceMembers(JSContext *cx, JNIEnv *jEnv,
|
||||
JavaClassDescriptor *class_descriptor);
|
||||
|
||||
extern JavaMemberDescriptor *
|
||||
jsj_GetClassStaticMembers(JSContext *cx, JNIEnv *jEnv,
|
||||
JavaClassDescriptor *class_descriptor);
|
||||
|
||||
extern JSBool
|
||||
jsj_InitJavaClassReflectionsTable();
|
||||
|
||||
/************************* Java field reflection ***************************/
|
||||
|
||||
extern JSBool
|
||||
jsj_GetJavaFieldValue(JSContext *cx, JNIEnv *jEnv, JavaFieldSpec *field_spec,
|
||||
jobject java_obj, jsval *vp);
|
||||
extern JSBool
|
||||
jsj_SetJavaFieldValue(JSContext *cx, JNIEnv *jEnv, JavaFieldSpec *field_spec,
|
||||
jobject java_obj, jsval js_val);
|
||||
extern JSBool
|
||||
jsj_ReflectJavaFields(JSContext *cx, JNIEnv *jEnv,
|
||||
JavaClassDescriptor *class_descriptor,
|
||||
JSBool reflect_only_static_fields);
|
||||
extern void
|
||||
jsj_DestroyFieldSpec(JSContext *cx, JNIEnv *jEnv, JavaFieldSpec *field);
|
||||
|
||||
/************************* Java method reflection ***************************/
|
||||
extern JSBool
|
||||
jsj_JavaInstanceMethodWrapper(JSContext *cx, JSObject *obj,
|
||||
uintN argc, jsval *argv, jsval *vp);
|
||||
extern JSBool
|
||||
jsj_JavaStaticMethodWrapper(JSContext *cx, JSObject *obj,
|
||||
uintN argc, jsval *argv, jsval *vp);
|
||||
extern JSBool
|
||||
jsj_JavaConstructorWrapper(JSContext *cx, JSObject *obj,
|
||||
uintN argc, jsval *argv, jsval *vp);
|
||||
extern JSBool
|
||||
jsj_ReflectJavaMethods(JSContext *cx, JNIEnv *jEnv,
|
||||
JavaClassDescriptor *class_descriptor,
|
||||
JSBool reflect_only_static_methods);
|
||||
extern void
|
||||
jsj_DestroyMethodSpec(JSContext *cx, JNIEnv *jEnv, JavaMethodSpec *method_spec);
|
||||
|
||||
/************************* Java member reflection ***************************/
|
||||
extern JSBool
|
||||
jsj_init_JavaMember(JSContext *, JSObject *);
|
||||
|
||||
extern JSBool
|
||||
jsj_ReflectJavaMethodsAndFields(JSContext *cx, JavaClassDescriptor *class_descriptor,
|
||||
JSBool reflect_only_statics);
|
||||
|
||||
extern JSObject *
|
||||
jsj_CreateJavaMember(JSContext *cx, jsval method_val, jsval field_val);
|
||||
|
||||
/************************* Java object reflection **************************/
|
||||
extern JSBool
|
||||
jsj_init_JavaObject(JSContext *, JSObject *);
|
||||
|
||||
extern JSObject *
|
||||
jsj_WrapJavaObject(JSContext *cx, JNIEnv *jEnv, jobject java_obj, jclass java_class);
|
||||
|
||||
extern void
|
||||
jsj_DiscardJavaObjReflections(JNIEnv *jEnv);
|
||||
|
||||
extern JSBool
|
||||
JavaObject_convert(JSContext *cx, JSObject *obj, JSType type, jsval *vp);
|
||||
|
||||
extern void
|
||||
JavaObject_finalize(JSContext *cx, JSObject *obj);
|
||||
|
||||
extern JSBool
|
||||
JavaObject_resolve(JSContext *cx, JSObject *obj, jsval id);
|
||||
|
||||
extern JSBool
|
||||
JavaObject_getProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp);
|
||||
|
||||
extern JSBool
|
||||
JavaObject_getPropertyById(JSContext *cx, JSObject *obj, jsid id, jsval *vp);
|
||||
|
||||
/************************* Java array reflection ***************************/
|
||||
extern JSBool
|
||||
jsj_init_JavaArray(JSContext *cx, JSObject *global_obj);
|
||||
|
||||
extern JSBool
|
||||
jsj_GetJavaArrayElement(JSContext *cx, JNIEnv *jEnv, jarray java_array,
|
||||
jsize index, JavaSignature *array_component_signature,
|
||||
jsval *vp);
|
||||
|
||||
extern JSBool
|
||||
jsj_SetJavaArrayElement(JSContext *cx, JNIEnv *jEnv, jarray java_array,
|
||||
jsize index, JavaSignature *array_component_signature,
|
||||
jsval js_val);
|
||||
|
||||
/********************* JavaScript object reflection ************************/
|
||||
extern jobject
|
||||
jsj_WrapJSObject(JSContext *cx, JNIEnv *jEnv, JSObject *js_obj);
|
||||
|
||||
extern JSObject *
|
||||
jsj_UnwrapJSObjectWrapper(JNIEnv *jEnv, jobject java_wrapper_obj);
|
||||
|
||||
extern void
|
||||
jsj_ClearPendingJSErrors(JSJavaThreadState *jsj_env);
|
||||
|
||||
extern JSBool
|
||||
jsj_ReportUncaughtJSException(JSContext *cx, JNIEnv *jEnv, jthrowable java_exception);
|
||||
|
||||
/**************************** Utilities ************************************/
|
||||
extern void
|
||||
jsj_ReportJavaError(JSContext *cx, JNIEnv *env, const char *format, ...);
|
||||
|
||||
extern void
|
||||
jsj_UnexpectedJavaError(JSContext *cx, JNIEnv *env, const char *format, ...);
|
||||
|
||||
extern const char *
|
||||
jsj_GetJavaErrorMessage(JNIEnv *env);
|
||||
|
||||
extern void
|
||||
jsj_LogError(const char *error_msg);
|
||||
|
||||
PR_CALLBACK JSJHashNumber
|
||||
jsj_HashJavaObject(const void *key, void* env);
|
||||
|
||||
PR_CALLBACK intN
|
||||
jsj_JavaObjectComparator(const void *v1, const void *v2, void *arg);
|
||||
|
||||
extern JSJavaThreadState *
|
||||
jsj_MapJavaThreadToJSJavaThreadState(JNIEnv *jEnv, char **errp);
|
||||
|
||||
extern void
|
||||
jsj_MakeJNIClassname(char *jClassName);
|
||||
|
||||
extern const char *
|
||||
jsj_ClassNameOfJavaObject(JSContext *cx, JNIEnv *jEnv, jobject java_object);
|
||||
|
||||
extern jsize
|
||||
jsj_GetJavaArrayLength(JSContext *cx, JNIEnv *jEnv, jarray java_array);
|
||||
|
||||
extern JSBool
|
||||
JavaStringToId(JSContext *cx, JNIEnv *jEnv, jstring jstr, jsid *idp);
|
||||
|
||||
extern const char *
|
||||
jsj_DupJavaStringUTF(JSContext *cx, JNIEnv *jEnv, jstring jstr);
|
||||
|
||||
JSJavaThreadState *
|
||||
jsj_MapJSContextToJSJThread(JSContext *cx, JNIEnv **envp);
|
||||
|
||||
JSJavaThreadState *
|
||||
jsj_SetJavaJSJEnv(JSJavaThreadState* java_jsj_env);
|
||||
|
||||
#ifdef DEBUG
|
||||
#define DEBUG_LOG(args) printf args
|
||||
#endif
|
||||
|
||||
#define JS_FREE_IF(cx, x) \
|
||||
PR_BEGIN_MACRO \
|
||||
if (x) \
|
||||
JS_free(cx, x); \
|
||||
PR_END_MACRO
|
||||
|
||||
#endif /* _JSJAVA_PVT_H */
|
||||
361
mozilla/js/src/liveconnect/jsj_utils.c
Normal file
@@ -0,0 +1,361 @@
|
||||
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.0 (the "License"); you may not use this file except in
|
||||
* compliance with the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
* the License for the specific language governing rights and limitations
|
||||
* under the License.
|
||||
*
|
||||
* The Original Code is Mozilla Communicator client code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are Copyright (C) 1998
|
||||
* Netscape Communications Corporation. All Rights Reserved.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is part of the Java-vendor-neutral implementation of LiveConnect
|
||||
*
|
||||
* It contains low-level utility code.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "jsj_private.h" /* LiveConnect internals */
|
||||
#include "jsjava.h" /* External LiveConnect API */
|
||||
|
||||
|
||||
/*
|
||||
* This is a hash-table utility routine that computes the hash code of a Java
|
||||
* object by calling java.lang.System.identityHashCode()
|
||||
*/
|
||||
PR_CALLBACK JSJHashNumber
|
||||
jsj_HashJavaObject(const void *key, void* env)
|
||||
{
|
||||
PRHashNumber hash_code;
|
||||
jobject java_obj;
|
||||
JNIEnv *jEnv;
|
||||
|
||||
java_obj = (jobject)key;
|
||||
jEnv = (JNIEnv*) env;
|
||||
hash_code = (*jEnv)->CallStaticIntMethod(jEnv, jlSystem,
|
||||
jlSystem_identityHashCode, java_obj);
|
||||
PR_ASSERT(!(*jEnv)->ExceptionOccurred(jEnv));
|
||||
return hash_code;
|
||||
}
|
||||
|
||||
/*
|
||||
* This is a hash-table utility routine for comparing two Java objects.
|
||||
* It's not possible to use the == operator to directly compare two jobject's,
|
||||
* since they're opaque references and aren't guaranteed to be simple pointers
|
||||
* or handles (though they may be in some JVM implementations). Instead,
|
||||
* use the JNI routine for comparing the two objects.
|
||||
*/
|
||||
PR_CALLBACK intN
|
||||
jsj_JavaObjectComparator(const void *v1, const void *v2, void *arg)
|
||||
{
|
||||
jobject java_obj1, java_obj2;
|
||||
JNIEnv *jEnv;
|
||||
|
||||
jEnv = (JNIEnv*)arg;
|
||||
java_obj1 = (jobject)v1;
|
||||
java_obj2 = (jobject)v2;
|
||||
|
||||
if (java_obj1 == java_obj2)
|
||||
return 1;
|
||||
return (*jEnv)->IsSameObject(jEnv, java_obj1, java_obj2);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return a UTF8, null-terminated encoding of a Java string. The string must
|
||||
* be free'ed by the caller.
|
||||
*
|
||||
* If an error occurs, returns NULL and calls the JS error reporter.
|
||||
*/
|
||||
const char *
|
||||
jsj_DupJavaStringUTF(JSContext *cx, JNIEnv *jEnv, jstring jstr)
|
||||
{
|
||||
const char *str, *retval;
|
||||
|
||||
str = (*jEnv)->GetStringUTFChars(jEnv, jstr, 0);
|
||||
if (!str) {
|
||||
jsj_UnexpectedJavaError(cx, jEnv, "Can't get UTF8 characters from "
|
||||
"Java string");
|
||||
return NULL;
|
||||
}
|
||||
retval = JS_strdup(cx, str);
|
||||
(*jEnv)->ReleaseStringUTFChars(jEnv, jstr, str);
|
||||
return retval;
|
||||
}
|
||||
|
||||
JSBool
|
||||
JavaStringToId(JSContext *cx, JNIEnv *jEnv, jstring jstr, jsid *idp)
|
||||
{
|
||||
const jschar *ucs2;
|
||||
JSString *jsstr;
|
||||
jsize ucs2_len;
|
||||
jsval val;
|
||||
|
||||
ucs2 = (*jEnv)->GetStringChars(jEnv, jstr, 0);
|
||||
if (!ucs2) {
|
||||
jsj_UnexpectedJavaError(cx, jEnv, "Couldn't obtain Unicode characters"
|
||||
"from Java string");
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
ucs2_len = (*jEnv)->GetStringLength(jEnv, jstr);
|
||||
jsstr = JS_InternUCStringN(cx, ucs2, ucs2_len);
|
||||
(*jEnv)->ReleaseStringChars(jEnv, jstr, ucs2);
|
||||
if (!jsstr)
|
||||
return JS_FALSE;
|
||||
|
||||
val = STRING_TO_JSVAL(jsstr);
|
||||
JS_ValueToId(cx, STRING_TO_JSVAL(jsstr), idp);
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
/* Not used ?
|
||||
const char *
|
||||
jsj_ClassNameOfJavaObject(JSContext *cx, JNIEnv *jEnv, jobject java_object)
|
||||
{
|
||||
jobject java_class;
|
||||
|
||||
java_class = (*jEnv)->GetObjectClass(jEnv, java_object);
|
||||
|
||||
if (!java_class) {
|
||||
PR_ASSERT(0);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return jsj_GetJavaClassName(cx, jEnv, java_class);
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
* Return, as a C string, the error message associated with a Java exception
|
||||
* that occurred as a result of a JNI call, preceded by the class name of
|
||||
* the exception. As a special case, if the class of the exception is
|
||||
* netscape.javascript.JSException, the exception class name is omitted.
|
||||
*
|
||||
* NULL is returned if no Java exception is pending. The caller is
|
||||
* responsible for free'ing the returned string. On exit, the Java exception
|
||||
* is *not* cleared.
|
||||
*/
|
||||
const char *
|
||||
jsj_GetJavaErrorMessage(JNIEnv *jEnv)
|
||||
{
|
||||
const char *java_error_msg;
|
||||
char *error_msg = NULL;
|
||||
jthrowable exception;
|
||||
jstring java_exception_jstring;
|
||||
|
||||
exception = (*jEnv)->ExceptionOccurred(jEnv);
|
||||
if (exception && jlThrowable_toString) {
|
||||
java_exception_jstring =
|
||||
(*jEnv)->CallObjectMethod(jEnv, exception, jlThrowable_toString);
|
||||
java_error_msg = (*jEnv)->GetStringUTFChars(jEnv, java_exception_jstring, NULL);
|
||||
error_msg = strdup((char*)java_error_msg);
|
||||
(*jEnv)->ReleaseStringUTFChars(jEnv, java_exception_jstring, java_error_msg);
|
||||
|
||||
#ifdef DEBUG
|
||||
/* (*jEnv)->ExceptionDescribe(jEnv); */
|
||||
#endif
|
||||
}
|
||||
return error_msg;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return, as a C string, the JVM stack trace associated with a Java
|
||||
* exception, as would be printed by java.lang.Throwable.printStackTrace().
|
||||
* The caller is responsible for free'ing the returned string.
|
||||
*
|
||||
* Returns NULL if an error occurs.
|
||||
*/
|
||||
static const char *
|
||||
get_java_stack_trace(JSContext *cx, JNIEnv *jEnv, jthrowable java_exception)
|
||||
{
|
||||
const char *backtrace;
|
||||
jstring backtrace_jstr;
|
||||
|
||||
backtrace = NULL;
|
||||
if (java_exception && njJSUtil_getStackTrace) {
|
||||
backtrace_jstr = (*jEnv)->CallStaticObjectMethod(jEnv, njJSUtil,
|
||||
njJSUtil_getStackTrace,
|
||||
java_exception);
|
||||
if (!backtrace_jstr) {
|
||||
jsj_UnexpectedJavaError(cx, jEnv, "Unable to get exception stack trace");
|
||||
return NULL;
|
||||
}
|
||||
backtrace = jsj_DupJavaStringUTF(cx, jEnv, backtrace_jstr);
|
||||
}
|
||||
return backtrace;
|
||||
}
|
||||
|
||||
/* Full Java backtrace when Java exceptions reported to JavaScript */
|
||||
#define REPORT_JAVA_EXCEPTION_STACK_TRACE
|
||||
|
||||
/*
|
||||
* This is a wrapper around JS_ReportError(), useful when an error condition
|
||||
* is the result of a JVM failure or exception condition. It appends the
|
||||
* message associated with the pending Java exception to the passed in
|
||||
* printf-style format string and arguments.
|
||||
*/
|
||||
static void
|
||||
vreport_java_error(JSContext *cx, JNIEnv *jEnv, const char *format, va_list ap)
|
||||
{
|
||||
char *error_msg, *js_error_msg;
|
||||
const char *java_stack_trace;
|
||||
const char *java_error_msg;
|
||||
jthrowable java_exception;
|
||||
|
||||
java_error_msg = NULL;
|
||||
java_exception = (*jEnv)->ExceptionOccurred(jEnv);
|
||||
if (java_exception && njJSException &&
|
||||
(*jEnv)->IsInstanceOf(jEnv, java_exception, njJSException)) {
|
||||
(*jEnv)->ExceptionClear(jEnv);
|
||||
jsj_ReportUncaughtJSException(cx, jEnv, java_exception);
|
||||
return;
|
||||
}
|
||||
|
||||
js_error_msg = PR_vsmprintf(format, ap);
|
||||
|
||||
if (!js_error_msg) {
|
||||
PR_ASSERT(0); /* Out-of-memory */
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef REPORT_JAVA_EXCEPTION_STACK_TRACE
|
||||
|
||||
java_stack_trace = get_java_stack_trace(cx, jEnv, java_exception);
|
||||
if (java_stack_trace) {
|
||||
error_msg = PR_smprintf("%s\n%s", js_error_msg, java_stack_trace);
|
||||
free((char*)java_stack_trace);
|
||||
if (!error_msg) {
|
||||
PR_ASSERT(0); /* Out-of-memory */
|
||||
return;
|
||||
}
|
||||
} else
|
||||
|
||||
#endif
|
||||
{
|
||||
java_error_msg = jsj_GetJavaErrorMessage(jEnv);
|
||||
if (java_error_msg) {
|
||||
error_msg = PR_smprintf("%s (%s)\n", js_error_msg, java_error_msg);
|
||||
free((char*)java_error_msg);
|
||||
free(js_error_msg);
|
||||
} else {
|
||||
error_msg = js_error_msg;
|
||||
}
|
||||
}
|
||||
|
||||
JS_ReportError(cx, error_msg);
|
||||
|
||||
/* Important: the Java exception must not be cleared until the reporter
|
||||
has been called, because the capture_js_error_reports_for_java(),
|
||||
called from JS_ReportError(), needs to read the exception from the JVM */
|
||||
(*jEnv)->ExceptionClear(jEnv);
|
||||
free(error_msg);
|
||||
}
|
||||
|
||||
void
|
||||
jsj_ReportJavaError(JSContext *cx, JNIEnv *env, const char *format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, format);
|
||||
vreport_java_error(cx, env, format, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
/*
|
||||
* Same as jsj_ReportJavaError, except "internal error: " is prepended
|
||||
* to message.
|
||||
*/
|
||||
void
|
||||
jsj_UnexpectedJavaError(JSContext *cx, JNIEnv *env, const char *format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
const char *format2;
|
||||
|
||||
va_start(ap, format);
|
||||
format2 = PR_smprintf("internal error: %s", format);
|
||||
if (format2) {
|
||||
vreport_java_error(cx, env, format2, ap);
|
||||
free((void*)format2);
|
||||
}
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
/*
|
||||
* Most LiveConnect errors are signaled by calling JS_ReportError(),
|
||||
* but in some circumstances, the target JSContext for such errors
|
||||
* is not determinable, e.g. during initialization. In such cases
|
||||
* any error messages are routed to this function.
|
||||
*/
|
||||
void
|
||||
jsj_LogError(const char *error_msg)
|
||||
{
|
||||
if (JSJ_callbacks && JSJ_callbacks->error_print)
|
||||
JSJ_callbacks->error_print(error_msg);
|
||||
else
|
||||
fputs(error_msg, stderr);
|
||||
}
|
||||
|
||||
jsize
|
||||
jsj_GetJavaArrayLength(JSContext *cx, JNIEnv *jEnv, jarray java_array)
|
||||
{
|
||||
jsize array_length = (*jEnv)->GetArrayLength(jEnv, java_array);
|
||||
if ((*jEnv)->ExceptionOccurred(jEnv)) {
|
||||
jsj_UnexpectedJavaError(cx, jEnv, "Couldn't obtain array length");
|
||||
return -1;
|
||||
}
|
||||
return array_length;
|
||||
}
|
||||
|
||||
static JSJavaThreadState *the_java_jsj_env = NULL;
|
||||
|
||||
JSJavaThreadState *
|
||||
jsj_MapJSContextToJSJThread(JSContext *cx, JNIEnv **envp)
|
||||
{
|
||||
JSJavaThreadState *jsj_env;
|
||||
char *err_msg;
|
||||
|
||||
*envp = NULL;
|
||||
err_msg = NULL;
|
||||
|
||||
jsj_env = the_java_jsj_env;
|
||||
if (jsj_env == NULL)
|
||||
jsj_env = JSJ_callbacks->map_js_context_to_jsj_thread(cx, &err_msg);
|
||||
if (!jsj_env) {
|
||||
if (err_msg) {
|
||||
JS_ReportError(cx, err_msg);
|
||||
free(err_msg);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
if (envp)
|
||||
*envp = jsj_env->jEnv;
|
||||
return jsj_env;
|
||||
}
|
||||
|
||||
/**
|
||||
* Since only one Java thread is allowed to enter JavaScript, this function is
|
||||
* used to enforce the use of that thread's state. The static global the_java_jsj_env
|
||||
* overrides using JSJ_callbacks->map_js_context_to_jsj_thread, which maps
|
||||
* native threads to JSJavaThreadStates. This isn't appropriate when Java calls
|
||||
* JavaScript, as there can be a many to one mapping from Java threads to native
|
||||
* threads.
|
||||
*/
|
||||
JSJavaThreadState *
|
||||
jsj_SetJavaJSJEnv(JSJavaThreadState* java_jsj_env)
|
||||
{
|
||||
JSJavaThreadState *old_jsj_env = the_java_jsj_env;
|
||||
the_java_jsj_env = java_jsj_env;
|
||||
return old_jsj_env;
|
||||
}
|
||||
264
mozilla/js/src/liveconnect/jsjava.h
Normal file
@@ -0,0 +1,264 @@
|
||||
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.0 (the "License"); you may not use this file except in
|
||||
* compliance with the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
* the License for the specific language governing rights and limitations
|
||||
* under the License.
|
||||
*
|
||||
* The Original Code is Mozilla Communicator client code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are Copyright (C) 1998
|
||||
* Netscape Communications Corporation. All Rights Reserved.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is part of the Java-vendor-neutral implementation of LiveConnect
|
||||
*
|
||||
* Publicly exported functions for JavaScript <==> Java communication.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _JSJAVA_H
|
||||
#define _JSJAVA_H
|
||||
|
||||
#ifndef prtypes_h___
|
||||
#include "prtypes.h"
|
||||
#endif
|
||||
|
||||
PR_BEGIN_EXTERN_C
|
||||
|
||||
#include "jni.h" /* Java Native Interface */
|
||||
#include "jsapi.h" /* JavaScript engine API */
|
||||
|
||||
/*
|
||||
* A JSJavaVM structure is a wrapper around a JavaVM which incorporates
|
||||
* additional LiveConnect state.
|
||||
*/
|
||||
typedef struct JSJavaVM JSJavaVM;
|
||||
|
||||
/* LiveConnect and Java state, one per thread */
|
||||
typedef struct JSJavaThreadState JSJavaThreadState;
|
||||
|
||||
/*
|
||||
* An opaque type that represents the connection to the Java VM. In stand-alone
|
||||
* Java environments, this may be a JNI JavaVM object; in the browser environment
|
||||
* it is a reference to a JVM plugin. A set of callbacks in the JSJCallbacks
|
||||
* struct allow it to be manipulated.
|
||||
*/
|
||||
typedef struct SystemJavaVM SystemJavaVM;
|
||||
|
||||
/*
|
||||
* This callback table provides hooks to external functions that implement
|
||||
* functionality specific to the embedding. For example, these callbacks are
|
||||
* necessary in multi-threaded environments or to implement a security
|
||||
* policy.
|
||||
*/
|
||||
typedef struct JSJCallbacks {
|
||||
|
||||
/* This callback is invoked when there is no JavaScript execution
|
||||
environment (JSContext) associated with the current Java thread and
|
||||
a call is made from Java into JavaScript. (A JSContext is associated
|
||||
with a Java thread by calling the JSJ_SetJSContextForJavaThread()
|
||||
function.) This callback is only invoked when Java spontaneously calls
|
||||
into JavaScript, i.e. it is not called when JS calls into Java which
|
||||
calls back into JS.
|
||||
|
||||
This callback can be used to create a JSContext lazily, or obtain
|
||||
one from a pool of available JSContexts. The implementation of this
|
||||
callback can call JSJ_SetJSContextForJavaThread() to avoid any further
|
||||
callbacks of this type for this Java thread. */
|
||||
JSContext * (*map_jsj_thread_to_js_context)(JSJavaThreadState *jsj_env,
|
||||
JNIEnv *jEnv,
|
||||
char **errp);
|
||||
|
||||
/* This callback is invoked whenever a call is made into Java from
|
||||
JavaScript. It's responsible for mapping from a JavaScript execution
|
||||
environment (JSContext) to a Java thread. (A JavaContext can only
|
||||
be associated with one Java thread at a time.) */
|
||||
JSJavaThreadState * (*map_js_context_to_jsj_thread)(JSContext *cx,
|
||||
char **errp);
|
||||
|
||||
/* This callback implements netscape.javascript.JSObject.getWindow(),
|
||||
a method named for its behavior in the browser environment, where it
|
||||
returns the JS "Window" object corresponding to the HTML window that an
|
||||
applet is embedded within. More generally, it's a way for Java to get
|
||||
hold of a JS object that has not been explicitly passed to it. */
|
||||
JSObject * (*map_java_object_to_js_object)(JNIEnv *jEnv, void *pJavaObject,
|
||||
char **errp);
|
||||
|
||||
/* An interim callback function until the LiveConnect security story is
|
||||
straightened out. This function pointer can be set to NULL. */
|
||||
JSPrincipals * (*get_JSPrincipals_from_java_caller)(JNIEnv *jEnv, JSContext *pJSContext);
|
||||
|
||||
/* The following two callbacks sandwich any JS evaluation performed
|
||||
from Java. They may be used to implement concurrency constraints, e.g.
|
||||
by suspending the current thread until some condition is met. In the
|
||||
browser embedding, these are used to maintain the run-to-completion
|
||||
semantics of JavaScript. It is acceptable for either function pointer
|
||||
to be NULL. */
|
||||
JSBool (*enter_js_from_java)(JNIEnv *jEnv, char **errp);
|
||||
void (*exit_js)(JNIEnv *jEnv);
|
||||
|
||||
/* Most LiveConnect errors are signaled by calling JS_ReportError(), but in
|
||||
some circumstances, the target JSContext for such errors is not
|
||||
determinable, e.g. during initialization. In such cases any error
|
||||
messages are routed to this function. If the function pointer is set to
|
||||
NULL, error messages are sent to stderr. */
|
||||
void (*error_print)(const char *error_msg);
|
||||
|
||||
/* This enables liveconnect to ask the VM for a java wrapper so that VM gets a chance to
|
||||
store a mapping between a jsobject and java wrapper. So the unwrapping can be done on the
|
||||
VM side before calling nsILiveconnect apis. This saves on a round trip request. */
|
||||
jobject (*get_java_wrapper)(JNIEnv *jEnv, jint jsobject);
|
||||
|
||||
/* The following set of methods abstract over the JavaVM object. */
|
||||
PRBool (*create_java_vm)(SystemJavaVM* *jvm, JNIEnv* *initialEnv, void* initargs);
|
||||
PRBool (*destroy_java_vm)(SystemJavaVM* jvm, JNIEnv* initialEnv);
|
||||
JNIEnv* (*attach_current_thread)(SystemJavaVM* jvm);
|
||||
PRBool (*detach_current_thread)(SystemJavaVM* jvm, JNIEnv* env);
|
||||
SystemJavaVM* (*get_java_vm)(JNIEnv* env);
|
||||
|
||||
/* Reserved for future use */
|
||||
void * reserved[10];
|
||||
} JSJCallbacks;
|
||||
|
||||
/*===========================================================================*/
|
||||
|
||||
/* A flag that denotes that a Java package has no sub-packages other than those
|
||||
explicitly pre-defined at the time of initialization. An access
|
||||
to a simple name within such a package, therefore, must either correspond to
|
||||
one of these explicitly pre-defined sub-packages or to a class within this
|
||||
package. It is reasonable for LiveConnect to signal an error if a simple
|
||||
name does not comply with these criteria. */
|
||||
#define PKG_SYSTEM 1
|
||||
|
||||
/* A flag that denotes that a Java package which might contain sub-packages
|
||||
that are not pre-defined at initialization time, because the sub-packages
|
||||
may not be the same in all installations. Therefore, an access to a simple
|
||||
name within such a a package which does not correspond to either a
|
||||
pre-defined sub-package or to a class, must be assummed to refer to an
|
||||
unknown sub-package. This behavior may cause bogus JavaPackage objects to be
|
||||
created if a package name is misspelled, e.g. sun.oi.net. */
|
||||
#define PKG_USER 2
|
||||
|
||||
/* A Java package defined at initialization time. */
|
||||
typedef struct JavaPackageDef {
|
||||
const char * name; /* e.g. "java.lang" */
|
||||
const char * path; /* e.g. "java/lang", or NULL for default */
|
||||
int flags; /* PKG_USER, PKG_SYSTEM, etc. */
|
||||
} JavaPackageDef;
|
||||
|
||||
/*===========================================================================*/
|
||||
|
||||
/* The following two convenience functions present a complete, but simplified
|
||||
LiveConnect API which is designed to handle the special case of a single
|
||||
Java-VM, with single-threaded operation, and the use of only one JSContext.
|
||||
The full API is in the section below. */
|
||||
|
||||
/* Initialize the provided JSContext by setting up the JS classes necessary for
|
||||
reflection and by defining JavaPackage objects for the default Java packages
|
||||
as properties of global_obj. If java_vm is NULL, a new Java VM is
|
||||
created, using the provided classpath in addition to any default classpath.
|
||||
The classpath argument is ignored, however, if java_vm is non-NULL. */
|
||||
PR_IMPLEMENT(JSBool)
|
||||
JSJ_SimpleInit(JSContext *cx, JSObject *global_obj,
|
||||
SystemJavaVM *java_vm, const char *classpath);
|
||||
|
||||
/* Free up all resources. Destroy the Java VM if it was created by LiveConnect */
|
||||
PR_IMPLEMENT(void)
|
||||
JSJ_SimpleShutdown();
|
||||
|
||||
/*===========================================================================*/
|
||||
|
||||
/* The "full" LiveConnect API, required when more than one thread, Java VM, or
|
||||
JSContext is involved. Initialization pseudocode might go roughly like
|
||||
this:
|
||||
|
||||
JSJ_Init() // Setup callbacks
|
||||
for each JavaVM {
|
||||
JSJ_ConnectToJavaVM(...)
|
||||
}
|
||||
for each JSContext {
|
||||
JSJ_InitJSContext(...)
|
||||
}
|
||||
for each JS evaluation {
|
||||
run JavaScript code in the JSContext;
|
||||
}
|
||||
*/
|
||||
|
||||
/* Called once for all instances of LiveConnect to set up callbacks */
|
||||
PR_IMPLEMENT(void)
|
||||
JSJ_Init(JSJCallbacks *callbacks);
|
||||
|
||||
/* Called once per Java VM, this function initializes the classes, fields, and
|
||||
methods required for Java reflection. If java_vm is NULL, a new Java VM is
|
||||
created according to the create_java_vm callback in the JSJCallbacks,
|
||||
using the provided classpath in addition to any default initargs.
|
||||
The initargs argument is ignored, however, if java_vm is non-NULL. */
|
||||
PR_IMPLEMENT(JSJavaVM *)
|
||||
JSJ_ConnectToJavaVM(SystemJavaVM *java_vm, void* initargs);
|
||||
|
||||
/* Initialize the provided JSContext by setting up the JS classes necessary for
|
||||
reflection and by defining JavaPackage objects for the default Java packages
|
||||
as properties of global_obj. Additional packages may be pre-defined by
|
||||
setting the predefined_packages argument. (Pre-defining a Java package at
|
||||
initialization time is not necessary, but it will make package lookup faster
|
||||
and, more importantly, will avoid unnecessary network accesses if classes
|
||||
are being loaded over the network.) */
|
||||
PR_IMPLEMENT(JSBool)
|
||||
JSJ_InitJSContext(JSContext *cx, JSObject *global_obj,
|
||||
JavaPackageDef *predefined_packages);
|
||||
|
||||
/* This function returns a structure that encapsulates the Java and JavaScript
|
||||
execution environment for the current native thread. It is intended to
|
||||
be called from the embedder's implementation of JSJCallback's
|
||||
map_js_context_to_jsj_thread() function. The thread_name argument is only
|
||||
used for debugging purposes and can be set to NULL. The Java JNI
|
||||
environment associated with this thread is returned through the java_envp
|
||||
argument if java_envp is non-NULL. */
|
||||
PR_IMPLEMENT(JSJavaThreadState *)
|
||||
JSJ_AttachCurrentThreadToJava(JSJavaVM *jsjava_vm, const char *thread_name,
|
||||
JNIEnv **java_envp);
|
||||
|
||||
/* Destructor routine for per-thread JSJavaThreadState structure */
|
||||
PR_IMPLEMENT(JSBool)
|
||||
JSJ_DetachCurrentThreadFromJava(JSJavaThreadState *jsj_env);
|
||||
|
||||
/* This function is used to specify a particular JSContext as *the* JavaScript
|
||||
execution environment to be used when LiveConnect is accessed from the given
|
||||
Java thread, i.e. when one of the methods of netscape.javascript.JSObject
|
||||
has been called. There can only be one such JS context for any given Java
|
||||
thread at a time. (To multiplex JSContexts among a single thread, this
|
||||
function could be called before Java is invoked on that thread.) The return
|
||||
value is the previous JSContext associated with the given Java thread.
|
||||
|
||||
If this function has not been called for a thread and a crossing is made
|
||||
into JavaScript from Java, the map_jsj_thread_to_js_context() callback will
|
||||
be invoked to determine the JSContext for the thread. The purpose of the
|
||||
function is to improve performance by avoiding the expense of the callback.
|
||||
*/
|
||||
PR_IMPLEMENT(JSContext *)
|
||||
JSJ_SetDefaultJSContextForJavaThread(JSContext *cx, JSJavaThreadState *jsj_env);
|
||||
|
||||
/* This routine severs the connection to a Java VM, freeing all related resources.
|
||||
It shouldn't be called until the global scope has been cleared in all related
|
||||
JSContexts (so that all LiveConnect objects are finalized) and a JavaScript
|
||||
GC is performed. Otherwise, accessed to free'ed memory could result. */
|
||||
PR_IMPLEMENT(void)
|
||||
JSJ_DisconnectFromJavaVM(JSJavaVM *);
|
||||
|
||||
/*
|
||||
* Reflect a Java object into a JS value. The source object, java_obj, must
|
||||
* be of type java.lang.Object or a subclass and may, therefore, be an array.
|
||||
*/
|
||||
PR_IMPLEMENT(JSBool)
|
||||
JSJ_ConvertJavaObjectToJSValue(JSContext *cx, jobject java_obj, jsval *vp);
|
||||
|
||||
PR_END_EXTERN_C
|
||||
#endif /* _JSJAVA_H */
|
||||
182
mozilla/js/src/liveconnect/makefile.win
Normal file
@@ -0,0 +1,182 @@
|
||||
# The contents of this file are subject to the Netscape Public License
|
||||
# Version 1.0 (the "NPL"); you may not use this file except in
|
||||
# compliance with the NPL. You may obtain a copy of the NPL at
|
||||
# http://www.mozilla.org/NPL/
|
||||
#
|
||||
# Software distributed under the NPL is distributed on an "AS IS" basis,
|
||||
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
||||
# for the specific language governing rights and limitations under the
|
||||
# NPL.
|
||||
#
|
||||
# The Initial Developer of this code under the NPL is Netscape
|
||||
# Communications Corporation. Portions created by Netscape are
|
||||
# Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
||||
# Reserved.
|
||||
|
||||
IGNORE_MANIFEST=1
|
||||
|
||||
#//------------------------------------------------------------------------
|
||||
#//
|
||||
#// Makefile to build the Java reflections of JavaScript objects
|
||||
#//
|
||||
#//------------------------------------------------------------------------
|
||||
|
||||
|
||||
#//------------------------------------------------------------------------
|
||||
#//
|
||||
#// Specify the depth of the current directory relative to the
|
||||
#// root of NS
|
||||
#//
|
||||
#//------------------------------------------------------------------------
|
||||
DEPTH= ..\..\..
|
||||
|
||||
include <$(DEPTH)/config/config.mak>
|
||||
|
||||
!ifdef NSJVM
|
||||
DIRS = classes
|
||||
!endif
|
||||
|
||||
|
||||
#//------------------------------------------------------------------------
|
||||
#//
|
||||
#// Define any Public Make Variables here: (ie. PDFFILE, MAPFILE, ...)
|
||||
#//
|
||||
#//------------------------------------------------------------------------
|
||||
DLLNAME=jsj$(MOZ_BITS)$(VERSION_NUMBER)
|
||||
PDBFILE=$(DLLNAME).pdb
|
||||
MAPFILE = $(DLLNAME).map
|
||||
RESFILE = jsj1640.res
|
||||
DLL=.\$(OBJDIR)\$(DLLNAME).dll
|
||||
MAKE_OBJ_TYPE = DLL
|
||||
|
||||
!if "$(MOZ_BITS)" == "16"
|
||||
DEFFILE = $(DLLNAME).def
|
||||
!endif
|
||||
|
||||
LLIBS=$(LIBNSPR) $(DIST)\lib\js$(MOZ_BITS)$(VERSION_NUMBER).lib \
|
||||
$(DIST)\lib\xpcom32.lib
|
||||
|
||||
!if "$(MOZ_BITS)"=="32" && defined(MOZ_DEBUG) && defined(GLOWCODE)
|
||||
LLIBS=$(LLIBS) $(GLOWDIR)\glowcode.lib
|
||||
!endif
|
||||
|
||||
#//------------------------------------------------------------------------
|
||||
#//
|
||||
#// Define the files necessary to build the target (ie. OBJS)
|
||||
#//
|
||||
#//------------------------------------------------------------------------
|
||||
OBJS= \
|
||||
.\$(OBJDIR)\jsj.obj \
|
||||
.\$(OBJDIR)\jsj_JSObject.obj \
|
||||
.\$(OBJDIR)\jsj_JavaArray.obj \
|
||||
.\$(OBJDIR)\jsj_JavaClass.obj \
|
||||
.\$(OBJDIR)\jsj_JavaMember.obj \
|
||||
.\$(OBJDIR)\jsj_JavaObject.obj \
|
||||
.\$(OBJDIR)\jsj_JavaPackage.obj \
|
||||
.\$(OBJDIR)\jsj_array.obj \
|
||||
.\$(OBJDIR)\jsj_class.obj \
|
||||
.\$(OBJDIR)\jsj_convert.obj \
|
||||
.\$(OBJDIR)\jsj_field.obj \
|
||||
.\$(OBJDIR)\jsj_hash.obj \
|
||||
.\$(OBJDIR)\jsj_method.obj \
|
||||
.\$(OBJDIR)\jsj_utils.obj \
|
||||
.\$(OBJDIR)\nsCLiveconnect.obj \
|
||||
.\$(OBJDIR)\nsCLiveconnectFactory.obj \
|
||||
!if "$(MOZ_BITS)" == "16"
|
||||
.\$(OBJDIR)\jsj_nodl.obj \
|
||||
!endif
|
||||
$(NULL)
|
||||
|
||||
#//------------------------------------------------------------------------
|
||||
#//
|
||||
#// install headers
|
||||
#//
|
||||
#//------------------------------------------------------------------------
|
||||
INSTALL_DIR=$(PUBLIC)\js
|
||||
INSTALL_FILE_LIST= \
|
||||
jsjava.h nsILiveconnect.h
|
||||
|
||||
#//------------------------------------------------------------------------
|
||||
#//
|
||||
#// Define any Public Targets here (ie. PROGRAM, LIBRARY, DLL, ...)
|
||||
#// (these must be defined before the common makefiles are included)
|
||||
#//
|
||||
#//------------------------------------------------------------------------
|
||||
|
||||
!ifdef NSJVM
|
||||
JNI_GEN= \
|
||||
netscape.javascript.JSObject \
|
||||
netscape.javascript.JSException \
|
||||
$(NULL)
|
||||
|
||||
!endif
|
||||
|
||||
MODULE = java
|
||||
EXPORTS = \
|
||||
$(JNI_GEN_DIR)\netscape_javascript_JSObject.h \
|
||||
$(JNI_GEN_DIR)\netscape_javascript_JSException.h \
|
||||
$(NULL)
|
||||
|
||||
|
||||
#//------------------------------------------------------------------------
|
||||
#//
|
||||
#// Define any local options for the make tools
|
||||
#// (ie. LCFLAGS, LLFLAGS, LLIBS, LINCS)
|
||||
#//
|
||||
#//------------------------------------------------------------------------
|
||||
|
||||
LINCS=$(LINCS) -I$(JNI_GEN_DIR) \
|
||||
-I$(PUBLIC)\js \
|
||||
-I$(PUBLIC)\java \
|
||||
-I$(PUBLIC)\xpcom \
|
||||
$(NULL)
|
||||
|
||||
|
||||
#!ifdef SERVER_BUILD
|
||||
#LLIBS=$(DIST)/lib/httpdlw.lib $(DIST)/lib/libsjboot.lib
|
||||
#!endif
|
||||
|
||||
#//------------------------------------------------------------------------
|
||||
#//
|
||||
#// Include the common makefile rules
|
||||
#//
|
||||
#//------------------------------------------------------------------------
|
||||
include <$(DEPTH)/config/rules.mak>
|
||||
|
||||
export:: INSTALL_FILES
|
||||
|
||||
libs:: $(DLL)
|
||||
$(MAKE_INSTALL) .\$(OBJDIR)\$(DLLNAME).dll $(DIST)\bin
|
||||
$(MAKE_INSTALL) .\$(OBJDIR)\$(DLLNAME).lib $(DIST)\lib
|
||||
|
||||
|
||||
####
|
||||
# this bit of extreme scariness came from the js/src makefile
|
||||
# reproduced here since that's where jsjava.c lives now...
|
||||
|
||||
!if ("$(MOZ_BITS)" == "16")
|
||||
#//
|
||||
#// Win16 Hoovers SO BAD!!!
|
||||
#//
|
||||
|
||||
!if !defined(MOZ_DEBUG)
|
||||
#//
|
||||
#// We must turn off codeview debug info so jni.c can build.
|
||||
#// Otherwise the linker gives errors about data in the $SYMBOLS
|
||||
#// segment being beyond a segment boundary.
|
||||
#//
|
||||
$(OBJDIR)\jsjava.obj: jsjava.c
|
||||
@$(CC) @<<$(CFGFILE)
|
||||
-c
|
||||
-Od
|
||||
$(CFLAGS)
|
||||
$(LCFLAGS)
|
||||
$(LINCS)
|
||||
$(LINCS_1)
|
||||
$(INCS)
|
||||
-Fd$(PDBFILE)
|
||||
-Fo.\$(OBJDIR)\
|
||||
$(*B).c
|
||||
<<KEEP
|
||||
!endif
|
||||
!endif
|
||||
111
mozilla/js/src/liveconnect/netscape_javascript_JSObject.h
Normal file
@@ -0,0 +1,111 @@
|
||||
/* -*- Mode: C; tab-width: 8 -*-
|
||||
* Copyright (C) 1998 Netscape Communications Corporation, All Rights Reserved.
|
||||
*/
|
||||
#include <jni.h>
|
||||
/* Header for class netscape_javascript_JSObject */
|
||||
|
||||
#ifndef _Included_netscape_javascript_JSObject
|
||||
#define _Included_netscape_javascript_JSObject
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
/*
|
||||
* Class: netscape_javascript_JSObject
|
||||
* Method: initClass
|
||||
* Signature: ()V
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_netscape_javascript_JSObject_initClass
|
||||
(JNIEnv *, jclass);
|
||||
|
||||
/*
|
||||
* Class: netscape_javascript_JSObject
|
||||
* Method: getMember
|
||||
* Signature: (Ljava/lang/String;)Ljava/lang/Object;
|
||||
*/
|
||||
JNIEXPORT jobject JNICALL Java_netscape_javascript_JSObject_getMember
|
||||
(JNIEnv *, jobject, jstring);
|
||||
|
||||
/*
|
||||
* Class: netscape_javascript_JSObject
|
||||
* Method: getSlot
|
||||
* Signature: (I)Ljava/lang/Object;
|
||||
*/
|
||||
JNIEXPORT jobject JNICALL Java_netscape_javascript_JSObject_getSlot
|
||||
(JNIEnv *, jobject, jint);
|
||||
|
||||
/*
|
||||
* Class: netscape_javascript_JSObject
|
||||
* Method: setMember
|
||||
* Signature: (Ljava/lang/String;Ljava/lang/Object;)V
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_netscape_javascript_JSObject_setMember
|
||||
(JNIEnv *, jobject, jstring, jobject);
|
||||
|
||||
/*
|
||||
* Class: netscape_javascript_JSObject
|
||||
* Method: setSlot
|
||||
* Signature: (ILjava/lang/Object;)V
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_netscape_javascript_JSObject_setSlot
|
||||
(JNIEnv *, jobject, jint, jobject);
|
||||
|
||||
/*
|
||||
* Class: netscape_javascript_JSObject
|
||||
* Method: removeMember
|
||||
* Signature: (Ljava/lang/String;)V
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_netscape_javascript_JSObject_removeMember
|
||||
(JNIEnv *, jobject, jstring);
|
||||
|
||||
/*
|
||||
* Class: netscape_javascript_JSObject
|
||||
* Method: call
|
||||
* Signature: (Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/Object;
|
||||
*/
|
||||
JNIEXPORT jobject JNICALL Java_netscape_javascript_JSObject_call
|
||||
(JNIEnv *, jobject, jstring, jobjectArray);
|
||||
|
||||
/*
|
||||
* Class: netscape_javascript_JSObject
|
||||
* Method: eval
|
||||
* Signature: (Ljava/lang/String;)Ljava/lang/Object;
|
||||
*/
|
||||
JNIEXPORT jobject JNICALL Java_netscape_javascript_JSObject_eval
|
||||
(JNIEnv *, jobject, jstring);
|
||||
|
||||
/*
|
||||
* Class: netscape_javascript_JSObject
|
||||
* Method: toString
|
||||
* Signature: ()Ljava/lang/String;
|
||||
*/
|
||||
JNIEXPORT jstring JNICALL Java_netscape_javascript_JSObject_toString
|
||||
(JNIEnv *, jobject);
|
||||
|
||||
/*
|
||||
* Class: netscape_javascript_JSObject
|
||||
* Method: getWindow
|
||||
* Signature: (Ljava/applet/Applet;)Lnetscape/javascript/JSObject;
|
||||
*/
|
||||
JNIEXPORT jobject JNICALL Java_netscape_javascript_JSObject_getWindow
|
||||
(JNIEnv *, jclass, jobject);
|
||||
|
||||
/*
|
||||
* Class: netscape_javascript_JSObject
|
||||
* Method: finalize
|
||||
* Signature: ()V
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_netscape_javascript_JSObject_finalize
|
||||
(JNIEnv *, jobject);
|
||||
|
||||
/*
|
||||
* Class: netscape_javascript_JSObject
|
||||
* Method: equals
|
||||
* Signature: (Ljava/lang/Object;)Z
|
||||
*/
|
||||
JNIEXPORT jboolean JNICALL Java_netscape_javascript_JSObject_equals
|
||||
(JNIEnv *, jobject, jobject);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
567
mozilla/js/src/liveconnect/nsCLiveconnect.cpp
Normal file
@@ -0,0 +1,567 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.0 (the "NPL"); you may not use this file except in
|
||||
* compliance with the NPL. You may obtain a copy of the NPL at
|
||||
* http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
||||
* for the specific language governing rights and limitations under the
|
||||
* NPL.
|
||||
*
|
||||
* The Initial Developer of this code under the NPL is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
||||
* Reserved.
|
||||
*/
|
||||
/*
|
||||
* This file is part of the Java-vendor-neutral implementation of LiveConnect
|
||||
*
|
||||
* It contains the implementation providing nsIFactory XP-COM interface.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "prtypes.h"
|
||||
#include "prprf.h"
|
||||
#include "prlog.h"
|
||||
PR_BEGIN_EXTERN_C
|
||||
|
||||
#ifdef XP_MAC
|
||||
#include "prosdep.h"
|
||||
#endif
|
||||
|
||||
#include "jsj_private.h"
|
||||
#include "jsjava.h"
|
||||
|
||||
#include "jscntxt.h" /* For js_ReportErrorAgain().
|
||||
TODO - get rid of private header */
|
||||
|
||||
#include "netscape_javascript_JSObject.h" /* javah-generated headers */
|
||||
|
||||
|
||||
/* A captured JavaScript error, created when JS_ReportError() is called while
|
||||
running JavaScript code that is itself called from Java. */
|
||||
struct CapturedJSError {
|
||||
char * message;
|
||||
JSErrorReport report; /* Line # of error, etc. */
|
||||
jthrowable java_exception; /* Java exception, error, or null */
|
||||
CapturedJSError * next; /* Next oldest captured JS error */
|
||||
};
|
||||
PR_END_EXTERN_C
|
||||
|
||||
#include "nsCLiveconnect.h"
|
||||
|
||||
static NS_DEFINE_IID(kILiveconnectIID, NS_ILIVECONNECT_IID);
|
||||
static NS_DEFINE_IID(kISupportsIID, NS_ISUPPORTS_IID);
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// from nsISupports and AggregatedQueryInterface:
|
||||
|
||||
// Thes macro expands to the aggregated query interface scheme.
|
||||
|
||||
NS_IMPL_AGGREGATED(nsCLiveconnect);
|
||||
|
||||
NS_METHOD
|
||||
nsCLiveconnect::AggregatedQueryInterface(const nsIID& aIID, void** aInstancePtr)
|
||||
{
|
||||
if (aIID.Equals(kISupportsIID)) {
|
||||
*aInstancePtr = GetInner();
|
||||
AddRef();
|
||||
return NS_OK;
|
||||
}
|
||||
if (aIID.Equals(kILiveconnectIID)) {
|
||||
*aInstancePtr = this;
|
||||
AddRef();
|
||||
return NS_OK;
|
||||
}
|
||||
return NS_NOINTERFACE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// from nsILiveconnect:
|
||||
|
||||
/**
|
||||
* get member of a Native JSObject for a given name.
|
||||
*
|
||||
* @param jEnv - JNIEnv on which the call is being made.
|
||||
* @param obj - A Native JS Object.
|
||||
* @param name - Name of a member.
|
||||
* @param pjobj - return parameter as a java object representing
|
||||
* the member. If it is a basic data type it is converted to
|
||||
* a corresponding java type. If it is a NJSObject, then it is
|
||||
* wrapped up as java wrapper netscape.javascript.JSObject.
|
||||
*/
|
||||
NS_METHOD
|
||||
nsCLiveconnect::GetMember(JNIEnv *jEnv, jsobject obj, const char *name, jobject *pjobj)
|
||||
{
|
||||
JSContext *cx = NULL;
|
||||
JSJavaThreadState *jsj_env = NULL;
|
||||
JSObject *js_obj = (JSObject *)obj;
|
||||
nsresult err = NS_OK;
|
||||
jobject member = NULL;
|
||||
jsval js_val = NULL;
|
||||
int dummy_cost = 0;
|
||||
JSBool dummy_bool = PR_FALSE;
|
||||
JavaToJSSavedState saved_state = {NULL,NULL};
|
||||
|
||||
if(jEnv == NULL)
|
||||
{
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
jsj_env = jsj_enter_js(jEnv, NULL, &cx, NULL, &saved_state);
|
||||
if (!jsj_env)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
if (!name) {
|
||||
JS_ReportError(cx, "illegal null member name");
|
||||
member = NULL;
|
||||
goto done;
|
||||
}
|
||||
|
||||
|
||||
if (!JS_GetProperty(cx, js_obj, name, &js_val))
|
||||
goto done;
|
||||
|
||||
jsj_ConvertJSValueToJavaObject(cx, jEnv, js_val, jsj_get_jlObject_descriptor(cx, jEnv),
|
||||
&dummy_cost, &member, &dummy_bool);
|
||||
|
||||
done:
|
||||
if (!jsj_exit_js(cx, jsj_env, &saved_state))
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
*pjobj = member;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* get member of a Native JSObject for a given index.
|
||||
*
|
||||
* @param jEnv - JNIEnv on which the call is being made.
|
||||
* @param obj - A Native JS Object.
|
||||
* @param index - Index of a member.
|
||||
* @param pjobj - return parameter as a java object representing
|
||||
* the member.
|
||||
*/
|
||||
NS_METHOD
|
||||
nsCLiveconnect::GetSlot(JNIEnv *jEnv, jsobject obj, int slot, jobject *pjobj)
|
||||
{
|
||||
JSContext *cx = NULL;
|
||||
JSJavaThreadState *jsj_env = NULL;
|
||||
JSObject *js_obj = (JSObject *)obj;
|
||||
nsresult err = NS_OK;
|
||||
jobject member = NULL;
|
||||
jsval js_val = NULL;
|
||||
int dummy_cost = 0;
|
||||
JSBool dummy_bool = PR_FALSE;
|
||||
JavaToJSSavedState saved_state = {NULL,NULL};
|
||||
|
||||
if(jEnv == NULL)
|
||||
{
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
jsj_env = jsj_enter_js(jEnv, NULL, &cx, NULL, &saved_state);
|
||||
if (!jsj_env)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
// =-= sudu: check to see if slot can be passed in as is.
|
||||
// Should it be converted to a jsint?
|
||||
if (!JS_GetElement(cx, js_obj, slot, &js_val))
|
||||
goto done;
|
||||
if (!jsj_ConvertJSValueToJavaObject(cx, jEnv, js_val, jsj_get_jlObject_descriptor(cx, jEnv),
|
||||
&dummy_cost, &member, &dummy_bool))
|
||||
goto done;
|
||||
|
||||
done:
|
||||
if (!jsj_exit_js(cx, jsj_env, &saved_state))
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
*pjobj = member;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* set member of a Native JSObject for a given name.
|
||||
*
|
||||
* @param jEnv - JNIEnv on which the call is being made.
|
||||
* @param obj - A Native JS Object.
|
||||
* @param name - Name of a member.
|
||||
* @param jobj - Value to set. If this is a basic data type, it is converted
|
||||
* using standard JNI calls but if it is a wrapper to a JSObject
|
||||
* then a internal mapping is consulted to convert to a NJSObject.
|
||||
*/
|
||||
NS_METHOD
|
||||
nsCLiveconnect::SetMember(JNIEnv *jEnv, jsobject obj, const char *name, jobject java_obj)
|
||||
{
|
||||
JSContext *cx = NULL;
|
||||
JSJavaThreadState *jsj_env = NULL;
|
||||
JSObject *js_obj = (JSObject *)obj;
|
||||
nsresult err = NS_OK;
|
||||
jobject member = NULL;
|
||||
jsval js_val = NULL;
|
||||
JavaToJSSavedState saved_state = {NULL,NULL};
|
||||
|
||||
if(jEnv == NULL)
|
||||
{
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
jsj_env = jsj_enter_js(jEnv, NULL, &cx, NULL, &saved_state);
|
||||
if (!jsj_env)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
if (!name) {
|
||||
JS_ReportError(cx, "illegal null member name");
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (!jsj_ConvertJavaObjectToJSValue(cx, jEnv, java_obj, &js_val))
|
||||
goto done;
|
||||
|
||||
JS_SetProperty(cx, js_obj, name, &js_val);
|
||||
|
||||
done:
|
||||
jsj_exit_js(cx, jsj_env, &saved_state);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* set member of a Native JSObject for a given index.
|
||||
*
|
||||
* @param jEnv - JNIEnv on which the call is being made.
|
||||
* @param obj - A Native JS Object.
|
||||
* @param index - Index of a member.
|
||||
* @param jobj - Value to set. If this is a basic data type, it is converted
|
||||
* using standard JNI calls but if it is a wrapper to a JSObject
|
||||
* then a internal mapping is consulted to convert to a NJSObject.
|
||||
*/
|
||||
NS_METHOD
|
||||
nsCLiveconnect::SetSlot(JNIEnv *jEnv, jsobject obj, int slot, jobject java_obj)
|
||||
{
|
||||
JSContext *cx = NULL;
|
||||
JSJavaThreadState *jsj_env = NULL;
|
||||
JSObject *js_obj = (JSObject *)obj;
|
||||
nsresult err = NS_OK;
|
||||
jsval js_val = NULL;
|
||||
JavaToJSSavedState saved_state = {NULL,NULL};
|
||||
|
||||
if(jEnv == NULL)
|
||||
{
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
jsj_env = jsj_enter_js(jEnv, NULL, &cx, NULL, &saved_state);
|
||||
if (!jsj_env)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
if (!jsj_ConvertJavaObjectToJSValue(cx, jEnv, java_obj, &js_val))
|
||||
goto done;
|
||||
JS_SetElement(cx, js_obj, slot, &js_val);
|
||||
|
||||
done:
|
||||
jsj_exit_js(cx, jsj_env, &saved_state);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* remove member of a Native JSObject for a given name.
|
||||
*
|
||||
* @param jEnv - JNIEnv on which the call is being made.
|
||||
* @param obj - A Native JS Object.
|
||||
* @param name - Name of a member.
|
||||
*/
|
||||
NS_METHOD
|
||||
nsCLiveconnect::RemoveMember(JNIEnv *jEnv, jsobject obj, const char *name)
|
||||
{
|
||||
JSContext *cx = NULL;
|
||||
JSJavaThreadState *jsj_env = NULL;
|
||||
JSObject *js_obj = (JSObject *)obj;
|
||||
nsresult err = NS_OK;
|
||||
jsval js_val = NULL;
|
||||
JavaToJSSavedState saved_state = {NULL,NULL};
|
||||
|
||||
if(jEnv == NULL)
|
||||
{
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
jsj_env = jsj_enter_js(jEnv, NULL, &cx, NULL, &saved_state);
|
||||
if (!jsj_env)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
if (!name) {
|
||||
JS_ReportError(cx, "illegal null member name");
|
||||
goto done;
|
||||
}
|
||||
JS_DeleteProperty2(cx, js_obj, name, &js_val);
|
||||
|
||||
done:
|
||||
jsj_exit_js(cx, jsj_env, &saved_state);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* call a method of Native JSObject.
|
||||
*
|
||||
* @param jEnv - JNIEnv on which the call is being made.
|
||||
* @param obj - A Native JS Object.
|
||||
* @param name - Name of a method.
|
||||
* @param jobjArr - Array of jobjects representing parameters of method being caled.
|
||||
* @param pjobj - return value.
|
||||
*/
|
||||
NS_METHOD
|
||||
nsCLiveconnect::Call(JNIEnv *jEnv, jsobject obj, const char *name, jobjectArray java_args, jobject *pjobj)
|
||||
{
|
||||
int i = 0;
|
||||
int argc = 0;
|
||||
int arg_num = 0;
|
||||
jsval *argv = 0;
|
||||
JSContext *cx = NULL;
|
||||
JSJavaThreadState *jsj_env = NULL;
|
||||
JSObject *js_obj = (JSObject *)obj;
|
||||
nsresult err = NS_OK;
|
||||
jobject member = NULL;
|
||||
jsval js_val = NULL;
|
||||
jsval function_val = NULL;
|
||||
int dummy_cost = 0;
|
||||
JSBool dummy_bool = PR_FALSE;
|
||||
JavaToJSSavedState saved_state = {NULL,NULL};
|
||||
jobject result = NULL;
|
||||
|
||||
if(jEnv == NULL)
|
||||
{
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
jsj_env = jsj_enter_js(jEnv, NULL, &cx, NULL, &saved_state);
|
||||
if (!jsj_env)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
result = NULL;
|
||||
if (!name) {
|
||||
JS_ReportError(cx, "illegal null JavaScript function name");
|
||||
goto done;
|
||||
}
|
||||
|
||||
|
||||
/* FIXME: What about security stuff ? Don't principals need to be set here ? */
|
||||
|
||||
/* Allocate space for JS arguments */
|
||||
if (java_args) {
|
||||
argc = jEnv->GetArrayLength(java_args);
|
||||
argv = (jsval*)JS_malloc(cx, argc * sizeof(jsval));
|
||||
} else {
|
||||
argc = 0;
|
||||
argv = 0;
|
||||
}
|
||||
|
||||
/* Convert arguments from Java to JS values */
|
||||
for (arg_num = 0; arg_num < argc; arg_num++) {
|
||||
jobject arg = jEnv->GetObjectArrayElement(java_args, arg_num);
|
||||
|
||||
if (!jsj_ConvertJavaObjectToJSValue(cx, jEnv, arg, &argv[arg_num]))
|
||||
goto cleanup_argv;
|
||||
JS_AddRoot(cx, &argv[arg_num]);
|
||||
}
|
||||
|
||||
if (!JS_GetProperty(cx, js_obj, name, &function_val))
|
||||
goto cleanup_argv;
|
||||
|
||||
if (!JS_CallFunctionValue(cx, js_obj, function_val, argc, argv, &js_val))
|
||||
goto cleanup_argv;
|
||||
|
||||
jsj_ConvertJSValueToJavaObject(cx, jEnv, js_val, jsj_get_jlObject_descriptor(cx, jEnv),
|
||||
&dummy_cost, &result, &dummy_bool);
|
||||
|
||||
cleanup_argv:
|
||||
if (argv) {
|
||||
for (i = 0; i < arg_num; i++)
|
||||
JS_RemoveRoot(cx, &argv[i]);
|
||||
JS_free(cx, argv);
|
||||
}
|
||||
|
||||
done:
|
||||
if (!jsj_exit_js(cx, jsj_env, &saved_state))
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
*pjobj = result;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Evaluate a script with a Native JS Object representing scope.
|
||||
*
|
||||
* @param jEnv - JNIEnv on which the call is being made.
|
||||
* @param obj - A Native JS Object.
|
||||
* @param pNSIPrincipaArray - Array of principals to be used to compare privileges.
|
||||
* @param numPrincipals - Number of principals being passed.
|
||||
* @param script - Script to be executed.
|
||||
* @param pjobj - return value.
|
||||
*/
|
||||
NS_METHOD
|
||||
nsCLiveconnect::Eval(JNIEnv *jEnv, jsobject obj, const char *script, jobject *pjobj)
|
||||
{
|
||||
JSContext *cx = NULL;
|
||||
JSJavaThreadState *jsj_env = NULL;
|
||||
JSObject *js_obj = (JSObject *)obj;
|
||||
nsresult err = NS_OK;
|
||||
jobject member = NULL;
|
||||
jsval js_val = NULL;
|
||||
jsval function_val = NULL;
|
||||
int dummy_cost = 0;
|
||||
JSBool dummy_bool = PR_FALSE;
|
||||
JavaToJSSavedState saved_state = {NULL,NULL};
|
||||
jobject result = NULL;
|
||||
const char *codebase = NULL;
|
||||
JSPrincipals *principals = NULL;
|
||||
JSBool eval_succeeded = PR_FALSE;
|
||||
|
||||
if(jEnv == NULL)
|
||||
{
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
jsj_env = jsj_enter_js(jEnv, NULL, &cx, NULL, &saved_state);
|
||||
if (!jsj_env)
|
||||
return NULL;
|
||||
|
||||
result = NULL;
|
||||
if (!script) {
|
||||
JS_ReportError(cx, "illegal null string eval argument");
|
||||
goto done;
|
||||
}
|
||||
|
||||
|
||||
/* Set up security stuff */
|
||||
principals = NULL;
|
||||
if (JSJ_callbacks->get_JSPrincipals_from_java_caller)
|
||||
principals = JSJ_callbacks->get_JSPrincipals_from_java_caller(jEnv, cx);
|
||||
codebase = principals ? principals->codebase : NULL;
|
||||
|
||||
/* Have the JS engine evaluate the unicode string */
|
||||
eval_succeeded = JS_EvaluateScriptForPrincipals(cx, js_obj, principals,
|
||||
script, strlen(script),
|
||||
codebase, 0, &js_val);
|
||||
if (!eval_succeeded)
|
||||
goto done;
|
||||
|
||||
/* Convert result to a subclass of java.lang.Object */
|
||||
jsj_ConvertJSValueToJavaObject(cx, jEnv, js_val, jsj_get_jlObject_descriptor(cx, jEnv),
|
||||
&dummy_cost, &result, &dummy_bool);
|
||||
|
||||
done:
|
||||
if (!jsj_exit_js(cx, jsj_env, &saved_state))
|
||||
return NULL;
|
||||
|
||||
*pjobj = result;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the window object for a plugin instance.
|
||||
*
|
||||
* @param jEnv - JNIEnv on which the call is being made.
|
||||
* @param pJavaObject - Either a jobject or a pointer to a plugin instance
|
||||
* representing the java object.
|
||||
* @param pjobj - return value. This is a native js object
|
||||
* representing the window object of a frame
|
||||
* in which a applet/bean resides.
|
||||
*/
|
||||
NS_METHOD
|
||||
nsCLiveconnect::GetWindow(JNIEnv *jEnv, void *pJavaObject, jsobject *pobj)
|
||||
{
|
||||
char *err_msg = NULL;
|
||||
JSContext *cx = NULL;
|
||||
JSObject *js_obj = NULL;
|
||||
jsval js_val = NULL;
|
||||
int dummy_cost = 0;
|
||||
JSBool dummy_bool = PR_FALSE;
|
||||
JavaToJSSavedState saved_state = {NULL,NULL};
|
||||
jobject java_obj = NULL;
|
||||
JSJavaThreadState *jsj_env = NULL;
|
||||
|
||||
if(jEnv == NULL)
|
||||
{
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
jsj_env = jsj_enter_js(jEnv, NULL, &cx, NULL, &saved_state);
|
||||
if (!jsj_env)
|
||||
return NULL;
|
||||
|
||||
err_msg = NULL;
|
||||
java_obj = NULL;
|
||||
js_obj = JSJ_callbacks->map_java_object_to_js_object(jEnv, pJavaObject, &err_msg);
|
||||
if (!js_obj) {
|
||||
if (err_msg) {
|
||||
JS_ReportError(cx, err_msg);
|
||||
free(err_msg);
|
||||
}
|
||||
goto done;
|
||||
}
|
||||
#if 0
|
||||
js_val = OBJECT_TO_JSVAL(js_obj);
|
||||
jsj_ConvertJSValueToJavaObject(cx, jEnv, js_val, jsj_get_jlObject_descriptor(cx, jEnv),
|
||||
&dummy_cost, &java_obj, &dummy_bool);
|
||||
#endif
|
||||
done:
|
||||
if (!jsj_exit_js(cx, jsj_env, &saved_state))
|
||||
return NULL;
|
||||
|
||||
//*pjobj = java_obj;
|
||||
*pobj = (jint)js_obj;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the window object for a plugin instance.
|
||||
*
|
||||
* @param jEnv - JNIEnv on which the call is being made.
|
||||
* @param obj - A Native JS Object.
|
||||
*/
|
||||
NS_METHOD
|
||||
nsCLiveconnect::FinalizeJSObject(JNIEnv *jEnv, jsobject obj)
|
||||
{
|
||||
JSContext *cx = NULL;
|
||||
JavaToJSSavedState saved_state = {NULL,NULL};
|
||||
JSJavaThreadState *jsj_env = NULL;
|
||||
JSObject *js_obj = (JSObject *)obj;
|
||||
|
||||
if(jEnv == NULL)
|
||||
{
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
jsj_env = jsj_enter_js(jEnv, NULL, &cx, NULL, &saved_state);
|
||||
if (!jsj_env) /* Note: memory leak if we exit here */
|
||||
return NS_ERROR_FAILURE;
|
||||
#ifdef PRESERVE_JSOBJECT_IDENTITY
|
||||
jsj_remove_js_obj_reflection_from_hashtable(cx, js_obj);
|
||||
#endif /* PRESERVE_JSOBJECT_IDENTITY */
|
||||
jsj_exit_js(cx, jsj_env, &saved_state);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// from nsCLiveconnect:
|
||||
|
||||
nsCLiveconnect::nsCLiveconnect(nsISupports *aOuter)
|
||||
{
|
||||
NS_INIT_AGGREGATED(aOuter);
|
||||
jsj_init_js_obj_reflections_table();
|
||||
}
|
||||
|
||||
nsCLiveconnect::~nsCLiveconnect()
|
||||
{
|
||||
}
|
||||
|
||||
166
mozilla/js/src/liveconnect/nsCLiveconnect.h
Normal file
@@ -0,0 +1,166 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.0 (the "NPL"); you may not use this file except in
|
||||
* compliance with the NPL. You may obtain a copy of the NPL at
|
||||
* http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
||||
* for the specific language governing rights and limitations under the
|
||||
* NPL.
|
||||
*
|
||||
* The Initial Developer of this code under the NPL is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
||||
* Reserved.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is part of the Java-vendor-neutral implementation of LiveConnect
|
||||
*
|
||||
* It contains class definition implementing the public interface.
|
||||
*
|
||||
*/
|
||||
/*
|
||||
* This file is part of the Java-vendor-neutral implementation of LiveConnect
|
||||
*
|
||||
* It contains the class definition to implement nsILiveconnect XP-COM interface.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifndef nsCLiveconnect_h___
|
||||
#define nsCLiveconnect_h___
|
||||
|
||||
#include "nsILiveconnect.h"
|
||||
#include "nsAgg.h"
|
||||
|
||||
|
||||
/**
|
||||
* nsCLiveconnect implements nsILiveconnect interface for navigator.
|
||||
* This is used by a JVM to implement netscape.javascript.JSObject functionality.
|
||||
*/
|
||||
class nsCLiveconnect :public nsILiveconnect {
|
||||
public:
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// from nsISupports and AggregatedQueryInterface:
|
||||
|
||||
NS_DECL_AGGREGATED
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// from nsILiveconnect:
|
||||
|
||||
/**
|
||||
* get member of a Native JSObject for a given name.
|
||||
*
|
||||
* @param obj - A Native JS Object.
|
||||
* @param name - Name of a member.
|
||||
* @param pjobj - return parameter as a java object representing
|
||||
* the member. If it is a basic data type it is converted to
|
||||
* a corresponding java type. If it is a NJSObject, then it is
|
||||
* wrapped up as java wrapper netscape.javascript.JSObject.
|
||||
*/
|
||||
NS_IMETHOD
|
||||
GetMember(JNIEnv *jEnv, jsobject obj, const char *name, jobject *pjobj);
|
||||
|
||||
/**
|
||||
* get member of a Native JSObject for a given index.
|
||||
*
|
||||
* @param obj - A Native JS Object.
|
||||
* @param index - Index of a member.
|
||||
* @param pjobj - return parameter as a java object representing
|
||||
* the member.
|
||||
*/
|
||||
NS_IMETHOD
|
||||
GetSlot(JNIEnv *jEnv, jsobject obj, int index, jobject *pjobj);
|
||||
|
||||
/**
|
||||
* set member of a Native JSObject for a given name.
|
||||
*
|
||||
* @param obj - A Native JS Object.
|
||||
* @param name - Name of a member.
|
||||
* @param jobj - Value to set. If this is a basic data type, it is converted
|
||||
* using standard JNI calls but if it is a wrapper to a JSObject
|
||||
* then a internal mapping is consulted to convert to a NJSObject.
|
||||
*/
|
||||
NS_IMETHOD
|
||||
SetMember(JNIEnv *jEnv, jsobject obj, const char *name, jobject jobj);
|
||||
|
||||
/**
|
||||
* set member of a Native JSObject for a given index.
|
||||
*
|
||||
* @param obj - A Native JS Object.
|
||||
* @param index - Index of a member.
|
||||
* @param jobj - Value to set. If this is a basic data type, it is converted
|
||||
* using standard JNI calls but if it is a wrapper to a JSObject
|
||||
* then a internal mapping is consulted to convert to a NJSObject.
|
||||
*/
|
||||
NS_IMETHOD
|
||||
SetSlot(JNIEnv *jEnv, jsobject obj, int slot, jobject jobj);
|
||||
|
||||
/**
|
||||
* remove member of a Native JSObject for a given name.
|
||||
*
|
||||
* @param obj - A Native JS Object.
|
||||
* @param name - Name of a member.
|
||||
*/
|
||||
NS_IMETHOD
|
||||
RemoveMember(JNIEnv *jEnv, jsobject obj, const char *name);
|
||||
|
||||
/**
|
||||
* call a method of Native JSObject.
|
||||
*
|
||||
* @param obj - A Native JS Object.
|
||||
* @param name - Name of a method.
|
||||
* @param jobjArr - Array of jobjects representing parameters of method being caled.
|
||||
* @param pjobj - return value.
|
||||
*/
|
||||
NS_IMETHOD
|
||||
Call(JNIEnv *jEnv, jsobject obj, const char *name, jobjectArray jobjArr, jobject *pjobj);
|
||||
|
||||
/**
|
||||
* Evaluate a script with a Native JS Object representing scope.
|
||||
*
|
||||
* @param obj - A Native JS Object.
|
||||
* @param pNSIPrincipaArray - Array of principals to be used to compare privileges.
|
||||
* @param numPrincipals - Number of principals being passed.
|
||||
* @param script - Script to be executed.
|
||||
* @param pjobj - return value.
|
||||
*/
|
||||
NS_IMETHOD
|
||||
//Eval(JNIEnv *jEnv, jsobject obj, nsIPrincipal **pNSIPrincipaArray, PRInt32 numPrincipals, const char *script, jobject *pjobj);
|
||||
Eval(JNIEnv *jEnv, jsobject obj, const char *script, jobject *pjobj);
|
||||
|
||||
/**
|
||||
* Get the window object for a plugin instance.
|
||||
*
|
||||
* @param pJavaObject - Either a jobject or a pointer to a plugin instance
|
||||
* representing the java object.
|
||||
* @param pjobj - return value. This is a native js object
|
||||
* representing the window object of a frame
|
||||
* in which a applet/bean resides.
|
||||
*/
|
||||
NS_IMETHOD
|
||||
GetWindow(JNIEnv *jEnv, void *pJavaObject, jsobject *pobj);
|
||||
|
||||
/**
|
||||
* Get the window object for a plugin instance.
|
||||
*
|
||||
* @param jEnv - JNIEnv on which the call is being made.
|
||||
* @param obj - A Native JS Object.
|
||||
*/
|
||||
NS_IMETHOD
|
||||
FinalizeJSObject(JNIEnv *jEnv, jsobject obj);
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// from nsCLiveconnect:
|
||||
|
||||
nsCLiveconnect(nsISupports *aOuter);
|
||||
virtual ~nsCLiveconnect(void);
|
||||
|
||||
protected:
|
||||
};
|
||||
|
||||
#endif // nsCLiveconnect_h___
|
||||
168
mozilla/js/src/liveconnect/nsCLiveconnectFactory.cpp
Normal file
@@ -0,0 +1,168 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.0 (the "NPL"); you may not use this file except in
|
||||
* compliance with the NPL. You may obtain a copy of the NPL at
|
||||
* http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
||||
* for the specific language governing rights and limitations under the
|
||||
* NPL.
|
||||
*
|
||||
* The Initial Developer of this code under the NPL is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
||||
* Reserved.
|
||||
*/
|
||||
/*
|
||||
* This file is part of the Java-vendor-neutral implementation of LiveConnect
|
||||
*
|
||||
* It contains the implementation providing nsILiveconnect XP-COM interface.
|
||||
*
|
||||
*/
|
||||
#include "prtypes.h"
|
||||
#include "nspr.h"
|
||||
#include "prmem.h"
|
||||
#include "prmon.h"
|
||||
#include "prlog.h"
|
||||
|
||||
#include "nsCLiveconnect.h"
|
||||
#include "nsCLiveconnectFactory.h"
|
||||
#include "nsRepository.h"
|
||||
|
||||
static NS_DEFINE_IID(kISupportsIID, NS_ISUPPORTS_IID);
|
||||
static NS_DEFINE_IID(kIFactoryIID, NS_IFACTORY_IID);
|
||||
static NS_DEFINE_CID(kCLiveconnectCID, NS_CLIVECONNECT_CID);
|
||||
static NS_DEFINE_IID(kILiveconnectIID, NS_ILIVECONNECT_IID);
|
||||
|
||||
nsIFactory *nsCLiveconnectFactory::m_pNSIFactory = NULL;
|
||||
nsCLiveconnect *nsCLiveconnectFactory::m_pNSCLiveconnect = NULL;
|
||||
|
||||
|
||||
|
||||
/*+++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
* NSGetFactory:
|
||||
* Provides entry point to liveconnect dll.
|
||||
+++++++++++++++++++++++++++++++++++++++++++++++++*/
|
||||
|
||||
extern "C" NS_EXPORT nsresult
|
||||
NSGetFactory(const nsCID &aClass, nsIFactory **aFactory)
|
||||
{
|
||||
|
||||
if (!aClass.Equals(kCLiveconnectCID)) {
|
||||
return NS_ERROR_FACTORY_NOT_LOADED; // XXX right error?
|
||||
}
|
||||
nsCLiveconnectFactory* pCLiveConnectFactory = new nsCLiveconnectFactory();
|
||||
if (pCLiveConnectFactory == NULL)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
pCLiveConnectFactory->AddRef();
|
||||
*aFactory = pCLiveConnectFactory;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
extern "C" NS_EXPORT PRBool
|
||||
NSCanUnload(void)
|
||||
{
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// from nsISupports
|
||||
|
||||
NS_METHOD
|
||||
nsCLiveconnectFactory::QueryInterface(const nsIID& aIID, void** aInstancePtr)
|
||||
{
|
||||
PR_ASSERT(NULL != aInstancePtr);
|
||||
if (NULL == aInstancePtr) {
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
}
|
||||
if (aIID.Equals(kIFactoryIID) ||
|
||||
aIID.Equals(kISupportsIID)) {
|
||||
*aInstancePtr = (void*) this;
|
||||
AddRef();
|
||||
return NS_OK;
|
||||
}
|
||||
return NS_NOINTERFACE;
|
||||
}
|
||||
|
||||
NS_IMPL_ADDREF(nsCLiveconnectFactory)
|
||||
NS_IMPL_RELEASE(nsCLiveconnectFactory)
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// from nsIFactory:
|
||||
|
||||
NS_METHOD
|
||||
nsCLiveconnectFactory::CreateInstance(nsISupports *aOuter, REFNSIID aIID, void **aResult)
|
||||
{
|
||||
nsCLiveconnect *pNSCLiveconnect = NULL;
|
||||
*aResult = NULL;
|
||||
|
||||
if (aOuter && !aIID.Equals(kISupportsIID))
|
||||
return NS_NOINTERFACE; // XXX right error?
|
||||
if (m_pNSCLiveconnect == NULL)
|
||||
{
|
||||
m_pNSCLiveconnect = new nsCLiveconnect(aOuter);
|
||||
}
|
||||
if (m_pNSCLiveconnect == NULL)
|
||||
{
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
if (m_pNSCLiveconnect->QueryInterface(aIID,
|
||||
(void**)aResult) != NS_OK) {
|
||||
// then we're trying get a interface other than nsISupports and
|
||||
// nsICapsManager
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_METHOD
|
||||
nsCLiveconnectFactory::LockFactory(PRBool aLock)
|
||||
{
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// from nsCLiveconnectFactory:
|
||||
|
||||
nsCLiveconnectFactory::nsCLiveconnectFactory(void)
|
||||
{
|
||||
if( m_pNSIFactory != NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
NS_INIT_REFCNT();
|
||||
nsresult err = NS_OK;
|
||||
NS_DEFINE_IID(kIFactoryIID, NS_IFACTORY_IID);
|
||||
|
||||
err = this->QueryInterface(kIFactoryIID, (void**)&m_pNSIFactory);
|
||||
if ( (err == NS_OK) && (m_pNSIFactory != NULL) )
|
||||
{
|
||||
NS_DEFINE_CID(kCLiveconnectCID, NS_CLIVECONNECT_CID);
|
||||
nsRepository::RegisterFactory(kCLiveconnectCID, m_pNSIFactory,
|
||||
PR_FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
nsCLiveconnectFactory::~nsCLiveconnectFactory()
|
||||
{
|
||||
if(mRefCnt == 0)
|
||||
{
|
||||
NS_DEFINE_CID(kCLiveconnectCID, NS_CLIVECONNECT_CID);
|
||||
nsRepository::UnregisterFactory(kCLiveconnectCID, (nsIFactory *)m_pNSIFactory);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
59
mozilla/js/src/liveconnect/nsCLiveconnectFactory.h
Normal file
@@ -0,0 +1,59 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.0 (the "NPL"); you may not use this file except in
|
||||
* compliance with the NPL. You may obtain a copy of the NPL at
|
||||
* http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
||||
* for the specific language governing rights and limitations under the
|
||||
* NPL.
|
||||
*
|
||||
* The Initial Developer of this code under the NPL is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
||||
* Reserved.
|
||||
*/
|
||||
/*
|
||||
* This file is part of the Java-vendor-neutral implementation of LiveConnect
|
||||
*
|
||||
* It contains the class definition to implement nsIFactory XP-COM interface.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef nsCLiveconnectFactory_h___
|
||||
#define nsCLiveconnectFactory_h___
|
||||
|
||||
#include "nsISupports.h"
|
||||
#include "nsIFactory.h"
|
||||
|
||||
class nsCLiveconnectFactory : public nsIFactory {
|
||||
public:
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// from nsISupports and AggregatedQueryInterface:
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// from nsIFactory:
|
||||
|
||||
NS_IMETHOD
|
||||
CreateInstance(nsISupports *aOuter, REFNSIID aIID, void **aResult);
|
||||
|
||||
NS_IMETHOD
|
||||
LockFactory(PRBool aLock);
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// from nsCLiveconnectFactory:
|
||||
|
||||
nsCLiveconnectFactory(void);
|
||||
virtual ~nsCLiveconnectFactory(void);
|
||||
|
||||
protected:
|
||||
static nsIFactory *m_pNSIFactory;
|
||||
static nsCLiveconnect *m_pNSCLiveconnect;
|
||||
};
|
||||
|
||||
#endif // nsCLiveconnectFactory_h___
|
||||
157
mozilla/js/src/liveconnect/nsILiveconnect.h
Normal file
@@ -0,0 +1,157 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.0 (the "NPL"); you may not use this file except in
|
||||
* compliance with the NPL. You may obtain a copy of the NPL at
|
||||
* http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
||||
* for the specific language governing rights and limitations under the
|
||||
* NPL.
|
||||
*
|
||||
* The Initial Developer of this code under the NPL is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
||||
* Reserved.
|
||||
*/
|
||||
/*
|
||||
* This file is part of the Java-vendor-neutral implementation of LiveConnect
|
||||
*
|
||||
* It contains the public XP-COM based interface for java to javascript communication.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef nsILiveconnect_h___
|
||||
#define nsILiveconnect_h___
|
||||
|
||||
#include "nsISupports.h"
|
||||
#include "nsIFactory.h"
|
||||
#include "jni.h"
|
||||
|
||||
|
||||
typedef jint jsobject;
|
||||
|
||||
class nsILiveconnect : public nsISupports {
|
||||
public:
|
||||
/**
|
||||
* get member of a Native JSObject for a given name.
|
||||
*
|
||||
* @param obj - A Native JS Object.
|
||||
* @param name - Name of a member.
|
||||
* @param pjobj - return parameter as a java object representing
|
||||
* the member. If it is a basic data type it is converted to
|
||||
* a corresponding java type. If it is a NJSObject, then it is
|
||||
* wrapped up as java wrapper netscape.javascript.JSObject.
|
||||
*/
|
||||
NS_IMETHOD
|
||||
GetMember(JNIEnv *jEnv, jsobject obj, const char *name, jobject *pjobj) = 0;
|
||||
|
||||
/**
|
||||
* get member of a Native JSObject for a given index.
|
||||
*
|
||||
* @param obj - A Native JS Object.
|
||||
* @param index - Index of a member.
|
||||
* @param pjobj - return parameter as a java object representing
|
||||
* the member.
|
||||
*/
|
||||
NS_IMETHOD
|
||||
GetSlot(JNIEnv *jEnv, jsobject obj, int index, jobject *pjobj) = 0;
|
||||
|
||||
/**
|
||||
* set member of a Native JSObject for a given name.
|
||||
*
|
||||
* @param obj - A Native JS Object.
|
||||
* @param name - Name of a member.
|
||||
* @param jobj - Value to set. If this is a basic data type, it is converted
|
||||
* using standard JNI calls but if it is a wrapper to a JSObject
|
||||
* then a internal mapping is consulted to convert to a NJSObject.
|
||||
*/
|
||||
NS_IMETHOD
|
||||
SetMember(JNIEnv *jEnv, jsobject obj, const char *name, jobject jobj) = 0;
|
||||
|
||||
/**
|
||||
* set member of a Native JSObject for a given index.
|
||||
*
|
||||
* @param obj - A Native JS Object.
|
||||
* @param index - Index of a member.
|
||||
* @param jobj - Value to set. If this is a basic data type, it is converted
|
||||
* using standard JNI calls but if it is a wrapper to a JSObject
|
||||
* then a internal mapping is consulted to convert to a NJSObject.
|
||||
*/
|
||||
NS_IMETHOD
|
||||
SetSlot(JNIEnv *jEnv, jsobject obj, int slot, jobject jobj) = 0;
|
||||
|
||||
/**
|
||||
* remove member of a Native JSObject for a given name.
|
||||
*
|
||||
* @param obj - A Native JS Object.
|
||||
* @param name - Name of a member.
|
||||
*/
|
||||
NS_IMETHOD
|
||||
RemoveMember(JNIEnv *jEnv, jsobject obj, const char *name) = 0;
|
||||
|
||||
/**
|
||||
* call a method of Native JSObject.
|
||||
*
|
||||
* @param obj - A Native JS Object.
|
||||
* @param name - Name of a method.
|
||||
* @param jobjArr - Array of jobjects representing parameters of method being caled.
|
||||
* @param pjobj - return value.
|
||||
*/
|
||||
NS_IMETHOD
|
||||
Call(JNIEnv *jEnv, jsobject obj, const char *name, jobjectArray jobjArr, jobject *pjobj) = 0;
|
||||
|
||||
/**
|
||||
* Evaluate a script with a Native JS Object representing scope.
|
||||
*
|
||||
* @param obj - A Native JS Object.
|
||||
* @param pNSIPrincipaArray - Array of principals to be used to compare privileges.
|
||||
* @param numPrincipals - Number of principals being passed.
|
||||
* @param script - Script to be executed.
|
||||
* @param pjobj - return value.
|
||||
*/
|
||||
NS_IMETHOD
|
||||
//Eval(jsobject obj, nsIPrincipal **pNSIPrincipaArray, PRInt32 numPrincipals, const char *script, jobject *pjobj) = 0;
|
||||
Eval(JNIEnv *jEnv, jsobject obj, const char *script, jobject *pjobj) = 0;
|
||||
|
||||
/**
|
||||
* Get the window object for a plugin instance.
|
||||
*
|
||||
* @param pJavaObject - Either a jobject or a pointer to a plugin instance
|
||||
* representing the java object.
|
||||
* @param pjobj - return value. This is a native js object
|
||||
* representing the window object of a frame
|
||||
* in which a applet/bean resides.
|
||||
*/
|
||||
NS_IMETHOD
|
||||
GetWindow(JNIEnv *jEnv, void *pJavaObject, jsobject *pobj) = 0;
|
||||
|
||||
/**
|
||||
* Get the window object for a plugin instance.
|
||||
*
|
||||
* @param jEnv - JNIEnv on which the call is being made.
|
||||
* @param obj - A Native JS Object.
|
||||
*/
|
||||
NS_IMETHOD
|
||||
FinalizeJSObject(JNIEnv *jEnv, jsobject obj) = 0;
|
||||
|
||||
};
|
||||
|
||||
#define NS_ILIVECONNECT_IID \
|
||||
{ /* 68190910-3318-11d2-97f0-00805f8a28d0 */ \
|
||||
0x68190910, \
|
||||
0x3318, \
|
||||
0x11d2, \
|
||||
{0x97, 0xf0, 0x00, 0x80, 0x5f, 0x8a, 0x28, 0xd0} \
|
||||
};
|
||||
|
||||
#define NS_CLIVECONNECT_CID \
|
||||
{ /* b8f0cef0-3931-11d2-97f0-00805f8a28d0 */ \
|
||||
0xb8f0cef0, \
|
||||
0x3931, \
|
||||
0x11d2, \
|
||||
{0x97, 0xf0, 0x00, 0x80, 0x5f, 0x8a, 0x28, 0xd0} \
|
||||
};
|
||||
|
||||
#endif // nsILiveconnect_h___
|
||||
@@ -1,58 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
import cgitb; cgitb.enable()
|
||||
|
||||
import sys
|
||||
import cgi
|
||||
import time
|
||||
import re
|
||||
|
||||
from pysqlite2 import dbapi2 as sqlite
|
||||
|
||||
print "Content-type: text/plain\n\n"
|
||||
|
||||
form = cgi.FieldStorage()
|
||||
|
||||
# incoming query string has the following parameters:
|
||||
# user=name
|
||||
# (REQUIRED) user that made this annotation
|
||||
# tbox=foopy
|
||||
# (REQUIRED) name of the tinderbox to annotate
|
||||
# data=string
|
||||
# annotation to record
|
||||
# time=seconds
|
||||
# time since the epoch in GMT of this test result; if ommitted, current time at time of script run is used
|
||||
|
||||
tbox = form.getfirst("tbox")
|
||||
user = form.getfirst("user")
|
||||
data = form.getfirst("data")
|
||||
timeval = form.getfirst("time")
|
||||
if timeval is None:
|
||||
timeval = int(time.time())
|
||||
|
||||
if (user is None) or (tbox is None) or (data is None):
|
||||
print "Bad args"
|
||||
sys.exit()
|
||||
|
||||
if re.match(r"[^A-Za-z0-9]", tbox):
|
||||
print "Bad tbox name"
|
||||
sys.exit()
|
||||
|
||||
db = sqlite.connect("db/" + tbox + ".sqlite")
|
||||
|
||||
try:
|
||||
db.execute("CREATE TABLE test_results (test_name STRING, test_time INTEGER, test_value FLOAT, test_data BLOB);")
|
||||
db.execute("CREATE TABLE annotations (anno_user STRING, anno_time INTEGER, anno_string STRING);")
|
||||
db.execute("CREATE INDEX test_name_idx ON test_results.test_name")
|
||||
db.execute("CREATE INDEX test_time_idx ON test_results.test_time")
|
||||
db.execute("CREATE INDEX anno_time_idx ON annotations.anno_time")
|
||||
except:
|
||||
pass
|
||||
|
||||
db.execute("INSERT INTO annotations VALUES (?,?,?)", (user, timeval, data))
|
||||
|
||||
db.commit()
|
||||
|
||||
print "Inserted."
|
||||
|
||||
sys.exit()
|
||||
@@ -1,59 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# bonsaibouncer
|
||||
#
|
||||
# Bounce a request to bonsai.mozilla.org, getting around silly
|
||||
# cross-domain XMLHTTPRequest deficiencies.
|
||||
#
|
||||
|
||||
import cgitb; cgitb.enable()
|
||||
|
||||
import os
|
||||
import sys
|
||||
import cgi
|
||||
import gzip
|
||||
import urllib
|
||||
from urllib import quote
|
||||
|
||||
import cStringIO
|
||||
|
||||
bonsai = "http://bonsai.mozilla.org/cvsquery.cgi";
|
||||
|
||||
def main():
|
||||
#doGzip = 0
|
||||
#try:
|
||||
# if string.find(os.environ["HTTP_ACCEPT_ENCODING"], "gzip") != -1:
|
||||
# doGzip = 1
|
||||
#except:
|
||||
# pass
|
||||
|
||||
form = cgi.FieldStorage()
|
||||
|
||||
treeid = form.getfirst("treeid")
|
||||
module = form.getfirst("module")
|
||||
branch = form.getfirst("branch")
|
||||
mindate = form.getfirst("mindate")
|
||||
maxdate = form.getfirst("maxdate")
|
||||
xml_nofiles = form.getfirst("xml_nofiles")
|
||||
|
||||
if not treeid or not module or not branch or not mindate or not maxdate:
|
||||
print "Content-type: text/plain\n\n"
|
||||
print "ERROR"
|
||||
return
|
||||
|
||||
url = bonsai + "?" + "branchtype=match&sortby=Date&date=explicit&cvsroot=%2Fcvsroot&xml=1"
|
||||
url += "&treeid=%s&module=%s&branch=%s&mindate=%s&maxdate=%s" % (quote(treeid), quote(module), quote(branch), quote(mindate), quote(maxdate))
|
||||
|
||||
if (xml_nofiles):
|
||||
url += "&xml_nofiles=1"
|
||||
|
||||
urlstream = urllib.urlopen(url)
|
||||
|
||||
sys.stdout.write("Content-type: text/xml\n\n")
|
||||
|
||||
for s in urlstream:
|
||||
sys.stdout.write(s)
|
||||
|
||||
urlstream.close()
|
||||
|
||||
main()
|
||||
@@ -1,216 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
import cgitb; cgitb.enable()
|
||||
|
||||
import sys
|
||||
import cgi
|
||||
import time
|
||||
import re
|
||||
|
||||
from graphsdb import db
|
||||
|
||||
#if var is a valid number returns a value other than None
|
||||
def checkNumber(var):
|
||||
if var is None:
|
||||
return 1
|
||||
reNumber = re.compile('^[0-9.]*$')
|
||||
return reNumber.match(var)
|
||||
|
||||
#if var is a valid string returns a value other than None
|
||||
def checkString(var):
|
||||
if var is None:
|
||||
return 1
|
||||
reString = re.compile('^[0-9A-Za-z._()\- ]*$')
|
||||
return reString.match(var)
|
||||
|
||||
print "Content-type: text/plain\n\n"
|
||||
link_format = "RETURN:%s:%.2f:%sspst=range&spstart=%d&spend=%d&bpst=cursor&bpstart=%d&bpend=%d&m1tid=%d&m1bl=0&m1avg=0\n"
|
||||
link_str = ""
|
||||
|
||||
|
||||
form = cgi.FieldStorage()
|
||||
|
||||
# incoming query string has the following parameters:
|
||||
# type=discrete|continuous
|
||||
# indicates discrete vs. continuous dataset, defaults to continuous
|
||||
# value=n
|
||||
# (REQUIRED) value to be recorded as the actual test value
|
||||
# tbox=foopy
|
||||
# (REQUIRED) name of the tinderbox reporting the value (or rather, the name that is to be given this set of data)
|
||||
# testname=test
|
||||
# (REQUIRED) the name of this test
|
||||
# data=rawdata
|
||||
# raw data for this test
|
||||
# time=seconds
|
||||
# time since the epoch in GMT of this test result; if ommitted, current time at time of script run is used
|
||||
# date
|
||||
# date that the test was run - this is for discrete graphs
|
||||
# branch=1.8.1,1.8.0 or 1.9.0
|
||||
# name of the branch that the build was generated for
|
||||
# branchid=id
|
||||
# date of the build
|
||||
# http://wiki.mozilla.org/MozillaQualityAssurance:Build_Ids
|
||||
|
||||
#takes as input a file for parsing in csv with the format:
|
||||
# value,testname,tbox,time,data,branch,branchid,type,data
|
||||
|
||||
# Create the DB schema if it doesn't already exist
|
||||
# XXX can pull out dataset_info.machine and dataset_info.{test,test_type} into two separate tables,
|
||||
# if we need to.
|
||||
|
||||
# value,testname,tbox,time,data,branch,branchid,type,data
|
||||
|
||||
fields = ["value", "testname", "tbox", "timeval", "date", "branch", "branchid", "type", "data"]
|
||||
strFields = ["type", "data", "tbox", "testname", "branch", "branchid"]
|
||||
numFields = ["date", "timeval", "value"]
|
||||
d_ids = []
|
||||
all_ids = []
|
||||
all_types = []
|
||||
if form.has_key("filename"):
|
||||
val = form["filename"]
|
||||
if val.file:
|
||||
print "found a file"
|
||||
for line in val.file:
|
||||
line = line.rstrip("\n\r")
|
||||
contents = line.split(',')
|
||||
#clear any previous content in the fields variables - stops reuse of data over lines
|
||||
for field in fields:
|
||||
globals()[field] = ''
|
||||
if len(contents) < 7:
|
||||
print "Incompatable file format"
|
||||
sys.exit(500)
|
||||
for field, content in zip(fields, contents):
|
||||
globals()[field] = content
|
||||
for strField in strFields:
|
||||
if not globals().has_key(strField):
|
||||
continue
|
||||
if not checkString(globals()[strField]):
|
||||
print "Invalid string arg: ", strField, " '" + globals()[strField] + "'"
|
||||
sys.exit(500)
|
||||
for numField in numFields:
|
||||
if not globals().has_key(numField):
|
||||
continue
|
||||
if not checkNumber(globals()[numField]):
|
||||
print "Invalid string arg: ", numField, " '" + globals()[numField] + "'"
|
||||
sys.exit(500)
|
||||
|
||||
#do some checks to ensure that we are enforcing the requirement rules of the script
|
||||
if (not type):
|
||||
type = "continuous"
|
||||
|
||||
if (not timeval):
|
||||
timeval = int(time.time())
|
||||
|
||||
if (type == "discrete") and (not date):
|
||||
print "Bad args, need a valid date"
|
||||
sys.exit(500)
|
||||
|
||||
if (not value) or (not tbox) or (not testname):
|
||||
print "Bad args"
|
||||
sys.exit(500)
|
||||
|
||||
|
||||
# figure out our dataset id
|
||||
setid = -1
|
||||
|
||||
# Not a big fan of this while loop. If something goes wrong with the select it will insert until the script times out.
|
||||
while setid == -1:
|
||||
cur = db.cursor()
|
||||
cur.execute("SELECT id FROM dataset_info WHERE type <=> ? AND machine <=> ? AND test <=> ? AND test_type <=> ? AND extra_data <=> ? AND branch <=> ? AND date <=> ? limit 1",
|
||||
(type, tbox, testname, "perf", "branch="+branch, branch, date))
|
||||
res = cur.fetchall()
|
||||
cur.close()
|
||||
|
||||
if len(res) == 0:
|
||||
db.execute("INSERT INTO dataset_info (type, machine, test, test_type, extra_data, branch, date) VALUES (?,?,?,?,?,?,?)",
|
||||
(type, tbox, testname, "perf", "branch="+branch, branch, date))
|
||||
else:
|
||||
setid = res[0][0]
|
||||
|
||||
db.execute("INSERT INTO dataset_values (dataset_id, time, value) VALUES (?,?,?)", (setid, timeval, value))
|
||||
db.execute("INSERT INTO dataset_branchinfo (dataset_id, time, branchid) VALUES (?,?,?)", (setid, timeval, branchid))
|
||||
if data and data != "":
|
||||
db.execute("INSERT INTO dataset_extra_data (dataset_id, time, data) VALUES (?,?,?)", (setid, timeval, data))
|
||||
|
||||
if (type == "discrete"):
|
||||
if not setid in d_ids:
|
||||
d_ids.append(setid)
|
||||
if not setid in all_ids:
|
||||
all_ids.append(setid)
|
||||
all_types.append(type)
|
||||
|
||||
for setid, type in zip(all_ids, all_types):
|
||||
cur = db.cursor()
|
||||
cur.execute("SELECT MIN(time), MAX(time), test FROM dataset_values, dataset_info WHERE dataset_id = ? and id = dataset_id GROUP BY test", (setid,))
|
||||
res = cur.fetchall()
|
||||
cur.close()
|
||||
tstart = res[0][0]
|
||||
tend = res[0][1]
|
||||
testname = res[0][2]
|
||||
if type == "discrete":
|
||||
link_str += (link_format % (testname, float(-1), "dgraph.html#name=" + testname + "&", tstart, tend, tstart, tend, setid,))
|
||||
else:
|
||||
tstart = 0
|
||||
link_str += (link_format % (testname, float(-1), "graph.html#",tstart, tend, tstart, tend, setid,))
|
||||
|
||||
#this code auto-adds a set of continuous data for each series of discrete data sets - creating an overview of the data
|
||||
# generated by a given test (matched by machine, test, test_type, extra_data and branch)
|
||||
for setid in d_ids:
|
||||
cur = db.cursor()
|
||||
#throw out the largest value and take the average of the rest
|
||||
cur.execute("SELECT AVG(value) FROM dataset_values WHERE dataset_id = ? and value != (SELECT MAX(value) from dataset_values where dataset_id = ?)", (setid, setid,))
|
||||
res = cur.fetchall()
|
||||
cur.close()
|
||||
avg = res[0][0]
|
||||
if avg is not None:
|
||||
cur = db.cursor()
|
||||
cur.execute("SELECT machine, test, test_type, extra_data, branch, date FROM dataset_info WHERE id = ?", (setid,))
|
||||
res = cur.fetchall()
|
||||
cur.close()
|
||||
tbox = res[0][0]
|
||||
testname = res[0][1]
|
||||
test_type = res[0][2]
|
||||
extra_data = res[0][3]
|
||||
branch = str(res[0][4])
|
||||
timeval = res[0][5]
|
||||
date = ''
|
||||
cur = db.cursor()
|
||||
cur.execute("SELECT branchid FROM dataset_branchinfo WHERE dataset_id = ?", (setid,))
|
||||
res = cur.fetchall()
|
||||
cur.close()
|
||||
branchid = res[0][0]
|
||||
dsetid = -1
|
||||
while dsetid == -1 :
|
||||
cur = db.cursor()
|
||||
cur.execute("SELECT id from dataset_info where type = ? AND machine <=> ? AND test = ? AND test_type = ? AND extra_data = ? AND branch <=> ? AND date <=> ? limit 1",
|
||||
("continuous", tbox, testname+"_avg", "perf", "branch="+branch, branch, date))
|
||||
res = cur.fetchall()
|
||||
cur.close()
|
||||
if len(res) == 0:
|
||||
db.execute("INSERT INTO dataset_info (type, machine, test, test_type, extra_data, branch, date) VALUES (?,?,?,?,?,?,?)",
|
||||
("continuous", tbox, testname+"_avg", "perf", "branch="+branch, branch, date))
|
||||
else:
|
||||
dsetid = res[0][0]
|
||||
cur = db.cursor()
|
||||
cur.execute("SELECT * FROM dataset_values WHERE dataset_id=? AND time <=> ? limit 1", (dsetid, timeval))
|
||||
res = cur.fetchall()
|
||||
cur.close()
|
||||
if len(res) == 0:
|
||||
db.execute("INSERT INTO dataset_values (dataset_id, time, value) VALUES (?,?,?)", (dsetid, timeval, avg))
|
||||
db.execute("INSERT INTO dataset_branchinfo (dataset_id, time, branchid) VALUES (?,?,?)", (dsetid, timeval, branchid))
|
||||
else:
|
||||
db.execute("UPDATE dataset_values SET value=? WHERE dataset_id=? AND time <=> ?", (avg, dsetid, timeval))
|
||||
db.execute("UPDATE dataset_branchinfo SET branchid=? WHERE dataset_id=? AND time <=> ?", (branchid, dsetid, timeval))
|
||||
cur = db.cursor()
|
||||
cur.execute("SELECT MIN(time), MAX(time) FROM dataset_values WHERE dataset_id = ?", (dsetid,))
|
||||
res = cur.fetchall()
|
||||
cur.close()
|
||||
tstart = 0
|
||||
tend = res[0][1]
|
||||
link_str += (link_format % (testname, float(avg), "graph.html#", tstart, tend, tstart, tend, dsetid,))
|
||||
|
||||
db.commit()
|
||||
print "Inserted."
|
||||
print link_str
|
||||
|
||||
sys.exit()
|
||||
@@ -1,175 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
import cgitb; cgitb.enable()
|
||||
|
||||
import sys
|
||||
import cgi
|
||||
import time
|
||||
import re
|
||||
|
||||
from graphsdb import db
|
||||
|
||||
#if var is a valid number returns a value other than None
|
||||
def checkNumber(var):
|
||||
if var is None:
|
||||
return 1
|
||||
reNumber = re.compile('^[0-9.]*$')
|
||||
return reNumber.match(var)
|
||||
|
||||
#if var is a valid string returns a value other than None
|
||||
def checkString(var):
|
||||
if var is None:
|
||||
return 1
|
||||
reString = re.compile('^[0-9A-Za-z._()\- ]*$')
|
||||
return reString.match(var)
|
||||
|
||||
print "Content-type: text/plain\n\n"
|
||||
link_format = "RETURN:%.2f:%sspst=range&spstart=%d&spend=%d&bpst=cursor&bpstart=%d&bpend=%d&m1tid=%d&m1bl=0&m1avg=0\n"
|
||||
link_str = ""
|
||||
|
||||
|
||||
form = cgi.FieldStorage()
|
||||
|
||||
# incoming query string has the following parameters:
|
||||
# type=discrete|continuous
|
||||
# indicates discrete vs. continuous dataset, defaults to continuous
|
||||
# value=n
|
||||
# (REQUIRED) value to be recorded as the actual test value
|
||||
# tbox=foopy
|
||||
# (REQUIRED) name of the tinderbox reporting the value (or rather, the name that is to be given this set of data)
|
||||
# testname=test
|
||||
# (REQUIRED) the name of this test
|
||||
# data=rawdata
|
||||
# raw data for this test
|
||||
# time=seconds
|
||||
# time since the epoch in GMT of this test result; if ommitted, current time at time of script run is used
|
||||
# date
|
||||
# date that the test was run - this is for discrete graphs
|
||||
# branch=1.8.1,1.8.0 or 1.9.0
|
||||
# name of the branch that the build was generated for
|
||||
# branchid=id
|
||||
# date of the build
|
||||
# http://wiki.mozilla.org/MozillaQualityAssurance:Build_Ids
|
||||
|
||||
#make sure that we are getting clean data from the user
|
||||
for strField in ["type", "data", "tbox", "testname", "branch", "branchid"]:
|
||||
val = form.getfirst(strField)
|
||||
if not checkString(val):
|
||||
print "Invalid string arg: ", strField, " '" + val + "'"
|
||||
sys.exit(500)
|
||||
globals()[strField] = val
|
||||
|
||||
for numField in ["date", "time", "value"]:
|
||||
val = form.getfirst(numField)
|
||||
if numField == "time":
|
||||
numField = "timeval"
|
||||
if not checkNumber(val):
|
||||
print "Invalid num arg: ", numField, " '" + val + "'"
|
||||
sys.exit(500)
|
||||
globals()[numField] = val
|
||||
|
||||
#do some checks to ensure that we are enforcing the requirement rules of the script
|
||||
if (not type):
|
||||
type = "continuous"
|
||||
|
||||
if (not timeval):
|
||||
timeval = int(time.time())
|
||||
|
||||
if (type == "discrete") and (not date):
|
||||
print "Bad args, need a valid date"
|
||||
sys.exit(500)
|
||||
|
||||
if (not value) or (not tbox) or (not testname):
|
||||
print "Bad args"
|
||||
sys.exit(500)
|
||||
|
||||
|
||||
# Create the DB schema if it doesn't already exist
|
||||
# XXX can pull out dataset_info.machine and dataset_info.{test,test_type} into two separate tables,
|
||||
# if we need to.
|
||||
|
||||
# figure out our dataset id
|
||||
setid = -1
|
||||
|
||||
while setid == -1:
|
||||
cur = db.cursor()
|
||||
cur.execute("SELECT id FROM dataset_info WHERE type <=> ? AND machine <=> ? AND test <=> ? AND test_type <=> ? AND extra_data=? AND branch <=> ? AND date <=> ?",
|
||||
(type, tbox, testname, "perf", "branch="+branch, branch, date))
|
||||
res = cur.fetchall()
|
||||
cur.close()
|
||||
|
||||
if len(res) == 0:
|
||||
db.execute("INSERT INTO dataset_info (type, machine, test, test_type, extra_data, branch, date) VALUES (?,?,?,?,?,?,?)",
|
||||
(type, tbox, testname, "perf", "branch="+branch, branch, date))
|
||||
else:
|
||||
setid = res[0][0]
|
||||
|
||||
db.execute("INSERT INTO dataset_values (dataset_id, time, value) VALUES (?,?,?)", (setid, timeval, value))
|
||||
db.execute("INSERT INTO dataset_branchinfo (dataset_id, time, branchid) VALUES (?,?,?)", (setid, timeval, branchid))
|
||||
if data and data != "":
|
||||
db.execute("INSERT INTO dataset_extra_data (dataset_id, time, data) VALUES (?,?,?)", (setid, timeval, data))
|
||||
|
||||
cur = db.cursor()
|
||||
cur.execute("SELECT MIN(time), MAX(time) FROM dataset_values WHERE dataset_id = ?", (setid,))
|
||||
res = cur.fetchall()
|
||||
cur.close()
|
||||
tstart = res[0][0]
|
||||
tend = res[0][1]
|
||||
if type == "discrete":
|
||||
link_str += (link_format % (float(-1), "dgraph.html#name=" + testname + "&", tstart, tend, tstart, tend, setid,))
|
||||
else:
|
||||
tstart = 0
|
||||
link_str += (link_format % (float(-1), "graph.html#",tstart, tend, tstart, tend, setid,))
|
||||
|
||||
|
||||
#this code auto-adds a set of continuous data for each series of discrete data sets - creating an overview of the data
|
||||
# generated by a given test (matched by machine, test, test_type, extra_data and branch)
|
||||
# it is not terribly efficient as it updates the tracking number on the continuous set each time a point is added
|
||||
# to the discrete set. If the efficiency becomes a concern we can re-examine the code - for now it is a good
|
||||
# solution for generating the secondary, tracking data.
|
||||
if type == "discrete" :
|
||||
timeval = date
|
||||
date = ''
|
||||
cur = db.cursor()
|
||||
#throw out the largest value and take the average of the rest
|
||||
cur.execute("SELECT AVG(value) FROM dataset_values WHERE dataset_id = ? and value != (SELECT MAX(value) from dataset_values where dataset_id = ?)", (setid, setid,))
|
||||
res = cur.fetchall()
|
||||
cur.close()
|
||||
avg = res[0][0]
|
||||
if avg is not None:
|
||||
|
||||
setid = -1
|
||||
while setid == -1 :
|
||||
cur = db.cursor()
|
||||
cur.execute("SELECT id from dataset_info where type <=> ? AND machine <=> ? AND test <=> ? AND test_type <=> ? AND extra_data <=> ? AND branch <=> ? AND date <=> ?",
|
||||
("continuous", tbox, testname+"_avg", "perf", "branch="+branch, branch, date))
|
||||
res = cur.fetchall()
|
||||
cur.close()
|
||||
if len(res) == 0:
|
||||
db.execute("INSERT INTO dataset_info (type, machine, test, test_type, extra_data, branch, date) VALUES (?,?,?,?,?,?,?)",
|
||||
("continuous", tbox, testname+"_avg", "perf", "branch="+branch, branch, date))
|
||||
else:
|
||||
setid = res[0][0]
|
||||
cur = db.cursor()
|
||||
cur.execute("SELECT * FROM dataset_values WHERE dataset_id=? AND time <=> ?", (setid, timeval))
|
||||
res = cur.fetchall()
|
||||
cur.close()
|
||||
if len(res) == 0:
|
||||
db.execute("INSERT INTO dataset_values (dataset_id, time, value) VALUES (?,?,?)", (setid, timeval, avg))
|
||||
db.execute("INSERT INTO dataset_branchinfo (dataset_id, time, branchid) VALUES (?,?,?)", (setid, timeval, branchid))
|
||||
else:
|
||||
db.execute("UPDATE dataset_values SET value=? WHERE dataset_id=? AND time <=> ?", (avg, setid, timeval))
|
||||
db.execute("UPDATE dataset_branchinfo SET branchid=? WHERE dataset_id=? AND time <=> ?", (branchid, setid, timeval))
|
||||
cur = db.cursor()
|
||||
cur.execute("SELECT MIN(time), MAX(time) FROM dataset_values WHERE dataset_id = ?", (setid,))
|
||||
res = cur.fetchall()
|
||||
cur.close()
|
||||
tstart = 0
|
||||
tend = res[0][1]
|
||||
link_str += (link_format % (float(avg), "graph.html#", tstart, tend, tstart, tend, setid,))
|
||||
|
||||
db.commit()
|
||||
print "Inserted."
|
||||
print link_str
|
||||
|
||||
sys.exit()
|
||||
@@ -1,20 +0,0 @@
|
||||
import MySQLdb
|
||||
from MySQLdb import *
|
||||
|
||||
|
||||
|
||||
|
||||
class GraphConnection(MySQLdb.connections.Connection):
|
||||
def execute(self,query, args):
|
||||
cur = self.cursor()
|
||||
result = cur.execute(query,args)
|
||||
cur.close()
|
||||
return result
|
||||
class GraphsCursor(MySQLdb.cursors.Cursor):
|
||||
def execute(self, query, args=None):
|
||||
query = query.replace('?','%s')
|
||||
return MySQLdb.cursors.Cursor.execute(self, query, args)
|
||||
|
||||
def connect(*args,**kwargs):
|
||||
kwargs['cursorclass'] = GraphsCursor
|
||||
return GraphConnection(*args,**kwargs)
|
||||
@@ -1,105 +0,0 @@
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
||||
<html>
|
||||
<head>
|
||||
<title>Perf-o-matic-too</title>
|
||||
|
||||
<link rel="stylesheet" type="text/css" href="js/graph.css"></link>
|
||||
|
||||
<!-- MochiKit -->
|
||||
<script type="text/javascript" src="js/mochikit/MochiKit.js"></script>
|
||||
|
||||
<!-- YUI -->
|
||||
<script type="text/javascript" src="js/yui/yahoo.js"></script>
|
||||
<script type="text/javascript" src="js/yui/dom.js"></script>
|
||||
<script type="text/javascript" src="js/yui/event.js"></script>
|
||||
<script type="text/javascript" src="js/yui/animation.js"></script>
|
||||
<script type="text/javascript" src="js/yui/container.js"></script>
|
||||
|
||||
<!-- Core -->
|
||||
<script type="text/javascript" src="js/TinderboxData.js"></script>
|
||||
<script type="text/javascript" src="js/DataSet.js"></script>
|
||||
<script type="text/javascript" src="js/GraphCanvas.js"></script>
|
||||
|
||||
<script type="text/javascript" src="js/dGraphFormModule.js"></script>
|
||||
<script type="text/javascript" src="js/graph.js"></script>
|
||||
<script type="text/javascript" src="js/ResizeGraph.js"></script>
|
||||
|
||||
<!-- BonsaiService needs e4x -->
|
||||
<script type="text/javascript; e4x=1" src="js/BonsaiService.js"></script>
|
||||
</head>
|
||||
|
||||
<body onload="loadingDone(DISCRETE_GRAPH)">
|
||||
<!--<h1>Graph</h1>-->
|
||||
|
||||
<!-- Take your damn divs and floats and clears and shove 'em! -->
|
||||
|
||||
<div style="width: 710px; height:20px; margin-left:10px ">
|
||||
<span id="loading" class="loading"></span>
|
||||
</div>
|
||||
<form action="javascript:;">
|
||||
<table class="graphconfig-no" width="100%">
|
||||
|
||||
<tr style="vertical-align: top">
|
||||
<td class="graphconfig-list">
|
||||
<div id="graphforms"></div>
|
||||
|
||||
</td>
|
||||
<td class="graphconfig-test-list">
|
||||
<div id="graphforms-test-list"></div>
|
||||
</td>
|
||||
|
||||
<td class="dgraphconfig">
|
||||
<!--
|
||||
<div id="baseline">
|
||||
<span>Use </span><select id="baselineDropdown"><option value="0">nothing</option></select><span> as a baseline</span><br>
|
||||
</div>
|
||||
-->
|
||||
<br>
|
||||
|
||||
<div id="formend">
|
||||
<input id="graphbutton" type="submit" onclick="onGraph()" value="Graph It!">
|
||||
<!-- <label for="baseline">No baseline</label><input type="radio" name="baseline" checked onclick="onNoBaseLineClick()"> -->
|
||||
</br> </br>
|
||||
<div><a id="linktothis" href="dgraph.html">Link to this graph</a> </div>
|
||||
</br>
|
||||
<div><a id="dumptocsv" href="dumpdata.cgi">Dump to csv</a> </div>
|
||||
</div>
|
||||
|
||||
</tr>
|
||||
|
||||
</table>
|
||||
</form>
|
||||
|
||||
<!-- small graph -->
|
||||
<div style="width: 900px; height:20px">
|
||||
<center><span id="status" class="status"></span></center>
|
||||
</div>
|
||||
|
||||
<div id="container" style="width: 100%">
|
||||
|
||||
<!-- these are absolute size, so we wrap them in a div that can overflow -->
|
||||
<div id="graph-container" style="width: 900px; margin:auto">
|
||||
<div id="smallgraph-labels-x" style="position: relative; left: 51px; margin-left: 1px; margin-right: 1px; height: 30px; width: 700px"></div>
|
||||
<div id="smallgraph-labels-y" style="position: relative; left: 0px; top: 0px; float: left; height: 76px; width: 50px;"></div>
|
||||
<canvas style="clear: left; border: 1px solid #888; padding-top: 1px;" id="smallgraph" height="75" width="650"></canvas>
|
||||
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
<div id="graph-labels-y" style="position: relative; left: 0px; top: 0px; float: left; margin-top: 1px; margin-bottom: 1px; height: 300px; width: 50px;"></div>
|
||||
<canvas style="clear: left; border: 1px solid #888;" id="graph" height="300" width="650"></canvas>
|
||||
<div id="graph-labels-x" style="position: relative; left: 50px; margin-left: 1px; margin-right: 1px; height: 50px; width: 700px"></div>
|
||||
</div>
|
||||
<div id="graph-label-container" style="float:left;margin-top:30px;">
|
||||
<span id="graph-label-list" class="graph-label-list-member" align="left"></span>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<script>
|
||||
ResizableBigGraph = new ResizeGraph();
|
||||
ResizableBigGraph.init('graph');
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -1,127 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
import cgitb; cgitb.enable()
|
||||
|
||||
import os
|
||||
import sys
|
||||
import cgi
|
||||
import time
|
||||
import re
|
||||
import gzip
|
||||
import minjson as json
|
||||
|
||||
import cStringIO
|
||||
|
||||
from graphsdb import db
|
||||
|
||||
#
|
||||
# returns a plain text file containing the information for a given dataset in two csv tables
|
||||
# the first table containing the dataset info (branch, date, etc)
|
||||
# the second table containing the databaset values
|
||||
#
|
||||
# incoming query string:
|
||||
#
|
||||
# setid=number
|
||||
# Where number is a valid setid
|
||||
#
|
||||
# starttime=tval
|
||||
# Start time to return results from, in seconds since GMT epoch
|
||||
# endtime=tval
|
||||
# End time, in seconds since GMT epoch
|
||||
|
||||
def doError(errCode):
|
||||
errString = "unknown error"
|
||||
if errCode == -1:
|
||||
errString = "bad tinderbox"
|
||||
elif errCode == -2:
|
||||
errString = "bad test name"
|
||||
print "{ resultcode: " + str(errCode) + ", error: '" + errString + "' }"
|
||||
|
||||
def esc(val):
|
||||
delim = '"'
|
||||
val = delim + str(val).replace(delim, delim + delim) + delim
|
||||
return val
|
||||
|
||||
def dumpData(fo, setid, starttime, endtime):
|
||||
s1 = ""
|
||||
s2 = ""
|
||||
if starttime:
|
||||
s1 = " AND time >= B." + starttime
|
||||
if endtime:
|
||||
s2 = " AND time <= B." + endtime
|
||||
|
||||
cur = db.cursor()
|
||||
setid = ",".join(setid)
|
||||
fo.write("dataset,machine,branch,test,date\n")
|
||||
cur.execute("SELECT B.id, B.machine, B.branch, B.test, B.date FROM dataset_info as B WHERE id IN (%s) %s %s ORDER BY id" % (setid, s1, s2,))
|
||||
for row in cur:
|
||||
fo.write ('%s,%s,%s,%s,%s\n' % (esc(row[0]), esc(row[1]), esc(row[2]), esc(row[3]), esc(row[4])))
|
||||
fo.write("dataset,time,value,buildid,data\n")
|
||||
cur.close()
|
||||
cur = db.cursor()
|
||||
#cur.execute("SELECT dataset_id, time, value, branchid, data from ((dataset_values NATURAL JOIN dataset_branchinfo) NATURAL JOIN dataset_extra_data) WHERE dataset_id IN (%s) %s %s ORDER BY dataset_id, time" % (setid, s1, s2,))
|
||||
cur.execute("SELECT dataset_values.dataset_id, dataset_values.time, dataset_values.value, dataset_branchinfo.branchid, dataset_extra_data.data FROM dataset_values LEFT JOIN dataset_branchinfo ON dataset_values.dataset_id = dataset_branchinfo.dataset_id AND dataset_values.time = dataset_branchinfo.time LEFT JOIN dataset_extra_data ON dataset_values.dataset_id = dataset_extra_data.dataset_id AND dataset_values.time = dataset_extra_data.time WHERE dataset_values.dataset_id IN (%s) %s %s ORDER BY dataset_values.dataset_id, dataset_values.time" % (setid, s1, s2))
|
||||
for row in cur:
|
||||
fo.write ('%s,%s,%s,%s,%s\n' % (esc(row[0]), esc(row[1]), esc(row[2]), esc(row[3]), esc(row[4])))
|
||||
cur.close()
|
||||
|
||||
#if var is a number returns a value other than None
|
||||
def checkNumber(var):
|
||||
if var is None:
|
||||
return 1
|
||||
reNumber = re.compile('^[0-9.]*$')
|
||||
return reNumber.match(var)
|
||||
|
||||
#if var is a string returns a value other than None
|
||||
def checkString(var):
|
||||
if var is None:
|
||||
return 1
|
||||
reString = re.compile('^[0-9A-Za-z._()\- ]*$')
|
||||
return reString.match(var)
|
||||
|
||||
doGzip = 0
|
||||
try:
|
||||
if "gzip" in os.environ["HTTP_ACCEPT_ENCODING"]:
|
||||
doGzip = 1
|
||||
except:
|
||||
pass
|
||||
|
||||
form = cgi.FieldStorage()
|
||||
|
||||
for numField in ["setid"]:
|
||||
val = form.getlist(numField)
|
||||
for v in val:
|
||||
if not checkNumber(v):
|
||||
print "Invalid string arg: ", numField, " '" + v + "'"
|
||||
sys.exit(500)
|
||||
globals()[numField] = val
|
||||
|
||||
for numField in ["starttime", "endtime"]:
|
||||
val = form.getfirst(numField)
|
||||
if not checkNumber(val):
|
||||
print "Invalid string arg: ", numField, " '" + val + "'"
|
||||
sys.exit(500)
|
||||
globals()[numField] = val
|
||||
|
||||
if not setid:
|
||||
print "Content-Type: text/plain\n"
|
||||
print "No data set selected\n"
|
||||
sys.exit(500)
|
||||
|
||||
zbuf = cStringIO.StringIO()
|
||||
zfile = zbuf
|
||||
if doGzip == 1:
|
||||
zfile = gzip.GzipFile(mode = 'wb', fileobj = zbuf, compresslevel = 9)
|
||||
|
||||
dumpData(zfile, setid, starttime, endtime)
|
||||
|
||||
sys.stdout.write("Content-Type: text/plain\n")
|
||||
if doGzip == 1:
|
||||
zfile.close()
|
||||
sys.stdout.write("Content-Encoding: gzip\n")
|
||||
sys.stdout.write("\n")
|
||||
|
||||
sys.stdout.write(zbuf.getvalue())
|
||||
|
||||
|
||||
|
||||
@@ -1,105 +0,0 @@
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
||||
<html>
|
||||
<head>
|
||||
<title>Perf-o-matic-too</title>
|
||||
|
||||
<link rel="stylesheet" type="text/css" href="js/graph.css"></link>
|
||||
|
||||
<!-- MochiKit -->
|
||||
<script type="text/javascript" src="js/mochikit/MochiKit.js"></script>
|
||||
|
||||
<!-- YUI -->
|
||||
<script type="text/javascript" src="js/yui/yahoo.js"></script>
|
||||
<script type="text/javascript" src="js/yui/dom.js"></script>
|
||||
<script type="text/javascript" src="js/yui/event.js"></script>
|
||||
<script type="text/javascript" src="js/yui/animation.js"></script>
|
||||
<script type="text/javascript" src="js/yui/container.js"></script>
|
||||
|
||||
<!-- Core -->
|
||||
<script type="text/javascript" src="js/TinderboxData.js"></script>
|
||||
<script type="text/javascript" src="js/DataSet.js"></script>
|
||||
<script type="text/javascript" src="js/GraphCanvas.js"></script>
|
||||
|
||||
<script type="text/javascript" src="js/edGraphFormModule.js"></script>
|
||||
<script type="text/javascript" src="js/graph.js"></script>
|
||||
<script type="text/javascript" src="js/ResizeGraph.js"></script>
|
||||
|
||||
<!-- BonsaiService needs e4x -->
|
||||
<script type="text/javascript; e4x=1" src="js/BonsaiService.js"></script>
|
||||
</head>
|
||||
|
||||
<body onload="loadingDone(DATA_GRAPH)">
|
||||
<!--<h1>Graph</h1>-->
|
||||
|
||||
<!-- Take your damn divs and floats and clears and shove 'em! -->
|
||||
|
||||
<div style="width: 710px; height:20px; margin-left:10px ">
|
||||
<span id="loading" class="loading"></span>
|
||||
</div>
|
||||
<form action="javascript:;">
|
||||
<table class="graphconfig-no" width="100%">
|
||||
|
||||
<tr style="vertical-align: top">
|
||||
<td class="graphconfig-list">
|
||||
<div id="graphforms"></div>
|
||||
|
||||
</td>
|
||||
<td class="graphconfig-test-list">
|
||||
<div id="graphforms-test-list"></div>
|
||||
</td>
|
||||
|
||||
<td class="dgraphconfig">
|
||||
<!--
|
||||
<div id="baseline">
|
||||
<span>Use </span><select id="baselineDropdown"><option value="0">nothing</option></select><span> as a baseline</span><br>
|
||||
</div>
|
||||
-->
|
||||
<br>
|
||||
|
||||
<div id="formend">
|
||||
<input id="graphbutton" type="submit" onclick="onGraph()" value="Graph It!">
|
||||
<!-- <label for="baseline">No baseline</label><input type="radio" name="baseline" checked onclick="onNoBaseLineClick()"> -->
|
||||
</br> </br>
|
||||
<div><a id="linktothis" href="edgraph.html">Link to this graph</a> </div>
|
||||
</br>
|
||||
<div><a id="dumptocsv" href="dumpdata.cgi">Dump to csv</a> </div>
|
||||
</div>
|
||||
|
||||
</tr>
|
||||
|
||||
</table>
|
||||
</form>
|
||||
|
||||
<!-- small graph -->
|
||||
<div style="width: 900px; height:20px">
|
||||
<center><span id="status" class="status"></span></center>
|
||||
</div>
|
||||
|
||||
<div id="container" style="width: 100%">
|
||||
|
||||
<!-- these are absolute size, so we wrap them in a div that can overflow -->
|
||||
<div id="graph-container" style="width: 900px; margin:auto">
|
||||
<div id="smallgraph-labels-x" style="position: relative; left: 51px; margin-left: 1px; margin-right: 1px; height: 30px; width: 700px"></div>
|
||||
<div id="smallgraph-labels-y" style="position: relative; left: 0px; top: 0px; float: left; height: 76px; width: 50px;"></div>
|
||||
<canvas style="clear: left; border: 1px solid #888; padding-top: 1px;" id="smallgraph" height="75" width="650"></canvas>
|
||||
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
<div id="graph-labels-y" style="position: relative; left: 0px; top: 0px; float: left; margin-top: 1px; margin-bottom: 1px; height: 300px; width: 50px;"></div>
|
||||
<canvas style="clear: left; border: 1px solid #888;" id="graph" height="300" width="650"></canvas>
|
||||
<div id="graph-labels-x" style="position: relative; left: 50px; margin-left: 1px; margin-right: 1px; height: 50px; width: 700px"></div>
|
||||
</div>
|
||||
<div id="graph-label-container" style="float:left;margin-top:30px;">
|
||||
<span id="graph-label-list" class="graph-label-list-member" align="left"></span>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<script>
|
||||
ResizableBigGraph = new ResizeGraph();
|
||||
ResizableBigGraph.init('graph');
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -1,47 +0,0 @@
|
||||
#!/usr/bin/perl
|
||||
|
||||
print "Content-type: text/plain\n\n";
|
||||
|
||||
#foreach my $k (keys(%ENV)) {
|
||||
# print "$k => " . $ENV{$k} . "\n";
|
||||
#}
|
||||
|
||||
my $QS = $ENV{"QUERY_STRING"};
|
||||
my %query = ();
|
||||
|
||||
{
|
||||
my @qp = split /\&/,$QS;
|
||||
foreach my $q (@qp) {
|
||||
my @qp1 = split /=/,$q;
|
||||
$query{$qp1[0]} = $qp1[1];
|
||||
}
|
||||
}
|
||||
|
||||
if (defined($query{"setid"})) {
|
||||
my $testid = $query{"setid"};
|
||||
|
||||
print "{ resultcode: 0, results: [";
|
||||
|
||||
srand();
|
||||
|
||||
my $lv = 200 + rand (100);
|
||||
foreach my $k (1 .. 500) {
|
||||
#my $kv = $k;
|
||||
#my $v = $k;
|
||||
my $kv = 1148589000 + ($k*60*20);
|
||||
my $v = $lv;
|
||||
$lv = $lv + (rand(10) - 5);
|
||||
print "$kv, $v, ";
|
||||
}
|
||||
print "] }";
|
||||
} else {
|
||||
print "{ resultcode: 0, results: [
|
||||
{ id: 1, machine: 'tbox1', test: 'test1', test_type: 'perf', extra_data: null },
|
||||
{ id: 4, machine: 'tbox2', test: 'test1', test_type: 'perf', extra_data: null },
|
||||
{ id: 3, machine: 'tbox1', test: 'test3', test_type: 'perf', extra_data: null },
|
||||
{ id: 6, machine: 'tbox3', test: 'test3', test_type: 'perf', extra_data: null },
|
||||
{ id: 2, machine: 'tbox1', test: 'test2', test_type: 'perf', extra_data: null },
|
||||
{ id: 5, machine: 'tbox2', test: 'test2', test_type: 'perf', extra_data: null },
|
||||
] }";
|
||||
}
|
||||
|
||||
@@ -1,276 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
import cgitb; cgitb.enable()
|
||||
|
||||
import os
|
||||
import sys
|
||||
import cgi
|
||||
import time
|
||||
import re
|
||||
import gzip
|
||||
import minjson as json
|
||||
|
||||
import cStringIO
|
||||
|
||||
from graphsdb import db
|
||||
#
|
||||
# All objects are returned in the form:
|
||||
# {
|
||||
# resultcode: n,
|
||||
# ...
|
||||
# }
|
||||
#
|
||||
# The ... is dependant on the result type.
|
||||
#
|
||||
# Result codes:
|
||||
# 0 success
|
||||
# -1 bad tinderbox
|
||||
# -2 bad test name
|
||||
#
|
||||
# incoming query string:
|
||||
# tbox=name
|
||||
# tinderbox name
|
||||
#
|
||||
# If only tbox specified, returns array of test names for that tinderbox in data
|
||||
# If invalid tbox specified, returns error -1
|
||||
#
|
||||
# test=testname
|
||||
# test name
|
||||
#
|
||||
# Returns results for that test in .results, in array of [time0, value0, time1, value1, ...]
|
||||
# Also returns .annotations for that dataset, in array of [time0, string0, time1, string1, ...]
|
||||
#
|
||||
# raw=1
|
||||
# Same as full results, but includes raw data for test in .rawdata, in form [time0, rawdata0, ...]
|
||||
#
|
||||
# starttime=tval
|
||||
# Start time to return results from, in seconds since GMT epoch
|
||||
# endtime=tval
|
||||
# End time, in seconds since GMT epoch
|
||||
#
|
||||
# getlist=1
|
||||
# To be combined with branch, machine and testname
|
||||
# Returns a list of distinct branches, machines or testnames in the database
|
||||
#
|
||||
# if neither getlist nor setid are found in the query string the returned results will be a list
|
||||
# of tests, limited by a given datelimit, branch, machine and testname
|
||||
# ie) dgetdata?datelimit=1&branch=1.8 will return all tests in the database that are not older than a day and that
|
||||
# were run on the 1.8 branch
|
||||
|
||||
def doError(errCode):
|
||||
errString = "unknown error"
|
||||
if errCode == -1:
|
||||
errString = "bad tinderbox"
|
||||
elif errCode == -2:
|
||||
errString = "bad test name"
|
||||
print "{ resultcode: " + str(errCode) + ", error: '" + errString + "' }"
|
||||
|
||||
def doGetList(fo, type, branch, machine, testname):
|
||||
results = []
|
||||
s1 = ""
|
||||
if branch:
|
||||
s1 = "SELECT DISTINCT branch FROM dataset_info"
|
||||
if machine:
|
||||
s1 = "SELECT DISTINCT machine FROM dataset_info"
|
||||
if testname:
|
||||
s1 = "SELECT DISTINCT test FROM dataset_info"
|
||||
cur = db.cursor()
|
||||
cur.execute(s1 + " WHERE type = ?", (type,))
|
||||
for row in cur:
|
||||
results.append({ "value": row[0] })
|
||||
cur.close()
|
||||
fo.write(json.write( {"resultcode": 0, "results": results} ))
|
||||
|
||||
def doListTests(fo, type, datelimit, branch, machine, testname, graphby):
|
||||
results = []
|
||||
s1 = ""
|
||||
|
||||
# FIXME: This could be vulnerable to SQL injection! Although it looks like checkstring should catch bad strings.
|
||||
if branch:
|
||||
s1 += " AND branch = '" + branch + "' "
|
||||
if machine:
|
||||
s1 += " AND machine = '" + machine + "' "
|
||||
if testname:
|
||||
s1 += " AND test = '" + testname + "' "
|
||||
|
||||
cur = db.cursor()
|
||||
if graphby and graphby == 'bydata':
|
||||
cur.execute("SELECT id, machine, test, test_type, dataset_extra_data.data, extra_data, branch FROM dataset_extra_data JOIN dataset_info ON dataset_extra_data.dataset_id = dataset_info.id WHERE type = ? AND test_type != ? and (date >= ?) " + s1 +" GROUP BY machine,test,test_type,dataset_extra_data.data, extra_data, branch", (type, "baseline", datelimit))
|
||||
else:
|
||||
cur.execute("SELECT id, machine, test, test_type, date, extra_data, branch FROM dataset_info WHERE type = ? AND test_type != ? and (date >= ?)" + s1, (type, "baseline", datelimit))
|
||||
for row in cur:
|
||||
if graphby and graphby == 'bydata':
|
||||
results.append( {"id": row[0],
|
||||
"machine": row[1],
|
||||
"test": row[2],
|
||||
"test_type": row[3],
|
||||
"data": row[4],
|
||||
"extra_data": row[5],
|
||||
"branch": row[6]})
|
||||
else:
|
||||
results.append( {"id": row[0],
|
||||
"machine": row[1],
|
||||
"test": row[2],
|
||||
"test_type": row[3],
|
||||
"date": row[4],
|
||||
"extra_data": row[5],
|
||||
"branch": row[6]})
|
||||
|
||||
cur.close()
|
||||
fo.write (json.write( {"resultcode": 0, "results": results} ))
|
||||
|
||||
|
||||
def getByDataResults(cur,setid,extradata,starttime,endtime):
|
||||
s1 = ""
|
||||
s2 = ""
|
||||
cur.execute("""
|
||||
SELECT dataset_info.date,avg(dataset_values.value)
|
||||
FROM dataset_info
|
||||
JOIN dataset_extra_data
|
||||
ON dataset_extra_data.dataset_id = dataset_info.id
|
||||
JOIN dataset_values
|
||||
ON dataset_extra_data.time = dataset_values.time
|
||||
AND dataset_info.id = dataset_values.dataset_id
|
||||
WHERE
|
||||
(dataset_info.machine,dataset_info.test,dataset_info.test_type,dataset_info.extra_data,dataset_info.branch) = (SELECT machine,test,test_type,extra_data,branch from dataset_info where id = ? limit 1)
|
||||
AND dataset_extra_data.data = ?
|
||||
GROUP BY dataset_info.date ORDER BY dataset_info.date
|
||||
""", (setid,extradata))
|
||||
|
||||
|
||||
def doSendResults(fo, setid, starttime, endtime, raw, graphby, extradata=None):
|
||||
s1 = ""
|
||||
s2 = ""
|
||||
if starttime:
|
||||
s1 = " AND time >= " + starttime
|
||||
if endtime:
|
||||
s2 = " AND time <= " + endtime
|
||||
|
||||
fo.write ("{ resultcode: 0,")
|
||||
|
||||
cur = db.cursor()
|
||||
if not graphby or graphby == "time":
|
||||
cur.execute("SELECT time, value FROM dataset_values WHERE dataset_id = ? " + s1 + s2 + " ORDER BY time", (setid,))
|
||||
else:
|
||||
getByDataResults(cur,setid, extradata,starttime,endtime)
|
||||
fo.write ("results: [")
|
||||
for row in cur:
|
||||
if row[1] == 'nan':
|
||||
continue
|
||||
fo.write ("%s,%s," % (row[0], row[1]))
|
||||
cur.close()
|
||||
fo.write ("],")
|
||||
|
||||
cur = db.cursor()
|
||||
cur.execute("SELECT time, value FROM annotations WHERE dataset_id = ? " + s1 + s2 + " ORDER BY time", (setid,))
|
||||
fo.write ("annotations: [")
|
||||
for row in cur:
|
||||
fo.write("%s,'%s'," % (row[0], row[1]))
|
||||
cur.close()
|
||||
fo.write ("],")
|
||||
|
||||
cur = db.cursor()
|
||||
cur.execute("SELECT test FROM dataset_info WHERE id = ?", (setid,))
|
||||
row = cur.fetchone()
|
||||
test_name = row[0]
|
||||
|
||||
cur.execute("SELECT id, extra_data FROM dataset_info WHERE test = ? and test_type = ?", (test_name, "baseline"))
|
||||
baselines = cur.fetchall()
|
||||
|
||||
fo.write ("baselines: {")
|
||||
for baseline in baselines:
|
||||
cur.execute("SELECT value FROM dataset_values WHERE dataset_id = ? LIMIT 1", (baseline[0],))
|
||||
row = cur.fetchone()
|
||||
fo.write("'%s': '%s'," % (baseline[1], row[0]))
|
||||
fo.write("},")
|
||||
cur.close()
|
||||
|
||||
if raw:
|
||||
cur = db.cursor()
|
||||
cur.execute("SELECT time, data FROM dataset_extra_data WHERE dataset_id = ? " + s1 + s2 + " ORDER BY time", (setid,))
|
||||
fo.write ("rawdata: [")
|
||||
for row in cur:
|
||||
blob = row[1]
|
||||
if "\\" in blob:
|
||||
blob = blob.replace("\\", "\\\\")
|
||||
if "'" in blob:
|
||||
blob = blob.replace("'", "\\'")
|
||||
fo.write("%s,'%s'," % (row[0], blob))
|
||||
cur.close()
|
||||
fo.write ("],")
|
||||
|
||||
cur = db.cursor()
|
||||
cur.execute("SELECT avg(value), max(value), min(value) from dataset_values where dataset_id = ? " + s1 + s2 + " GROUP BY dataset_id", (setid,))
|
||||
fo.write("stats: [")
|
||||
for row in cur:
|
||||
fo.write("%s, %s, %s," %(row[0], row[1], row[2]))
|
||||
cur.close()
|
||||
fo.write("],")
|
||||
|
||||
fo.write ("}")
|
||||
|
||||
#if var is a number returns a value other than None
|
||||
def checkNumber(var):
|
||||
if var is None:
|
||||
return 1
|
||||
reNumber = re.compile('^[0-9.]*$')
|
||||
return reNumber.match(var)
|
||||
|
||||
#if var is a string returns a value other than None
|
||||
def checkString(var):
|
||||
if var is None:
|
||||
return 1
|
||||
reString = re.compile('^[0-9A-Za-z._()\- ]*$')
|
||||
return reString.match(var)
|
||||
|
||||
doGzip = 0
|
||||
try:
|
||||
if "gzip" in os.environ["HTTP_ACCEPT_ENCODING"]:
|
||||
doGzip = 1
|
||||
except:
|
||||
pass
|
||||
|
||||
form = cgi.FieldStorage()
|
||||
|
||||
#make sure that we are getting clean data from the user
|
||||
for strField in ["type", "machine", "branch", "test", "graphby","extradata"]:
|
||||
val = form.getfirst(strField)
|
||||
if strField == "test":
|
||||
strField = "testname"
|
||||
if not checkString(val):
|
||||
print "Invalid string arg: ", strField, " '" + val + "'"
|
||||
sys.exit(500)
|
||||
globals()[strField] = val
|
||||
|
||||
for numField in ["setid", "raw", "starttime", "endtime", "datelimit", "getlist"]:
|
||||
val = form.getfirst(numField)
|
||||
if not checkNumber(val):
|
||||
print "Invalid string arg: ", numField, " '" + val + "'"
|
||||
sys.exit(500)
|
||||
globals()[numField] = val
|
||||
|
||||
if not datelimit:
|
||||
datelimit = 0
|
||||
|
||||
zbuf = cStringIO.StringIO()
|
||||
zfile = zbuf
|
||||
if doGzip == 1:
|
||||
zfile = gzip.GzipFile(mode = 'wb', fileobj = zbuf, compresslevel = 5)
|
||||
|
||||
if not setid and not getlist:
|
||||
doListTests(zfile, type, datelimit, branch, machine, testname, graphby)
|
||||
elif not getlist:
|
||||
doSendResults(zfile, setid, starttime, endtime, raw, graphby,extradata)
|
||||
else:
|
||||
doGetList(zfile, type, branch, machine, testname)
|
||||
|
||||
sys.stdout.write("Content-Type: text/plain\n")
|
||||
if doGzip == 1:
|
||||
zfile.close()
|
||||
sys.stdout.write("Content-Encoding: gzip\n")
|
||||
sys.stdout.write("\n")
|
||||
|
||||
sys.stdout.write(zbuf.getvalue())
|
||||
|
||||
|
||||
|
||||
@@ -1,115 +0,0 @@
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
||||
<html>
|
||||
<head>
|
||||
<title>Perf-o-matic</title>
|
||||
|
||||
<link rel="stylesheet" type="text/css" href="js/graph.css">
|
||||
|
||||
<!-- MochiKit -->
|
||||
<script type="text/javascript" src="js/mochikit/MochiKit.js"></script>
|
||||
|
||||
<!-- YUI -->
|
||||
<script type="text/javascript" src="js/yui/yahoo.js"></script>
|
||||
<script type="text/javascript" src="js/yui/dom.js"></script>
|
||||
<script type="text/javascript" src="js/yui/event.js"></script>
|
||||
<script type="text/javascript" src="js/yui/animation.js"></script>
|
||||
<script type="text/javascript" src="js/yui/container.js"></script>
|
||||
|
||||
<!-- Core -->
|
||||
<script type="text/javascript" src="js/TinderboxData.js"></script>
|
||||
<script type="text/javascript" src="js/DataSet.js"></script>
|
||||
<script type="text/javascript" src="js/GraphCanvas.js"></script>
|
||||
|
||||
<script type="text/javascript" src="js/GraphFormModule.js"></script>
|
||||
<script type="text/javascript" src="js/graph.js"></script>
|
||||
<script type="text/javascript" src="js/ResizeGraph.js"></script>
|
||||
|
||||
<!-- BonsaiService needs e4x -->
|
||||
<script type="text/javascript; e4x=1" src="js/BonsaiService.js"></script>
|
||||
</head>
|
||||
|
||||
<body onload="loadingDone(CONTINUOUS_GRAPH)">
|
||||
<!--<h1>Graph</h1>-->
|
||||
|
||||
<!-- Take your damn divs and floats and clears and shove 'em! -->
|
||||
|
||||
<div style="width: 710px; height:20px; margin-left:10px ">
|
||||
<span id="loading" class="loading"></span>
|
||||
</div>
|
||||
|
||||
<form action="javascript:;">
|
||||
<table class="graphconfig-no" width="100%">
|
||||
|
||||
<tr style="vertical-align: top">
|
||||
<td class="graphconfig">
|
||||
<table>
|
||||
<tr style="vertical-align: top;">
|
||||
<td>Show</td>
|
||||
<td>
|
||||
<input id="load-all-radio" type="radio" name="dataload" onclick="onDataLoadChanged()" checked>
|
||||
<label>all data</label><br>
|
||||
<input id="load-days-radio" type="radio" name="dataload" onclick="onDataLoadChanged()">
|
||||
<label>previous</label> <input type="text" value="30" id="load-days-entry" size="3" onchange="onDataLoadChanged()"> <label>days</label>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<div id="baseline">
|
||||
<span>Use </span><select id="baselineDropdown"><option value="0">nothing</option></select><span> as a baseline</span><br>
|
||||
</div>
|
||||
|
||||
<br>
|
||||
|
||||
<div id="formend">
|
||||
<input type="submit" onclick="onGraph()" value="Graph It!">
|
||||
</br> </br>
|
||||
<!-- <label for="baseline">No baseline</label><input type="radio" name="baseline" checked onclick="onNoBaseLineClick()"> -->
|
||||
<a id="linktothis" href="graph.html">Link to this graph</a>
|
||||
</br>
|
||||
<div><a id="dumptocsv" href="dumpdata.cgi">Dump to csv</a> </div>
|
||||
</div>
|
||||
|
||||
<br>
|
||||
|
||||
<input style="display:none" id="bonsaibutton" type="button" onclick="onUpdateBonsai()" value="Refresh Bonsai Data">
|
||||
</td>
|
||||
|
||||
<td class="graphconfig-list">
|
||||
<div id="graphforms"></div>
|
||||
<div id="addone">
|
||||
<img src="js/img/plus.png" class="plusminus" onclick="addGraphForm()" alt="Plus">
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
</form>
|
||||
|
||||
<!-- small graph -->
|
||||
<div style="width: 900px; height:20px">
|
||||
<center><span id="status" class="status"></span></center>
|
||||
</div>
|
||||
|
||||
<!-- these are absolute size, so we wrap them in a div that can overflow -->
|
||||
<div id="graph-container" style="margin:auto; width:900px;">
|
||||
<div id="smallgraph-labels-x" style="position: relative; left: 51px; margin-left: 1px; margin-right: 1px; height: 30px; width: 700px"></div>
|
||||
<div id="smallgraph-labels-y" style="position: relative; left: 0px; top: 0px; float: left; height: 76px; width: 50px;"></div>
|
||||
<canvas style="clear: left; border: 1px solid #888; padding-top: 1px;" id="smallgraph" height="75" width="700"></canvas>
|
||||
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
<div id="graph-labels-y" style="position: relative; left: 0px; top: 0px; float: left; margin-top: 1px; margin-bottom: 1px; height: 300px; width: 50px;"></div>
|
||||
<canvas style="clear: left; border: 1px solid #888;" id="graph" height="300" width="700"></canvas>
|
||||
<div id="graph-labels-x" style="position: relative; left: 50px; margin-left: 1px; margin-right: 1px; height: 50px; width: 700px"></div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
ResizableBigGraph = new ResizeGraph();
|
||||
ResizableBigGraph.init('graph');
|
||||
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
from pysqlite2 import dbapi2 as sqlite
|
||||
from databases import mysql as MySQLdb
|
||||
|
||||
|
||||
db = MySQLdb.connect("localhost","o","o","o_graphs")
|
||||
|
||||
@@ -1,111 +0,0 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is new-graph code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla Corporation
|
||||
* Portions created by the Initial Developer are Copyright (C) 2006
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Vladimir Vukicevic <vladimir@pobox.com> (Original Author)
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
function BonsaiService() {
|
||||
}
|
||||
|
||||
BonsaiService.prototype = {
|
||||
// this could cache stuff, so that we only have to request the bookend data
|
||||
// if we want a wider range, but it's probably not worth it for now.
|
||||
//
|
||||
// The callback is called with an object argument which contains:
|
||||
// {
|
||||
// times: [ t1, t2, t3, .. ],
|
||||
// who: [ w1, w2, w3, .. ],
|
||||
// log: [ l1, l2, l3, .. ],
|
||||
// files: [ [ r11, f11, r12, f12, r13, f13, .. ], [ r21, f21, r22, f22, r23, f23, .. ], .. ]
|
||||
// }
|
||||
//
|
||||
// r = revision number, as a string, e.g. "1.15"
|
||||
// f = file, e.g. "mozilla/widget/foo.cpp"
|
||||
//
|
||||
// arg1 = callback, arg2 = null
|
||||
// arg1 = includeFiles, arg2 = callback
|
||||
requestCheckinsBetween: function (startDate, endDate, arg1, arg2) {
|
||||
var includeFiles = arg1;
|
||||
var callback = arg2;
|
||||
|
||||
if (arg2 == null) {
|
||||
callback = arg1;
|
||||
includeFiles = null;
|
||||
}
|
||||
|
||||
var queryargs = {
|
||||
treeid: "default",
|
||||
module: "SeaMonkeyAll",
|
||||
branch: "HEAD",
|
||||
mindate: startDate,
|
||||
maxdate: endDate
|
||||
};
|
||||
|
||||
if (!includeFiles)
|
||||
queryargs.xml_nofiles = "1";
|
||||
|
||||
log ("bonsai request: ", queryString(queryargs));
|
||||
|
||||
doSimpleXMLHttpRequest (bonsaicgi, queryargs)
|
||||
.addCallbacks(
|
||||
function (obj) {
|
||||
var result = { times: [], who: [], comment: [], files: null };
|
||||
if (includeFiles)
|
||||
result.files = [];
|
||||
|
||||
// strip out the xml declaration
|
||||
var s = obj.responseText.replace(/<\?xml version="1.0"\?>/, "");
|
||||
var bq = new XML(s);
|
||||
for (var i = 0; i < bq.ci.length(); i++) {
|
||||
var ci = bq.ci[i];
|
||||
result.times.push(ci.@date);
|
||||
result.who.push(ci.@who);
|
||||
result.comment.push(ci.log.text().toString());
|
||||
if (includeFiles) {
|
||||
var files = [];
|
||||
for (var j = 0; j < ci.files.f.length(); j++) {
|
||||
var f = ci.files.f[j];
|
||||
files.push(f.@rev);
|
||||
files.push(f.text().toString());
|
||||
}
|
||||
result.files.push(files);
|
||||
}
|
||||
}
|
||||
|
||||
callback.call (window, result);
|
||||
},
|
||||
function () { alert ("Error talking to bonsai"); });
|
||||
},
|
||||
};
|
||||
|
||||
@@ -1,273 +0,0 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is new-graph code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla Corporation
|
||||
* Portions created by the Initial Developer are Copyright (C) 2006
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Vladimir Vukicevic <vladimir@pobox.com> (Original Author)
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
function TimeDataSet(data) {
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
TimeDataSet.prototype = {
|
||||
data: null,
|
||||
|
||||
indicesForTimeRange: function (startTime, endTime) {
|
||||
var startIndex = -1;
|
||||
var endIndex = -1;
|
||||
|
||||
if (this.data[0] > endTime ||
|
||||
this.data[this.data.length-2] < startTime)
|
||||
return null;
|
||||
|
||||
for (var i = 0; i < this.data.length/2; i++) {
|
||||
if (startIndex == -1 && this.data[i*2] >= startTime) {
|
||||
startIndex = i;
|
||||
} else if (startIndex != -1 && this.data[i*2] > endTime) {
|
||||
endIndex = i;
|
||||
return [startIndex, endIndex];
|
||||
}
|
||||
}
|
||||
|
||||
endIndex = (this.data.length/2) - 1;
|
||||
return [startIndex, endIndex];
|
||||
},
|
||||
};
|
||||
|
||||
function TimeValueDataSet(data, color) {
|
||||
this.data = data;
|
||||
|
||||
this.firstTime = data[0];
|
||||
if (data.length > 2)
|
||||
this.lastTime = data[data.length-2];
|
||||
else
|
||||
this.lastTime = data[0];
|
||||
|
||||
if (color) {
|
||||
this.color = color;
|
||||
} else {
|
||||
this.color = "#000000";
|
||||
}
|
||||
|
||||
log ("new tds:", this.firstTime, this.lastTime);
|
||||
|
||||
this.relativeToSets = new Array();
|
||||
}
|
||||
|
||||
TimeValueDataSet.prototype = {
|
||||
__proto__: new TimeDataSet(),
|
||||
|
||||
firstTime: 0,
|
||||
lastTime: 0,
|
||||
data: null, // array: [time0, value0, time1, value1, ...]
|
||||
relativeTo: null,
|
||||
|
||||
color: "black",
|
||||
title: '',
|
||||
|
||||
minMaxValueForTimeRange: function (startTime, endTime) {
|
||||
var minValue = Number.POSITIVE_INFINITY;
|
||||
var maxValue = Number.NEGATIVE_INFINITY;
|
||||
for (var i = 0; i < this.data.length/2; i++) {
|
||||
var t = this.data[i*2];
|
||||
if (t >= startTime && t <= endTime) {
|
||||
var v = this.data[i*2+1];
|
||||
if (v < minValue)
|
||||
minValue = v;
|
||||
if (v > maxValue)
|
||||
maxValue = v;
|
||||
}
|
||||
}
|
||||
|
||||
return [minValue, maxValue];
|
||||
},
|
||||
|
||||
// create a new ds that's the average of this ds's values,
|
||||
// with the average sampled over the given interval,
|
||||
// at every avginterval/2
|
||||
createAverage: function (avginterval) {
|
||||
if (avginterval <= 0)
|
||||
throw "avginterval <= 0";
|
||||
|
||||
if (this.averageDataSet != null &&
|
||||
this.averageInterval == avginterval)
|
||||
{
|
||||
return this.averageDataSet;
|
||||
}
|
||||
|
||||
var newdata = [];
|
||||
|
||||
var time0 = this.data[0];
|
||||
var val0 = 0;
|
||||
var count0 = 0;
|
||||
|
||||
var time1 = time0 + avginterval/2;
|
||||
var val1 = 0;
|
||||
var count1 = 0;
|
||||
|
||||
var ns = this.data.length/2;
|
||||
for (var i = 0; i < ns; i++) {
|
||||
var t = this.data[i*2];
|
||||
var v = this.data[i*2+1];
|
||||
if (t > time0+avginterval) {
|
||||
newdata.push(time0 + avginterval/2);
|
||||
newdata.push(count0 ? (val0 / count0) : 0);
|
||||
|
||||
// catch up
|
||||
while (time1 < t) {
|
||||
time0 += avginterval/2;
|
||||
time1 = time0;
|
||||
}
|
||||
|
||||
time0 = time1;
|
||||
val0 = val1;
|
||||
count0 = count1;
|
||||
|
||||
time1 = time0 + avginterval/2;
|
||||
val1 = 0;
|
||||
count1 = 0;
|
||||
}
|
||||
|
||||
val0 += v;
|
||||
count0++;
|
||||
|
||||
if (t > time1) {
|
||||
val1 += v;
|
||||
count1++;
|
||||
}
|
||||
}
|
||||
|
||||
if (count0 > 0) {
|
||||
newdata.push(time0 + avginterval/2);
|
||||
newdata.push(val0 / count0);
|
||||
}
|
||||
|
||||
var newds = new TimeValueDataSet(newdata, lighterColor(this.color));
|
||||
newds.averageOf = this;
|
||||
|
||||
this.averageDataSet = newds;
|
||||
this.averageInterval = avginterval;
|
||||
|
||||
return newds;
|
||||
},
|
||||
|
||||
// create a new dataset with this ds's data,
|
||||
// relative to otherds
|
||||
createRelativeTo: function (otherds, absval) {
|
||||
if (otherds == this) {
|
||||
log("error, same ds");
|
||||
return null;
|
||||
}
|
||||
|
||||
for each (var s in this.relativeToSets) {
|
||||
if (s.relativeTo == otherds)
|
||||
return s;
|
||||
}
|
||||
|
||||
var firstTime = this.firstTime;
|
||||
var lastTime = this.lastTime;
|
||||
|
||||
if (otherds.firstTime > firstTime)
|
||||
firstTime = otherds.firstTime;
|
||||
if (otherds.lastTime < lastTime)
|
||||
lastTime = otherds.lastTime;
|
||||
|
||||
var newdata = [];
|
||||
|
||||
var thisidx = this.indicesForTimeRange (firstTime, lastTime);
|
||||
var otheridx = this.indicesForTimeRange (firstTime, lastTime);
|
||||
|
||||
var o = otheridx[0];
|
||||
var ov, ov1, ov2, ot1, ot2;
|
||||
for (var i = thisidx[0]; i < thisidx[1]; i++) {
|
||||
var t = this.data[i*2];
|
||||
var tv = this.data[i*2+1];
|
||||
while (otherds.data[o*2] < t)
|
||||
o++;
|
||||
|
||||
ot1 = otherds.data[o*2];
|
||||
ov1 = otherds.data[o*2+1];
|
||||
if (o < otheridx[1]) {
|
||||
ot2 = otherds.data[o*2+2];
|
||||
ov2 = otherds.data[o*2+3];
|
||||
} else {
|
||||
ot2 = ot1;
|
||||
ov2 = ov1;
|
||||
}
|
||||
|
||||
|
||||
var d = (t-ot1)/(ot2-ot1);
|
||||
ov = (1-d) * ov1 + d * ov2;
|
||||
|
||||
newdata.push(t);
|
||||
//log ("i", i, "tv", tv, "ov", ov, "t", t, "ot1", ot1, "ot2", ot2, "ov1", ov1, "ov2", ov2);
|
||||
//log ("i", i, "tv", tv, "ov", ov, "tv/ov", tv/ov, "ov/tv", ov/tv);
|
||||
if (absval) {
|
||||
newdata.push(tv-ov);
|
||||
} else {
|
||||
if (tv > ov)
|
||||
newdata.push((tv/ov) - 1);
|
||||
else
|
||||
newdata.push(-((ov/tv) - 1));
|
||||
}
|
||||
}
|
||||
|
||||
var newds = new TimeValueDataSet(newdata, this.color);
|
||||
newds.relativeTo = otherds;
|
||||
|
||||
this.relativeToSets.push(newds);
|
||||
|
||||
return newds;
|
||||
},
|
||||
};
|
||||
|
||||
function TimeStringDataSet(data) {
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
TimeStringDataSet.prototype = {
|
||||
__proto__: new TimeDataSet(),
|
||||
data: null,
|
||||
|
||||
onDataSetChanged: null,
|
||||
|
||||
init: function () {
|
||||
},
|
||||
|
||||
addString: function (time, string) {
|
||||
},
|
||||
|
||||
removeStringAt: function (index) {
|
||||
},
|
||||
};
|
||||
|
||||
@@ -1,192 +0,0 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is new-graph code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla Corporation
|
||||
* Portions created by the Initial Developer are Copyright (C) 2006
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Vladimir Vukicevic <vladimir@pobox.com> (Original Author)
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
var GraphFormModules = [];
|
||||
var GraphFormModuleCount = 0;
|
||||
|
||||
function GraphFormModule(userConfig) {
|
||||
GraphFormModuleCount++;
|
||||
this.__proto__.__proto__.constructor.call(this, "graphForm" + GraphFormModuleCount, userConfig);
|
||||
}
|
||||
|
||||
GraphFormModule.prototype = {
|
||||
__proto__: new YAHOO.widget.Module(),
|
||||
|
||||
imageRoot: "",
|
||||
|
||||
testId: null,
|
||||
baseline: false,
|
||||
average: false,
|
||||
color: "#000000",
|
||||
onLoadingDone : new YAHOO.util.CustomEvent("onloadingdone"),
|
||||
onLoading : new YAHOO.util.CustomEvent("onloading"),
|
||||
|
||||
init: function (el, userConfig) {
|
||||
var self = this;
|
||||
|
||||
this.__proto__.__proto__.init.call(this, el/*, userConfig*/);
|
||||
|
||||
this.cfg = new YAHOO.util.Config(this);
|
||||
this.cfg.addProperty("testid", { suppressEvent: true });
|
||||
this.cfg.addProperty("average", { suppressEvent: true });
|
||||
this.cfg.addProperty("baseline", { suppressEvent: true });
|
||||
|
||||
if (userConfig)
|
||||
this.cfg.applyConfig(userConfig, true);
|
||||
|
||||
var form, td, el;
|
||||
|
||||
form = new DIV({ class: "graphform-line" });
|
||||
|
||||
td = new SPAN();
|
||||
/*
|
||||
el = new IMG({ src: "js/img/plus.png", class: "plusminus",
|
||||
onclick: function(event) { addGraphForm(); } });
|
||||
td.appendChild(el);
|
||||
*/
|
||||
el = new IMG({ src: "js/img/minus.png", class: "plusminus",
|
||||
onclick: function(event) { self.remove(); } });
|
||||
td.appendChild(el);
|
||||
form.appendChild(td);
|
||||
|
||||
td = new SPAN();
|
||||
el = new DIV({ id: "whee", style: "display: inline; border: 1px solid black; height: 15; " +
|
||||
"padding-right: 15; vertical-align: middle; margin: 3px;" });
|
||||
this.colorDiv = el;
|
||||
td.appendChild(el);
|
||||
form.appendChild(td);
|
||||
|
||||
td = new SPAN();
|
||||
el = new SELECT({ name: "testname",
|
||||
class: "testname",
|
||||
onchange: function(event) { self.onChangeTest(); } });
|
||||
this.testSelect = el;
|
||||
td.appendChild(el);
|
||||
form.appendChild(td);
|
||||
|
||||
td = new SPAN({ style: "padding-left: 10px;"});
|
||||
appendChildNodes(td, "Average:");
|
||||
el = new INPUT({ name: "average",
|
||||
type: "checkbox",
|
||||
onchange: function(event) { self.average = event.target.checked; } });
|
||||
this.averageCheckbox = el;
|
||||
td.appendChild(el);
|
||||
form.appendChild(td);
|
||||
|
||||
this.setBody (form);
|
||||
|
||||
var forceTestId = null;
|
||||
this.average = false;
|
||||
if (userConfig) {
|
||||
forceTestId = this.cfg.getProperty("testid");
|
||||
avg = this.cfg.getProperty("average");
|
||||
baseline = this.cfg.getProperty("baseline");
|
||||
if (avg == 1) {
|
||||
this.averageCheckbox.checked = true;
|
||||
this.average = true;
|
||||
}
|
||||
if (baseline == 1)
|
||||
this.onBaseLineRadioClick();
|
||||
}
|
||||
|
||||
Tinderbox.requestTestList(function (tests) {
|
||||
var opts = [];
|
||||
// let's sort by machine name
|
||||
var sortedTests = Array.sort(tests, function (a, b) {
|
||||
if (a.machine < b.machine) return -1;
|
||||
if (a.machine > b.machine) return 1;
|
||||
if (a.test < b.test) return -1;
|
||||
if (a.test > b.test) return 1;
|
||||
if (a.test_type < b.test_type) return -1;
|
||||
if (a.test_type > b.test_type) return 1;
|
||||
return 0;
|
||||
});
|
||||
|
||||
for each (var test in sortedTests) {
|
||||
var tstr = test.machine + " - " + test.test + " - " + test.branch;
|
||||
opts.push(new OPTION({ value: test.id }, tstr));
|
||||
}
|
||||
replaceChildNodes(self.testSelect, opts);
|
||||
|
||||
if (forceTestId != null) {
|
||||
self.testSelect.value = forceTestId;
|
||||
} else {
|
||||
self.testSelect.value = sortedTests[0].id;
|
||||
}
|
||||
setTimeout(function () { self.onChangeTest(forceTestId); }, 0);
|
||||
self.onLoadingDone.fire();
|
||||
});
|
||||
|
||||
GraphFormModules.push(this);
|
||||
},
|
||||
|
||||
getQueryString: function (prefix) {
|
||||
return prefix + "tid=" + this.testId + "&" + prefix + "bl=" + (this.baseline ? "1" : "0")
|
||||
+ "&" + prefix + "avg=" + (this.average? "1" : "0");
|
||||
},
|
||||
|
||||
getDumpString: function () {
|
||||
return "setid=" + this.testId;
|
||||
},
|
||||
|
||||
onChangeTest: function (forceTestId) {
|
||||
this.testId = this.testSelect.value;
|
||||
},
|
||||
|
||||
onBaseLineRadioClick: function () {
|
||||
GraphFormModules.forEach(function (g) { g.baseline = false; });
|
||||
this.baseline = true;
|
||||
},
|
||||
|
||||
setColor: function (newcolor) {
|
||||
this.color = newcolor;
|
||||
this.colorDiv.style.backgroundColor = colorToRgbString(newcolor);
|
||||
},
|
||||
|
||||
remove: function () {
|
||||
if (GraphFormModules.length == 1)
|
||||
return;
|
||||
|
||||
var nf = [];
|
||||
for each (var f in GraphFormModules) {
|
||||
if (f != this)
|
||||
nf.push(f);
|
||||
}
|
||||
GraphFormModules = nf;
|
||||
this.destroy();
|
||||
},
|
||||
};
|
||||
@@ -1,161 +0,0 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is new-graph code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla Corporation
|
||||
* Portions created by the Initial Developer are Copyright (C) 2006
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Jeremiah Orem <oremj@oremj.com> (Original Author)
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
function ResizeGraph() {
|
||||
}
|
||||
|
||||
ResizeGraph.prototype = {
|
||||
|
||||
margin_right: 25,
|
||||
margin_bottom: 25,
|
||||
resizing: false,
|
||||
active: false,
|
||||
element: null,
|
||||
handle: null,
|
||||
startX: null,
|
||||
startY: null,
|
||||
startHeight: null,
|
||||
startWidth: null,
|
||||
startTop: null,
|
||||
startLeft: null,
|
||||
currentDirection: '',
|
||||
|
||||
|
||||
init: function(elem) {
|
||||
this.handle = elem;
|
||||
this.element = getElement(elem);
|
||||
connect(this.handle,'onmousedown',this, 'mouseDownFunc');
|
||||
connect(document,'onmouseup',this, 'mouseUpFunc');
|
||||
connect(this.handle,'onmousemove',this, 'mouseMoveFunc');
|
||||
connect(document,'onmousemove',this, 'updateElement');
|
||||
},
|
||||
|
||||
directions: function(e) {
|
||||
var pointer = e.mouse();
|
||||
var graphPosition = elementPosition(this.handle);
|
||||
var dimensions = elementDimensions(this.handle);
|
||||
var dir = '';
|
||||
if ( pointer.page.x > (graphPosition.x + dimensions.w) - this.margin_right ) {
|
||||
dir= "e";
|
||||
}
|
||||
else if ( pointer.page.y > (graphPosition.y + dimensions.h) - this.margin_bottom ) {
|
||||
dir = "s";
|
||||
}
|
||||
return dir;
|
||||
},
|
||||
|
||||
draw: function(e) {
|
||||
var pointer = [e.mouse().page.x, e.mouse().page.y];
|
||||
var style = this.element.style;
|
||||
if (this.currentDirection.indexOf('s') != -1) {
|
||||
var newHeight = this.startHeight + pointer[1] - this.startY;
|
||||
if (newHeight > this.margin_bottom) {
|
||||
style.height = newHeight + "px";
|
||||
this.element.height = newHeight;
|
||||
}
|
||||
}
|
||||
if (this.currentDirection.indexOf('e') != -1) {
|
||||
var newWidth = this.startWidth + pointer[0] - this.startX;
|
||||
if (newWidth > this.margin_right) {
|
||||
if (newWidth > 900) {
|
||||
getElement('graph-container').style.width = (newWidth + 200) + "px";
|
||||
}
|
||||
style.width = newWidth + "px";
|
||||
this.element.width = newWidth;
|
||||
}
|
||||
}
|
||||
},
|
||||
mouseDownFunc: function(e)
|
||||
{
|
||||
var dir = this.directions(e);
|
||||
pointer = e.mouse();
|
||||
if (dir.length > 0 ) {
|
||||
this.active = true;
|
||||
var dimensions = elementDimensions(this.handle);
|
||||
var graphPosition = elementPosition(this.handle);
|
||||
this.startTop = graphPosition.y;
|
||||
this.startLeft = graphPosition.x;
|
||||
this.startHeight = dimensions.h;
|
||||
this.startWidth = dimensions.w;
|
||||
this.startX = pointer.page.x + document.body.scrollLeft + document.documentElement.scrollLeft;
|
||||
this.startY = pointer.page.y + document.body.scrollLeft + document.documentElement.scrollLeft;
|
||||
this.currentDirection = dir;
|
||||
e.stop();
|
||||
}
|
||||
},
|
||||
mouseMoveFunc: function(e)
|
||||
{
|
||||
pointer = e.mouse();
|
||||
graphPosition = elementPosition(this.handle);
|
||||
dimensions = elementDimensions(this.handle);
|
||||
dir = this.directions(e);
|
||||
if(dir.length > 0) {
|
||||
getElement(this.handle).style.cursor = dir + "-resize";
|
||||
}
|
||||
else {
|
||||
getElement(this.handle).style.cursor = '';
|
||||
}
|
||||
},
|
||||
updateElement: function(e)
|
||||
{
|
||||
if( this.active ) {
|
||||
if ( ! this.resizing ) {
|
||||
var style = getElement(this.handle).style;
|
||||
this.resizing = true;
|
||||
style.position = "relative";
|
||||
}
|
||||
this.draw(e);
|
||||
e.stop()
|
||||
return false;
|
||||
}
|
||||
},
|
||||
finishResize: function(e,success) {
|
||||
this.active = false;
|
||||
this.resizing = false;
|
||||
},
|
||||
mouseUpFunc: function(e)
|
||||
{
|
||||
if(this.active && this.resizing) {
|
||||
this.finishResize(e,true);
|
||||
BigPerfGraph.resize();
|
||||
e.stop();
|
||||
}
|
||||
this.active = false;
|
||||
this.resizing = false;
|
||||
},
|
||||
|
||||
};
|
||||
@@ -1,417 +0,0 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is new-graph code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla Corporation
|
||||
* Portions created by the Initial Developer are Copyright (C) 2006
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Vladimir Vukicevic <vladimir@pobox.com> (Original Author)
|
||||
* Alice Nodelman <anodelman@mozilla.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
//const getdatacgi = "getdata-fake.cgi?";
|
||||
//const getdatacgi = "http://localhost:9050/getdata.cgi?";
|
||||
const getdatacgi = "getdata.cgi?"
|
||||
|
||||
|
||||
function checkErrorReturn(obj) {
|
||||
if (!obj || obj.resultcode != 0) {
|
||||
alert ("Error: " + (obj ? (obj.error + "(" + obj.resultcode + ")") : "(nil)"));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function TinderboxData() {
|
||||
this.onTestListAvailable = new YAHOO.util.CustomEvent("testlistavailable");
|
||||
this.onDataSetAvailable = new YAHOO.util.CustomEvent("datasetavailable");
|
||||
this.testList = null;
|
||||
|
||||
this.testData = {};
|
||||
|
||||
}
|
||||
|
||||
TinderboxData.prototype = {
|
||||
testList: null,
|
||||
testData: null,
|
||||
|
||||
onTestListAvailable: null,
|
||||
onDataSetAvailable: null,
|
||||
|
||||
defaultLoadRange: null,
|
||||
raw: 0,
|
||||
|
||||
init: function () {
|
||||
var self = this;
|
||||
//netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect")
|
||||
|
||||
loadJSONDoc(getdatacgi + "type=continuous")
|
||||
.addCallbacks(
|
||||
function (obj) {
|
||||
if (!checkErrorReturn(obj)) return;
|
||||
self.testList = obj.results;
|
||||
//log("default test list" + self.testList);
|
||||
self.onTestListAvailable.fire(self.testList);
|
||||
},
|
||||
function () {alert ("Error talking to " + getdatacgi + ""); });
|
||||
},
|
||||
|
||||
requestTestList: function (callback) {
|
||||
//log("requestTestList default");
|
||||
var self = this;
|
||||
|
||||
if (this.testList != null) {
|
||||
callback.call (window, this.testList);
|
||||
} else {
|
||||
var cb =
|
||||
function (type, args, obj) {
|
||||
self.onTestListAvailable.unsubscribe(cb, obj);
|
||||
obj.call (window, args[0]);
|
||||
};
|
||||
|
||||
this.onTestListAvailable.subscribe (cb, callback);
|
||||
}
|
||||
},
|
||||
|
||||
// arg1 = startTime, arg2 = endTime, arg3 = callback
|
||||
// arg1 = callback, arg2/arg3 == null
|
||||
requestDataSetFor: function (testId, arg1, arg2, arg3) {
|
||||
var self = this;
|
||||
|
||||
var startTime = arg1;
|
||||
var endTime = arg2;
|
||||
var callback = arg3;
|
||||
|
||||
if (arg1 && arg2 == null && arg3 == null) {
|
||||
callback = arg1;
|
||||
if (this.defaultLoadRange) {
|
||||
startTime = this.defaultLoadRange[0];
|
||||
endTime = this.defaultLoadRange[1];
|
||||
//log ("load range using default", startTime, endTime);
|
||||
} else {
|
||||
startTime = null;
|
||||
endTime = null;
|
||||
}
|
||||
}
|
||||
|
||||
if (testId in this.testData) {
|
||||
var ds = this.testData[testId];
|
||||
//log ("Can maybe use cached?");
|
||||
if ((ds.requestedFirstTime == null && ds.requestedLastTime == null) ||
|
||||
(ds.requestedFirstTime <= startTime &&
|
||||
ds.requestedLastTime >= endTime))
|
||||
{
|
||||
//log ("Using cached ds");
|
||||
callback.call (window, testId, ds);
|
||||
return;
|
||||
}
|
||||
|
||||
// this can be optimized, if we request just the bookend bits,
|
||||
// but that's overkill
|
||||
if (ds.firstTime < startTime)
|
||||
startTime = ds.firstTime;
|
||||
if (ds.lastTime > endTime)
|
||||
endTime = ds.lastTime;
|
||||
}
|
||||
|
||||
var cb =
|
||||
function (type, args, obj) {
|
||||
if (args[0] != testId ||
|
||||
args[2] > startTime ||
|
||||
args[3] < endTime)
|
||||
{
|
||||
// not useful for us; there's another
|
||||
// outstanding request for our time range, so wait for that
|
||||
return;
|
||||
}
|
||||
|
||||
self.onDataSetAvailable.unsubscribe(cb, obj);
|
||||
obj.call (window, args[0], args[1]);
|
||||
};
|
||||
this.onDataSetAvailable.subscribe (cb, callback);
|
||||
|
||||
//netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect")
|
||||
|
||||
var reqstr = getdatacgi + "setid=" + testId;
|
||||
if (startTime)
|
||||
reqstr += "&starttime=" + startTime;
|
||||
if (endTime)
|
||||
reqstr += "&endtime=" + endTime;
|
||||
//raw data is the extra_data column
|
||||
if (this.raw)
|
||||
reqstr += "&raw=1";
|
||||
//log (reqstr);
|
||||
loadJSONDoc(reqstr)
|
||||
.addCallbacks(
|
||||
function (obj) {
|
||||
if (!checkErrorReturn(obj)) return;
|
||||
|
||||
var ds = new TimeValueDataSet(obj.results);
|
||||
|
||||
//this is the the case of a discrete graph - where the entire test run is always requested
|
||||
//so the start and end points are the first and last entries in the returned data set
|
||||
if (!startTime && !endTime) {
|
||||
startTime = ds.data[0];
|
||||
endTime = ds.data[ds.data.length -2];
|
||||
}
|
||||
ds.requestedFirstTime = startTime;
|
||||
ds.requestedLastTime = endTime;
|
||||
self.testData[testId] = ds;
|
||||
if (obj.annotations)
|
||||
ds.annotations = new TimeStringDataSet(obj.annotations);
|
||||
if (obj.baselines)
|
||||
ds.baselines = obj.baselines;
|
||||
if (obj.rawdata)
|
||||
ds.rawdata = obj.rawdata;
|
||||
if (obj.stats)
|
||||
ds.stats = obj.stats;
|
||||
self.onDataSetAvailable.fire(testId, ds, startTime, endTime);
|
||||
},
|
||||
function (obj) {alert ("Error talking to " + getdatacgi + " (" + obj + ")"); log (obj.stack); });
|
||||
},
|
||||
|
||||
clearValueDataSets: function () {
|
||||
//log ("clearvalueDatasets");
|
||||
this.tinderboxTestData = {};
|
||||
},
|
||||
|
||||
};
|
||||
|
||||
function DiscreteTinderboxData() {
|
||||
};
|
||||
|
||||
DiscreteTinderboxData.prototype = {
|
||||
__proto__: new TinderboxData(),
|
||||
|
||||
init: function () {
|
||||
},
|
||||
|
||||
requestTestList: function (limitDate, branch, machine, testname, callback) {
|
||||
var self = this;
|
||||
//netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect")
|
||||
var limiters = "";
|
||||
|
||||
var tDate = 0;
|
||||
if (limitDate != null) {
|
||||
tDate = new Date().getTime();
|
||||
tDate -= limitDate * 86400 * 1000;
|
||||
//log ("returning test lists greater than this date" + (new Date(tDate)).toGMTString());
|
||||
//TODO hack hack hack
|
||||
tDate = Math.floor(tDate/1000)
|
||||
|
||||
}
|
||||
if (branch != null) limiters += "&branch=" + branch;
|
||||
if (machine != null) limiters += "&machine=" + machine;
|
||||
if (testname != null) limiters += "&test=" + testname;
|
||||
//log("drequestTestList: " + getdatacgi + "type=discrete&datelimit=" + tDate + limiters);
|
||||
loadJSONDoc(getdatacgi + "type=discrete&datelimit=" + tDate + limiters)
|
||||
.addCallbacks(
|
||||
function (obj) {
|
||||
if (!checkErrorReturn(obj)) return;
|
||||
self.testList = obj.results;
|
||||
//log ("testlist: " + self.testList);
|
||||
callback.call(window, self.testList);
|
||||
},
|
||||
function () {alert ("requestTestList: Error talking to " + getdatacgi + ""); });
|
||||
},
|
||||
|
||||
requestSearchList: function (branch, machine, testname, callback) {
|
||||
var self = this;
|
||||
limiters = "";
|
||||
if (branch != null) limiters += "&branch=" + branch;
|
||||
if (machine != null) limiters += "&machine=" + machine;
|
||||
if (testname != null) limiters += "&test=" + testname;
|
||||
//log(getdatacgi + "getlist=1&type=discrete" + limiters);
|
||||
loadJSONDoc(getdatacgi + "getlist=1&type=discrete" + limiters)
|
||||
.addCallbacks(
|
||||
function (obj) {
|
||||
if (!checkErrorReturn(obj)) return;
|
||||
callback.call(window, obj.results);
|
||||
},
|
||||
function () {alert ("requestSearchList: Error talking to " + getdatacgi); });
|
||||
},
|
||||
};
|
||||
function ExtraDataTinderboxData() {
|
||||
};
|
||||
|
||||
ExtraDataTinderboxData.prototype = {
|
||||
__proto__: new TinderboxData(),
|
||||
|
||||
init: function () {
|
||||
},
|
||||
|
||||
requestTestList: function (limitDate, branch, machine, testname, callback) {
|
||||
var self = this;
|
||||
//netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect")
|
||||
var limiters = "";
|
||||
|
||||
var tDate = 0;
|
||||
if (limitDate != null) {
|
||||
tDate = new Date().getTime();
|
||||
tDate -= limitDate * 86400 * 1000;
|
||||
//log ("returning test lists greater than this date" + (new Date(tDate)).toGMTString());
|
||||
//TODO hack hack hack
|
||||
tDate = Math.floor(tDate/1000)
|
||||
|
||||
}
|
||||
if (branch != null) limiters += "&branch=" + branch;
|
||||
if (machine != null) limiters += "&machine=" + machine;
|
||||
if (testname != null) limiters += "&test=" + testname;
|
||||
//log("drequestTestList: " + getdatacgi + "type=discrete&datelimit=" + tDate + limiters);
|
||||
loadJSONDoc(getdatacgi + "type=discrete&graphby=bydata&datelimit=" + tDate + limiters)
|
||||
.addCallbacks(
|
||||
function (obj) {
|
||||
if (!checkErrorReturn(obj)) return;
|
||||
self.testList = obj.results;
|
||||
//log ("testlist: " + self.testList);
|
||||
callback.call(window, self.testList);
|
||||
},
|
||||
function () {alert ("requestTestList: Error talking to " + getdatacgi + ""); });
|
||||
},
|
||||
|
||||
requestSearchList: function (branch, machine, testname, callback) {
|
||||
var self = this;
|
||||
limiters = "";
|
||||
if (branch != null) limiters += "&branch=" + branch;
|
||||
if (machine != null) limiters += "&machine=" + machine;
|
||||
if (testname != null) limiters += "&test=" + testname;
|
||||
//log(getdatacgi + "getlist=1&type=discrete" + limiters);
|
||||
loadJSONDoc(getdatacgi + "getlist=1&type=discrete" + limiters)
|
||||
.addCallbacks(
|
||||
function (obj) {
|
||||
if (!checkErrorReturn(obj)) return;
|
||||
callback.call(window, obj.results);
|
||||
},
|
||||
function () {alert ("requestSearchList: Error talking to " + getdatacgi); });
|
||||
},
|
||||
// arg1 = startTime, arg2 = endTime, arg3 = callback
|
||||
// arg1 = callback, arg2/arg3 == null
|
||||
requestDataSetFor: function (testId, arg1, arg2, arg3) {
|
||||
var self = this;
|
||||
|
||||
var startTime = arg1;
|
||||
var endTime = arg2;
|
||||
var callback = arg3;
|
||||
|
||||
var tempArray = new Array();
|
||||
tempArray = testId.split("_",2);
|
||||
testId = tempArray[0];
|
||||
var extradata = tempArray[1];
|
||||
|
||||
if (arg1 && arg2 == null && arg3 == null) {
|
||||
callback = arg1;
|
||||
if (this.defaultLoadRange) {
|
||||
startTime = this.defaultLoadRange[0];
|
||||
endTime = this.defaultLoadRange[1];
|
||||
//log ("load range using default", startTime, endTime);
|
||||
} else {
|
||||
startTime = null;
|
||||
endTime = null;
|
||||
}
|
||||
}
|
||||
|
||||
if (testId in this.testData) {
|
||||
var ds = this.testData[testId];
|
||||
//log ("Can maybe use cached?");
|
||||
if ((ds.requestedFirstTime == null && ds.requestedLastTime == null) ||
|
||||
(ds.requestedFirstTime <= startTime &&
|
||||
ds.requestedLastTime >= endTime))
|
||||
{
|
||||
//log ("Using cached ds");
|
||||
callback.call (window, testId, ds);
|
||||
return;
|
||||
}
|
||||
|
||||
// this can be optimized, if we request just the bookend bits,
|
||||
// but that's overkill
|
||||
if (ds.firstTime < startTime)
|
||||
startTime = ds.firstTime;
|
||||
if (ds.lastTime > endTime)
|
||||
endTime = ds.lastTime;
|
||||
}
|
||||
|
||||
var cb =
|
||||
function (type, args, obj) {
|
||||
if (args[0] != testId ||
|
||||
args[2] > startTime ||
|
||||
args[3] < endTime)
|
||||
{
|
||||
// not useful for us; there's another
|
||||
// outstanding request for our time range, so wait for that
|
||||
return;
|
||||
}
|
||||
|
||||
self.onDataSetAvailable.unsubscribe(cb, obj);
|
||||
obj.call (window, args[0], args[1]);
|
||||
};
|
||||
this.onDataSetAvailable.subscribe (cb, callback);
|
||||
|
||||
//netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect")
|
||||
|
||||
var reqstr = getdatacgi + "setid=" + testId;
|
||||
if (startTime)
|
||||
reqstr += "&starttime=" + startTime;
|
||||
if (endTime)
|
||||
reqstr += "&endtime=" + endTime;
|
||||
//raw data is the extra_data column
|
||||
if (this.raw)
|
||||
reqstr += "&raw=1";
|
||||
reqstr += "&graphby=bydata";
|
||||
reqstr += "&extradata=" + extradata;
|
||||
//log (reqstr);
|
||||
loadJSONDoc(reqstr)
|
||||
.addCallbacks(
|
||||
function (obj) {
|
||||
if (!checkErrorReturn(obj)) return;
|
||||
|
||||
var ds = new TimeValueDataSet(obj.results);
|
||||
|
||||
//this is the the case of a discrete graph - where the entire test run is always requested
|
||||
//so the start and end points are the first and last entries in the returned data set
|
||||
if (!startTime && !endTime) {
|
||||
startTime = ds.data[0];
|
||||
endTime = ds.data[ds.data.length -2];
|
||||
}
|
||||
ds.requestedFirstTime = startTime;
|
||||
ds.requestedLastTime = endTime;
|
||||
self.testData[testId] = ds;
|
||||
if (obj.annotations)
|
||||
ds.annotations = new TimeStringDataSet(obj.annotations);
|
||||
if (obj.baselines)
|
||||
ds.baselines = obj.baselines;
|
||||
if (obj.rawdata)
|
||||
ds.rawdata = obj.rawdata;
|
||||
if (obj.stats)
|
||||
ds.stats = obj.stats;
|
||||
self.onDataSetAvailable.fire(testId, ds, startTime, endTime);
|
||||
},
|
||||
function (obj) {alert ("Error talking to " + getdatacgi + " (" + obj + ")"); log (obj.stack); });
|
||||
},
|
||||
};
|
||||
@@ -1,381 +0,0 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is new-graph code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla Corporation
|
||||
* Portions created by the Initial Developer are Copyright (C) 2006
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Vladimir Vukicevic <vladimir@pobox.com> (Original Author)
|
||||
* Alice Nodelman <anodelman@mozilla.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
var GraphFormModules = [];
|
||||
var GraphFormModuleCount = 0;
|
||||
|
||||
function DiscreteGraphFormModule(userConfig, userName) {
|
||||
GraphFormModuleCount++;
|
||||
//log("userName: " + userName);
|
||||
//this.__proto__.__proto__.constructor.call(this, "graphForm" + GraphFormModuleCount, userConfig, userName);
|
||||
this.init("graphForm" + GraphFormModuleCount, userConfig, userName);
|
||||
}
|
||||
|
||||
DiscreteGraphFormModule.prototype = {
|
||||
__proto__: new YAHOO.widget.Module(),
|
||||
|
||||
imageRoot: "",
|
||||
|
||||
testId: null,
|
||||
testIds: null,
|
||||
testText: "",
|
||||
baseline: false,
|
||||
average: false,
|
||||
name: "",
|
||||
limitDays: null,
|
||||
isLimit: null,
|
||||
onLoadingDone : new YAHOO.util.CustomEvent("onloadingdone"),
|
||||
onLoading : new YAHOO.util.CustomEvent("onloading"),
|
||||
addedInitialInfo : new YAHOO.util.CustomEvent("addedinitialinfo"),
|
||||
|
||||
init: function (el, userConfig, userName) {
|
||||
var self = this;
|
||||
//log("el " + el + " userConfig " + userConfig + " userName " + userName);
|
||||
this.__proto__.__proto__.init.call(this, el/*, userConfig*/);
|
||||
|
||||
this.cfg = new YAHOO.util.Config(this);
|
||||
this.cfg.addProperty("testid", { suppressEvent: true });
|
||||
this.cfg.addProperty("average", { suppressEvent: true });
|
||||
this.cfg.addProperty("baseline", { suppressEvent: true });
|
||||
|
||||
if (userConfig)
|
||||
this.cfg.applyConfig(userConfig, true);
|
||||
|
||||
var form, td, el;
|
||||
var tbl;
|
||||
var tbl_row;
|
||||
var tbl_col;
|
||||
tbl = new TABLE({});
|
||||
tbl_row = new TR({});
|
||||
tbl_col = new TD({colspan: 2});
|
||||
appendChildNodes(tbl_col,"Limit selection list by:");
|
||||
appendChildNodes(tbl_row, tbl_col);
|
||||
tbl_col = new TD({});
|
||||
appendChildNodes(tbl_col,"Choose test(s) to graph:");
|
||||
appendChildNodes(tbl_row, tbl_col);
|
||||
tbl.appendChild(tbl_row);
|
||||
|
||||
|
||||
tbl_row = new TR({});
|
||||
|
||||
form = new DIV({ class: "graphform-line" });
|
||||
|
||||
tbl_col = new TD({});
|
||||
el = new INPUT({ name: "dataload" + GraphFormModules.length,
|
||||
id: "all-days-radio",
|
||||
type: "radio",
|
||||
checked: 1,
|
||||
onchange: function(event) { self.update(null, self.branchSelect.value, self.machineSelect.value, self.testtypeSelect.value); } });
|
||||
tbl_col.appendChild(el);
|
||||
appendChildNodes(tbl_col, "all tests");
|
||||
|
||||
tbl_col.appendChild(new DIV({}));
|
||||
el = new INPUT({ name: "dataload" + GraphFormModules.length,
|
||||
type: "radio",
|
||||
onchange: function(event) { self.update(self.limitDays.value, self.branchSelect.value, self.machineSelect.value, self.testtypeSelect.value);} });
|
||||
this.isLimit = el;
|
||||
tbl_col.appendChild(el);
|
||||
appendChildNodes(tbl_col, "previous ");
|
||||
el = new INPUT({ name: "load-days-entry",
|
||||
id: "load-days-entry",
|
||||
type: "text",
|
||||
size: "3",
|
||||
value: "5",
|
||||
onchange: function(event) { if (self.isLimit.checked) {
|
||||
self.update(self.limitDays.value, self.branchSelect.value, self.machineSelect.value, self.testtypeSelect.value);} } });
|
||||
this.limitDays = el;
|
||||
tbl_col.appendChild(el);
|
||||
appendChildNodes(tbl_col, " days");
|
||||
|
||||
tbl_row.appendChild(tbl_col);
|
||||
|
||||
tbl_col = new TD({});
|
||||
appendChildNodes(tbl_col, "Branch: ");
|
||||
appendChildNodes(tbl_col, new BR({}));
|
||||
el = new SELECT({ name: "branchname",
|
||||
class: "other",
|
||||
size: 5,
|
||||
onchange: function(event) { if (self.isLimit.checked) {
|
||||
self.update(self.limitDays.value, self.branchSelect.value, self.machineSelect.value, self.testtypeSelect.value);}
|
||||
else self.update(null, self.branchSelect.value, self.machineSelect.value, self.testtypeSelect.value); } });
|
||||
this.branchSelect = el;
|
||||
Tinderbox.requestSearchList(1, null, null, function (list) {
|
||||
var opts = [];
|
||||
opts.push(new OPTION({value: null, selected: true}, "all"));
|
||||
for each (var listvalue in list) {
|
||||
opts.push(new OPTION({ value: listvalue.value}, listvalue.value));
|
||||
}
|
||||
replaceChildNodes(self.branchSelect, opts);
|
||||
});
|
||||
tbl_col.appendChild(el);
|
||||
tbl_row.appendChild(tbl_col);
|
||||
tbl_col = new TD({rowspan: 2, colspan: 2});
|
||||
span = new SPAN({id: "listname"});
|
||||
appendChildNodes(tbl_col, span);
|
||||
appendChildNodes(tbl_col, new BR({}));
|
||||
el = new SELECT({ name: "testname",
|
||||
class: "testname",
|
||||
multiple: true,
|
||||
center: true,
|
||||
size: 20,
|
||||
onchange: function(event) { self.onChangeTest(); } });
|
||||
this.testSelect = el;
|
||||
tbl_col.appendChild(el);
|
||||
tbl_row.appendChild(tbl_col);
|
||||
tbl.appendChild(tbl_row);
|
||||
tbl_row = new TR({});
|
||||
|
||||
tbl_col = new TD({});
|
||||
appendChildNodes(tbl_col, "Machine: ");
|
||||
appendChildNodes(tbl_col, new BR({}));
|
||||
el = new SELECT({ name: "machinename",
|
||||
class: "other",
|
||||
size: 5,
|
||||
onchange: function(event) { if (self.isLimit.checked) {
|
||||
self.update(self.limitDays.value, self.branchSelect.value, self.machineSelect.value, self.testtypeSelect.value);}
|
||||
else self.update(null, self.branchSelect.value, self.machineSelect.value, self.testtypeSelect.value); } });
|
||||
this.machineSelect = el;
|
||||
Tinderbox.requestSearchList(null, 1, null, function (list) {
|
||||
var opts = [];
|
||||
opts.push(new OPTION({value: null, selected: true}, "all"));
|
||||
for each (var listvalue in list) {
|
||||
opts.push(new OPTION({ value: listvalue.value}, listvalue.value));
|
||||
}
|
||||
replaceChildNodes(self.machineSelect, opts);
|
||||
});
|
||||
tbl_col.appendChild(el);
|
||||
tbl_row.appendChild(tbl_col);
|
||||
|
||||
tbl_col = new TD({});
|
||||
appendChildNodes(tbl_col, "Test name: ");
|
||||
appendChildNodes(tbl_col, new BR({}));
|
||||
el = new SELECT({ name: "testtypename",
|
||||
class: "other",
|
||||
size: 5,
|
||||
onchange: function(event) { if (self.isLimit.checked) {
|
||||
self.update(self.limitDays.value, self.branchSelect.value, self.machineSelect.value, self.testtypeSelect.value);}
|
||||
else self.update(null, self.branchSelect.value, self.machineSelect.value, self.testtypeSelect.value); } });
|
||||
this.testtypeSelect = el;
|
||||
|
||||
var forceTestIds = null;
|
||||
this.average = false;
|
||||
if (userConfig) {
|
||||
forceTestIds = userConfig;
|
||||
}
|
||||
//log ("userName: " + userName);
|
||||
|
||||
Tinderbox.requestSearchList(null, null, 1, function (list) {
|
||||
var opts = [];
|
||||
//opts.push(new OPTION({value: null, selected: true}, "all"));
|
||||
for each (var listvalue in list) {
|
||||
if ((userName) && (userName == listvalue.value)) {
|
||||
opts.push(new OPTION({ value: listvalue.value, selected : true}, listvalue.value));
|
||||
}
|
||||
else {
|
||||
opts.push(new OPTION({ value: listvalue.value}, listvalue.value));
|
||||
}
|
||||
}
|
||||
replaceChildNodes(self.testtypeSelect, opts);
|
||||
if (forceTestIds == null) {
|
||||
self.testtypeSelect.options[0].selected = true;
|
||||
self.update(null, null, null, self.testtypeSelect.value, forceTestIds);
|
||||
}
|
||||
else {
|
||||
self.update(null, null, null, userName, forceTestIds);
|
||||
}
|
||||
});
|
||||
tbl_col.appendChild(el);
|
||||
tbl_row.appendChild(tbl_col);
|
||||
/*
|
||||
tbl_col = new TD({rowspan: 2, colspan: 2});
|
||||
el = new SELECT({ name: "testname",
|
||||
class: "testname",
|
||||
multiple: true,
|
||||
size: 20,
|
||||
onchange: function(event) { self.onChangeTest(); } });
|
||||
this.testSelect = el;
|
||||
tbl_col.appendChild(el);
|
||||
tbl_row.appendChild(tbl_col);
|
||||
*/
|
||||
tbl.appendChild(tbl_row);
|
||||
form.appendChild(tbl);
|
||||
|
||||
|
||||
|
||||
this.setBody (form);
|
||||
/*
|
||||
var forceTestIds = null;
|
||||
this.average = false;
|
||||
if (userConfig) {
|
||||
forceTestIds = userConfig;
|
||||
}
|
||||
*/
|
||||
//self.update(null, null, null, null, forceTestIds);
|
||||
GraphFormModules.push(this);
|
||||
},
|
||||
|
||||
getQueryString: function (prefix) {
|
||||
var qstring = '';
|
||||
ctr = 1;
|
||||
for each (var opt in this.testSelect.options) {
|
||||
if (opt.selected) {
|
||||
prefixed = prefix + ctr;
|
||||
qstring += "&" + prefixed + "tid=" + opt.value + "&" + prefixed + "bl=" + (this.baseline ? "1" : "0")
|
||||
+ "&" + prefixed + "avg=" + (this.average? "1" : "0");
|
||||
ctr++
|
||||
}
|
||||
}
|
||||
return qstring;
|
||||
},
|
||||
|
||||
getDumpString: function () {
|
||||
var prefix = '';
|
||||
var dstring = '';
|
||||
for each (var opt in this.testSelect.options) {
|
||||
if (opt.selected) {
|
||||
dstring += prefix + "setid=" + opt.value;
|
||||
prefix = "&";
|
||||
}
|
||||
}
|
||||
return dstring;
|
||||
},
|
||||
|
||||
onChangeTest: function (forceTestIds) {
|
||||
this.testId = this.testSelect.value;
|
||||
//log("setting testId: " + this.testId);
|
||||
this.testIds = [];
|
||||
for each (var opt in this.testSelect.options) {
|
||||
if (opt.selected) {
|
||||
//log("opt: " + opt.value);
|
||||
this.testIds.push([opt.value, opt.text]);
|
||||
}
|
||||
}
|
||||
//log("testIDs: " + this.testIds);
|
||||
//log(this.testSelect.options[this.testSelect.selectedIndex].text);
|
||||
this.testText = this.testSelect.options[this.testSelect.selectedIndex];
|
||||
this.addedInitialInfo.fire();
|
||||
this.name = this.testtypeSelect.value;
|
||||
},
|
||||
|
||||
onBaseLineRadioClick: function () {
|
||||
GraphFormModules.forEach(function (g) { g.baseline = false; });
|
||||
this.baseline = true;
|
||||
},
|
||||
|
||||
remove: function () {
|
||||
var nf = [];
|
||||
for each (var f in GraphFormModules) {
|
||||
if (f != this)
|
||||
nf.push(f);
|
||||
}
|
||||
GraphFormModules = nf;
|
||||
this.destroy();
|
||||
},
|
||||
|
||||
update: function (limitD, branch, machine, testname, forceTestIds) {
|
||||
var self = this;
|
||||
this.onLoading.fire("updating test list");
|
||||
//log ("attempting to update graphformmodule, forceTestIds " + forceTestIds);
|
||||
Tinderbox.requestTestList(limitD, branch, machine, testname, function (tests) {
|
||||
var opts = [];
|
||||
var branch_opts = [];
|
||||
if (tests == '') {
|
||||
log("empty test list");
|
||||
self.onLoadingDone.fire();
|
||||
replaceChildNodes(self.testSelect, null);
|
||||
btn = getElement("graphbutton");
|
||||
btn.disabled = true;
|
||||
return;
|
||||
}
|
||||
// let's sort by machine name
|
||||
var sortedTests = Array.sort(tests, function (a, b) {
|
||||
if (a.machine < b.machine) return -1;
|
||||
if (a.machine > b.machine) return 1;
|
||||
if (a.test < b.test) return -1;
|
||||
if (a.test > b.test) return 1;
|
||||
if (a.test_type < b.test_type) return -1;
|
||||
if (a.test_type > b.test_type) return 1;
|
||||
if (a.date < b.date) return -1;
|
||||
if (a.date > b.date) return 1;
|
||||
return 0;
|
||||
});
|
||||
|
||||
for each (var test in sortedTests) {
|
||||
var d = new Date(test.date*1000);
|
||||
var s1 = (d.getHours() < 10 ? "0" : "") + d.getHours() + (d.getMinutes() < 10 ? ":0" : ":") + d.getMinutes() +
|
||||
//(d.getSeconds() < 10 ? ":0" : ":") + d.getSeconds() +
|
||||
" " + (d.getDate() < 10 ? "0" : "") + d.getDate();
|
||||
s1 += "/" + MONTH_ABBREV[d.getMonth()] + "/" + (d.getFullYear() -2000 < 10 ? "0" : "") + (d.getFullYear() - 2000);
|
||||
//(d.getYear() + 1900);
|
||||
var padstr = "--------------------";
|
||||
var tstr = "" + //test.test + padstr.substr(0, 20-test.test.length) +
|
||||
test.branch.toString() + padstr.substr(0, 6-test.branch.toString().length) +
|
||||
"-" + test.machine + padstr.substr(0, 10-test.machine.length) +
|
||||
"-" + s1;
|
||||
startSelected = false;
|
||||
if (forceTestIds != null) {
|
||||
if ((forceTestIds == test.id) || (forceTestIds.indexOf(Number(test.id)) > -1)) {
|
||||
startSelected = true;
|
||||
}
|
||||
}
|
||||
if (startSelected) {
|
||||
//log("starting with an initial selection");
|
||||
opts.push(new OPTION({ value: test.id, selected: true}, tstr));
|
||||
}
|
||||
else {
|
||||
opts.push(new OPTION({ value: test.id}, tstr));
|
||||
}
|
||||
}
|
||||
replaceChildNodes(self.testSelect, opts);
|
||||
|
||||
if (forceTestIds == null) {
|
||||
self.testSelect.options[0].selected = true;
|
||||
//self.testSelect.value = sortedTests[0].id;
|
||||
}
|
||||
replaceChildNodes("listname", null);
|
||||
appendChildNodes("listname","Select from " + testname + ":");
|
||||
btn = getElement("graphbutton");
|
||||
btn.disabled = false;
|
||||
setTimeout(function () { self.onChangeTest(forceTestIds); }, 0);
|
||||
self.onLoadingDone.fire();
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
};
|
||||
|
||||
@@ -1,376 +0,0 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is new-graph code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla Corporation
|
||||
* Portions created by the Initial Developer are Copyright (C) 2006
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Vladimir Vukicevic <vladimir@pobox.com> (Original Author)
|
||||
* Alice Nodelman <anodelman@mozilla.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
var GraphFormModules = [];
|
||||
var GraphFormModuleCount = 0;
|
||||
|
||||
function ExtraDataGraphFormModule(userConfig, userName) {
|
||||
GraphFormModuleCount++;
|
||||
//log("userName: " + userName);
|
||||
//this.__proto__.__proto__.constructor.call(this, "graphForm" + GraphFormModuleCount, userConfig, userName);
|
||||
this.init("graphForm" + GraphFormModuleCount, userConfig, userName);
|
||||
}
|
||||
|
||||
ExtraDataGraphFormModule.prototype = {
|
||||
__proto__: new YAHOO.widget.Module(),
|
||||
|
||||
imageRoot: "",
|
||||
|
||||
testId: null,
|
||||
testIds: null,
|
||||
testText: "",
|
||||
baseline: false,
|
||||
average: false,
|
||||
name: "",
|
||||
limitDays: null,
|
||||
isLimit: null,
|
||||
onLoadingDone : new YAHOO.util.CustomEvent("onloadingdone"),
|
||||
onLoading : new YAHOO.util.CustomEvent("onloading"),
|
||||
addedInitialInfo : new YAHOO.util.CustomEvent("addedinitialinfo"),
|
||||
|
||||
init: function (el, userConfig, userName) {
|
||||
var self = this;
|
||||
//log("el " + el + " userConfig " + userConfig + " userName " + userName);
|
||||
this.__proto__.__proto__.init.call(this, el/*, userConfig*/);
|
||||
|
||||
this.cfg = new YAHOO.util.Config(this);
|
||||
this.cfg.addProperty("testid", { suppressEvent: true });
|
||||
this.cfg.addProperty("average", { suppressEvent: true });
|
||||
this.cfg.addProperty("baseline", { suppressEvent: true });
|
||||
|
||||
if (userConfig)
|
||||
this.cfg.applyConfig(userConfig, true);
|
||||
|
||||
var form, td, el;
|
||||
var tbl;
|
||||
var tbl_row;
|
||||
var tbl_col;
|
||||
tbl = new TABLE({});
|
||||
tbl_row = new TR({});
|
||||
tbl_col = new TD({colspan: 2});
|
||||
appendChildNodes(tbl_col,"Limit selection list by:");
|
||||
appendChildNodes(tbl_row, tbl_col);
|
||||
tbl_col = new TD({});
|
||||
appendChildNodes(tbl_col,"Choose test(s) to graph:");
|
||||
appendChildNodes(tbl_row, tbl_col);
|
||||
tbl.appendChild(tbl_row);
|
||||
|
||||
|
||||
tbl_row = new TR({});
|
||||
|
||||
form = new DIV({ class: "graphform-line" });
|
||||
|
||||
tbl_col = new TD({});
|
||||
el = new INPUT({ name: "dataload" + GraphFormModules.length,
|
||||
id: "all-days-radio",
|
||||
type: "radio",
|
||||
checked: 1,
|
||||
onchange: function(event) { self.update(null, self.branchSelect.value, self.machineSelect.value, self.testtypeSelect.value); } });
|
||||
tbl_col.appendChild(el);
|
||||
appendChildNodes(tbl_col, "all tests");
|
||||
|
||||
tbl_col.appendChild(new DIV({}));
|
||||
el = new INPUT({ name: "dataload" + GraphFormModules.length,
|
||||
type: "radio",
|
||||
onchange: function(event) { self.update(self.limitDays.value, self.branchSelect.value, self.machineSelect.value, self.testtypeSelect.value);} });
|
||||
this.isLimit = el;
|
||||
tbl_col.appendChild(el);
|
||||
appendChildNodes(tbl_col, "previous ");
|
||||
el = new INPUT({ name: "load-days-entry",
|
||||
id: "load-days-entry",
|
||||
type: "text",
|
||||
size: "3",
|
||||
value: "5",
|
||||
onchange: function(event) { if (self.isLimit.checked) {
|
||||
self.update(self.limitDays.value, self.branchSelect.value, self.machineSelect.value, self.testtypeSelect.value);} } });
|
||||
this.limitDays = el;
|
||||
tbl_col.appendChild(el);
|
||||
appendChildNodes(tbl_col, " days");
|
||||
|
||||
tbl_row.appendChild(tbl_col);
|
||||
|
||||
tbl_col = new TD({});
|
||||
appendChildNodes(tbl_col, "Branch: ");
|
||||
appendChildNodes(tbl_col, new BR({}));
|
||||
el = new SELECT({ name: "branchname",
|
||||
class: "other",
|
||||
size: 5,
|
||||
onchange: function(event) { if (self.isLimit.checked) {
|
||||
self.update(self.limitDays.value, self.branchSelect.value, self.machineSelect.value, self.testtypeSelect.value);}
|
||||
else self.update(null, self.branchSelect.value, self.machineSelect.value, self.testtypeSelect.value); } });
|
||||
this.branchSelect = el;
|
||||
Tinderbox.requestSearchList(1, null, null, function (list) {
|
||||
var opts = [];
|
||||
opts.push(new OPTION({value: null, selected: true}, "all"));
|
||||
for each (var listvalue in list) {
|
||||
opts.push(new OPTION({ value: listvalue.value}, listvalue.value));
|
||||
}
|
||||
replaceChildNodes(self.branchSelect, opts);
|
||||
});
|
||||
tbl_col.appendChild(el);
|
||||
tbl_row.appendChild(tbl_col);
|
||||
tbl_col = new TD({rowspan: 2, colspan: 2});
|
||||
span = new SPAN({id: "listname"});
|
||||
appendChildNodes(tbl_col, span);
|
||||
appendChildNodes(tbl_col, new BR({}));
|
||||
el = new SELECT({ name: "testname",
|
||||
class: "testname",
|
||||
multiple: true,
|
||||
center: true,
|
||||
size: 20,
|
||||
onchange: function(event) { self.onChangeTest(); } });
|
||||
this.testSelect = el;
|
||||
tbl_col.appendChild(el);
|
||||
tbl_row.appendChild(tbl_col);
|
||||
tbl.appendChild(tbl_row);
|
||||
tbl_row = new TR({});
|
||||
|
||||
tbl_col = new TD({});
|
||||
appendChildNodes(tbl_col, "Machine: ");
|
||||
appendChildNodes(tbl_col, new BR({}));
|
||||
el = new SELECT({ name: "machinename",
|
||||
class: "other",
|
||||
size: 5,
|
||||
onchange: function(event) { if (self.isLimit.checked) {
|
||||
self.update(self.limitDays.value, self.branchSelect.value, self.machineSelect.value, self.testtypeSelect.value);}
|
||||
else self.update(null, self.branchSelect.value, self.machineSelect.value, self.testtypeSelect.value); } });
|
||||
this.machineSelect = el;
|
||||
Tinderbox.requestSearchList(null, 1, null, function (list) {
|
||||
var opts = [];
|
||||
opts.push(new OPTION({value: null, selected: true}, "all"));
|
||||
for each (var listvalue in list) {
|
||||
opts.push(new OPTION({ value: listvalue.value}, listvalue.value));
|
||||
}
|
||||
replaceChildNodes(self.machineSelect, opts);
|
||||
});
|
||||
tbl_col.appendChild(el);
|
||||
tbl_row.appendChild(tbl_col);
|
||||
|
||||
tbl_col = new TD({});
|
||||
appendChildNodes(tbl_col, "Test name: ");
|
||||
appendChildNodes(tbl_col, new BR({}));
|
||||
el = new SELECT({ name: "testtypename",
|
||||
class: "other",
|
||||
size: 5,
|
||||
onchange: function(event) { if (self.isLimit.checked) {
|
||||
self.update(self.limitDays.value, self.branchSelect.value, self.machineSelect.value, self.testtypeSelect.value);}
|
||||
else self.update(null, self.branchSelect.value, self.machineSelect.value, self.testtypeSelect.value); } });
|
||||
this.testtypeSelect = el;
|
||||
|
||||
var forceTestIds = null;
|
||||
this.average = false;
|
||||
if (userConfig) {
|
||||
forceTestIds = userConfig;
|
||||
}
|
||||
//log ("userName: " + userName);
|
||||
|
||||
Tinderbox.requestSearchList(null, null, 1, function (list) {
|
||||
var opts = [];
|
||||
//opts.push(new OPTION({value: null, selected: true}, "all"));
|
||||
for each (var listvalue in list) {
|
||||
if ((userName) && (userName == listvalue.value)) {
|
||||
opts.push(new OPTION({ value: listvalue.value, selected : true}, listvalue.value));
|
||||
}
|
||||
else {
|
||||
opts.push(new OPTION({ value: listvalue.value}, listvalue.value));
|
||||
}
|
||||
}
|
||||
replaceChildNodes(self.testtypeSelect, opts);
|
||||
if (forceTestIds == null) {
|
||||
self.testtypeSelect.options[0].selected = true;
|
||||
self.update(null, null, null, self.testtypeSelect.value, forceTestIds);
|
||||
}
|
||||
else {
|
||||
self.update(null, null, null, userName, forceTestIds);
|
||||
}
|
||||
});
|
||||
tbl_col.appendChild(el);
|
||||
tbl_row.appendChild(tbl_col);
|
||||
/*
|
||||
tbl_col = new TD({rowspan: 2, colspan: 2});
|
||||
el = new SELECT({ name: "testname",
|
||||
class: "testname",
|
||||
multiple: true,
|
||||
size: 20,
|
||||
onchange: function(event) { self.onChangeTest(); } });
|
||||
this.testSelect = el;
|
||||
tbl_col.appendChild(el);
|
||||
tbl_row.appendChild(tbl_col);
|
||||
*/
|
||||
tbl.appendChild(tbl_row);
|
||||
form.appendChild(tbl);
|
||||
|
||||
|
||||
|
||||
this.setBody (form);
|
||||
/*
|
||||
var forceTestIds = null;
|
||||
this.average = false;
|
||||
if (userConfig) {
|
||||
forceTestIds = userConfig;
|
||||
}
|
||||
*/
|
||||
//self.update(null, null, null, null, forceTestIds);
|
||||
GraphFormModules.push(this);
|
||||
},
|
||||
|
||||
getQueryString: function (prefix) {
|
||||
var qstring = '';
|
||||
ctr = 1;
|
||||
for each (var opt in this.testSelect.options) {
|
||||
if (opt.selected) {
|
||||
prefixed = prefix + ctr;
|
||||
qstring += "&" + prefixed + "tid=" + opt.value + "&" + prefixed + "bl=" + (this.baseline ? "1" : "0")
|
||||
+ "&" + prefixed + "avg=" + (this.average? "1" : "0");
|
||||
ctr++
|
||||
}
|
||||
}
|
||||
return qstring;
|
||||
},
|
||||
|
||||
getDumpString: function () {
|
||||
var prefix = '';
|
||||
var dstring = '';
|
||||
for each (var opt in this.testSelect.options) {
|
||||
if (opt.selected) {
|
||||
dstring += prefix + "setid=" + opt.value;
|
||||
prefix = "&";
|
||||
}
|
||||
}
|
||||
return dstring;
|
||||
},
|
||||
|
||||
onChangeTest: function (forceTestIds) {
|
||||
this.testId = this.testSelect.value;
|
||||
//log("setting testId: " + this.testId);
|
||||
this.testIds = [];
|
||||
for each (var opt in this.testSelect.options) {
|
||||
if (opt.selected) {
|
||||
//log("opt: " + opt.value);
|
||||
this.testIds.push([opt.value, opt.text]);
|
||||
}
|
||||
}
|
||||
//log("testIDs: " + this.testIds);
|
||||
//log(this.testSelect.options[this.testSelect.selectedIndex].text);
|
||||
this.testText = this.testSelect.options[this.testSelect.selectedIndex];
|
||||
this.addedInitialInfo.fire();
|
||||
this.name = this.testtypeSelect.value;
|
||||
},
|
||||
|
||||
onBaseLineRadioClick: function () {
|
||||
GraphFormModules.forEach(function (g) { g.baseline = false; });
|
||||
this.baseline = true;
|
||||
},
|
||||
|
||||
remove: function () {
|
||||
var nf = [];
|
||||
for each (var f in GraphFormModules) {
|
||||
if (f != this)
|
||||
nf.push(f);
|
||||
}
|
||||
GraphFormModules = nf;
|
||||
this.destroy();
|
||||
},
|
||||
|
||||
update: function (limitD, branch, machine, testname, forceTestIds) {
|
||||
var self = this;
|
||||
this.onLoading.fire("updating test list");
|
||||
//log ("attempting to update graphformmodule, forceTestIds " + forceTestIds);
|
||||
Tinderbox.requestTestList(limitD, branch, machine, testname, function (tests) {
|
||||
var opts = [];
|
||||
var branch_opts = [];
|
||||
if (tests == '') {
|
||||
log("empty test list");
|
||||
self.onLoadingDone.fire();
|
||||
replaceChildNodes(self.testSelect, null);
|
||||
btn = getElement("graphbutton");
|
||||
btn.disabled = true;
|
||||
return;
|
||||
}
|
||||
// let's sort by machine name
|
||||
var sortedTests = Array.sort(tests, function (a, b) {
|
||||
if (a.machine < b.machine) return -1;
|
||||
if (a.machine > b.machine) return 1;
|
||||
if (a.test < b.test) return -1;
|
||||
if (a.test > b.test) return 1;
|
||||
if (a.test_type < b.test_type) return -1;
|
||||
if (a.test_type > b.test_type) return 1;
|
||||
if (a.data < b.data) return -1;
|
||||
if (a.data > b.data) return 1;
|
||||
return 0;
|
||||
});
|
||||
|
||||
for each (var test in sortedTests) {
|
||||
var s1 = test.data;
|
||||
var padstr = "--------------------";
|
||||
var tstr = "" + //test.test + padstr.substr(0, 20-test.test.length) +
|
||||
test.branch.toString() + padstr.substr(0, 6-test.branch.toString().length) +
|
||||
"-" + test.machine + padstr.substr(0, 10-test.machine.length) +
|
||||
"-" + s1;
|
||||
startSelected = false;
|
||||
if (forceTestIds != null) {
|
||||
if ((forceTestIds == test.id) || (forceTestIds.indexOf(Number(test.id)) > -1)) {
|
||||
startSelected = true;
|
||||
}
|
||||
}
|
||||
if (startSelected) {
|
||||
//log("starting with an initial selection");
|
||||
opts.push(new OPTION({ value: test.id + "_" + test.data, selected: true}, tstr));
|
||||
}
|
||||
else {
|
||||
opts.push(new OPTION({ value: test.id + "_" + test.data}, tstr));
|
||||
}
|
||||
}
|
||||
replaceChildNodes(self.testSelect, opts);
|
||||
|
||||
if (forceTestIds == null) {
|
||||
self.testSelect.options[0].selected = true;
|
||||
//self.testSelect.value = sortedTests[0].id;
|
||||
}
|
||||
replaceChildNodes("listname", null);
|
||||
appendChildNodes("listname","Select from " + testname + ":");
|
||||
btn = getElement("graphbutton");
|
||||
btn.disabled = false;
|
||||
setTimeout(function () { self.onChangeTest(forceTestIds); }, 0);
|
||||
self.onLoadingDone.fire();
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
};
|
||||
|
||||
@@ -1,87 +0,0 @@
|
||||
|
||||
.graphconfig {
|
||||
background-color: #cccccc;
|
||||
-moz-border-radius: 10px 0 0 10px;
|
||||
padding: 10px;
|
||||
width: 15em;
|
||||
}
|
||||
|
||||
.dgraphconfig {
|
||||
background-color: #cccccc;
|
||||
-moz-border-radius: 10px 0 0 10px;
|
||||
padding: 10px;
|
||||
width: 7em;
|
||||
}
|
||||
|
||||
.graphconfig-list {
|
||||
background-color: #cccccc;
|
||||
-moz-border-radius: 0 10px 10px 0;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
/* Yuck */
|
||||
|
||||
.graphform-line, .baseline {
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.graphform-first-span {
|
||||
/* font-weight: bold; */
|
||||
}
|
||||
|
||||
/*
|
||||
#graphforms div .bd .graphform-line .graphform-first-span:after {
|
||||
content: "For ";
|
||||
}
|
||||
|
||||
.module + .module .bd .graphform-line .graphform-first-span:after {
|
||||
content: "and " ! important;
|
||||
}
|
||||
*/
|
||||
|
||||
select.tinderbox, select.testname {
|
||||
font-family: monospace;
|
||||
width: 350px;
|
||||
}
|
||||
|
||||
select.other {
|
||||
font-family: monospace;
|
||||
width: 225px;
|
||||
}
|
||||
|
||||
.plusminus {
|
||||
padding: 3px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.plusminus:hover {
|
||||
background: #999;
|
||||
}
|
||||
|
||||
.plusminushidden {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
.y-axis-label {
|
||||
font-family: Tahoma, Verdana, Vera Sans, "Bitstream Vera Sans", Arial, Helvetica, sans-serif;
|
||||
font-size: 75%;
|
||||
vertical-align: middle;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.x-axis-label {
|
||||
font-family: Tahoma, Verdana, Vera Sans, "Bitstream Vera Sans", Arial, Helvetica, sans-serif;
|
||||
font-size: 75%;
|
||||
padding: 0px;
|
||||
vertical-align: top;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.status {
|
||||
color: blue;
|
||||
}
|
||||
|
||||
/* debug */
|
||||
/*div { border: 1px solid blue; }*/
|
||||
@@ -1,661 +0,0 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is new-graph code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla Corporation
|
||||
* Portions created by the Initial Developer are Copyright (C) 2006
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Vladimir Vukicevic <vladimir@pobox.com> (Original Author)
|
||||
* Alice Nodelman <anodelman@mozilla.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
// all times are in seconds
|
||||
|
||||
const ONE_HOUR_SECONDS = 60*60;
|
||||
const ONE_DAY_SECONDS = 24*ONE_HOUR_SECONDS;
|
||||
const ONE_WEEK_SECONDS = 7*ONE_DAY_SECONDS;
|
||||
const ONE_YEAR_SECONDS = 365*ONE_DAY_SECONDS; // leap years whatever.
|
||||
|
||||
const MONTH_ABBREV = [ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" ];
|
||||
|
||||
const CONTINUOUS_GRAPH = 0;
|
||||
const DISCRETE_GRAPH = 1;
|
||||
const DATA_GRAPH = 2;
|
||||
|
||||
const bonsaicgi = "bonsaibouncer.cgi";
|
||||
|
||||
// more days than this and we'll force user confirmation for the bonsai query
|
||||
const bonsaiNoForceDays = 90;
|
||||
|
||||
// the default average interval
|
||||
var gAverageInterval = 3*ONE_HOUR_SECONDS;
|
||||
var gCurrentLoadRange = null;
|
||||
var gForceBonsai = false;
|
||||
|
||||
var Tinderbox;
|
||||
var BigPerfGraph;
|
||||
var SmallPerfGraph;
|
||||
var Bonsai;
|
||||
var graphType;
|
||||
|
||||
function loadingDone(graphTypePref) {
|
||||
//createLoggingPane(true);
|
||||
graphType = graphTypePref;
|
||||
|
||||
if (graphType == CONTINUOUS_GRAPH) {
|
||||
Tinderbox = new TinderboxData();
|
||||
SmallPerfGraph = new CalendarTimeGraph("smallgraph");
|
||||
BigPerfGraph = new CalendarTimeGraph("graph");
|
||||
onDataLoadChanged();
|
||||
} else if (graphType == DATA_GRAPH) {
|
||||
Tinderbox = new ExtraDataTinderboxData();
|
||||
SmallPerfGraph = new CalendarTimeGraph("smallgraph");
|
||||
BigPerfGraph = new CalendarTimeGraph("graph");
|
||||
}
|
||||
else {
|
||||
Tinderbox = new DiscreteTinderboxData();
|
||||
Tinderbox.raw = 1;
|
||||
SmallPerfGraph = new DiscreteGraph("smallgraph");
|
||||
BigPerfGraph = new DiscreteGraph("graph");
|
||||
onDiscreteDataLoadChanged();
|
||||
}
|
||||
|
||||
Tinderbox.init();
|
||||
|
||||
if (BonsaiService)
|
||||
Bonsai = new BonsaiService();
|
||||
|
||||
SmallPerfGraph.yLabelHeight = 20;
|
||||
SmallPerfGraph.setSelectionType("range");
|
||||
BigPerfGraph.setSelectionType("cursor");
|
||||
BigPerfGraph.setCursorType("free");
|
||||
|
||||
|
||||
SmallPerfGraph.onSelectionChanged.
|
||||
subscribe (function (type, args, obj) {
|
||||
log ("selchanged");
|
||||
|
||||
if (args[0] == "range") {
|
||||
if (args[1] && args[2]) {
|
||||
var t1 = args[1];
|
||||
var t2 = args[2];
|
||||
|
||||
var foundIndexes = [];
|
||||
|
||||
// make sure that there are at least two points
|
||||
// on at least one graph for this
|
||||
var foundPoints = false;
|
||||
var dss = BigPerfGraph.dataSets;
|
||||
for (var i = 0; i < dss.length; i++) {
|
||||
var idcs = dss[i].indicesForTimeRange(t1, t2);
|
||||
if (idcs[1] - idcs[0] > 1) {
|
||||
foundPoints = true;
|
||||
break;
|
||||
}
|
||||
foundIndexes.push(idcs);
|
||||
}
|
||||
|
||||
if (!foundPoints) {
|
||||
// we didn't find at least two points in at least
|
||||
// one graph; so munge the time numbers until we do.
|
||||
log("Orig t1 " + t1 + " t2 " + t2);
|
||||
|
||||
for (var i = 0; i < dss.length; i++) {
|
||||
if (foundIndexes[i][0] > 0) {
|
||||
t1 = Math.min(dss[i].data[(foundIndexes[i][0] - 1) * 2], t1);
|
||||
} else if (foundIndexes[i][1]+1 < (ds.data.length/2)) {
|
||||
t2 = Math.max(dss[i].data[(foundIndexes[i][1] + 1) * 2], t2);
|
||||
}
|
||||
}
|
||||
|
||||
log("Fixed t1 " + t1 + " t2 " + t2);
|
||||
}
|
||||
|
||||
BigPerfGraph.setTimeRange (t1, t2);
|
||||
} else {
|
||||
BigPerfGraph.setTimeRange (SmallPerfGraph.startTime, SmallPerfGraph.endTime);
|
||||
}
|
||||
BigPerfGraph.autoScale();
|
||||
BigPerfGraph.redraw();
|
||||
}
|
||||
|
||||
updateLinkToThis();
|
||||
updateDumpToCsv();
|
||||
});
|
||||
|
||||
if (graphType == CONTINUOUS_GRAPH) {
|
||||
BigPerfGraph.onCursorMoved.
|
||||
subscribe (function (type, args, obj) {
|
||||
var time = args[0];
|
||||
var val = args[1];
|
||||
if (time != null && val != null) {
|
||||
// cheat
|
||||
showStatus("Date: " + formatTime(time) + " Value: " + val.toFixed(2));
|
||||
} else {
|
||||
showStatus(null);
|
||||
}
|
||||
});
|
||||
BigPerfGraph.onNewGraph.
|
||||
subscribe (function(type, args, obj) {
|
||||
if (args[0].length >= GraphFormModules.length) {
|
||||
clearLoadingAnimation();
|
||||
}
|
||||
});
|
||||
}
|
||||
else if (graphType == DATA_GRAPH) {
|
||||
BigPerfGraph.onCursorMoved.
|
||||
subscribe (function (type, args, obj) {
|
||||
var time = args[0];
|
||||
var val = args[1];
|
||||
if (time != null && val != null) {
|
||||
// cheat
|
||||
showStatus("Date: " + formatTime(time) + " Value: " + val.toFixed(2));
|
||||
} else {
|
||||
showStatus(null);
|
||||
}
|
||||
});
|
||||
BigPerfGraph.onNewGraph.
|
||||
subscribe (function(type, args, obj) {
|
||||
showGraphList(args[0]);
|
||||
});
|
||||
}
|
||||
else {
|
||||
BigPerfGraph.onCursorMoved.
|
||||
subscribe (function (type, args, obj) {
|
||||
var time = args[0];
|
||||
var val = args[1];
|
||||
var extra_data = args[2]
|
||||
if (time != null && val != null) {
|
||||
// cheat
|
||||
showStatus("Interval: " + Math.floor(time) + " Value: " + val.toFixed(2) + " " + extra_data);
|
||||
} else {
|
||||
showStatus(null);
|
||||
}
|
||||
});
|
||||
BigPerfGraph.onNewGraph.
|
||||
subscribe (function(type, args, obj) {
|
||||
showGraphList(args[0]);
|
||||
});
|
||||
}
|
||||
if (document.location.hash) {
|
||||
handleHash(document.location.hash);
|
||||
} else {
|
||||
if (graphType == CONTINUOUS_GRAPH) {
|
||||
addGraphForm();
|
||||
}
|
||||
else if ( graphType == DATA_GRAPH ) {
|
||||
addExtraDataGraphForm();
|
||||
}
|
||||
else {
|
||||
addDiscreteGraphForm();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function addExtraDataGraphForm(config, name) {
|
||||
showLoadingAnimation("populating lists");
|
||||
var ed = new ExtraDataGraphFormModule(config, name);
|
||||
ed.onLoading.subscribe (function(type,args,obj) { showLoadingAnimation(args[0]);});
|
||||
ed.onLoadingDone.subscribe (function(type,args,obj) { clearLoadingAnimation();});
|
||||
if (config) {
|
||||
ed.addedInitialInfo.subscribe(function(type,args,obj) { graphInitial();});
|
||||
}
|
||||
ed.render (getElement("graphforms"));
|
||||
return ed;
|
||||
}
|
||||
|
||||
function addDiscreteGraphForm(config, name) {
|
||||
showLoadingAnimation("populating lists");
|
||||
//log("name: " + name);
|
||||
var m = new DiscreteGraphFormModule(config, name);
|
||||
m.onLoading.subscribe (function(type,args,obj) { showLoadingAnimation(args[0]);});
|
||||
m.onLoadingDone.subscribe (function(type,args,obj) { clearLoadingAnimation();});
|
||||
if (config) {
|
||||
m.addedInitialInfo.subscribe(function(type,args,obj) { graphInitial();});
|
||||
}
|
||||
m.render (getElement("graphforms"));
|
||||
//m.setColor(randomColor());
|
||||
return m;
|
||||
}
|
||||
|
||||
function addGraphForm(config) {
|
||||
showLoadingAnimation("populating list");
|
||||
var m = new GraphFormModule(config);
|
||||
m.render (getElement("graphforms"));
|
||||
m.setColor(randomColor());
|
||||
m.onLoading.subscribe (function(type,args,obj) { showLoadingAnimation(args[0]);});
|
||||
m.onLoadingDone.subscribe (function(type,args,obj) { clearLoadingAnimation();});
|
||||
return m;
|
||||
}
|
||||
|
||||
function onNoBaseLineClick() {
|
||||
GraphFormModules.forEach (function (g) { g.baseline = false; });
|
||||
}
|
||||
|
||||
// whether the bonsai data query should redraw the graph or not
|
||||
var gReadyForRedraw = true;
|
||||
|
||||
function onUpdateBonsai() {
|
||||
BigPerfGraph.deleteAllMarkers();
|
||||
|
||||
getElement("bonsaibutton").disabled = true;
|
||||
|
||||
if (gCurrentLoadRange) {
|
||||
if ((gCurrentLoadRange[1] - gCurrentLoadRange[0]) < (bonsaiNoForceDays * ONE_DAY_SECONDS) || gForceBonsai) {
|
||||
Bonsai.requestCheckinsBetween (gCurrentLoadRange[0], gCurrentLoadRange[1],
|
||||
function (bdata) {
|
||||
for (var i = 0; i < bdata.times.length; i++) {
|
||||
BigPerfGraph.addMarker (bdata.times[i], bdata.who[i] + ": " + bdata.comment[i]);
|
||||
}
|
||||
if (gReadyForRedraw)
|
||||
BigPerfGraph.redraw();
|
||||
|
||||
getElement("bonsaibutton").disabled = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
function onGraph() {
|
||||
showLoadingAnimation("building graph");
|
||||
showStatus(null);
|
||||
for each (var g in [BigPerfGraph, SmallPerfGraph]) {
|
||||
g.clearDataSets();
|
||||
g.setTimeRange(null, null);
|
||||
}
|
||||
|
||||
gReadyForRedraw = false;
|
||||
|
||||
// do the actual graph data request
|
||||
var baselineModule = null;
|
||||
GraphFormModules.forEach (function (g) { if (g.baseline) baselineModule = g; });
|
||||
if (baselineModule) {
|
||||
Tinderbox.requestDataSetFor (baselineModule.testId,
|
||||
function (testid, ds) {
|
||||
try {
|
||||
//log ("Got results for baseline: '" + testid + "' ds: " + ds);
|
||||
ds.color = baselineModule.color;
|
||||
onGraphLoadRemainder(ds);
|
||||
} catch(e) { log(e); }
|
||||
});
|
||||
} else {
|
||||
onGraphLoadRemainder();
|
||||
}
|
||||
}
|
||||
|
||||
function onGraphLoadRemainder(baselineDataSet) {
|
||||
for each (var graphModule in GraphFormModules) {
|
||||
//log ("onGraphLoadRemainder: ", graphModule.id, graphModule.testId, "color:", graphModule.color, "average:", graphModule.average);
|
||||
|
||||
// this would have been loaded earlier
|
||||
if (graphModule.baseline)
|
||||
continue;
|
||||
|
||||
var autoExpand = true;
|
||||
if (SmallPerfGraph.selectionType == "range" &&
|
||||
SmallPerfGraph.selectionStartTime &&
|
||||
SmallPerfGraph.selectionEndTime)
|
||||
{
|
||||
if (gCurrentLoadRange && (SmallPerfGraph.selectionStartTime < gCurrentLoadRange[0] ||
|
||||
SmallPerfGraph.selectionEndTime > gCurrentLoadRange[1]))
|
||||
{
|
||||
SmallPerfGraph.selectionStartTime = Math.max (SmallPerfGraph.selectionStartTime, gCurrentLoadRange[0]);
|
||||
SmallPerfGraph.selectionEndTime = Math.min (SmallPerfGraph.selectionEndTime, gCurrentLoadRange[1]);
|
||||
}
|
||||
|
||||
BigPerfGraph.setTimeRange (SmallPerfGraph.selectionStartTime, SmallPerfGraph.selectionEndTime);
|
||||
autoExpand = false;
|
||||
}
|
||||
|
||||
// we need a new closure here so that we can get the right value
|
||||
// of graphModule in our closure
|
||||
var makeCallback = function (module, color, title) {
|
||||
return function (testid, ds) {
|
||||
try {
|
||||
log("ds.firstTime " + ds.firstTime + " ds.lastTime " + ds.lastTime);
|
||||
if (undefined == ds.firstTime || !ds.lastTime) {
|
||||
// got a data set with no data in this time range, or damaged data
|
||||
// better to not graph
|
||||
for each (g in [BigPerfGraph, SmallPerfGraph]) {
|
||||
g.clearGraph();
|
||||
|
||||
}
|
||||
showStatus("No data in the given time range");
|
||||
clearLoadingAnimation();
|
||||
|
||||
}
|
||||
else {
|
||||
ds.color = color;
|
||||
if (title) {
|
||||
ds.title = title;
|
||||
}
|
||||
|
||||
if (baselineDataSet)
|
||||
ds = ds.createRelativeTo(baselineDataSet);
|
||||
|
||||
//log ("got ds: (", module.id, ")", ds.firstTime, ds.lastTime, ds.data.length);
|
||||
var avgds = null;
|
||||
if (baselineDataSet == null &&
|
||||
module.average)
|
||||
{
|
||||
avgds = ds.createAverage(gAverageInterval);
|
||||
}
|
||||
|
||||
if (avgds)
|
||||
log ("got avgds: (", module.id, ")", avgds.firstTime, avgds.lastTime, avgds.data.length);
|
||||
|
||||
for each (g in [BigPerfGraph, SmallPerfGraph]) {
|
||||
g.addDataSet(ds);
|
||||
if (avgds)
|
||||
g.addDataSet(avgds);
|
||||
if (g == SmallPerfGraph || autoExpand) {
|
||||
g.expandTimeRange(Math.max(ds.firstTime, gCurrentLoadRange ? gCurrentLoadRange[0] : ds.firstTime),
|
||||
Math.min(ds.lastTime, gCurrentLoadRange ? gCurrentLoadRange[1] : ds.lastTime));
|
||||
}
|
||||
|
||||
g.autoScale();
|
||||
|
||||
g.redraw();
|
||||
gReadyForRedraw = true;
|
||||
}
|
||||
|
||||
//if (graphType == CONTINUOUS_GRAPH) {
|
||||
updateLinkToThis();
|
||||
updateDumpToCsv();
|
||||
//}
|
||||
}
|
||||
|
||||
} catch(e) { log(e); }
|
||||
};
|
||||
};
|
||||
|
||||
if (graphModule.testIds) {
|
||||
for each (var testId in graphModule.testIds) {
|
||||
// log ("working with testId: " + testId);
|
||||
Tinderbox.requestDataSetFor (testId[0], makeCallback(graphModule, randomColor(), testId[1]));
|
||||
}
|
||||
}
|
||||
else {
|
||||
// log ("working with standard, single testId");
|
||||
Tinderbox.requestDataSetFor (graphModule.testId, makeCallback(graphModule, graphModule.color));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function onDataLoadChanged() {
|
||||
log ("loadchanged");
|
||||
if (getElement("load-days-radio").checked) {
|
||||
var dval = new Number(getElement("load-days-entry").value);
|
||||
log ("dval", dval);
|
||||
if (dval <= 0) {
|
||||
//getElement("load-days-entry").style.background-color = "red";
|
||||
return;
|
||||
} else {
|
||||
//getElement("load-days-entry").style.background-color = "inherit";
|
||||
}
|
||||
|
||||
var d2 = Math.ceil(Date.now() / 1000);
|
||||
d2 = (d2 - (d2 % ONE_DAY_SECONDS)) + ONE_DAY_SECONDS;
|
||||
var d1 = Math.floor(d2 - (dval * ONE_DAY_SECONDS));
|
||||
log ("drange", d1, d2);
|
||||
|
||||
Tinderbox.defaultLoadRange = [d1, d2];
|
||||
gCurrentLoadRange = [d1, d2];
|
||||
} else {
|
||||
Tinderbox.defaultLoadRange = null;
|
||||
gCurrentLoadRange = null;
|
||||
}
|
||||
|
||||
Tinderbox.clearValueDataSets();
|
||||
|
||||
// hack, reset colors
|
||||
randomColorBias = 0;
|
||||
}
|
||||
|
||||
function onExtraDataLoadChanged() {
|
||||
log ("loadchanged");
|
||||
Tinderbox.defaultLoadRange = null;
|
||||
gCurrentLoadRange = null;
|
||||
|
||||
// hack, reset colors
|
||||
randomColorBias = 0;
|
||||
}
|
||||
|
||||
|
||||
function onDiscreteDataLoadChanged() {
|
||||
log ("loadchanged");
|
||||
Tinderbox.defaultLoadRange = null;
|
||||
gCurrentLoadRange = null;
|
||||
|
||||
// hack, reset colors
|
||||
randomColorBias = 0;
|
||||
}
|
||||
|
||||
function findGraphModule(testId) {
|
||||
for each (var gm in GraphFormModules) {
|
||||
if (gm.testId == testId)
|
||||
return gm;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function updateDumpToCsv() {
|
||||
var ds = "?"
|
||||
prefix = ""
|
||||
for each (var gm in GraphFormModules) {
|
||||
ds += prefix + gm.getDumpString();
|
||||
prefix = "&"
|
||||
}
|
||||
log ("ds");
|
||||
getElement("dumptocsv").href = "http://" + document.location.host + "/dumpdata.cgi" + ds;
|
||||
}
|
||||
|
||||
function updateLinkToThis() {
|
||||
var qs = "";
|
||||
|
||||
qs += SmallPerfGraph.getQueryString("sp");
|
||||
qs += "&";
|
||||
qs += BigPerfGraph.getQueryString("bp");
|
||||
|
||||
if (graphType == CONTINUOUS_GRAPH) {
|
||||
var ctr = 1;
|
||||
for each (var gm in GraphFormModules) {
|
||||
qs += "&" + gm.getQueryString("m" + ctr);
|
||||
ctr++;
|
||||
}
|
||||
}
|
||||
else {
|
||||
qs += "&";
|
||||
qs += "name=" + GraphFormModules[0].name;
|
||||
for each (var gm in GraphFormModules) {
|
||||
qs += gm.getQueryString("m");
|
||||
}
|
||||
}
|
||||
|
||||
getElement("linktothis").href = document.location.pathname + "#" + qs;
|
||||
}
|
||||
|
||||
function handleHash(hash) {
|
||||
var qsdata = {};
|
||||
for each (var s in hash.substring(1).split("&")) {
|
||||
var q = s.split("=");
|
||||
qsdata[q[0]] = q[1];
|
||||
}
|
||||
|
||||
if (graphType == CONTINUOUS_GRAPH) {
|
||||
var ctr = 1;
|
||||
while (("m" + ctr + "tid") in qsdata) {
|
||||
var prefix = "m" + ctr;
|
||||
addGraphForm({testid: qsdata[prefix + "tid"],
|
||||
average: qsdata[prefix + "avg"]});
|
||||
ctr++;
|
||||
}
|
||||
}
|
||||
else {
|
||||
var ctr=1;
|
||||
testids = [];
|
||||
while (("m" + ctr + "tid") in qsdata) {
|
||||
var prefix = "m" + ctr;
|
||||
testids.push(Number(qsdata[prefix + "tid"]));
|
||||
ctr++;
|
||||
}
|
||||
// log("qsdata[name] " + qsdata["name"]);
|
||||
addDiscreteGraphForm(testids, qsdata["name"]);
|
||||
}
|
||||
|
||||
SmallPerfGraph.handleQueryStringData("sp", qsdata);
|
||||
BigPerfGraph.handleQueryStringData("bp", qsdata);
|
||||
|
||||
var tstart = new Number(qsdata["spstart"]);
|
||||
var tend = new Number(qsdata["spend"]);
|
||||
|
||||
//Tinderbox.defaultLoadRange = [tstart, tend];
|
||||
|
||||
if (graphType == CONTINUOUS_GRAPH) {
|
||||
Tinderbox.requestTestList(function (tests) {
|
||||
setTimeout (onGraph, 0); // let the other handlers do their thing
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function graphInitial() {
|
||||
GraphFormModules[0].addedInitialInfo.unsubscribeAll();
|
||||
Tinderbox.requestTestList(null, null, null, null, function (tests) {
|
||||
setTimeout(onGraph, 0);
|
||||
});
|
||||
}
|
||||
|
||||
function showStatus(s) {
|
||||
replaceChildNodes("status", s);
|
||||
}
|
||||
|
||||
function showLoadingAnimation(message) {
|
||||
//log("starting loading animation: " + message);
|
||||
td = new SPAN();
|
||||
el = new IMG({ src: "js/img/Throbber-small.gif"});
|
||||
appendChildNodes(td, el);
|
||||
appendChildNodes(td, " loading: " + message + " ");
|
||||
replaceChildNodes("loading", td);
|
||||
}
|
||||
|
||||
function clearLoadingAnimation() {
|
||||
//log("ending loading animation");
|
||||
replaceChildNodes("loading", null);
|
||||
}
|
||||
|
||||
function showGraphList(s) {
|
||||
replaceChildNodes("graph-label-list",null);
|
||||
// log("s: " +s);
|
||||
var tbl = new TABLE({});
|
||||
var tbl_tr = new TR();
|
||||
appendChildNodes(tbl_tr, new TD(""));
|
||||
appendChildNodes(tbl_tr, new TD("avg"));
|
||||
appendChildNodes(tbl_tr, new TD("max"));
|
||||
appendChildNodes(tbl_tr, new TD("min"));
|
||||
appendChildNodes(tbl_tr, new TD("test name"));
|
||||
appendChildNodes(tbl, tbl_tr);
|
||||
for each (var ds in s) {
|
||||
var tbl_tr = new TR();
|
||||
var rstring = ds.stats + " ";
|
||||
var colorDiv = new DIV({ id: "whee", style: "display: inline; border: 1px solid black; height: 15; " +
|
||||
"padding-right: 15; vertical-align: middle; margin: 3px;" });
|
||||
colorDiv.style.backgroundColor = colorToRgbString(ds.color);
|
||||
// log("ds.stats" + ds.stats);
|
||||
appendChildNodes(tbl_tr, colorDiv);
|
||||
for each (var val in ds.stats) {
|
||||
appendChildNodes(tbl_tr, new TD(val.toFixed(2)));
|
||||
}
|
||||
appendChildNodes(tbl, tbl_tr);
|
||||
appendChildNodes(tbl_tr, new TD(ds.title));
|
||||
}
|
||||
appendChildNodes("graph-label-list", tbl);
|
||||
if (s.length == GraphFormModules[0].testIds.length) {
|
||||
clearLoadingAnimation();
|
||||
}
|
||||
//replaceChildNodes("graph-label-list",rstring);
|
||||
}
|
||||
|
||||
/* Get some pre-set colors in for the first 5 graphs, thens start randomly generating stuff */
|
||||
var presetColorIndex = 0;
|
||||
var presetColors = [
|
||||
[0.0, 0.0, 0.7, 1.0],
|
||||
[0.0, 0.5, 0.0, 1.0],
|
||||
[0.7, 0.0, 0.0, 1.0],
|
||||
[0.7, 0.0, 0.7, 1.0],
|
||||
[0.0, 0.7, 0.7, 1.0]
|
||||
];
|
||||
|
||||
var randomColorBias = 0;
|
||||
function randomColor() {
|
||||
if (presetColorIndex < presetColors.length) {
|
||||
return presetColors[presetColorIndex++];
|
||||
}
|
||||
|
||||
var col = [
|
||||
(Math.random()*0.5) + ((randomColorBias==0) ? 0.5 : 0.2),
|
||||
(Math.random()*0.5) + ((randomColorBias==1) ? 0.5 : 0.2),
|
||||
(Math.random()*0.5) + ((randomColorBias==2) ? 0.5 : 0.2),
|
||||
1.0
|
||||
];
|
||||
randomColorBias++;
|
||||
if (randomColorBias == 3)
|
||||
randomColorBias = 0;
|
||||
|
||||
return col;
|
||||
}
|
||||
|
||||
function lighterColor(col) {
|
||||
return [
|
||||
Math.min(0.85, col[0] * 1.2),
|
||||
Math.min(0.85, col[1] * 1.2),
|
||||
Math.min(0.85, col[2] * 1.2),
|
||||
col[3]
|
||||
];
|
||||
}
|
||||
|
||||
function colorToRgbString(col) {
|
||||
// log ("in colorToRgbString");
|
||||
if (col[3] < 1) {
|
||||
return "rgba("
|
||||
+ Math.floor(col[0]*255) + ","
|
||||
+ Math.floor(col[1]*255) + ","
|
||||
+ Math.floor(col[2]*255) + ","
|
||||
+ col[3]
|
||||
+ ")";
|
||||
}
|
||||
return "rgb("
|
||||
+ Math.floor(col[0]*255) + ","
|
||||
+ Math.floor(col[1]*255) + ","
|
||||
+ Math.floor(col[2]*255) + ")";
|
||||
}
|
||||
|
Before Width: | Height: | Size: 825 B |
|
Before Width: | Height: | Size: 256 B |
|
Before Width: | Height: | Size: 144 B |
|
Before Width: | Height: | Size: 156 B |
@@ -1,637 +0,0 @@
|
||||
/***
|
||||
|
||||
MochiKit.Async 1.3.1
|
||||
|
||||
See <http://mochikit.com/> for documentation, downloads, license, etc.
|
||||
|
||||
(c) 2005 Bob Ippolito. All rights Reserved.
|
||||
|
||||
***/
|
||||
|
||||
if (typeof(dojo) != 'undefined') {
|
||||
dojo.provide("MochiKit.Async");
|
||||
dojo.require("MochiKit.Base");
|
||||
}
|
||||
if (typeof(JSAN) != 'undefined') {
|
||||
JSAN.use("MochiKit.Base", []);
|
||||
}
|
||||
|
||||
try {
|
||||
if (typeof(MochiKit.Base) == 'undefined') {
|
||||
throw "";
|
||||
}
|
||||
} catch (e) {
|
||||
throw "MochiKit.Async depends on MochiKit.Base!";
|
||||
}
|
||||
|
||||
if (typeof(MochiKit.Async) == 'undefined') {
|
||||
MochiKit.Async = {};
|
||||
}
|
||||
|
||||
MochiKit.Async.NAME = "MochiKit.Async";
|
||||
MochiKit.Async.VERSION = "1.3.1";
|
||||
MochiKit.Async.__repr__ = function () {
|
||||
return "[" + this.NAME + " " + this.VERSION + "]";
|
||||
};
|
||||
MochiKit.Async.toString = function () {
|
||||
return this.__repr__();
|
||||
};
|
||||
|
||||
MochiKit.Async.Deferred = function (/* optional */ canceller) {
|
||||
this.chain = [];
|
||||
this.id = this._nextId();
|
||||
this.fired = -1;
|
||||
this.paused = 0;
|
||||
this.results = [null, null];
|
||||
this.canceller = canceller;
|
||||
this.silentlyCancelled = false;
|
||||
this.chained = false;
|
||||
};
|
||||
|
||||
MochiKit.Async.Deferred.prototype = {
|
||||
repr: function () {
|
||||
var state;
|
||||
if (this.fired == -1) {
|
||||
state = 'unfired';
|
||||
} else if (this.fired === 0) {
|
||||
state = 'success';
|
||||
} else {
|
||||
state = 'error';
|
||||
}
|
||||
return 'Deferred(' + this.id + ', ' + state + ')';
|
||||
},
|
||||
|
||||
toString: MochiKit.Base.forwardCall("repr"),
|
||||
|
||||
_nextId: MochiKit.Base.counter(),
|
||||
|
||||
cancel: function () {
|
||||
var self = MochiKit.Async;
|
||||
if (this.fired == -1) {
|
||||
if (this.canceller) {
|
||||
this.canceller(this);
|
||||
} else {
|
||||
this.silentlyCancelled = true;
|
||||
}
|
||||
if (this.fired == -1) {
|
||||
this.errback(new self.CancelledError(this));
|
||||
}
|
||||
} else if ((this.fired === 0) && (this.results[0] instanceof self.Deferred)) {
|
||||
this.results[0].cancel();
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
_pause: function () {
|
||||
/***
|
||||
|
||||
Used internally to signal that it's waiting on another Deferred
|
||||
|
||||
***/
|
||||
this.paused++;
|
||||
},
|
||||
|
||||
_unpause: function () {
|
||||
/***
|
||||
|
||||
Used internally to signal that it's no longer waiting on another
|
||||
Deferred.
|
||||
|
||||
***/
|
||||
this.paused--;
|
||||
if ((this.paused === 0) && (this.fired >= 0)) {
|
||||
this._fire();
|
||||
}
|
||||
},
|
||||
|
||||
_continue: function (res) {
|
||||
/***
|
||||
|
||||
Used internally when a dependent deferred fires.
|
||||
|
||||
***/
|
||||
this._resback(res);
|
||||
this._unpause();
|
||||
},
|
||||
|
||||
_resback: function (res) {
|
||||
/***
|
||||
|
||||
The primitive that means either callback or errback
|
||||
|
||||
***/
|
||||
this.fired = ((res instanceof Error) ? 1 : 0);
|
||||
this.results[this.fired] = res;
|
||||
this._fire();
|
||||
},
|
||||
|
||||
_check: function () {
|
||||
if (this.fired != -1) {
|
||||
if (!this.silentlyCancelled) {
|
||||
throw new MochiKit.Async.AlreadyCalledError(this);
|
||||
}
|
||||
this.silentlyCancelled = false;
|
||||
return;
|
||||
}
|
||||
},
|
||||
|
||||
callback: function (res) {
|
||||
this._check();
|
||||
if (res instanceof MochiKit.Async.Deferred) {
|
||||
throw new Error("Deferred instances can only be chained if they are the result of a callback");
|
||||
}
|
||||
this._resback(res);
|
||||
},
|
||||
|
||||
errback: function (res) {
|
||||
this._check();
|
||||
var self = MochiKit.Async;
|
||||
if (res instanceof self.Deferred) {
|
||||
throw new Error("Deferred instances can only be chained if they are the result of a callback");
|
||||
}
|
||||
if (!(res instanceof Error)) {
|
||||
res = new self.GenericError(res);
|
||||
}
|
||||
this._resback(res);
|
||||
},
|
||||
|
||||
addBoth: function (fn) {
|
||||
if (arguments.length > 1) {
|
||||
fn = MochiKit.Base.partial.apply(null, arguments);
|
||||
}
|
||||
return this.addCallbacks(fn, fn);
|
||||
},
|
||||
|
||||
addCallback: function (fn) {
|
||||
if (arguments.length > 1) {
|
||||
fn = MochiKit.Base.partial.apply(null, arguments);
|
||||
}
|
||||
return this.addCallbacks(fn, null);
|
||||
},
|
||||
|
||||
addErrback: function (fn) {
|
||||
if (arguments.length > 1) {
|
||||
fn = MochiKit.Base.partial.apply(null, arguments);
|
||||
}
|
||||
return this.addCallbacks(null, fn);
|
||||
},
|
||||
|
||||
addCallbacks: function (cb, eb) {
|
||||
if (this.chained) {
|
||||
throw new Error("Chained Deferreds can not be re-used");
|
||||
}
|
||||
this.chain.push([cb, eb]);
|
||||
if (this.fired >= 0) {
|
||||
this._fire();
|
||||
}
|
||||
return this;
|
||||
},
|
||||
|
||||
_fire: function () {
|
||||
/***
|
||||
|
||||
Used internally to exhaust the callback sequence when a result
|
||||
is available.
|
||||
|
||||
***/
|
||||
var chain = this.chain;
|
||||
var fired = this.fired;
|
||||
var res = this.results[fired];
|
||||
var self = this;
|
||||
var cb = null;
|
||||
while (chain.length > 0 && this.paused === 0) {
|
||||
// Array
|
||||
var pair = chain.shift();
|
||||
var f = pair[fired];
|
||||
if (f === null) {
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
res = f(res);
|
||||
fired = ((res instanceof Error) ? 1 : 0);
|
||||
if (res instanceof MochiKit.Async.Deferred) {
|
||||
cb = function (res) {
|
||||
self._continue(res);
|
||||
};
|
||||
this._pause();
|
||||
}
|
||||
} catch (err) {
|
||||
fired = 1;
|
||||
if (!(err instanceof Error)) {
|
||||
err = new MochiKit.Async.GenericError(err);
|
||||
}
|
||||
res = err;
|
||||
}
|
||||
}
|
||||
this.fired = fired;
|
||||
this.results[fired] = res;
|
||||
if (cb && this.paused) {
|
||||
// this is for "tail recursion" in case the dependent deferred
|
||||
// is already fired
|
||||
res.addBoth(cb);
|
||||
res.chained = true;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
MochiKit.Base.update(MochiKit.Async, {
|
||||
evalJSONRequest: function (/* req */) {
|
||||
return eval('(' + arguments[0].responseText + ')');
|
||||
},
|
||||
|
||||
succeed: function (/* optional */result) {
|
||||
var d = new MochiKit.Async.Deferred();
|
||||
d.callback.apply(d, arguments);
|
||||
return d;
|
||||
},
|
||||
|
||||
fail: function (/* optional */result) {
|
||||
var d = new MochiKit.Async.Deferred();
|
||||
d.errback.apply(d, arguments);
|
||||
return d;
|
||||
},
|
||||
|
||||
getXMLHttpRequest: function () {
|
||||
var self = arguments.callee;
|
||||
if (!self.XMLHttpRequest) {
|
||||
var tryThese = [
|
||||
function () { return new XMLHttpRequest(); },
|
||||
function () { return new ActiveXObject('Msxml2.XMLHTTP'); },
|
||||
function () { return new ActiveXObject('Microsoft.XMLHTTP'); },
|
||||
function () { return new ActiveXObject('Msxml2.XMLHTTP.4.0'); },
|
||||
function () {
|
||||
throw new MochiKit.Async.BrowserComplianceError("Browser does not support XMLHttpRequest");
|
||||
}
|
||||
];
|
||||
for (var i = 0; i < tryThese.length; i++) {
|
||||
var func = tryThese[i];
|
||||
try {
|
||||
self.XMLHttpRequest = func;
|
||||
return func();
|
||||
} catch (e) {
|
||||
// pass
|
||||
}
|
||||
}
|
||||
}
|
||||
return self.XMLHttpRequest();
|
||||
},
|
||||
|
||||
_nothing: function () {},
|
||||
|
||||
_xhr_onreadystatechange: function (d) {
|
||||
// MochiKit.Logging.logDebug('this.readyState', this.readyState);
|
||||
if (this.readyState == 4) {
|
||||
// IE SUCKS
|
||||
try {
|
||||
this.onreadystatechange = null;
|
||||
} catch (e) {
|
||||
try {
|
||||
this.onreadystatechange = MochiKit.Async._nothing;
|
||||
} catch (e) {
|
||||
}
|
||||
}
|
||||
var status = null;
|
||||
try {
|
||||
status = this.status;
|
||||
if (!status && MochiKit.Base.isNotEmpty(this.responseText)) {
|
||||
// 0 or undefined seems to mean cached or local
|
||||
status = 304;
|
||||
}
|
||||
} catch (e) {
|
||||
// pass
|
||||
// MochiKit.Logging.logDebug('error getting status?', repr(items(e)));
|
||||
}
|
||||
// 200 is OK, 304 is NOT_MODIFIED
|
||||
if (status == 200 || status == 304) { // OK
|
||||
d.callback(this);
|
||||
} else {
|
||||
var err = new MochiKit.Async.XMLHttpRequestError(this, "Request failed");
|
||||
if (err.number) {
|
||||
// XXX: This seems to happen on page change
|
||||
d.errback(err);
|
||||
} else {
|
||||
// XXX: this seems to happen when the server is unreachable
|
||||
d.errback(err);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
_xhr_canceller: function (req) {
|
||||
// IE SUCKS
|
||||
try {
|
||||
req.onreadystatechange = null;
|
||||
} catch (e) {
|
||||
try {
|
||||
req.onreadystatechange = MochiKit.Async._nothing;
|
||||
} catch (e) {
|
||||
}
|
||||
}
|
||||
req.abort();
|
||||
},
|
||||
|
||||
|
||||
sendXMLHttpRequest: function (req, /* optional */ sendContent) {
|
||||
if (typeof(sendContent) == "undefined" || sendContent === null) {
|
||||
sendContent = "";
|
||||
}
|
||||
|
||||
var m = MochiKit.Base;
|
||||
var self = MochiKit.Async;
|
||||
var d = new self.Deferred(m.partial(self._xhr_canceller, req));
|
||||
|
||||
try {
|
||||
req.onreadystatechange = m.bind(self._xhr_onreadystatechange,
|
||||
req, d);
|
||||
req.send(sendContent);
|
||||
} catch (e) {
|
||||
try {
|
||||
req.onreadystatechange = null;
|
||||
} catch (ignore) {
|
||||
// pass
|
||||
}
|
||||
d.errback(e);
|
||||
}
|
||||
|
||||
return d;
|
||||
|
||||
},
|
||||
|
||||
doSimpleXMLHttpRequest: function (url/*, ...*/) {
|
||||
var self = MochiKit.Async;
|
||||
var req = self.getXMLHttpRequest();
|
||||
if (arguments.length > 1) {
|
||||
var m = MochiKit.Base;
|
||||
var qs = m.queryString.apply(null, m.extend(null, arguments, 1));
|
||||
if (qs) {
|
||||
url += "?" + qs;
|
||||
}
|
||||
}
|
||||
req.open("GET", url, true);
|
||||
return self.sendXMLHttpRequest(req);
|
||||
},
|
||||
|
||||
loadJSONDoc: function (url) {
|
||||
var self = MochiKit.Async;
|
||||
var d = self.doSimpleXMLHttpRequest.apply(self, arguments);
|
||||
d = d.addCallback(self.evalJSONRequest);
|
||||
return d;
|
||||
},
|
||||
|
||||
wait: function (seconds, /* optional */value) {
|
||||
var d = new MochiKit.Async.Deferred();
|
||||
var m = MochiKit.Base;
|
||||
if (typeof(value) != 'undefined') {
|
||||
d.addCallback(function () { return value; });
|
||||
}
|
||||
var timeout = setTimeout(
|
||||
m.bind("callback", d),
|
||||
Math.floor(seconds * 1000));
|
||||
d.canceller = function () {
|
||||
try {
|
||||
clearTimeout(timeout);
|
||||
} catch (e) {
|
||||
// pass
|
||||
}
|
||||
};
|
||||
return d;
|
||||
},
|
||||
|
||||
callLater: function (seconds, func) {
|
||||
var m = MochiKit.Base;
|
||||
var pfunc = m.partial.apply(m, m.extend(null, arguments, 1));
|
||||
return MochiKit.Async.wait(seconds).addCallback(
|
||||
function (res) { return pfunc(); }
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
MochiKit.Async.DeferredLock = function () {
|
||||
this.waiting = [];
|
||||
this.locked = false;
|
||||
this.id = this._nextId();
|
||||
};
|
||||
|
||||
MochiKit.Async.DeferredLock.prototype = {
|
||||
__class__: MochiKit.Async.DeferredLock,
|
||||
acquire: function () {
|
||||
d = new MochiKit.Async.Deferred();
|
||||
if (this.locked) {
|
||||
this.waiting.push(d);
|
||||
} else {
|
||||
this.locked = true;
|
||||
d.callback(this);
|
||||
}
|
||||
return d;
|
||||
},
|
||||
release: function () {
|
||||
if (!this.locked) {
|
||||
throw TypeError("Tried to release an unlocked DeferredLock");
|
||||
}
|
||||
this.locked = false;
|
||||
if (this.waiting.length > 0) {
|
||||
this.locked = true;
|
||||
this.waiting.shift().callback(this);
|
||||
}
|
||||
},
|
||||
_nextId: MochiKit.Base.counter(),
|
||||
repr: function () {
|
||||
var state;
|
||||
if (this.locked) {
|
||||
state = 'locked, ' + this.waiting.length + ' waiting';
|
||||
} else {
|
||||
state = 'unlocked';
|
||||
}
|
||||
return 'DeferredLock(' + this.id + ', ' + state + ')';
|
||||
},
|
||||
toString: MochiKit.Base.forwardCall("repr")
|
||||
|
||||
};
|
||||
|
||||
MochiKit.Async.DeferredList = function (list, /* optional */fireOnOneCallback, fireOnOneErrback, consumeErrors, canceller) {
|
||||
this.list = list;
|
||||
this.resultList = new Array(this.list.length);
|
||||
|
||||
// Deferred init
|
||||
this.chain = [];
|
||||
this.id = this._nextId();
|
||||
this.fired = -1;
|
||||
this.paused = 0;
|
||||
this.results = [null, null];
|
||||
this.canceller = canceller;
|
||||
this.silentlyCancelled = false;
|
||||
|
||||
if (this.list.length === 0 && !fireOnOneCallback) {
|
||||
this.callback(this.resultList);
|
||||
}
|
||||
|
||||
this.finishedCount = 0;
|
||||
this.fireOnOneCallback = fireOnOneCallback;
|
||||
this.fireOnOneErrback = fireOnOneErrback;
|
||||
this.consumeErrors = consumeErrors;
|
||||
|
||||
var index = 0;
|
||||
MochiKit.Base.map(MochiKit.Base.bind(function (d) {
|
||||
d.addCallback(MochiKit.Base.bind(this._cbDeferred, this), index, true);
|
||||
d.addErrback(MochiKit.Base.bind(this._cbDeferred, this), index, false);
|
||||
index += 1;
|
||||
}, this), this.list);
|
||||
};
|
||||
|
||||
MochiKit.Base.update(MochiKit.Async.DeferredList.prototype,
|
||||
MochiKit.Async.Deferred.prototype);
|
||||
|
||||
MochiKit.Base.update(MochiKit.Async.DeferredList.prototype, {
|
||||
_cbDeferred: function (index, succeeded, result) {
|
||||
this.resultList[index] = [succeeded, result];
|
||||
this.finishedCount += 1;
|
||||
if (this.fired !== 0) {
|
||||
if (succeeded && this.fireOnOneCallback) {
|
||||
this.callback([index, result]);
|
||||
} else if (!succeeded && this.fireOnOneErrback) {
|
||||
this.errback(result);
|
||||
} else if (this.finishedCount == this.list.length) {
|
||||
this.callback(this.resultList);
|
||||
}
|
||||
}
|
||||
if (!succeeded && this.consumeErrors) {
|
||||
result = null;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
});
|
||||
|
||||
MochiKit.Async.gatherResults = function (deferredList) {
|
||||
var d = new MochiKit.Async.DeferredList(deferredList, false, true, false);
|
||||
d.addCallback(function (results) {
|
||||
var ret = [];
|
||||
for (var i = 0; i < results.length; i++) {
|
||||
ret.push(results[i][1]);
|
||||
}
|
||||
return ret;
|
||||
});
|
||||
return d;
|
||||
};
|
||||
|
||||
MochiKit.Async.maybeDeferred = function (func) {
|
||||
var self = MochiKit.Async;
|
||||
var result;
|
||||
try {
|
||||
var r = func.apply(null, MochiKit.Base.extend([], arguments, 1));
|
||||
if (r instanceof self.Deferred) {
|
||||
result = r;
|
||||
} else if (r instanceof Error) {
|
||||
result = self.fail(r);
|
||||
} else {
|
||||
result = self.succeed(r);
|
||||
}
|
||||
} catch (e) {
|
||||
result = self.fail(e);
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
|
||||
MochiKit.Async.EXPORT = [
|
||||
"AlreadyCalledError",
|
||||
"CancelledError",
|
||||
"BrowserComplianceError",
|
||||
"GenericError",
|
||||
"XMLHttpRequestError",
|
||||
"Deferred",
|
||||
"succeed",
|
||||
"fail",
|
||||
"getXMLHttpRequest",
|
||||
"doSimpleXMLHttpRequest",
|
||||
"loadJSONDoc",
|
||||
"wait",
|
||||
"callLater",
|
||||
"sendXMLHttpRequest",
|
||||
"DeferredLock",
|
||||
"DeferredList",
|
||||
"gatherResults",
|
||||
"maybeDeferred"
|
||||
];
|
||||
|
||||
MochiKit.Async.EXPORT_OK = [
|
||||
"evalJSONRequest"
|
||||
];
|
||||
|
||||
MochiKit.Async.__new__ = function () {
|
||||
var m = MochiKit.Base;
|
||||
var ne = m.partial(m._newNamedError, this);
|
||||
ne("AlreadyCalledError",
|
||||
function (deferred) {
|
||||
/***
|
||||
|
||||
Raised by the Deferred if callback or errback happens
|
||||
after it was already fired.
|
||||
|
||||
***/
|
||||
this.deferred = deferred;
|
||||
}
|
||||
);
|
||||
|
||||
ne("CancelledError",
|
||||
function (deferred) {
|
||||
/***
|
||||
|
||||
Raised by the Deferred cancellation mechanism.
|
||||
|
||||
***/
|
||||
this.deferred = deferred;
|
||||
}
|
||||
);
|
||||
|
||||
ne("BrowserComplianceError",
|
||||
function (msg) {
|
||||
/***
|
||||
|
||||
Raised when the JavaScript runtime is not capable of performing
|
||||
the given function. Technically, this should really never be
|
||||
raised because a non-conforming JavaScript runtime probably
|
||||
isn't going to support exceptions in the first place.
|
||||
|
||||
***/
|
||||
this.message = msg;
|
||||
}
|
||||
);
|
||||
|
||||
ne("GenericError",
|
||||
function (msg) {
|
||||
this.message = msg;
|
||||
}
|
||||
);
|
||||
|
||||
ne("XMLHttpRequestError",
|
||||
function (req, msg) {
|
||||
/***
|
||||
|
||||
Raised when an XMLHttpRequest does not complete for any reason.
|
||||
|
||||
***/
|
||||
this.req = req;
|
||||
this.message = msg;
|
||||
try {
|
||||
// Strange but true that this can raise in some cases.
|
||||
this.number = req.status;
|
||||
} catch (e) {
|
||||
// pass
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
this.EXPORT_TAGS = {
|
||||
":common": this.EXPORT,
|
||||
":all": m.concat(this.EXPORT, this.EXPORT_OK)
|
||||
};
|
||||
|
||||
m.nameFunctions(this);
|
||||
|
||||
};
|
||||
|
||||
MochiKit.Async.__new__();
|
||||
|
||||
MochiKit.Base._exportSymbols(this, MochiKit.Async);
|
||||
@@ -1,825 +0,0 @@
|
||||
/***
|
||||
|
||||
MochiKit.Color 1.3.1
|
||||
|
||||
See <http://mochikit.com/> for documentation, downloads, license, etc.
|
||||
|
||||
(c) 2005 Bob Ippolito and others. All rights Reserved.
|
||||
|
||||
***/
|
||||
|
||||
if (typeof(dojo) != 'undefined') {
|
||||
dojo.provide('MochiKit.Color');
|
||||
dojo.require('MochiKit.Base');
|
||||
}
|
||||
|
||||
if (typeof(JSAN) != 'undefined') {
|
||||
JSAN.use("MochiKit.Base", []);
|
||||
}
|
||||
|
||||
try {
|
||||
if (typeof(MochiKit.Base) == 'undefined') {
|
||||
throw "";
|
||||
}
|
||||
} catch (e) {
|
||||
throw "MochiKit.Color depends on MochiKit.Base";
|
||||
}
|
||||
|
||||
if (typeof(MochiKit.Color) == "undefined") {
|
||||
MochiKit.Color = {};
|
||||
}
|
||||
|
||||
MochiKit.Color.NAME = "MochiKit.Color";
|
||||
MochiKit.Color.VERSION = "1.3.1";
|
||||
|
||||
MochiKit.Color.__repr__ = function () {
|
||||
return "[" + this.NAME + " " + this.VERSION + "]";
|
||||
};
|
||||
|
||||
MochiKit.Color.toString = function () {
|
||||
return this.__repr__();
|
||||
};
|
||||
|
||||
|
||||
MochiKit.Color.Color = function (red, green, blue, alpha) {
|
||||
if (typeof(alpha) == 'undefined' || alpha === null) {
|
||||
alpha = 1.0;
|
||||
}
|
||||
this.rgb = {
|
||||
r: red,
|
||||
g: green,
|
||||
b: blue,
|
||||
a: alpha
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
// Prototype methods
|
||||
MochiKit.Color.Color.prototype = {
|
||||
|
||||
__class__: MochiKit.Color.Color,
|
||||
|
||||
colorWithAlpha: function (alpha) {
|
||||
var rgb = this.rgb;
|
||||
var m = MochiKit.Color;
|
||||
return m.Color.fromRGB(rgb.r, rgb.g, rgb.b, alpha);
|
||||
},
|
||||
|
||||
colorWithHue: function (hue) {
|
||||
// get an HSL model, and set the new hue...
|
||||
var hsl = this.asHSL();
|
||||
hsl.h = hue;
|
||||
var m = MochiKit.Color;
|
||||
// convert back to RGB...
|
||||
return m.Color.fromHSL(hsl);
|
||||
},
|
||||
|
||||
colorWithSaturation: function (saturation) {
|
||||
// get an HSL model, and set the new hue...
|
||||
var hsl = this.asHSL();
|
||||
hsl.s = saturation;
|
||||
var m = MochiKit.Color;
|
||||
// convert back to RGB...
|
||||
return m.Color.fromHSL(hsl);
|
||||
},
|
||||
|
||||
colorWithLightness: function (lightness) {
|
||||
// get an HSL model, and set the new hue...
|
||||
var hsl = this.asHSL();
|
||||
hsl.l = lightness;
|
||||
var m = MochiKit.Color;
|
||||
// convert back to RGB...
|
||||
return m.Color.fromHSL(hsl);
|
||||
},
|
||||
|
||||
darkerColorWithLevel: function (level) {
|
||||
var hsl = this.asHSL();
|
||||
hsl.l = Math.max(hsl.l - level, 0);
|
||||
var m = MochiKit.Color;
|
||||
return m.Color.fromHSL(hsl);
|
||||
},
|
||||
|
||||
lighterColorWithLevel: function (level) {
|
||||
var hsl = this.asHSL();
|
||||
hsl.l = Math.min(hsl.l + level, 1);
|
||||
var m = MochiKit.Color;
|
||||
return m.Color.fromHSL(hsl);
|
||||
},
|
||||
|
||||
blendedColor: function (other, /* optional */ fraction) {
|
||||
if (typeof(fraction) == 'undefined' || fraction === null) {
|
||||
fraction = 0.5;
|
||||
}
|
||||
var sf = 1.0 - fraction;
|
||||
var s = this.rgb;
|
||||
var d = other.rgb;
|
||||
var df = fraction;
|
||||
return MochiKit.Color.Color.fromRGB(
|
||||
(s.r * sf) + (d.r * df),
|
||||
(s.g * sf) + (d.g * df),
|
||||
(s.b * sf) + (d.b * df),
|
||||
(s.a * sf) + (d.a * df)
|
||||
);
|
||||
},
|
||||
|
||||
compareRGB: function (other) {
|
||||
var a = this.asRGB();
|
||||
var b = other.asRGB();
|
||||
return MochiKit.Base.compare(
|
||||
[a.r, a.g, a.b, a.a],
|
||||
[b.r, b.g, b.b, b.a]
|
||||
);
|
||||
},
|
||||
|
||||
isLight: function () {
|
||||
return this.asHSL().b > 0.5;
|
||||
},
|
||||
|
||||
isDark: function () {
|
||||
return (!this.isLight());
|
||||
},
|
||||
|
||||
toHSLString: function () {
|
||||
var c = this.asHSL();
|
||||
var ccc = MochiKit.Color.clampColorComponent;
|
||||
var rval = this._hslString;
|
||||
if (!rval) {
|
||||
var mid = (
|
||||
ccc(c.h, 360).toFixed(0)
|
||||
+ "," + ccc(c.s, 100).toPrecision(4) + "%"
|
||||
+ "," + ccc(c.l, 100).toPrecision(4) + "%"
|
||||
);
|
||||
var a = c.a;
|
||||
if (a >= 1) {
|
||||
a = 1;
|
||||
rval = "hsl(" + mid + ")";
|
||||
} else {
|
||||
if (a <= 0) {
|
||||
a = 0;
|
||||
}
|
||||
rval = "hsla(" + mid + "," + a + ")";
|
||||
}
|
||||
this._hslString = rval;
|
||||
}
|
||||
return rval;
|
||||
},
|
||||
|
||||
toRGBString: function () {
|
||||
var c = this.rgb;
|
||||
var ccc = MochiKit.Color.clampColorComponent;
|
||||
var rval = this._rgbString;
|
||||
if (!rval) {
|
||||
var mid = (
|
||||
ccc(c.r, 255).toFixed(0)
|
||||
+ "," + ccc(c.g, 255).toFixed(0)
|
||||
+ "," + ccc(c.b, 255).toFixed(0)
|
||||
);
|
||||
if (c.a != 1) {
|
||||
rval = "rgba(" + mid + "," + c.a + ")";
|
||||
} else {
|
||||
rval = "rgb(" + mid + ")";
|
||||
}
|
||||
this._rgbString = rval;
|
||||
}
|
||||
return rval;
|
||||
},
|
||||
|
||||
asRGB: function () {
|
||||
return MochiKit.Base.clone(this.rgb);
|
||||
},
|
||||
|
||||
toHexString: function () {
|
||||
var m = MochiKit.Color;
|
||||
var c = this.rgb;
|
||||
var ccc = MochiKit.Color.clampColorComponent;
|
||||
var rval = this._hexString;
|
||||
if (!rval) {
|
||||
rval = ("#" +
|
||||
m.toColorPart(ccc(c.r, 255)) +
|
||||
m.toColorPart(ccc(c.g, 255)) +
|
||||
m.toColorPart(ccc(c.b, 255))
|
||||
);
|
||||
this._hexString = rval;
|
||||
}
|
||||
return rval;
|
||||
},
|
||||
|
||||
asHSV: function () {
|
||||
var hsv = this.hsv;
|
||||
var c = this.rgb;
|
||||
if (typeof(hsv) == 'undefined' || hsv === null) {
|
||||
hsv = MochiKit.Color.rgbToHSV(this.rgb);
|
||||
this.hsv = hsv;
|
||||
}
|
||||
return MochiKit.Base.clone(hsv);
|
||||
},
|
||||
|
||||
asHSL: function () {
|
||||
var hsl = this.hsl;
|
||||
var c = this.rgb;
|
||||
if (typeof(hsl) == 'undefined' || hsl === null) {
|
||||
hsl = MochiKit.Color.rgbToHSL(this.rgb);
|
||||
this.hsl = hsl;
|
||||
}
|
||||
return MochiKit.Base.clone(hsl);
|
||||
},
|
||||
|
||||
toString: function () {
|
||||
return this.toRGBString();
|
||||
},
|
||||
|
||||
repr: function () {
|
||||
var c = this.rgb;
|
||||
var col = [c.r, c.g, c.b, c.a];
|
||||
return this.__class__.NAME + "(" + col.join(", ") + ")";
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
// Constructor methods
|
||||
MochiKit.Base.update(MochiKit.Color.Color, {
|
||||
fromRGB: function (red, green, blue, alpha) {
|
||||
// designated initializer
|
||||
var Color = MochiKit.Color.Color;
|
||||
if (arguments.length == 1) {
|
||||
var rgb = red;
|
||||
red = rgb.r;
|
||||
green = rgb.g;
|
||||
blue = rgb.b;
|
||||
if (typeof(rgb.a) == 'undefined') {
|
||||
alpha = undefined;
|
||||
} else {
|
||||
alpha = rgb.a;
|
||||
}
|
||||
}
|
||||
return new Color(red, green, blue, alpha);
|
||||
},
|
||||
|
||||
fromHSL: function (hue, saturation, lightness, alpha) {
|
||||
var m = MochiKit.Color;
|
||||
return m.Color.fromRGB(m.hslToRGB.apply(m, arguments));
|
||||
},
|
||||
|
||||
fromHSV: function (hue, saturation, value, alpha) {
|
||||
var m = MochiKit.Color;
|
||||
return m.Color.fromRGB(m.hsvToRGB.apply(m, arguments));
|
||||
},
|
||||
|
||||
fromName: function (name) {
|
||||
var Color = MochiKit.Color.Color;
|
||||
// Opera 9 seems to "quote" named colors(?!)
|
||||
if (name.charAt(0) == '"') {
|
||||
name = name.substr(1, name.length - 2);
|
||||
}
|
||||
var htmlColor = Color._namedColors[name.toLowerCase()];
|
||||
if (typeof(htmlColor) == 'string') {
|
||||
return Color.fromHexString(htmlColor);
|
||||
} else if (name == "transparent") {
|
||||
return Color.transparentColor();
|
||||
}
|
||||
return null;
|
||||
},
|
||||
|
||||
fromString: function (colorString) {
|
||||
var self = MochiKit.Color.Color;
|
||||
var three = colorString.substr(0, 3);
|
||||
if (three == "rgb") {
|
||||
return self.fromRGBString(colorString);
|
||||
} else if (three == "hsl") {
|
||||
return self.fromHSLString(colorString);
|
||||
} else if (colorString.charAt(0) == "#") {
|
||||
return self.fromHexString(colorString);
|
||||
}
|
||||
return self.fromName(colorString);
|
||||
},
|
||||
|
||||
|
||||
fromHexString: function (hexCode) {
|
||||
if (hexCode.charAt(0) == '#') {
|
||||
hexCode = hexCode.substring(1);
|
||||
}
|
||||
var components = [];
|
||||
var i, hex;
|
||||
if (hexCode.length == 3) {
|
||||
for (i = 0; i < 3; i++) {
|
||||
hex = hexCode.substr(i, 1);
|
||||
components.push(parseInt(hex + hex, 16) / 255.0);
|
||||
}
|
||||
} else {
|
||||
for (i = 0; i < 6; i += 2) {
|
||||
hex = hexCode.substr(i, 2);
|
||||
components.push(parseInt(hex, 16) / 255.0);
|
||||
}
|
||||
}
|
||||
var Color = MochiKit.Color.Color;
|
||||
return Color.fromRGB.apply(Color, components);
|
||||
},
|
||||
|
||||
|
||||
_fromColorString: function (pre, method, scales, colorCode) {
|
||||
// parses either HSL or RGB
|
||||
if (colorCode.indexOf(pre) === 0) {
|
||||
colorCode = colorCode.substring(colorCode.indexOf("(", 3) + 1, colorCode.length - 1);
|
||||
}
|
||||
var colorChunks = colorCode.split(/\s*,\s*/);
|
||||
var colorFloats = [];
|
||||
for (var i = 0; i < colorChunks.length; i++) {
|
||||
var c = colorChunks[i];
|
||||
var val;
|
||||
var three = c.substring(c.length - 3);
|
||||
if (c.charAt(c.length - 1) == '%') {
|
||||
val = 0.01 * parseFloat(c.substring(0, c.length - 1));
|
||||
} else if (three == "deg") {
|
||||
val = parseFloat(c) / 360.0;
|
||||
} else if (three == "rad") {
|
||||
val = parseFloat(c) / (Math.PI * 2);
|
||||
} else {
|
||||
val = scales[i] * parseFloat(c);
|
||||
}
|
||||
colorFloats.push(val);
|
||||
}
|
||||
return this[method].apply(this, colorFloats);
|
||||
},
|
||||
|
||||
fromComputedStyle: function (elem, style, mozillaEquivalentCSS) {
|
||||
var d = MochiKit.DOM;
|
||||
var cls = MochiKit.Color.Color;
|
||||
for (elem = d.getElement(elem); elem; elem = elem.parentNode) {
|
||||
var actualColor = d.computedStyle.apply(d, arguments);
|
||||
if (!actualColor) {
|
||||
continue;
|
||||
}
|
||||
var color = cls.fromString(actualColor);
|
||||
if (!color) {
|
||||
break;
|
||||
}
|
||||
if (color.asRGB().a > 0) {
|
||||
return color;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
},
|
||||
|
||||
fromBackground: function (elem) {
|
||||
var cls = MochiKit.Color.Color;
|
||||
return cls.fromComputedStyle(
|
||||
elem, "backgroundColor", "background-color") || cls.whiteColor();
|
||||
},
|
||||
|
||||
fromText: function (elem) {
|
||||
var cls = MochiKit.Color.Color;
|
||||
return cls.fromComputedStyle(
|
||||
elem, "color", "color") || cls.blackColor();
|
||||
},
|
||||
|
||||
namedColors: function () {
|
||||
return MochiKit.Base.clone(MochiKit.Color.Color._namedColors);
|
||||
}
|
||||
});
|
||||
|
||||
// Module level functions
|
||||
MochiKit.Base.update(MochiKit.Color, {
|
||||
clampColorComponent: function (v, scale) {
|
||||
v *= scale;
|
||||
if (v < 0) {
|
||||
return 0;
|
||||
} else if (v > scale) {
|
||||
return scale;
|
||||
} else {
|
||||
return v;
|
||||
}
|
||||
},
|
||||
|
||||
_hslValue: function (n1, n2, hue) {
|
||||
if (hue > 6.0) {
|
||||
hue -= 6.0;
|
||||
} else if (hue < 0.0) {
|
||||
hue += 6.0;
|
||||
}
|
||||
var val;
|
||||
if (hue < 1.0) {
|
||||
val = n1 + (n2 - n1) * hue;
|
||||
} else if (hue < 3.0) {
|
||||
val = n2;
|
||||
} else if (hue < 4.0) {
|
||||
val = n1 + (n2 - n1) * (4.0 - hue);
|
||||
} else {
|
||||
val = n1;
|
||||
}
|
||||
return val;
|
||||
},
|
||||
|
||||
hsvToRGB: function (hue, saturation, value, alpha) {
|
||||
if (arguments.length == 1) {
|
||||
var hsv = hue;
|
||||
hue = hsv.h;
|
||||
saturation = hsv.s;
|
||||
value = hsv.v;
|
||||
alpha = hsv.a;
|
||||
}
|
||||
var red;
|
||||
var green;
|
||||
var blue;
|
||||
if (saturation === 0) {
|
||||
red = 0;
|
||||
green = 0;
|
||||
blue = 0;
|
||||
} else {
|
||||
var i = Math.floor(hue * 6);
|
||||
var f = (hue * 6) - i;
|
||||
var p = value * (1 - saturation);
|
||||
var q = value * (1 - (saturation * f));
|
||||
var t = value * (1 - (saturation * (1 - f)));
|
||||
switch (i) {
|
||||
case 1: red = q; green = value; blue = p; break;
|
||||
case 2: red = p; green = value; blue = t; break;
|
||||
case 3: red = p; green = q; blue = value; break;
|
||||
case 4: red = t; green = p; blue = value; break;
|
||||
case 5: red = value; green = p; blue = q; break;
|
||||
case 6: // fall through
|
||||
case 0: red = value; green = t; blue = p; break;
|
||||
}
|
||||
}
|
||||
return {
|
||||
r: red,
|
||||
g: green,
|
||||
b: blue,
|
||||
a: alpha
|
||||
};
|
||||
},
|
||||
|
||||
hslToRGB: function (hue, saturation, lightness, alpha) {
|
||||
if (arguments.length == 1) {
|
||||
var hsl = hue;
|
||||
hue = hsl.h;
|
||||
saturation = hsl.s;
|
||||
lightness = hsl.l;
|
||||
alpha = hsl.a;
|
||||
}
|
||||
var red;
|
||||
var green;
|
||||
var blue;
|
||||
if (saturation === 0) {
|
||||
red = lightness;
|
||||
green = lightness;
|
||||
blue = lightness;
|
||||
} else {
|
||||
var m2;
|
||||
if (lightness <= 0.5) {
|
||||
m2 = lightness * (1.0 + saturation);
|
||||
} else {
|
||||
m2 = lightness + saturation - (lightness * saturation);
|
||||
}
|
||||
var m1 = (2.0 * lightness) - m2;
|
||||
var f = MochiKit.Color._hslValue;
|
||||
var h6 = hue * 6.0;
|
||||
red = f(m1, m2, h6 + 2);
|
||||
green = f(m1, m2, h6);
|
||||
blue = f(m1, m2, h6 - 2);
|
||||
}
|
||||
return {
|
||||
r: red,
|
||||
g: green,
|
||||
b: blue,
|
||||
a: alpha
|
||||
};
|
||||
},
|
||||
|
||||
rgbToHSV: function (red, green, blue, alpha) {
|
||||
if (arguments.length == 1) {
|
||||
var rgb = red;
|
||||
red = rgb.r;
|
||||
green = rgb.g;
|
||||
blue = rgb.b;
|
||||
alpha = rgb.a;
|
||||
}
|
||||
var max = Math.max(Math.max(red, green), blue);
|
||||
var min = Math.min(Math.min(red, green), blue);
|
||||
var hue;
|
||||
var saturation;
|
||||
var value = max;
|
||||
if (min == max) {
|
||||
hue = 0;
|
||||
saturation = 0;
|
||||
} else {
|
||||
var delta = (max - min);
|
||||
saturation = delta / max;
|
||||
|
||||
if (red == max) {
|
||||
hue = (green - blue) / delta;
|
||||
} else if (green == max) {
|
||||
hue = 2 + ((blue - red) / delta);
|
||||
} else {
|
||||
hue = 4 + ((red - green) / delta);
|
||||
}
|
||||
hue /= 6;
|
||||
if (hue < 0) {
|
||||
hue += 1;
|
||||
}
|
||||
if (hue > 1) {
|
||||
hue -= 1;
|
||||
}
|
||||
}
|
||||
return {
|
||||
h: hue,
|
||||
s: saturation,
|
||||
v: value,
|
||||
a: alpha
|
||||
};
|
||||
},
|
||||
|
||||
rgbToHSL: function (red, green, blue, alpha) {
|
||||
if (arguments.length == 1) {
|
||||
var rgb = red;
|
||||
red = rgb.r;
|
||||
green = rgb.g;
|
||||
blue = rgb.b;
|
||||
alpha = rgb.a;
|
||||
}
|
||||
var max = Math.max(red, Math.max(green, blue));
|
||||
var min = Math.min(red, Math.min(green, blue));
|
||||
var hue;
|
||||
var saturation;
|
||||
var lightness = (max + min) / 2.0;
|
||||
var delta = max - min;
|
||||
if (delta === 0) {
|
||||
hue = 0;
|
||||
saturation = 0;
|
||||
} else {
|
||||
if (lightness <= 0.5) {
|
||||
saturation = delta / (max + min);
|
||||
} else {
|
||||
saturation = delta / (2 - max - min);
|
||||
}
|
||||
if (red == max) {
|
||||
hue = (green - blue) / delta;
|
||||
} else if (green == max) {
|
||||
hue = 2 + ((blue - red) / delta);
|
||||
} else {
|
||||
hue = 4 + ((red - green) / delta);
|
||||
}
|
||||
hue /= 6;
|
||||
if (hue < 0) {
|
||||
hue += 1;
|
||||
}
|
||||
if (hue > 1) {
|
||||
hue -= 1;
|
||||
}
|
||||
|
||||
}
|
||||
return {
|
||||
h: hue,
|
||||
s: saturation,
|
||||
l: lightness,
|
||||
a: alpha
|
||||
};
|
||||
},
|
||||
|
||||
toColorPart: function (num) {
|
||||
num = Math.round(num);
|
||||
var digits = num.toString(16);
|
||||
if (num < 16) {
|
||||
return '0' + digits;
|
||||
}
|
||||
return digits;
|
||||
},
|
||||
|
||||
__new__: function () {
|
||||
var m = MochiKit.Base;
|
||||
this.Color.fromRGBString = m.bind(
|
||||
this.Color._fromColorString, this.Color, "rgb", "fromRGB",
|
||||
[1.0/255.0, 1.0/255.0, 1.0/255.0, 1]
|
||||
);
|
||||
this.Color.fromHSLString = m.bind(
|
||||
this.Color._fromColorString, this.Color, "hsl", "fromHSL",
|
||||
[1.0/360.0, 0.01, 0.01, 1]
|
||||
);
|
||||
|
||||
var third = 1.0 / 3.0;
|
||||
var colors = {
|
||||
// NSColor colors plus transparent
|
||||
black: [0, 0, 0],
|
||||
blue: [0, 0, 1],
|
||||
brown: [0.6, 0.4, 0.2],
|
||||
cyan: [0, 1, 1],
|
||||
darkGray: [third, third, third],
|
||||
gray: [0.5, 0.5, 0.5],
|
||||
green: [0, 1, 0],
|
||||
lightGray: [2 * third, 2 * third, 2 * third],
|
||||
magenta: [1, 0, 1],
|
||||
orange: [1, 0.5, 0],
|
||||
purple: [0.5, 0, 0.5],
|
||||
red: [1, 0, 0],
|
||||
transparent: [0, 0, 0, 0],
|
||||
white: [1, 1, 1],
|
||||
yellow: [1, 1, 0]
|
||||
};
|
||||
|
||||
var makeColor = function (name, r, g, b, a) {
|
||||
var rval = this.fromRGB(r, g, b, a);
|
||||
this[name] = function () { return rval; };
|
||||
return rval;
|
||||
};
|
||||
|
||||
for (var k in colors) {
|
||||
var name = k + "Color";
|
||||
var bindArgs = m.concat(
|
||||
[makeColor, this.Color, name],
|
||||
colors[k]
|
||||
);
|
||||
this.Color[name] = m.bind.apply(null, bindArgs);
|
||||
}
|
||||
|
||||
var isColor = function () {
|
||||
for (var i = 0; i < arguments.length; i++) {
|
||||
if (!(arguments[i] instanceof Color)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
var compareColor = function (a, b) {
|
||||
return a.compareRGB(b);
|
||||
};
|
||||
|
||||
m.nameFunctions(this);
|
||||
|
||||
m.registerComparator(this.Color.NAME, isColor, compareColor);
|
||||
|
||||
this.EXPORT_TAGS = {
|
||||
":common": this.EXPORT,
|
||||
":all": m.concat(this.EXPORT, this.EXPORT_OK)
|
||||
};
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
MochiKit.Color.EXPORT = [
|
||||
"Color"
|
||||
];
|
||||
|
||||
MochiKit.Color.EXPORT_OK = [
|
||||
"clampColorComponent",
|
||||
"rgbToHSL",
|
||||
"hslToRGB",
|
||||
"rgbToHSV",
|
||||
"hsvToRGB",
|
||||
"toColorPart"
|
||||
];
|
||||
|
||||
MochiKit.Color.__new__();
|
||||
|
||||
MochiKit.Base._exportSymbols(this, MochiKit.Color);
|
||||
|
||||
// Full table of css3 X11 colors <http://www.w3.org/TR/css3-color/#X11COLORS>
|
||||
|
||||
MochiKit.Color.Color._namedColors = {
|
||||
aliceblue: "#f0f8ff",
|
||||
antiquewhite: "#faebd7",
|
||||
aqua: "#00ffff",
|
||||
aquamarine: "#7fffd4",
|
||||
azure: "#f0ffff",
|
||||
beige: "#f5f5dc",
|
||||
bisque: "#ffe4c4",
|
||||
black: "#000000",
|
||||
blanchedalmond: "#ffebcd",
|
||||
blue: "#0000ff",
|
||||
blueviolet: "#8a2be2",
|
||||
brown: "#a52a2a",
|
||||
burlywood: "#deb887",
|
||||
cadetblue: "#5f9ea0",
|
||||
chartreuse: "#7fff00",
|
||||
chocolate: "#d2691e",
|
||||
coral: "#ff7f50",
|
||||
cornflowerblue: "#6495ed",
|
||||
cornsilk: "#fff8dc",
|
||||
crimson: "#dc143c",
|
||||
cyan: "#00ffff",
|
||||
darkblue: "#00008b",
|
||||
darkcyan: "#008b8b",
|
||||
darkgoldenrod: "#b8860b",
|
||||
darkgray: "#a9a9a9",
|
||||
darkgreen: "#006400",
|
||||
darkgrey: "#a9a9a9",
|
||||
darkkhaki: "#bdb76b",
|
||||
darkmagenta: "#8b008b",
|
||||
darkolivegreen: "#556b2f",
|
||||
darkorange: "#ff8c00",
|
||||
darkorchid: "#9932cc",
|
||||
darkred: "#8b0000",
|
||||
darksalmon: "#e9967a",
|
||||
darkseagreen: "#8fbc8f",
|
||||
darkslateblue: "#483d8b",
|
||||
darkslategray: "#2f4f4f",
|
||||
darkslategrey: "#2f4f4f",
|
||||
darkturquoise: "#00ced1",
|
||||
darkviolet: "#9400d3",
|
||||
deeppink: "#ff1493",
|
||||
deepskyblue: "#00bfff",
|
||||
dimgray: "#696969",
|
||||
dimgrey: "#696969",
|
||||
dodgerblue: "#1e90ff",
|
||||
firebrick: "#b22222",
|
||||
floralwhite: "#fffaf0",
|
||||
forestgreen: "#228b22",
|
||||
fuchsia: "#ff00ff",
|
||||
gainsboro: "#dcdcdc",
|
||||
ghostwhite: "#f8f8ff",
|
||||
gold: "#ffd700",
|
||||
goldenrod: "#daa520",
|
||||
gray: "#808080",
|
||||
green: "#008000",
|
||||
greenyellow: "#adff2f",
|
||||
grey: "#808080",
|
||||
honeydew: "#f0fff0",
|
||||
hotpink: "#ff69b4",
|
||||
indianred: "#cd5c5c",
|
||||
indigo: "#4b0082",
|
||||
ivory: "#fffff0",
|
||||
khaki: "#f0e68c",
|
||||
lavender: "#e6e6fa",
|
||||
lavenderblush: "#fff0f5",
|
||||
lawngreen: "#7cfc00",
|
||||
lemonchiffon: "#fffacd",
|
||||
lightblue: "#add8e6",
|
||||
lightcoral: "#f08080",
|
||||
lightcyan: "#e0ffff",
|
||||
lightgoldenrodyellow: "#fafad2",
|
||||
lightgray: "#d3d3d3",
|
||||
lightgreen: "#90ee90",
|
||||
lightgrey: "#d3d3d3",
|
||||
lightpink: "#ffb6c1",
|
||||
lightsalmon: "#ffa07a",
|
||||
lightseagreen: "#20b2aa",
|
||||
lightskyblue: "#87cefa",
|
||||
lightslategray: "#778899",
|
||||
lightslategrey: "#778899",
|
||||
lightsteelblue: "#b0c4de",
|
||||
lightyellow: "#ffffe0",
|
||||
lime: "#00ff00",
|
||||
limegreen: "#32cd32",
|
||||
linen: "#faf0e6",
|
||||
magenta: "#ff00ff",
|
||||
maroon: "#800000",
|
||||
mediumaquamarine: "#66cdaa",
|
||||
mediumblue: "#0000cd",
|
||||
mediumorchid: "#ba55d3",
|
||||
mediumpurple: "#9370db",
|
||||
mediumseagreen: "#3cb371",
|
||||
mediumslateblue: "#7b68ee",
|
||||
mediumspringgreen: "#00fa9a",
|
||||
mediumturquoise: "#48d1cc",
|
||||
mediumvioletred: "#c71585",
|
||||
midnightblue: "#191970",
|
||||
mintcream: "#f5fffa",
|
||||
mistyrose: "#ffe4e1",
|
||||
moccasin: "#ffe4b5",
|
||||
navajowhite: "#ffdead",
|
||||
navy: "#000080",
|
||||
oldlace: "#fdf5e6",
|
||||
olive: "#808000",
|
||||
olivedrab: "#6b8e23",
|
||||
orange: "#ffa500",
|
||||
orangered: "#ff4500",
|
||||
orchid: "#da70d6",
|
||||
palegoldenrod: "#eee8aa",
|
||||
palegreen: "#98fb98",
|
||||
paleturquoise: "#afeeee",
|
||||
palevioletred: "#db7093",
|
||||
papayawhip: "#ffefd5",
|
||||
peachpuff: "#ffdab9",
|
||||
peru: "#cd853f",
|
||||
pink: "#ffc0cb",
|
||||
plum: "#dda0dd",
|
||||
powderblue: "#b0e0e6",
|
||||
purple: "#800080",
|
||||
red: "#ff0000",
|
||||
rosybrown: "#bc8f8f",
|
||||
royalblue: "#4169e1",
|
||||
saddlebrown: "#8b4513",
|
||||
salmon: "#fa8072",
|
||||
sandybrown: "#f4a460",
|
||||
seagreen: "#2e8b57",
|
||||
seashell: "#fff5ee",
|
||||
sienna: "#a0522d",
|
||||
silver: "#c0c0c0",
|
||||
skyblue: "#87ceeb",
|
||||
slateblue: "#6a5acd",
|
||||
slategray: "#708090",
|
||||
slategrey: "#708090",
|
||||
snow: "#fffafa",
|
||||
springgreen: "#00ff7f",
|
||||
steelblue: "#4682b4",
|
||||
tan: "#d2b48c",
|
||||
teal: "#008080",
|
||||
thistle: "#d8bfd8",
|
||||
tomato: "#ff6347",
|
||||
turquoise: "#40e0d0",
|
||||
violet: "#ee82ee",
|
||||
wheat: "#f5deb3",
|
||||
white: "#ffffff",
|
||||
whitesmoke: "#f5f5f5",
|
||||
yellow: "#ffff00",
|
||||
yellowgreen: "#9acd32"
|
||||
};
|
||||
@@ -1,208 +0,0 @@
|
||||
/***
|
||||
|
||||
MochiKit.DateTime 1.3.1
|
||||
|
||||
See <http://mochikit.com/> for documentation, downloads, license, etc.
|
||||
|
||||
(c) 2005 Bob Ippolito. All rights Reserved.
|
||||
|
||||
***/
|
||||
|
||||
if (typeof(dojo) != 'undefined') {
|
||||
dojo.provide('MochiKit.DateTime');
|
||||
}
|
||||
|
||||
if (typeof(MochiKit) == 'undefined') {
|
||||
MochiKit = {};
|
||||
}
|
||||
|
||||
if (typeof(MochiKit.DateTime) == 'undefined') {
|
||||
MochiKit.DateTime = {};
|
||||
}
|
||||
|
||||
MochiKit.DateTime.NAME = "MochiKit.DateTime";
|
||||
MochiKit.DateTime.VERSION = "1.3.1";
|
||||
MochiKit.DateTime.__repr__ = function () {
|
||||
return "[" + this.NAME + " " + this.VERSION + "]";
|
||||
};
|
||||
MochiKit.DateTime.toString = function () {
|
||||
return this.__repr__();
|
||||
};
|
||||
|
||||
MochiKit.DateTime.isoDate = function (str) {
|
||||
str = str + "";
|
||||
if (typeof(str) != "string" || str.length === 0) {
|
||||
return null;
|
||||
}
|
||||
var iso = str.split('-');
|
||||
if (iso.length === 0) {
|
||||
return null;
|
||||
}
|
||||
return new Date(iso[0], iso[1] - 1, iso[2]);
|
||||
};
|
||||
|
||||
MochiKit.DateTime._isoRegexp = /(\d{4,})(?:-(\d{1,2})(?:-(\d{1,2})(?:[T ](\d{1,2}):(\d{1,2})(?::(\d{1,2})(?:\.(\d+))?)?(?:(Z)|([+-])(\d{1,2})(?::(\d{1,2}))?)?)?)?)?/;
|
||||
|
||||
MochiKit.DateTime.isoTimestamp = function (str) {
|
||||
str = str + "";
|
||||
if (typeof(str) != "string" || str.length === 0) {
|
||||
return null;
|
||||
}
|
||||
var res = str.match(MochiKit.DateTime._isoRegexp);
|
||||
if (typeof(res) == "undefined" || res === null) {
|
||||
return null;
|
||||
}
|
||||
var year, month, day, hour, min, sec, msec;
|
||||
year = parseInt(res[1], 10);
|
||||
if (typeof(res[2]) == "undefined" || res[2] === '') {
|
||||
return new Date(year);
|
||||
}
|
||||
month = parseInt(res[2], 10) - 1;
|
||||
day = parseInt(res[3], 10);
|
||||
if (typeof(res[4]) == "undefined" || res[4] === '') {
|
||||
return new Date(year, month, day);
|
||||
}
|
||||
hour = parseInt(res[4], 10);
|
||||
min = parseInt(res[5], 10);
|
||||
sec = (typeof(res[6]) != "undefined" && res[6] !== '') ? parseInt(res[6], 10) : 0;
|
||||
if (typeof(res[7]) != "undefined" && res[7] !== '') {
|
||||
msec = Math.round(1000.0 * parseFloat("0." + res[7]));
|
||||
} else {
|
||||
msec = 0;
|
||||
}
|
||||
if ((typeof(res[8]) == "undefined" || res[8] === '') && (typeof(res[9]) == "undefined" || res[9] === '')) {
|
||||
return new Date(year, month, day, hour, min, sec, msec);
|
||||
}
|
||||
var ofs;
|
||||
if (typeof(res[9]) != "undefined" && res[9] !== '') {
|
||||
ofs = parseInt(res[10], 10) * 3600000;
|
||||
if (typeof(res[11]) != "undefined" && res[11] !== '') {
|
||||
ofs += parseInt(res[11], 10) * 60000;
|
||||
}
|
||||
if (res[9] == "-") {
|
||||
ofs = -ofs;
|
||||
}
|
||||
} else {
|
||||
ofs = 0;
|
||||
}
|
||||
return new Date(Date.UTC(year, month, day, hour, min, sec, msec) - ofs);
|
||||
};
|
||||
|
||||
MochiKit.DateTime.toISOTime = function (date, realISO/* = false */) {
|
||||
if (typeof(date) == "undefined" || date === null) {
|
||||
return null;
|
||||
}
|
||||
var hh = date.getHours();
|
||||
var mm = date.getMinutes();
|
||||
var ss = date.getSeconds();
|
||||
var lst = [
|
||||
((realISO && (hh < 10)) ? "0" + hh : hh),
|
||||
((mm < 10) ? "0" + mm : mm),
|
||||
((ss < 10) ? "0" + ss : ss)
|
||||
];
|
||||
return lst.join(":");
|
||||
};
|
||||
|
||||
MochiKit.DateTime.toISOTimestamp = function (date, realISO/* = false*/) {
|
||||
if (typeof(date) == "undefined" || date === null) {
|
||||
return null;
|
||||
}
|
||||
var sep = realISO ? "T" : " ";
|
||||
var foot = realISO ? "Z" : "";
|
||||
if (realISO) {
|
||||
date = new Date(date.getTime() + (date.getTimezoneOffset() * 60000));
|
||||
}
|
||||
return MochiKit.DateTime.toISODate(date) + sep + MochiKit.DateTime.toISOTime(date, realISO) + foot;
|
||||
};
|
||||
|
||||
MochiKit.DateTime.toISODate = function (date) {
|
||||
if (typeof(date) == "undefined" || date === null) {
|
||||
return null;
|
||||
}
|
||||
var _padTwo = MochiKit.DateTime._padTwo;
|
||||
return [
|
||||
date.getFullYear(),
|
||||
_padTwo(date.getMonth() + 1),
|
||||
_padTwo(date.getDate())
|
||||
].join("-");
|
||||
};
|
||||
|
||||
MochiKit.DateTime.americanDate = function (d) {
|
||||
d = d + "";
|
||||
if (typeof(d) != "string" || d.length === 0) {
|
||||
return null;
|
||||
}
|
||||
var a = d.split('/');
|
||||
return new Date(a[2], a[0] - 1, a[1]);
|
||||
};
|
||||
|
||||
MochiKit.DateTime._padTwo = function (n) {
|
||||
return (n > 9) ? n : "0" + n;
|
||||
};
|
||||
|
||||
MochiKit.DateTime.toPaddedAmericanDate = function (d) {
|
||||
if (typeof(d) == "undefined" || d === null) {
|
||||
return null;
|
||||
}
|
||||
var _padTwo = MochiKit.DateTime._padTwo;
|
||||
return [
|
||||
_padTwo(d.getMonth() + 1),
|
||||
_padTwo(d.getDate()),
|
||||
d.getFullYear()
|
||||
].join('/');
|
||||
};
|
||||
|
||||
MochiKit.DateTime.toAmericanDate = function (d) {
|
||||
if (typeof(d) == "undefined" || d === null) {
|
||||
return null;
|
||||
}
|
||||
return [d.getMonth() + 1, d.getDate(), d.getFullYear()].join('/');
|
||||
};
|
||||
|
||||
MochiKit.DateTime.EXPORT = [
|
||||
"isoDate",
|
||||
"isoTimestamp",
|
||||
"toISOTime",
|
||||
"toISOTimestamp",
|
||||
"toISODate",
|
||||
"americanDate",
|
||||
"toPaddedAmericanDate",
|
||||
"toAmericanDate"
|
||||
];
|
||||
|
||||
MochiKit.DateTime.EXPORT_OK = [];
|
||||
MochiKit.DateTime.EXPORT_TAGS = {
|
||||
":common": MochiKit.DateTime.EXPORT,
|
||||
":all": MochiKit.DateTime.EXPORT
|
||||
};
|
||||
|
||||
MochiKit.DateTime.__new__ = function () {
|
||||
// MochiKit.Base.nameFunctions(this);
|
||||
var base = this.NAME + ".";
|
||||
for (var k in this) {
|
||||
var o = this[k];
|
||||
if (typeof(o) == 'function' && typeof(o.NAME) == 'undefined') {
|
||||
try {
|
||||
o.NAME = base + k;
|
||||
} catch (e) {
|
||||
// pass
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
MochiKit.DateTime.__new__();
|
||||
|
||||
if (typeof(MochiKit.Base) != "undefined") {
|
||||
MochiKit.Base._exportSymbols(this, MochiKit.DateTime);
|
||||
} else {
|
||||
(function (globals, module) {
|
||||
if ((typeof(JSAN) == 'undefined' && typeof(dojo) == 'undefined')
|
||||
|| (typeof(MochiKit.__compat__) == 'boolean' && MochiKit.__compat__)) {
|
||||
var all = module.EXPORT_TAGS[":all"];
|
||||
for (var i = 0; i < all.length; i++) {
|
||||
globals[all[i]] = module[all[i]];
|
||||
}
|
||||
}
|
||||
})(this, MochiKit.DateTime);
|
||||
}
|
||||
@@ -1,294 +0,0 @@
|
||||
/***
|
||||
|
||||
MochiKit.Format 1.3.1
|
||||
|
||||
See <http://mochikit.com/> for documentation, downloads, license, etc.
|
||||
|
||||
(c) 2005 Bob Ippolito. All rights Reserved.
|
||||
|
||||
***/
|
||||
|
||||
if (typeof(dojo) != 'undefined') {
|
||||
dojo.provide('MochiKit.Format');
|
||||
}
|
||||
|
||||
if (typeof(MochiKit) == 'undefined') {
|
||||
MochiKit = {};
|
||||
}
|
||||
|
||||
if (typeof(MochiKit.Format) == 'undefined') {
|
||||
MochiKit.Format = {};
|
||||
}
|
||||
|
||||
MochiKit.Format.NAME = "MochiKit.Format";
|
||||
MochiKit.Format.VERSION = "1.3.1";
|
||||
MochiKit.Format.__repr__ = function () {
|
||||
return "[" + this.NAME + " " + this.VERSION + "]";
|
||||
};
|
||||
MochiKit.Format.toString = function () {
|
||||
return this.__repr__();
|
||||
};
|
||||
|
||||
MochiKit.Format._numberFormatter = function (placeholder, header, footer, locale, isPercent, precision, leadingZeros, separatorAt, trailingZeros) {
|
||||
return function (num) {
|
||||
num = parseFloat(num);
|
||||
if (typeof(num) == "undefined" || num === null || isNaN(num)) {
|
||||
return placeholder;
|
||||
}
|
||||
var curheader = header;
|
||||
var curfooter = footer;
|
||||
if (num < 0) {
|
||||
num = -num;
|
||||
} else {
|
||||
curheader = curheader.replace(/-/, "");
|
||||
}
|
||||
var me = arguments.callee;
|
||||
var fmt = MochiKit.Format.formatLocale(locale);
|
||||
if (isPercent) {
|
||||
num = num * 100.0;
|
||||
curfooter = fmt.percent + curfooter;
|
||||
}
|
||||
num = MochiKit.Format.roundToFixed(num, precision);
|
||||
var parts = num.split(/\./);
|
||||
var whole = parts[0];
|
||||
var frac = (parts.length == 1) ? "" : parts[1];
|
||||
var res = "";
|
||||
while (whole.length < leadingZeros) {
|
||||
whole = "0" + whole;
|
||||
}
|
||||
if (separatorAt) {
|
||||
while (whole.length > separatorAt) {
|
||||
var i = whole.length - separatorAt;
|
||||
//res = res + fmt.separator + whole.substring(i, whole.length);
|
||||
res = fmt.separator + whole.substring(i, whole.length) + res;
|
||||
whole = whole.substring(0, i);
|
||||
}
|
||||
}
|
||||
res = whole + res;
|
||||
if (precision > 0) {
|
||||
while (frac.length < trailingZeros) {
|
||||
frac = frac + "0";
|
||||
}
|
||||
res = res + fmt.decimal + frac;
|
||||
}
|
||||
return curheader + res + curfooter;
|
||||
};
|
||||
};
|
||||
|
||||
MochiKit.Format.numberFormatter = function (pattern, placeholder/* = "" */, locale/* = "default" */) {
|
||||
// http://java.sun.com/docs/books/tutorial/i18n/format/numberpattern.html
|
||||
// | 0 | leading or trailing zeros
|
||||
// | # | just the number
|
||||
// | , | separator
|
||||
// | . | decimal separator
|
||||
// | % | Multiply by 100 and format as percent
|
||||
if (typeof(placeholder) == "undefined") {
|
||||
placeholder = "";
|
||||
}
|
||||
var match = pattern.match(/((?:[0#]+,)?[0#]+)(?:\.([0#]+))?(%)?/);
|
||||
if (!match) {
|
||||
throw TypeError("Invalid pattern");
|
||||
}
|
||||
var header = pattern.substr(0, match.index);
|
||||
var footer = pattern.substr(match.index + match[0].length);
|
||||
if (header.search(/-/) == -1) {
|
||||
header = header + "-";
|
||||
}
|
||||
var whole = match[1];
|
||||
var frac = (typeof(match[2]) == "string" && match[2] != "") ? match[2] : "";
|
||||
var isPercent = (typeof(match[3]) == "string" && match[3] != "");
|
||||
var tmp = whole.split(/,/);
|
||||
var separatorAt;
|
||||
if (typeof(locale) == "undefined") {
|
||||
locale = "default";
|
||||
}
|
||||
if (tmp.length == 1) {
|
||||
separatorAt = null;
|
||||
} else {
|
||||
separatorAt = tmp[1].length;
|
||||
}
|
||||
var leadingZeros = whole.length - whole.replace(/0/g, "").length;
|
||||
var trailingZeros = frac.length - frac.replace(/0/g, "").length;
|
||||
var precision = frac.length;
|
||||
var rval = MochiKit.Format._numberFormatter(
|
||||
placeholder, header, footer, locale, isPercent, precision,
|
||||
leadingZeros, separatorAt, trailingZeros
|
||||
);
|
||||
var m = MochiKit.Base;
|
||||
if (m) {
|
||||
var fn = arguments.callee;
|
||||
var args = m.concat(arguments);
|
||||
rval.repr = function () {
|
||||
return [
|
||||
self.NAME,
|
||||
"(",
|
||||
map(m.repr, args).join(", "),
|
||||
")"
|
||||
].join("");
|
||||
};
|
||||
}
|
||||
return rval;
|
||||
};
|
||||
|
||||
MochiKit.Format.formatLocale = function (locale) {
|
||||
if (typeof(locale) == "undefined" || locale === null) {
|
||||
locale = "default";
|
||||
}
|
||||
if (typeof(locale) == "string") {
|
||||
var rval = MochiKit.Format.LOCALE[locale];
|
||||
if (typeof(rval) == "string") {
|
||||
rval = arguments.callee(rval);
|
||||
MochiKit.Format.LOCALE[locale] = rval;
|
||||
}
|
||||
return rval;
|
||||
} else {
|
||||
return locale;
|
||||
}
|
||||
};
|
||||
|
||||
MochiKit.Format.twoDigitAverage = function (numerator, denominator) {
|
||||
if (denominator) {
|
||||
var res = numerator / denominator;
|
||||
if (!isNaN(res)) {
|
||||
return MochiKit.Format.twoDigitFloat(numerator / denominator);
|
||||
}
|
||||
}
|
||||
return "0";
|
||||
};
|
||||
|
||||
MochiKit.Format.twoDigitFloat = function (someFloat) {
|
||||
var sign = (someFloat < 0 ? '-' : '');
|
||||
var s = Math.floor(Math.abs(someFloat) * 100).toString();
|
||||
if (s == '0') {
|
||||
return s;
|
||||
}
|
||||
if (s.length < 3) {
|
||||
while (s.charAt(s.length - 1) == '0') {
|
||||
s = s.substring(0, s.length - 1);
|
||||
}
|
||||
return sign + '0.' + s;
|
||||
}
|
||||
var head = sign + s.substring(0, s.length - 2);
|
||||
var tail = s.substring(s.length - 2, s.length);
|
||||
if (tail == '00') {
|
||||
return head;
|
||||
} else if (tail.charAt(1) == '0') {
|
||||
return head + '.' + tail.charAt(0);
|
||||
} else {
|
||||
return head + '.' + tail;
|
||||
}
|
||||
};
|
||||
|
||||
MochiKit.Format.lstrip = function (str, /* optional */chars) {
|
||||
str = str + "";
|
||||
if (typeof(str) != "string") {
|
||||
return null;
|
||||
}
|
||||
if (!chars) {
|
||||
return str.replace(/^\s+/, "");
|
||||
} else {
|
||||
return str.replace(new RegExp("^[" + chars + "]+"), "");
|
||||
}
|
||||
};
|
||||
|
||||
MochiKit.Format.rstrip = function (str, /* optional */chars) {
|
||||
str = str + "";
|
||||
if (typeof(str) != "string") {
|
||||
return null;
|
||||
}
|
||||
if (!chars) {
|
||||
return str.replace(/\s+$/, "");
|
||||
} else {
|
||||
return str.replace(new RegExp("[" + chars + "]+$"), "");
|
||||
}
|
||||
};
|
||||
|
||||
MochiKit.Format.strip = function (str, /* optional */chars) {
|
||||
var self = MochiKit.Format;
|
||||
return self.rstrip(self.lstrip(str, chars), chars);
|
||||
};
|
||||
|
||||
MochiKit.Format.truncToFixed = function (aNumber, precision) {
|
||||
aNumber = Math.floor(aNumber * Math.pow(10, precision));
|
||||
var res = (aNumber * Math.pow(10, -precision)).toFixed(precision);
|
||||
if (res.charAt(0) == ".") {
|
||||
res = "0" + res;
|
||||
}
|
||||
return res;
|
||||
};
|
||||
|
||||
MochiKit.Format.roundToFixed = function (aNumber, precision) {
|
||||
return MochiKit.Format.truncToFixed(
|
||||
aNumber + 0.5 * Math.pow(10, -precision),
|
||||
precision
|
||||
);
|
||||
};
|
||||
|
||||
MochiKit.Format.percentFormat = function (someFloat) {
|
||||
return MochiKit.Format.twoDigitFloat(100 * someFloat) + '%';
|
||||
};
|
||||
|
||||
MochiKit.Format.EXPORT = [
|
||||
"truncToFixed",
|
||||
"roundToFixed",
|
||||
"numberFormatter",
|
||||
"formatLocale",
|
||||
"twoDigitAverage",
|
||||
"twoDigitFloat",
|
||||
"percentFormat",
|
||||
"lstrip",
|
||||
"rstrip",
|
||||
"strip"
|
||||
];
|
||||
|
||||
MochiKit.Format.LOCALE = {
|
||||
en_US: {separator: ",", decimal: ".", percent: "%"},
|
||||
de_DE: {separator: ".", decimal: ",", percent: "%"},
|
||||
fr_FR: {separator: " ", decimal: ",", percent: "%"},
|
||||
"default": "en_US"
|
||||
};
|
||||
|
||||
MochiKit.Format.EXPORT_OK = [];
|
||||
MochiKit.Format.EXPORT_TAGS = {
|
||||
':all': MochiKit.Format.EXPORT,
|
||||
':common': MochiKit.Format.EXPORT
|
||||
};
|
||||
|
||||
MochiKit.Format.__new__ = function () {
|
||||
// MochiKit.Base.nameFunctions(this);
|
||||
var base = this.NAME + ".";
|
||||
var k, v, o;
|
||||
for (k in this.LOCALE) {
|
||||
o = this.LOCALE[k];
|
||||
if (typeof(o) == "object") {
|
||||
o.repr = function () { return this.NAME; };
|
||||
o.NAME = base + "LOCALE." + k;
|
||||
}
|
||||
}
|
||||
for (k in this) {
|
||||
o = this[k];
|
||||
if (typeof(o) == 'function' && typeof(o.NAME) == 'undefined') {
|
||||
try {
|
||||
o.NAME = base + k;
|
||||
} catch (e) {
|
||||
// pass
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
MochiKit.Format.__new__();
|
||||
|
||||
if (typeof(MochiKit.Base) != "undefined") {
|
||||
MochiKit.Base._exportSymbols(this, MochiKit.Format);
|
||||
} else {
|
||||
(function (globals, module) {
|
||||
if ((typeof(JSAN) == 'undefined' && typeof(dojo) == 'undefined')
|
||||
|| (typeof(MochiKit.__compat__) == 'boolean' && MochiKit.__compat__)) {
|
||||
var all = module.EXPORT_TAGS[":all"];
|
||||
for (var i = 0; i < all.length; i++) {
|
||||
globals[all[i]] = module[all[i]];
|
||||
}
|
||||
}
|
||||
})(this, MochiKit.Format);
|
||||
}
|
||||
@@ -1,789 +0,0 @@
|
||||
/***
|
||||
|
||||
MochiKit.Iter 1.3.1
|
||||
|
||||
See <http://mochikit.com/> for documentation, downloads, license, etc.
|
||||
|
||||
(c) 2005 Bob Ippolito. All rights Reserved.
|
||||
|
||||
***/
|
||||
if (typeof(dojo) != 'undefined') {
|
||||
dojo.provide('MochiKit.Iter');
|
||||
dojo.require('MochiKit.Base');
|
||||
}
|
||||
|
||||
if (typeof(JSAN) != 'undefined') {
|
||||
JSAN.use("MochiKit.Base", []);
|
||||
}
|
||||
|
||||
try {
|
||||
if (typeof(MochiKit.Base) == 'undefined') {
|
||||
throw "";
|
||||
}
|
||||
} catch (e) {
|
||||
throw "MochiKit.Iter depends on MochiKit.Base!";
|
||||
}
|
||||
|
||||
if (typeof(MochiKit.Iter) == 'undefined') {
|
||||
MochiKit.Iter = {};
|
||||
}
|
||||
|
||||
MochiKit.Iter.NAME = "MochiKit.Iter";
|
||||
MochiKit.Iter.VERSION = "1.3.1";
|
||||
MochiKit.Base.update(MochiKit.Iter, {
|
||||
__repr__: function () {
|
||||
return "[" + this.NAME + " " + this.VERSION + "]";
|
||||
},
|
||||
toString: function () {
|
||||
return this.__repr__();
|
||||
},
|
||||
|
||||
registerIteratorFactory: function (name, check, iterfactory, /* optional */ override) {
|
||||
MochiKit.Iter.iteratorRegistry.register(name, check, iterfactory, override);
|
||||
},
|
||||
|
||||
iter: function (iterable, /* optional */ sentinel) {
|
||||
var self = MochiKit.Iter;
|
||||
if (arguments.length == 2) {
|
||||
return self.takewhile(
|
||||
function (a) { return a != sentinel; },
|
||||
iterable
|
||||
);
|
||||
}
|
||||
if (typeof(iterable.next) == 'function') {
|
||||
return iterable;
|
||||
} else if (typeof(iterable.iter) == 'function') {
|
||||
return iterable.iter();
|
||||
}
|
||||
try {
|
||||
return self.iteratorRegistry.match(iterable);
|
||||
} catch (e) {
|
||||
var m = MochiKit.Base;
|
||||
if (e == m.NotFound) {
|
||||
e = new TypeError(typeof(iterable) + ": " + m.repr(iterable) + " is not iterable");
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
},
|
||||
|
||||
count: function (n) {
|
||||
if (!n) {
|
||||
n = 0;
|
||||
}
|
||||
var m = MochiKit.Base;
|
||||
return {
|
||||
repr: function () { return "count(" + n + ")"; },
|
||||
toString: m.forwardCall("repr"),
|
||||
next: m.counter(n)
|
||||
};
|
||||
},
|
||||
|
||||
cycle: function (p) {
|
||||
var self = MochiKit.Iter;
|
||||
var m = MochiKit.Base;
|
||||
var lst = [];
|
||||
var iterator = self.iter(p);
|
||||
return {
|
||||
repr: function () { return "cycle(...)"; },
|
||||
toString: m.forwardCall("repr"),
|
||||
next: function () {
|
||||
try {
|
||||
var rval = iterator.next();
|
||||
lst.push(rval);
|
||||
return rval;
|
||||
} catch (e) {
|
||||
if (e != self.StopIteration) {
|
||||
throw e;
|
||||
}
|
||||
if (lst.length === 0) {
|
||||
this.next = function () {
|
||||
throw self.StopIteration;
|
||||
};
|
||||
} else {
|
||||
var i = -1;
|
||||
this.next = function () {
|
||||
i = (i + 1) % lst.length;
|
||||
return lst[i];
|
||||
};
|
||||
}
|
||||
return this.next();
|
||||
}
|
||||
}
|
||||
};
|
||||
},
|
||||
|
||||
repeat: function (elem, /* optional */n) {
|
||||
var m = MochiKit.Base;
|
||||
if (typeof(n) == 'undefined') {
|
||||
return {
|
||||
repr: function () {
|
||||
return "repeat(" + m.repr(elem) + ")";
|
||||
},
|
||||
toString: m.forwardCall("repr"),
|
||||
next: function () {
|
||||
return elem;
|
||||
}
|
||||
};
|
||||
}
|
||||
return {
|
||||
repr: function () {
|
||||
return "repeat(" + m.repr(elem) + ", " + n + ")";
|
||||
},
|
||||
toString: m.forwardCall("repr"),
|
||||
next: function () {
|
||||
if (n <= 0) {
|
||||
throw MochiKit.Iter.StopIteration;
|
||||
}
|
||||
n -= 1;
|
||||
return elem;
|
||||
}
|
||||
};
|
||||
},
|
||||
|
||||
next: function (iterator) {
|
||||
return iterator.next();
|
||||
},
|
||||
|
||||
izip: function (p, q/*, ...*/) {
|
||||
var m = MochiKit.Base;
|
||||
var next = MochiKit.Iter.next;
|
||||
var iterables = m.map(iter, arguments);
|
||||
return {
|
||||
repr: function () { return "izip(...)"; },
|
||||
toString: m.forwardCall("repr"),
|
||||
next: function () { return m.map(next, iterables); }
|
||||
};
|
||||
},
|
||||
|
||||
ifilter: function (pred, seq) {
|
||||
var m = MochiKit.Base;
|
||||
seq = MochiKit.Iter.iter(seq);
|
||||
if (pred === null) {
|
||||
pred = m.operator.truth;
|
||||
}
|
||||
return {
|
||||
repr: function () { return "ifilter(...)"; },
|
||||
toString: m.forwardCall("repr"),
|
||||
next: function () {
|
||||
while (true) {
|
||||
var rval = seq.next();
|
||||
if (pred(rval)) {
|
||||
return rval;
|
||||
}
|
||||
}
|
||||
// mozilla warnings aren't too bright
|
||||
return undefined;
|
||||
}
|
||||
};
|
||||
},
|
||||
|
||||
ifilterfalse: function (pred, seq) {
|
||||
var m = MochiKit.Base;
|
||||
seq = MochiKit.Iter.iter(seq);
|
||||
if (pred === null) {
|
||||
pred = m.operator.truth;
|
||||
}
|
||||
return {
|
||||
repr: function () { return "ifilterfalse(...)"; },
|
||||
toString: m.forwardCall("repr"),
|
||||
next: function () {
|
||||
while (true) {
|
||||
var rval = seq.next();
|
||||
if (!pred(rval)) {
|
||||
return rval;
|
||||
}
|
||||
}
|
||||
// mozilla warnings aren't too bright
|
||||
return undefined;
|
||||
}
|
||||
};
|
||||
},
|
||||
|
||||
islice: function (seq/*, [start,] stop[, step] */) {
|
||||
var self = MochiKit.Iter;
|
||||
var m = MochiKit.Base;
|
||||
seq = self.iter(seq);
|
||||
var start = 0;
|
||||
var stop = 0;
|
||||
var step = 1;
|
||||
var i = -1;
|
||||
if (arguments.length == 2) {
|
||||
stop = arguments[1];
|
||||
} else if (arguments.length == 3) {
|
||||
start = arguments[1];
|
||||
stop = arguments[2];
|
||||
} else {
|
||||
start = arguments[1];
|
||||
stop = arguments[2];
|
||||
step = arguments[3];
|
||||
}
|
||||
return {
|
||||
repr: function () {
|
||||
return "islice(" + ["...", start, stop, step].join(", ") + ")";
|
||||
},
|
||||
toString: m.forwardCall("repr"),
|
||||
next: function () {
|
||||
var rval;
|
||||
while (i < start) {
|
||||
rval = seq.next();
|
||||
i++;
|
||||
}
|
||||
if (start >= stop) {
|
||||
throw self.StopIteration;
|
||||
}
|
||||
start += step;
|
||||
return rval;
|
||||
}
|
||||
};
|
||||
},
|
||||
|
||||
imap: function (fun, p, q/*, ...*/) {
|
||||
var m = MochiKit.Base;
|
||||
var self = MochiKit.Iter;
|
||||
var iterables = m.map(self.iter, m.extend(null, arguments, 1));
|
||||
var map = m.map;
|
||||
var next = self.next;
|
||||
return {
|
||||
repr: function () { return "imap(...)"; },
|
||||
toString: m.forwardCall("repr"),
|
||||
next: function () {
|
||||
return fun.apply(this, map(next, iterables));
|
||||
}
|
||||
};
|
||||
},
|
||||
|
||||
applymap: function (fun, seq, self) {
|
||||
seq = MochiKit.Iter.iter(seq);
|
||||
var m = MochiKit.Base;
|
||||
return {
|
||||
repr: function () { return "applymap(...)"; },
|
||||
toString: m.forwardCall("repr"),
|
||||
next: function () {
|
||||
return fun.apply(self, seq.next());
|
||||
}
|
||||
};
|
||||
},
|
||||
|
||||
chain: function (p, q/*, ...*/) {
|
||||
// dumb fast path
|
||||
var self = MochiKit.Iter;
|
||||
var m = MochiKit.Base;
|
||||
if (arguments.length == 1) {
|
||||
return self.iter(arguments[0]);
|
||||
}
|
||||
var argiter = m.map(self.iter, arguments);
|
||||
return {
|
||||
repr: function () { return "chain(...)"; },
|
||||
toString: m.forwardCall("repr"),
|
||||
next: function () {
|
||||
while (argiter.length > 1) {
|
||||
try {
|
||||
return argiter[0].next();
|
||||
} catch (e) {
|
||||
if (e != self.StopIteration) {
|
||||
throw e;
|
||||
}
|
||||
argiter.shift();
|
||||
}
|
||||
}
|
||||
if (argiter.length == 1) {
|
||||
// optimize last element
|
||||
var arg = argiter.shift();
|
||||
this.next = m.bind("next", arg);
|
||||
return this.next();
|
||||
}
|
||||
throw self.StopIteration;
|
||||
}
|
||||
};
|
||||
},
|
||||
|
||||
takewhile: function (pred, seq) {
|
||||
var self = MochiKit.Iter;
|
||||
seq = self.iter(seq);
|
||||
return {
|
||||
repr: function () { return "takewhile(...)"; },
|
||||
toString: MochiKit.Base.forwardCall("repr"),
|
||||
next: function () {
|
||||
var rval = seq.next();
|
||||
if (!pred(rval)) {
|
||||
this.next = function () {
|
||||
throw self.StopIteration;
|
||||
};
|
||||
this.next();
|
||||
}
|
||||
return rval;
|
||||
}
|
||||
};
|
||||
},
|
||||
|
||||
dropwhile: function (pred, seq) {
|
||||
seq = MochiKit.Iter.iter(seq);
|
||||
var m = MochiKit.Base;
|
||||
var bind = m.bind;
|
||||
return {
|
||||
"repr": function () { return "dropwhile(...)"; },
|
||||
"toString": m.forwardCall("repr"),
|
||||
"next": function () {
|
||||
while (true) {
|
||||
var rval = seq.next();
|
||||
if (!pred(rval)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
this.next = bind("next", seq);
|
||||
return rval;
|
||||
}
|
||||
};
|
||||
},
|
||||
|
||||
_tee: function (ident, sync, iterable) {
|
||||
sync.pos[ident] = -1;
|
||||
var m = MochiKit.Base;
|
||||
var listMin = m.listMin;
|
||||
return {
|
||||
repr: function () { return "tee(" + ident + ", ...)"; },
|
||||
toString: m.forwardCall("repr"),
|
||||
next: function () {
|
||||
var rval;
|
||||
var i = sync.pos[ident];
|
||||
|
||||
if (i == sync.max) {
|
||||
rval = iterable.next();
|
||||
sync.deque.push(rval);
|
||||
sync.max += 1;
|
||||
sync.pos[ident] += 1;
|
||||
} else {
|
||||
rval = sync.deque[i - sync.min];
|
||||
sync.pos[ident] += 1;
|
||||
if (i == sync.min && listMin(sync.pos) != sync.min) {
|
||||
sync.min += 1;
|
||||
sync.deque.shift();
|
||||
}
|
||||
}
|
||||
return rval;
|
||||
}
|
||||
};
|
||||
},
|
||||
|
||||
tee: function (iterable, n/* = 2 */) {
|
||||
var rval = [];
|
||||
var sync = {
|
||||
"pos": [],
|
||||
"deque": [],
|
||||
"max": -1,
|
||||
"min": -1
|
||||
};
|
||||
if (arguments.length == 1) {
|
||||
n = 2;
|
||||
}
|
||||
var self = MochiKit.Iter;
|
||||
iterable = self.iter(iterable);
|
||||
var _tee = self._tee;
|
||||
for (var i = 0; i < n; i++) {
|
||||
rval.push(_tee(i, sync, iterable));
|
||||
}
|
||||
return rval;
|
||||
},
|
||||
|
||||
list: function (iterable) {
|
||||
// Fast-path for Array and Array-like
|
||||
var m = MochiKit.Base;
|
||||
if (typeof(iterable.slice) == 'function') {
|
||||
return iterable.slice();
|
||||
} else if (m.isArrayLike(iterable)) {
|
||||
return m.concat(iterable);
|
||||
}
|
||||
|
||||
var self = MochiKit.Iter;
|
||||
iterable = self.iter(iterable);
|
||||
var rval = [];
|
||||
try {
|
||||
while (true) {
|
||||
rval.push(iterable.next());
|
||||
}
|
||||
} catch (e) {
|
||||
if (e != self.StopIteration) {
|
||||
throw e;
|
||||
}
|
||||
return rval;
|
||||
}
|
||||
// mozilla warnings aren't too bright
|
||||
return undefined;
|
||||
},
|
||||
|
||||
|
||||
reduce: function (fn, iterable, /* optional */initial) {
|
||||
var i = 0;
|
||||
var x = initial;
|
||||
var self = MochiKit.Iter;
|
||||
iterable = self.iter(iterable);
|
||||
if (arguments.length < 3) {
|
||||
try {
|
||||
x = iterable.next();
|
||||
} catch (e) {
|
||||
if (e == self.StopIteration) {
|
||||
e = new TypeError("reduce() of empty sequence with no initial value");
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
try {
|
||||
while (true) {
|
||||
x = fn(x, iterable.next());
|
||||
}
|
||||
} catch (e) {
|
||||
if (e != self.StopIteration) {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
return x;
|
||||
},
|
||||
|
||||
range: function (/* [start,] stop[, step] */) {
|
||||
var start = 0;
|
||||
var stop = 0;
|
||||
var step = 1;
|
||||
if (arguments.length == 1) {
|
||||
stop = arguments[0];
|
||||
} else if (arguments.length == 2) {
|
||||
start = arguments[0];
|
||||
stop = arguments[1];
|
||||
} else if (arguments.length == 3) {
|
||||
start = arguments[0];
|
||||
stop = arguments[1];
|
||||
step = arguments[2];
|
||||
} else {
|
||||
throw new TypeError("range() takes 1, 2, or 3 arguments!");
|
||||
}
|
||||
if (step === 0) {
|
||||
throw new TypeError("range() step must not be 0");
|
||||
}
|
||||
return {
|
||||
next: function () {
|
||||
if ((step > 0 && start >= stop) || (step < 0 && start <= stop)) {
|
||||
throw MochiKit.Iter.StopIteration;
|
||||
}
|
||||
var rval = start;
|
||||
start += step;
|
||||
return rval;
|
||||
},
|
||||
repr: function () {
|
||||
return "range(" + [start, stop, step].join(", ") + ")";
|
||||
},
|
||||
toString: MochiKit.Base.forwardCall("repr")
|
||||
};
|
||||
},
|
||||
|
||||
sum: function (iterable, start/* = 0 */) {
|
||||
var x = start || 0;
|
||||
var self = MochiKit.Iter;
|
||||
iterable = self.iter(iterable);
|
||||
try {
|
||||
while (true) {
|
||||
x += iterable.next();
|
||||
}
|
||||
} catch (e) {
|
||||
if (e != self.StopIteration) {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
return x;
|
||||
},
|
||||
|
||||
exhaust: function (iterable) {
|
||||
var self = MochiKit.Iter;
|
||||
iterable = self.iter(iterable);
|
||||
try {
|
||||
while (true) {
|
||||
iterable.next();
|
||||
}
|
||||
} catch (e) {
|
||||
if (e != self.StopIteration) {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
forEach: function (iterable, func, /* optional */self) {
|
||||
var m = MochiKit.Base;
|
||||
if (arguments.length > 2) {
|
||||
func = m.bind(func, self);
|
||||
}
|
||||
// fast path for array
|
||||
if (m.isArrayLike(iterable)) {
|
||||
try {
|
||||
for (var i = 0; i < iterable.length; i++) {
|
||||
func(iterable[i]);
|
||||
}
|
||||
} catch (e) {
|
||||
if (e != MochiKit.Iter.StopIteration) {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
self = MochiKit.Iter;
|
||||
self.exhaust(self.imap(func, iterable));
|
||||
}
|
||||
},
|
||||
|
||||
every: function (iterable, func) {
|
||||
var self = MochiKit.Iter;
|
||||
try {
|
||||
self.ifilterfalse(func, iterable).next();
|
||||
return false;
|
||||
} catch (e) {
|
||||
if (e != self.StopIteration) {
|
||||
throw e;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
},
|
||||
|
||||
sorted: function (iterable, /* optional */cmp) {
|
||||
var rval = MochiKit.Iter.list(iterable);
|
||||
if (arguments.length == 1) {
|
||||
cmp = MochiKit.Base.compare;
|
||||
}
|
||||
rval.sort(cmp);
|
||||
return rval;
|
||||
},
|
||||
|
||||
reversed: function (iterable) {
|
||||
var rval = MochiKit.Iter.list(iterable);
|
||||
rval.reverse();
|
||||
return rval;
|
||||
},
|
||||
|
||||
some: function (iterable, func) {
|
||||
var self = MochiKit.Iter;
|
||||
try {
|
||||
self.ifilter(func, iterable).next();
|
||||
return true;
|
||||
} catch (e) {
|
||||
if (e != self.StopIteration) {
|
||||
throw e;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
},
|
||||
|
||||
iextend: function (lst, iterable) {
|
||||
if (MochiKit.Base.isArrayLike(iterable)) {
|
||||
// fast-path for array-like
|
||||
for (var i = 0; i < iterable.length; i++) {
|
||||
lst.push(iterable[i]);
|
||||
}
|
||||
} else {
|
||||
var self = MochiKit.Iter;
|
||||
iterable = self.iter(iterable);
|
||||
try {
|
||||
while (true) {
|
||||
lst.push(iterable.next());
|
||||
}
|
||||
} catch (e) {
|
||||
if (e != self.StopIteration) {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
return lst;
|
||||
},
|
||||
|
||||
groupby: function(iterable, /* optional */ keyfunc) {
|
||||
var m = MochiKit.Base;
|
||||
var self = MochiKit.Iter;
|
||||
if (arguments.length < 2) {
|
||||
keyfunc = m.operator.identity;
|
||||
}
|
||||
iterable = self.iter(iterable);
|
||||
|
||||
// shared
|
||||
var pk = undefined;
|
||||
var k = undefined;
|
||||
var v;
|
||||
|
||||
function fetch() {
|
||||
v = iterable.next();
|
||||
k = keyfunc(v);
|
||||
};
|
||||
|
||||
function eat() {
|
||||
var ret = v;
|
||||
v = undefined;
|
||||
return ret;
|
||||
};
|
||||
|
||||
var first = true;
|
||||
return {
|
||||
repr: function () { return "groupby(...)"; },
|
||||
next: function() {
|
||||
// iterator-next
|
||||
|
||||
// iterate until meet next group
|
||||
while (k == pk) {
|
||||
fetch();
|
||||
if (first) {
|
||||
first = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
pk = k;
|
||||
return [k, {
|
||||
next: function() {
|
||||
// subiterator-next
|
||||
if (v == undefined) { // Is there something to eat?
|
||||
fetch();
|
||||
}
|
||||
if (k != pk) {
|
||||
throw self.StopIteration;
|
||||
}
|
||||
return eat();
|
||||
}
|
||||
}];
|
||||
}
|
||||
};
|
||||
},
|
||||
|
||||
groupby_as_array: function (iterable, /* optional */ keyfunc) {
|
||||
var m = MochiKit.Base;
|
||||
var self = MochiKit.Iter;
|
||||
if (arguments.length < 2) {
|
||||
keyfunc = m.operator.identity;
|
||||
}
|
||||
|
||||
iterable = self.iter(iterable);
|
||||
var result = [];
|
||||
var first = true;
|
||||
var prev_key;
|
||||
while (true) {
|
||||
try {
|
||||
var value = iterable.next();
|
||||
var key = keyfunc(value);
|
||||
} catch (e) {
|
||||
if (e == self.StopIteration) {
|
||||
break;
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
if (first || key != prev_key) {
|
||||
var values = [];
|
||||
result.push([key, values]);
|
||||
}
|
||||
values.push(value);
|
||||
first = false;
|
||||
prev_key = key;
|
||||
}
|
||||
return result;
|
||||
},
|
||||
|
||||
arrayLikeIter: function (iterable) {
|
||||
var i = 0;
|
||||
return {
|
||||
repr: function () { return "arrayLikeIter(...)"; },
|
||||
toString: MochiKit.Base.forwardCall("repr"),
|
||||
next: function () {
|
||||
if (i >= iterable.length) {
|
||||
throw MochiKit.Iter.StopIteration;
|
||||
}
|
||||
return iterable[i++];
|
||||
}
|
||||
};
|
||||
},
|
||||
|
||||
hasIterateNext: function (iterable) {
|
||||
return (iterable && typeof(iterable.iterateNext) == "function");
|
||||
},
|
||||
|
||||
iterateNextIter: function (iterable) {
|
||||
return {
|
||||
repr: function () { return "iterateNextIter(...)"; },
|
||||
toString: MochiKit.Base.forwardCall("repr"),
|
||||
next: function () {
|
||||
var rval = iterable.iterateNext();
|
||||
if (rval === null || rval === undefined) {
|
||||
throw MochiKit.Iter.StopIteration;
|
||||
}
|
||||
return rval;
|
||||
}
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
MochiKit.Iter.EXPORT_OK = [
|
||||
"iteratorRegistry",
|
||||
"arrayLikeIter",
|
||||
"hasIterateNext",
|
||||
"iterateNextIter",
|
||||
];
|
||||
|
||||
MochiKit.Iter.EXPORT = [
|
||||
"StopIteration",
|
||||
"registerIteratorFactory",
|
||||
"iter",
|
||||
"count",
|
||||
"cycle",
|
||||
"repeat",
|
||||
"next",
|
||||
"izip",
|
||||
"ifilter",
|
||||
"ifilterfalse",
|
||||
"islice",
|
||||
"imap",
|
||||
"applymap",
|
||||
"chain",
|
||||
"takewhile",
|
||||
"dropwhile",
|
||||
"tee",
|
||||
"list",
|
||||
"reduce",
|
||||
"range",
|
||||
"sum",
|
||||
"exhaust",
|
||||
"forEach",
|
||||
"every",
|
||||
"sorted",
|
||||
"reversed",
|
||||
"some",
|
||||
"iextend",
|
||||
"groupby",
|
||||
"groupby_as_array"
|
||||
];
|
||||
|
||||
MochiKit.Iter.__new__ = function () {
|
||||
var m = MochiKit.Base;
|
||||
this.StopIteration = new m.NamedError("StopIteration");
|
||||
this.iteratorRegistry = new m.AdapterRegistry();
|
||||
// Register the iterator factory for arrays
|
||||
this.registerIteratorFactory(
|
||||
"arrayLike",
|
||||
m.isArrayLike,
|
||||
this.arrayLikeIter
|
||||
);
|
||||
|
||||
this.registerIteratorFactory(
|
||||
"iterateNext",
|
||||
this.hasIterateNext,
|
||||
this.iterateNextIter
|
||||
);
|
||||
|
||||
this.EXPORT_TAGS = {
|
||||
":common": this.EXPORT,
|
||||
":all": m.concat(this.EXPORT, this.EXPORT_OK)
|
||||
};
|
||||
|
||||
m.nameFunctions(this);
|
||||
|
||||
};
|
||||
|
||||
MochiKit.Iter.__new__();
|
||||
|
||||
//
|
||||
// XXX: Internet Explorer blows
|
||||
//
|
||||
if (!MochiKit.__compat__) {
|
||||
reduce = MochiKit.Iter.reduce;
|
||||
}
|
||||
|
||||
MochiKit.Base._exportSymbols(this, MochiKit.Iter);
|
||||
@@ -1,290 +0,0 @@
|
||||
/***
|
||||
|
||||
MochiKit.Logging 1.3.1
|
||||
|
||||
See <http://mochikit.com/> for documentation, downloads, license, etc.
|
||||
|
||||
(c) 2005 Bob Ippolito. All rights Reserved.
|
||||
|
||||
***/
|
||||
if (typeof(dojo) != 'undefined') {
|
||||
dojo.provide('MochiKit.Logging');
|
||||
dojo.require('MochiKit.Base');
|
||||
}
|
||||
|
||||
if (typeof(JSAN) != 'undefined') {
|
||||
JSAN.use("MochiKit.Base", []);
|
||||
}
|
||||
|
||||
try {
|
||||
if (typeof(MochiKit.Base) == 'undefined') {
|
||||
throw "";
|
||||
}
|
||||
} catch (e) {
|
||||
throw "MochiKit.Logging depends on MochiKit.Base!";
|
||||
}
|
||||
|
||||
if (typeof(MochiKit.Logging) == 'undefined') {
|
||||
MochiKit.Logging = {};
|
||||
}
|
||||
|
||||
MochiKit.Logging.NAME = "MochiKit.Logging";
|
||||
MochiKit.Logging.VERSION = "1.3.1";
|
||||
MochiKit.Logging.__repr__ = function () {
|
||||
return "[" + this.NAME + " " + this.VERSION + "]";
|
||||
};
|
||||
|
||||
MochiKit.Logging.toString = function () {
|
||||
return this.__repr__();
|
||||
};
|
||||
|
||||
|
||||
MochiKit.Logging.EXPORT = [
|
||||
"LogLevel",
|
||||
"LogMessage",
|
||||
"Logger",
|
||||
"alertListener",
|
||||
"logger",
|
||||
"log",
|
||||
"logError",
|
||||
"logDebug",
|
||||
"logFatal",
|
||||
"logWarning"
|
||||
];
|
||||
|
||||
|
||||
MochiKit.Logging.EXPORT_OK = [
|
||||
"logLevelAtLeast",
|
||||
"isLogMessage",
|
||||
"compareLogMessage"
|
||||
];
|
||||
|
||||
|
||||
MochiKit.Logging.LogMessage = function (num, level, info) {
|
||||
this.num = num;
|
||||
this.level = level;
|
||||
this.info = info;
|
||||
this.timestamp = new Date();
|
||||
};
|
||||
|
||||
MochiKit.Logging.LogMessage.prototype = {
|
||||
repr: function () {
|
||||
var m = MochiKit.Base;
|
||||
return 'LogMessage(' +
|
||||
m.map(
|
||||
m.repr,
|
||||
[this.num, this.level, this.info]
|
||||
).join(', ') + ')';
|
||||
},
|
||||
toString: MochiKit.Base.forwardCall("repr")
|
||||
};
|
||||
|
||||
MochiKit.Base.update(MochiKit.Logging, {
|
||||
logLevelAtLeast: function (minLevel) {
|
||||
var self = MochiKit.Logging;
|
||||
if (typeof(minLevel) == 'string') {
|
||||
minLevel = self.LogLevel[minLevel];
|
||||
}
|
||||
return function (msg) {
|
||||
var msgLevel = msg.level;
|
||||
if (typeof(msgLevel) == 'string') {
|
||||
msgLevel = self.LogLevel[msgLevel];
|
||||
}
|
||||
return msgLevel >= minLevel;
|
||||
};
|
||||
},
|
||||
|
||||
isLogMessage: function (/* ... */) {
|
||||
var LogMessage = MochiKit.Logging.LogMessage;
|
||||
for (var i = 0; i < arguments.length; i++) {
|
||||
if (!(arguments[i] instanceof LogMessage)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
},
|
||||
|
||||
compareLogMessage: function (a, b) {
|
||||
return MochiKit.Base.compare([a.level, a.info], [b.level, b.info]);
|
||||
},
|
||||
|
||||
alertListener: function (msg) {
|
||||
alert(
|
||||
"num: " + msg.num +
|
||||
"\nlevel: " + msg.level +
|
||||
"\ninfo: " + msg.info.join(" ")
|
||||
);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
MochiKit.Logging.Logger = function (/* optional */maxSize) {
|
||||
this.counter = 0;
|
||||
if (typeof(maxSize) == 'undefined' || maxSize === null) {
|
||||
maxSize = -1;
|
||||
}
|
||||
this.maxSize = maxSize;
|
||||
this._messages = [];
|
||||
this.listeners = {};
|
||||
this.useNativeConsole = false;
|
||||
};
|
||||
|
||||
MochiKit.Logging.Logger.prototype = {
|
||||
clear: function () {
|
||||
this._messages.splice(0, this._messages.length);
|
||||
},
|
||||
|
||||
logToConsole: function (msg) {
|
||||
if (typeof(window) != "undefined" && window.console
|
||||
&& window.console.log) {
|
||||
// Safari
|
||||
window.console.log(msg);
|
||||
} else if (typeof(opera) != "undefined" && opera.postError) {
|
||||
// Opera
|
||||
opera.postError(msg);
|
||||
} else if (typeof(printfire) == "function") {
|
||||
// FireBug
|
||||
printfire(msg);
|
||||
}
|
||||
},
|
||||
|
||||
dispatchListeners: function (msg) {
|
||||
for (var k in this.listeners) {
|
||||
var pair = this.listeners[k];
|
||||
if (pair.ident != k || (pair[0] && !pair[0](msg))) {
|
||||
continue;
|
||||
}
|
||||
pair[1](msg);
|
||||
}
|
||||
},
|
||||
|
||||
addListener: function (ident, filter, listener) {
|
||||
if (typeof(filter) == 'string') {
|
||||
filter = MochiKit.Logging.logLevelAtLeast(filter);
|
||||
}
|
||||
var entry = [filter, listener];
|
||||
entry.ident = ident;
|
||||
this.listeners[ident] = entry;
|
||||
},
|
||||
|
||||
removeListener: function (ident) {
|
||||
delete this.listeners[ident];
|
||||
},
|
||||
|
||||
baseLog: function (level, message/*, ...*/) {
|
||||
var msg = new MochiKit.Logging.LogMessage(
|
||||
this.counter,
|
||||
level,
|
||||
MochiKit.Base.extend(null, arguments, 1)
|
||||
);
|
||||
this._messages.push(msg);
|
||||
this.dispatchListeners(msg);
|
||||
if (this.useNativeConsole) {
|
||||
this.logToConsole(msg.level + ": " + msg.info.join(" "));
|
||||
}
|
||||
this.counter += 1;
|
||||
while (this.maxSize >= 0 && this._messages.length > this.maxSize) {
|
||||
this._messages.shift();
|
||||
}
|
||||
},
|
||||
|
||||
getMessages: function (howMany) {
|
||||
var firstMsg = 0;
|
||||
if (!(typeof(howMany) == 'undefined' || howMany === null)) {
|
||||
firstMsg = Math.max(0, this._messages.length - howMany);
|
||||
}
|
||||
return this._messages.slice(firstMsg);
|
||||
},
|
||||
|
||||
getMessageText: function (howMany) {
|
||||
if (typeof(howMany) == 'undefined' || howMany === null) {
|
||||
howMany = 30;
|
||||
}
|
||||
var messages = this.getMessages(howMany);
|
||||
if (messages.length) {
|
||||
var lst = map(function (m) {
|
||||
return '\n [' + m.num + '] ' + m.level + ': ' + m.info.join(' ');
|
||||
}, messages);
|
||||
lst.unshift('LAST ' + messages.length + ' MESSAGES:');
|
||||
return lst.join('');
|
||||
}
|
||||
return '';
|
||||
},
|
||||
|
||||
debuggingBookmarklet: function (inline) {
|
||||
if (typeof(MochiKit.LoggingPane) == "undefined") {
|
||||
alert(this.getMessageText());
|
||||
} else {
|
||||
MochiKit.LoggingPane.createLoggingPane(inline || false);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
MochiKit.Logging.__new__ = function () {
|
||||
this.LogLevel = {
|
||||
ERROR: 40,
|
||||
FATAL: 50,
|
||||
WARNING: 30,
|
||||
INFO: 20,
|
||||
DEBUG: 10
|
||||
};
|
||||
|
||||
var m = MochiKit.Base;
|
||||
m.registerComparator("LogMessage",
|
||||
this.isLogMessage,
|
||||
this.compareLogMessage
|
||||
);
|
||||
|
||||
var partial = m.partial;
|
||||
|
||||
var Logger = this.Logger;
|
||||
var baseLog = Logger.prototype.baseLog;
|
||||
m.update(this.Logger.prototype, {
|
||||
debug: partial(baseLog, 'DEBUG'),
|
||||
log: partial(baseLog, 'INFO'),
|
||||
error: partial(baseLog, 'ERROR'),
|
||||
fatal: partial(baseLog, 'FATAL'),
|
||||
warning: partial(baseLog, 'WARNING')
|
||||
});
|
||||
|
||||
// indirectly find logger so it can be replaced
|
||||
var self = this;
|
||||
var connectLog = function (name) {
|
||||
return function () {
|
||||
self.logger[name].apply(self.logger, arguments);
|
||||
};
|
||||
};
|
||||
|
||||
this.log = connectLog('log');
|
||||
this.logError = connectLog('error');
|
||||
this.logDebug = connectLog('debug');
|
||||
this.logFatal = connectLog('fatal');
|
||||
this.logWarning = connectLog('warning');
|
||||
this.logger = new Logger();
|
||||
this.logger.useNativeConsole = true;
|
||||
|
||||
this.EXPORT_TAGS = {
|
||||
":common": this.EXPORT,
|
||||
":all": m.concat(this.EXPORT, this.EXPORT_OK)
|
||||
};
|
||||
|
||||
m.nameFunctions(this);
|
||||
|
||||
};
|
||||
|
||||
if (typeof(printfire) == "undefined" &&
|
||||
typeof(document) != "undefined" && document.createEvent &&
|
||||
typeof(dispatchEvent) != "undefined") {
|
||||
// FireBug really should be less lame about this global function
|
||||
printfire = function () {
|
||||
printfire.args = arguments;
|
||||
var ev = document.createEvent("Events");
|
||||
ev.initEvent("printfire", false, true);
|
||||
dispatchEvent(ev);
|
||||
};
|
||||
}
|
||||
|
||||
MochiKit.Logging.__new__();
|
||||
|
||||
MochiKit.Base._exportSymbols(this, MochiKit.Logging);
|
||||
@@ -1,356 +0,0 @@
|
||||
/***
|
||||
|
||||
MochiKit.LoggingPane 1.3.1
|
||||
|
||||
See <http://mochikit.com/> for documentation, downloads, license, etc.
|
||||
|
||||
(c) 2005 Bob Ippolito. All rights Reserved.
|
||||
|
||||
***/
|
||||
if (typeof(dojo) != 'undefined') {
|
||||
dojo.provide('MochiKit.LoggingPane');
|
||||
dojo.require('MochiKit.Logging');
|
||||
dojo.require('MochiKit.Base');
|
||||
}
|
||||
|
||||
if (typeof(JSAN) != 'undefined') {
|
||||
JSAN.use("MochiKit.Logging", []);
|
||||
JSAN.use("MochiKit.Base", []);
|
||||
}
|
||||
|
||||
try {
|
||||
if (typeof(MochiKit.Base) == 'undefined' || typeof(MochiKit.Logging) == 'undefined') {
|
||||
throw "";
|
||||
}
|
||||
} catch (e) {
|
||||
throw "MochiKit.LoggingPane depends on MochiKit.Base and MochiKit.Logging!";
|
||||
}
|
||||
|
||||
if (typeof(MochiKit.LoggingPane) == 'undefined') {
|
||||
MochiKit.LoggingPane = {};
|
||||
}
|
||||
|
||||
MochiKit.LoggingPane.NAME = "MochiKit.LoggingPane";
|
||||
MochiKit.LoggingPane.VERSION = "1.3.1";
|
||||
MochiKit.LoggingPane.__repr__ = function () {
|
||||
return "[" + this.NAME + " " + this.VERSION + "]";
|
||||
};
|
||||
|
||||
MochiKit.LoggingPane.toString = function () {
|
||||
return this.__repr__();
|
||||
};
|
||||
|
||||
MochiKit.LoggingPane.createLoggingPane = function (inline/* = false */) {
|
||||
var m = MochiKit.LoggingPane;
|
||||
inline = !(!inline);
|
||||
if (m._loggingPane && m._loggingPane.inline != inline) {
|
||||
m._loggingPane.closePane();
|
||||
m._loggingPane = null;
|
||||
}
|
||||
if (!m._loggingPane || m._loggingPane.closed) {
|
||||
m._loggingPane = new m.LoggingPane(inline, MochiKit.Logging.logger);
|
||||
}
|
||||
return m._loggingPane;
|
||||
};
|
||||
|
||||
MochiKit.LoggingPane.LoggingPane = function (inline/* = false */, logger/* = MochiKit.Logging.logger */) {
|
||||
/* Use a div if inline, pop up a window if not */
|
||||
/* Create the elements */
|
||||
if (typeof(logger) == "undefined" || logger === null) {
|
||||
logger = MochiKit.Logging.logger;
|
||||
}
|
||||
this.logger = logger;
|
||||
var update = MochiKit.Base.update;
|
||||
var updatetree = MochiKit.Base.updatetree;
|
||||
var bind = MochiKit.Base.bind;
|
||||
var clone = MochiKit.Base.clone;
|
||||
var win = window;
|
||||
var uid = "_MochiKit_LoggingPane";
|
||||
if (typeof(MochiKit.DOM) != "undefined") {
|
||||
win = MochiKit.DOM.currentWindow();
|
||||
}
|
||||
if (!inline) {
|
||||
// name the popup with the base URL for uniqueness
|
||||
var url = win.location.href.split("?")[0].replace(/[:\/.><&]/g, "_");
|
||||
var name = uid + "_" + url;
|
||||
var nwin = win.open("", name, "dependent,resizable,height=200");
|
||||
if (!nwin) {
|
||||
alert("Not able to open debugging window due to pop-up blocking.");
|
||||
return undefined;
|
||||
}
|
||||
nwin.document.write(
|
||||
'<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" '
|
||||
+ '"http://www.w3.org/TR/html4/loose.dtd">'
|
||||
+ '<html><head><title>[MochiKit.LoggingPane]</title></head>'
|
||||
+ '<body></body></html>'
|
||||
);
|
||||
nwin.document.close();
|
||||
nwin.document.title += ' ' + win.document.title;
|
||||
win = nwin;
|
||||
}
|
||||
var doc = win.document;
|
||||
this.doc = doc;
|
||||
|
||||
// Connect to the debug pane if it already exists (i.e. in a window orphaned by the page being refreshed)
|
||||
var debugPane = doc.getElementById(uid);
|
||||
var existing_pane = !!debugPane;
|
||||
if (debugPane && typeof(debugPane.loggingPane) != "undefined") {
|
||||
debugPane.loggingPane.logger = this.logger;
|
||||
debugPane.loggingPane.buildAndApplyFilter();
|
||||
return debugPane.loggingPane;
|
||||
}
|
||||
|
||||
if (existing_pane) {
|
||||
// clear any existing contents
|
||||
var child;
|
||||
while ((child = debugPane.firstChild)) {
|
||||
debugPane.removeChild(child);
|
||||
}
|
||||
} else {
|
||||
debugPane = doc.createElement("div");
|
||||
debugPane.id = uid;
|
||||
}
|
||||
debugPane.loggingPane = this;
|
||||
var levelFilterField = doc.createElement("input");
|
||||
var infoFilterField = doc.createElement("input");
|
||||
var filterButton = doc.createElement("button");
|
||||
var loadButton = doc.createElement("button");
|
||||
var clearButton = doc.createElement("button");
|
||||
var closeButton = doc.createElement("button");
|
||||
var logPaneArea = doc.createElement("div");
|
||||
var logPane = doc.createElement("div");
|
||||
|
||||
/* Set up the functions */
|
||||
var listenerId = uid + "_Listener";
|
||||
this.colorTable = clone(this.colorTable);
|
||||
var messages = [];
|
||||
var messageFilter = null;
|
||||
|
||||
var messageLevel = function (msg) {
|
||||
var level = msg.level;
|
||||
if (typeof(level) == "number") {
|
||||
level = MochiKit.Logging.LogLevel[level];
|
||||
}
|
||||
return level;
|
||||
};
|
||||
|
||||
var messageText = function (msg) {
|
||||
return msg.info.join(" ");
|
||||
};
|
||||
|
||||
var addMessageText = bind(function (msg) {
|
||||
var level = messageLevel(msg);
|
||||
var text = messageText(msg);
|
||||
var c = this.colorTable[level];
|
||||
var p = doc.createElement("span");
|
||||
p.className = "MochiKit-LogMessage MochiKit-LogLevel-" + level;
|
||||
p.style.cssText = "margin: 0px; white-space: -moz-pre-wrap; white-space: -o-pre-wrap; white-space: pre-wrap; white-space: pre-line; word-wrap: break-word; wrap-option: emergency; color: " + c;
|
||||
p.appendChild(doc.createTextNode(level + ": " + text));
|
||||
logPane.appendChild(p);
|
||||
logPane.appendChild(doc.createElement("br"));
|
||||
if (logPaneArea.offsetHeight > logPaneArea.scrollHeight) {
|
||||
logPaneArea.scrollTop = 0;
|
||||
} else {
|
||||
logPaneArea.scrollTop = logPaneArea.scrollHeight;
|
||||
}
|
||||
}, this);
|
||||
|
||||
var addMessage = function (msg) {
|
||||
messages[messages.length] = msg;
|
||||
addMessageText(msg);
|
||||
};
|
||||
|
||||
var buildMessageFilter = function () {
|
||||
var levelre, infore;
|
||||
try {
|
||||
/* Catch any exceptions that might arise due to invalid regexes */
|
||||
levelre = new RegExp(levelFilterField.value);
|
||||
infore = new RegExp(infoFilterField.value);
|
||||
} catch(e) {
|
||||
/* If there was an error with the regexes, do no filtering */
|
||||
logDebug("Error in filter regex: " + e.message);
|
||||
return null;
|
||||
}
|
||||
|
||||
return function (msg) {
|
||||
return (
|
||||
levelre.test(messageLevel(msg)) &&
|
||||
infore.test(messageText(msg))
|
||||
);
|
||||
};
|
||||
};
|
||||
|
||||
var clearMessagePane = function () {
|
||||
while (logPane.firstChild) {
|
||||
logPane.removeChild(logPane.firstChild);
|
||||
}
|
||||
};
|
||||
|
||||
var clearMessages = function () {
|
||||
messages = [];
|
||||
clearMessagePane();
|
||||
};
|
||||
|
||||
var closePane = bind(function () {
|
||||
if (this.closed) {
|
||||
return;
|
||||
}
|
||||
this.closed = true;
|
||||
if (MochiKit.LoggingPane._loggingPane == this) {
|
||||
MochiKit.LoggingPane._loggingPane = null;
|
||||
}
|
||||
this.logger.removeListener(listenerId);
|
||||
|
||||
debugPane.loggingPane = null;
|
||||
|
||||
if (inline) {
|
||||
debugPane.parentNode.removeChild(debugPane);
|
||||
} else {
|
||||
this.win.close();
|
||||
}
|
||||
}, this);
|
||||
|
||||
var filterMessages = function () {
|
||||
clearMessagePane();
|
||||
|
||||
for (var i = 0; i < messages.length; i++) {
|
||||
var msg = messages[i];
|
||||
if (messageFilter === null || messageFilter(msg)) {
|
||||
addMessageText(msg);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
this.buildAndApplyFilter = function () {
|
||||
messageFilter = buildMessageFilter();
|
||||
|
||||
filterMessages();
|
||||
|
||||
this.logger.removeListener(listenerId);
|
||||
this.logger.addListener(listenerId, messageFilter, addMessage);
|
||||
};
|
||||
|
||||
|
||||
var loadMessages = bind(function () {
|
||||
messages = this.logger.getMessages();
|
||||
filterMessages();
|
||||
}, this);
|
||||
|
||||
var filterOnEnter = bind(function (event) {
|
||||
event = event || window.event;
|
||||
key = event.which || event.keyCode;
|
||||
if (key == 13) {
|
||||
this.buildAndApplyFilter();
|
||||
}
|
||||
}, this);
|
||||
|
||||
/* Create the debug pane */
|
||||
var style = "display: block; z-index: 1000; left: 0px; bottom: 0px; position: fixed; width: 100%; background-color: white; font: " + this.logFont;
|
||||
if (inline) {
|
||||
style += "; height: 10em; border-top: 2px solid black";
|
||||
} else {
|
||||
style += "; height: 100%;";
|
||||
}
|
||||
debugPane.style.cssText = style;
|
||||
|
||||
if (!existing_pane) {
|
||||
doc.body.appendChild(debugPane);
|
||||
}
|
||||
|
||||
/* Create the filter fields */
|
||||
style = {"cssText": "width: 33%; display: inline; font: " + this.logFont};
|
||||
|
||||
updatetree(levelFilterField, {
|
||||
"value": "FATAL|ERROR|WARNING|INFO|DEBUG",
|
||||
"onkeypress": filterOnEnter,
|
||||
"style": style
|
||||
});
|
||||
debugPane.appendChild(levelFilterField);
|
||||
|
||||
updatetree(infoFilterField, {
|
||||
"value": ".*",
|
||||
"onkeypress": filterOnEnter,
|
||||
"style": style
|
||||
});
|
||||
debugPane.appendChild(infoFilterField);
|
||||
|
||||
/* Create the buttons */
|
||||
style = "width: 8%; display:inline; font: " + this.logFont;
|
||||
|
||||
filterButton.appendChild(doc.createTextNode("Filter"));
|
||||
filterButton.onclick = bind("buildAndApplyFilter", this);
|
||||
filterButton.style.cssText = style;
|
||||
debugPane.appendChild(filterButton);
|
||||
|
||||
loadButton.appendChild(doc.createTextNode("Load"));
|
||||
loadButton.onclick = loadMessages;
|
||||
loadButton.style.cssText = style;
|
||||
debugPane.appendChild(loadButton);
|
||||
|
||||
clearButton.appendChild(doc.createTextNode("Clear"));
|
||||
clearButton.onclick = clearMessages;
|
||||
clearButton.style.cssText = style;
|
||||
debugPane.appendChild(clearButton);
|
||||
|
||||
closeButton.appendChild(doc.createTextNode("Close"));
|
||||
closeButton.onclick = closePane;
|
||||
closeButton.style.cssText = style;
|
||||
debugPane.appendChild(closeButton);
|
||||
|
||||
/* Create the logging pane */
|
||||
logPaneArea.style.cssText = "overflow: auto; width: 100%";
|
||||
logPane.style.cssText = "width: 100%; height: " + (inline ? "8em" : "100%");
|
||||
|
||||
logPaneArea.appendChild(logPane);
|
||||
debugPane.appendChild(logPaneArea);
|
||||
|
||||
this.buildAndApplyFilter();
|
||||
loadMessages();
|
||||
|
||||
if (inline) {
|
||||
this.win = undefined;
|
||||
} else {
|
||||
this.win = win;
|
||||
}
|
||||
this.inline = inline;
|
||||
this.closePane = closePane;
|
||||
this.closed = false;
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
MochiKit.LoggingPane.LoggingPane.prototype = {
|
||||
"logFont": "8pt Verdana,sans-serif",
|
||||
"colorTable": {
|
||||
"ERROR": "red",
|
||||
"FATAL": "darkred",
|
||||
"WARNING": "blue",
|
||||
"INFO": "black",
|
||||
"DEBUG": "green"
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
MochiKit.LoggingPane.EXPORT_OK = [
|
||||
"LoggingPane"
|
||||
];
|
||||
|
||||
MochiKit.LoggingPane.EXPORT = [
|
||||
"createLoggingPane"
|
||||
];
|
||||
|
||||
MochiKit.LoggingPane.__new__ = function () {
|
||||
this.EXPORT_TAGS = {
|
||||
":common": this.EXPORT,
|
||||
":all": MochiKit.Base.concat(this.EXPORT, this.EXPORT_OK)
|
||||
};
|
||||
|
||||
MochiKit.Base.nameFunctions(this);
|
||||
|
||||
MochiKit.LoggingPane._loggingPane = null;
|
||||
|
||||
};
|
||||
|
||||
MochiKit.LoggingPane.__new__();
|
||||
|
||||
MochiKit.Base._exportSymbols(this, MochiKit.LoggingPane);
|
||||
152
mozilla/webtools/new-graph/js/mochikit/MochiKit.js
vendored
@@ -1,152 +0,0 @@
|
||||
/***
|
||||
|
||||
MochiKit.MochiKit 1.3.1
|
||||
|
||||
See <http://mochikit.com/> for documentation, downloads, license, etc.
|
||||
|
||||
(c) 2005 Bob Ippolito. All rights Reserved.
|
||||
|
||||
***/
|
||||
|
||||
if (typeof(MochiKit) == 'undefined') {
|
||||
MochiKit = {};
|
||||
}
|
||||
|
||||
if (typeof(MochiKit.MochiKit) == 'undefined') {
|
||||
MochiKit.MochiKit = {};
|
||||
}
|
||||
|
||||
MochiKit.MochiKit.NAME = "MochiKit.MochiKit";
|
||||
MochiKit.MochiKit.VERSION = "1.3.1";
|
||||
MochiKit.MochiKit.__repr__ = function () {
|
||||
return "[" + this.NAME + " " + this.VERSION + "]";
|
||||
};
|
||||
|
||||
MochiKit.MochiKit.toString = function () {
|
||||
return this.__repr__();
|
||||
};
|
||||
|
||||
MochiKit.MochiKit.SUBMODULES = [
|
||||
"Base",
|
||||
"Iter",
|
||||
"Logging",
|
||||
"DateTime",
|
||||
"Format",
|
||||
"Async",
|
||||
"DOM",
|
||||
"LoggingPane",
|
||||
"Color",
|
||||
"Signal",
|
||||
"Visual"
|
||||
];
|
||||
|
||||
if (typeof(JSAN) != 'undefined' || typeof(dojo) != 'undefined') {
|
||||
if (typeof(dojo) != 'undefined') {
|
||||
dojo.provide('MochiKit.MochiKit');
|
||||
dojo.require("MochiKit.*");
|
||||
}
|
||||
if (typeof(JSAN) != 'undefined') {
|
||||
// hopefully this makes it easier for static analysis?
|
||||
JSAN.use("MochiKit.Base", []);
|
||||
JSAN.use("MochiKit.Iter", []);
|
||||
JSAN.use("MochiKit.Logging", []);
|
||||
JSAN.use("MochiKit.DateTime", []);
|
||||
JSAN.use("MochiKit.Format", []);
|
||||
JSAN.use("MochiKit.Async", []);
|
||||
JSAN.use("MochiKit.DOM", []);
|
||||
JSAN.use("MochiKit.LoggingPane", []);
|
||||
JSAN.use("MochiKit.Color", []);
|
||||
JSAN.use("MochiKit.Signal", []);
|
||||
JSAN.use("MochiKit.Visual", []);
|
||||
}
|
||||
(function () {
|
||||
var extend = MochiKit.Base.extend;
|
||||
var self = MochiKit.MochiKit;
|
||||
var modules = self.SUBMODULES;
|
||||
var EXPORT = [];
|
||||
var EXPORT_OK = [];
|
||||
var EXPORT_TAGS = {};
|
||||
var i, k, m, all;
|
||||
for (i = 0; i < modules.length; i++) {
|
||||
m = MochiKit[modules[i]];
|
||||
extend(EXPORT, m.EXPORT);
|
||||
extend(EXPORT_OK, m.EXPORT_OK);
|
||||
for (k in m.EXPORT_TAGS) {
|
||||
EXPORT_TAGS[k] = extend(EXPORT_TAGS[k], m.EXPORT_TAGS[k]);
|
||||
}
|
||||
all = m.EXPORT_TAGS[":all"];
|
||||
if (!all) {
|
||||
all = extend(null, m.EXPORT, m.EXPORT_OK);
|
||||
}
|
||||
var j;
|
||||
for (j = 0; j < all.length; j++) {
|
||||
k = all[j];
|
||||
self[k] = m[k];
|
||||
}
|
||||
}
|
||||
self.EXPORT = EXPORT;
|
||||
self.EXPORT_OK = EXPORT_OK;
|
||||
self.EXPORT_TAGS = EXPORT_TAGS;
|
||||
}());
|
||||
|
||||
} else {
|
||||
if (typeof(MochiKit.__compat__) == 'undefined') {
|
||||
MochiKit.__compat__ = true;
|
||||
}
|
||||
(function () {
|
||||
var scripts = document.getElementsByTagName("script");
|
||||
var kXULNSURI = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
|
||||
var base = null;
|
||||
var baseElem = null;
|
||||
var allScripts = {};
|
||||
var i;
|
||||
for (i = 0; i < scripts.length; i++) {
|
||||
var src = scripts[i].getAttribute("src");
|
||||
if (!src) {
|
||||
continue;
|
||||
}
|
||||
allScripts[src] = true;
|
||||
if (src.match(/MochiKit.js$/)) {
|
||||
base = src.substring(0, src.lastIndexOf('MochiKit.js'));
|
||||
baseElem = scripts[i];
|
||||
}
|
||||
}
|
||||
if (base === null) {
|
||||
return;
|
||||
}
|
||||
var modules = MochiKit.MochiKit.SUBMODULES;
|
||||
for (var i = 0; i < modules.length; i++) {
|
||||
if (MochiKit[modules[i]]) {
|
||||
continue;
|
||||
}
|
||||
var uri = base + modules[i] + '.js';
|
||||
if (uri in allScripts) {
|
||||
continue;
|
||||
}
|
||||
if (document.documentElement &&
|
||||
document.documentElement.namespaceURI == kXULNSURI) {
|
||||
// XUL
|
||||
var s = document.createElementNS(kXULNSURI, 'script');
|
||||
s.setAttribute("id", "MochiKit_" + base + modules[i]);
|
||||
s.setAttribute("src", uri);
|
||||
s.setAttribute("type", "application/x-javascript");
|
||||
baseElem.parentNode.appendChild(s);
|
||||
} else {
|
||||
// HTML
|
||||
/*
|
||||
DOM can not be used here because Safari does
|
||||
deferred loading of scripts unless they are
|
||||
in the document or inserted with document.write
|
||||
|
||||
This is not XHTML compliant. If you want XHTML
|
||||
compliance then you must use the packed version of MochiKit
|
||||
or include each script individually (basically unroll
|
||||
these document.write calls into your XHTML source)
|
||||
|
||||
*/
|
||||
document.write('<script src="' + uri +
|
||||
'" type="text/javascript"></script>');
|
||||
}
|
||||
};
|
||||
})();
|
||||
}
|
||||
@@ -1,73 +0,0 @@
|
||||
/***
|
||||
|
||||
MochiKit.MockDOM 1.3.1
|
||||
|
||||
See <http://mochikit.com/> for documentation, downloads, license, etc.
|
||||
|
||||
(c) 2005 Bob Ippolito. All rights Reserved.
|
||||
|
||||
***/
|
||||
if (typeof(MochiKit) == "undefined") {
|
||||
var MochiKit = {};
|
||||
}
|
||||
|
||||
if (typeof(MochiKit.MockDOM) == "undefined") {
|
||||
MochiKit.MockDOM = {};
|
||||
}
|
||||
|
||||
MochiKit.MockDOM.NAME = "MochiKit.MockDOM";
|
||||
MochiKit.MockDOM.VERSION = "1.3.1";
|
||||
|
||||
MochiKit.MockDOM.__repr__ = function () {
|
||||
return "[" + this.NAME + " " + this.VERSION + "]";
|
||||
};
|
||||
|
||||
MochiKit.MockDOM.toString = function () {
|
||||
return this.__repr__();
|
||||
};
|
||||
|
||||
MochiKit.MockDOM.createDocument = function () {
|
||||
var doc = new MochiKit.MockDOM.MockElement("DOCUMENT");
|
||||
doc.body = doc.createElement("BODY");
|
||||
doc.appendChild(doc.body);
|
||||
return doc;
|
||||
};
|
||||
|
||||
MochiKit.MockDOM.MockElement = function (name, data) {
|
||||
this.nodeName = name.toUpperCase();
|
||||
if (typeof(data) == "string") {
|
||||
this.nodeValue = data;
|
||||
this.nodeType = 3;
|
||||
} else {
|
||||
this.nodeType = 1;
|
||||
this.childNodes = [];
|
||||
}
|
||||
if (name.substring(0, 1) == "<") {
|
||||
var nameattr = name.substring(
|
||||
name.indexOf('"') + 1, name.lastIndexOf('"'));
|
||||
name = name.substring(1, name.indexOf(" "));
|
||||
this.nodeName = name.toUpperCase();
|
||||
this.setAttribute("name", nameattr);
|
||||
}
|
||||
};
|
||||
|
||||
MochiKit.MockDOM.MockElement.prototype = {
|
||||
createElement: function (nodeName) {
|
||||
return new MochiKit.MockDOM.MockElement(nodeName);
|
||||
},
|
||||
createTextNode: function (text) {
|
||||
return new MochiKit.MockDOM.MockElement("text", text);
|
||||
},
|
||||
setAttribute: function (name, value) {
|
||||
this[name] = value;
|
||||
},
|
||||
getAttribute: function (name) {
|
||||
return this[name];
|
||||
},
|
||||
appendChild: function (child) {
|
||||
this.childNodes.push(child);
|
||||
},
|
||||
toString: function () {
|
||||
return "MockElement(" + this.nodeName + ")";
|
||||
}
|
||||
};
|
||||
@@ -1,680 +0,0 @@
|
||||
/***
|
||||
|
||||
MochiKit.Signal 1.3.1
|
||||
|
||||
See <http://mochikit.com/> for documentation, downloads, license, etc.
|
||||
|
||||
(c) 2006 Jonathan Gardner, Beau Hartshorne, Bob Ippolito. All rights Reserved.
|
||||
|
||||
***/
|
||||
|
||||
if (typeof(dojo) != 'undefined') {
|
||||
dojo.provide('MochiKit.Signal');
|
||||
dojo.require('MochiKit.Base');
|
||||
dojo.require('MochiKit.DOM');
|
||||
}
|
||||
if (typeof(JSAN) != 'undefined') {
|
||||
JSAN.use('MochiKit.Base', []);
|
||||
JSAN.use('MochiKit.DOM', []);
|
||||
}
|
||||
|
||||
try {
|
||||
if (typeof(MochiKit.Base) == 'undefined') {
|
||||
throw '';
|
||||
}
|
||||
} catch (e) {
|
||||
throw 'MochiKit.Signal depends on MochiKit.Base!';
|
||||
}
|
||||
|
||||
try {
|
||||
if (typeof(MochiKit.DOM) == 'undefined') {
|
||||
throw '';
|
||||
}
|
||||
} catch (e) {
|
||||
throw 'MochiKit.Signal depends on MochiKit.DOM!';
|
||||
}
|
||||
|
||||
if (typeof(MochiKit.Signal) == 'undefined') {
|
||||
MochiKit.Signal = {};
|
||||
}
|
||||
|
||||
MochiKit.Signal.NAME = 'MochiKit.Signal';
|
||||
MochiKit.Signal.VERSION = '1.3.1';
|
||||
|
||||
MochiKit.Signal._observers = [];
|
||||
|
||||
MochiKit.Signal.Event = function (src, e) {
|
||||
this._event = e || window.event;
|
||||
this._src = src;
|
||||
};
|
||||
|
||||
MochiKit.Base.update(MochiKit.Signal.Event.prototype, {
|
||||
|
||||
__repr__: function() {
|
||||
var repr = MochiKit.Base.repr;
|
||||
var str = '{event(): ' + repr(this.event()) +
|
||||
', src(): ' + repr(this.src()) +
|
||||
', type(): ' + repr(this.type()) +
|
||||
', target(): ' + repr(this.target()) +
|
||||
', modifier(): ' + '{alt: ' + repr(this.modifier().alt) +
|
||||
', ctrl: ' + repr(this.modifier().ctrl) +
|
||||
', meta: ' + repr(this.modifier().meta) +
|
||||
', shift: ' + repr(this.modifier().shift) +
|
||||
', any: ' + repr(this.modifier().any) + '}';
|
||||
|
||||
if (this.type() && this.type().indexOf('key') === 0) {
|
||||
str += ', key(): {code: ' + repr(this.key().code) +
|
||||
', string: ' + repr(this.key().string) + '}';
|
||||
}
|
||||
|
||||
if (this.type() && (
|
||||
this.type().indexOf('mouse') === 0 ||
|
||||
this.type().indexOf('click') != -1 ||
|
||||
this.type() == 'contextmenu')) {
|
||||
|
||||
str += ', mouse(): {page: ' + repr(this.mouse().page) +
|
||||
', client: ' + repr(this.mouse().client);
|
||||
|
||||
if (this.type() != 'mousemove') {
|
||||
str += ', button: {left: ' + repr(this.mouse().button.left) +
|
||||
', middle: ' + repr(this.mouse().button.middle) +
|
||||
', right: ' + repr(this.mouse().button.right) + '}}';
|
||||
} else {
|
||||
str += '}';
|
||||
}
|
||||
}
|
||||
if (this.type() == 'mouseover' || this.type() == 'mouseout') {
|
||||
str += ', relatedTarget(): ' + repr(this.relatedTarget());
|
||||
}
|
||||
str += '}';
|
||||
return str;
|
||||
},
|
||||
|
||||
toString: function () {
|
||||
return this.__repr__();
|
||||
},
|
||||
|
||||
src: function () {
|
||||
return this._src;
|
||||
},
|
||||
|
||||
event: function () {
|
||||
return this._event;
|
||||
},
|
||||
|
||||
type: function () {
|
||||
return this._event.type || undefined;
|
||||
},
|
||||
|
||||
target: function () {
|
||||
return this._event.target || this._event.srcElement;
|
||||
},
|
||||
|
||||
relatedTarget: function () {
|
||||
if (this.type() == 'mouseover') {
|
||||
return (this._event.relatedTarget ||
|
||||
this._event.fromElement);
|
||||
} else if (this.type() == 'mouseout') {
|
||||
return (this._event.relatedTarget ||
|
||||
this._event.toElement);
|
||||
}
|
||||
// throw new Error("relatedTarget only available for 'mouseover' and 'mouseout'");
|
||||
return undefined;
|
||||
},
|
||||
|
||||
modifier: function () {
|
||||
var m = {};
|
||||
m.alt = this._event.altKey;
|
||||
m.ctrl = this._event.ctrlKey;
|
||||
m.meta = this._event.metaKey || false; // IE and Opera punt here
|
||||
m.shift = this._event.shiftKey;
|
||||
m.any = m.alt || m.ctrl || m.shift || m.meta;
|
||||
return m;
|
||||
},
|
||||
|
||||
key: function () {
|
||||
var k = {};
|
||||
if (this.type() && this.type().indexOf('key') === 0) {
|
||||
|
||||
/*
|
||||
|
||||
If you're looking for a special key, look for it in keydown or
|
||||
keyup, but never keypress. If you're looking for a Unicode
|
||||
chracter, look for it with keypress, but never keyup or
|
||||
keydown.
|
||||
|
||||
Notes:
|
||||
|
||||
FF key event behavior:
|
||||
key event charCode keyCode
|
||||
DOWN ku,kd 0 40
|
||||
DOWN kp 0 40
|
||||
ESC ku,kd 0 27
|
||||
ESC kp 0 27
|
||||
a ku,kd 0 65
|
||||
a kp 97 0
|
||||
shift+a ku,kd 0 65
|
||||
shift+a kp 65 0
|
||||
1 ku,kd 0 49
|
||||
1 kp 49 0
|
||||
shift+1 ku,kd 0 0
|
||||
shift+1 kp 33 0
|
||||
|
||||
IE key event behavior:
|
||||
(IE doesn't fire keypress events for special keys.)
|
||||
key event keyCode
|
||||
DOWN ku,kd 40
|
||||
DOWN kp undefined
|
||||
ESC ku,kd 27
|
||||
ESC kp 27
|
||||
a ku,kd 65
|
||||
a kp 97
|
||||
shift+a ku,kd 65
|
||||
shift+a kp 65
|
||||
1 ku,kd 49
|
||||
1 kp 49
|
||||
shift+1 ku,kd 49
|
||||
shift+1 kp 33
|
||||
|
||||
Safari key event behavior:
|
||||
(Safari sets charCode and keyCode to something crazy for
|
||||
special keys.)
|
||||
key event charCode keyCode
|
||||
DOWN ku,kd 63233 40
|
||||
DOWN kp 63233 63233
|
||||
ESC ku,kd 27 27
|
||||
ESC kp 27 27
|
||||
a ku,kd 97 65
|
||||
a kp 97 97
|
||||
shift+a ku,kd 65 65
|
||||
shift+a kp 65 65
|
||||
1 ku,kd 49 49
|
||||
1 kp 49 49
|
||||
shift+1 ku,kd 33 49
|
||||
shift+1 kp 33 33
|
||||
|
||||
*/
|
||||
|
||||
/* look for special keys here */
|
||||
if (this.type() == 'keydown' || this.type() == 'keyup') {
|
||||
k.code = this._event.keyCode;
|
||||
k.string = (MochiKit.Signal._specialKeys[k.code] ||
|
||||
'KEY_UNKNOWN');
|
||||
return k;
|
||||
|
||||
/* look for characters here */
|
||||
} else if (this.type() == 'keypress') {
|
||||
|
||||
/*
|
||||
|
||||
Special key behavior:
|
||||
|
||||
IE: does not fire keypress events for special keys
|
||||
FF: sets charCode to 0, and sets the correct keyCode
|
||||
Safari: sets keyCode and charCode to something stupid
|
||||
|
||||
*/
|
||||
|
||||
k.code = 0;
|
||||
k.string = '';
|
||||
|
||||
if (typeof(this._event.charCode) != 'undefined' &&
|
||||
this._event.charCode !== 0 &&
|
||||
!MochiKit.Signal._specialMacKeys[this._event.charCode]) {
|
||||
k.code = this._event.charCode;
|
||||
k.string = String.fromCharCode(k.code);
|
||||
} else if (this._event.keyCode &&
|
||||
typeof(this._event.charCode) == 'undefined') { // IE
|
||||
k.code = this._event.keyCode;
|
||||
k.string = String.fromCharCode(k.code);
|
||||
}
|
||||
|
||||
return k;
|
||||
}
|
||||
}
|
||||
// throw new Error('This is not a key event');
|
||||
return undefined;
|
||||
},
|
||||
|
||||
mouse: function () {
|
||||
var m = {};
|
||||
var e = this._event;
|
||||
|
||||
if (this.type() && (
|
||||
this.type().indexOf('mouse') === 0 ||
|
||||
this.type().indexOf('click') != -1 ||
|
||||
this.type() == 'contextmenu')) {
|
||||
|
||||
m.client = new MochiKit.DOM.Coordinates(0, 0);
|
||||
if (e.clientX || e.clientY) {
|
||||
m.client.x = (!e.clientX || e.clientX < 0) ? 0 : e.clientX;
|
||||
m.client.y = (!e.clientY || e.clientY < 0) ? 0 : e.clientY;
|
||||
}
|
||||
|
||||
m.page = new MochiKit.DOM.Coordinates(0, 0);
|
||||
if (e.pageX || e.pageY) {
|
||||
m.page.x = (!e.pageX || e.pageX < 0) ? 0 : e.pageX;
|
||||
m.page.y = (!e.pageY || e.pageY < 0) ? 0 : e.pageY;
|
||||
} else {
|
||||
/*
|
||||
|
||||
IE keeps the document offset in:
|
||||
document.documentElement.clientTop ||
|
||||
document.body.clientTop
|
||||
|
||||
and:
|
||||
document.documentElement.clientLeft ||
|
||||
document.body.clientLeft
|
||||
|
||||
see:
|
||||
http://msdn.microsoft.com/workshop/author/dhtml/reference/methods/getboundingclientrect.asp
|
||||
|
||||
The offset is (2,2) in standards mode and (0,0) in quirks
|
||||
mode.
|
||||
|
||||
*/
|
||||
|
||||
var de = MochiKit.DOM._document.documentElement;
|
||||
var b = MochiKit.DOM._document.body;
|
||||
|
||||
m.page.x = e.clientX +
|
||||
(de.scrollLeft || b.scrollLeft) -
|
||||
(de.clientLeft || b.clientLeft);
|
||||
|
||||
m.page.y = e.clientY +
|
||||
(de.scrollTop || b.scrollTop) -
|
||||
(de.clientTop || b.clientTop);
|
||||
|
||||
}
|
||||
if (this.type() != 'mousemove') {
|
||||
m.button = {};
|
||||
m.button.left = false;
|
||||
m.button.right = false;
|
||||
m.button.middle = false;
|
||||
|
||||
/* we could check e.button, but which is more consistent */
|
||||
if (e.which) {
|
||||
m.button.left = (e.which == 1);
|
||||
m.button.middle = (e.which == 2);
|
||||
m.button.right = (e.which == 3);
|
||||
|
||||
/*
|
||||
|
||||
Mac browsers and right click:
|
||||
|
||||
- Safari doesn't fire any click events on a right
|
||||
click:
|
||||
http://bugzilla.opendarwin.org/show_bug.cgi?id=6595
|
||||
|
||||
- Firefox fires the event, and sets ctrlKey = true
|
||||
|
||||
- Opera fires the event, and sets metaKey = true
|
||||
|
||||
oncontextmenu is fired on right clicks between
|
||||
browsers and across platforms.
|
||||
|
||||
*/
|
||||
|
||||
} else {
|
||||
m.button.left = !!(e.button & 1);
|
||||
m.button.right = !!(e.button & 2);
|
||||
m.button.middle = !!(e.button & 4);
|
||||
}
|
||||
}
|
||||
return m;
|
||||
}
|
||||
// throw new Error('This is not a mouse event');
|
||||
return undefined;
|
||||
},
|
||||
|
||||
stop: function () {
|
||||
this.stopPropagation();
|
||||
this.preventDefault();
|
||||
},
|
||||
|
||||
stopPropagation: function () {
|
||||
if (this._event.stopPropagation) {
|
||||
this._event.stopPropagation();
|
||||
} else {
|
||||
this._event.cancelBubble = true;
|
||||
}
|
||||
},
|
||||
|
||||
preventDefault: function () {
|
||||
if (this._event.preventDefault) {
|
||||
this._event.preventDefault();
|
||||
} else {
|
||||
this._event.returnValue = false;
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
/* Safari sets keyCode to these special values onkeypress. */
|
||||
MochiKit.Signal._specialMacKeys = {
|
||||
3: 'KEY_ENTER',
|
||||
63289: 'KEY_NUM_PAD_CLEAR',
|
||||
63276: 'KEY_PAGE_UP',
|
||||
63277: 'KEY_PAGE_DOWN',
|
||||
63275: 'KEY_END',
|
||||
63273: 'KEY_HOME',
|
||||
63234: 'KEY_ARROW_LEFT',
|
||||
63232: 'KEY_ARROW_UP',
|
||||
63235: 'KEY_ARROW_RIGHT',
|
||||
63233: 'KEY_ARROW_DOWN',
|
||||
63302: 'KEY_INSERT',
|
||||
63272: 'KEY_DELETE'
|
||||
};
|
||||
|
||||
/* for KEY_F1 - KEY_F12 */
|
||||
for (i = 63236; i <= 63242; i++) {
|
||||
MochiKit.Signal._specialMacKeys[i] = 'KEY_F' + (i - 63236 + 1); // no F0
|
||||
}
|
||||
|
||||
/* Standard keyboard key codes. */
|
||||
MochiKit.Signal._specialKeys = {
|
||||
8: 'KEY_BACKSPACE',
|
||||
9: 'KEY_TAB',
|
||||
12: 'KEY_NUM_PAD_CLEAR', // weird, for Safari and Mac FF only
|
||||
13: 'KEY_ENTER',
|
||||
16: 'KEY_SHIFT',
|
||||
17: 'KEY_CTRL',
|
||||
18: 'KEY_ALT',
|
||||
19: 'KEY_PAUSE',
|
||||
20: 'KEY_CAPS_LOCK',
|
||||
27: 'KEY_ESCAPE',
|
||||
32: 'KEY_SPACEBAR',
|
||||
33: 'KEY_PAGE_UP',
|
||||
34: 'KEY_PAGE_DOWN',
|
||||
35: 'KEY_END',
|
||||
36: 'KEY_HOME',
|
||||
37: 'KEY_ARROW_LEFT',
|
||||
38: 'KEY_ARROW_UP',
|
||||
39: 'KEY_ARROW_RIGHT',
|
||||
40: 'KEY_ARROW_DOWN',
|
||||
44: 'KEY_PRINT_SCREEN',
|
||||
45: 'KEY_INSERT',
|
||||
46: 'KEY_DELETE',
|
||||
59: 'KEY_SEMICOLON', // weird, for Safari and IE only
|
||||
91: 'KEY_WINDOWS_LEFT',
|
||||
92: 'KEY_WINDOWS_RIGHT',
|
||||
93: 'KEY_SELECT',
|
||||
106: 'KEY_NUM_PAD_ASTERISK',
|
||||
107: 'KEY_NUM_PAD_PLUS_SIGN',
|
||||
109: 'KEY_NUM_PAD_HYPHEN-MINUS',
|
||||
110: 'KEY_NUM_PAD_FULL_STOP',
|
||||
111: 'KEY_NUM_PAD_SOLIDUS',
|
||||
144: 'KEY_NUM_LOCK',
|
||||
145: 'KEY_SCROLL_LOCK',
|
||||
186: 'KEY_SEMICOLON',
|
||||
187: 'KEY_EQUALS_SIGN',
|
||||
188: 'KEY_COMMA',
|
||||
189: 'KEY_HYPHEN-MINUS',
|
||||
190: 'KEY_FULL_STOP',
|
||||
191: 'KEY_SOLIDUS',
|
||||
192: 'KEY_GRAVE_ACCENT',
|
||||
219: 'KEY_LEFT_SQUARE_BRACKET',
|
||||
220: 'KEY_REVERSE_SOLIDUS',
|
||||
221: 'KEY_RIGHT_SQUARE_BRACKET',
|
||||
222: 'KEY_APOSTROPHE'
|
||||
// undefined: 'KEY_UNKNOWN'
|
||||
};
|
||||
|
||||
/* for KEY_0 - KEY_9 */
|
||||
for (var i = 48; i <= 57; i++) {
|
||||
MochiKit.Signal._specialKeys[i] = 'KEY_' + (i - 48);
|
||||
}
|
||||
|
||||
/* for KEY_A - KEY_Z */
|
||||
for (i = 65; i <= 90; i++) {
|
||||
MochiKit.Signal._specialKeys[i] = 'KEY_' + String.fromCharCode(i);
|
||||
}
|
||||
|
||||
/* for KEY_NUM_PAD_0 - KEY_NUM_PAD_9 */
|
||||
for (i = 96; i <= 105; i++) {
|
||||
MochiKit.Signal._specialKeys[i] = 'KEY_NUM_PAD_' + (i - 96);
|
||||
}
|
||||
|
||||
/* for KEY_F1 - KEY_F12 */
|
||||
for (i = 112; i <= 123; i++) {
|
||||
MochiKit.Signal._specialKeys[i] = 'KEY_F' + (i - 112 + 1); // no F0
|
||||
}
|
||||
|
||||
MochiKit.Base.update(MochiKit.Signal, {
|
||||
|
||||
__repr__: function () {
|
||||
return '[' + this.NAME + ' ' + this.VERSION + ']';
|
||||
},
|
||||
|
||||
toString: function () {
|
||||
return this.__repr__();
|
||||
},
|
||||
|
||||
_unloadCache: function () {
|
||||
var self = MochiKit.Signal;
|
||||
var observers = self._observers;
|
||||
|
||||
for (var i = 0; i < observers.length; i++) {
|
||||
self._disconnect(observers[i]);
|
||||
}
|
||||
|
||||
delete self._observers;
|
||||
|
||||
try {
|
||||
window.onload = undefined;
|
||||
} catch(e) {
|
||||
// pass
|
||||
}
|
||||
|
||||
try {
|
||||
window.onunload = undefined;
|
||||
} catch(e) {
|
||||
// pass
|
||||
}
|
||||
},
|
||||
|
||||
_listener: function (src, func, obj, isDOM) {
|
||||
var E = MochiKit.Signal.Event;
|
||||
if (!isDOM) {
|
||||
return MochiKit.Base.bind(func, obj);
|
||||
}
|
||||
obj = obj || src;
|
||||
if (typeof(func) == "string") {
|
||||
return function (nativeEvent) {
|
||||
obj[func].apply(obj, [new E(src, nativeEvent)]);
|
||||
};
|
||||
} else {
|
||||
return function (nativeEvent) {
|
||||
func.apply(obj, [new E(src, nativeEvent)]);
|
||||
};
|
||||
}
|
||||
},
|
||||
|
||||
connect: function (src, sig, objOrFunc/* optional */, funcOrStr) {
|
||||
src = MochiKit.DOM.getElement(src);
|
||||
var self = MochiKit.Signal;
|
||||
|
||||
if (typeof(sig) != 'string') {
|
||||
throw new Error("'sig' must be a string");
|
||||
}
|
||||
|
||||
var obj = null;
|
||||
var func = null;
|
||||
if (typeof(funcOrStr) != 'undefined') {
|
||||
obj = objOrFunc;
|
||||
func = funcOrStr;
|
||||
if (typeof(funcOrStr) == 'string') {
|
||||
if (typeof(objOrFunc[funcOrStr]) != "function") {
|
||||
throw new Error("'funcOrStr' must be a function on 'objOrFunc'");
|
||||
}
|
||||
} else if (typeof(funcOrStr) != 'function') {
|
||||
throw new Error("'funcOrStr' must be a function or string");
|
||||
}
|
||||
} else if (typeof(objOrFunc) != "function") {
|
||||
throw new Error("'objOrFunc' must be a function if 'funcOrStr' is not given");
|
||||
} else {
|
||||
func = objOrFunc;
|
||||
}
|
||||
if (typeof(obj) == 'undefined' || obj === null) {
|
||||
obj = src;
|
||||
}
|
||||
|
||||
var isDOM = !!(src.addEventListener || src.attachEvent);
|
||||
var listener = self._listener(src, func, obj, isDOM);
|
||||
|
||||
if (src.addEventListener) {
|
||||
src.addEventListener(sig.substr(2), listener, false);
|
||||
} else if (src.attachEvent) {
|
||||
src.attachEvent(sig, listener); // useCapture unsupported
|
||||
}
|
||||
|
||||
var ident = [src, sig, listener, isDOM, objOrFunc, funcOrStr];
|
||||
self._observers.push(ident);
|
||||
|
||||
|
||||
return ident;
|
||||
},
|
||||
|
||||
_disconnect: function (ident) {
|
||||
// check isDOM
|
||||
if (!ident[3]) { return; }
|
||||
var src = ident[0];
|
||||
var sig = ident[1];
|
||||
var listener = ident[2];
|
||||
if (src.removeEventListener) {
|
||||
src.removeEventListener(sig.substr(2), listener, false);
|
||||
} else if (src.detachEvent) {
|
||||
src.detachEvent(sig, listener); // useCapture unsupported
|
||||
} else {
|
||||
throw new Error("'src' must be a DOM element");
|
||||
}
|
||||
},
|
||||
|
||||
disconnect: function (ident) {
|
||||
var self = MochiKit.Signal;
|
||||
var observers = self._observers;
|
||||
var m = MochiKit.Base;
|
||||
if (arguments.length > 1) {
|
||||
// compatibility API
|
||||
var src = MochiKit.DOM.getElement(arguments[0]);
|
||||
var sig = arguments[1];
|
||||
var obj = arguments[2];
|
||||
var func = arguments[3];
|
||||
for (var i = observers.length - 1; i >= 0; i--) {
|
||||
var o = observers[i];
|
||||
if (o[0] === src && o[1] === sig && o[4] === obj && o[5] === func) {
|
||||
self._disconnect(o);
|
||||
observers.splice(i, 1);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
var idx = m.findIdentical(observers, ident);
|
||||
if (idx >= 0) {
|
||||
self._disconnect(ident);
|
||||
observers.splice(idx, 1);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
disconnectAll: function(src/* optional */, sig) {
|
||||
src = MochiKit.DOM.getElement(src);
|
||||
var m = MochiKit.Base;
|
||||
var signals = m.flattenArguments(m.extend(null, arguments, 1));
|
||||
var self = MochiKit.Signal;
|
||||
var disconnect = self._disconnect;
|
||||
var observers = self._observers;
|
||||
if (signals.length === 0) {
|
||||
// disconnect all
|
||||
for (var i = observers.length - 1; i >= 0; i--) {
|
||||
var ident = observers[i];
|
||||
if (ident[0] === src) {
|
||||
disconnect(ident);
|
||||
observers.splice(i, 1);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
var sigs = {};
|
||||
for (var i = 0; i < signals.length; i++) {
|
||||
sigs[signals[i]] = true;
|
||||
}
|
||||
for (var i = observers.length - 1; i >= 0; i--) {
|
||||
var ident = observers[i];
|
||||
if (ident[0] === src && ident[1] in sigs) {
|
||||
disconnect(ident);
|
||||
observers.splice(i, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
signal: function (src, sig) {
|
||||
var observers = MochiKit.Signal._observers;
|
||||
src = MochiKit.DOM.getElement(src);
|
||||
var args = MochiKit.Base.extend(null, arguments, 2);
|
||||
var errors = [];
|
||||
for (var i = 0; i < observers.length; i++) {
|
||||
var ident = observers[i];
|
||||
if (ident[0] === src && ident[1] === sig) {
|
||||
try {
|
||||
ident[2].apply(src, args);
|
||||
} catch (e) {
|
||||
errors.push(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (errors.length == 1) {
|
||||
throw errors[0];
|
||||
} else if (errors.length > 1) {
|
||||
var e = new Error("Multiple errors thrown in handling 'sig', see errors property");
|
||||
e.errors = errors;
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
MochiKit.Signal.EXPORT_OK = [];
|
||||
|
||||
MochiKit.Signal.EXPORT = [
|
||||
'connect',
|
||||
'disconnect',
|
||||
'signal',
|
||||
'disconnectAll'
|
||||
];
|
||||
|
||||
MochiKit.Signal.__new__ = function (win) {
|
||||
var m = MochiKit.Base;
|
||||
this._document = document;
|
||||
this._window = win;
|
||||
|
||||
try {
|
||||
this.connect(window, 'onunload', this._unloadCache);
|
||||
} catch (e) {
|
||||
// pass: might not be a browser
|
||||
}
|
||||
|
||||
this.EXPORT_TAGS = {
|
||||
':common': this.EXPORT,
|
||||
':all': m.concat(this.EXPORT, this.EXPORT_OK)
|
||||
};
|
||||
|
||||
m.nameFunctions(this);
|
||||
};
|
||||
|
||||
MochiKit.Signal.__new__(this);
|
||||
|
||||
//
|
||||
// XXX: Internet Explorer blows
|
||||
//
|
||||
if (!MochiKit.__compat__) {
|
||||
connect = MochiKit.Signal.connect;
|
||||
disconnect = MochiKit.Signal.disconnect;
|
||||
disconnectAll = MochiKit.Signal.disconnectAll;
|
||||
signal = MochiKit.Signal.signal;
|
||||
}
|
||||
|
||||
MochiKit.Base._exportSymbols(this, MochiKit.Signal);
|
||||
@@ -1,181 +0,0 @@
|
||||
/***
|
||||
|
||||
MochiKit.Test 1.3.1
|
||||
|
||||
See <http://mochikit.com/> for documentation, downloads, license, etc.
|
||||
|
||||
(c) 2005 Bob Ippolito. All rights Reserved.
|
||||
|
||||
***/
|
||||
|
||||
if (typeof(dojo) != 'undefined') {
|
||||
dojo.provide('MochiKit.Test');
|
||||
dojo.require('MochiKit.Base');
|
||||
}
|
||||
|
||||
if (typeof(JSAN) != 'undefined') {
|
||||
JSAN.use("MochiKit.Base", []);
|
||||
}
|
||||
|
||||
try {
|
||||
if (typeof(MochiKit.Base) == 'undefined') {
|
||||
throw "";
|
||||
}
|
||||
} catch (e) {
|
||||
throw "MochiKit.Test depends on MochiKit.Base!";
|
||||
}
|
||||
|
||||
if (typeof(MochiKit.Test) == 'undefined') {
|
||||
MochiKit.Test = {};
|
||||
}
|
||||
|
||||
MochiKit.Test.NAME = "MochiKit.Test";
|
||||
MochiKit.Test.VERSION = "1.3.1";
|
||||
MochiKit.Test.__repr__ = function () {
|
||||
return "[" + this.NAME + " " + this.VERSION + "]";
|
||||
};
|
||||
|
||||
MochiKit.Test.toString = function () {
|
||||
return this.__repr__();
|
||||
};
|
||||
|
||||
|
||||
MochiKit.Test.EXPORT = ["runTests"];
|
||||
MochiKit.Test.EXPORT_OK = [];
|
||||
|
||||
MochiKit.Test.runTests = function (obj) {
|
||||
if (typeof(obj) == "string") {
|
||||
obj = JSAN.use(obj);
|
||||
}
|
||||
var suite = new MochiKit.Test.Suite();
|
||||
suite.run(obj);
|
||||
};
|
||||
|
||||
MochiKit.Test.Suite = function () {
|
||||
this.testIndex = 0;
|
||||
MochiKit.Base.bindMethods(this);
|
||||
};
|
||||
|
||||
MochiKit.Test.Suite.prototype = {
|
||||
run: function (obj) {
|
||||
try {
|
||||
obj(this);
|
||||
} catch (e) {
|
||||
this.traceback(e);
|
||||
}
|
||||
},
|
||||
traceback: function (e) {
|
||||
var items = MochiKit.Iter.sorted(MochiKit.Base.items(e));
|
||||
print("not ok " + this.testIndex + " - Error thrown");
|
||||
for (var i = 0; i < items.length; i++) {
|
||||
var kv = items[i];
|
||||
if (kv[0] == "stack") {
|
||||
kv[1] = kv[1].split(/\n/)[0];
|
||||
}
|
||||
this.print("# " + kv.join(": "));
|
||||
}
|
||||
},
|
||||
print: function (s) {
|
||||
print(s);
|
||||
},
|
||||
is: function (got, expected, /* optional */message) {
|
||||
var res = 1;
|
||||
var msg = null;
|
||||
try {
|
||||
res = MochiKit.Base.compare(got, expected);
|
||||
} catch (e) {
|
||||
msg = "Can not compare " + typeof(got) + ":" + typeof(expected);
|
||||
}
|
||||
if (res) {
|
||||
msg = "Expected value did not compare equal";
|
||||
}
|
||||
if (!res) {
|
||||
return this.testResult(true, message);
|
||||
}
|
||||
return this.testResult(false, message,
|
||||
[[msg], ["got:", got], ["expected:", expected]]);
|
||||
},
|
||||
|
||||
testResult: function (pass, msg, failures) {
|
||||
this.testIndex += 1;
|
||||
if (pass) {
|
||||
this.print("ok " + this.testIndex + " - " + msg);
|
||||
return;
|
||||
}
|
||||
this.print("not ok " + this.testIndex + " - " + msg);
|
||||
if (failures) {
|
||||
for (var i = 0; i < failures.length; i++) {
|
||||
this.print("# " + failures[i].join(" "));
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
isDeeply: function (got, expected, /* optional */message) {
|
||||
var m = MochiKit.Base;
|
||||
var res = 1;
|
||||
try {
|
||||
res = m.compare(got, expected);
|
||||
} catch (e) {
|
||||
// pass
|
||||
}
|
||||
if (res === 0) {
|
||||
return this.ok(true, message);
|
||||
}
|
||||
var gk = m.keys(got);
|
||||
var ek = m.keys(expected);
|
||||
gk.sort();
|
||||
ek.sort();
|
||||
if (m.compare(gk, ek)) {
|
||||
// differing keys
|
||||
var cmp = {};
|
||||
var i;
|
||||
for (i = 0; i < gk.length; i++) {
|
||||
cmp[gk[i]] = "got";
|
||||
}
|
||||
for (i = 0; i < ek.length; i++) {
|
||||
if (ek[i] in cmp) {
|
||||
delete cmp[ek[i]];
|
||||
} else {
|
||||
cmp[ek[i]] = "expected";
|
||||
}
|
||||
}
|
||||
var diffkeys = m.keys(cmp);
|
||||
diffkeys.sort();
|
||||
var gotkeys = [];
|
||||
var expkeys = [];
|
||||
while (diffkeys.length) {
|
||||
var k = diffkeys.shift();
|
||||
if (k in Object.prototype) {
|
||||
continue;
|
||||
}
|
||||
(cmp[k] == "got" ? gotkeys : expkeys).push(k);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
return this.testResult((!res), msg,
|
||||
(msg ? [["got:", got], ["expected:", expected]] : undefined)
|
||||
);
|
||||
},
|
||||
|
||||
ok: function (res, message) {
|
||||
return this.testResult(res, message);
|
||||
}
|
||||
};
|
||||
|
||||
MochiKit.Test.__new__ = function () {
|
||||
var m = MochiKit.Base;
|
||||
|
||||
this.EXPORT_TAGS = {
|
||||
":common": this.EXPORT,
|
||||
":all": m.concat(this.EXPORT, this.EXPORT_OK)
|
||||
};
|
||||
|
||||
m.nameFunctions(this);
|
||||
|
||||
};
|
||||
|
||||
MochiKit.Test.__new__();
|
||||
|
||||
MochiKit.Base._exportSymbols(this, MochiKit.Test);
|
||||
@@ -1,402 +0,0 @@
|
||||
/***
|
||||
|
||||
MochiKit.Visual 1.3.1
|
||||
|
||||
See <http://mochikit.com/> for documentation, downloads, license, etc.
|
||||
|
||||
(c) 2005 Bob Ippolito and others. All rights Reserved.
|
||||
|
||||
***/
|
||||
|
||||
if (typeof(dojo) != 'undefined') {
|
||||
dojo.provide('MochiKit.Visual');
|
||||
dojo.require('MochiKit.Base');
|
||||
dojo.require('MochiKit.DOM');
|
||||
dojo.require('MochiKit.Color');
|
||||
}
|
||||
|
||||
if (typeof(JSAN) != 'undefined') {
|
||||
JSAN.use("MochiKit.Base", []);
|
||||
JSAN.use("MochiKit.DOM", []);
|
||||
JSAN.use("MochiKit.Color", []);
|
||||
}
|
||||
|
||||
try {
|
||||
if (typeof(MochiKit.Base) == 'undefined' ||
|
||||
typeof(MochiKit.DOM) == 'undefined' ||
|
||||
typeof(MochiKit.Color) == 'undefined') {
|
||||
throw "";
|
||||
}
|
||||
} catch (e) {
|
||||
throw "MochiKit.Visual depends on MochiKit.Base, MochiKit.DOM and MochiKit.Color!";
|
||||
}
|
||||
|
||||
if (typeof(MochiKit.Visual) == "undefined") {
|
||||
MochiKit.Visual = {};
|
||||
}
|
||||
|
||||
MochiKit.Visual.NAME = "MochiKit.Visual";
|
||||
MochiKit.Visual.VERSION = "1.3.1";
|
||||
|
||||
MochiKit.Visual.__repr__ = function () {
|
||||
return "[" + this.NAME + " " + this.VERSION + "]";
|
||||
};
|
||||
|
||||
MochiKit.Visual.toString = function () {
|
||||
return this.__repr__();
|
||||
};
|
||||
|
||||
|
||||
MochiKit.Visual._RoundCorners = function (e, options) {
|
||||
e = MochiKit.DOM.getElement(e);
|
||||
this._setOptions(options);
|
||||
if (this.options.__unstable__wrapElement) {
|
||||
e = this._doWrap(e);
|
||||
}
|
||||
|
||||
var color = this.options.color;
|
||||
var C = MochiKit.Color.Color;
|
||||
if (this.options.color == "fromElement") {
|
||||
color = C.fromBackground(e);
|
||||
} else if (!(color instanceof C)) {
|
||||
color = C.fromString(color);
|
||||
}
|
||||
this.isTransparent = (color.asRGB().a <= 0);
|
||||
|
||||
var bgColor = this.options.bgColor;
|
||||
if (this.options.bgColor == "fromParent") {
|
||||
bgColor = C.fromBackground(e.offsetParent);
|
||||
} else if (!(bgColor instanceof C)) {
|
||||
bgColor = C.fromString(bgColor);
|
||||
}
|
||||
|
||||
this._roundCornersImpl(e, color, bgColor);
|
||||
};
|
||||
|
||||
MochiKit.Visual._RoundCorners.prototype = {
|
||||
_doWrap: function (e) {
|
||||
var parent = e.parentNode;
|
||||
var doc = MochiKit.DOM.currentDocument();
|
||||
if (typeof(doc.defaultView) == "undefined"
|
||||
|| doc.defaultView === null) {
|
||||
return e;
|
||||
}
|
||||
var style = doc.defaultView.getComputedStyle(e, null);
|
||||
if (typeof(style) == "undefined" || style === null) {
|
||||
return e;
|
||||
}
|
||||
var wrapper = MochiKit.DOM.DIV({"style": {
|
||||
display: "block",
|
||||
// convert padding to margin
|
||||
marginTop: style.getPropertyValue("padding-top"),
|
||||
marginRight: style.getPropertyValue("padding-right"),
|
||||
marginBottom: style.getPropertyValue("padding-bottom"),
|
||||
marginLeft: style.getPropertyValue("padding-left"),
|
||||
// remove padding so the rounding looks right
|
||||
padding: "0px"
|
||||
/*
|
||||
paddingRight: "0px",
|
||||
paddingLeft: "0px"
|
||||
*/
|
||||
}});
|
||||
wrapper.innerHTML = e.innerHTML;
|
||||
e.innerHTML = "";
|
||||
e.appendChild(wrapper);
|
||||
return e;
|
||||
},
|
||||
|
||||
_roundCornersImpl: function (e, color, bgColor) {
|
||||
if (this.options.border) {
|
||||
this._renderBorder(e, bgColor);
|
||||
}
|
||||
if (this._isTopRounded()) {
|
||||
this._roundTopCorners(e, color, bgColor);
|
||||
}
|
||||
if (this._isBottomRounded()) {
|
||||
this._roundBottomCorners(e, color, bgColor);
|
||||
}
|
||||
},
|
||||
|
||||
_renderBorder: function (el, bgColor) {
|
||||
var borderValue = "1px solid " + this._borderColor(bgColor);
|
||||
var borderL = "border-left: " + borderValue;
|
||||
var borderR = "border-right: " + borderValue;
|
||||
var style = "style='" + borderL + ";" + borderR + "'";
|
||||
el.innerHTML = "<div " + style + ">" + el.innerHTML + "</div>";
|
||||
},
|
||||
|
||||
_roundTopCorners: function (el, color, bgColor) {
|
||||
var corner = this._createCorner(bgColor);
|
||||
for (var i = 0; i < this.options.numSlices; i++) {
|
||||
corner.appendChild(
|
||||
this._createCornerSlice(color, bgColor, i, "top")
|
||||
);
|
||||
}
|
||||
el.style.paddingTop = 0;
|
||||
el.insertBefore(corner, el.firstChild);
|
||||
},
|
||||
|
||||
_roundBottomCorners: function (el, color, bgColor) {
|
||||
var corner = this._createCorner(bgColor);
|
||||
for (var i = (this.options.numSlices - 1); i >= 0; i--) {
|
||||
corner.appendChild(
|
||||
this._createCornerSlice(color, bgColor, i, "bottom")
|
||||
);
|
||||
}
|
||||
el.style.paddingBottom = 0;
|
||||
el.appendChild(corner);
|
||||
},
|
||||
|
||||
_createCorner: function (bgColor) {
|
||||
var dom = MochiKit.DOM;
|
||||
return dom.DIV({style: {backgroundColor: bgColor.toString()}});
|
||||
},
|
||||
|
||||
_createCornerSlice: function (color, bgColor, n, position) {
|
||||
var slice = MochiKit.DOM.SPAN();
|
||||
|
||||
var inStyle = slice.style;
|
||||
inStyle.backgroundColor = color.toString();
|
||||
inStyle.display = "block";
|
||||
inStyle.height = "1px";
|
||||
inStyle.overflow = "hidden";
|
||||
inStyle.fontSize = "1px";
|
||||
|
||||
var borderColor = this._borderColor(color, bgColor);
|
||||
if (this.options.border && n === 0) {
|
||||
inStyle.borderTopStyle = "solid";
|
||||
inStyle.borderTopWidth = "1px";
|
||||
inStyle.borderLeftWidth = "0px";
|
||||
inStyle.borderRightWidth = "0px";
|
||||
inStyle.borderBottomWidth = "0px";
|
||||
// assumes css compliant box model
|
||||
inStyle.height = "0px";
|
||||
inStyle.borderColor = borderColor.toString();
|
||||
} else if (borderColor) {
|
||||
inStyle.borderColor = borderColor.toString();
|
||||
inStyle.borderStyle = "solid";
|
||||
inStyle.borderWidth = "0px 1px";
|
||||
}
|
||||
|
||||
if (!this.options.compact && (n == (this.options.numSlices - 1))) {
|
||||
inStyle.height = "2px";
|
||||
}
|
||||
|
||||
this._setMargin(slice, n, position);
|
||||
this._setBorder(slice, n, position);
|
||||
|
||||
return slice;
|
||||
},
|
||||
|
||||
_setOptions: function (options) {
|
||||
this.options = {
|
||||
corners: "all",
|
||||
color: "fromElement",
|
||||
bgColor: "fromParent",
|
||||
blend: true,
|
||||
border: false,
|
||||
compact: false,
|
||||
__unstable__wrapElement: false
|
||||
};
|
||||
MochiKit.Base.update(this.options, options);
|
||||
|
||||
this.options.numSlices = (this.options.compact ? 2 : 4);
|
||||
},
|
||||
|
||||
_whichSideTop: function () {
|
||||
var corners = this.options.corners;
|
||||
if (this._hasString(corners, "all", "top")) {
|
||||
return "";
|
||||
}
|
||||
|
||||
var has_tl = (corners.indexOf("tl") != -1);
|
||||
var has_tr = (corners.indexOf("tr") != -1);
|
||||
if (has_tl && has_tr) {
|
||||
return "";
|
||||
}
|
||||
if (has_tl) {
|
||||
return "left";
|
||||
}
|
||||
if (has_tr) {
|
||||
return "right";
|
||||
}
|
||||
return "";
|
||||
},
|
||||
|
||||
_whichSideBottom: function () {
|
||||
var corners = this.options.corners;
|
||||
if (this._hasString(corners, "all", "bottom")) {
|
||||
return "";
|
||||
}
|
||||
|
||||
var has_bl = (corners.indexOf('bl') != -1);
|
||||
var has_br = (corners.indexOf('br') != -1);
|
||||
if (has_bl && has_br) {
|
||||
return "";
|
||||
}
|
||||
if (has_bl) {
|
||||
return "left";
|
||||
}
|
||||
if (has_br) {
|
||||
return "right";
|
||||
}
|
||||
return "";
|
||||
},
|
||||
|
||||
_borderColor: function (color, bgColor) {
|
||||
if (color == "transparent") {
|
||||
return bgColor;
|
||||
} else if (this.options.border) {
|
||||
return this.options.border;
|
||||
} else if (this.options.blend) {
|
||||
return bgColor.blendedColor(color);
|
||||
}
|
||||
return "";
|
||||
},
|
||||
|
||||
|
||||
_setMargin: function (el, n, corners) {
|
||||
var marginSize = this._marginSize(n) + "px";
|
||||
var whichSide = (
|
||||
corners == "top" ? this._whichSideTop() : this._whichSideBottom()
|
||||
);
|
||||
var style = el.style;
|
||||
|
||||
if (whichSide == "left") {
|
||||
style.marginLeft = marginSize;
|
||||
style.marginRight = "0px";
|
||||
} else if (whichSide == "right") {
|
||||
style.marginRight = marginSize;
|
||||
style.marginLeft = "0px";
|
||||
} else {
|
||||
style.marginLeft = marginSize;
|
||||
style.marginRight = marginSize;
|
||||
}
|
||||
},
|
||||
|
||||
_setBorder: function (el, n, corners) {
|
||||
var borderSize = this._borderSize(n) + "px";
|
||||
var whichSide = (
|
||||
corners == "top" ? this._whichSideTop() : this._whichSideBottom()
|
||||
);
|
||||
|
||||
var style = el.style;
|
||||
if (whichSide == "left") {
|
||||
style.borderLeftWidth = borderSize;
|
||||
style.borderRightWidth = "0px";
|
||||
} else if (whichSide == "right") {
|
||||
style.borderRightWidth = borderSize;
|
||||
style.borderLeftWidth = "0px";
|
||||
} else {
|
||||
style.borderLeftWidth = borderSize;
|
||||
style.borderRightWidth = borderSize;
|
||||
}
|
||||
},
|
||||
|
||||
_marginSize: function (n) {
|
||||
if (this.isTransparent) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
var o = this.options;
|
||||
if (o.compact && o.blend) {
|
||||
var smBlendedMarginSizes = [1, 0];
|
||||
return smBlendedMarginSizes[n];
|
||||
} else if (o.compact) {
|
||||
var compactMarginSizes = [2, 1];
|
||||
return compactMarginSizes[n];
|
||||
} else if (o.blend) {
|
||||
var blendedMarginSizes = [3, 2, 1, 0];
|
||||
return blendedMarginSizes[n];
|
||||
} else {
|
||||
var marginSizes = [5, 3, 2, 1];
|
||||
return marginSizes[n];
|
||||
}
|
||||
},
|
||||
|
||||
_borderSize: function (n) {
|
||||
var o = this.options;
|
||||
var borderSizes;
|
||||
if (o.compact && (o.blend || this.isTransparent)) {
|
||||
return 1;
|
||||
} else if (o.compact) {
|
||||
borderSizes = [1, 0];
|
||||
} else if (o.blend) {
|
||||
borderSizes = [2, 1, 1, 1];
|
||||
} else if (o.border) {
|
||||
borderSizes = [0, 2, 0, 0];
|
||||
} else if (this.isTransparent) {
|
||||
borderSizes = [5, 3, 2, 1];
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
return borderSizes[n];
|
||||
},
|
||||
|
||||
_hasString: function (str) {
|
||||
for (var i = 1; i< arguments.length; i++) {
|
||||
if (str.indexOf(arguments[i]) != -1) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
_isTopRounded: function () {
|
||||
return this._hasString(this.options.corners,
|
||||
"all", "top", "tl", "tr"
|
||||
);
|
||||
},
|
||||
|
||||
_isBottomRounded: function () {
|
||||
return this._hasString(this.options.corners,
|
||||
"all", "bottom", "bl", "br"
|
||||
);
|
||||
},
|
||||
|
||||
_hasSingleTextChild: function (el) {
|
||||
return (el.childNodes.length == 1 && el.childNodes[0].nodeType == 3);
|
||||
}
|
||||
};
|
||||
|
||||
MochiKit.Visual.roundElement = function (e, options) {
|
||||
new MochiKit.Visual._RoundCorners(e, options);
|
||||
};
|
||||
|
||||
MochiKit.Visual.roundClass = function (tagName, className, options) {
|
||||
var elements = MochiKit.DOM.getElementsByTagAndClassName(
|
||||
tagName, className
|
||||
);
|
||||
for (var i = 0; i < elements.length; i++) {
|
||||
MochiKit.Visual.roundElement(elements[i], options);
|
||||
}
|
||||
};
|
||||
|
||||
// Compatibility with MochiKit 1.0
|
||||
MochiKit.Visual.Color = MochiKit.Color.Color;
|
||||
MochiKit.Visual.getElementsComputedStyle = MochiKit.DOM.computedStyle;
|
||||
|
||||
/* end of Rico adaptation */
|
||||
|
||||
MochiKit.Visual.__new__ = function () {
|
||||
var m = MochiKit.Base;
|
||||
|
||||
m.nameFunctions(this);
|
||||
|
||||
this.EXPORT_TAGS = {
|
||||
":common": this.EXPORT,
|
||||
":all": m.concat(this.EXPORT, this.EXPORT_OK)
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
MochiKit.Visual.EXPORT = [
|
||||
"roundElement",
|
||||
"roundClass"
|
||||
];
|
||||
|
||||
MochiKit.Visual.EXPORT_OK = [];
|
||||
|
||||
MochiKit.Visual.__new__();
|
||||
|
||||
MochiKit.Base._exportSymbols(this, MochiKit.Visual);
|
||||
@@ -1,17 +0,0 @@
|
||||
dojo.hostenv.conditionalLoadModule({
|
||||
"common": [
|
||||
"MochiKit.Base",
|
||||
"MochiKit.Iter",
|
||||
"MochiKit.Logging",
|
||||
"MochiKit.DateTime",
|
||||
"MochiKit.Format",
|
||||
"MochiKit.Async",
|
||||
"MochiKit.Color"
|
||||
],
|
||||
"browser": [
|
||||
"MochiKit.DOM",
|
||||
"MochiKit.LoggingPane",
|
||||
"MochiKit.Visual"
|
||||
]
|
||||
});
|
||||
dojo.hostenv.moduleLoaded("MochiKit.*");
|
||||
|
Before Width: | Height: | Size: 971 B |
|
Before Width: | Height: | Size: 591 B |
@@ -1,163 +0,0 @@
|
||||
/* Copyright (c) 2006 Yahoo! Inc. All rights reserved. */
|
||||
/* Container Styles */
|
||||
|
||||
.calcontainer {*height:1%;} /* IE */
|
||||
.calcontainer:after {content:'.';clear:both;display:block;visibility:hidden;height:0;} /* others */
|
||||
|
||||
.calbordered {
|
||||
float:left;
|
||||
padding:5px;
|
||||
background-color:#F7F9FB;
|
||||
border:1px solid #7B9EBD;
|
||||
}
|
||||
|
||||
.calbordered .title {
|
||||
font:73% Arial,Helvetica,sans-serif;
|
||||
color:#000;
|
||||
font-weight:bold;
|
||||
margin-bottom:5px;
|
||||
height:auto;
|
||||
width:304px;
|
||||
position:relative;
|
||||
}
|
||||
|
||||
.title .close-icon {
|
||||
position:absolute;
|
||||
right:0;
|
||||
top:0;
|
||||
border:none;
|
||||
}
|
||||
|
||||
.cal2up {
|
||||
float:left;
|
||||
}
|
||||
|
||||
.calnavleft {
|
||||
position:absolute;
|
||||
top:0;
|
||||
bottom:0;
|
||||
height:12px;
|
||||
left:2px;
|
||||
}
|
||||
|
||||
.calnavright {
|
||||
position:absolute;
|
||||
top:0;
|
||||
bottom:0;
|
||||
height:12px;
|
||||
right:2px;
|
||||
}
|
||||
|
||||
/* Calendar element styles */
|
||||
|
||||
.calendar {
|
||||
font:73% Arial,Helvetica,sans-serif;
|
||||
text-align:center;
|
||||
border-spacing:0;
|
||||
}
|
||||
|
||||
td.calcell {
|
||||
width:1.5em;
|
||||
height:1em;
|
||||
border:1px solid #E0E0E0;
|
||||
background-color:#FFF;
|
||||
}
|
||||
|
||||
.calendar.wait td.calcell {
|
||||
color:#999;
|
||||
background-color:#CCC;
|
||||
}
|
||||
|
||||
.calendar.wait td.calcell a {
|
||||
color:#999;
|
||||
font-style:italic;
|
||||
}
|
||||
|
||||
td.calcell a {
|
||||
color:#003DB8;
|
||||
text-decoration:none;
|
||||
}
|
||||
|
||||
td.calcell.today {
|
||||
border:1px solid #000;
|
||||
}
|
||||
|
||||
td.calcell.oom {
|
||||
cursor:default;
|
||||
color:#999;
|
||||
background-color:#EEE;
|
||||
border:1px solid #E0E0E0;
|
||||
}
|
||||
|
||||
td.calcell.selected {
|
||||
color:#003DB8;
|
||||
background-color:#FFF19F;
|
||||
border:1px solid #FF9900;
|
||||
}
|
||||
|
||||
td.calcell.calcellhover {
|
||||
cursor:pointer;
|
||||
color:#FFF;
|
||||
background-color:#FF9900;
|
||||
border:1px solid #FF9900;
|
||||
}
|
||||
|
||||
/* Added to perform some correction for Opera 8.5
|
||||
hover redraw bug */
|
||||
table:hover {
|
||||
background-color:#FFF;
|
||||
}
|
||||
|
||||
td.calcell.calcellhover a {
|
||||
color:#FFF;
|
||||
}
|
||||
|
||||
td.calcell.restricted {
|
||||
text-decoration:line-through;
|
||||
}
|
||||
|
||||
td.calcell.previous {
|
||||
color:#CCC;
|
||||
}
|
||||
|
||||
td.calcell.highlight1 { background-color:#CCFF99; }
|
||||
td.calcell.highlight2 { background-color:#99CCFF; }
|
||||
td.calcell.highlight3 { background-color:#FFCCCC; }
|
||||
td.calcell.highlight4 { background-color:#CCFF99; }
|
||||
|
||||
|
||||
.calhead {
|
||||
border:1px solid #E0E0E0;
|
||||
vertical-align:middle;
|
||||
background-color:#FFF;
|
||||
}
|
||||
|
||||
.calheader {
|
||||
position:relative;
|
||||
width:100%;
|
||||
}
|
||||
|
||||
.calheader img {
|
||||
border:none;
|
||||
}
|
||||
|
||||
.calweekdaycell {
|
||||
color:#666;
|
||||
font-weight:normal;
|
||||
}
|
||||
|
||||
.calfoot {
|
||||
background-color:#EEE;
|
||||
}
|
||||
|
||||
.calrowhead, .calrowfoot {
|
||||
color:#666;
|
||||
font-size:9px;
|
||||
font-style:italic;
|
||||
font-weight:normal;
|
||||
width:15px;
|
||||
}
|
||||
|
||||
.calrowhead {
|
||||
border-right-width:2px;
|
||||
}
|
||||
|
Before Width: | Height: | Size: 93 B |
|
Before Width: | Height: | Size: 94 B |
|
Before Width: | Height: | Size: 88 B |
|
Before Width: | Height: | Size: 85 B |
@@ -1,206 +0,0 @@
|
||||
.overlay {
|
||||
position:absolute;
|
||||
display:block;
|
||||
}
|
||||
|
||||
.tt {
|
||||
visibility:hidden;
|
||||
position:absolute;
|
||||
color:#333;
|
||||
background-color:#FDFFB4;
|
||||
font-family:arial,helvetica,verdana,sans-serif;
|
||||
padding:2px;
|
||||
border:1px solid #FCC90D;
|
||||
font:100% sans-serif;
|
||||
width:auto;
|
||||
}
|
||||
|
||||
* html body.masked select {
|
||||
visibility:hidden;
|
||||
}
|
||||
|
||||
* html div.panel-container select {
|
||||
visibility:inherit;
|
||||
}
|
||||
|
||||
* html div.drag select {
|
||||
visibility:hidden;
|
||||
}
|
||||
|
||||
* html div.hide-select select {
|
||||
visibility:hidden;
|
||||
}
|
||||
|
||||
.mask {
|
||||
z-index:0;
|
||||
display:none;
|
||||
position:absolute;
|
||||
top:0;
|
||||
left:0;
|
||||
background-color:#CCC;
|
||||
-moz-opacity: 0.5;
|
||||
opacity:.50;
|
||||
filter: alpha(opacity=50);
|
||||
}
|
||||
.mask[id]{ /* IE6 and below Can't See This */
|
||||
position:fixed;
|
||||
}
|
||||
|
||||
.hide-scrollbars * {
|
||||
overflow:hidden;
|
||||
}
|
||||
|
||||
.hide-scrollbars textarea, .hide-scrollbars select {
|
||||
overflow:hidden;
|
||||
display:none;
|
||||
}
|
||||
|
||||
.show-scrollbars textarea, .show-scrollbars select {
|
||||
overflow:visible;
|
||||
}
|
||||
|
||||
.panel-container {
|
||||
position:absolute;
|
||||
background-color:transparent;
|
||||
z-index:6;
|
||||
visibility:hidden;
|
||||
overflow:visible;
|
||||
width:auto;
|
||||
}
|
||||
|
||||
.panel-container.matte {
|
||||
padding:3px;
|
||||
background-color:#FFF;
|
||||
}
|
||||
|
||||
.panel-container.matte .underlay {
|
||||
display:none;
|
||||
}
|
||||
|
||||
.panel-container.shadow {
|
||||
padding:0px;
|
||||
background-color:transparent;
|
||||
}
|
||||
|
||||
.panel-container.shadow .underlay {
|
||||
visibility:inherit;
|
||||
position:absolute;
|
||||
background-color:#CCC;
|
||||
top:3px;left:3px;
|
||||
z-index:0;
|
||||
width:100%;
|
||||
height:100%;
|
||||
-moz-opacity: 0.7;
|
||||
opacity:.70;
|
||||
filter:alpha(opacity=70);
|
||||
}
|
||||
|
||||
.panel {
|
||||
visibility:hidden;
|
||||
border-collapse:separate;
|
||||
position:relative;
|
||||
left:0px;top:0px;
|
||||
font:1em Arial;
|
||||
background-color:#FFF;
|
||||
border:1px solid #000;
|
||||
z-index:1;
|
||||
overflow:auto;
|
||||
}
|
||||
|
||||
.panel .hd {
|
||||
background-color:#3d77cb;
|
||||
color:#FFF;
|
||||
font-size:1em;
|
||||
height:1em;
|
||||
border:1px solid #FFF;
|
||||
border-bottom:1px solid #000;
|
||||
font-weight:bold;
|
||||
overflow:hidden;
|
||||
padding:4px;
|
||||
}
|
||||
|
||||
.panel .bd {
|
||||
overflow:hidden;
|
||||
padding:4px;
|
||||
}
|
||||
|
||||
.panel .bd p {
|
||||
margin:0 0 1em;
|
||||
}
|
||||
|
||||
.panel .close {
|
||||
position:absolute;
|
||||
top:5px;
|
||||
right:4px;
|
||||
z-index:6;
|
||||
height:12px;
|
||||
width:12px;
|
||||
margin:0px;
|
||||
padding:0px;
|
||||
background-repeat:no-repeat;
|
||||
cursor:pointer;
|
||||
visibility:inherit;
|
||||
}
|
||||
|
||||
.panel .close.nonsecure {
|
||||
background-image:url(http://us.i1.yimg.com/us.yimg.com/i/nt/ic/ut/alt3/close12_1.gif);
|
||||
}
|
||||
|
||||
.panel .close.secure {
|
||||
background-image:url(https://a248.e.akamai.net/sec.yimg.com/i/nt/ic/ut/alt3/close12_1.gif);
|
||||
}
|
||||
|
||||
.panel .ft {
|
||||
padding:4px;
|
||||
overflow:hidden;
|
||||
}
|
||||
|
||||
.simple-dialog .bd .icon {
|
||||
background-repeat:no-repeat;
|
||||
width:16px;
|
||||
height:16px;
|
||||
margin-right:10px;
|
||||
float:left;
|
||||
}
|
||||
|
||||
.dialog .ft, .simple-dialog .ft {
|
||||
padding-bottom:5px;
|
||||
padding-right:5px;
|
||||
text-align:right;
|
||||
}
|
||||
|
||||
.dialog form, .simple-dialog form {
|
||||
margin:0;
|
||||
}
|
||||
|
||||
.button-group button {
|
||||
font:100 76% verdana;
|
||||
text-decoration:none;
|
||||
background-color: #E4E4E4;
|
||||
color: #333;
|
||||
cursor: hand;
|
||||
vertical-align: middle;
|
||||
border: 2px solid #797979;
|
||||
border-top-color:#FFF;
|
||||
border-left-color:#FFF;
|
||||
margin:2px;
|
||||
padding:2px;
|
||||
}
|
||||
|
||||
.button-group button.default {
|
||||
font-weight:bold;
|
||||
}
|
||||
|
||||
.button-group button:hover, .button-group button.hover {
|
||||
border:2px solid #90A029;
|
||||
background-color:#EBF09E;
|
||||
border-top-color:#FFF;
|
||||
border-left-color:#FFF;
|
||||
}
|
||||
|
||||
.button-group button:active {
|
||||
border:2px solid #E4E4E4;
|
||||
background-color:#BBB;
|
||||
border-top-color:#333;
|
||||
border-left-color:#333;
|
||||
}
|
||||
|
Before Width: | Height: | Size: 928 B |
|
Before Width: | Height: | Size: 601 B |
|
Before Width: | Height: | Size: 94 B |
|
Before Width: | Height: | Size: 106 B |
|
Before Width: | Height: | Size: 142 B |
|
Before Width: | Height: | Size: 2.6 KiB |
|
Before Width: | Height: | Size: 130 B |
|
Before Width: | Height: | Size: 111 B |
@@ -1,264 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2006, Yahoo! Inc. All rights reserved.
|
||||
Code licensed under the BSD License:
|
||||
http://developer.yahoo.net/yui/license.txt
|
||||
*/
|
||||
|
||||
|
||||
/* Menu styles */
|
||||
|
||||
div.yuimenu {
|
||||
|
||||
z-index:1;
|
||||
visibility:hidden;
|
||||
background-color:#f6f7ee;
|
||||
border:solid 1px #c4c4be;
|
||||
padding:1px;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* MenuBar Styles */
|
||||
|
||||
div.yuimenubar {
|
||||
|
||||
background-color:#f6f7ee;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
Application of "zoom:1" triggers "haslayout" in IE so that the module's
|
||||
body clears its floated elements
|
||||
*/
|
||||
div.yuimenubar div.bd {
|
||||
|
||||
zoom:1;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
Clear the module body for other browsers
|
||||
*/
|
||||
div.yuimenubar div.bd:after {
|
||||
|
||||
content:'.';
|
||||
display:block;
|
||||
clear:both;
|
||||
visibility:hidden;
|
||||
height:0;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* Matches the group title (H6) inside a Menu or MenuBar instance */
|
||||
|
||||
div.yuimenu h6,
|
||||
div.yuimenubar h6 {
|
||||
|
||||
font-size:100%;
|
||||
font-weight:normal;
|
||||
margin:0;
|
||||
border:solid 1px #c4c4be;
|
||||
color:#b9b9b9;
|
||||
|
||||
}
|
||||
|
||||
div.yuimenubar h6 {
|
||||
|
||||
float:left;
|
||||
display:inline; /* Prevent margin doubling in IE */
|
||||
padding:4px 12px;
|
||||
border-width:0 1px 0 0;
|
||||
|
||||
}
|
||||
|
||||
div.yuimenu h6 {
|
||||
|
||||
float:none;
|
||||
display:block;
|
||||
border-width:1px 0 0 0;
|
||||
padding:5px 10px 0 10px;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* Matches the UL inside a Menu or MenuBar instance */
|
||||
|
||||
div.yuimenubar ul {
|
||||
|
||||
list-style-type:none;
|
||||
margin:0;
|
||||
padding:0;
|
||||
overflow:hidden;
|
||||
|
||||
}
|
||||
|
||||
div.yuimenu ul {
|
||||
|
||||
list-style-type:none;
|
||||
border:solid 1px #c4c4be;
|
||||
border-width:1px 0 0 0;
|
||||
margin:0;
|
||||
padding:10px 0;
|
||||
|
||||
}
|
||||
|
||||
|
||||
div.yuimenu ul.first,
|
||||
div.yuimenu ul.hastitle,
|
||||
div.yuimenu h6.first {
|
||||
|
||||
border-width:0;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* MenuItem and MenuBarItem styles */
|
||||
|
||||
div.yuimenu li,
|
||||
div.yuimenubar li {
|
||||
|
||||
font-size:85%;
|
||||
cursor:pointer;
|
||||
cursor:hand;
|
||||
white-space:nowrap;
|
||||
text-align:left;
|
||||
|
||||
}
|
||||
|
||||
div.yuimenu li.yuimenuitem {
|
||||
|
||||
padding:2px 24px;
|
||||
|
||||
}
|
||||
|
||||
div.yuimenu li li,
|
||||
div.yuimenubar li li {
|
||||
|
||||
font-size:100%;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* Matches the help text for a MenuItem instance */
|
||||
|
||||
div.yuimenu li em {
|
||||
|
||||
font-style:normal;
|
||||
margin:0 0 0 40px;
|
||||
|
||||
}
|
||||
|
||||
div.yuimenu li a em {
|
||||
|
||||
margin:0;
|
||||
|
||||
}
|
||||
|
||||
div.yuimenu li a,
|
||||
div.yuimenubar li a {
|
||||
|
||||
/*
|
||||
"zoom:1" triggers "haslayout" in IE to ensure that the mouseover and
|
||||
mouseout events bubble to the parent LI in IE.
|
||||
*/
|
||||
zoom:1;
|
||||
color:#000;
|
||||
text-decoration:none;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* Matches the sub menu indicator for a MenuItem instance */
|
||||
|
||||
div.yuimenu li img {
|
||||
|
||||
margin:0 -16px 0 10px;
|
||||
border:0;
|
||||
|
||||
}
|
||||
|
||||
div.yuimenu li.hassubmenu,
|
||||
div.yuimenu li.hashelptext {
|
||||
|
||||
text-align:right;
|
||||
|
||||
}
|
||||
|
||||
div.yuimenu li.hassubmenu a.hassubmenu,
|
||||
div.yuimenu li.hashelptext a.hashelptext {
|
||||
|
||||
float:left;
|
||||
display:inline; /* Prevent margin doubling in IE */
|
||||
text-align:left;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* Matches focused and selected MenuItem instances */
|
||||
|
||||
div.yuimenu li.selected,
|
||||
div.yuimenubar li.selected {
|
||||
|
||||
background-color:#8c8ad0;
|
||||
|
||||
}
|
||||
|
||||
div.yuimenu li.selected a.selected,
|
||||
div.yuimenubar li.selected a.selected {
|
||||
|
||||
text-decoration:underline;
|
||||
|
||||
}
|
||||
|
||||
div.yuimenu li.selected a.selected,
|
||||
div.yuimenu li.selected em.selected,
|
||||
div.yuimenubar li.selected a.selected {
|
||||
|
||||
color:#fff;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* Matches disabled MenuItem instances */
|
||||
|
||||
div.yuimenu li.disabled,
|
||||
div.yuimenubar li.disabled {
|
||||
|
||||
cursor:default;
|
||||
|
||||
}
|
||||
|
||||
div.yuimenu li.disabled a.disabled,
|
||||
div.yuimenu li.disabled em.disabled,
|
||||
div.yuimenubar li.disabled a.disabled {
|
||||
|
||||
color:#b9b9b9;
|
||||
cursor:default;
|
||||
|
||||
}
|
||||
|
||||
div.yuimenubar li.yuimenubaritem {
|
||||
|
||||
float:left;
|
||||
display:inline; /* Prevent margin doubling in IE */
|
||||
border-width:0 0 0 1px;
|
||||
border-style:solid;
|
||||
border-color:#c4c4be;
|
||||
padding:4px 24px;
|
||||
margin:0;
|
||||
|
||||
}
|
||||
|
||||
div.yuimenubar li.yuimenubaritem.first {
|
||||
|
||||
border-width:0;
|
||||
|
||||
}
|
||||
|
||||
div.yuimenubar li.yuimenubaritem img {
|
||||
|
||||
margin:0 0 0 10px;
|
||||
vertical-align:middle;
|
||||
|
||||
}
|
||||
|
Before Width: | Height: | Size: 63 B |
|
Before Width: | Height: | Size: 63 B |