Namenskorrektur II

This commit is contained in:
lars 2008-08-23 13:11:19 +00:00
parent c0258314f4
commit 23d54c5ac7
75 changed files with 108 additions and 108 deletions

View file

View file

@ -0,0 +1,53 @@
# -*- coding: utf-8 -*-
"""This module contains functions called from console script entry points."""
import sys
from os import getcwd
from os.path import dirname, exists, join
import pkg_resources
pkg_resources.require("TurboGears>=1.0.4.4")
import cherrypy
import turbogears
cherrypy.lowercase_api = True
class ConfigurationError(Exception):
pass
def start():
"""Start the CherryPy application server."""
setupdir = dirname(dirname(__file__))
curdir = getcwd()
# First look on the command line for a desired config file,
# if it's not on the command line, then look for 'setup.py'
# in the current directory. If there, load configuration
# from a file called 'dev.cfg'. If it's not there, the project
# is probably installed and we'll look first for a file called
# 'prod.cfg' in the current directory and then for a default
# config file called 'default.cfg' packaged in the egg.
if len(sys.argv) > 1:
configfile = sys.argv[1]
elif exists(join(setupdir, "setup.py")):
configfile = join(setupdir, "dev.cfg")
elif exists(join(curdir, "prod.cfg")):
configfile = join(curdir, "prod.cfg")
else:
try:
configfile = pkg_resources.resource_filename(
pkg_resources.Requirement.parse("fotokiosk"),
"config/default.cfg")
except pkg_resources.DistributionNotFound:
raise ConfigurationError("Could not find default configuration.")
turbogears.update_config(configfile=configfile,
modulename="fotokiosk.config")
from fotokiosk.controllers import Root
turbogears.start_server(Root())

View file

View file

@ -0,0 +1,66 @@
[global]
# The settings in this file should not vary depending on the deployment
# environment. dev.cfg and prod.cfg are the locations for
# the different deployment settings. Settings in this file will
# be overridden by settings in those other files.
# The commented out values below are the defaults
# VIEW
# which view (template engine) to use if one is not specified in the
# template name
# tg.defaultview = "kid"
# The following kid settings determine the settings used by the kid serializer.
# Kid output method (e.g. html, html-strict, xhtml, xhtml-strict, xml, json)
# and formatting (e.g. default, straight, compact, newlines, wrap, nice)
# kid.outputformat="html default"
# kid.encoding="utf-8"
# The sitetemplate is used for overall styling of a site that
# includes multiple TurboGears applications
# tg.sitetemplate="<packagename.templates.templatename>"
# Allow every exposed function to be called as json,
# tg.allow_json = False
# Suppress the inclusion of the shipped MochiKit version, which is rather outdated.
# Attention: setting this to True and listing 'turbogears.mochikit' in 'tg.include_widgets'
# is a contradiction. This option will overrule the default-inclusion to prevent version
# mismatch bugs.
# tg.mochikit_suppress = True
# List of Widgets to include on every page.
# for example ['turbogears.mochikit']
# tg.include_widgets = []
# Set to True if the scheduler should be started
# tg.scheduler = False
# Set to True to allow paginate decorator redirects when page number gets
# out of bound. Useful for getting the real page id in the url
# paginate.redirect_on_out_of_range = True
# Set to True to allow paginate decorator redirects when last page is requested.
# This is useful for getting the real last page id in the url
# paginate.redirect_on_last_page = True
# Set session or cookie
# session_filter.on = True
# compress the data sends to the web browser
# [/]
# gzip_filter.on = True
# gzip_filter.mime_types = ["application/x-javascript", "text/javascript", "text/html", "text/css", "text/plain"]
[/static]
static_filter.on = True
static_filter.dir = "%(top_level_dir)s/static"
[/favicon.ico]
static_filter.on = True
static_filter.file = "%(top_level_dir)s/static/images/favicon.ico"

View file

@ -0,0 +1,29 @@
# LOGGING
# Logging is often deployment specific, but some handlers and
# formatters can be defined here.
[logging]
[[formatters]]
[[[message_only]]]
format='*(message)s'
[[[full_content]]]
format='*(asctime)s *(name)s *(levelname)s *(message)s'
[[handlers]]
[[[debug_out]]]
class='StreamHandler'
level='DEBUG'
args='(sys.stdout,)'
formatter='full_content'
[[[access_out]]]
class='StreamHandler'
level='INFO'
args='(sys.stdout,)'
formatter='message_only'
[[[error_out]]]
class='StreamHandler'
level='ERROR'
args='(sys.stdout,)'

View file

@ -0,0 +1,244 @@
# -*- coding: utf-8 -*-
import turbogears as tg
from turbogears import controllers, expose, flash, redirect
# from fotokiosk import model
# import logging
# log = logging.getLogger("fotokiosk.controllers")
class SamplePicture(object):
title = "leer"
url = "nichts"
import os
import urllib
import tempfile
import cherrypy
import re
import datetime
import random
IMAGE_GALLERY_PATH = os.path.join(os.getcwd(), 'fotokiosk', 'static', 'gallery')
IMAGE_SUFFIX = ".jpg"
IMAGE_STORE = os.path.join(tempfile.gettempdir(), "fotokiosk" + IMAGE_SUFFIX)
GALLERY_NUM = 12
VIDEO_URL = "http://fotokiosk:8081/?action=stream"
SNAPSHOT_URL = "http://fotokiosk:8081/?action=snapshot"
ALLOWED_MAILADDRESS_CHARACTERS = "\w._%@-"
ALLOWED_MAILTEXT_CHARACTERS = "\w@_\-\.\s\n\#\(\)\[\]\{\}\|\>\<\,\+/\'\"\?\!\:=%\$^&\*"
MAIL_ADDRESS_REGEX = r"^[a-zA-Z0-9._%-]+@[a-zA-Z0-9._%-]+\.[a-zA-Z]{2,6}$"
# TODO: this path is relative - to be fixed!
MAIL_SIGNATURE_FILE = os.path.join(os.getcwd(), "mail_signature.txt")
MAIL_FROM_ADDRESS = '"Frieda-Fotokiosk" <fotokiosk@glasmensch.org>'
MAIL_SUBJECT = "Ein überwachungskritisches Foto aus der Frieda!"
MAIL_ATTACHMENT_FILENAME = "frieda" + IMAGE_SUFFIX
SMTP_HOST = "localhost"
SMTP_PORT = "25"
MAIL_MAX_LENGTH = 5000
ERRORS_MAX_LENGTH = 25
errors = []
DEFAULT_DICT = { "video_url": VIDEO_URL }
def debug(message):
log_msg = "%s: %s" % (datetime.datetime.now().isoformat(), message)
errors.append(log_msg)
# remove old messages, if necessary
while len(errors) > ERRORS_MAX_LENGTH:
del errors[0]
print log_msg
def merged_dicts(dict_a, dict_b):
return dict(dict_a.items() + dict_b.items())
def filter_mailaddress(address):
return re.sub("[^%s]" % ALLOWED_MAILADDRESS_CHARACTERS, "", address)
def filter_mailtext(text):
filtered = re.sub("[^%s]" % ALLOWED_MAILTEXT_CHARACTERS, "", text)
if len(filtered) > MAIL_MAX_LENGTH:
return filtered[:MAIL_MAX_LENGTH-1]
else:
return filtered
def check_mailaddress(address):
if re.match(MAIL_ADDRESS_REGEX, address):
return True
else:
return False
def store_picture():
if not os.path.isdir(IMAGE_GALLERY_PATH):
os.mkdir(IMAGE_GALLERY_PATH)
import shutil
timestamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
filename = os.path.join(IMAGE_GALLERY_PATH, "%s%s" % (timestamp, IMAGE_SUFFIX))
shutil.copy(IMAGE_STORE, filename)
def get_random_pictures():
default = [""] * GALLERY_NUM
try:
result = []
all_files = [fname for fname in os.listdir(IMAGE_GALLERY_PATH)
if os.path.isfile(os.path.join(IMAGE_GALLERY_PATH, fname))
and fname.endswith(IMAGE_SUFFIX)]
if not all_files:
return default
all_files.sort()
print all_files
# the last five pictures
result.extend(all_files[-5:])
while len(result) < GALLERY_NUM:
result.append(all_files[random.randint(0, len(all_files)-1)])
return result
except OSError:
return default
def send_mail(address, text):
import smtplib
import StringIO
import email.Generator
import email.MIMEMultipart
import email.MIMEText
import email.MIMEImage
import rfc822
# read the additional mail parts (signature and picture)
try:
signature = file(MAIL_SIGNATURE_FILE).read()
except IOError, msg:
debug("failed to open the signature file (%s): %s" % \
(MAIL_SIGNATURE_FILE, msg))
return False
try:
picture = file(IMAGE_STORE).read()
except IOError, msg:
debug("failed to open the image file (%s): %s" % \
(IMAGE_STORE, msg))
return False
# prepare the message
#mail_flat = StringIO.StringIO()
#mail_gen = email.Generator.Generator(mail_flat)
#mail_gen.flatten(body)
mail = email.MIMEMultipart.MIMEMultipart()
mail_text = email.MIMEText.MIMEText((unicode(text) +
unicode(signature, 'latin-1')).encode('utf-8'), _charset='utf-8')
mail_pict = email.MIMEImage.MIMEImage(picture, "jpeg")
mail_pict.add_header("Content-Disposition",
'attachment; filename="%s"' % MAIL_ATTACHMENT_FILENAME)
mail.add_header("Subject", MAIL_SUBJECT)
mail.add_header("To", address)
mail.add_header("From", MAIL_FROM_ADDRESS)
mail.add_header("Date", rfc822.formatdate())
mail.add_header("Content-Disposition", "inline")
mail.attach(mail_text)
mail.attach(mail_pict)
writer = StringIO.StringIO()
email.Generator.Generator(writer).flatten(mail)
# send the mail
try:
con = smtplib.SMTP(SMTP_HOST, SMTP_PORT)
con.sendmail(MAIL_FROM_ADDRESS, address, writer.getvalue())
con.quit()
except (smtplib.SMTPHeloError, smtplib.SMTPRecipientsRefused,
smtplib.SMTPSenderRefused, smtplib.SMTPDataError), msg:
debug("an error occoured while sending the mail: %s" % msg)
return False
return True
class Root(controllers.RootController):
@expose(template="fotokiosk.templates.start")
def index(self, **kargs):
# TODO: this should generate a selection of random pictures
pic_names = get_random_pictures()
gallery = []
for i in range(len(pic_names)):
obj = SamplePicture()
obj.title = "pic%d" % (i+1)
obj.url = "%s" % pic_names[i]
gallery.append(obj)
# remove old picture
if os.path.isfile(IMAGE_STORE):
os.unlink(IMAGE_STORE)
return merged_dicts({ "gallery": gallery }, DEFAULT_DICT)
@expose(template="fotokiosk.templates.ausloeser")
def ausloeser(self, **kargs):
flash("Das Bild wird in 5 Sekunden aufgenommen!")
return merged_dicts({}, DEFAULT_DICT)
@expose(template="fotokiosk.templates.mailtext")
def mailtext(self, mailaddress="", mailtext="", already_captured="no", already_stored="no", **kargs):
# store the picture if necessary
if already_captured != "yes":
try:
urllib.urlretrieve(SNAPSHOT_URL, IMAGE_STORE)
except:
#os.system("reboot")
flash("Achtung: dein Foto enthaelt moeglicherweise menschenverachtende Inhalte. Bitte wende dich fuer einen umfassenden Persoenlichkeitstest an der Bar. Danke fuer deine Kooperation!")
redirect("index", DEFAULT_DICT)
already_captured = "no"
if already_stored != "yes":
already_stored = "no"
# filter input
mailaddress = filter_mailaddress(mailaddress)
mailtext = filter_mailtext(mailtext)
#if not check_mailaddress(mailaddress):
# turbogears.flash(
return merged_dicts({
"mailaddress": mailaddress,
"mailtext": mailtext,
"already_stored": already_stored,
}, DEFAULT_DICT)
@expose(template="fotokiosk.templates.senden")
def senden(self, mailaddress="", mailtext="", already_stored="no", senden=None):
# filter input
mailaddress = filter_mailaddress(mailaddress)
mailtext = filter_mailtext(mailtext)
if already_stored != "yes":
already_stored = "no"
return_dict = merged_dicts({
"mailaddress": mailaddress,
"mailtext": mailtext,
"already_stored": already_stored,
}, DEFAULT_DICT)
# check for a valid mail address and redirect if necessary
if not check_mailaddress(mailaddress):
if not mailaddress:
flash("Gib bitte eine Ziel-Mailadresse an!")
else:
flash("Die Mailadresse scheint nicht ungueltig zu sein.")
redirect("mailtext", return_dict)
else:
# send the mail
if already_stored != "yes":
store_picture()
if send_mail(mailaddress, mailtext):
return return_dict
else:
flash("Fehler beim Senden der Mail! Ist die Adresse korrekt?")
redirect("mailtext", return_dict)
@expose()
def get_current_shot(self):
if os.path.exists(IMAGE_STORE):
return cherrypy.lib.cptools.serveFile(IMAGE_STORE,
"image/jpeg")
else:
return ""

View file

@ -0,0 +1,10 @@
# A JSON-based API(view) for your app.
# Most rules would look like:
# @jsonify.when("isinstance(obj, YourClass)")
# def jsonify_yourclass(obj):
# return [obj.val1, obj.val2]
# @jsonify can convert your objects to following types:
# lists, dicts, numbers and strings
from turbojson.jsonify import jsonify

View file

@ -0,0 +1,21 @@
import pkg_resources
pkg_resources.require("SQLObject>=0.8")
from turbogears.database import PackageHub
# import some basic SQLObject classes for declaring the data model
# (see http://www.sqlobject.org/SQLObject.html#declaring-the-class)
from sqlobject import SQLObject, SQLObjectNotFound, RelatedJoin
# import some datatypes for table columns from SQLObject
# (see http://www.sqlobject.org/SQLObject.html#column-types for more)
from sqlobject import StringCol, UnicodeCol, IntCol, DateTimeCol
__connection__ = hub = PackageHub('fotokiosk')
class Picture(SQLObject):
adresse = UnicodeCol()
text = UnicodeCol()
date = DateTimeCol()
picture = BLOBCol()

View file

@ -0,0 +1,14 @@
# Release information about fotokiosk
version = "1.0"
# description = "Your plan to rule the world"
# long_description = "More description about your plan"
# author = "Your Name Here"
# email = "YourEmail@YourDomain"
# copyright = "Vintage 2006 - a good year indeed"
# if it's open source, you might want to specify these
# url = "http://yourcool.site/"
# download_url = "http://yourcool.site/download"
# license = "MIT"

View file

@ -0,0 +1,135 @@
body {
padding: 0;
margin: 0;
color: #454456;
text-align: center;
font: 1em Arial, Helvetica, sans-serif;
}
input.button {
margin: 5px 20px 5px 20px;
text-align: center;
font-size: large;
}
label {
font-size: large;
}
#header {
/** background: url(../static/images/header.jpg) top left no-repeat;
position: relative;
height: 160px;
padding-left: 85px;
font-size: 5em;
color: #777688;
width: 762px;
width: 89%; */
margin: 10px auto 30px auto;
}
#nav {
position: relative;
margin: 15px 0 10px auto;
width: 89%;
line-height: 2em;
}
#nav ul {
padding:5px;
margin:0;
padding:0;
}
#nav ul li {
float:right;
list-style:none;
margin:0;
padding:0;
}
#nav a, a:link {
display:block;
margin:0;
padding: 2px 15px;
text-align:center;
background: #EFE9ED;
}
#nav a:hover {
color: #EFE9ED;
background: #5684BF;
text-decoration: none;
}
/* dimensions are necessary - otherwise the picture/video
* fails to show up sometimes
*/
#mail_pic img {
width: 350px;
height: 260px;
}
/* Styles for the text area */
#main_content {
position: relative;
margin: 15px auto 15px auto;
padding: 0;
width: 95%;
text-align: left;
line-height: 1.25em;
}
a, a:link {
color: #5684BF;
background-color: inherit;
text-decoration: none;
display: inline;
padding: 0;
}
a:hover {
color: #454456;
text-decoration: underline;
}
p {
margin: 0;
padding: 5px;
padding-left: 20px;
}
h1 {
font: 1.5em Garamond, serif;
color: #777688;
border-left: #777688 15px solid;
padding: 5px;
margin: 20px 0;
}
h2 {
font:1.25em Garamond, serif;
color: #777688;
margin: 0;
padding: 20px;
}
#vkb {
margin: 0 auto 0 15%;
}
img.gallery {
width: 100px;
height: 60px;
}
/* Style for the footer */
#footer {
padding: 2px;
margin: auto;
background-color: #EFE9ED;
font-size: 1em;
width: 70%;
}

View file

@ -0,0 +1,139 @@
/*
* Quick mash-up of CSS for the TG quick start page.
*/
html, body {
color: black;
background-color: #ddd;
font: x-small "Lucida Grande", "Lucida Sans Unicode", geneva, verdana, sans-serif;
margin: 0;
padding: 0;
}
td, th {padding:3px;border:none;}
tr th {text-align:left;background-color:#f0f0f0;color:#333;}
tr.odd td {background-color:#edf3fe;}
tr.even td {background-color:#fff;}
#header {
height: 100px;
width: 770px;
background: blue URL('../images/header_glasmensch.gif') no-repeat;
border-left: 1px solid #aaa;
border-right: 1px solid #aaa;
margin: 0 auto 0 auto;
}
a.link, a, a.active {
color: #369;
}
#main_content {
color: black;
font-size: 127%;
background-color: white;
width: 757px;
margin: 0 auto 0 auto;
border-left: 1px solid #aaa;
border-right: 1px solid #aaa;
padding: 10px;
}
#sidebar {
border: 1px solid #aaa;
background-color: #eee;
margin: 0.5em;
padding: 1em;
float: right;
width: 200px;
font-size: 88%;
}
#sidebar h2 {
margin-top: 0;
}
#sidebar ul {
margin-left: 1.5em;
padding-left: 0;
}
h1,h2,h3,h4,h5,h6 {
font-family: "Century Schoolbook L", Georgia, serif;
font-weight: bold;
}
h2 {
font-size: 150%;
}
#footer {
clear: both;
border: 1px solid #aaa;
border-top: 0px none;
color: #999;
background-color: white;
padding: 10px;
font-size: 80%;
text-align: center;
width: 757px;
margin: 0 auto 1em auto;
}
.code {
font-family: monospace;
}
span.code {
font-weight: bold;
background: #eee;
}
#status_block {
margin: 0 auto 0.5em auto;
padding: 15px 10px 15px 55px;
background: #cec URL('../images/ok.png') left center no-repeat;
border: 1px solid #9c9;
width: 450px;
font-size: 120%;
font-weight: bolder;
}
.notice {
margin: 0.5em auto 0.5em auto;
padding: 15px 10px 15px 55px;
width: 450px;
background: #eef URL('../images/info.png') left center no-repeat;
border: 1px solid #cce;
}
.fielderror {
color: red;
font-weight: bold;
}
#gallery {
clear: both;
margin: 20px;
}
#live_pic {
float: left;
margin: 20px;
}
#shoot_pic {
text-align: center;
}
#mail_pic {
float: left;
margin: 10px;
}
#mail_info {
float: left;
margin: 20px;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 77 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 63 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

View file

@ -0,0 +1,40 @@
/* Copyright (C) 2007 Richard Atterer, richard©atterer.net
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License, version 2. See the file
COPYING for details. */
var imageNr = 0; // Serial number of current image
var finished = new Array(); // References to img objects which have finished downloading
var paused = false;
function createImageLayer() {
var img = new Image();
img.style.position = "absolute";
img.style.zIndex = -1;
img.style.width = "400px";
img.style.height = "320px";
img.onload = imageOnload;
img.onclick = imageOnclick;
img.src = "http://fotokiosk:8081/?action=snapshot&n=" + (++imageNr);
var webcam = document.getElementById("live_pic");
webcam.insertBefore(img, webcam.firstChild);
}
// Two layers are always present (except at the very beginning), to avoid flicker
function imageOnload() {
this.style.zIndex = imageNr; // Image finished, bring to front!
while (1 < finished.length) {
var del = finished.shift(); // Delete old image(s) from document
del.parentNode.removeChild(del);
}
finished.push(this);
if (!paused) window.setTimeout(createImageLayer(), 1000);
}
function imageOnclick() { // Clicking on the image will pause the stream
paused = !paused;
if (!paused) createImageLayer();
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

View file

@ -0,0 +1,335 @@
html.VirtualKeyboardPopup, body.VirtualKeyboardPopup {
padding: 0;
margin: 0;
}
#virtualKeyboard {
border: 1px solid #686888;
background: #fefefe;
height: 160px;
margin: 0;
padding: 0;
position: relative;
width: 396px;
}
/*
* global overrides
*/
#virtualKeyboard * {
border: 0;
color: black;
cursor: default;
margin: 0;
padding: 0;
}
#virtualKeyboard #kbDesk {
display: inline-block;
margin: 0;
padding: 4px 2px 0 2px;
/*IE5.5 will ignore the rule below */
margin/**/:/**/ 4px 2px 0 4px;
padding/**/:/**/ 0;
/*--*/
position: relative;
font-size: 1px;
overflow: hidden;
-moz-user-select: none;
-khtml-user-select: none;
}
#virtualKeyboard #kbDesk div.kbButton {
float: left;
height: 26px;
overflow: hidden;
padding: 0;
position: relative;
width: 26px;
z-index: 2;
}
#virtualKeyboard #kbDesk div.kbButton a {
background: url(button_set.gif) 0 0 no-repeat;
display: block;
height: 100%;
position: relative;
text-decoration: none;
width: 100%;
}
#virtualKeyboard #kbDesk.capsLock div.kbButton span.normal {
text-transform: uppercase;
}
#virtualKeyboard #kbDesk div.kbButtonHover a {
background-position: 0 -27px;
}
#virtualKeyboard #kbDesk div.kbButtonDown a {
background-position: 0 -54px;
}
#virtualKeyboard #kbDesk div.kbButton span {
display: block;
font-family: Verdana;
font-size: 13px;
font-weight: normal;
overflow: visible;
text-align: center;
}
#virtualKeyboard #kbDesk div.kbButton span.shifted,
#virtualKeyboard #kbDesk div.kbButton span.alted {
color: green;
font-size: 6pt;
height: 100%;
line-height: 1.1;
position: absolute;
right: -5px;
top: 0;
text-transform: none;
vertical-align: bottom;
width: 100%;
}
#virtualKeyboard #kbDesk div.kbButton span.alted {
color: blue;
right: 7px;
}
#virtualKeyboard #kbDesk div.kbButton span.normal {
position: absolute;
bottom: 4px;
left: 5px;
text-indent: 0;
}
#virtualKeyboard #kbDesk span.deadKey {
color: red;
}
#virtualKeyboard #kbDesk div#kb_benter {
background-position: -194px 0px;
margin-top: -26px;
position: relative;
float: right;
height: 52px;
width: 56px;
z-index: -1;
}
#virtualKeyboard #kbDesk div#kb_benter[id] {
z-index: 0;
}
#virtualKeyboard #kbDesk div#kb_benter a {
background-position: -194px 0px;
}
#virtualKeyboard #kbDesk div#kb_benter.kbButtonHover a {
background-position: -194px -53px;
}
#virtualKeyboard #kbDesk div#kb_benter.kbButtonDown a {
background-position: -194px -106px;
}
#virtualKeyboard #kbDesk div#kb_bbackspace a {
background-position: -27px -81px;
}
#virtualKeyboard #kbDesk div#kb_bbackspace.kbButtonHover a {
background-position: -27px -108px;
}
#virtualKeyboard #kbDesk div#kb_bbackspace.kbButtonDown a {
background-position: -27px -135px;
}
#virtualKeyboard #kbDesk div#kb_btab {
width: 41px;
}
#virtualKeyboard #kbDesk div#kb_btab a {
background-position: -155px -81px;
}
#virtualKeyboard #kbDesk div#kb_btab.kbButtonHover a {
background-position: -155px -108px;
}
#virtualKeyboard #kbDesk div#kb_btab.kbButtonDown a {
background-position: -155px -135px;
}
#virtualKeyboard #kbDesk div#kb_bcaps {
width: 48px;
}
#virtualKeyboard #kbDesk div#kb_bcaps a {
background-position: -107px -81px;
}
#virtualKeyboard #kbDesk div#kb_bcaps.kbButtonHover a {
background-position: -107px -108px;
}
#virtualKeyboard #kbDesk div#kb_bcaps.kbButtonDown a {
background-position: -107px -135px;
}
#virtualKeyboard #kbDesk div#kb_bshift_left,
#virtualKeyboard #kbDesk div#kb_bshift_right {
width: 52px;
}
#virtualKeyboard #kbDesk div#kb_bshift_left a,
#virtualKeyboard #kbDesk div#kb_bshift_right a {
background-position: -54px -81px;
}
#virtualKeyboard #kbDesk div#kb_bshift_left.kbButtonHover a,
#virtualKeyboard #kbDesk div#kb_bshift_right.kbButtonHover a {
background-position: -54px -108px;
}
#virtualKeyboard #kbDesk div#kb_bshift_left.kbButtonDown a,
#virtualKeyboard #kbDesk div#kb_bshift_right.kbButtonDown a {
background-position: -54px -135px;
}
#virtualKeyboard #kbDesk div#kb_balt_left,
#virtualKeyboard #kbDesk div#kb_balt_right {
padding: 0 0 0 2px;
width: 32px;
}
#virtualKeyboard #kbDesk div#kb_balt_left {
margin-left: 33px;
padding-left: 0;
/*IE5.5 will ignore the rule below */
padding-left/**/:/**/ 41px;
margin-left/**/:/**/ 0;
/*--*/
}
#virtualKeyboard #kbDesk div#kb_balt_left a,
#virtualKeyboard #kbDesk div#kb_balt_right a {
background-position: -251px 0;
}
#virtualKeyboard #kbDesk div#kb_balt_left.kbButtonHover a,
#virtualKeyboard #kbDesk div#kb_balt_right.kbButtonHover a {
background-position: -251px -27px;
}
#virtualKeyboard #kbDesk div#kb_balt_left.kbButtonDown a,
#virtualKeyboard #kbDesk div#kb_balt_right.kbButtonDown a {
background-position: -251px -54px;
}
#virtualKeyboard #kbDesk div#kb_bctrl_left,
#virtualKeyboard #kbDesk div#kb_bctrl_right {
float: left;
width: 32px;
}
#virtualKeyboard #kbDesk div#kb_bctrl_right {
float: right;
}
#virtualKeyboard #kbDesk div#kb_bctrl_left a,
#virtualKeyboard #kbDesk div#kb_bctrl_right a {
background-position: -251px -81px;
}
#virtualKeyboard #kbDesk div#kb_bctrl_left.kbButtonHover a,
#virtualKeyboard #kbDesk div#kb_bctrl_right.kbButtonHover a {
background-position: -251px -108px;
}
#virtualKeyboard #kbDesk div#kb_bctrl_left.kbButtonDown a,
#virtualKeyboard #kbDesk div#kb_bctrl_right.kbButtonDown a {
background-position: -251px -135px;
}
#virtualKeyboard #kbDesk div#kb_bdel a {
background-position: 0 -81px;
}
#virtualKeyboard #kbDesk div#kb_bdel.kbButtonHover a {
background-position: 0 -108px;
}
#virtualKeyboard #kbDesk div#kb_bdel.kbButtonDown a {
background-position: 0 -135px;
}
#virtualKeyboard #kbDesk div#kb_bspace {
width: 166px;
}
#virtualKeyboard #kbDesk div#kb_bspace a {
background-position: -27px 0;
}
#virtualKeyboard #kbDesk div#kb_bspace.kbButtonHover a {
background-position: -27px -27px;
}
#virtualKeyboard #kbDesk div#kb_bspace.kbButtonDown a {
background-position: -27px -54px;
}
#virtualKeyboard select#kb_langselector,
#virtualKeyboard select#kb_mappingselector {
border: 1px solid black;
bottom: 2px;
position: absolute;
right: 2px;
width: 125px;
}
#virtualKeyboard select#kb_mappingselector {
right: 140px;
}
#virtualKeyboard select,
#virtualKeyboard select option {
background: #fff;
font-family: Arial, Tahoma, Verdana sans-serif;
font-size: 11px;
}
#virtualKeyboard select optgroup option {
padding-left: 20px;
}
#virtualKeyboard #copyrights {
bottom: 4px;
color: blue;
font-size: 9px;
left: 2px;
line-height: normal;
position: absolute;
}
#virtualKeyboard #copyrights a {
font-size: 9px;
color: blue;
cursor: default;
outline: 0;
}
/**
*
* Styles for the IME field
*
*/
#VirtualKeyboardIME {
background: #fff;
border:1px solid #333;
position: absolute;
width: 200px;
}
#VirtualKeyboardIME div.IMEContent {
border: 1px solid #333;
border-top: 0;
border-bottom: 0;
height: 21px;
line-height: 21px;
margin: 0 12px;
overflow: auto;
padding: 0 3px;
white-space: nowrap;
}
#VirtualKeyboardIME div.left {
border-bottom: 10px solid #fff;
border-left: 0px solid black;
border-right: 10px solid #000;
border-top: 10px solid #fff;
position: absolute;
left: 1px;
font-size: 1px;
overflow: hidden;
}
#VirtualKeyboardIME div.right {
border-bottom: 10px solid #fff;
border-left: 10px solid #000;
border-right: 0px solid black;
border-top: 10px solid #fff;
float: right;
position: absolute;
right: 1px;
overflow: hidden;
}
/************************************
* Place for the locale-dependent styles
* overload fonts here
*
* Language-dependent class name is equal to uppercased language domain code (ZH in zh-CN)
*/
#virtualKeyboard #kbDesk.ZH div.kbButton span {
font-family: MingLiU, SimSun, "Arial Unicode MS";
font-size: 13px;
}
#virtualKeyboard #kbDesk.ZH div.kbButton span.alted,
#virtualKeyboard #kbDesk.ZH div.kbButton span.shifted {
font-size: 9px;
}
#VirtualKeyboardIME.ZH div.IMEContent {
font-family: SimSun, "Arial Unicode MS";
font-size: 16px;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

View file

@ -0,0 +1,307 @@
html.VirtualKeyboardPopup, body.VirtualKeyboardPopup {
padding: 0;
margin: 0;
}
#virtualKeyboard {
border: 1px solid #686888;
background: #f0ecff;
height: 120px;
margin: 0;
padding: 0;
position: relative;
width: 276px;
}
/*
* global overrides
*/
#virtualKeyboard * {
border: 0;
color: black;
cursor: default;
margin: 0;
padding: 0;
}
#virtualKeyboard #kbDesk {
display: inline-block;
margin: 0;
padding: 4px 2px 0 2px;
/*IE5.5 will ignore the rule below */
margin/**/:/**/ 4px 2px 0 4px;
padding/**/:/**/ 0;
/*--*/
position: relative;
font-size: 1px;
overflow: hidden;
-moz-user-select: none;
-khtml-user-select: none;
}
#virtualKeyboard #kbDesk div.kbButton {
float: left;
height: 18px;
overflow: hidden;
padding: 0;
position: relative;
width: 18px;
z-index: 2;
}
#virtualKeyboard #kbDesk div.kbButton a {
background: url(button_set.gif) 0 0 no-repeat;
display: block;
height: 100%;
position: relative;
text-decoration: none;
width: 100%;
}
#virtualKeyboard #kbDesk.capsLock div.kbButton span.normal {
text-transform: uppercase;
}
#virtualKeyboard #kbDesk div.kbButtonHover a {
background-position: 0 -21px;
}
#virtualKeyboard #kbDesk div.kbButtonDown a {
background-position: 0 -42px;
}
#virtualKeyboard #kbDesk div.kbButton span {
display: block;
font-family: Verdana;
font-size: 11px;
font-weight: normal;
overflow: visible;
position: relative;
text-align: center;
top: 2px;
}
#virtualKeyboard #kbDesk div.kbButton span.shifted,
#virtualKeyboard #kbDesk div.kbButton span.alted {
display: none;
}
#virtualKeyboard #kbDesk span.deadKey {
color: red;
}
#virtualKeyboard #kbDesk div#kb_benter {
margin-top: -18px;
position: relative;
float: right;
height: 36px;
width: 38px;
z-index: -1;
}
#virtualKeyboard #kbDesk div#kb_benter[id] {
z-index: 0;
}
#virtualKeyboard #kbDesk div#kb_benter a {
background-position: -150px 0;
}
#virtualKeyboard #kbDesk div#kb_benter.kbButtonHover a {
background-position: -150px -42px;
}
#virtualKeyboard #kbDesk div#kb_benter.kbButtonDown a {
background-position: -150px -84px;
}
#virtualKeyboard #kbDesk div#kb_bbackspace a {
background-position: -21px -63px;
}
#virtualKeyboard #kbDesk div#kb_bbackspace.kbButtonHover a {
background-position: -21px -84px;
}
#virtualKeyboard #kbDesk div#kb_bbackspace.kbButtonDown a {
background-position: -21px -105px;
}
#virtualKeyboard #kbDesk div#kb_btab {
width: 29px;
}
#virtualKeyboard #kbDesk div#kb_btab a {
background-position: -117px -63px;
}
#virtualKeyboard #kbDesk div#kb_btab.kbButtonHover a {
background-position: -117px -84px;
}
#virtualKeyboard #kbDesk div#kb_btab.kbButtonDown a {
background-position: -117px -105px;
}
#virtualKeyboard #kbDesk div#kb_bcaps {
width: 33px;
}
#virtualKeyboard #kbDesk div#kb_bcaps a {
background-position: -81px -63px;
}
#virtualKeyboard #kbDesk div#kb_bcaps.kbButtonHover a {
background-position: -81px -84px;
}
#virtualKeyboard #kbDesk div#kb_bcaps.kbButtonDown a {
background-position: -81px -105px;
}
#virtualKeyboard #kbDesk div#kb_bshift_left,
#virtualKeyboard #kbDesk div#kb_bshift_right {
width: 36px;
}
#virtualKeyboard #kbDesk div#kb_bshift_left a,
#virtualKeyboard #kbDesk div#kb_bshift_right a {
background-position: -42px -63px;
}
#virtualKeyboard #kbDesk div#kb_bshift_left.kbButtonHover a,
#virtualKeyboard #kbDesk div#kb_bshift_right.kbButtonHover a {
background-position: -42px -84px;
}
#virtualKeyboard #kbDesk div#kb_bshift_left.kbButtonDown a,
#virtualKeyboard #kbDesk div#kb_bshift_right.kbButtonDown a {
background-position: -42px -105px;
}
#virtualKeyboard #kbDesk div#kb_balt_left,
#virtualKeyboard #kbDesk div#kb_balt_right {
width: 21px;
}
#virtualKeyboard #kbDesk div#kb_balt_left {
margin-left: -23px;
padding-left: 0;
/*IE5.5 will ignore the rule below */
padding-left/**/:/**/ 32px;
margin-left/**/:/**/ 0;
/*--*/
}
#virtualKeyboard #kbDesk div#kb_balt_left a,
#virtualKeyboard #kbDesk div#kb_balt_right a {
background-position: -192px 0;
}
#virtualKeyboard #kbDesk div#kb_balt_left.kbButtonHover a,
#virtualKeyboard #kbDesk div#kb_balt_right.kbButtonHover a {
background-position: -192px -21px;
}
#virtualKeyboard #kbDesk div#kb_balt_left.kbButtonDown a,
#virtualKeyboard #kbDesk div#kb_balt_right.kbButtonDown a {
background-position: -192px -42px;
}
#virtualKeyboard #kbDesk div#kb_bctrl_left,
#virtualKeyboard #kbDesk div#kb_bctrl_right {
float: left;
width: 29px;
}
#virtualKeyboard #kbDesk div#kb_bctrl_right {
float: right;
}
#virtualKeyboard #kbDesk div#kb_bctrl_left a,
#virtualKeyboard #kbDesk div#kb_bctrl_right a {
background-position: -191px -63px;
}
#virtualKeyboard #kbDesk div#kb_bctrl_left.kbButtonHover a,
#virtualKeyboard #kbDesk div#kb_bctrl_right.kbButtonHover a {
background-position: -191px -84px;
}
#virtualKeyboard #kbDesk div#kb_bctrl_left.kbButtonDown a,
#virtualKeyboard #kbDesk div#kb_bctrl_right.kbButtonDown a {
background-position: -191px -105px;
}
#virtualKeyboard #kbDesk div#kb_bdel a {
background-position: 0 -63px;
}
#virtualKeyboard #kbDesk div#kb_bdel.kbButtonHover a {
background-position: 0 -84px;
}
#virtualKeyboard #kbDesk div#kb_bdel.kbButtonDown a {
background-position: 0 -105px;
}
#virtualKeyboard #kbDesk div#kb_bspace {
width: 100px;
}
#virtualKeyboard #kbDesk div#kb_bspace a {
background-position: -21px 0;
}
#virtualKeyboard #kbDesk div#kb_bspace.kbButtonHover a {
background-position: -21px -21px;
}
#virtualKeyboard #kbDesk div#kb_bspace.kbButtonDown a {
background-position: -21px -42px;
}
#virtualKeyboard select#kb_langselector,
#virtualKeyboard select#kb_mappingselector {
border: 1px solid black;
bottom: 2px;
position: absolute;
right: 2px;
width: 75px;
}
#virtualKeyboard select#kb_mappingselector {
right: 80px;
}
#virtualKeyboard select,
#virtualKeyboard select option {
background: #fff;
font-family: Arial, Tahoma, Verdana sans-serif;
font-size: 11px;
}
#virtualKeyboard select optgroup option {
padding-left: 20px;
}
#virtualKeyboard #copyrights {
bottom: 2px;
color: #77a;
font-size: 9px;
left: 4px;
line-height: normal;
position: absolute;
}
#virtualKeyboard #copyrights a {
font-size: 9px;
color: #77a;
cursor: default;
outline: 0;
}
/**
*
* Styles for the IME field
*
*/
#VirtualKeyboardIME {
background: #fff;
border:1px solid #333;
position: absolute;
width: 200px;
}
#VirtualKeyboardIME div.IMEContent {
border: 1px solid #333;
border-top: 0;
border-bottom: 0;
height: 21px;
line-height: 21px;
margin: 0 12px;
overflow: auto;
padding: 0 3px;
white-space: nowrap;
}
#VirtualKeyboardIME div.left {
border-bottom: 10px solid #fff;
border-left: 0px solid black;
border-right: 10px solid #000;
border-top: 10px solid #fff;
position: absolute;
left: 1px;
font-size: 1px;
overflow: hidden;
}
#VirtualKeyboardIME div.right {
border-bottom: 10px solid #fff;
border-left: 10px solid #000;
border-right: 0px solid black;
border-top: 10px solid #fff;
float: right;
position: absolute;
right: 1px;
overflow: hidden;
}
/************************************
* Place for the locale-dependent styles
* overload fonts here
*
* Language-dependent class name is equal to uppercased language domain code (ZH in zh-CN)
*/
#virtualKeyboard #kbDesk.ZH div.kbButton span {
font-family: MingLiU, SimSun, "Arial Unicode MS";
font-size: 11px;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 6 KiB

View file

@ -0,0 +1,342 @@
/* Skin made by Bastiaan Fronik (info [ at ] bastiaanfronik dot com)
based on stylesheet of WingedFox */
html.VirtualKeyboardPopup, body.VirtualKeyboardPopup {
padding: 0;
margin: 0;
}
#virtualKeyboard {
border: 1px solid #686888;
background: #dedfe0;
height: 242px;
margin: 0;
padding-right: 2px;
position: relative;
width: 606px;
}
/*
* global overrides
*/
#virtualKeyboard * {
border: 0;
color: black;
cursor: default;
margin: 0;
padding: 0;
}
#virtualKeyboard #kbDesk {
display: inline-block;
margin: 0;
padding: 4px 2px 0 2px;
/*IE5.5 will ignore the rule below */
margin/**/:/**/ 4px 2px 0 4px;
padding/**/:/**/ 0;
/*--*/
position: relative;
font-size: 1px;
overflow: hidden;
-moz-user-select: none;
-khtml-user-select: none;
}
#virtualKeyboard #kbDesk div.kbButton {
float: left;
height: 38px;
overflow: hidden;
padding: 0;
margin: 1px;
position: relative;
width: 38px;
z-index: 2;
}
#virtualKeyboard #kbDesk div.kbButton a {
background: url(button_set.gif) 0 0 no-repeat;
display: block;
height: 100%;
position: relative;
text-decoration: none;
width: 100%;
}
#virtualKeyboard #kbDesk.capsLock div.kbButton span.normal {
text-transform: uppercase;
}
#virtualKeyboard #kbDesk div.kbButtonHover a {
background-position: 0 -41px;
}
#virtualKeyboard #kbDesk div.kbButtonDown a {
background-position: 0 -82px;
}
#virtualKeyboard #kbDesk div.kbButton span {
display: block;
font-family: Verdana;
font-size: 18px;
font-weight: normal;
overflow: visible;
text-align: center;
}
#virtualKeyboard #kbDesk div.kbButton span.shifted,
#virtualKeyboard #kbDesk div.kbButton span.alted {
color: green;
font-size: 9pt;
height: 100%;
line-height: 1.1;
position: absolute;
right: -5px;
top: 0;
text-transform: none;
vertical-align: bottom;
width: 100%;
}
#virtualKeyboard #kbDesk div.kbButton span.alted {
color: blue;
right: 7px;
}
#virtualKeyboard #kbDesk div.kbButton span.normal {
position: absolute;
bottom: 4px;
left: 5px;
text-indent: 0;
}
#virtualKeyboard #kbDesk span.deadKey {
color: red;
}
#virtualKeyboard #kbDesk div#kb_benter
{
background-position: -303px 0px;
margin-top: -39px;
margin-bottom: 1px;
position: relative;
float: right;
height: 78px;
width: 85px;
z-index: -1;
}
#virtualKeyboard #kbDesk div#kb_benter[id] {
z-index: 0;
}
#virtualKeyboard #kbDesk div#kb_benter a {
background-position: -303px 0px;
}
#virtualKeyboard #kbDesk div#kb_benter.kbButtonHover a {
background-position: -303px -81px;
}
#virtualKeyboard #kbDesk div#kb_benter.kbButtonDown a {
background-position: -303px -162px;
}
#virtualKeyboard #kbDesk div#kb_bbackspace a {
background-position: -41px -123px;
}
#virtualKeyboard #kbDesk div#kb_bbackspace.kbButtonHover a {
background-position: -41px -164px;
}
#virtualKeyboard #kbDesk div#kb_bbackspace.kbButtonDown a {
background-position: -41px -205px;
}
#virtualKeyboard #kbDesk div#kb_btab {
width: 60px;
}
#virtualKeyboard #kbDesk div#kb_btab a {
background-position: -238px -123px;
}
#virtualKeyboard #kbDesk div#kb_btab.kbButtonHover a {
background-position: -238px -164px;
}
#virtualKeyboard #kbDesk div#kb_btab.kbButtonDown a {
background-position: -238px -205px;
}
#virtualKeyboard #kbDesk div#kb_bcaps {
width: 71px;
}
#virtualKeyboard #kbDesk div#kb_bcaps a {
background-position: -164px -123px;
}
#virtualKeyboard #kbDesk div#kb_bcaps.kbButtonHover a {
background-position: -164px -164px;
}
#virtualKeyboard #kbDesk div#kb_bcaps.kbButtonDown a {
background-position: -164px -205px;
}
#virtualKeyboard #kbDesk div#kb_bshift_left,
#virtualKeyboard #kbDesk div#kb_bshift_right {
width: 78px;
}
#virtualKeyboard #kbDesk div#kb_bshift_left a,
#virtualKeyboard #kbDesk div#kb_bshift_right a {
background-position: -82px -123px;
}
#virtualKeyboard #kbDesk div#kb_bshift_left.kbButtonHover a,
#virtualKeyboard #kbDesk div#kb_bshift_right.kbButtonHover a {
background-position: -82px -164px;
}
#virtualKeyboard #kbDesk div#kb_bshift_left.kbButtonDown a,
#virtualKeyboard #kbDesk div#kb_bshift_right.kbButtonDown a {
background-position: -82px -205px;
}
#virtualKeyboard #kbDesk div#kb_balt_left,
#virtualKeyboard #kbDesk div#kb_balt_right {
padding: 0 0 0 2px;
width: 47px;
}
#virtualKeyboard #kbDesk div#kb_balt_left {
margin-left: 33px;
padding-left: 0;
/*IE5.5 will ignore the rule below */
padding-left/**/:/**/ 41px;
margin-left/**/:/**/ 0;
/*--*/
}
#virtualKeyboard #kbDesk div#kb_balt_left a,
#virtualKeyboard #kbDesk div#kb_balt_right a {
background-position: -391px 0;
}
#virtualKeyboard #kbDesk div#kb_balt_left.kbButtonHover a,
#virtualKeyboard #kbDesk div#kb_balt_right.kbButtonHover a {
background-position: -391px -41px;
}
#virtualKeyboard #kbDesk div#kb_balt_left.kbButtonDown a,
#virtualKeyboard #kbDesk div#kb_balt_right.kbButtonDown a {
background-position: -391px -82px;
}
#virtualKeyboard #kbDesk div#kb_bctrl_left,
#virtualKeyboard #kbDesk div#kb_bctrl_right {
float: left;
width: 48px;
}
#virtualKeyboard #kbDesk div#kb_bctrl_right {
float: right;
}
#virtualKeyboard #kbDesk div#kb_bctrl_left a,
#virtualKeyboard #kbDesk div#kb_bctrl_right a {
background-position: -391px -123px;
}
#virtualKeyboard #kbDesk div#kb_bctrl_left.kbButtonHover a,
#virtualKeyboard #kbDesk div#kb_bctrl_right.kbButtonHover a {
background-position: -391px -164px;
}
#virtualKeyboard #kbDesk div#kb_bctrl_left.kbButtonDown a,
#virtualKeyboard #kbDesk div#kb_bctrl_right.kbButtonDown a {
background-position: -391px -205px;
}
#virtualKeyboard #kbDesk div#kb_bdel a {
background-position: 0 -123px;
}
#virtualKeyboard #kbDesk div#kb_bdel.kbButtonHover a {
background-position: 0 -164px;
}
#virtualKeyboard #kbDesk div#kb_bdel.kbButtonDown a {
background-position: 0 -205px;
}
#virtualKeyboard #kbDesk div#kb_bspace {
width: 259px;
}
#virtualKeyboard #kbDesk div#kb_bspace a {
background-position: -41px 0;
}
#virtualKeyboard #kbDesk div#kb_bspace.kbButtonHover a {
background-position: -41px -41px;
}
#virtualKeyboard #kbDesk div#kb_bspace.kbButtonDown a {
background-position: -41px -82px;
}
#virtualKeyboard select#kb_langselector,
#virtualKeyboard select#kb_mappingselector {
border: 1px solid black;
bottom: 2px;
position: absolute;
right: 2px;
width: 125px;
}
#virtualKeyboard select#kb_mappingselector {
right: 140px;
}
#virtualKeyboard select,
#virtualKeyboard select option {
background: #fff;
font-family: Arial, Tahoma, Verdana sans-serif;
font-size: 11px;
}
#virtualKeyboard select optgroup option {
padding-left: 20px;
}
#virtualKeyboard #copyrights
{
bottom: 4px;
color: #6f737a;
font-size: 9px;
left: 4px;
line-height: normal;
position: absolute;
}
#virtualKeyboard #copyrights a {
font-size: 9px;
color: #6f737a;
cursor: default;
outline: 0;
}
/**
*
* Styles for the IME field
*
*/
#VirtualKeyboardIME {
background: #fff;
border:1px solid #333;
position: absolute;
width: 200px;
}
#VirtualKeyboardIME div.IMEContent {
border: 1px solid #333;
border-top: 0;
border-bottom: 0;
height: 21px;
line-height: 21px;
margin: 0 12px;
overflow: auto;
padding: 0 3px;
white-space: nowrap;
}
#VirtualKeyboardIME div.left {
border-bottom: 10px solid #fff;
border-left: 0px solid black;
border-right: 10px solid #000;
border-top: 10px solid #fff;
position: absolute;
left: 1px;
font-size: 1px;
overflow: hidden;
}
#VirtualKeyboardIME div.right {
border-bottom: 10px solid #fff;
border-left: 10px solid #000;
border-right: 0px solid black;
border-top: 10px solid #fff;
float: right;
position: absolute;
right: 1px;
overflow: hidden;
}
/************************************
* Place for the locale-dependent styles
* overload fonts here
*
* Language-dependend class name is equal to uppercased language domain code (ZH in zh-CN)
*/
#virtualKeyboard #kbDesk.ZH div.kbButton span {
font-family: MingLiU, SimSun, "Arial Unicode MS";
font-size: 13px;
}
#virtualKeyboard #kbDesk.ZH div.kbButton span.alted,
#virtualKeyboard #kbDesk.ZH div.kbButton span.shifted {
font-size: 9px;
}
#VirtualKeyboardIME.ZH div.IMEContent {
font-family: SimSun, "Arial Unicode MS";
font-size: 16px;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

View file

@ -0,0 +1,338 @@
html.VirtualKeyboardPopup, body.VirtualKeyboardPopup {
padding: 0;
margin: 0;
}
#virtualKeyboard {
border: 1px solid #686888;
background: #ECE9D8;
height: 160px;
margin: 0;
padding: 0;
position: relative;
width: 396px;
}
/*
* global overrides
*/
#virtualKeyboard * {
border: 0;
color: black;
cursor: default;
margin: 0;
padding: 0;
}
#virtualKeyboard #kbDesk {
display: inline-block;
margin: 0;
padding: 4px 2px 0 2px;
/*IE5.5 will ignore the rule below */
margin/**/:/**/ 4px 2px 0 4px;
padding/**/:/**/ 0;
/*--*/
position: relative;
font-size: 1px;
overflow: hidden;
-moz-user-select: none;
-khtml-user-select: none;
}
#virtualKeyboard #kbDesk div.kbButton {
float: left;
height: 26px;
overflow: hidden;
padding: 0;
position: relative;
width: 26px;
z-index: 2;
}
#virtualKeyboard #kbDesk div.kbButton a {
background: url(button_set.gif) 0 0 no-repeat;
display: block;
height: 100%;
position: relative;
text-decoration: none;
width: 100%;
}
#virtualKeyboard #kbDesk.capsLock div.kbButton span.normal {
text-transform: uppercase;
}
#virtualKeyboard #kbDesk div.kbButtonHover a {
background-position: 0 -27px;
}
#virtualKeyboard #kbDesk div.kbButtonDown a {
background-position: 0 -54px;
}
#virtualKeyboard #kbDesk div.kbButton span {
display: block;
font-family: Verdana;
font-size: 13px;
font-weight: normal;
overflow: visible;
text-align: center;
}
#virtualKeyboard #kbDesk div.kbButton span.shifted,
#virtualKeyboard #kbDesk div.kbButton span.alted {
color: green;
font-size: 6pt;
height: 100%;
line-height: 1.1;
position: absolute;
right: -5px;
top: 0;
text-transform: none;
vertical-align: bottom;
width: 100%;
}
#virtualKeyboard #kbDesk div.kbButton span.alted {
color: blue;
right: 7px;
}
#virtualKeyboard #kbDesk div.kbButton span.normal {
position: absolute;
bottom: 4px;
left: 5px;
text-indent: 0;
}
#virtualKeyboard #kbDesk span.deadKey {
color: red;
}
#virtualKeyboard #kbDesk div#kb_benter {
background-position: -194px 0px;
margin-top: -26px;
position: relative;
float: right;
height: 52px;
width: 56px;
z-index: -1;
}
#virtualKeyboard #kbDesk div#kb_benter[id] {
z-index: 0;
}
#virtualKeyboard #kbDesk div#kb_benter a {
background-position: -194px 0px;
}
#virtualKeyboard #kbDesk div#kb_benter.kbButtonHover a {
background-position: -194px -53px;
}
#virtualKeyboard #kbDesk div#kb_benter.kbButtonDown a {
background-position: -194px -106px;
}
#virtualKeyboard #kbDesk div#kb_bbackspace a {
background-position: -27px -81px;
}
#virtualKeyboard #kbDesk div#kb_bbackspace.kbButtonHover a {
background-position: -27px -108px;
}
#virtualKeyboard #kbDesk div#kb_bbackspace.kbButtonDown a {
background-position: -27px -135px;
}
#virtualKeyboard #kbDesk div#kb_btab {
width: 41px;
}
#virtualKeyboard #kbDesk div#kb_btab a {
background-position: -155px -81px;
}
#virtualKeyboard #kbDesk div#kb_btab.kbButtonHover a {
background-position: -155px -108px;
}
#virtualKeyboard #kbDesk div#kb_btab.kbButtonDown a {
background-position: -155px -135px;
}
#virtualKeyboard #kbDesk div#kb_bcaps {
width: 48px;
}
#virtualKeyboard #kbDesk div#kb_bcaps a {
background-position: -107px -81px;
}
#virtualKeyboard #kbDesk div#kb_bcaps.kbButtonHover a {
background-position: -107px -108px;
}
#virtualKeyboard #kbDesk div#kb_bcaps.kbButtonDown a {
background-position: -107px -135px;
}
#virtualKeyboard #kbDesk div#kb_bshift_left,
#virtualKeyboard #kbDesk div#kb_bshift_right {
width: 52px;
}
#virtualKeyboard #kbDesk div#kb_bshift_left a,
#virtualKeyboard #kbDesk div#kb_bshift_right a {
background-position: -54px -81px;
}
#virtualKeyboard #kbDesk div#kb_bshift_left.kbButtonHover a,
#virtualKeyboard #kbDesk div#kb_bshift_right.kbButtonHover a {
background-position: -54px -108px;
}
#virtualKeyboard #kbDesk div#kb_bshift_left.kbButtonDown a,
#virtualKeyboard #kbDesk div#kb_bshift_right.kbButtonDown a {
background-position: -54px -135px;
}
#virtualKeyboard #kbDesk div#kb_balt_left,
#virtualKeyboard #kbDesk div#kb_balt_right {
padding: 0 0 0 2px;
width: 32px;
}
#virtualKeyboard #kbDesk div#kb_balt_left {
margin-left: 33px;
padding-left: 0;
/*IE5.5 will ignore the rule below */
padding-left/**/:/**/ 41px;
margin-left/**/:/**/ 0;
/*--*/
}
#virtualKeyboard #kbDesk div#kb_balt_left a,
#virtualKeyboard #kbDesk div#kb_balt_right a {
background-position: -251px 0;
}
#virtualKeyboard #kbDesk div#kb_balt_left.kbButtonHover a,
#virtualKeyboard #kbDesk div#kb_balt_right.kbButtonHover a {
background-position: -251px -27px;
}
#virtualKeyboard #kbDesk div#kb_balt_left.kbButtonDown a,
#virtualKeyboard #kbDesk div#kb_balt_right.kbButtonDown a {
background-position: -251px -54px;
}
#virtualKeyboard #kbDesk div#kb_bctrl_left,
#virtualKeyboard #kbDesk div#kb_bctrl_right {
float: left;
width: 32px;
}
#virtualKeyboard #kbDesk div#kb_bctrl_right {
float: right;
}
#virtualKeyboard #kbDesk div#kb_bctrl_left a,
#virtualKeyboard #kbDesk div#kb_bctrl_right a {
background-position: -251px -81px;
}
#virtualKeyboard #kbDesk div#kb_bctrl_left.kbButtonHover a,
#virtualKeyboard #kbDesk div#kb_bctrl_right.kbButtonHover a {
background-position: -251px -108px;
}
#virtualKeyboard #kbDesk div#kb_bctrl_left.kbButtonDown a,
#virtualKeyboard #kbDesk div#kb_bctrl_right.kbButtonDown a {
background-position: -251px -135px;
}
#virtualKeyboard #kbDesk div#kb_bdel a {
background-position: 0 -81px;
}
#virtualKeyboard #kbDesk div#kb_bdel.kbButtonHover a {
background-position: 0 -108px;
}
#virtualKeyboard #kbDesk div#kb_bdel.kbButtonDown a {
background-position: 0 -135px;
}
#virtualKeyboard #kbDesk div#kb_bspace {
width: 166px;
}
#virtualKeyboard #kbDesk div#kb_bspace a {
background-position: -27px 0;
}
#virtualKeyboard #kbDesk div#kb_bspace.kbButtonHover a {
background-position: -27px -27px;
}
#virtualKeyboard #kbDesk div#kb_bspace.kbButtonDown a {
background-position: -27px -54px;
}
#virtualKeyboard select#kb_langselector,
#virtualKeyboard select#kb_mappingselector {
border: 1px solid black;
bottom: 2px;
position: absolute;
right: 2px;
width: 125px;
}
#virtualKeyboard select#kb_mappingselector {
right: 140px;
}
#virtualKeyboard select,
#virtualKeyboard select option {
background: #fff;
font-family: Arial, Tahoma, Verdana sans-serif;
font-size: 11px;
}
#virtualKeyboard select optgroup option {
padding-left: 20px;
}
#virtualKeyboard #copyrights {
bottom: 4px;
color: blue;
font-size: 9px;
left: 2px;
line-height: normal;
position: absolute;
}
#virtualKeyboard #copyrights a {
font-size: 9px;
color: blue;
cursor: default;
outline: 0;
}
/**
*
* Styles for the IME field
*
*/
#VirtualKeyboardIME {
background: #fff;
border:1px solid #333;
position: absolute;
width: 200px;
}
#VirtualKeyboardIME div.IMEContent {
border: 1px solid #333;
border-top: 0;
border-bottom: 0;
height: 21px;
line-height: 21px;
margin: 0 12px;
overflow: auto;
padding: 0 3px;
white-space: nowrap;
}
#VirtualKeyboardIME div.left {
border-bottom: 10px solid #fff;
border-left: 0px solid black;
border-right: 10px solid #000;
border-top: 10px solid #fff;
position: absolute;
left: 1px;
font-size: 1px;
overflow: hidden;
}
#VirtualKeyboardIME div.right {
border-bottom: 10px solid #fff;
border-left: 10px solid #000;
border-right: 0px solid black;
border-top: 10px solid #fff;
float: right;
position: absolute;
right: 1px;
overflow: hidden;
}
/************************************
* Place for the locale-dependent styles
* overload fonts here
*
* Language-dependend class name is equal to uppercased language domain code (ZH in zh-CN)
*/
#virtualKeyboard #kbDesk.ZH div.kbButton span {
font-family: MingLiU, SimSun, "Arial Unicode MS";
font-size: 13px;
}
#virtualKeyboard #kbDesk.ZH div.kbButton span.alted,
#virtualKeyboard #kbDesk.ZH div.kbButton span.shifted {
font-size: 9px;
}
#VirtualKeyboardIME.ZH div.IMEContent {
font-family: SimSun, "Arial Unicode MS";
font-size: 16px;
}

View file

@ -0,0 +1,695 @@
/*
* $Id: documentselection.js 413 2008-05-16 21:30:59Z wingedfox $
* $HeadURL: https://svn.debugger.ru/repos/jslibs/BrowserExtensions/tags/BrowserExtensions.018/documentselection.js $
*
* Class implements cross-browser work with text selection
*
* @author Ilya Lebedev
* @author $Author: wingedfox $
* @modified $Date: 2008-05-17 01:30:59 +0400 (Сбт, 17 Май 2008) $
* @version $Rev: 413 $
* @license LGPL
*/
/*
* @class DocumentSelection
*/
DocumentSelection = new function () {
var self = this;
/*
* Stores hash of keys, applied to elements
*
* @type Object
* @scope private
*/
var keys = {
'prevCalcNode' : '__prevCalcNode'
}
//---------------------------------------------------------------------------
// PRIVATES
//---------------------------------------------------------------------------
/**
* Calls specified method with the supplied params
* This is done to process only correct requests
*
* @param {Function} method to call
* @param {Array} arguments of [target, param1, paramN]
* @return {Object} method call result or false, if any error happened
* @scope private
*/
var callMethod = function (m, arg) {
var el = arg[0]
,id
,module = ""
if (!el || !el.tagName) return false;
switch (arg[0].tagName.toLowerCase()) {
case 'input':
if (el.type && el.type != 'text' && el.type != 'password') return false;
case 'textarea':
module = "input";
break;
case 'iframe':
module = "frame";
arg[0] = el.contentWindow;
break;
default:
return false;
}
/*
* instantiate the module
*/
if ('function' == typeof self.module[module])
self.module[module] = new self.module[module](keys);
/*
* throw the exception, is method is not implemented
*/
if (!self.module[module] || !self.module[module][m])
throw new Error ('Method \''+m+'\' is not implemented for DocumentSelection \''+module+'\' module.');
return self.module[module][m].apply(self,arg);
}
/**
* Keeps scrolling on the place for browsers, those don't support this natively
*
* @param {HTMLElement} el target element
* @param {Number} ot old scrollTop property
* @param {Number} ol old scrollLeft property
* @scope private
*/
var keepScroll = function (el,ot,ol) {
if (window.getSelection && 'iframe'!=el.tagName.toLowerCase()) {
var q = self.getSelectionOffset(el)
if (el.contentWindow) el = el.contentWindow.document.body;
if (ot>q.y) el.scrollTop = q.y;
else if (ot+el.clientHeight>q.y) el.scrollTop = ot;
else el.scrollTop = q.y-el.clientHeight/2;
if (ol>q.x) el.scrollLeft = q.x;
else if (ol+el.clientWidth>q.x) el.scrollLeft = ol;
else el.scrollLeft = q.x-el.clientWidth/2;
}
}
//---------------------------------------------------------------------------
// SETTERS
//---------------------------------------------------------------------------
/**
* getSelectionRange wrapper/emulator
*
* @param {HTMLElement}
* @param {Number} start position
* @param {Number} end position
* @param {Boolean} related indicates calculation of range relatively to current start point
* @return void
* @scope public
*/
self.setRange = function(el, start, end, related) {
var ot = el.scrollTop
,ol = el.scrollLeft
/*
* set range on relative coordinates
*/
if (related) {
var st = self.getStart(el);
end = st+end;
start = st+start;
}
if (start < 0) start = 0;
if (end < start) end = start;
callMethod ('setRange',[el,start,end]);
keepScroll(el,ot,ol);
}
//---------------------------------------------------------------------------
// GETTERS
//---------------------------------------------------------------------------
/**
* Return contents of the current selection
*
* @param {HTMLElement} el element to look position on
* @return {String}
* @scope public
*/
self.getSelection = function(el) {
return callMethod('getSelection',[el]);
}
/**
* getSelectionStart wrapper/emulator
* adapted version
*
* @param {HTMLElement} el element to calculate end position for
* @return {Number} start position
* @scope public
*/
self.getStart = function (el) {
return callMethod('getPos',[el,true]);
}
/*
* getSelectionEnd wrapper/emulator
* adapted version
*
* @param {HTMLElement} el element to calculate end position for
* @return {Number} start position
* @scope public
*/
self.getEnd = function (el) {
return callMethod('getPos',[el,false]);
}
/*
* Return cursor position for supplied field
*
* @param {HTMLElement} element to get cursor position from
* @return {Number} position
* @scope public
*/
self.getCursorPosition = function (el) {
return self.getStart(el);
}
//---------------------------------------------------------------------------
// MISC FUNCTIONS
//---------------------------------------------------------------------------
/*
* Insert text at cursor position
*
* @param {HTMLElement} text field to insert text
* @param {String} text to insert
* @scope public
*/
self.insertAtCursor = function (el, val, keep) {
var ot = el.scrollTop
,ol = el.scrollLeft
if (!keep) {
callMethod('del',[el]);
}
var pos = callMethod('ins',[el,val]);
keepScroll(el,ot,ol);
return pos;
}
/*
* Wraps selection with start and end text
*
* @param {HTMLElement} text field to insert text
* @param {String} start text at the beginnging of the selection
* @param {String} end text at the end of the selection
* @scope public
*/
self.wrapSelection = function (el, start, end) {
var s = self.getCursorPosition(el)
,e = self.getEnd(el)
if (s==e) {
self.insertAtCursor(el,start+end);
} else {
self.insertAtCursor(el,start,true);
self.setRange(el,e+start.length,e+start.length);
self.insertAtCursor(el,end,true);
}
}
/*
* Deletes char at cursor position
*
* @param {HTMLElement} text field to delete text
* @param {Boolean} delete text before (backspace) or after (del) cursor
* @scope public
*/
self.deleteAtCursor = function (el, after) {
if (!self.getSelection(el)) {
if (after)
self.setRange(el,0,1,true);
else
self.setRange(el,-1,0,true);
}
return self.deleteSelection(el);
}
/**
* Removes the selection, if available
*
* @param {HTMLElement} el field to delete text from
* @scope public
*/
self.deleteSelection = function (el) {
var ol = el.scrollLeft
,ot = el.scrollTop
,ret = callMethod('del',[el]);
keepScroll(el,ot,ol);
return ret;
}
/**
* Method is used to caclulate pixel offsets for the selection in TextArea (other inputs are not tested yet)
*
* @param {HTMLTextareaElement} el target to calculate offsets
* @return {Object} {x: horizontal offset, y: vertical offset, h: height offset}
* @scope public
*/
self.getSelectionOffset = function (el) {
return callMethod('getSelectionOffset',[el],true);
}
}
DocumentSelection.module = {
/**
* Module processing selection in the 'input' and 'textarea' fields
*
* @param {Object} keys properties, registered for use in DS
* @scope protected
*/
'input' : function (keys) {
var self=this;
/**
* Special document node, used to calculate range offsets in Mozilla
*
* @type HtmlDivElement
* @scope private
*/
var offsetCalculator = null;
/**
* Returns selection start or end position in absolute chars from the field start
*
* @param {HTMLInputElement, HTMLTextareaElement} el input or textarea to get position from
* @param {Boolean} start get start or end selection position
* @return {Number} offset from the beginning
* @scope private
*/
self.getPos = function (el, start) {
var off;
try {
el.setActive();
if (start)
off = Math.abs(el.document.selection.createRange().moveStart("character", -100000000));
else
off = Math.abs(el.document.selection.createRange().moveEnd("character", -100000000));
/*
* test for the TEXTAREA's dumb behavior
*/
if (el.tagName.toLowerCase() != 'input') {
/*
* calculate node offset
*/
var r = el.document.body.createTextRange();
r.moveToElementText(el);
var sTest = Math.abs(r.moveStart("character", -100000000));
off -= sTest;
}
} catch (e) {
try {
off = (start?el.selectionStart:el.selectionEnd);
} catch (e) {
off = 0;
}
}
return off;
}
/**
* Removes the selection, if available
*
* @param {HTMLElement} el field to delete text from
* @return {String} deleted substring
* @scope public
*/
self.del = function (el) {
var ret = ""
,s = self.getPos(el,true)
,e = self.getPos(el,false)
if (s!=e) {
/*
* check for IE, because Opera does use \r\n sequence, but calculate positions correctly
*/
var tmp = document.selection&&!window.opera?el.value.replace(/\r/g,""):el.value;
ret = tmp.substring(s,e);
el.value = tmp.substring(0, s)+tmp.substring(e,tmp.length);
self.setRange(el,s,s);
}
return ret;
}
/**
* Inserts text to the textarea
*
* @param {HTMLElement} text field to insert text
* @param {String} text to insert
* @return {Number} new cursor position
* @scope public
*/
self.ins = function (el,val) {
var ret = ""
,s = self.getPos(el,true)
/*
* check for IE, because Opera does use \r\n sequence, but calculate positions correctly
*/
var tmp = document.selection&&!window.opera?el.value.replace(/\r/g,""):el.value;
el.value = tmp.substring(0,s)+val+tmp.substring(s,tmp.length);
s += val.length;
self.setRange(el,s,s);
return s;
}
/**
* Return contents of the current selection
*
* @param {HTMLElement} el element to look position on
* @param {Number} s start position
* @param {Number} e end position
* @return {String}
* @scope public
*/
self.getSelection = function (el) {
var s = self.getPos(el,true),
e = self.getPos(el,false)
/*
* w/o this check content might be duplicated on delete
*/
if (e<s) e = s;
/*
* check for IE, because Opera does use \r\n sequence, but calculate positions correctly
*/
var tmp = document.selection&&!window.opera?el.value.replace(/\r/g,""):el.value;
return tmp.substring(s,e);
}
/**
* Sets the selection range
*
* @param {HTMLElement}
* @param {Number} start position
* @param {Number} end position
* @return void
* @scope public
*/
self.setRange = function (el,start,end) {
if ('function' == typeof el.setSelectionRange) {
/*
* for Mozilla
*/
try {el.setSelectionRange(start, end)} catch (e) {}
} else {
/*
* for IE
*/
var range;
/*
* just try to create a range....
*/
try {
range = el.createTextRange();
} catch(e) {
try {
range = el.document.body.createTextRange();
range.moveToElementText(el);
} catch(e) {
return false;
}
}
el.focus();
range.collapse(true);
range.moveStart("character", start);
range.moveEnd("character", end - start);
range.select();
}
}
/**
* Method is used to caclulate pixel offsets for the selection in TextArea (other inputs are not tested yet)
*
* @param {HTMLTextareaElement} el target to calculate offsets
* @return {Object} {x: horizontal offset, y: vertical offset, h: height offset}
* @scope public
*/
self.getSelectionOffset = function (el) {
var range;
if ('function' == typeof el.setSelectionRange) {
/*
* For Mozilla
*/
if (!offsetCalculator) {
/*
* create hidden div, which will 'emulate' the textarea
* it's put 'below the ground', because toggling block/none is too expensive
*/
offsetCalculator = document.createElement('td');
document.body.appendChild(offsetCalculator);
}
/*
* store the reference to last-checked object, to prevent recalculation of styles
*/
if (offsetCalculator[keys.prevCalcNode] != el) {
offsetCalculator[keys.prevCalcNode] = el;
var cs = document.defaultView.getComputedStyle(el, null);
for (var i in cs) {
try {if (cs[i]) offsetCalculator.style[i] = cs[i];}catch(e){}
}
offsetCalculator.style.overflow = 'auto';
offsetCalculator.style.position = 'absolute';
offsetCalculator.style.visibility = 'hidden';
offsetCalculator.style.zIndex = '-10';
offsetCalculator.style.left="-10000px";
offsetCalculator.style.top="-10000px";
offsetCalculator.style.backgroundColor = 'yellow';
}
/*
* caclulate offsets to target and move div right below it
*/
var range = document.createRange()
,val = el.value || " ";
if ('input'==el.tagName.toLowerCase()) {
offsetCalculator.style.width = 'auto'
offsetCalculator.style.whiteSpace = 'nowrap';
} else {
offsetCalculator.style.whiteSpace = 'off'==el.getAttribute('wrap')?"pre":"";
}
val = val.replace(/\x20\x20/g,"\x20\xa0").replace(/</g,"&lt;").replace(/>/g,"&gt");
offsetCalculator.innerHTML = ( val.substring(0,el.selectionStart-1)+"<span>"+val.substring(el.selectionStart-1,el.selectionStart)+"</span>"
+val.substring(el.selectionStart)).replace(/\n/g,"<br />")
.replace(/\t/g,"<em style=\"white-space:pre\">\t</em>")
/*
* span is used to find the offsets
*/
var span = offsetCalculator.getElementsByTagName('span')[0];
span.style.border = '1px solid red';
range.offsetLeft = span.offsetLeft// - el.scrollLeft + span.clientWidth;
range.offsetTop = span.offsetTop// - el.scrollTop;
range.offsetHeight = span.offsetHeight;
if ("\n"==val.charAt(el.selectionStart-1)) range.offsetTop += range.offsetHeight*2;
span = null;
} else if (document.selection && document.selection.createRange) {
/*
* For IE
*/
range = document.selection.createRange();
/*
* IE does not allow to calculate lineHeight, but this check is easy
*/
range.offsetHeight = Math.round(range.boundingHeight/(range.text.replace(/[^\n]/g,"").length+1));
if (el.tagName && 'textarea'==el.tagName.toLowerCase()) {
var xy = DOM.getOffset(el)
range = {
'offsetTop' : range.offsetTop-xy.y+DOM.getBodyScrollTop()
,'offsetLeft' : range.offsetLeft-xy.x+DOM.getBodyScrollLeft()
,'offsetHeight' : range.offsetHeight
}
}
}
if (range) {
return {'x': range.offsetLeft, 'y': range.offsetTop, 'h': range.offsetHeight};
}
return {'x': 0, 'y': 0, 'h': 0};
}
}
,'frame' : function () {
var self=this;
/**
* Returns selection start or end position in absolute chars from the field start
*
* @param {HTMLInputElement, HTMLTextareaElement} el input or textarea to get position from
* @param {Boolean} start get start or end selection position
* @return {Number} offset from the beginning
* @scope private
*/
self.getPos = function (el, start) {
var pos = 0
if ('function' == typeof el.getSelection) {
/*
* we need to calculate both start and end points, because range could be reversed
* but we can't move selection end point before start one
*/
var sel = el.getSelection()
,sn = sel.anchorNode
,so = sel.anchorOffset
,en = sel.focusNode
,eo = sel.focusOffset
,ss = false
,es = false
,sc = 0
,ec = 0
,cn
,tw=document.createTreeWalker(el.document.body,NodeFilter.SHOW_TEXT,null,false)
while (sn && sn.nodeType != 3) {
sn = sn.childNodes[so]
so = 0;
}
while (en && en.nodeType != 3) {
en = en.childNodes[eo]
eo = 0;
}
while (cn=tw.nextNode()) {
if (cn == en) {
ec += eo
es = true
}
if (cn == sn) {
sc += so
ss = true
}
if (!es) ec += cn.nodeValue.length
if (!ss) sc += cn.nodeValue.length
if (es && ss) break;
}
pos = start?Math.min(ec,sc):Math.max(ec,sc)
} else {
el.document.body.setActive();
pos = Math.abs(el.document.selection.createRange()[start?"moveStart":"moveEnd"]("character", -100000000));
}
return pos;
}
/**
* Removes the selection, if available
*
* @param {HTMLElement} el field to delete text from
* @return {String} deleted substring
* @scope public
*/
self.del = function (el) {
if ('function' == typeof el.getSelection) {
var s = el.getSelection()
,i = s.rangeCount
while (--i>-1) s.getRangeAt(i).deleteContents();
} else if (el.document && el.document.selection) {
el.document.selection.createRange().text = "";
el.document.selection.createRange().select();
}
}
/**
* Inserts text to the textarea
*
* @param {HTMLElement} text field to insert text
* @param {String} text to insert
* @scope public
*/
self.ins = function (el,val) {
var p = self.getPos(el,true)+val.length;
if ('function' == typeof el.getSelection) {
var n = el.document.createTextNode(val)
,s = el.getSelection()
s.getRangeAt(0).insertNode(n);
n.parentNode.normalize();
} else if (el.document && el.document.selection) {
el.document.body.setActive();
el.document.selection.createRange().text = val;
}
self.setRange(el,p,p)
return p;
}
/**
* Return contents of the current selection
*
* @param {HTMLElement} el element to look position on
* @param {Number} s start position
* @param {Number} e end position
* @return {String}
* @scope public
*/
self.getSelection = function (el,s,e) {
if ('function' == typeof el.getSelection) {
var s = el.getSelection();
return s?s.toString():"";
} else if (el.document && el.document.selection) {
return el.document.selection.createRange().text;
}
}
/**
* Sets the selection range
*
* @param {HTMLElement}
* @param {Number} start position
* @param {Number} end position
* @return void
* @scope public
*/
self.setRange = function (el,start,end) {
if ('function' == typeof el.getSelection) {
var sel = el.getSelection();
sel.removeAllRanges();
var r = el.document.createRange()
,cnt = 0
,cl = 0
,cn
,pn
,tw=document.createTreeWalker(el.document.body,NodeFilter.SHOW_TEXT,null,false);
while ((cn=tw.nextNode())&&(!cn.nodeValue.length||(cnt+cn.nodeValue.length < start))) {
pn = cn;
cnt += cn.nodeValue.length;
}
/*
* explicitly set range borders
*/
if (cn||(cn=pn)) {
r.setStart(cn,start-cnt);
r.setEnd(cn,start-cnt);
}
if (cn) {
do {
if (cn.nodeType != 3) continue;
if (cnt+cn.nodeValue.length < end) {
cnt += cn.nodeValue.length;
} else {
r.setEnd(cn,end-cnt);
break;
}
} while (cn=tw.nextNode())
}
sel.addRange(r);
} else if (el.document && el.document.selection) {
el.document.body.setActive();
var r = el.document.selection.createRange()
r.moveToElementText(el.document.body);
r.move("character",start);
r.moveEnd("character",end-start);
r.select();
}
}
/**
* Method is used to calculate pixel offsets for the selection in TextArea (other inputs are not tested yet)
*
* @param {HTMLTextareaElement} el target to calculate offsets
* @return {Object} {x: horizontal offset, y: vertical offset, h: height offset}
* @scope public
*/
self.getSelectionOffset = function (el) {
var off = {'x':0, 'y':0, 'h':0};
if ('function' == typeof el.getSelection) {
var r = el.getSelection().getRangeAt(0)
,e = r.endOffset
,s = el.document.createElement('span')
,n = s;
s.style.borderLeft='1px solid red';
r.insertNode(s);
off.h = n.offsetHeight;
while (n.offsetParent) {
off.x += n.offsetLeft;
off.y += n.offsetTop;
n = n.offsetParent
}
s.parentNode.removeChild(s);
if (e-r.endOffset) {
r.setEnd(r.endContainer.nextSibling,e-r.endOffset);
el.getSelection().addRange(r)
}
} else if (el.document && el.document.selection) {
var r = el.document.selection.createRange()
off.h = r.boundingHeight
off.x = r.offsetLeft;
off.y = r.offsetTop;
}
return off;
}
}
}

View file

@ -0,0 +1,338 @@
/*
* $Id: dom.js 378 2007-12-13 10:07:23Z wingedfox $
* $HeadURL: https://svn.debugger.ru/repos/jslibs/BrowserExtensions/tags/BrowserExtensions.018/dom.js $
*
* DOM-related stuff and CSS manipulation class
*
* @author Ilya Lebedev
* @author $Author: wingedfox $
* @modified $Date: 2007-12-13 13:07:23 +0300 (Чтв, 13 Дек 2007) $
* @version $Rev: 378 $
* @license LGPL
* @depends helpers.js
* @depends arrayextensions.js
*/
if (isUndefined(DOM)) var DOM = {};
/**
* Performs parent lookup by
* - node object: actually it's "is child of" check
* - tagname: getParent(el, 'li') == getParent(el, 'tagName', 'LI')
* - any node attribute
*
* @param {HTMLElement} el source element
* @param {HTMLElement, String} cp DOMNode or string tagname or string attribute name
* @param {String} vl optional attribute value
* @return {HTMLElement, Null}
* @scope public
*/
DOM.getParent = function (el /* : HTMLElement */, cp /* :String, HTMLElement */, vl /* :String */) /* :HTMLElement */ {
if (el == null) return null;
else if (el.nodeType == 1 &&
((!isUndefined(vl) && el[cp] == vl) ||
('string' == typeof cp && DOM.hasTagName(el, cp)) ||
el == cp)) return el;
else return arguments.callee(el.parentNode, cp, vl);
};
/**
* Calculates the offset for the DOM node from top left corner
*
* @author Matt Kruse
* @see http://javascripttoolbox.com/lib/objectposition/index.php
* @param {HTMLElement} el
* @return {Object} x: horizontal offset, y: vertical offset
* @scope public
*/
DOM.getOffset = function (el /* :HTMLElement */) /* :Object */ {
var fixBrowserQuirks = true
,o = el
,left = 0
,top = 0
,width = 0
,height = 0
,parentNode = null
,offsetParent = null;
if (o==null) return null;
offsetParent = o.offsetParent;
var originalObject = o
,el = o; // "el" will be nodes as we walk up, "o" will be saved for offsetParent references
while (el.parentNode!=null) {
el = el.parentNode;
if (el.offsetParent!==null) {
var considerScroll = true;
/*
In Opera, if parentNode of the first object is scrollable, then offsetLeft/offsetTop already
take its scroll position into account. If elements further up the chain are scrollable, their
scroll offsets still need to be added in. And for some reason, TR nodes have a scrolltop value
which must be ignored.
*/
if (fixBrowserQuirks && window.opera) {
if (el==originalObject.parentNode || el.nodeName=="TR") {
considerScroll = false;
}
}
if (considerScroll) {
if (el.scrollTop && el.scrollTop>0) {
top -= el.scrollTop;
}
if (el.scrollLeft && el.scrollLeft>0) {
left -= el.scrollLeft;
}
}
}
// If this node is also the offsetParent, add on the offsets and reset to the new offsetParent
if (el == offsetParent) {
left += o.offsetLeft;
if (el.clientLeft && el.nodeName!="TABLE") {
left += el.clientLeft;
}
top += o.offsetTop;
if (el.clientTop && el.nodeName!="TABLE") {
top += el.clientTop;
}
o = el;
if (o.offsetParent==null) {
if (o.offsetLeft) {
left += o.offsetLeft;
}
if (o.offsetTop) {
top += o.offsetTop;
}
}
offsetParent = o.offsetParent;
}
}
if (originalObject.offsetWidth) {
width = originalObject.offsetWidth;
}
if (originalObject.offsetHeight) {
height = originalObject.offsetHeight;
}
return {'x':left, 'y':top, 'width':width, 'height':height};
};
//DOM.getOffset = function (el /* :HTMLElement */) /* :Object */ {
/*
var xy = {'x' : el.offsetLeft , 'y' : el.offsetTop};
if (el.offsetParent) {
var xy1 = arguments.callee(el.offsetParent);
xy.x += xy1.x;
xy.y += xy1.y;
}
return xy;
}
*/
/**
* Returns the width of the window canvas
*
* @return {Number}
* @scope public
*/
DOM.getClientWidth = function () /* :Number */{
var w=0;
if (self.innerHeight) w = self.innerWidth;
else if (document.documentElement && document.documentElement.clientWidth) w = document.documentElement.clientWidth;
else if (document.body) w = document.body.clientWidth;
return w;
};
/**
* Returns the height of the window canvas
*
* @return {Number}
* @scope public
*/
DOM.getClientHeight = function () /* :Number */{
var h=0;
if (self.innerHeight) h = self.innerHeight;
else if (document.documentElement && document.documentElement.clientHeight) h = document.documentElement.clientHeight;
else if (document.body) h = document.body.clientHeight;
return h;
};
/**
* Returns the height of the scrolled area for the body
*
* @return {Number}
* @scope public
*/
DOM.getBodyScrollTop = function () /* :Number */{
return self.pageYOffset || (document.documentElement && document.documentElement.scrollTop) || (document.body && document.body.scrollTop);
};
/**
* Returns the height of the scrolled area for the body
*
* @return {Number}
* @scope public
*/
DOM.getBodyScrollLeft = function () /* :Number */{
return self.pageXOffset || (document.documentElement && document.documentElement.scrollLeft) || (document.body && document.body.scrollLeft);
};
/**
* Calculates cursor position properly
*
* @param {Event} e event object to get cursor positions from
* @return {Object} object with x and y cursor positions
* @scope protected
* @see http://hartshorne.ca/2006/01/23/javascript_cursor_position/
* @author Beau Hartshorne
*/
DOM.getCursorPosition = function (e) {
if (e.pageX || e.pageY) return {'x': e.pageX, 'y': e.pageY};
var de = document.documentElement || document.body;
return {'x': e.clientX + de.scrollLeft - (de.clientLeft || 0)
,'y': e.clientY + de.scrollTop - (de.clientTop || 0)};
};
/**
* Checks, if property matches a tagname(s)
*
* @param {HTMLElement} prop
* @param {String, Array} tags
* @return {Boolean}
* @scope public
*/
DOM.hasTagName = function (prop /* :HTMLElement */, tags /* :String, Array */) {
if (isString(tags)) tags = [tags];
if (!isArray(tags) || isEmpty(tags) || isUndefined(prop) || isEmpty(prop.tagName)) return false;
var t = prop.tagName.toLowerCase();
for (var i=0, tL=tags.length; i<tL; i++) {
if (tags[i].toLowerCase() == t) return true;
}
return false;
};
/**
* Return the actual rgb color value from the following formats
* #rrggbb
* #rgb
* rgb (0..255, 0..255,0..255)
* rgb (0..100%, 0..100%,0..100%)
* <color_name>
*
* @param {String} from attr name
* @return {Array} r,g,b values
* @scope public
*/
DOM.color2rgb = function (prop) {
var e;
/*
* note, properties like borderColor might have the series of colors
*/
if (/^([a-z]+)($|\s[a-z]+)/i.test(prop)) {
var d = document.body, ov = d.vLink;
d.vLink = prop.split(" ")[0];
prop = d.vLink;
d.vLink = ov;
}
try {
if (e = prop.match(/^#([\da-f]{6})$/i))
return e=parseInt(e[1],16),[(e&0xff0000)>>16,(e&0xff00)>>8,(e&0xff)]
else if (e = prop.match(/^#([\da-f]{3})$/i)) {
return e=parseInt(e[1],16),[((e&0xf00)>>8)*0x11,((e&0xf0)>>4)*0x11,(e&0xf)*0x11];
} else
return (prop.match(/([\d%]+)/g).splice(0,3).map(function(a){ return /%/.test(a)?(parseInt(a)*2.55).toFixed(0):parseInt(a)}))
} catch(err){
}
}
/**
* DOM.CSS is the CSS processing class, allowing to easy mangle class names
*
* @param {HTMLElement} el element to provide interface for
* @scope public
* @constructor
* @class DOM.CSS
* @exception on invalid parameter
* @depends arrayextensions.js
* @depends helpers.js
*/
DOM.CSS = function (el) {
var self = this
/**
* Adds the class name, unlimited number of arguments is supported
*
* @param {String} class classname to apply to the element
* @return {Object} singleton object to chain operations
* @scope public
*/
self.addClass = function() {
var arg = isArray(arguments[0])?arguments[0]:Array.prototype.slice.call(arguments);
self.removeClass(arg);
el.className = el.className+" "+Array.prototype.join.call(arg," ");
return self;
};
/**
* Removes the class name, unlimited number of arguments is supported
*
* @param {String} class classname to apply to the element
* @return {Object} singleton object to chain operations
* @scope public
*/
self.removeClass = function() {
var arg = Array.prototype.join.call((isArray(arguments[0])?arguments[0]:arguments),"|");
if (!arguments.callee.cache) arguments.callee.cache = {}
var c = arguments.callee.cache
if (!c.hasOwnProperty(arg)) c[arg] = new RegExp("(^|\\s+)("+arg+")(\\s+|$)","g");
el.className = el.className.replace(c[arg]," ");
return self;
};
/**
* Checks classname for the certain class
*
* @param {String} c class name to check for
* @return {Boolean} class name existence
* @scope public
*/
self.hasClass = function(c) {
re=new RegExp("(^|\\s+)"+c+"(\\s+|$)");
return el.className.match(re," "+c+" ");
};
/**
* Returns the actual CSS class for the element
*
* @return {String} css class
* @scope public
*/
self.getClass = function() {
return el.className;
}
/**
* Retrieves class value from class name by pattern
* class-var = "name:value"
* name = [a-z][-a-z0-9]
* value = value | val1:val2:...:valN
*
* @param {String} c class name to check for
* @return {String, Array} value(s)
* @scope public
*/
self.getClassValue = function(c) {
var vals = el.className.match(new RegExp("(^|\\s)"+c+":([^\\s]+)"));
return vals?((vals[2].indexOf(":")+1)?vals[2].split(":")
:vals[2])
:null;
};
/**
* Returns actual style for the element, computed from CSS and inline styles
*
* @param {String} prop optional style property to fetch
* @return {Object} computed style or property value
* @scope public
*/
self.getComputedStyle = function(prop) {
var y;
if (el.currentStyle)
y = prop?el.currentStyle[prop]:el.currentStyle;
else if (window.getComputedStyle) {
y = document.defaultView.getComputedStyle(el,null);
if (prop) y=y[prop];
} else {
y = null;
}
return y;
}
return this;
};

View file

@ -0,0 +1,524 @@
/**
* $Id: eventmanager.js 397 2008-04-22 20:17:57Z wingedfox $
* $HeadURL: https://svn.debugger.ru/repos/jslibs/BrowserExtensions/tags/BrowserExtensions.018/eventmanager.js $
*
* EventManager (EM shorthand) is the class, written to manage event attach/detach/register and so on
*
* @modified $Date: 2008-04-23 00:17:57 +0400 (Срд, 23 Апр 2008) $
* @version $Rev: 397 $
* @license LGPL 2.1 or later
* @author Ilya Lebedev <ilya@lebedev.net>
* @depends helpers.js
*
* @class
* @constructor EventManager
*/
var EM = new function () {
var self = this;
/**
* Events pool
* Element format:
* { 'node' : {HTMLElement},
* ['rootEHCaller' : {Function}]
* 'handler' : {
* <event_name> : [Function[, Function[, ...]]]
* [,<event_name> : [Function[, Function[, ...]]]]
* }
* }
*
* @type Array
* @scope private
*/
var pool = [];
/**
* Unique ID counter, used to attach IDs to the objects
*
* @type Number
* @scope private
*/
var UID = 0;
/**
* List of used keys, applied to different kinds of objects
*
* @type Object
* @scope private
*/
var keys = {
'UEID' : '__eventManagerUniqueElementId'
// ,'UHID' : '__eventManagerUniqueHandlerId'
};
/**************************************************************************
* PROTECTED METHODS
***************************************************************************/
/**
* Method is being binded to any new event handler, then, when called,
* does some unification between browser platforms and calls all binded
* event handlers
*
* @param {Event} e event object
* @scope protected
*/
var rootEventHandler = function (e) {
unifyEvent(e);
var id = null
,hid = null
,el = e.target
,fe = true
,res = true;
if (!e.currentTarget || !(id = e.currentTarget[keys.UEID]) || !(hid = pool[id].handler[e.type])) return;
try {
for (var i=0, hL=hid.length; i<hL; i++) if (isFunction(hid[i])) res=res&&!(false===hid[i].call(e.currentTarget, e));
} catch (err) { setTimeout(function(){throw new Error("Event handler for ["+e.type+"] has failed with exception: \""+err.message+"\"");},10) }
return res;
};
/**
* Performs events cleanup on page unload
* It aims to remove leaking closures
*
* @param {Event} e window.unload event
* @scope protected
*/
var unloadEventHandler = function (e) {
for (var i=pool.length-1,pid=null,el=null; i>=0; i--) {
if (pool[i] && (el=(pid = pool[i]).node)) {
for (var z in pid.handler) {
if (!pid.handler.hasOwnProperty(z)) continue;
try {
if (el.removeEventListener) {
el.removeEventListener(z, pid.rootEHCaller?pid.rootEHCaller:rootEventHandler, false);
} else if (el.detachEvent) {
el.detachEvent('on'+z, pid.rootEHCaller?pid.rootEHCaller:rootEventHandler);
}
} catch (e) {}
pid.handler[z].length = 0;
}
}
el = pid.node = null;
}
if (window.removeEventListener) {
window.removeEventListener(z, arguments.callee, false);
} else {
window.detachEvent('on'+z, arguments.callee);
}
};
/**************************************************************************
* PRIVATE METHODS
***************************************************************************/
/**
* Makes an event clone, it does not dereference objects in the event properties
*
* @param {Event} e event handler
* @return {Object} cloned event
* @scope private
*/
var unifyEvent = function (e) {
var i=self.EU.length
,cur,cur1,k,init
while (i--) {
cur = self.EU[i];
if (cur[0].test(e.type)) {
k=cur[1].length;
init = null;
while (k--) {
cur1 = cur[1][k];
if ('init' == cur1[0]) init = cur1[1]
else if (!e[cur1[0]]) e[cur1[0]] = cur1[1];
}
if (init) init.call(e);
}
}
if (!e.target && e.type != 'unload') e.target = e.srcElement;
return e;
};
/**
* Returns UEID property for the specified element, creates it, if asked
*
* @param {Object} el element to find UEID on
* @param {Boolean} f optional flag to force UEID creation, if not exists
* @retutn {Number} UEID, if > 0
* @scope private
*/
var getUEID = function (el, f) {
return el[keys.UEID] || (f && (el[keys.UEID] = ++UID));
};
/**************************************************************************
* PUBLIC METHODS
***************************************************************************/
/**
* Adds the event listener to the queue
*
* @param {Object} el element to attach event handler to
* @param {String} et event name to attach event handler to (without 'on' prefix)
* @param {Function} h event handler
* @return {Boolean} success state
* @scope public
*/
self.addEventListener = function (el, et, h) {
if (!el || !isFunction(h)) return false;
// if (!el.addEventListener && !el.attachEvent) return false;
/*
* unique identifier is used to keep an eye on the element
*/
var id = getUEID(el, true)
,pid = null
,hid = null;
/*
* prepare pool object, if needed
*/
if (!pool[id]) {
pool[id] = {
'node' : el
,'handler' : {}
}
};
pid = pool[id];
/*
* prepare handlers storage in the pool object, if needed
*/
if (!pid.handler.hasOwnProperty(et)) {
pid.handler[et] = [];
/*
* if we a here, this means that we have not connected to a node yet
* note, we've already made a check for the required methods existense
*/
if (el.addEventListener) {
el.addEventListener(et, rootEventHandler, false);
} else if (el.attachEvent) {
/*
* this workaround is used to avoid IE's lack of currentTarget property
*/
pid.rootEHCaller = function(e) {
e.currentTarget = pid.node;//pool[id].node;
var res = rootEventHandler(e);
e.currentTarget = null;
return res;
};
el.attachEvent('on'+et, pid.rootEHCaller);
}
};
hid = pid.handler[et];
/*
* finally, attach handler, if it was not attached before
*/
if (hid.indexOf(h)==-1) {
hid[hid.length] = h;
return true;
}
return false;
};
/**
* Removes the event listener from the queue
*
* @param {Object} el element to attach event handler to
* @param {String} et event name to attach event handler to (without 'on' prefix)
* @param {Function} h event handler
* @return {Boolean} success state
* @scope public
*/
self.removeEventListener = function (el,et,h) {
if (!el || !isFunction(h)) return false;
var id = getUEID(el)
,pid = pool[id]
,eid = null;
if (pid && (eid = pid.handler[et])) {
/*
* we've found an event handler
*/
eid.splice(eid.indexOf(h),1);
if (0 == eid.length) {
delete pid.handler[et];
/*
* remove the actual listener
*/
if (el.removeEventListener) {
el.removeEventListener(et, pid.rootEHCaller?pid.rootEHCaller:rootEventHandler, false);
} else if (el.detachEvent) {
el.detachEvent('on'+et, pid.rootEHCaller?pid.rootEHCaller:rootEventHandler);
}
}
return true;
}
return false;
};
/**
* Dispatch custom events on the specified element
*
* @param {Object} e event object itself
* @return {Boolean} cancelled status
* @scope public
*/
self.dispatchEvent = function (e) {
var res = rootEventHandler(e);
return res;
};
/**
* Registers new event handler for any object
* It's a good idea to register events on the object instances, really
*
* @param {Object} o object to register new event on
* @param {String} n bindable event name
* @param {Boolean} b optional bubbling allowed flag
* @param {Function} d optional default action function
* @return {EMEvent} object, allowing to invoke events
* @scope public
* @see EM.EventTarget
*/
self.registerEvent = function (o, n, b, d) {
var id = getUEID(o,true);
if (!pool[id]) {
pool[id] = {'node' : o,
'handler' : []};
} else {
pool[id].node = o;
}
return new EM.EventTarget(o, n, b, d);
};
/**
* Performs object initialization
*
*/
var __construct = function() {
/*
* for IE, to dereference event handlers and remove memory leaks
*/
if (window.attachEvent && !window.addEventListener) {
window.attachEvent('onunload',unloadEventHandler);
}
};
__construct();
};
/******************************************************************************
* STATIC METHODS
******************************************************************************/
EM.preventDefaultAction = function(e) {
e.preventDefault();
}
EM.stopPropagationAction = function(e) {
e.stopPropagation();
}
/******************************************************************************
* SUPPLEMENTARY CLASSES
******************************************************************************/
/**
* EventTarget base class
* Used to create self-containing event object
*
* @class EM.EventTarget
* @constructor
* @param {String} name event name
* @param {Null, Object} obj event execution context (this), window if null passed
* @param {Boolean} bubble flag allowing event to bubble across element.parentNode
* @param {Function} def default action for the event
*/
EM.EventTarget = function (obj, name, bubble, def) {
var self = this;
/**
* Indicates possible bubbling, by default bubbling is not allowed
*
* @type Boolean
* @default false
* @scope private
*/
var canBubble = !!bubble;
/**
* Stores function, performing default action for the event
*
* @type Function
* @scope private
*/
var defaultAction = isFunction(def)?def:null;
/**************************************************************************
* PRIVATE METHODS
***************************************************************************/
/**************************************************************************
* PROTECTED METHODS
***************************************************************************/
/**
* Used to trigger created event on the supplied object or on the 'obj' constructor param
*
*
* @param {Object} el optional element to trigger event on (.target property in the event object)
* @param {Object} event data
*/
self.trigger = function (el, data) {
if (!(arguments.length-1) && el!=obj) {
data = el;
el = null;
}
if (!el) el = obj;
var e = {}
,res = true
,undef = true
,tmp = null
for (var i in data) {
if (data.hasOwnProperty(i)) e[i] = data[i];
}
/*
* set defaults
*/
canBubble = !!bubble;
defaultAction = def;
/*
* start the go
*/
do {
e.preventDefault = preventDefault;
e.stopPropagation = stopPropagation;
e.target = el;
e.currentTarget = el;
e.type = name;
tmp = EM.dispatchEvent(e);
undef &= (isUndefined(tmp))
res &= !(false===tmp);
} while ((el = el.parentNode) && canBubble);
/*
* try to execute the default action
*/
if (isFunction(defaultAction) && res && !undef) {
defaultAction(e);
}
return (defaultAction && res && !undef);
};
/**
* Prevents default event action
*
* @scope protected
*/
var preventDefault = function () {
defaultAction = null;
};
/**
* Stops bubbling
*
* @scope protected
*/
var stopPropagation = function () {
canBubble = false;
};
};
/**
* Namespace for event unification routines
*
* @type Array
* @scope protected
*/
EM.EU = [
[/./ , [
/**
* Prevents event from calling default event handler
*
* @scope protected
*/
['preventDefault', function() {
this.returnValue = false;
}
]
/**
* Prevents event from futher bubbling
*
* @scope protected
*/
,['stopPropagation', function() {
this.cancelBubble = true;
}
]
]]
,[/^mouse(over|out|down|up)/ , [
/**
* Used to detect left or right button pressed.
* Due to some browser inconsistense, middle button is ignored
*
* @return {Number} 1 - left button, 2 - right button
* @scope protected
*/
['getButton', function () {
return this.button==2?2:1
}
]
,['EM_MB_LEFT', '1']
,['EM_MB_RIGHT', '2']
]]
,[/^key(down|up|press)/ , [
/**
* Used to return browser-independend keycode
*
* @return {Number} fixed key code
* @scope protected
*/
['getKeyCode', function () {
switch (this.keyCode) {
case 189: return 109;
case 187: return 61;
case 186: return 59;
default: return this.keyCode;
}
}
]
/**
* Calculates 'repeat' property for the key events
*
* @return {Number} 0 means no repeating keystroke detected
* @scope protected
*/
,['getRepeat', function () {
return arguments.callee.repeat
}
]
,['init', function () {
var ac = this.getRepeat
if ('keyup' == this.type) {
ac.repeat = 0;
ac.keyCode = 0;
} else if ('keydown' == this.type) {
ac.repeat = ac.keyCode==this.keyCode;
ac.keyCode=this.keyCode;
}
}
]
]]
];
/*
* register core event handler, domload
* it's called right on the document initialization, before images complete load
*/
(function (){
var evt = EM.registerEvent(window,'domload')
,executed = false
,clearEvents = function() {
//For IE
EM.removeEventListener(document, 'propertychange', handlers.ie);
//For Mozilla
EM.removeEventListener(document, 'DOMContentLoaded', handlers.mz);
//For someone else
EM.removeEventListener(window, 'load', handlers.mz);
}
,handlers = { 'ie' : function(e) {
if (window.event.propertyName == 'activeElement' && !executed) {
evt.trigger(window);
clearEvents();
executed = true;
}
}
,'mz' : function (e) {if(!executed)evt.trigger(window); executed=true;}
};
//For IE
EM.addEventListener(document, 'propertychange', handlers.ie);
//For Mozilla
EM.addEventListener(document,'DOMContentLoaded', handlers.mz);
//For Safari and Opera
if(/WebKit|Khtml/i.test(navigator.userAgent)||(window.opera&&parseInt(window.opera.version())<9))(function(){/loaded|complete/.test(document.readyState)?(evt.trigger(window),executed=true):setTimeout(arguments.callee,100)})();
//For someone else
EM.addEventListener(window, 'load', handlers.mz);
})();

View file

@ -0,0 +1,325 @@
// Array Extensions v1.0.7
// documentation: http://www.dithered.com/javascript/array/index.html
// license: http://creativecommons.org/licenses/by/1.0/
// code by Chris Nott (chris[at]dithered[dot]com)
// code by Ilya Lebedev (ilya[at]lebedev[dot]net)
// Array.concat() - Join two arrays
if (isUndefined(Array.prototype.concat)) {
Array.prototype.concat = function (secondArray) {
var firstArray = this.copy();
for (var i = 0, saL = secondArray.length; i < saL; i++) {
firstArray[firstArray.length] = secondArray[i];
}
return firstArray;
};
}
// Array.copy() - Copy an array
if (isUndefined(Array.prototype.copy)) {
Array.prototype.copy = function() {
var copy = new Array();
for (var i = 0, tL = this.length; i < tL; i++) {
copy[i] = this[i];
}
return copy;
};
}
// Array.pop() - Remove the last element of an array and return it
if (isUndefined(Array.prototype.pop)) {
Array.prototype.pop = function() {
var lastItem = undefined;
if ( this.length > 0 ) {
lastItem = this[this.length - 1];
this.length--;
}
return lastItem;
};
}
// Array.push() - Add an element to the end of an array
if (isUndefined(Array.prototype.push)) {
Array.prototype.push = function() {
var currentLength = this.length;
for (var i = 0; i < arguments.length; i++) {
this[currentLength + i] = arguments[i];
}
return this.length;
};
}
// Array.shift() - Remove the first element of an array and return it
if (isUndefined(Array.prototype.shift)) {
Array.prototype.shift = function() {
var firstItem = this[0];
for (var i = 0, tL = this.length - 1; i < tL; i++) {
this[i] = this[i + 1];
}
this.length--;
return firstItem;
};
}
// Array.slice() - Copy several elements of an array and return them
if (isUndefined(Array.prototype.slice)) {
Array.prototype.slice = function(start, end) {
var temp;
if (end == null || end == '') end = this.length;
// negative arguments measure from the end of the array
else if (end < 0) end = this.length + end;
if (start < 0) start = this.length + start;
// swap limits if they are backwards
if (end < start) {
temp = end;
end = start;
start = temp;
}
// copy elements from array to a new array and return the new array
var newArray = new Array();
for (var i = 0; i < end - start; i++) {
newArray[i] = this[start + i];
}
return newArray;
};
}
// Array.splice() - Splice out and / or replace several elements of an array and return any deleted elements
if (isUndefined(Array.prototype.splice)) {
Array.prototype.splice = function(start, deleteCount) {
if (deleteCount == null || deleteCount == '') deleteCount = this.length - start;
// create a temporary copy of the array
var tempArray = this.copy();
// Copy new elements into array (over-writing old entries)
for (var i = start, aL = start + arguments.length - 2; i < aL; i++) {
this[i] = arguments[i - start + 2];
}
// Copy old entries after the end of the splice back into array and return
var dC = deleteCount - arguments.length + 2;
for (var i = start + arguments.length - 2, tL = this.length - deleteCount + arguments.length - 2; i < tL; i++) {
this[i] = tempArray[i + dC];
}
this.length = this.length - dC;
return tempArray.slice(start, start + deleteCount);
};
}
// Array.unshift - Add an element to the beginning of an array
if (isUndefined(Array.prototype.unshift)) {
Array.prototype.unshift = function(the_item) {
for (var loop = this.length-1 ; loop >= 0; loop--) {
this[loop+1] = this[loop];
}
this[0] = the_item;
return this.length;
};
}
// Array.indexOf - return index of found element or -1 (similar to String.indexOf)
// Don't do the check on 'undefined' because Mozilla does calculate index weirdly
Array.prototype.indexOf = function(needle,begin) {
for (var i=(null==begin||isNaN(begin)||begin<0)?0:Math.round(begin),len = this.length, idx = -1; idx==-1 & i<len; i++) {
idx = (this[i]==needle)?i:idx;
}
return idx;
};
// Array.lastIndexOf - return index of found element or -1 (similar to String.lastIndexOf)
// Don't do the check on 'undefined' because Mozilla does calculate index weirdly
Array.prototype.lastIndexOf = function(needle,end) {
for (var i=(null==end||isNaN(end)||end>this.length)?this.length-1:Math.round(end), idx = -1; idx==-1 & i>-1; i--) {
idx = (this[i]==needle)?i:idx;
}
return idx;
};
// Array.map - maps a function on the array elements
if (isUndefined(Array.prototype.map)) {
Array.prototype.map = function(func) {
if ('function' != typeof func) return this;
var tmp = [];
for (var loop = this.length-1 ; loop >= 0; loop--) {
tmp[loop] = func(this[loop]);
}
return tmp;
};
}
if (isUndefined(Array.prototype.unique)) {
/**
* Method removes dumplicate entries
*
* @return {Array}
* @scope public
*/
Array.prototype.unique = function() /* :Array */{
var tmp = [];
for(var i=0, tL=this.length; i<tL; i++ ) {
if( tmp.indexOf(this[i]) < 0 ) tmp[tmp.length] = this[i];
}
return tmp;
};
}
if (isUndefined(Array.prototype.flatten)) {
/**
* Method flattens 2-dimensional array, when no cols supplied only the cols number from 0th row will be counted
*
* @param {Number, Array} cols columns to insert to resulting array
* @return {Array}
* @scope public
*/
Array.prototype.flatten = function(cols /* :Array */, cd) /* :Array */{
if (this.length<1) return [];
if (isNumeric(cols)) cols = [cols];
var idx = false;
if (isArray(cols)) {
idx = {};
for (var i=0,cL=cols.length;i<cL;i++) idx[cols[i]]=true;
}
var tmp = [];
for (var i=0, tL=this.length; i<tL; i++ ) {
if (isUndefined(this[i])) continue;
if (!isArray(this[i])) {
if (false===idx) tmp[tmp.length] = this[i];
} else {
for (var k=0, cL=this[i].length; k<cL; k++) {
if (false===idx || idx.hasOwnProperty(k)) tmp[tmp.length] = this[i][k];
}
}
}
return tmp;
};
}
if (isUndefined(Array.prototype.filter)) {
/**
* Method returns array with non-empty (not evaluating to false) entries
*
* @param {Function} cbk optional callback function to perform a filter
* @return {Array}
* @scope public
*/
Array.prototype.filter = function(cbk /* :Function */) /* :Array */ {
if (!isFunction(cbk)) cbk = null;
for (var i=0, tL = this.length, tmp = [], ti=null; i<tL;i++) {
ti = cbk?cbk(this[i]):this[i];
if (!isEmpty(ti)) tmp[tmp.length] = ti;
}
return tmp;
};
}
if (isUndefined(Array.prototype.binSearch)) {
/**
* Provides binary search for the sorted array, causes unexpected results on unsorted one
*
* @param {Variant} el element to search for
* @return {Number} array index
* @scope public
*/
Array.prototype.binSearch = function (el,key) {
var l = 0
,r = this.length
,len = Math.max(r-1,0)
,c = Math.ceil(r/2)
,cnt = 0
if (null != key)
while ((!this[c] || el!=this[c][key]) && r>=l) {
if (this[c] && el>this[c][key])
l=c+1
else
r=c-1
c=Math.max(0,Math.ceil((r+l)/2))
}
else
while (el!=this[c] && r>=l) {
if (el>this[c])
l=c+1
else
r=c-1
c=Math.max(0,Math.ceil((r+l)/2));
}
return c
}
}
/**
* heap sort ( N log N )
*
* @scope public
*/
Array.prototype.heapSort = function () {
// prepare the array with special sorting method
if (!this.sift) {
/**
* Innersorting method for the heap sort
*
* @param {Number} low
* @param {Number} up
*/
this.sift = function (low, up) {
var c, tmp = this[low];
while(true){
c = (low << 1) + 1;
if( c > up ) break;
if( c < up && this[c+1][0] > this[c][0] ) c++;
if( tmp[0] >= this[c][0] ) break;
this[low] = this[c]; // 1/2 (mini) swap ))
low = c;
}
this[low] = tmp;
}
}
var tmp,
maximal = this.length - 1,
i = maximal << 1;
while( i >= 0 ){ this.sift(i--, maximal) };
i = maximal;
while( i > 0 ){
// full swap
tmp = this[0];
this[0] = this[i];
this[i] = tmp;
this.sift(0,--i);
}
}
//-----------------------------------------------------------------------------
// STATIC METHODS
//-----------------------------------------------------------------------------
if (isUndefined(Array.range)) {
/**
* Method creates the array with values in the specified range
* 1 argument: create array from min(0, end) to max(0, end) with increment 1
* 2 arguments: create array from min(start, end) to max(start, end) with increment 1
* 3 arguments: create array from min(start, end) to max(start, end) with increment inc
*
* @param {Number} end end position
* @param {Number} start start position
* @param {Number} inc increment
* @return {Array}
* @scope public
*/
Array.range = function(end /* :Number */, start /* :Number */, inc /* :Number */) /* :Array */{
if (!isNumber(end)) return null;
if (!isNumber(inc)) inc = 1;
if (!isNumber(start)) start = 0;
var tmp = []
,mn = Math.min(start, end)
,mx = Math.max(start, end)
,i = Math.abs(inc)
,cnt = -1;
do {
cnt++;
tmp[cnt] = mn;
mn += i;
} while (mn<=mx);
return inc>0?tmp:tmp.reverse();
};
}

View file

@ -0,0 +1,12 @@
/*
* Checks if property is derived from prototype, applies method if it is not exists
*
* @param string property name
* @return bool true if prototyped
* @access public
*/
if ('undefined' == typeof Object.hasOwnProperty) {
Object.prototype.hasOwnProperty = function (prop) {
return !('undefined' == typeof this[prop] || this.constructor && this.constructor.prototype[prop] && this[prop] === this.constructor.prototype[prop]);
}
}

View file

@ -0,0 +1,33 @@
/**************************************************
*
* Extensions for the RegExp object
*
* @author Ilya Lebedev <ilya@lebedev.net>
* @modified $Date: 2007-10-26 19:25:39 +0400 (Птн, 26 Окт 2007) $
* @version $Rev: 339 $
* @license LGPL 2.1 or later
**************************************************/
/**
* Does escape of special regexp characters
*
* Modified version from Simon Willison
*
* @see http://simon.incutio.com/archive/2006/01/20/escape
* @param {String, Array} text to escape
* @return {String} escaped result
* @scope public
*/
RegExp.escape = function(text /* :String, Array */) /* :String */ {
if (!arguments.callee.sRE) {
var specials = [
'/', '.', '*', '+', '?', '|',
'(', ')', '[', ']', '{', '}', '$', '^', '\\'
];
arguments.callee.sRE = new RegExp(
'(\\' + specials.join('|\\') + ')', 'g'
);
}
return isString(text)?text.replace(arguments.callee.sRE, '\\$1')
:(isArray(text)?text.map(RegExp.escape).join("|")
:"");
}

View file

@ -0,0 +1,307 @@
/**
* $Id: string.js 370 2007-11-25 01:39:30Z wingedfox $
* $HeadURL: https://svn.debugger.ru/repos/jslibs/BrowserExtensions/tags/BrowserExtensions.018/ext/string.js $
*
* @author Ildar Shaimordanov
* @author Ilya Lebedev
* @license LGPL
* @version $Rev: 370 $
*/
/**
* Decodes html entities
*
* @return {String} string with decoded entities
* @scope public
*/
String.prototype.entityDecode = function() {
if (!arguments.callee.span) arguments.callee.span = document.createElement('span');
var s = arguments.callee.span;
s.innerHTML = this;
return s.firstChild?s.firstChild.nodeValue:"";
}
/**
* Method is used to trim specified chars from the left of the string
*
* @param {String, Array} c char or char list to be trimmed, default is \s
* @return {String}
* @scope public
*/
String.prototype.ltrim = function(c) {
if (isString(c)) c=c.split("");
if (isArray(c) || isUndefined(c)) {
c = isEmpty(c)?"\\s":RegExp.escape(c);
c = new RegExp("^(?:"+c+")+", "g");
return this.replace(c, "");
}
return this;
}
/**
* Method is used to trim specified list from the right of the string
*
* @param {String, Array} c char or char sequence to be trimmed, default is \s
* @return {String}
* @scope public
*/
String.prototype.rtrim = function(c) {
if (isString(c)) c=c.split("");
if (isArray(c) || isUndefined(c)) {
c = isEmpty(c)?"\\s":RegExp.escape(c);
c = new RegExp("(?:"+c+")+$", "g");
return this.replace(c, "");
}
return this;
}
/**
* Method is used to trim specified chars from the left and the right of the string
*
* @param {String, Array} c char or char list to be trimmed, default is \s
* @return {String}
* @scope public
*/
String.prototype.trim = function(c) {
if (isString(c)) c=c.split("");
if (isArray(c) || isUndefined(c)) {
c = isEmpty(c)?"\\s":RegExp.escape(c);
c = new RegExp("^(?:"+c+")+|(?:"+c+")+$", "g");
return this.replace(c, "");
}
return this;
}
/**
* Duplicates the string
*
* @return {String}
* @scope public
*/
String.prototype.dup = function() {
var val = this.valueOf();
return [val,val].join("");
}
/**
* Repeats string specified number of times
*
* @param {Number} n number of times to repeat the string
* @return {String}
* @scope public
*/
String.prototype.repeat = function(n /* :Number */) /* :String */ {
if (isNaN(n=parseInt(n)) || n<0) return "";
return Array(n+1).join(this.valueOf());
}
/**
* Pads the string to the specified length
*
* @param {Number} n number of times to repeat c
* positive - on the right side
* negative - on the left side
* @param {String} c fill char, space is default
* @return {String}
* @scope public
*/
String.prototype.padding = function(n, c) {
var val = this.valueOf();
n = parseInt(n);
if (!n) return val;
if (isUndefined(c)) c = " ";
var pad = String(c).charAt(0).repeat(Math.abs(n) - this.length);
return (n < 0) ? pad + val : val + pad;
}
/**
* Pads the string on the right side
*
* @param {Number} n number of times to repeat c
* @param {String} c fill char
* @return {String}
* @scope public
*/
String.prototype.padLeft = function(n, c) {
return this.padding(-Math.abs(n), c);
}
/**
* Pads the string on the left side
*
* @param {Number} n number of times to repeat c
* @param {String} c fill char
* @return {String}
* @scope public
*/
String.prototype.padRight = function(n, c) {
return this.padding(Math.abs(n), c);
}
/**
* sprintf(format, argument_list)
*
* The string format function like the one in C/C++, PHP, Perl
* Each conversion specification is defined as below:
*
* %[index][alignment][padding][width][precision]type
*
* index An optional index specifier that changes the order of the
* arguments in the list to be displayed.
* alignment An optional alignment specifier that says if the result should be
* left-justified or right-justified. The default is
* right-justified; a "-" character here will make it left-justified.
* padding An optional padding specifier that says what character will be
* used for padding the results to the right string size. This may
* be a space character or a "0" (zero character). The default is to
* pad with spaces. An alternate padding character can be specified
* by prefixing it with a single quote ('). See the examples below.
* width An optional number, a width specifier that says how many
* characters (minimum) this conversion should result in.
* precision An optional precision specifier that says how many decimal digits
* should be displayed for floating-point numbers. This option has
* no effect for other types than float.
* type A type specifier that says what type the argument data should be
* treated as. Possible types:
*
* % - a literal percent character. No argument is required.
* b - the argument is treated as an integer, and presented as a binary number.
* c - the argument is treated as an integer, and presented as the character
* with that ASCII value.
* d - the argument is treated as an integer, and presented as a decimal number.
* u - the same as "d".
* f - the argument is treated as a float, and presented as a floating-point.
* o - the argument is treated as an integer, and presented as an octal number.
* s - the argument is treated as and presented as a string.
* x - the argument is treated as an integer and presented as a hexadecimal
* number (with lowercase letters).
* X - the argument is treated as an integer and presented as a hexadecimal
* number (with uppercase letters).
*
* @return {String}
* @scope public
*/
String.prototype.sprintf = function() {
var args = isArray(arguments[0])?arguments[0]:arguments
,index = 0
,frmt = this.replace(/%%/g, "\0\0")
,re = /%((?:\d+\$)?)((?:[-0+# ])?)((?:\d+|\*(?:\d+\$)?)?)((?:.(?:\d+|\*(?:\d+\$)?))?)([bcdeEfosuxX])/g;
/*
* The re.exec() method returns the array with the following properties
* wich are used in this function
* x.index contains the substring position found at the origin string
* x[0] contains the found substring
* x[1] contains the explicit parameter number
* x[2] contains the flags
* x[3] contains the minwidth
* x[4] contains the precision
* x[5] contains the type specifier (as [bcdfosuxX])
*/
frmt = frmt.replace(re, function() {
var x = arguments
,sign = false
,ins;
/*
* calculate min width
*/
if (!isUndefined(x[3]) && x[3].indexOf("*")==0) {
x[3] = parseInt(x[3].replace(/\D/g,""))
if (isNaN(x[3])) {
x[3] = args[index];
/*
* increment
*/
index++;
} else {
x[3] = args[x[3]]
}
}
/*
* calculate precision
*/
if ("" != x[4]) {
if (x[4].indexOf("*")==1) {
x[4] = parseInt(x[4].replace(/\D/g,""))
if (isNaN(x[4])) {
x[4] = args[index];
/*
* increment
*/
index++;
} else {
x[4] = args[x[4]]
}
} else {
x[4] = x[4].replace(/\D/,"")
}
x[4] = Math.abs(x[4]);
}
/*
* calculate insertion value
*/
x[1] = parseInt(x[1]);
var ins;
if (isNumeric(x[1])) {
ins = args[x[1]];
} else {
ins = args[index];
/*
* index should be incremented only when no explicit parameter number is specified
*/
index++;
}
switch (x[5]) {
case "b":
if (ins<0) ins = 0x10000000000000000+parseInt(ins);
ins = Number(ins).bin(x[4]);
if (x[4]) ins = ins.substr(0,x[4]);
if (x[2]=='#') ins = '0b'+ins;
break;
case "c":
ins = String.fromCharCode(ins);
break;
case "u":
ins = Math.abs(ins);
case "d":
ins = Math.round(ins);
if (ins<0) {
ins = "-"+Math.abs(ins).dec(x[4]);
} else {
ins = Number(ins).dec(x[4]);
sign = (x[2] == ' ' || x[2] == '+');
}
break;
case "e":
case "E":
if (ins>0) {
sign = (x[2] == ' ' || x[2] == '+');
}
ins = Number(ins).toExponential(x[4]?x[4]:6);
if (x[5]=='E') ins=ins.toUpperCase();
break;
case "f":
if (ins>0) {
sign = (x[2] == ' ' || x[2] == '+');
}
ins = Number(ins).toFixed(isNumeric(x[4])?x[4]:6);
break;
case "o":
if (ins<0) ins = 0x10000000000000000+parseInt(ins);
ins = Number(ins).toString(8);
if (x[4]) ins = ins.substr(0,x[4]);
if (x[2]=='#' && ins != 0) ins = '0'+ins;
break;
case "s":
ins = String(ins);
if (x[4]) ins = ins.substr(0,x[4]);
break;
case "x":
case "X":
if (ins<0) ins = 0x10000000000000000+parseInt(ins);
ins = Number(ins).hex(-x[4]);
if (x[4]) ins = ins.substr(0,x[4]);
if (x[2]=='#') ins = '0x'+ins;
if (x[5]=='X') ins = ins.toUpperCase();
break;
}
if (sign) ins = x[2]+ins;
if (x[3]) ins = (x[2]=='-' || x[3]<0)?ins.padRight(x[3]):ins.padLeft(x[3],x[2]=='0'?0:" ");
return ins;
})
return frmt.replace(/\0\0/g, "%");
}

View file

@ -0,0 +1,388 @@
/**
* $Id: helpers.js 366 2007-11-24 02:27:32Z wingedfox $
* $HeadURL: https://svn.debugger.ru/repos/jslibs/BrowserExtensions/tags/BrowserExtensions.018/helpers.js $
*
* File contains differrent helper functions
*
* @author Ilya Lebedev <ilya@lebedev.net>
* @license LGPL
* @version $Rev: 366 $
*/
//-----------------------------------------------------------------------------
// Variable/property checks
//-----------------------------------------------------------------------------
/**
* Checks if property is undefined
*
* @param {Object} prop value to check
* @return {Boolean} true if matched
* @scope public
*/
function isUndefined (prop /* :Object */) /* :Boolean */ {
return (typeof prop == 'undefined');
}
/**
* Checks if property is function
*
* @param {Object} prop value to check
* @return {Boolean} true if matched
* @scope public
*/
function isFunction (prop /* :Object */) /* :Boolean */ {
return (typeof prop == 'function');
}
/**
* Checks if property is string
*
* @param {Object} prop value to check
* @return {Boolean} true if matched
* @scope public
*/
function isString (prop /* :Object */) /* :Boolean */ {
return (typeof prop == 'string');
}
/**
* Checks if property is number
*
* @param {Object} prop value to check
* @return {Boolean} true if matched
* @scope public
*/
function isNumber (prop /* :Object */) /* :Boolean */ {
return (typeof prop == 'number');
}
/**
* Checks if property is the calculable number
*
* @param {Object} prop value to check
* @return {Boolean} true if matched
* @scope public
*/
function isNumeric (prop /* :Object */) /* :Boolean */ {
return (isNumber(prop)||isString(prop))&&!isNaN(parseInt(prop))&&isFinite(parseInt(prop));
}
/**
* Checks if property is array
*
* @param {Object} prop value to check
* @return {Boolean} true if matched
* @scope public
*/
function isArray (prop /* :Object */) /* :Boolean */ {
return (prop instanceof Array);
}
/**
* Checks if property is regexp
*
* @param {Object} prop value to check
* @return {Boolean} true if matched
* @scope public
*/
function isRegExp (prop /* :Object */) /* :Boolean */ {
return (prop instanceof RegExp);
}
/**
* Checks if property is a boolean value
*
* @param {Object} prop value to check
* @return {Boolean} true if matched
* @scope public
*/
function isBoolean (prop /* :Object */) /* :Boolean */ {
return ('boolean' == typeof prop);
}
/**
* Checks if property is a scalar value (value that could be used as the hash key)
*
* @param {Object} prop value to check
* @return {Boolean} true if matched
* @scope public
*/
function isScalar (prop /* :Object */) /* :Boolean */ {
return isNumeric(prop)||isString(prop)||isBoolean(prop);
}
/**
* Checks if property is empty
*
* @param {Object} prop value to check
* @return {Boolean} true if matched
* @scope public
*/
function isEmpty (prop /* :Object */) /* :Boolean */ {
if (isBoolean(prop)) return false;
if (isRegExp(prop) && new RegExp("").toString() == prop.toString()) return true;
if (isString(prop) || isNumber(prop)) return !prop;
if (Boolean(prop)&&false != prop) {
for (var i in prop) if(prop.hasOwnProperty(i)) return false
}
return true;
}
//-----------------------------------------------------------------------------
// File paths functions
//-----------------------------------------------------------------------------
/**
* used to glue path's
*
* @param {String} number of strings
* @return {String} glued path
* @scope public
*/
function gluePath () /* :String */ {
var aL=arguments.length, i=aL-2, s = arguments[aL-1];
for(;i>=0;i--)
s = ((!isString(arguments[i])&&!isNumber(arguments[i]))||isEmpty(arguments[i])
?s
:arguments[i]+'\x00'+s);
return s?s.replace(/\/*\x00+\/*/g,"/"):"";
}
/**
* return full path to the script
*
* @param {String} sname script name
* @return {String, Null} mixed string full path or null
* @scope public
*/
function findPath (sname /* :String */) /* :String */{
var h =document.getElementsByTagName('html')[0].innerHTML
,sr=new RegExp('<scr'+'ipt[^>]+?src\s*=\s*["\']?([^>]+?/)'+sname+'[^>]*>.?</scr'+'ipt>','i')
,m =h.match(sr);
if (m) {
/*
* we've matched the full path
*/
if (m[1].match(/^((https?|file)\:\/{2,}|\w:[\\])/)) return m[1];
/*
* we've matched absolute path from the site root
*/
if (m[1].indexOf("/")==0) return m[1];
b = document.getElementsByTagName('base');
if (b[0] && b[0].href) return b[0].href+m[1];
/*
* return matching part of the document location and path to js file
*/
return (document.location.href.match(/(.*[\/\\])/)[0]+m[1]).replace(/^\/+/,"");
}
return null;
}
/**
* return parsed query string for the specified script name
*
* @param {String} sname script name
* @return {String, Null} mixed string full path or null
* @scope public
*/
function getScriptQuery (sname) {
var h =document.getElementsByTagName('html')[0].innerHTML
,sr=new RegExp('<scr'+'ipt[^>]+?src\s*[^>]+?/'+sname+'([^#"\']*).+?</scr'+'ipt>','i')
,m = h.match(sr);
if (m) return parseQuery(m[1].replace(/^[^?]*\?([^#]+)/,"$1"));
return {};
}
/**
* Function parses supplied query string and returns the hash with the values
* Multiple values are stored in the array
*
* @param {String} q query string
* @return {Object}
* @scope public
*/
function parseQuery (q) {
if ('string'!=typeof q || q.length<2) return {};
q = q.split(/&amp;|&/g);
for (var z=0,qL=q.length,rs={},kv,rkv;z<qL;z++) {
kv=q[z].split("=");
/*
* convert PHP and Perl-styled hashes to JS has keys
*/
kv[0]=kv[0].replace(/[{}\[\]]*$/,"");
rkv = rs[kv[0]];
/*
* replace all + with spaces, unescape skips this part
*/
kv[1]=unescape(kv[1]?kv[1].replace("+"," "):"");
if (rkv)
if ('array'==typeof(rkv))rs[kv[0]][rs[kv[0]].length]=kv[1];
else rs[kv[0]]=[rs[kv[0]],kv[1]];
else rs[kv[0]]=kv[1];
}
return rs
}
//-----------------------------------------------------------------------------
// Misc helpers
//-----------------------------------------------------------------------------
/**
* Method is used to convert table into the array
*
* @param {String, HTMLTableElement, HTMLTBodyElement, HTMLTHeadElement, HTMLTFootElement} id
* @param {Number} ci column indexes to put in the array
* @param {String} section optional section type
* @param {Object} subsection optional subsection index
* @return {NULL, Array}
* @scope public
*/
function table2array (id, ci, section, subsection) {
if (isString(id)) id = document.getElementById(id);
if (!id || !DOM.hasTagName(id, ['table','tbody,','thead','tfoot'])) return null;
if (!isEmpty(section) && (!isString(section) || !(id = id.getElementsByTagName(section)))) return null;
if (!isEmpty(subsection) && (!isNumber(subsection) || subsection<0 || !(id = id[subsection]))) return null;
if (isUndefined(id.rows)) return null;
var res = []
,span = document.createElement('span')
,ts = null
,ce = null
for (var i=0, rL=id.rows.length; i<rL; i++) {
var tr = [];
if (isArray(ci)) {
for (var z=0, cL=ci.length; z<cL; z++) {
ce = id.rows[i].cells[ci[z]];
if (ce) {
span.innerHTML = ce.innerText?ce.innerText:ce.innerHTML.replace(/<script\s+(.|\r?\n)*?<\/script>|<[^>]*>/g,"");
span.normalize();
tr[tr.length] = span.firstChild?span.firstChild.nodeValue.trim(" \xA0"):"";
} else {
tr[tr.length] = "";
}
}
} else {
for (var z=0, tL=id.rows[i].cells.length; z<tL; z++) {
cd = id.rows[i].cells[z];
span.innerHTML = ce.innerText?ce.innerText:ce.innerHTML.replace(/<script\s+(.|\r?\n)*?<\/script>|<[^>]*>/g,"");
span.normalize();
tr[tr.length] = span.firstChild?span.firstChild.nodeValue.trim(" \xA0"):"";
}
}
if (!isEmpty(tr)) res[res.length] = tr;
}
return res;
}
/**
* Creates element all-at-once
*
* @param {String} tag name
* @param {Object} p element properties { 'class' : 'className',
* 'style' : { 'property' : value, ... },
* 'event' : { 'eventType' : handler, ... },
* 'child' : [ child1, child2, ...],
* 'param' : { 'property' : value, ... },
* @return {HTMLElement} created element or null
* @scope public
*/
document.createElementExt = function (tag /* :String */, p /* :Object */ ) /* :HTMLElement */{
var L, i, k, el = document.createElement(tag);
if (!el) return null;
for (i in p) {
if (!p.hasOwnProperty(i)) continue;
switch (i) {
case "class" : el.setAttribute('className',p[i]); el.setAttribute('class',p[i]); break;
case "style" : for (k in p[i]) { if (!p[i].hasOwnProperty(k)) continue; el.style[k] = p[i][k]; } break;
case "event" : for (k in p[i]) { if (!p[i].hasOwnProperty(k)) continue; el.attachEvent(k,p[i][k]); } break;
case "child" : L = p[i].length; for (k = 0; k<L; k++) el.appendChild(p[i][k]); break;
case "param" : for (k in p[i]) { if (!p[i].hasOwnProperty(k)) continue; try { el[k] = p[i][k] } catch(e) {} } break;
}
}
return el;
}
/**
* simple setInterval/setTimout wrappers
*
* @param {Function} f function to be launched
* @param {Number} i interval
* @param {Array} o optional function parameters to be applied
* @return {Number} interval id
* @scope public
*/
function playInterval (f /* :Function */, i /* :Number */, o /* :Array */) /* :Number */ { return setInterval(function(){(o instanceof Array)?f.apply(this,o):f.call(this,o)},i) }
function playTimeout (f /* :Function */, i /* :Number */, o /* :Array */) /* :Number */ { return setTimeout(function(){(o instanceof Array)?f.apply(this,o):f.call(this,o)},i) }
/**
* Clone object
*
* @param optional object to clone
* @return cloned object
* @access public
*/
function cloneObject (obj) {
if (isScalar(obj) || isFunction(obj) || null == obj) return obj;
try { var newObject = new obj.constructor(); } catch(e) {return null;}
if (isArray(newObject)) {
for (var i=0,oL=obj.length;i<oL;i++) {
newObject[i] = cloneObject(obj[i]);
}
} else {
for (var i in obj) {
if (!obj.hasOwnProperty(i)) continue;
newObject[i] = cloneObject(obj[i]);
}
}
return newObject;
}
/**
* Merges multiple objects to one
*
* @param {Object} obj1 original object
* @param {Object} obj2 update object
* @param {Object} objN update object
* @return {Object}
* @access public
*/
function mergeObject () {
var res = {}
,oi
,obj
for (var z=0,aL=arguments.length;z<aL;z++) {
obj = arguments[z];
for (var i in obj) {
if (!obj.hasOwnProperty(i)) continue;
oi = obj[i];
if (null == oi) {
if (!res.hasOwnProperty(i)) res[i] = oi;
} else if (isArray(oi)) {
if (isArray(res[i]))
res[i] = res[i].concat(oi).unique();
else
res[i] = oi.slice(0);
} else if (isScalar(oi) || isFunction(oi)) {
res[i] = oi;
} else {
if (res.hasOwnProperty(i))
res[i] = mergeObject(res[i],oi)
else
res[i] = cloneObject(oi);
}
}
}
return res;
}
//-----------------------------------------------------------------------------
// Loaders
//-----------------------------------------------------------------------------
/**
* Method to load stylesheets
*
* @param {String} sn path to stylesheet
* @return {HTMLLinkElement} reference to the corresponding link
*/
function loadStyleSheet (sn) {
var head = document.getElementsByTagName('head')[0]
,links = head.getElementsByTagName('link')
,ll = links.length
,cl;
while (--ll>-1) {
cl = links[ll];
if (!cl.rel || cl.rel.toLowerCase() != 'stylesheet' || cl.src != sn) continue;
return cl;
}
var link = document.createElementExt('link',{'param': { 'rel': 'stylesheet', 'type': 'text/css', 'href': sn}})
head.appendChild(link);
return link;
}

View file

@ -0,0 +1,200 @@
/**
* $Id: scriptqueue.js 351 2007-11-13 12:56:18Z wingedfox $
* $HeadURL: https://svn.debugger.ru/repos/jslibs/BrowserExtensions/tags/BrowserExtensions.018/scriptqueue.js $
*
* Dynamically load scripts and script queues (when load order is important)
*
**********NOTE********
* If you need to load any scripts before ScriptQueue exists, use the following snippet
* <code>
* if (!(window.ScriptQueueIncludes instanceof Array)) window.ScriptQueueIncludes = []
* window.ScriptQueueIncludes = window.ScriptQueueIncludes.concat(scriptsarray);
* </code>
* ScriptQueue loads all the scripts, queued before its' load in the ScriptQueueIncludes
**********
*
* @author Ilya Lebedev <ilya@lebedev.net>
* @modified $Date: 2007-11-13 15:56:18 +0300 (Втр, 13 Ноя 2007) $
* @version $Rev: 351 $
* @license LGPL 2.1 or later
*
* @class ScriptQueue
* @param {Function} optional callback function, called on each successful script load
* @scope public
*/
ScriptQueue = function (cbk) {
var self = this
,static = arguments.callee;
/*
* empty function is better than number of checks in the code...
*/
if ('function' != typeof cbk) cbk = function(){}
/**
* Queue for the current loader instance
*
* @type {Array}
* @scope private
*/
var queue = [];
//-------------------------------------------------------------------------
// PUBLIC
//-------------------------------------------------------------------------
/**
* Loads the single script, independent from any other
*
* @param {String} path path to the target script
* @return {Boolean} true when script is getting loaded, false otherwise
* @scope public
*/
self.load = function (path) {
load(path,cbk);
}
/**
* Builds a queue of scripts, when they should be loaded in the proper order
*
* @param {String} path script name to add to the queue
* @scope public
*/
self.queue = function (path) {
var f = queue.length;
queue[f] = path;
if (!f) load(path,queuemonitor);
}
//-------------------------------------------------------------------------
// PRIVATE
//-------------------------------------------------------------------------
/**
* Performs scripts existense check and loads it, if needed
*
* @param {String} path path to the script
* @param {Function} cbk callback
* @scope private
*/
var load = function (path, cbk) {
var sid
,scr = static.scripts;
if (sid = scr.hash[path]) { // in queue
scr = static.scripts[sid]
if (scr[2]) { // loaded
cbk(path,scr[2]);
} else {
scr[1].push(cbk);
}
} else {
sid = scr.length;
scr[sid] = [path,[cbk],false];
scr.hash[path] = sid;
ls(path);
}
}
/**
* Attaches script to the document
*
* @param {String} src path to script
* @scope private
*/
var ls = function (src) {
if (document.body) { // document is loaded, don't use document.write
var s = document.createElement('script')
,h = document.getElementsByTagName("head")[0];
s.type= "text/javascript";
s.charset="UTF-8";
s.src=src;
/*
* some browsers does change the src, store original one here
*/
s.rSrc=src;
s.onload = s.onreadystatechange = loadmonitor;
h.appendChild(s);
} else {
document.write("<scr"+"ipt onload=\"\" src=\""+src+"\" charset=\"UTF-8\"></scr"+"ipt>");
/*
* note, real onload handler is commented out, because IE calls it too late,
* which is not acceptable, because it breaks onload there
* assume, that scripts are loaded successfully
*/
// s.onload = s.onreadystatechange = loadmonitor;
loadmonitor.call({'rSrc':src},{'type':'load'});
}
}
//-------------------------------------------------------------------------
// PROTECTED
//-------------------------------------------------------------------------
/**
* Monitors queue load and runs next iteration, untill empties the queue
*
* @param {String} path loaded script
* @param {Boolean} s load completed status
* @scope protected
*/
var queuemonitor = function (path,s) {
/*
* execute the user callback
*/
cbk(path,s);
queue.splice(0,1);
/*
* next run
*/
if (queue.length && s)
load(queue[0],arguments.callee);
else
cbk(null,s)
}
/**
* Handles onload and onreadystatechange events
*
* @param {Event} e handled event object
* @scope protected
*/
var loadmonitor = function (e) {
var scr = static.scripts
,sid = scr.hash[this.rSrc]
,e = e||window.event
scr = scr[sid];
if (('load' == e.type || 'complete'==this.readyState)) {
if (!scr[2])
scr[2] = true;
else
return; // prevent duplicate calls from event handler
}
for (var i=0,cbk=scr[1],cL=cbk.length;i<cL;i++) {
cbk[i](scr[0],scr[2]);
}
}
}
/**
* Stores information about the loaded scripts
* Element structure:
* [0 : string script path
* 1 : [ array of callback functions ]
* 2 : boolean 'loaded' flag
* ]
* Array fields:
* .hash { maps script paths' to array ids }
*
* @type {Array}
* @scope protected
*/
ScriptQueue.scripts = [false];
ScriptQueue.scripts.hash = {};
/**
* Static method to load bunch of scripts at once
* note, there's no callback support
*
* @param {Array} arr list of scripts to execute
* @scope public
*/
ScriptQueue.queue = function(arr) {
if (!arr.length) return;
var q = new ScriptQueue;
for (var i=0,aL=arr.length;i<aL;i++) {
q.queue(arr[i]);
}
}
/*
* If any load requests does exists, serve them
*/
if (window.ScriptQueueIncludes instanceof Array) {
ScriptQueue.queue(window.ScriptQueueIncludes);
}

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,92 @@
VirtualKeyboard = new function () {
var self = this, to = null;
self.show = self.hide = self.toggle = self.attachInput = function () {
window.status = 'VirtualKeyboard is not loaded yet.';
if (!to) setTimeout(function(){window.status = ''},1000);
}
self.isOpen = function () {
return false;
}
};
(function () {
var pq = function (q) {if ('string'!=typeof q || q.length<2) return {};q = q.split(/&amp;|&/g);for (var z=0,qL=q.length,rs={},kv,rkv;z<qL;z++){kv=q[z].split("=");kv[0]=kv[0].replace(/[{}\[\]]*$/,"");rkv = rs[kv[0]];kv[1]=unescape(kv[1]?kv[1].replace("+"," "):"");if (rkv)if ('array'==typeof(rkv))rs[kv[0]][rs[kv[0]].length]=kv[1];else rs[kv[0]]=[rs[kv[0]],kv[1]];else rs[kv[0]]=kv[1];}return rs}
/*
* track, how we've opened
*/
var targetWindow = window.dialogArguments||window.opener||window.top
,addHead = null
,targetScript = 'vk_loader.js';
try {
if (targetWindow != window) {
var addHead = targetWindow.document.getElementsByTagName('head')[0];
var targetScript = window.location.href.match(/.*\/(.+)\..+$/)[1]+'.js';
}
} catch (e) {
targetWindow = window;
}
q = (function (sname,td){var h=(td||document).getElementsByTagName('html')[0].innerHTML,sr=new RegExp('<scr'+'ipt[^>]+?src[^"\']+.*?'+sname+'([^#"\']*)','i'),m = h.match(sr);if (m) return pq(m[1].replace(/^[^?]*\?([^#]+)/,"$1"));return {};})(targetScript,targetWindow.document)
var p = (function (sname){var sc=document.getElementsByTagName('script'),sr=new RegExp('^(.*/|)('+sname+')([#?]|$)');for (var i=0,scL=sc.length; i<scL; i++) {var m = String(sc[i].src).match(sr);if (m) {if (m[1].match(/^((https?|file)\:\/{2,}|\w:[\\])/)) return m[1];if (m[1].indexOf("/")==0) return m[1];b = document.getElementsByTagName('base');if (b[0] && b[0].href) return b[0].href+m[1];return (document.location.href.match(/(.*[\/\\])/)[0]+m[1]).replace(/^\/+/,"");}}return null;})
('vk_loader.js');
var qs = pq(targetWindow.location.search.slice(1));
var dpd = [ 'extensions/helpers.js'
,'extensions/dom.js'
,'extensions/ext/object.js'
,'extensions/ext/string.js'
,'extensions/ext/regexp.js'
,'extensions/ext/array.js'
,'extensions/eventmanager.js'
,'extensions/documentselection.js'
/*
* not used by default
*
* ,'layouts/unconverted.js'
*/
];
q.skin = qs.vk_skin || q.vk_skin || 'winxp';
q.layout = qs.vk_layout || q.vk_layout || null;
var head = document.getElementsByTagName('head')[0]
,s;
/*
* load styles at the proper places
*/
s = document.createElement('link');
s.rel = 'stylesheet';
s.type= 'text/css';
s.href= p+'css/'+q.skin+'/keyboard.css';
head.appendChild(s);
if (addHead) {
var lnk = targetWindow.document.createElement('link');
lnk.rel = 'stylesheet';
lnk.type= 'text/css';
lnk.href= p+'css/'+q.skin+'/keyboard.css';
addHead.appendChild(lnk);
lnk = null;
}
for (var i=0,dL=dpd.length;i<dL;i++)
dpd[i] = p+dpd[i];
dpd[i++] = p+'virtualkeyboard.js?layout='+q.layout;
dpd[i] = p+'layouts/layouts.js';
if (window.ScriptQueue) {
ScriptQueue.queue(dpd);
} else {
if (!(window.ScriptQueueIncludes instanceof Array)) window.ScriptQueueIncludes = []
window.ScriptQueueIncludes = window.ScriptQueueIncludes.concat(dpd);
/*
* attach script loader
*/
if (document.body) {
s = document.createElement('script');
s.type="text/javascript";
s.src = p+'extensions/scriptqueue.js';
head.appendChild(s);
} else {
document.write("<scr"+"ipt type=\"text/javascript\" src=\""+p+'extensions/scriptqueue.js'+"\"></scr"+"ipt>");
}
}
})();

View file

@ -0,0 +1,16 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:py="http://purl.org/kid/ns#"
py:extends="'master.kid'">
<head>
<meta content="text/html; charset=utf-8" http-equiv="Content-Type" py:replace="''"/>
<meta http-equiv="refresh" content="5;URL=${tg.url('/mailtext')}" />
<title>K&auml;&auml;&auml;&auml;&auml;&auml;&auml;sekuchen!</title>
</head>
<body>
<div id="live_pic"><img src="../static/images/fotokiosk-default.png"
py:attrs="src=video_url"/></div>
</body>
</html>

View file

@ -0,0 +1,114 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:py="http://purl.org/kid/ns#">
<head>
<meta content="text/html; charset=UTF-8"
http-equiv="content-type" py:replace="''"/>
<title>Login</title>
<style type="text/css">
#loginBox
{
width: 30%;
margin: auto;
margin-top: 10%;
padding-left: 10%;
padding-right: 10%;
padding-top: 5%;
padding-bottom: 5%;
font-family: verdana;
font-size: 10px;
background-color: #eee;
border: 2px solid #ccc;
}
#loginBox h1
{
font-size: 42px;
font-family: "Trebuchet MS";
margin: 0;
color: #ddd;
}
#loginBox p
{
position: relative;
top: -1.5em;
padding-left: 4em;
font-size: 12px;
margin: 0;
color: #666;
}
#loginBox table
{
table-layout: fixed;
border-spacing: 0;
width: 100%;
}
#loginBox td.label
{
width: 33%;
text-align: right;
}
#loginBox td.field
{
width: 66%;
}
#loginBox td.field input
{
width: 100%;
}
#loginBox td.buttons
{
text-align: right;
}
</style>
</head>
<body>
<div id="loginBox">
<h1>Login</h1>
<p>${message}</p>
<form action="${previous_url}" method="POST">
<table>
<tr>
<td class="label">
<label for="user_name">User Name:</label>
</td>
<td class="field">
<input type="text" id="user_name" name="user_name"/>
</td>
</tr>
<tr>
<td class="label">
<label for="password">Password:</label>
</td>
<td class="field">
<input type="password" id="password" name="password"/>
</td>
</tr>
<tr>
<td colspan="2" class="buttons">
<input class="button" type="submit" name="login" value="Login"/>
</td>
</tr>
</table>
<input py:if="forward_url" type="hidden" name="forward_url"
value="${forward_url}"/>
<div py:for="name,values in original_parameters.items()" py:strip="1">
<input py:for="value in isinstance(values, list) and values or [values]"
type="hidden" name="${name}" value="${value}"/>
</div>
</form>
</div>
</body>
</html>

View file

@ -0,0 +1,54 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:py="http://purl.org/kid/ns#"
py:extends="'master.kid'">
<head>
<meta content="text/html; charset=utf-8" http-equiv="Content-Type" py:replace="''"/>
<script type="text/javascript"
src="../static/virtual_keyboard/vk_loader.js?vk_layout=DE German"
py:attrs="src=tg.url('/static/virtual_keyboard/vk_loader.js?vk_layout=DE%20German&amp;vk_skin=soberTouch')" />
<title>Bild versenden</title>
</head>
<body>
<table>
<tr>
<td>
<form action="${tg.url('/')}" method="post">
<input class="button" type="submit" name="senden" value="Zur&uuml;ck" />
</form>
</td><td>
<div id="mail_pic"><img src="../static/images/fotokiosk-default.png"
py:attrs="src=tg.url('/get_current_shot')"/></div>
</td>
<td>
<div id="mail_info">
<form action="${tg.url('/senden')}" method="post">
<table><tr><td>
<label for="mailaddress">An:</label><br/>
<input type="textfield" id="mailaddress"
name="mailaddress" value="${mailaddress}" size="40"
onfocus="VirtualKeyboard.attachInput(this)" />
<br/>
<br/>
<label for="mailtext">Text:</label><br/>
<textarea name="mailtext" id="mailtext"
rows="5" cols="40" wrap="physical"
onfocus="VirtualKeyboard.attachInput(this)"
>${mailtext}</textarea>
</td><td>
<input class="button" type="submit" name="senden" value="Senden!" />
</td></tr></table>
</form>
</div>
</td>
</tr>
</table>
<div id="vkb"></div>
<script type="text/javascript">
EM.addEventListener(window,'domload',function(){
VirtualKeyboard.toggle('mailaddress','vkb');
});
</script>
</body>
</html>

View file

@ -0,0 +1,64 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<?python import sitetemplate ?>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:py="http://purl.org/kid/ns#"
py:extends="sitetemplate">
<head py:match="item.tag=='{http://www.w3.org/1999/xhtml}head'" py:attrs="item.items()">
<meta content="text/html; charset=UTF-8" http-equiv="content-type" py:replace="''"/>
<title py:replace="''">panoptische Fotokiosk</title>
<meta py:replace="item[:]" name="description" content="master template"/>
<style type="text/css" media="screen">
#pageLogin
{
font-size: 10px;
font-family: verdana;
text-align: right;
}
</style>
<link rel="stylesheet" type="text/css" media="screen" href="../static/css/1024optimized.css"
py:attrs="href=tg.url('/static/css/1024optimized.css')"/>
<title>Bild versenden</title>
</head>
<body py:match="item.tag=='{http://www.w3.org/1999/xhtml}body'" py:attrs="item.items()">
<div py:if="tg.config('identity.on') and not defined('logging_in')" id="pageLogin">
<span py:if="tg.identity.anonymous">
<a href="${tg.url('/login')}">Login</a>
</span>
<span py:if="not tg.identity.anonymous">
Welcome ${tg.identity.user.display_name or tg.identity.user.user_name}.
<a href="${tg.url('/logout')}">Logout</a>
</span>
</div>
<div id="header">
<img src="../static/images/header.png')"
py:attrs="src=tg.url('/static/images/header.png')"
alt="panoptische Fotokiosk" />
</div>
<div id="main_content">
<!--
<div id="nav">
<ul>
<li><a href="#">Privacy Shades</a></li>
<li><a href="/">Start</a></li>
</ul>
</div>
-->
<div id="status_block" class="flash"
py:if="value_of('tg_flash', None)" py:content="tg_flash"></div>
<div py:replace="[item.text]+item[:]">
<h1>&Uuml;berschrift</h1>
<p>page content</p>
<h2>kleinere &Uuml;berschrift</h2>
<p> foo </p>
<h1>&Uuml;berschrift</h1>
<p>page content</p>
</div>
</div>
</body>
</html>

View file

@ -0,0 +1,38 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:py="http://purl.org/kid/ns#"
py:extends="'master.kid'">
<head>
<meta content="text/html; charset=utf-8" http-equiv="Content-Type" py:replace="''"/>
<title>K&auml;&auml;&auml;&auml;&auml;&auml;&auml;sekuchen!</title>
</head>
<body>
<table>
<tr><td>
<div id="mail_pic"><img src="../static/images/fotokiosk-default.png"
py:attrs="src=tg.url('/get_current_shot')"/></div>
</td><td>
<div id="mail_info">
<form action="${tg.url('/mailtext')}" method="post">
<input type="hidden" name="mailtext" value="${mailtext}" />
<input type="hidden" name="already_stored" value="yes" />
<input type="hidden" name="already_captured" value="yes" />
<input class="button" type="submit" name="send" value="Erneut versenden" />
</form>
<form action="${tg.url('/')}" method="post">
<input class="button" type="submit" name="send" value="Fertig!" />
</form>
</div>
</td></tr>
</table>
<div id="footer">
<p>
<img src="${tg.url('/static/images/logo.png')}" alt="Sense.Lab e.V." /> <br/>
Die Fotokiosk ist ein sense.lab-Projekt und ein Modul der Glasmensch-Ausstellung.<br/>
Alle Inhalte k&ouml;nnen im Sinne einer Creative Commons Lizenz (BY-SA) beliebig weiter verwendet werden.
</p>
</div>
</body>
</html>

View file

@ -0,0 +1,86 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:py="http://purl.org/kid/ns#"
py:extends="'master.kid'">
<head>
<meta content="text/html; charset=utf-8" http-equiv="Content-Type" py:replace="''"/>
<title>Willkommen in der Fotokiosk!</title>
<script type="text/javascript" src="../static/javascript/mjp-streamer.js"
py:attrs="src=tg.url('/static/javascript/mjp-streamer.js')" />
<title>Bild versenden</title>
</head>
<body onload="createImageLayer();">
<table>
<tr>
<td>
<div id="live_pic"><noscript><img width="400" height="320"
src="../static/images/fotokiosk-default.jpg"
py:attrs="src=video_url"/></noscript></div>
<div id="default_pic"><img width="400" height="320"
src="../static/images/fotokiosk-default.jpg" /></div>
</td>
<td valign="center">
<form action="${tg.url('/mailtext')}" method="post">
<input class="button" type="submit" value="Bild senden" />
</form>
</td>
</tr>
</table>
<div id="gallery">
<!-- see http://www.kid-templating.org/trac/wiki/GenerateTableFromListRecipe -->
<?python i= iter(gallery); rows= map(None, i, i, i, i, i, i, i, i, i, i, i) ?>
<table>
<tr>
<td><img class="gallery" src="../static/images/platzhalter.jpg"
alt="${gallery[0].title}"
py:attrs="src=tg.url('static/gallery/') + gallery[0].url" /></td>
<td><img class="gallery" src="../static/images/platzhalter.jpg"
alt="${gallery[1].title}"
py:attrs="src=tg.url('static/gallery/') + gallery[1].url" /></td>
<td><img class="gallery" src="../static/images/platzhalter.jpg"
alt="${gallery[2].title}"
py:attrs="src=tg.url('static/gallery/') + gallery[2].url" /></td>
<td><img class="gallery" src="../static/images/platzhalter.jpg"
alt="${gallery[3].title}"
py:attrs="src=tg.url('static/gallery/') + gallery[3].url" /></td>
<td><img class="gallery" src="../static/images/platzhalter.jpg"
alt="${gallery[4].title}"
py:attrs="src=tg.url('static/gallery/') + gallery[4].url" /></td>
<td><img class="gallery" src="../static/images/platzhalter.jpg"
alt="${gallery[5].title}"
py:attrs="src=tg.url('static/gallery/') + gallery[5].url" /></td>
<td><img class="gallery" src="../static/images/platzhalter.jpg"
alt="${gallery[6].title}"
py:attrs="src=tg.url('static/gallery/') + gallery[6].url" /></td>
<td><img class="gallery" src="../static/images/platzhalter.jpg"
alt="${gallery[7].title}"
py:attrs="src=tg.url('static/gallery/') + gallery[7].url" /></td>
</tr>
<tr>
<td><img class="gallery" src="../static/images/platzhalter.jpg"
alt="${gallery[8].title}"
py:attrs="src=tg.url('static/gallery/') + gallery[8].url" /></td>
<td><img class="gallery" src="../static/images/platzhalter.jpg"
alt="${gallery[9].title}"
py:attrs="src=tg.url('static/gallery/') + gallery[9].url" /></td>
<td colspan="4">
<img src="${tg.url('/static/images/logo.png')}" alt="Sense.Lab e.V." /></td>
<td><img class="gallery" src="../static/images/platzhalter.jpg"
alt="${gallery[10].title}"
py:attrs="src=tg.url('static/gallery/') + gallery[10].url" /></td>
<td><img class="gallery" src="../static/images/platzhalter.jpg"
alt="${gallery[11].title}"
py:attrs="src=tg.url('static/gallery/') + gallery[11].url" /></td>
</tr>
</table>
</div>
<div id="footer">
<p>
Die Fotokiosk ist ein sense.lab-Projekt und ein Modul der Glasmensch-Ausstellung.<br/>
Alle Inhalte k&ouml;nnen im Sinne einer Creative Commons Lizenz (BY-SA) beliebig weiter verwendet werden.
</p>
</div>
</body>
</html>

View file

@ -0,0 +1,47 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:py="http://purl.org/kid/ns#"
py:extends="'master.kid'">
<head>
<meta content="text/html; charset=utf-8" http-equiv="Content-Type" py:replace="''"/>
<title>Welcome to TurboGears</title>
</head>
<body>
<div id="sidebar">
<h2>Learn more</h2>
Learn more about TurboGears and take part in its
development
<ul class="links">
<li><a href="http://www.turbogears.org">Official website</a></li>
<li><a href="http://docs.turbogears.org">Documentation</a></li>
<li><a href="http://trac.turbogears.org/turbogears/">Trac
(bugs/suggestions)</a></li>
<li><a href="http://groups.google.com/group/turbogears"> Mailing list</a> </li>
</ul>
<span py:replace="now">now</span>
</div>
<div id="getting_started">
<ol id="getting_started_steps">
<li class="getting_started">
<h3>Model</h3>
<p> <a href="http://docs.turbogears.org/1.0/GettingStarted/DefineDatabase">Design models</a> in the <span class="code">model.py</span>.<br/>
Edit <span class="code">dev.cfg</span> to <a href="http://docs.turbogears.org/1.0/GettingStarted/UseDatabase">use a different backend</a>, or start with a pre-configured SQLite database. <br/>
Use script <span class="code">tg-admin sql create</span> to create the database tables.</p>
</li>
<li class="getting_started">
<h3>View</h3>
<p> Edit <a href="http://docs.turbogears.org/1.0/GettingStarted/Kid">html-like templates</a> in the <span class="code">/templates</span> folder;<br/>
Put all <a href="http://docs.turbogears.org/1.0/StaticFiles">static contents</a> in the <span class="code">/static</span> folder. </p>
</li>
<li class="getting_started">
<h3>Controller</h3>
<p> Edit <span class="code"> controllers.py</span> and <a href="http://docs.turbogears.org/1.0/GettingStarted/CherryPy">build your
website structure</a> with the simplicity of Python objects. <br/>
TurboGears will automatically reload itself when you modify your project. </p>
</li>
</ol>
<div class="notice"> If you create something cool, please <a href="http://groups.google.com/group/turbogears">let people know</a>, and consider contributing something back to the <a href="http://groups.google.com/group/turbogears">community</a>.</div>
</div>
<!-- End of getting_started -->
</body>
</html>

View file

View file

@ -0,0 +1,32 @@
import unittest
import turbogears
from turbogears import testutil
from fotokiosk.controllers import Root
import cherrypy
cherrypy.root = Root()
class TestPages(unittest.TestCase):
def setUp(self):
turbogears.startup.startTurboGears()
def tearDown(self):
"""Tests for apps using identity need to stop CP/TG after each test to
stop the VisitManager thread.
See http://trac.turbogears.org/turbogears/ticket/1217 for details.
"""
turbogears.startup.stopTurboGears()
def test_method(self):
"the index method should return a string called now"
import types
result = testutil.call(cherrypy.root.index)
assert type(result["now"]) == types.StringType
def test_indextitle(self):
"The indexpage should have the right title"
testutil.create_request("/")
response = cherrypy.response.body[0].lower()
assert "<title>welcome to turbogears</title>" in response

View file

@ -0,0 +1,22 @@
# If your project uses a database, you can set up database tests
# similar to what you see below. Be sure to set the db_uri to
# an appropriate uri for your testing database. sqlite is a good
# choice for testing, because you can use an in-memory database
# which is very fast.
from turbogears import testutil, database
# from fotokiosk.model import YourDataClass, User
# database.set_db_uri("sqlite:///:memory:")
# class TestUser(testutil.DBTest):
# def get_model(self):
# return User
# def test_creation(self):
# "Object creation should set the name"
# obj = User(user_name = "creosote",
# email_address = "spam@python.not",
# display_name = "Mr Creosote",
# password = "Wafer-thin Mint")
# assert obj.display_name == "Mr Creosote"