Compare commits

...
11 Commits
Author SHA1 Message Date
ignace c27556b3b8 added artwork 2026-08-09 14:36:39 +02:00
ignace cafec256b5 more modest h1 2026-08-06 23:02:06 +02:00
ignace 897477bec9 8 second timeout on the show screen 2026-08-06 22:24:28 +02:00
ignace 73380b0c07 another deployment update 2026-07-26 12:44:50 +02:00
ignace d642e0e2b8 updated readme for gunicorn 2026-07-26 12:24:36 +02:00
ignace ab82ecd306 added familiar icon 2026-07-18 22:19:10 +02:00
ignace 882bf0d409 removed a few labels and unused files 2026-07-18 21:16:07 +02:00
ignace 4a5ebc726e more modest ux 2026-07-18 21:00:33 +02:00
ignace 399f539b4f rewritten after codex recommendations 2026-07-18 20:27:19 +02:00
ignace f9dc885937 more readme 2026-07-18 19:39:18 +02:00
ignace 9c726e49d4 updated readme 2026-07-18 19:36:23 +02:00
85 changed files with 1729 additions and 17067 deletions
+11
View File
@@ -0,0 +1,11 @@
__pycache__/AccessControl.cpython-314.pyc
__pycache__/Config.cpython-314.pyc
__pycache__/flower_vase.cpython-314.pyc
__pycache__/flowers.cpython-314.pyc
__pycache__/FlowerServices.cpython-314.pyc
__pycache__/Log.cpython-314.pyc
__pycache__/
tests/__pycache__/
.pytest_cache/
secrets.yaml
.DS_Store
+58 -30
View File
@@ -1,40 +1,68 @@
from Config import *
import pickle, os
import datetime
"""Small file-backed login throttle.
The legacy pickle file is deliberately not read: pickle is unsafe for mutable
runtime files. A JSON document is used instead and malformed files fail closed
to an empty recent-attempt list.
"""
from __future__ import annotations
import json
import os
import tempfile
from datetime import datetime, timedelta, timezone
from pathlib import Path
from Config import ACCESSFILE
from Log import Log
class Access():
access_list = []
def __init__(self):
five_minutes_ago = datetime.datetime.now() - datetime.timedelta(minutes=5)
new_list = []
if os.path.exists(ACCESSFILE):
with open(ACCESSFILE, 'rb') as pf:
self.access_list = pickle.load(pf)
for entry in self.access_list:
if entry['time'] > five_minutes_ago:
new_list.append(entry)
self.access_list = new_list
class Access:
limit = 3
window = timedelta(minutes=5)
def granted(self, ipaddress):
result = 0
for entry in self.access_list:
if entry['ip'] == ipaddress:
result += 1
def __init__(self, path: str = ACCESSFILE) -> None:
self.path = Path(path)
self.access_list = self._load()
if result<3:
def granted(self, ipaddress: str) -> bool:
failures = sum(entry["ip"] == ipaddress for entry in self.access_list)
if failures < self.limit:
return True
Log.info("Access denied for {}".format(ipaddress))
self.deny(ipaddress)
Log.info(f"Access denied for {ipaddress}")
return False
def deny(self, ipaddress: str) -> None:
self.access_list.append(
{"ip": str(ipaddress), "time": datetime.now(timezone.utc).isoformat()}
)
self._save()
def deny(self, ipaddress):
now = datetime.datetime.now()
self.access_list.append({'ip': ipaddress, 'time': now})
with open(ACCESSFILE, 'wb') as pf:
pickle.dump(self.access_list, pf, 2)
def _load(self) -> list[dict[str, str]]:
cutoff = datetime.now(timezone.utc) - self.window
try:
raw = json.loads(self.path.read_text(encoding="utf-8"))
recent = []
for entry in raw:
recorded = datetime.fromisoformat(entry["time"])
if recorded.tzinfo is None:
recorded = recorded.replace(tzinfo=timezone.utc)
if recorded > cutoff:
recent.append({"ip": str(entry["ip"]), "time": recorded.isoformat()})
return recent
except (OSError, ValueError, TypeError, KeyError):
return []
def _save(self) -> None:
self.path.parent.mkdir(parents=True, exist_ok=True)
descriptor, temporary = tempfile.mkstemp(
prefix=f".{self.path.name}.", dir=str(self.path.parent), text=True
)
try:
with os.fdopen(descriptor, "w", encoding="utf-8") as handle:
json.dump(self.access_list, handle, separators=(",", ":"))
os.chmod(temporary, 0o600)
os.replace(temporary, self.path)
finally:
if os.path.exists(temporary):
os.unlink(temporary)
+61 -8
View File
@@ -1,9 +1,62 @@
"""Runtime configuration for Flowers.
LOGFILE = '/tmp/wsgi_flowers.log'
DEBUG = 0
MAXTEXTLEN = 70
MINFIELDLEN = 3
INFO = 1
DONOTSETFILTER = 'DoNotSetFilterinCookie'
ACCESSFILE = '/tmp/wsgi_flower_accessfile'
URLPREFIX = '/flowers'
Secrets are read from the git-ignored ``secrets.yaml`` file. Environment
variables take precedence, which is useful for container deployments.
"""
import os
import secrets
from pathlib import Path
import yaml
BASE_DIR = Path(__file__).resolve().parent
SECRETS_FILE = Path(
os.getenv("FLOWERS_SECRETS_FILE", str(BASE_DIR / "secrets.yaml"))
)
def _load_secrets(path: Path) -> dict:
try:
data = yaml.safe_load(path.read_text(encoding="utf-8")) or {}
except FileNotFoundError:
return {}
except (OSError, yaml.YAMLError) as exc:
raise RuntimeError(f"Could not read Flowers secrets file: {path}") from exc
if not isinstance(data, dict):
raise RuntimeError(f"Flowers secrets file must contain a mapping: {path}")
return data
_SECRETS = _load_secrets(SECRETS_FILE)
_FLASK_SECRETS = _SECRETS.get("flask", {})
_DATABASE_SECRETS = _SECRETS.get("database", {})
if not isinstance(_FLASK_SECRETS, dict) or not isinstance(_DATABASE_SECRETS, dict):
raise RuntimeError("The flask and database secrets sections must be mappings")
LOGFILE = os.getenv("FLOWERS_LOG_FILE", "/tmp/wsgi_flowers.log")
DEBUG = os.getenv("FLOWERS_DEBUG", "0") == "1"
INFO = os.getenv("FLOWERS_INFO", "1") == "1"
MAXTEXTLEN = int(os.getenv("FLOWERS_MAX_TEXT_LENGTH", "70"))
MINFIELDLEN = int(os.getenv("FLOWERS_MIN_FIELD_LENGTH", "3"))
DONOTSETFILTER = "DoNotSetFilterinCookie"
ACCESSFILE = os.getenv("FLOWERS_ACCESS_FILE", "/tmp/wsgi_flower_accessfile")
URLPREFIX = os.getenv("FLOWERS_URL_PREFIX", "").rstrip("/")
DB_HOST = os.getenv("FLOWERS_DB_HOST", "localhost")
DB_PORT = int(os.getenv("FLOWERS_DB_PORT", "3306"))
DB_NAME = os.getenv("FLOWERS_DB_NAME", "Flowers")
DB_ADMIN_USER = os.getenv("FLOWERS_DB_ADMIN_USER", "flower")
DB_ADMIN_PASSWORD = os.getenv(
"FLOWERS_DB_ADMIN_PASSWORD", str(_DATABASE_SECRETS.get("admin_password", ""))
)
SESSION_MINUTES = int(os.getenv("FLOWERS_SESSION_MINUTES", "10"))
SECRET_KEY = (
os.getenv("FLOWERS_SECRET_KEY")
or str(_FLASK_SECRETS.get("secret_key", ""))
or secrets.token_hex(32)
)
COOKIE_SECURE = os.getenv("FLOWERS_COOKIE_SECURE", "0") == "1"
-79
View File
@@ -1,79 +0,0 @@
@app.route('/loadconfig' , methods=['GET'])
def loadconfig():
user=None
mode='text'
try:
user = request.args.get('userId')
mode = request.args.get('mode')
except HTTPException as err:
print("http error: {0}".format(err))
except:
print('some error', sys.exc_info()[0])
cfg=Dashboard(userId=user)
resp = make_response(json.dumps({'plugs':cfg.plugs.listAsText()}))
resp.headers['Content-type'] = 'application/json; charset=utf-8'
return resp
@app.route('/loadPlugin' , methods=['GET'])
def loadPlugin():
try:
plname = request.args.get('plugin')
params = request.args.get('parameters')
ClassType = getattr(Plugin, plname)
p = ClassType(params)
resp = make_response(json.dumps({'plugin':p.asHtml()}))
except HTTPException as err:
print("http error: {0}".format(err))
resp = make_response(json.dumps({'plugin':err}))
except:
print('some error', sys.exc_info()[0])
resp = make_response(json.dumps({'plugin':'System error loading plugin'}))
resp.headers['Content-type'] = 'application/json; charset=utf-8'
return resp
@app.route('/saveplugs' , methods=['POST'])
def saveplugs():
user=request.form['userId']
mode=request.form['mode']
plugs=request.form['plugs']
cfg=Dashboard(userId=user)
cfg.updatePlugs(plugs)
cfg.save()
resp = make_response(json.dumps({'plugs':cfg.plugs.listAsText()}))
resp.headers['Content-type'] = 'application/json; charset=utf-8'
return resp
@app.route('/json', methods=['GET'])
def myjson():
user=request.form['userId']
resp = make_response(json.dumps({'plugs':'user'}))
resp.headers['Content-type'] = 'application/json; charset=utf-8'
return resp
@app.route('/upload', methods=['GET'])
def upload():
resp = make_response('function upload')
resp.headers['Content-type'] = 'text/plain; charset=utf-8'
if request.method == 'GET':
try:
f = request.args.get('user')
print(f)
except HTTPException as err:
print("http error: {0}".format(err))
except:
print('some error', sys.exc_info()[0])
return resp
@app.route('/echo' , methods=['GET'])
def echo():
text=None
try:
text = request.args.get('text')
except HTTPException as err:
print("http error: {0}".format(err))
except:
print('some error', sys.exc_info()[0])
resp = make_response(text)
resp.headers['Content-type'] = 'text/plain; charset=utf-8'
return resp
+303 -245
View File
@@ -1,269 +1,327 @@
from fernet import Fernet
from Log import Log
from Config import *
"""Database and encryption services for the legacy Flowers data format.
The public ``Flower`` API intentionally remains compatible with the original
application. Existing tables and Fernet ciphertext require no migration.
"""
from __future__ import annotations
import re
from contextlib import contextmanager
from typing import Callable, Iterator
import pymysql as mdb
from fernet import Fernet
#encryption stuff
SECRET = b'XBxB603cX_mULEXxfavOg3FDc0Ox3gChwYEY-Uxd3tE='
from Config import (
DB_ADMIN_PASSWORD,
DB_ADMIN_USER,
DB_HOST,
DB_NAME,
DB_PORT,
MINFIELDLEN,
)
from Log import Log
class Flower():
_USERNAME = re.compile(r"^[A-Za-z0-9_]{1,31}$")
def __init__(self, user, pwd):
self.db = 'Flowers'
self.db_username = user + '_'
self.db_password = (pwd*10)[:43]+"="
class InvalidCredentials(ValueError):
"""The supplied username/password cannot address a Flowers vault."""
class StorageError(RuntimeError):
"""A database operation failed."""
def legacy_key(password: str) -> str:
"""Return the exact DB password/Fernet key used by historical releases."""
if not isinstance(password, str) or not password:
raise InvalidCredentials("A password is required")
key = (password * 10)[:43] + "="
try:
Fernet(key.encode("ascii"))
except (UnicodeEncodeError, ValueError) as exc:
raise InvalidCredentials(
"Password must use Base64-compatible characters"
) from exc
return key
def _identifier(username: str) -> str:
if not isinstance(username, str) or not _USERNAME.fullmatch(username):
raise InvalidCredentials(
"Username must contain only letters, numbers, and underscores"
)
return f"{username}_"
class Flower:
"""Read and write one user's existing Flowers table."""
def __init__(
self,
user: str,
pwd: str,
connection_factory: Callable[..., object] | None = None,
) -> None:
self.db = DB_NAME
self.db_username = _identifier(user)
self.db_password = legacy_key(pwd)
self.customer_table = self.db_username
self.fernet = Fernet(bytes(self.db_password, 'ascii'))
self._table = f"`{self.customer_table}`"
self.fernet = Fernet(self.db_password.encode("ascii"))
self._connect = connection_factory or mdb.connect
def encode(self, s):
if len(s)==0:
return ''
return self.fernet.encrypt(s.encode()).decode()
def decode(self, s):
if len(s)==0:
return ''
return self.fernet.decrypt(s.encode()).decode()
def add(self, organization, myname, myid, secret, deleted=0, timestamp=None):
''' POST a new flower
'''
if len(organization)>MINFIELDLEN and len(myid)>MINFIELDLEN and len(secret)>MINFIELDLEN:
sql = 'INSERT INTO {} (organization ,myID ,myName ,mySecret, deleted) VALUES ("{}", "{}", "{}", "{}", {})'.format(self.customer_table, organization, self.encode(myid), self.encode(myname), self.encode(secret), deleted)
if timestamp is not None:
sql = 'INSERT INTO {} (organization ,myID ,myName ,mySecret, deleted, dateCreated) VALUES ("{}", "{}", "{}", "{}", {}, "{}")'.format(self.customer_table, organization, self.encode(myid), self.encode(myname), self.encode(secret), deleted, timestamp)
result, data = self.do_db_commit(sql)
Log.debug(result)
if result==1:
return {'organization': organization, 'dateCreated': 'STORED', 'myID': myid, 'myName': myname,'mySecret': secret}
return {'organization': organization, 'dateCreated': 'FAILED', 'myID': myid, 'myName': myname,'mySecret': secret}
def all(self, isdeleted=0):
''' GET flowers list
'''
#sql = "SELECT organization, myID, myName, dateCreated FROM %s " % (self.customer_table)
sql = """
select uniqueflowers.organization, uniqueflowers.myID, uniqueflowers.dateCreated from {0} as uniqueflowers
inner join (
select organization, max(dateCreated) as lastCreated from {0} group by organization order by dateCreated DESC) allflowers
on allflowers.organization=uniqueflowers.organization and lastCreated=uniqueflowers.dateCreated where uniqueflowers.deleted={1}
""".format(self.customer_table, isdeleted)
result, data = self.do_db_allrows(sql)
#Log.debug(sql_result)
all_flowers=[]
if result==1:
for row in data:
all_flowers.append({'organization': str(row[0]), 'myID': self.decode(row[1]), 'dateCreated': str(row[2])})
return all_flowers
def one(self, organization, datetimestamp ):
''' flower for user, org and datetime
'''
result = -1
secret = ':-('
sql = "SELECT mySecret, myID, myName FROM %s where organization='%s' and dateCreated='%s' order by dateCreated DESC limit 1" % (self.customer_table, organization, datetimestamp)
result, data = self.do_db_1row(sql)
if result == 1:
return {'organization': organization, 'dateCreated': datetimestamp, 'myID': self.decode(data[1]), 'myName': self.decode(data[2]),'mySecret': self.decode(data[0])}
return {'organization': organization, 'dateCreated': datetimestamp, 'myID': '', 'myName': '','mySecret': '-- Not found --'}
def deactivate(self, organization, datetimestamp ):
''' flower for user, org and datetime
'''
result = -1
secret = ':-('
sql = "update {} set deleted=1 where organization='{}' and dateCreated='{}' ".format(self.customer_table, organization, datetimestamp)
result, data = self.do_db_commit(sql)
if result == 1:
secret = '- DELETED -'
return {'organization': organization, 'dateCreated': datetimestamp, 'myID': '', 'myName': '','mySecret': secret}
def empty(self):
''' empty flower
'''
return {'organization': '', 'dateCreated': '', 'myID': '', 'myName': '','mySecret': ''}
def numberOfEntries(self):
''' GET login info, check if its valid
'''
sql = "SELECT count(*) FROM {};".format(self.customer_table)
result, data = self.do_db_1row(sql)
if result == 1:
return(data[0])
return -1
def update_pwd(self, new_pwd):
long_newpwd = (new_pwd*10)[:43]+"="
self.new_fernet = Fernet(bytes(long_newpwd, 'ascii'))
def new_encode(s):
if len(s)==0:
return ''
return self.new_fernet.encrypt(s.encode()).decode()
end_result = "ERROR updating hushes\n"
sql = """
select myID, myName, mySecret, organization, dateCreated from {0}""".format(self.customer_table)
result, data = self.do_db_allrows(sql)
# Log.debug(sql_result)
if result == 1:
# convert all hushes
sql = ""
for row in data:
sql += "update {} set myID='{}', myName='{}', mySecret='{}' where organization='{}' and dateCreated='{}';\n".\
format(self.customer_table,
new_encode(self.decode(row[0])),
new_encode(self.decode(row[1])),
new_encode(self.decode(row[2])),row[3], row[4])
result, data = self.do_db_commit(sql)
if result == 1:
end_result = "ERROR updating user-password\n"
# update the password of the user
sql = "SET PASSWORD FOR '{}'@'localhost' = PASSWORD('{}'); ".format(self.db_username, long_newpwd)
result, data = self.do_db_commit(sql)
if result == 1:
end_result = "SUCCESSFULLY updated, now login again\n"
return end_result
def do_db_commit(self, sql):
Log.debug('INSc: '+sql)
result = 0
data = ''
con = None
@contextmanager
def _connection(self) -> Iterator[object]:
connection = None
try:
con = mdb.connect(host='localhost', passwd=self.db_password, user=self.db_username, db=self.db);
cur = con.cursor()
if ";\n" in sql:
for s in sql.split(";\n"):
if len(s)>1:
cur.execute(s)
else:
cur.execute(sql)
cur.close()
con.commit()
result = 1
except mdb.Error as e:
m = "Error %d: %s" % (e.args[0],e.args[1])
data = {'message': m}
Log.debug(m)
result = -1
connection = self._connect(
host=DB_HOST,
port=DB_PORT,
user=self.db_username,
passwd=self.db_password,
db=self.db,
charset="latin1",
)
yield connection
except mdb.Error as exc:
Log.debug(f"Database error: {exc}")
raise StorageError("The vault database is unavailable") from exc
finally:
if con:
con.close()
return result, data
if connection is not None:
connection.close()
def encode(self, value: str) -> str:
if not value:
return ""
return self.fernet.encrypt(value.encode("utf-8")).decode("ascii")
def do_db_1row(self, sql):
Log.debug('1row sql: '+sql)
result = 0
con = None
def decode(self, value: str) -> str:
if not value:
return ""
return self.fernet.decrypt(value.encode("ascii")).decode("utf-8")
def authenticate(self) -> bool:
try:
con = mdb.connect(host='localhost', passwd=self.db_password, user=self.db_username, db=self.db);
cur = con.cursor()
cur.execute(sql)
data = cur.fetchone()
if data:
result = 1
except mdb.Error as e:
m = "Error %d: %s" % (e.args[0],e.args[1])
data = {'message': m}
Log.debug(m)
result = -1
finally:
if con:
con.close()
return result, data
with self._connection() as connection:
with connection.cursor() as cursor:
cursor.execute(f"SELECT COUNT(*) FROM {self._table}")
cursor.fetchone()
return True
except (StorageError, ValueError):
return False
def do_db_allrows(self, sql):
Log.debug('all rows sql: '+sql)
result = 0
con = None
def numberOfEntries(self) -> int:
"""Compatibility method used by older clients and scripts."""
try:
con = mdb.connect(host='localhost', passwd=self.db_password, user=self.db_username, db=self.db);
cur = con.cursor()
cur.execute(sql)
data = cur.fetchall()
if data:
result = 1
except mdb.Error as e:
m = "Error %d: %s" % (e.args[0],e.args[1])
data = {'message': m}
Log.debug(m)
result = -1
finally:
if con:
con.close()
return result, data
with self._connection() as connection:
with connection.cursor() as cursor:
cursor.execute(f"SELECT COUNT(*) FROM {self._table}")
row = cursor.fetchone()
return int(row[0]) if row else 0
except StorageError:
return -1
def add(
self,
organization: str,
myname: str,
myid: str,
secret: str,
deleted: int = 0,
timestamp=None,
) -> dict:
item = self._item(organization, "FAILED", myid, myname, secret)
if not all(isinstance(v, str) for v in (organization, myname, myid, secret)):
return item
if not (
len(organization) > MINFIELDLEN
and len(myid) > MINFIELDLEN
and len(secret) > MINFIELDLEN
):
return item
columns = "organization, myID, myName, mySecret, deleted"
values = [
organization,
self.encode(myid),
self.encode(myname),
self.encode(secret),
int(bool(deleted)),
]
placeholders = "%s, %s, %s, %s, %s"
if timestamp is not None:
columns += ", dateCreated"
placeholders += ", %s"
values.append(timestamp)
sql = f"INSERT INTO {self._table} ({columns}) VALUES ({placeholders})"
self._execute_write(sql, values)
return self._item(organization, "STORED", myid, myname, secret)
def all(self, isdeleted: int = 0) -> list[dict]:
sql = f"""
SELECT latest.organization, latest.myID, latest.dateCreated
FROM {self._table} AS latest
INNER JOIN (
SELECT organization, MAX(dateCreated) AS lastCreated
FROM {self._table}
GROUP BY organization
) AS versions
ON versions.organization = latest.organization
AND versions.lastCreated = latest.dateCreated
WHERE latest.deleted = %s
ORDER BY latest.dateCreated DESC, latest.organization ASC
"""
with self._connection() as connection:
with connection.cursor() as cursor:
cursor.execute(sql, (int(bool(isdeleted)),))
rows = cursor.fetchall()
return [
{
"organization": str(row[0]),
"myID": self.decode(row[1]),
"dateCreated": str(row[2]),
}
for row in rows
]
def one(self, organization: str, datetimestamp) -> dict:
sql = f"""
SELECT mySecret, myID, myName
FROM {self._table}
WHERE organization = %s AND dateCreated = %s
ORDER BY dateCreated DESC
LIMIT 1
"""
with self._connection() as connection:
with connection.cursor() as cursor:
cursor.execute(sql, (organization, datetimestamp))
row = cursor.fetchone()
if row:
return self._item(
organization,
str(datetimestamp),
self.decode(row[1]),
self.decode(row[2]),
self.decode(row[0]),
)
return self._item(organization, str(datetimestamp), "", "", "-- Not found --")
def deactivate(self, organization: str, datetimestamp) -> dict:
sql = f"UPDATE {self._table} SET deleted = 1 WHERE organization = %s AND dateCreated = %s"
changed = self._execute_write(sql, (organization, datetimestamp))
message = "- DELETED -" if changed else "-- Not found --"
return self._item(organization, str(datetimestamp), "", "", message)
def empty(self) -> dict:
return self._item("", "", "", "", "")
def update_pwd(self, new_pwd: str) -> str:
"""Re-encrypt every value and update the legacy per-user DB password."""
new_db_password = legacy_key(new_pwd)
new_fernet = Fernet(new_db_password.encode("ascii"))
try:
with self._connection() as connection:
try:
with connection.cursor() as cursor:
cursor.execute(
f"SELECT myID, myName, mySecret, organization, dateCreated FROM {self._table}"
)
rows = cursor.fetchall()
update = f"""
UPDATE {self._table}
SET myID = %s, myName = %s, mySecret = %s
WHERE organization = %s AND dateCreated = %s
"""
for row in rows:
encrypted = [
new_fernet.encrypt(self.decode(value).encode("utf-8")).decode("ascii")
if value else ""
for value in row[:3]
]
cursor.execute(update, (*encrypted, row[3], row[4]))
# This form is supported by the MariaDB versions used by
# historical Flowers installations.
cursor.execute("SET PASSWORD = PASSWORD(%s)", (new_db_password,))
connection.commit()
except Exception:
connection.rollback()
raise
except Exception as exc:
Log.debug(f"Password update failed: {exc}")
return "ERROR updating password"
return "SUCCESSFULLY updated, now login again"
def _execute_write(self, sql: str, parameters) -> int:
with self._connection() as connection:
try:
with connection.cursor() as cursor:
changed = cursor.execute(sql, parameters)
connection.commit()
return int(changed)
except Exception:
connection.rollback()
raise
@staticmethod
def _item(organization, timestamp, myid, myname, secret) -> dict:
return {
"organization": organization,
"dateCreated": timestamp,
"myID": myid,
"myName": myname,
"mySecret": secret,
}
class SuperFlower(Flower):
"""Provision a legacy per-user table and database account."""
def __init__(self, customer, pwd):
super().__init__(customer, pwd)
self.customer_name = customer + '_'
self.customer_pwd = (pwd*10)[:43]+"="
def __init__(self, customer: str, pwd: str, connection_factory=None) -> None:
super().__init__(customer, pwd, connection_factory)
self.customer_name = self.customer_table
self.customer_pwd = self.db_password
self.db_username = DB_ADMIN_USER
self.db_password = DB_ADMIN_PASSWORD
self.db_username = 'flower'
self.db_password = '608f0b988db4a96066af7dd8870de96c'
def createNewTable(self):
# create new table and user
sql = """
CREATE TABLE `{}` (
`organization` varchar(80) NOT NULL,
`myID` varchar(255) NOT NULL,
`myName` varchar(255) NOT NULL,
`mySecret` varchar(255) NOT NULL,
`dateCreated` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`deleted` int(11) DEFAULT '0',
PRIMARY KEY (`organization`,`dateCreated`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;""".format(self.customer_table)
result, data = self.do_db_1row(sql)
if result < 0:
Log.info("SQL ERROR:")
Log.info(data)
def createNewTable(self) -> int:
statements = [
f"""CREATE TABLE {self._table} (
organization varchar(80) NOT NULL,
myID varchar(255) NOT NULL,
myName varchar(255) NOT NULL,
mySecret varchar(255) NOT NULL,
dateCreated timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
deleted int(11) DEFAULT 0,
PRIMARY KEY (organization, dateCreated)
) ENGINE=InnoDB DEFAULT CHARSET=latin1""",
f"CREATE USER '{self.customer_name}'@'localhost' IDENTIFIED BY %s",
f"GRANT SELECT, UPDATE, INSERT ON `{self.db}`.{self._table} TO '{self.customer_name}'@'localhost'",
]
try:
with self._connection() as connection:
with connection.cursor() as cursor:
cursor.execute(statements[0])
cursor.execute(statements[1], (self.customer_pwd,))
cursor.execute(statements[2])
connection.commit()
return 1
except StorageError as exc:
Log.info(f"Could not create vault: {exc}")
return 0
sql = """create user {}@localhost identified by '{}';""".format(self.customer_name, self.customer_pwd)
result, data = self.do_db_1row(sql)
if result < 0:
Log.info("SQL ERROR:")
Log.info(data)
def flush_privs(self) -> int:
try:
self._execute_write("FLUSH PRIVILEGES", ())
return 1
except StorageError:
return 0
sql = """grant select,update,insert on Flowers.{} to {}@localhost;""".format(self.customer_table, self.customer_name)
result, data = self.do_db_1row(sql)
if result < 0:
Log.info("SQL ERROR:")
Log.info(data)
return 0
self.flush_privs()
return 1
def flush_privs(self):
sql = """flush privileges;"""
result, data = self.do_db_1row(sql)
if result < 0:
Log.info("SQL ERROR:")
Log.info(data)
return 0
return 1
if __name__ == '__main__':
print("this is a library, sorry dude")
if __name__ == "__main__":
print("This module is a library.")
+22 -15
View File
@@ -1,20 +1,27 @@
from sys import stderr
from Config import *
"""Compatibility logging facade."""
import logging
from logging.handlers import RotatingFileHandler
from Config import DEBUG, INFO, LOGFILE
_logger = logging.getLogger("flowers")
if not _logger.handlers and (DEBUG or INFO):
try:
handler = RotatingFileHandler(LOGFILE, maxBytes=1_000_000, backupCount=2)
handler.setFormatter(logging.Formatter("%(asctime)s flowers %(levelname)s %(message)s"))
_logger.addHandler(handler)
_logger.setLevel(logging.DEBUG if DEBUG else logging.INFO)
except OSError:
_logger.addHandler(logging.NullHandler())
class Log:
@staticmethod
def info(someString):
if INFO:
f = open(LOGFILE, "a")
f.write( "flower: %s \n" % someString )
f.close()
if DEBUG:
print(someString)
def info(message) -> None:
_logger.info("%s", message)
@staticmethod
def debug(someString):
if DEBUG:
f = open(LOGFILE, "a")
f.write( "flower: %s \n" % someString )
f.close()
def debug(message) -> None:
_logger.debug("%s", message)
+318 -21
View File
@@ -1,30 +1,327 @@
FLowers
-------
# Flowers
The current code base is designed to run undert a waitress server as a backend to apache
The app should be called as http:// ... /flowers (so as a subfolder of the domain)
Flowers is a small self-hosted credential vault built with Flask and MariaDB/MySQL. This version rewrites the legacy server and browser UI while intentionally preserving its on-disk data contract.
to install the env:
python3 -m venv venv
source venv/bin/activate
pip install flask waitress fernet pymysql pytz
## Existing database compatibility
No data migration is required. The rewritten application continues to use:
install apache and activate proxy:
a2enmod proxy
a2enmod proxy_http
- the `Flowers` database;
- one database account and table named `<username>_` per vault;
- the existing `organization`, `myID`, `myName`, `mySecret`, `dateCreated`, and `deleted` columns;
- the historical password transformation `(password * 10)[:43] + "="` for both the database password and Fernet key;
- Fernet ciphertext in the three protected columns;
- append-only edits, where the newest timestamp is the visible version; and
- `deleted = 1` for deactivation.
and put the following in the site...conf file:
ProxyPass "/flowers" "http://127.0.0.1:5012/flowers"
ProxyPassReverse "/flowers" "http://127.0.0.1:5012/flowers"
The old form-encoded `POST /app` endpoint is also retained. Its `list` and `flower` properties remain JSON strings inside the outer JSON response for existing client compatibility.
The legacy key derivation is preserved only because changing it would make existing data unreadable. It is not a modern password KDF. A future KDF upgrade requires an explicit, tested data migration rather than an in-place code change.
## What changed
# as root in mysql
create database Flowers;
grant create,select,update,insert,grant option on Flowers.* to flower@localhost identified by '608f0b988db4a96066af7dd8870de96c';
grant create user,reload on *.* to flower@localhost;
flush privileges;
- All stored values are passed to MariaDB as query parameters.
- Usernames are validated before being used as table/account identifiers.
- Database and runtime settings can be supplied through environment variables.
- Browser forms have CSRF protection.
- Database credentials are stored in server memory behind an opaque session token, not in Flask's signed browser cookie.
- Browser sessions expire after ten minutes of inactivity.
- Failed-login state is JSON rather than unsafe pickle data.
- The browser interface is responsive and no longer depends on jQuery, Pure CSS, or remote assets.
- The Flask application factory and WSGI entry point both work.
- Compatibility tests cover legacy encryption, reads, writes, listing, and the old API format.
start waitress:
waitress-serve --threads=6 --host=127.0.0.1 --port=5012 --call flowers:create_app
## Requirements
- Python 3.10 or newer
- MariaDB or MySQL on the configured host
- the packages in `requirements.txt`
```bash
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
```
## Configuration
Local secrets are loaded from the git-ignored `secrets.yaml` file:
```yaml
flask:
secret_key: "a-long-random-value"
database:
admin_password: "the-provisioning-account-password"
```
Use `secrets.example.yaml` as a template. `FLOWERS_SECRETS_FILE` can point to a different file. Secret environment variables take precedence over YAML, which is useful for containers and managed deployments.
The other settings remain environment-based:
| Environment variable | Default |
| --- | --- |
| `FLOWERS_SECRETS_FILE` | `secrets.yaml` beside the application |
| `FLOWERS_SECRET_KEY` | overrides `flask.secret_key` from YAML |
| `FLOWERS_DB_HOST` | `localhost` |
| `FLOWERS_DB_PORT` | `3306` |
| `FLOWERS_DB_NAME` | `Flowers` |
| `FLOWERS_DB_ADMIN_USER` | `flower` |
| `FLOWERS_DB_ADMIN_PASSWORD` | overrides `database.admin_password` from YAML |
| `FLOWERS_URL_PREFIX` | empty |
| `FLOWERS_SESSION_MINUTES` | `10` |
| `FLOWERS_COOKIE_SECURE` | `0`; set to `1` behind HTTPS |
| `FLOWERS_ACCESS_FILE` | `/tmp/wsgi_flower_accessfile` |
| `FLOWERS_LOG_FILE` | `/tmp/wsgi_flowers.log` |
The provisioning account is needed only by the web-based `/create` flow. Existing vault reads and writes connect with their existing per-user database accounts.
## Database bootstrap for a new installation
An existing Flowers database should be left untouched. For a new installation, create the database and provisioning user, replacing the example password:
```sql
CREATE DATABASE Flowers;
CREATE USER 'flower'@'localhost' IDENTIFIED BY 'replace-this';
GRANT CREATE, SELECT, UPDATE, INSERT ON Flowers.*
TO 'flower'@'localhost' WITH GRANT OPTION;
GRANT CREATE USER, RELOAD ON *.* TO 'flower'@'localhost';
FLUSH PRIVILEGES;
```
Put the same value in `database.admin_password` in `secrets.yaml` before starting Flowers.
## Run locally
Development:
```bash
python flowers.py
```
To exercise the production WSGI server locally:
```bash
gunicorn --workers 1 --threads 6 --bind 127.0.0.1:5012 'flowers:create_app()'
```
Flowers keeps authenticated database credentials in process memory. Always use exactly
one Gunicorn worker: users would otherwise appear to be logged out whenever a request
reached a different worker. Threads provide concurrency within that worker. Restarting
Gunicorn intentionally expires all active Flowers sessions.
## Deploy with Nginx, Gunicorn, and systemd
The following example installs Flowers in `/opt/flowers`, runs it as an unprivileged
`flowers` user, binds Gunicorn only to loopback, and exposes it through Nginx over
HTTPS. Adapt the paths, hostname, user, and certificate locations for your server.
### 1. Install the application
Install Python, its virtual-environment support, MariaDB/MySQL client libraries, Nginx,
and your distribution's certificate tooling. Then copy or clone the repository and
create the service account and virtual environment:
```bash
sudo useradd --system --user-group --home /opt/flowers \
--shell /usr/sbin/nologin flowers
sudo install -d -o flowers -g flowers /opt/flowers
sudo -u flowers git clone https://example.invalid/flowers.git /opt/flowers
sudo -u flowers python3 -m venv /opt/flowers/.venv
sudo -u flowers /opt/flowers/.venv/bin/pip install \
-r /opt/flowers/requirements.txt
```
Replace the example clone URL with this repository's URL. For an artifact-based
deployment, copy the release into `/opt/flowers` instead and make it owned by
`flowers:flowers`.
### 2. Configure secrets and the environment
Keep deployment secrets outside the repository:
```bash
sudo install -d -m 0750 -o root -g flowers /etc/flowers
sudo install -m 0640 -o root -g flowers \
/opt/flowers/secrets.example.yaml /etc/flowers/secrets.yaml
sudoedit /etc/flowers/secrets.yaml
sudoedit /etc/flowers/flowers.env
sudo chown root:flowers /etc/flowers/flowers.env
sudo chmod 0640 /etc/flowers/flowers.env
```
Use this as `/etc/flowers/flowers.env`:
```dotenv
FLOWERS_SECRETS_FILE=/etc/flowers/secrets.yaml
FLOWERS_DB_HOST=127.0.0.1
FLOWERS_DB_PORT=3306
FLOWERS_DB_NAME=Flowers
FLOWERS_DB_ADMIN_USER=flower
FLOWERS_COOKIE_SECURE=1
FLOWERS_ACCESS_FILE=/var/lib/flowers/access
FLOWERS_LOG_FILE=/var/log/flowers/flowers.log
```
Create the writable locations referenced above:
```bash
sudo install -d -m 0750 -o flowers -g flowers /var/lib/flowers
sudo install -d -m 0750 -o flowers -g flowers /var/log/flowers
```
Set a stable, random `flask.secret_key` and the database provisioning password in
`/etc/flowers/secrets.yaml`. Do not generate a new Flask secret on each deployment,
because changing it invalidates every browser session. If the database is on another
host, adjust `FLOWERS_DB_HOST` and ensure its grants and firewall allow the Flowers
server.
### 3. Create the systemd service
Create `/etc/systemd/system/flowers.service`:
```ini
[Unit]
Description=Flowers credential vault
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
User=flowers
Group=flowers
WorkingDirectory=/opt/flowers
EnvironmentFile=/etc/flowers/flowers.env
ExecStart=/opt/flowers/.venv/bin/gunicorn --workers 1 --threads 6 --bind 127.0.0.1:5012 --access-logfile - --error-logfile - "flowers:create_app()"
Restart=on-failure
RestartSec=5
TimeoutStopSec=30
PrivateTmp=true
NoNewPrivileges=true
UMask=0077
[Install]
WantedBy=multi-user.target
```
Enable the service and confirm that Gunicorn answers locally:
```bash
sudo systemctl daemon-reload
sudo systemctl enable --now flowers
sudo systemctl status flowers
curl --fail --head http://127.0.0.1:5012/
```
Service and access logs are available through `journalctl -u flowers`. The application
also writes its own log to the configured `FLOWERS_LOG_FILE`.
### 4. Configure Nginx
Create `/etc/nginx/sites-available/flowers` (or the equivalent include path on your
distribution):
```nginx
server {
listen 80;
listen [::]:80;
server_name flowers.example.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name flowers.example.com;
ssl_certificate /etc/letsencrypt/live/flowers.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/flowers.example.com/privkey.pem;
client_max_body_size 64k;
location / {
proxy_pass http://127.0.0.1:5012;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Connection "";
proxy_read_timeout 30s;
}
}
```
Obtain the certificate before enabling the TLS server, or first use your ACME client's
HTTP-only bootstrap configuration. Then enable and validate the site:
```bash
sudo ln -s /etc/nginx/sites-available/flowers /etc/nginx/sites-enabled/flowers
sudo nginx -t
sudo systemctl reload nginx
curl --fail --head https://flowers.example.com/
```
Keep port `5012` closed in the host firewall; only ports 80 and 443 need to be public.
If another reverse proxy sits in front of Nginx, configure Nginx to accept client IP
headers only from that proxy rather than from arbitrary clients.
### Deploy under a URL prefix
To publish Flowers at `https://example.com/flowers/`, add this setting to
`/etc/flowers/flowers.env`:
```dotenv
FLOWERS_URL_PREFIX=/flowers
```
Use these Nginx locations without a trailing path on `proxy_pass`, so the `/flowers`
prefix reaches Flask unchanged:
```nginx
location = /flowers {
return 301 /flowers/;
}
location /flowers/ {
proxy_pass http://127.0.0.1:5012;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Connection "";
}
```
After changing the environment or application code, restart Gunicorn with
`sudo systemctl restart flowers`. After changing Nginx, run `sudo nginx -t` before
reloading it.
## Tests
The tests do not need a live database; they use the actual legacy Fernet implementation with a MariaDB-compatible fake connection.
```bash
pip install -r requirements-dev.txt
python -m pytest
```
They can also run using only the standard library test runner:
```bash
python -m unittest discover -s tests -v
```
## Remaining security constraints
The rewrite removes the immediately exploitable SQL interpolation and browser-cookie credential storage, but Flowers remains a small personal vault with a legacy storage design:
- the historical password-derived Fernet key is intentionally still weak;
- the web process still has provisioning privileges if `/create` is enabled;
- the in-memory credential store is suitable for one application process, not a multi-process cluster; and
- rate-limit state is local to one host.
Use a strong unique password made only of Base64-compatible characters, bind Gunicorn
to localhost, and expose it only through an authenticated HTTPS reverse proxy. Set
stable provisioning and Flask secrets before deployment.
-315
View File
@@ -1,315 +0,0 @@
####################
#
# file is replaced by FlowerServices.py
#
1= # intentional python syntax error
#
#####################
from Crypto.Cipher import AES
from Crypto.Hash import MD5
import base64
from Log import Log
from Config import *
import pymysql as mdb
#encryption stuff
SECRET='HSPh1O5vc6YY2Xt8jUxlTp'
BLOCK_SIZE = 32
PADDING='_'
# one-liner to sufficiently pad the text to be encrypted
pad = lambda s: s + (BLOCK_SIZE - len(s) % BLOCK_SIZE) * PADDING
def md5(message):
hash = MD5.new()
hash.update(message.encode('utf-8'))
return hash.hexdigest()
class Flower():
def __init__(self, user, pwd):
self.db = 'Flowers'
self.db_username = user + '_'
self.db_password = md5(pwd)
self.customer_table = self.db_username
self.cipher = AES.new(pad(SECRET + pwd))
def encode(self, s):
return str(base64.b64encode(self.cipher.encrypt(pad(s))).decode("utf-8"))
def decode(self, e):
return str(self.cipher.decrypt(base64.b64decode(e)).decode("utf-8")).rstrip(PADDING)
def add(self, organization, myname, myid, secret, deleted=0, timestamp=None):
''' POST a new flower
'''
if len(organization)>MINFIELDLEN and len(myid)>MINFIELDLEN and len(secret)>MINFIELDLEN:
sql = "INSERT INTO {} (organization ,myID ,myName ,mySecret, deleted) VALUES ('{}', '{}', '{}', '{}', {})".format(self.customer_table, organization, self.encode(myid), self.encode(myname), self.encode(secret), deleted)
if timestamp is not None:
sql = "INSERT INTO {} (organization ,myID ,myName ,mySecret, deleted, dateCreated) VALUES ('{}', '{}', '{}', '{}', {}, '{}')".format(self.customer_table, organization, self.encode(myid), self.encode(myname), self.encode(secret), deleted, timestamp)
result, data = self.do_db_commit(sql)
Log.debug(result)
if result==1:
return {'organization': organization, 'dateCreated': 'STORED', 'myID': myid, 'myName': myname,'mySecret': secret}
return {'organization': organization, 'dateCreated': 'FAILED', 'myID': myid, 'myName': myname,'mySecret': secret}
def all(self, isdeleted=0):
''' GET flowers list
'''
#sql = "SELECT organization, myID, myName, dateCreated FROM %s " % (self.customer_table)
sql = """
select uniqueflowers.organization, uniqueflowers.myID, uniqueflowers.dateCreated from {0} as uniqueflowers
inner join (
select organization, max(dateCreated) as lastCreated from {0} group by organization order by dateCreated DESC) allflowers
on allflowers.organization=uniqueflowers.organization and lastCreated=uniqueflowers.dateCreated where uniqueflowers.deleted={1}
""".format(self.customer_table, isdeleted)
result, data = self.do_db_allrows(sql)
#Log.debug(sql_result)
all_flowers=[]
if result==1:
for row in data:
all_flowers.append({'organization': str(row[0]), 'myID': self.decode(row[1]), 'dateCreated': str(row[2])})
return all_flowers
def one(self, organization, datetimestamp ):
''' flower for user, org and datetime
'''
result = -1
secret = ':-('
sql = "SELECT mySecret, myID, myName FROM %s where organization='%s' and dateCreated='%s' order by dateCreated DESC limit 1" % (self.customer_table, organization, datetimestamp)
result, data = self.do_db_1row(sql)
if result == 1:
return {'organization': organization, 'dateCreated': datetimestamp, 'myID': self.decode(data[1]), 'myName': self.decode(data[2]),'mySecret': self.decode(data[0])}
return {'organization': organization, 'dateCreated': datetimestamp, 'myID': '', 'myName': '','mySecret': '-- Not found --'}
def deactivate(self, organization, datetimestamp ):
''' flower for user, org and datetime
'''
result = -1
secret = ':-('
sql = "update {} set deleted=1 where organization='{}' and dateCreated='{}' ".format(self.customer_table, organization, datetimestamp)
result, data = self.do_db_commit(sql)
if result == 1:
secret = '- DELETED -'
return {'organization': organization, 'dateCreated': datetimestamp, 'myID': '', 'myName': '','mySecret': secret}
def empty(self):
''' empty flower
'''
return {'organization': '', 'dateCreated': '', 'myID': '', 'myName': '','mySecret': ''}
def numberOfEntries(self):
''' GET login info, check if its valid
'''
sql = "SELECT count(*) FROM {};".format(self.customer_table)
result, data = self.do_db_1row(sql)
if result == 1:
return(data[0])
return -1
def update_pwd(self, new_pwd):
newcipher = AES.new(pad(SECRET + new_pwd))
def new_encode(s):
return str(base64.b64encode(newcipher.encrypt(pad(s))).decode("utf-8"))
end_result = "ERROR updating hushes\n"
sql = """
select myID, myName, mySecret, organization, dateCreated from {0}""".format(self.customer_table)
result, data = self.do_db_allrows(sql)
# Log.debug(sql_result)
if result == 1:
# convert all hushes
sql = ""
for row in data:
sql += "update {} set myID='{}', myName='{}', mySecret='{}' where organization='{}' and dateCreated='{}';\n".\
format(self.customer_table,
new_encode(self.decode(row[0])),
new_encode(self.decode(row[1])),
new_encode(self.decode(row[2])),row[3], row[4])
result, data = self.do_db_commit(sql)
if result == 1:
end_result = "ERROR updating user-password\n"
# update the password of the user
sql = "SET PASSWORD FOR '{}'@'localhost' = PASSWORD('{}'); ".format(self.db_username, md5(new_pwd))
result, data = self.do_db_commit(sql)
if result == 1:
end_result = "SUCCESSFULLY updated, now login again\n"
return end_result
def do_db_commit(self, sql):
Log.debug('INSc: '+sql)
result = 0
data = ''
con = None
try:
con = mdb.connect(host='localhost', passwd=self.db_password, user=self.db_username, db=self.db);
cur = con.cursor()
if ";\n" in sql:
for s in sql.split(";\n"):
if len(s)>1:
cur.execute(s)
else:
cur.execute(sql)
cur.close()
con.commit()
result = 1
except mdb.Error as e:
m = "Error %d: %s" % (e.args[0],e.args[1])
data = {'message': m}
Log.debug(m)
result = -1
finally:
if con:
con.close()
return result, data
def do_db_1row(self, sql):
Log.debug('1row sql: '+sql)
result = 0
con = None
try:
con = mdb.connect(host='localhost', passwd=self.db_password, user=self.db_username, db=self.db);
cur = con.cursor()
cur.execute(sql)
data = cur.fetchone()
if data:
result = 1
except mdb.Error as e:
m = "Error %d: %s" % (e.args[0],e.args[1])
data = {'message': m}
Log.debug(m)
result = -1
finally:
if con:
con.close()
return result, data
def do_db_allrows(self, sql):
Log.debug('all rows sql: '+sql)
result = 0
con = None
try:
con = mdb.connect(host='localhost', passwd=self.db_password, user=self.db_username, db=self.db);
cur = con.cursor()
cur.execute(sql)
data = cur.fetchall()
if data:
result = 1
except mdb.Error as e:
m = "Error %d: %s" % (e.args[0],e.args[1])
data = {'message': m}
Log.debug(m)
result = -1
finally:
if con:
con.close()
return result, data
class SuperFlower(Flower):
def __init__(self, customer, pwd):
super().__init__(customer, pwd)
self.customer_name = customer + '_'
self.customer_pwd = pwd
self.db_username = 'flower'
self.db_password = md5('flower')
def createNewTable(self):
# create new table and user
sql = """
CREATE TABLE `{}` (
`organization` varchar(80) NOT NULL,
`myID` varchar(129) NOT NULL,
`myName` varchar(129) NOT NULL,
`mySecret` varchar(65) NOT NULL,
`dateCreated` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`deleted` int(11) DEFAULT '0',
PRIMARY KEY (`organization`,`dateCreated`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;""".format(self.customer_table)
result, data = self.do_db_1row(sql)
if result < 0:
Log.info("SQL ERROR:")
Log.info(data)
return 0
sql = """create user {}@localhost identified by '{}';""".format(self.customer_name, md5(self.customer_pwd))
result, data = self.do_db_1row(sql)
if result < 0:
Log.info("SQL ERROR:")
Log.info(data)
return 0
sql = """grant select,update,insert on Flowers.{} to {}@localhost;""".format(self.customer_table, self.customer_name)
result, data = self.do_db_1row(sql)
if result < 0:
Log.info("SQL ERROR:")
Log.info(data)
return 0
self.flush_privs()
return 1
def flush_privs(self):
sql = """flush privileges;"""
result, data = self.do_db_1row(sql)
if result < 0:
Log.info("SQL ERROR:")
Log.info(data)
return 0
return 1
def migrate(self, old_customer_name):
OLDSECRET = 'HSPh1O5vc6YY2Xt8jUxlTpd*DZsjMMAH'
OLDCIPHER = AES.new(OLDSECRET)
old_DecodeAES = lambda e: str(OLDCIPHER.decrypt(base64.b64decode(e)).decode("utf-8")).rstrip(PADDING)
def sql_datetime(datetime_type):
return datetime_type.strftime("%Y-%m-%d %H:%M:%S")
end_result = "ERROR creting new table\n"
if self.createNewTable():
end_result = "ERROR updating hushes\n"
sql = """
select myID, myName, mySecret, organization, dateCreated, deleted from {0}""".format(old_customer_name)
# 0 1 2 3 4 5
result, data = self.do_db_allrows(sql)
# Log.debug(sql_result)
if result == 1:
# convert all hushes
sql = ""
for row in data:
#sql += "insert {} set organization='{}', myID='{}', myName='{}', mySecret='{}', deleted={}, dateCreated='{}' where organization='{}' and dateCreated='{}';\n". \
sql += "INSERT INTO {} (organization ,myID ,myName ,mySecret, deleted, dateCreated) VALUES ('{}', '{}', '{}', '{}', {}, '{}') ;\n".\
format(self.customer_table,
row[3],
self.encode(row[0]),
self.encode(row[1]),
self.encode(old_DecodeAES(row[2])),
row[5],
sql_datetime(row[4]))
result, data = self.do_db_commit(sql)
if result == 1:
end_result = "SUCCESSFULLY updated, now login again\n"
return end_result
if __name__ == '__main__':
print("this is a library, sorry dude")
-272
View File
@@ -1,272 +0,0 @@
####################
#
# file is replaced by SecretServices.py
#
1= # intentional python syntax error
#
####################
from Crypto.Cipher import AES
from Crypto.Hash import MD5
import base64
import os, time, re, sys
from Log import Log
from Config import *
import json
import pymysql as mdb
import datetime
import hashlib
#encryption stuff
SECRET='HSPh1O5vc6YY2Xt8jUxlTpd*DZsjMMAH'
BLOCK_SIZE = 32
PADDING='_'
# one-liner to sufficiently pad the text to be encrypted
pad = lambda s: s + (BLOCK_SIZE - len(s) % BLOCK_SIZE) * PADDING
# one-liners to encrypt/encode and decrypt/decode a string
# encrypt with AES, encode with base64
CIPHER = AES.new(SECRET)
EncodeAES = lambda s: str(base64.b64encode(CIPHER.encrypt(pad(s))).decode("utf-8"))
DecodeAES = lambda e: str(CIPHER.decrypt(base64.b64decode(e)).decode("utf-8")).rstrip(PADDING)
def md5(message):
hash = MD5.new()
hash.update(message.encode('utf-8'))
return hash.hexdigest()
class Flower():
def __init__(self, user, pwd):
self.database = 'Flowers'
self.table = user
self.username = user
self.password = md5(pwd)
def add(self, organization, myname, myid, secret):
''' POST a new flower
'''
if len(organization)>MINFIELDLEN and len(myid)>MINFIELDLEN and len(secret)>MINFIELDLEN:
sql = "INSERT INTO {} (organization ,myID ,myName ,mySecret, deleted) VALUES ('{}', '{}', '{}', '{}', 0)".format(self.table, organization, myid, myname, EncodeAES(secret))
result, data = self.do_db_commit(sql)
Log.debug(result)
if result==1:
return {'organization': organization, 'dateCreated': 'STORED', 'myID': myid, 'myName': myname,'mySecret': secret}
return {'organization': organization, 'dateCreated': 'FAILED', 'myID': myid, 'myName': myname,'mySecret': secret}
def all(self, isdeleted=0):
''' GET flowers list
'''
#sql = "SELECT organization, myID, myName, dateCreated FROM %s " % (self.table)
sql = """
select uniqueflowers.organization, uniqueflowers.myID, uniqueflowers.dateCreated from {0} as uniqueflowers
inner join (
select organization, max(dateCreated) as lastCreated from {0} group by organization order by dateCreated DESC) allflowers
on allflowers.organization=uniqueflowers.organization and lastCreated=uniqueflowers.dateCreated where uniqueflowers.deleted={1}
""".format(self.table, isdeleted)
result, data = self.do_db_allrows(sql)
#Log.debug(sql_result)
all_flowers=[]
if result==1:
for row in data:
all_flowers.append({'organization': str(row[0]), 'myID': str(row[1]), 'dateCreated': str(row[2])})
return all_flowers
def one(self, organization, datetimestamp ):
''' flower for user, org and datetime
'''
result = -1
secret = ':-('
sql = "SELECT mySecret, myID, myName FROM %s where organization='%s' and dateCreated='%s' order by dateCreated DESC limit 1" % (self.table, organization, datetimestamp)
result, data = self.do_db_1row(sql)
if result == 1:
secret = DecodeAES(data[0])
return {'organization': organization, 'dateCreated': datetimestamp, 'myID': data[1], 'myName': data[2],'mySecret': secret}
def deactivate(self, organization, datetimestamp ):
''' flower for user, org and datetime
'''
result = -1
secret = ':-('
sql = "update %s set deleted=1 where organization='%s' and dateCreated='%s' " % (self.table, organization, datetimestamp)
result, data = self.do_db_commit(sql)
if result == 1:
secret = '- DELETED -'
return {'organization': organization, 'dateCreated': datetimestamp, 'myID': '', 'myName': '','mySecret': secret}
def empty(self):
''' empty flower
'''
return {'organization': '', 'dateCreated': '', 'myID': '', 'myName': '','mySecret': ''}
def numberOfEntries(self):
''' GET login info, check if its valid
'''
sql = "SELECT count(*) FROM {};".format(self.table)
result, data = self.do_db_1row(sql)
if result == 1:
return(data[0])
return -1
def do_db_commit(self, sql):
Log.debug('INSc: '+sql)
result = 0
data = ''
con = None
try:
con = mdb.connect(host='localhost', passwd=self.password, user=self.username, db=self.database);
cur = con.cursor()
cur.execute(sql)
con.commit()
cur.close()
result = 1
except mdb.Error as e:
m = "Error %d: %s" % (e.args[0],e.args[1])
data = {'message': m}
Log.debug(m)
result = -1
finally:
if con:
con.close()
return result, data
def do_db_1row(self, sql):
Log.debug('1row sql: '+sql)
result = 0
con = None
try:
con = mdb.connect(host='localhost', passwd=self.password, user=self.username, db=self.database);
cur = con.cursor()
cur.execute(sql)
data = cur.fetchone()
if data:
result = 1
except mdb.Error as e:
m = "Error %d: %s" % (e.args[0],e.args[1])
data = {'message': m}
Log.debug(m)
result = -1
finally:
if con:
con.close()
return result, data
def do_db_allrows(self, sql):
Log.debug('all rows sql: '+sql)
result = 0
con = None
try:
con = mdb.connect(host='localhost', passwd=self.password, user=self.username, db=self.database);
cur = con.cursor()
cur.execute(sql)
data = cur.fetchall()
if data:
result = 1
except mdb.Error as e:
m = "Error %d: %s" % (e.args[0],e.args[1])
data = {'message': m}
Log.debug(m)
result = -1
finally:
if con:
con.close()
return result, data
class SuperFlower(Flower):
def __init__(self, user, pwd):
self.database = 'Flowers'
self.table = user
self.table_hush = pwd
self.username = 'flower'
self.password = md5('flower')
def createNewTable(self):
# create new table and user
sql = """
CREATE TABLE `{0}` (
`organization` varchar(50) NOT NULL,
`myID` varchar(50) NOT NULL,
`myName` varchar(50) NOT NULL,
`mySecret` varchar(50) NOT NULL,
`dateCreated` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`deleted` int(11) DEFAULT '0',
PRIMARY KEY (`organization`,`dateCreated`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;""".format(self.table)
result, data = self.do_db_1row(sql)
if result < 0:
Log.info("SQL ERROR:")
Log.info(data)
return 0
sql = """create user {0}@localhost identified by '{1}';""".format(self.table, md5(self.table_hush))
result, data = self.do_db_1row(sql)
if result < 0:
Log.info("SQL ERROR:")
Log.info(data)
return 0
sql = """grant select,update,insert on Flowers.{0} to {0}@localhost;""".format(self.table)
result, data = self.do_db_1row(sql)
if result < 0:
Log.info("SQL ERROR:")
Log.info(data)
return 0
sql = """flush privileges;"""
result, data = self.do_db_1row(sql)
if result < 0:
Log.info("SQL ERROR:")
Log.info(data)
return 0
return 1
def re_hush(self, new_hush):
end_result = "Starting Rehush\n"
sql = """
select mySecret, organization, dateCreated from {0}""".format(self.table)
result, data = self.do_db_allrows(sql)
# Log.debug(sql_result)
if result == 1:
# convert all hushes
sql = ""
for row in data:
old_hush = DecodeAES(row[0])
sql += "update {} set mySecret='{}' where organization='{}' and dateCreated='{}';\n".format(self.table, md5(old_hush), row[1], row[2])
result, data = self.do_db_commit(sql)
if result == 1:
end_result = "Finished Rehush\n"
end_result = "Starting update user password\n"
# update the password of the user
sql = "SET PASSWORD FOR '{}'@'localhost' = PASSWORD(md5(secret));\n".format(self.table)
sql += "flush privileges;"
result, data = self.do_db_commit(sql)
if result == 1:
end_result = "Finished update user password\n"
if __name__ == '__main__':
print("this is a library, sorry dude")
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
-9
View File
@@ -1,9 +0,0 @@
WSGIDaemonProcess flowers user=www-data group=www-data threads=5
WSGIScriptAlias /flowers /usr/share/projects/Flowers/flowers.wsgi
<Directory /usr/share/projects/Flowers>
WSGIProcessGroup flowers
WSGIApplicationGroup %{GLOBAL}
Order deny,allow
Allow from all
</Directory>
-17
View File
@@ -1,17 +0,0 @@
import kivy
kivy.require('1.0.6') # replace with your current kivy version !
from kivy.app import App
from kivy.uix.label import Label
class MyApp(App):
def build(self):
return Label(text='Hello world')
if __name__ == '__main__':
MyApp().run()
-7
View File
@@ -1,7 +0,0 @@
import requests
r = requests.post('http://0.0.0.0:8080/app', data = {'name':'piet', 'password': 'piet', 'action': 'list'})
#r = requests.post('http://0.0.0.0:8080/app', data = {'name':'ignace', 'password': 'white', 'action': 'one', 'dateCreated': '2018-05-30 21:18:00', 'organization': 'https://mijntele2.tele2.nl/'})
#r = requests.post('http://0.0.0.0:8080/app', data = {'name':'ignace', 'password': 'white', 'action': 'save'})
#r = requests.post('http://0.0.0.0:8080/app', data = {'name':'ignace', 'password': 'white', 'action': 'list'})
# print(r.text)
-139
View File
File diff suppressed because one or more lines are too long
-54
View File
@@ -1,54 +0,0 @@
# from flask import Flask
from Config import *
import sys
import datetime
from SecretServices import Flower,SuperFlower
from AccessControl import Access
import json
# from flask import Flask, request, session, g, redirect, url_for, abort, render_template, flash, json, make_response
# from werkzeug.exceptions import HTTPException
newuser = 'ignace'
newhush = 'black'
# login db with generic user
# f = SuperFlower(newuser, newhush)
# if f.createNewTable():
# login as new user
# u = Flower(newuser, newhush)
# add one line
#u.add('Demo organisation', 'Demo name', 'Demo login', 'Demo hush')
# read one line
#create user
# login db with generic user
# f = SuperFlower(newuser, newhush)
# if f.createNewTable():
# # login as new user
# u = Flower(newuser, newhush)
# # add one line
# u.add('Demo organisation', 'Demo name', 'Demo login', 'Demo hush')
# retrieve all flowers
# u = Flower(newuser, newhush)
# flowers=u.all()
# print(flowers)
# retrieve one flowers
# u = Flower(newuser, newhush)
# flower=u.one('ah', '2003-03-17 17:30:27')
# print(flower)
# dump all flowers with pwds
u = Flower(newuser, newhush)
flowers=u.all()
for f in flowers:
flower = u.one(f['organization'], f['dateCreated'])
print('"{}","{}","{}","{}","{}",'.format(flower['organization'],flower['dateCreated'],flower['myID'],flower['myName'],flower['mySecret']))
+310 -184
View File
@@ -1,202 +1,328 @@
from flask import Flask, Blueprint, send_from_directory
from Config import *
import sys
import datetime
import pytz
from FlowerServices import Flower,SuperFlower
from AccessControl import Access
"""HTTP routes for the Flowers browser UI and legacy form API."""
from __future__ import annotations
import json
from flask import Flask, request, session, g, redirect, url_for, abort, render_template, flash, json, make_response
from werkzeug.exceptions import HTTPException
import secrets
import threading
from dataclasses import dataclass
from datetime import datetime, timedelta, timezone
# configuration
# DEBUG = False
# SECRET_KEY = 'development key'
flower_bp = Blueprint("flower_vase", __name__, url_prefix=URLPREFIX)
from flask import (
Blueprint,
abort,
current_app,
flash,
jsonify,
redirect,
render_template,
request,
session,
url_for,
)
from AccessControl import Access
from Config import DONOTSETFILTER, SESSION_MINUTES, URLPREFIX
from FlowerServices import Flower, InvalidCredentials, StorageError, SuperFlower
# app = Flask(__name__)
# app.config.from_object(__name__)
flower_bp = Blueprint(
"flower_vase",
__name__,
url_prefix=URLPREFIX,
static_folder="static",
static_url_path="/static",
template_folder="templates",
)
@flower_bp.route('/static/<filename>')
def statix(filename):
return send_from_directory('static', filename)
@flower_bp.route('/')
@dataclass
class _Credential:
username: str
password: str
expires_at: datetime
class CredentialStore:
"""Keep database credentials server-side instead of in Flask's cookie."""
def __init__(self) -> None:
self._items: dict[str, _Credential] = {}
self._lock = threading.Lock()
def create(self, username: str, password: str) -> str:
token = secrets.token_urlsafe(32)
with self._lock:
self._purge()
self._items[token] = _Credential(username, password, self._deadline())
return token
def get(self, token: str | None) -> tuple[str, str] | None:
if not token:
return None
with self._lock:
self._purge()
credential = self._items.get(token)
if credential is None:
return None
credential.expires_at = self._deadline()
return credential.username, credential.password
def revoke(self, token: str | None) -> None:
if token:
with self._lock:
self._items.pop(token, None)
def _purge(self) -> None:
now = datetime.now(timezone.utc)
expired = [key for key, value in self._items.items() if value.expires_at <= now]
for key in expired:
del self._items[key]
@staticmethod
def _deadline() -> datetime:
return datetime.now(timezone.utc) + timedelta(minutes=SESSION_MINUTES)
def _credentials() -> CredentialStore:
return current_app.extensions["credential_store"]
def _csrf_token() -> str:
token = session.get("csrf_token")
if not token:
token = secrets.token_urlsafe(32)
session["csrf_token"] = token
return token
@flower_bp.context_processor
def template_context() -> dict:
return {"csrf_token": _csrf_token()}
@flower_bp.before_request
def protect_browser_posts():
if request.method != "POST" or request.endpoint == "flower_vase.web_service":
return None
supplied = request.form.get("csrf_token", "")
expected = session.get("csrf_token", "")
if not expected or not secrets.compare_digest(supplied, expected):
abort(400, description="Invalid or expired form token")
return None
def _vault_from_session() -> Flower | None:
credential = _credentials().get(session.get("auth_token"))
if not credential:
return None
try:
return Flower(*credential)
except InvalidCredentials:
return None
def _login_page(name="Welcome back", password="Enter your bouquet password", status=200):
return render_template(
"index.html", name_suggestion=name, pwd_suggestion=password
), status
@flower_bp.get("/")
def index():
print(request.remote_addr)
return render_template('index.html', name_suggestion="Hello", pwd_suggestion="Want to try your luck?")
return _login_page()
@flower_bp.route('/browser' , methods=['POST', 'GET'])
@flower_bp.route("/browser", methods=["GET", "POST"])
def application():
now = datetime.datetime.now(pytz.timezone('Europe/Amsterdam'))
if request.method == "GET":
vault = _vault_from_session()
if vault is None:
return redirect(url_for("flower_vase.index"))
try:
selected_filter = session.get("filter", "")
return render_template(
"list.html", flowers=vault.all(), filter=selected_filter
)
except StorageError:
flash("The bouquet database could not complete that request.", "error")
return redirect(url_for("flower_vase.index"))
if request.method == 'GET':
return render_template('index.html', name_suggestion="Faded out", pwd_suggestion="Want to retry your luck?")
access = Access()
client_ip = request.remote_addr or "unknown"
if not access.granted(client_ip):
return _login_page("Too many attempts", "Try again in five minutes", 429)
access_ctrl = Access()
if not access_ctrl.granted(request.remote_addr):
return render_template('index.html', name_suggestion="Sorry", pwd_suggestion="Access denied")
action = request.form.get("action", "")
if action == "login":
return _login(access, client_ip)
if action == "logout":
_credentials().revoke(session.pop("auth_token", None))
session.pop("filter", None)
flash("You have been signed out.", "success")
return redirect(url_for("flower_vase.index"))
action=request.form['action']
filter=''
if 'filter' in session:
filter = session['filter']
vault = _vault_from_session()
if vault is None:
session.pop("auth_token", None)
flash("Your session expired. Please sign in again.", "error")
return redirect(url_for("flower_vase.index"))
if action == 'logout':
session['filter'] = request.form['filter']
session['timeout'] = now - datetime.timedelta(minutes=999)
return render_template('index.html', name_suggestion="Bye", pwd_suggestion="Come back any time")
if action == 'login':
user=request.form['name']
pwd=request.form['password']
F = Flower(user, pwd)
if F.numberOfEntries()>=0:
session['dbuser'] = user
session['dbpwd'] = pwd
session['timeout'] = now
session['filter'] = filter
return render_template('list.html', flowers=F.all(), filter=filter)
#login failure
access_ctrl.deny(request.remote_addr)
print("Flowers - authorization failed for {}".format(user))
return render_template('index.html', name_suggestion="Sorry", pwd_suggestion="Better next time")
if 'timeout' in session and session['timeout']+datetime.timedelta(minutes=10)>now:
session['timeout'] = now
if 'filter' in request.form.keys() and len(request.form['filter'])>1 and request.form['filter'] != DONOTSETFILTER:
session['filter']=request.form['filter']
filter = request.form['filter']
F = Flower(session['dbuser'], session['dbpwd'])
if F.numberOfEntries()>=0:
if action == 'list':
return render_template('list.html', flowers=F.all(), filter=filter)
if action == 'show':
return render_template('show.html', flower=F.one(request.form['organization'], request.form['datetime']))
if action == 'edit':
return render_template('edit.html', flower=F.one(request.form['organization'], request.form['datetime']))
if action == 'new':
return render_template('edit.html', flower=F.empty())
if action == 'save':
flower = F.add(request.form['organization'],request.form['myname'],request.form['myid'],request.form['secret'])
session['filter']=request.form['organization']
return render_template('show.html', flower=flower)
if action == 'deactivate':
flower = F.deactivate(request.form['organization'],request.form['datetime'])
session['filter']=''
return render_template('show.html', flower=flower)
if action == 'rehush':
return render_template('rehush.html', flower=F.empty())
else:
return render_template('new.html', flower=F.empty())
return render_template('index.html', name_suggestion="Sorry", pwd_suggestion="Better next time")
@flower_bp.route('/create' , methods=['POST','GET'])
def create():
access_ctrl = Access()
if not access_ctrl.granted(request.remote_addr):
return render_template('index.html', name_suggestion="Sorry", pwd_suggestion="Access denied")
if 'name' not in request.form:
return render_template('create.html')
newuser = request.form['name']
newhush = request.form['password']
# login db with generic user
f = SuperFlower(newuser, newhush)
if f.createNewTable():
# login as new user
u = Flower(newuser, newhush)
# add one line
u.add('Demo organisation', 'Demo name', 'Demo login', 'Demo hush')
# return to the login page
return render_template('index.html', name_suggestion="Now login", pwd_suggestion="for your very first time")
return render_template('create.html', message="Sorry - System error - check log files")
@flower_bp.route('/update_pwd', methods=['POST','GET'])
def update_pwd():
if 'name' not in request.form:
return render_template('rehush.html')
user = request.form['name']
oldhush = request.form['old_password']
newhush = request.form['new_password']
# login db with generic user
f = Flower(user, oldhush)
message = f.update_pwd(newhush)
f = SuperFlower(user, oldhush)
f.flush_privs()
return render_template('index.html', name_suggestion=message, pwd_suggestion="...")
# @app.route('/migrate', methods=['POST','GET'])
# def migrate():
# user = 'ignace'
# hush = 'black'
#
# f = SuperFlower(user, hush)
# f.migrate(user)
#
# return render_template('index.html', name_suggestion='login again', pwd_suggestion="...")
@flower_bp.route('/app' , methods=['POST'])
def web_service():
# same thing as 'aplication, but returns go in json
result = json.dumps({'result': -1, 'message': 'Invalid entry'})
selected_filter = session.get("filter", "")
form_filter = request.form.get("filter", "")
if len(form_filter) > 1 and form_filter != DONOTSETFILTER:
selected_filter = form_filter
session["filter"] = selected_filter
try:
access_ctrl = Access()
if not access_ctrl.granted(request.remote_addr):
result = json.dumps({'result': -1, 'message': 'Access denied'})
if action == "list":
return render_template("list.html", flowers=vault.all(), filter=selected_filter)
if action in {"show", "edit"}:
flower = vault.one(
request.form.get("organization", ""), request.form.get("datetime", "")
)
return render_template(f"{action}.html", flower=flower, filter=selected_filter)
if action == "new":
return render_template("edit.html", flower=vault.empty(), filter=selected_filter)
if action == "save":
flower = vault.add(
request.form.get("organization", "").strip(),
request.form.get("myname", "").strip(),
request.form.get("myid", "").strip(),
request.form.get("secret", ""),
)
if flower["dateCreated"] == "FAILED":
flash("Organization, login, and secret must each be at least four characters.", "error")
return render_template("edit.html", flower=flower, filter=selected_filter), 422
session["filter"] = flower["organization"]
flash("Entry saved as a new version.", "success")
return render_template("show.html", flower=flower, filter=flower["organization"])
if action == "deactivate":
flower = vault.deactivate(
request.form.get("organization", ""), request.form.get("datetime", "")
)
session["filter"] = ""
flash("Entry removed from the active list.", "success")
return render_template("show.html", flower=flower, filter="")
if action == "rehush":
return render_template("rehush.html")
except StorageError:
flash("The bouquet database could not complete that request.", "error")
return redirect(url_for("flower_vase.index"))
else:
#no session variables here - the client will take care of fileter and timeout
action = request.form['action']
user = request.form['name']
pwd = request.form['password']
F = Flower(user, pwd)
if F.numberOfEntries() == -1:
#login failure
access_ctrl.deny(request.remote_addr)
result = json.dumps({'result': 0, 'message': 'Invalid username or password'})
elif action == 'login':
result = json.dumps({'result': 1, 'message': 'Access granted'})
elif action == 'list':
result = json.dumps({'result': 1, 'message': 'Ok', 'list': json.dumps(F.all())})
elif action == 'one':
result = json.dumps({'result': 1, 'message': 'Ok', 'flower': json.dumps( F.one(request.form['organization'], request.form['dateCreated']) )})
elif action == 'save':
result = json.dumps({'result': 1, 'message': 'Ok', 'flower': json.dumps(F.add(request.form['organization'],request.form['myname'],request.form['myid'],request.form['secret']) )})
elif action == 'deactivate':
result = json.dumps({'result': 1, 'message': 'Ok', 'flower': json.dumps(F.deactivate(request.form['organization'], request.form['dateCreated']))})
except:
pass
return result
abort(400, description="Unknown action")
def _login(access: Access, client_ip: str):
username = request.form.get("name", "").strip()
password = request.form.get("password", "")
try:
vault = Flower(username, password)
authenticated = vault.authenticate()
except InvalidCredentials:
authenticated = False
if not authenticated:
access.deny(client_ip)
return _login_page("Sign-in failed", "Check your username and password", 401)
old_token = session.get("auth_token")
_credentials().revoke(old_token)
session.clear()
session["csrf_token"] = secrets.token_urlsafe(32)
session["auth_token"] = _credentials().create(username, password)
session["filter"] = ""
return redirect(url_for("flower_vase.application"))
@flower_bp.route("/create", methods=["GET", "POST"])
def create():
if request.method == "GET":
return render_template("create.html")
access = Access()
client_ip = request.remote_addr or "unknown"
if not access.granted(client_ip):
return _login_page("Too many attempts", "Try again later", 429)
username = request.form.get("name", "").strip()
password = request.form.get("password", "")
try:
provisioner = SuperFlower(username, password)
created = provisioner.createNewTable()
except InvalidCredentials as exc:
return render_template("create.html", message=str(exc)), 422
if created:
Flower(username, password).add(
"Demo organisation", "Demo name", "Demo login", "Demo secret"
)
flash("Your bouquet is ready. Sign in to continue.", "success")
return redirect(url_for("flower_vase.index"))
return render_template(
"create.html", message="The bouquet could not be created. Check the server log."
), 500
@flower_bp.route("/update_pwd", methods=["GET", "POST"])
def update_pwd():
if request.method == "GET":
return render_template("rehush.html")
try:
vault = Flower(
request.form.get("name", "").strip(),
request.form.get("old_password", ""),
)
if not vault.authenticate():
raise InvalidCredentials("Current credentials are not valid")
message = vault.update_pwd(request.form.get("new_password", ""))
except InvalidCredentials as exc:
return render_template("rehush.html", message=str(exc)), 422
_credentials().revoke(session.pop("auth_token", None))
flash(message, "success" if message.startswith("SUCCESS") else "error")
return redirect(url_for("flower_vase.index"))
@flower_bp.post("/app")
def web_service():
"""Preserve the historical form API, including double-encoded payloads."""
access = Access()
client_ip = request.remote_addr or "unknown"
if not access.granted(client_ip):
return jsonify(result=-1, message="Access denied")
action = request.form.get("action", "")
username = request.form.get("name", "")
password = request.form.get("password", "")
try:
vault = Flower(username, password)
if not vault.authenticate():
access.deny(client_ip)
return jsonify(result=0, message="Invalid username or password")
if action == "login":
return jsonify(result=1, message="Access granted")
if action == "list":
return jsonify(result=1, message="Ok", list=json.dumps(vault.all()))
if action == "one":
item = vault.one(
request.form.get("organization", ""),
request.form.get("dateCreated", ""),
)
return jsonify(result=1, message="Ok", flower=json.dumps(item))
if action == "save":
item = vault.add(
request.form.get("organization", ""),
request.form.get("myname", ""),
request.form.get("myid", ""),
request.form.get("secret", ""),
)
return jsonify(result=1, message="Ok", flower=json.dumps(item))
if action == "deactivate":
item = vault.deactivate(
request.form.get("organization", ""),
request.form.get("dateCreated", ""),
)
return jsonify(result=1, message="Ok", flower=json.dumps(item))
except (InvalidCredentials, StorageError, ValueError):
current_app.logger.exception("Flowers API request failed")
return jsonify(result=-1, message="Invalid entry")
+19 -8
View File
@@ -1,16 +1,27 @@
"""Flowers application factory."""
from flask import Flask
from flower_vase import flower_bp
from Config import COOKIE_SECURE, DEBUG, SECRET_KEY
from flower_vase import CredentialStore, flower_bp
def create_app():
def create_app(test_config: dict | None = None) -> Flask:
app = Flask(__name__)
app.config["SECRET_KEY"] = 'adhf adsh 8347y92347rupqo;wjf cowuyergc9b24387ryx1 -923pqr pqwejf qy7i34'
app.config.from_mapping(
SECRET_KEY=SECRET_KEY,
SESSION_COOKIE_HTTPONLY=True,
SESSION_COOKIE_SAMESITE="Lax",
SESSION_COOKIE_SECURE=COOKIE_SECURE,
MAX_CONTENT_LENGTH=64 * 1024,
)
if test_config:
app.config.update(test_config)
app.extensions["credential_store"] = CredentialStore()
app.register_blueprint(flower_bp)
return app
if __name__ == '__main__':
my_app = create_app()
# if needed - initialize data
my_app.run(debug=True, host='127.0.0.1', port=5012)
if __name__ == "__main__":
create_app().run(debug=DEBUG, host="127.0.0.1", port=5012)
+4 -2
View File
@@ -1,7 +1,9 @@
#!/usr/bin/python
import sys
sys.path.insert(0, '/usr/share/projects/wsgi_apps/flowers')
from flowers import app as application
sys.path.insert(0, "/usr/share/projects/wsgi_apps/flowers")
from flowers import create_app
application = create_app()
-28
View File
@@ -1,28 +0,0 @@
from Config import *
import sys
import datetime
from FlowerServices import Flower,SuperFlower
from AccessControl import Access
file1 = open('pins.csv', 'r')
Lines = file1.readlines()
newuser = 'janine'
newhush = 'demaat196'
# create user in the db.
f = SuperFlower(newuser, newhush)
if f.createNewTable():
# login as new user
u = Flower(newuser, newhush)
count = 0
# Strips the newline character
for line in Lines:
count += 1
line=line.strip()
print(line)
(org, date, id, name, pwd) = line.split('","',5)
org = org[1:]
pwd = pwd[:-2]
u.add(org, name, id, pwd, 0, date)
-317
View File
@@ -1,317 +0,0 @@
"https://en.lespassionnesduvin.com/","2023-07-23 15:05:32","janine@demaat.info","","HELLO2023&$",
"Www.kaartje2go.nl","2023-05-22 20:13:29","janine@demaat.info","","Kkart2211zs#",
"Ignace tel ontgrendelen","2023-04-30 19:17:14","janine@demaat.info","","007662",
"www.almeerplant.nl","2023-04-17 20:00:44","janine@demaat.info","kaart nummer 00089277","TISmeWHAT!@",
"www.spasereen.nl","2023-04-08 08:38:59","janine@demaat.info",""," Massage Sport 25 min. Start",
"https://www.america-today.com","2023-03-28 15:38:35","janine@demaat.info","","9yrtaqSXRUhx5Wm",
"komoot.nl","2023-03-08 07:55:02","janine@demaat.info","","K20k23@#&",
"Promedico.topdesk.net zelfservice portaal selfservice ","2023-03-01 13:11:37","jdmaat","","Pro2020!",
"www.topgear.nl","2023-02-14 09:57:39","janine@demaat.info","","tttopGEAR#@",
"https://loket.loket.nl werkgevers loket","2023-02-02 14:52:33","janine@demaat.info","","Welkom01",
"https://gegevensportaal.belastingdienst.nl","2023-02-02 09:25:35","UBD002281","","Muiden2023!!",
"www.eherkenning.nl Reconi","2023-01-26 17:23:34","janine@demaat.info","","Muiden2023#@!",
"www.eherkenning.nl","2023-01-26 16:57:57","janine@demaat.info","","Muiden2023#@!",
"https://waarneemapp.nl/companies/4708/schedules/openshifts","2023-01-26 15:46:15","janine@demaat.info","","HASamen2019",
"Loonheffing praktijk Belastingdienst Postbus 8738 4820 BA BREDA","2023-01-18 17:02:51","janine@demaat.info","","857592683L02",
"Bureaublad waarnemer","2023-01-11 07:35:31","waarnemer ","","Welkom2023",
"nationale nederlanden nn.nl --&amp;amp;gt; ZAKELIJK!","2023-01-09 16:27:05","ci4000025776","ci4000025776","NAT2023Burg15A",
"www.allesvoordesauna.nl","2023-01-08 22:25:54","janine@demaat.info","","SELdeVie202367",
"Www.mijngezondheidsmeter.nl","2023-01-03 06:20:53","janine@demaat.info","","PgOin2023@#!",
"https://www.milieubarometer.nl/csr/o/zhjws/i/88566/y1/n/0/","2022-12-29 18:37:12","v_verstappen@hotmail.com","","Burgemeester15A",
"www.asr.nl","2022-12-20 21:26:06","janine@demaat.info","","6497",
"www.debevlogenhuisarts.nl","2022-12-01 14:38:56","janine@demaat.info","","FlyFree2023#!",
"Https:/portaal.zorgvandezaak.nl/login","2022-11-25 11:13:42","Huisartsdemaat@ezorg.nl","","ZZZorg2023%!",
"www.gowah.nl","2022-11-20 21:45:22","janine@demaat.info","","LeD$&2022!",
"Www.123led.nl","2022-11-20 16:28:41","janine@demaat.info","","LeD$&2022!",
"www.uziregister.nl","2022-11-03 13:37:36","janine@demaat.info","Intrek VwuS5neALLc8","Pin 283357 puk 231958 ",
"www.coolblue.com","2022-10-23 13:20:42","janine@demaat.info","","B2v-EPG-Cri-uu",
"www.FMS.nl","2022-10-09 09:54:32","janine@demaat.info ","","FMSricht202144",
"Digitalis NHG rx","2022-10-04 21:35:30","v_verstappen@hotmail.com","","Burgemeester15a",
"www.1reaal.nl","2022-10-04 15:45:57","janine@demaat.info","","REa!@33X",
"MedGemak+","2022-10-04 08:45:12","Janine","","64971",
"ignaceontgrendelingtelefoon","2022-09-11 09:11:13","janine@demaat.info","","070662",
"Inlog praktijk start scherm bureaublad desktop","2023-07-25 10:35:26","janine@demaat.info","","HUISarts67!@#$%!!!!",
"Dpg.nl","2022-07-12 16:52:54","janine@demaat.info","","DpppG2021#!",
"transferpunt-go.nl","2022-07-12 16:15:41","JdeMaat","","Muiden2022oke",
"www.arcusit.itclientportal.com","2022-07-08 12:27:28","Huisartsdemaat@ezorg.nl","","MuidenGez!!",
"Uber","2022-06-20 19:02:51","janine@demaat.info","","ZzGg56&#",
"https://mijnoproep.sanquin.nl/","2022-06-15 16:07:04","janine@demaat.info","","SanQUIN2022&##",
"www.netflix.com","2022-06-03 18:06:00","ignace.suy@gmail.com","","querijnnf",
"GAIA https://www.pe-online.org/SPE001_PR_Inloggen.aspx?taalID=&amp;Calenda","2022-05-26 13:07:07","BIG-19042868401","","GaIA2022$#",
"Moby parkeren","2022-05-08 08:48:19","janine@demaat.info","","MoBy2022$$",
"Www.Beowulf.nl","2022-05-01 18:40:38","janine@demaat.info","","BEoAlm2022!",
"Discord","2022-04-27 09:53:37","janinedemaat","janine@demaat.info","Pompen2022#",
"Inlog praktijk startscherm bureaublad","2022-11-25 07:01:05","janine@demaat.info","","HUISarts67!@#$%!!",
"ABN Amro Gold Creditcard 64971","2022-03-02 21:38:21","JDEMAAT1967","1381","creditin2015isnotBAD@",
"www.light in the box","2022-02-24 16:53:54","janine@demaat.info","","R9TC8cS",
"https://www.gowah.nl/default.htm","2022-02-22 15:13:00","janine@demaat.info","","GGowah3342&#",
"Medfeed","2022-02-20 15:50:29","janine@demaat.info","","ME21&&#@",
"https://www.neleman.org","2022-02-17 12:06:37","janine@demaat.info","","87NEel&&&",
"www.gocards.nl","2022-02-03 08:24:40","Janinedm","","44554xq!",
"Www.bezorgdehuisartsen.nl","2022-01-31 06:06:06","janine@demaat.info","","Bezorgdin2022!?&",
"Cees.bezorgdehuisartsen.nl","2022-01-31 06:05:40","janine@demaat.info","","Bezorgdin2022!?&",
"www.hkvi.nl","2022-01-28 15:00:34","Huisartsdemaat@ezorg.nl","","HuisartsvanMuiden2021!",
"IMDB","2022-01-01 20:05:41","janine@demaat.info","","IiMmDdBB2021!?",
"www.greetz.com","2021-12-10 17:22:32","janine@demaat.info","","GRRR2019&@ha",
"Administratiehuisartsvanmuiden@ezorg.nl","2021-12-02 14:53:33","janine@demaat.info","","LiesKa80",
"Www.vasco.nl","2021-11-28 11:36:50","janine@demaat.info","","RivmVasco2921## 64971",
"Inlog praktijk start scherm bureaublad","2022-07-26 12:58:56","janine@demaat.info","","HUISarts67!@#$%!",
"www.henryschein.nl","2021-10-26 08:10:21","janine@demaat.info","","HENry2021@@",
"www.denieuwebibliotheek.nl","2021-10-24 19:29:11","janinedemaat","","BiBlio2121!",
"www.wehkamp.nl","2021-10-17 07:09:50","janine@demaat.info","","WEH2021k!!",
"Www.doecksen.nl","2021-10-13 21:04:21","janine@demaat.info","","2021Doecksen&&",
"Www.skge.nl","2021-10-13 16:25:10","janine@demaat.info","","VanKlacht2021$#",
"Spar.nl","2021-10-10 17:58:07","janine@demaat.info","","SpAr67$#!",
"Hopin.com","2021-10-05 16:44:07","janine@demaat.info","","HOPhop2021%$",
"Microsoft Teams.nl","2021-10-03 11:34:47","janine@demaat.info","","Xander@2",
"Kinepolis.nl bioscoop","2021-10-03 07:36:50","janine@demaat.info","","AlmKin67$$",
"Stocard.com","2021-09-30 11:15:26","janine@demaat.info","","1112",
"DHL.nl app","2021-09-26 21:19:04","janine@demaat.info","","@3daH-55",
"Pharmeon beheer pagina","2022-07-12 13:26:55","assistenteverstappen@ezorg.nl","","Muiden2022!",
"persgroep.beleefklassiek.nl","2021-09-18 08:24:54","Janine.Maat.978","","7fb5a18ca6",
"https://www.familienet.nl/client/katja-suy-linders/","2021-09-12 10:54:13","janine@demaat.info","","KatjaMOERG2020!",
"Bureaublad praktijk waarnemer en assistentes","2021-09-10 13:59:14","Waarnemer","","Muiden2021!",
"Www.picknick.nl","2021-08-26 14:31:01","janine@demaat.info","","vooruitmetdegeit2021!",
"Promedico dongel wrnarts","2021-07-30 06:17:52","wrnarts","","4444",
"Www.paul&pitalarm.nl","2021-07-22 07:59:35","janine@demaat.info","Janine","102127",
"www.raamdecoratie.com","2021-07-04 17:38:04","janine@demaat.info","","r2021aam@&",
"https://www.supersaas.nl/schedule/login/hartforherAlmere/hart_for_her_","2021-06-21 18:44:57","janine@demaat.info","","sport2021!!",
"Vecozo persoonlijk certificaat 30000000252756","2023-06-21 10:26:24","JdeMaat","","2023Muiden!",
"www.ssfh.nl stichting sociaal fonds huisartsenzorg","2021-05-18 15:20:36","janine@demaat.info","","SSfh2020!9",
"https://open.viadesk.com/do/portal","2021-05-11 17:26:35","janine@demaat.info","","OPEN2020Janine$#",
"www.natuurhuisje.nl","2021-05-11 05:03:54","janine@demaat.info","","NAtuurr2021!",
"Promedico.topdesk.net zelfservice portaal","2021-05-02 18:03:37","jdmaat","","Pro2020!",
"www.tuinland.nl","2021-04-24 12:05:21","janine@demaat.info","","T@uinland!2",
"https://www.teunstuinposters.nl/","2021-03-28 10:10:53","janine@demaat.info","","857058d8",
"Owncloud https://www.suy.nu/cloud","2021-03-26 20:27:19","janine","","6767 pincode, xanderj2",
"sparkmail inlog mijndomijn janine@demaat.info","2021-05-03 20:03:00","janine@demaat.info","","Xander^66Suy",
"mail inlog mijndomijn janine@demaat.info","2021-05-03 20:03:38","janine@demaat.info","","Xander^66Suy",
"Www.fagron.nl","2021-03-15 14:45:28","janine@demaat.info","","FGRN2021#@",
"financieelhuisartsvanmuiden@ezorg.nl webmail","2021-03-14 16:09:59","financieelhuisartsvanmuiden@ezorg.nl","","kr39S5q0lonc",
"huisartsvanmuiden@ezorg.nl webmail ","2021-03-14 16:08:45","huisartsvanmuiden@ezorg.nl","","Ywlz9SWyuOLF",
"https://online.loket.nl/vso.prd.loket werkgevers loket","2021-03-11 15:21:10","janine@demaat.info","","Welkom01",
"Medi-access","2021-02-28 17:08:18","janine@demaat.info","","MeDI2021!Acc!$",
"intershift","2023-02-12 11:22:35","janine@demaat.info","","XanderJ2!",
"ABN Amro Gold Creditcard","2021-02-18 10:12:13","JDEMAAT1967","1381","creditin2015isnotBAD@",
"ABN NL65ABNA0247117560 pas 221 ","2021-02-14 21:26:34","janine@demaat.info","","pin 6783",
"ABN NL53ABNA0247355232 pas 441","2021-02-14 21:18:26","janine@demaat.info","","2921",
"Geneeskunde boek.nl","2021-02-07 13:30:10","janine@demaat.info","","BSl2021xj!",
"Zorgdomein.nl","2023-06-08 19:39:55","Huisartsdemaat@ezorg.nl",""," ZOrg2021!!!",
"Gast guest login","2021-02-01 21:49:20","Legio scipio","","althome_2019*FF",
"Login.WeSeeDo.nl","2021-02-01 08:20:15","Huisartsdemaat@ezorg.nl","","We2020SEE!",
"www.speld.nl","2021-01-28 15:42:03","janine@demaat.info","","Sspeld2021!!",
"Gold card","2021-01-25 18:42:58","janine@demaat.info","5341260091362308 425","2021secabn (3d security code)",
"Signal","2021-01-17 10:23:14","janine@demaat.info","","6767",
"Amazon","2021-01-14 23:06:47","janine@demaat.info","","AMAzing2121&!",
"Amazon prime","2021-01-14 22:12:51","Ignace.suy@gmail.com","","querijnAP",
"https://landelijkeleeromgeving.nspoh.nl/local/nspoh_register/signup.ph","2021-01-14 15:52:22","janine@demaat.info","","CoViD2019@#",
"Stumpel","2021-01-14 10:37:33","janine@demaat.info","","ST2021u$$",
"beheer.pharmeon.nl/Inloggen/app/","2021-01-14 09:00:05","v_verstappen@hotmail.com","","Burgemeester15a!",
"www.staatsloterijl.nl","2021-01-10 18:17:04","janine@demaat.info","","ST@aat!@2!35",
"Leeg worddocument","2021-01-07 10:15:58","janine@demaat.info","Op de Fschijf","Hierinstaanallewachtwoorden",
"Huisarts.mediq.nl/inloggen Mediq voorschrijfportaal hulpmiddelen","2020-12-21 07:39:17","MEDIQpatientdeMaat","","Mediq20211398",
"Mediq voorschrijfportaal hulpmiddelen","2020-12-18 10:10:24","Huisartsdemaat@ezorg.nl","","MEDIQpatientdeMaat",
"sum-up app","2020-11-13 11:59:42","v_verstappen@hotmail.com","","Burgemeester1398BE!",
"https://www.dokterandrebeautyworld.nl/","2020-11-09 22:14:11","janine@demaat.info","","##!2020jm!",
"Lanteltelefooninlogstoring","2020-11-02 11:36:49","janine@demaat.info toestel 16","16","3316572479",
"LHV panel","2020-10-30 19:05:34","janine@demaat.info","","LHv2222#@",
"Mcc gooi en Vechtstreek","2020-10-29 15:36:30","janine@demaat.info","","McC2019xj",
"Flitsmeister","2020-10-17 10:53:17","janine@demaat.info","","Flitzz!",
"Weesper nieuws","2020-10-16 20:29:56","janine@demaat.info","","WEEsper2020&#",
"Weesper nieuwa","2020-10-16 20:29:32","janine@demaat.info","","WEEsper2020&#",
"Natuurmonumenten","2020-10-15 13:37:03","janine@demaat.info","","3996486 lidnummer",
"https://www.bambooimport.com","2020-10-01 20:22:00","janine@demaat.info","","Bbambooo2020!",
"onlinebibliotheek.nl","2020-09-03 13:54:23","20060004773818","","BIEB2020@!67e",
"Mijn.euronature.nl","2020-09-03 08:34:35","janine@demaat.info","","rGPqNciD",
"DASHBOARD open","2020-08-22 11:54:04","janine@demaat.info","","DASH2020@#",
"Van Haren","2020-08-22 10:54:27","janine@demaat.info","","V5e11wONm",
"Zoom janine@demaat.info","2020-08-21 12:55:46","janine@demaat.info","","ZooM@#2020!",
"decathlon","2020-08-09 09:19:57","janine@demaat.info","","DE2020LL!",
"Faxhuisartsvanmuiden@ezorg.nl","2020-08-05 10:38:10","Faxhuisartsvanmuiden@ezorg.nl","","Welkom2020!",
"Promedico.topdesk.net","2020-07-28 11:32:25","jdmaat","","Pro2020!",
"www.voedingscentrum.nl","2020-07-19 15:40:23","janine@demaat.info","","Voe2020DD@",
"EZORG webmail inloggen assistenteverstappen@ezorg.nl","2020-07-14 06:17:29","assistenteverstappen@ezorg.nl","","Muiden2020",
"Bergman clinics app","2020-07-13 14:00:55","janine@demaat.info","","676764",
"https://mijnhypotheek.lloydsbank.nl/hypotheek","2020-07-09 12:33:55","janine@demaat.info","","LLOY2019%#!",
"Flevo-landschap.nl","2020-06-30 21:00:59","janine@demaat.info","","Flevo2020!@",
"Rhogo.qarebase.nl/account/login","2020-06-30 17:50:46","janine@demaat.info","","Mcix+Q69",
"Zilveren kruis app persoonlijk","2020-06-28 11:42:37","janine@demaat.info","","64971",
"Https://Promedico.topdesk.net","2020-06-19 14:58:02","jdmaat","","Muiden2020",
"Richtlijnendatabase.nl","2020-06-19 13:34:12","Huisartsdemaat@ezorg.nl","","MedSpeFed2020",
"EZORG webmail inloggen","2020-05-13 10:21:33","assistentedemaat@ezorg.nl","","Muiden2020",
"Mediq.nl","2020-05-04 05:47:30","Huisartsdemaat@ezorg.nl","","MedBis2020!",
"NPA Vincent","2021-08-03 08:33:23","v_verstappen@hotmail.com","","npaweb1398BE",
"www.avaya.com workplace","2020-04-30 13:25:13","Toestel 16","","Muiden1398",
"www.avaya.com","2020-04-30 13:21:50","Toestel 16","","Muiden1398",
"NPAweb.nl","2022-06-13 13:33:10","janine@demaat.info","","NPA2020Muiden1!!!",
"Groene Amsterdammer","2020-04-24 14:55:39","janine@demaat.info","","Groen22!",
"Open","2020-04-23 16:36:21","janine@demaat.info","","OPEN2020Janine$#",
"ISSUU","2020-04-13 17:02:19","janine@demaat.info","","ISSUU2020#@1",
"nationale nederlanden nn.nl --&amp;gt; ZAKELIJK!","2020-04-12 11:17:15","ci4000025776","v_verstappen@gmail.com","Burgemeester1398B&",
"Https://covid19.u-diagnostics.com","2020-04-07 14:45:35","Huisartsdemaat@ezorg.nl","","GoFit2020#$2",
"WeSeeDo","2020-03-30 10:17:36","Huisartsdemaat@ezorg.nl","","We2020SEE!",
"Videoconsult.clickdoc.nl CGM videobellen","2020-03-27 09:39:39","jdemaat","jdemaat","CGMvideo2020$$",
"Zoom","2020-03-25 14:30:20","Huisartsdemaat@ezorg.nl","","ZZZoom2020!",
"Webmail.mijndomein.nl","2020-05-15 10:35:09","janine@demaat.info","","xanderJ2",
"CGM videobellen","2020-03-23 14:50:03","jdemaat","","CGMvideo2020$$",
"Siilo","2021-03-25 14:58:30","janine@demaat.info","janine@demaat.info","64971",
"Wish","2020-03-22 10:28:33","janine@demaat.info","janine@demaat.info","WiSH2121#@",
"Medischescholing.nl","2020-05-12 18:19:45","janine@demaat.info","janine@demaat.info"," MediCovid2020!",
"MedGemak","2020-03-03 09:12:38","Janine","","64971",
"Zorgmail POH GGZ","2020-02-27 11:53:47","500110871","","pjj4s-zb3s9-yzntx-62kvu-f2x7d",
"Zorgmail Huisarts van Muiden","2020-02-27 11:52:52","500107607","","5wgza-ajpxv-h5j7j-2wpjm-28wny",
"Zorgmail Verstappen","2020-02-27 11:51:52","500107252","","yup5s-sn62n-vmsvr-7wp68-j4ru7",
"Zorgmail de Maat","2020-05-22 10:18:39","xa3bm-x6uak-zsmw4-6fsra-jbdh8","500013469","ZorgMaildemaat2020!",
"De nieuwe bibliotheek","2020-02-20 19:42:42","JdeMaat","","BiebAlmere2020!",
"Bureaublad praktijk waarnemer","2021-01-27 06:54:56","Waarnemer","","Welkom2021",
"Waarneemapp","2019-12-28 11:29:57","janine@demaat.info","janine@demaat.info","HASamen2019",
"www.nvve.nl","2019-12-21 15:26:45","janine@demaat.info","janine@demaat.info","MaatNVVE2019",
"SNGP Griep","2021-10-11 12:21:09","0108030-01","janine@demaat.info","MUIDEN1398BE!!",
"Computer praktijk Vincent","2020-02-26 13:45:33","Vincent","Vincent","Muiden2017!",
"GhoGo.nl","2019-11-13 22:37:35","janine@demaat.info","janine@demaat.info","GhoGo2019#$2",
"PIM inloggen telefonie huisartsenpost","2019-11-10 09:05:22","janine@demaat.info","primair-bla-spreekkamer5 ( of een ander nummer)","Pr1m@1r!",
"MX-5 Owners","2019-11-03 10:16:44","janine@demaat.info","janine@demaat.info","Owners445",
"MX-5 Iwners","2019-11-03 10:15:53","janine@demaat.info","janine@demaat.info","Owners445",
"Omzetbelasting nummer (ob-nummer)","2019-10-31 15:41:01","janine@demaat.info","janine@demaat.info","101394585B01",
"BTW identificatienummer","2019-10-31 15:39:55","janine@demaat.info","janine@demaat.info","NL001387127B24",
"paspoort Janine de Maat 17 05 1967","2019-10-24 19:03:50","Janine paspoort tot 16 11 2027","janine@demaat.info","NM87JHH81",
"paspoort Ignace Marie Lucien Suy 12 11 1964","2019-10-24 19:02:34","janine@demaat.info","Ignace paspoort tot 17 10 2026","NT9DKR0C1",
"Eetmeter","2019-10-17 15:41:41","janine@demaat.info","janine@demaat.info","Eet!Eet",
"Body FX figure8","2019-09-26 16:40:09","janine@demaat.info","","2019janinenew",
"Inlog praktijk start scherm","2021-07-14 05:54:56","janine@demaat.info","","HUISarts67!@#",
"Lantel cloud","2020-11-10 06:53:35","Huisartsdemaat@ezorg.nl","Huisartsdemaat@ezorg.nl","LanTel2019@@##",
"Lantel cliud","2019-08-14 15:26:51","Huisartsdemaat@ezorg.nl","Huisartsdemaat@ezorg.nl","LanTel2019@#3EZORG",
"Zelfstroom zonnepanelen","2019-08-02 16:08:01","janine@demaat.info","","Zelf2019&&",
"nationale nederlanden nn.nl --&gt; ZAKELIJK!","2019-11-28 12:07:53","ci4000025776","huisartsverstappen@ezorg.nl","NAT2019Burg15A",
"Bayer medischwijzer.nl","2019-07-08 08:08:48","janine@demaat.info","","BaYer2019$$",
"Google","2020-03-22 13:46:51","janine.de.maat@gmail.com","","Xanderj2!",
"Vecozo","2023-06-02 12:27:06","Systeemcertificaat","MUIDEN2021!@","40000000127056pin MUIDEN2023!!",
"IC Taurus zelfservice portaal","2019-06-03 07:24:52","Huisartsverstappen@ezorg.nl","","W3Lkom@19!!",
"Vakantie piraten","2019-05-30 17:47:29","janine@demaat.info","janinepir","Vak2019Piraten#",
"Pharmeon","2021-09-07 06:40:54","assistenteverstappen@ezorg.nl","","2DEjTsFsDtw1",
"Makro","2019-05-28 15:04:16","janine@demaat.info","","Makro&&2019",
"de la mar","2019-05-25 11:54:42","janine@demaat.info","","altijdLEUK2019!",
"CBOARDS caresharing","2019-05-27 10:48:47","Huisartsdemaat@ezorg.nl","Huisartsdemaat@ezorg.nl","CBOARDS janine 2019 pin 64971",
"Instituut verantwoord medicijn gebruik IVM","2019-05-16 14:54:02","janine@demaat.info","","IvM2019IvM!",
"Digitalis","2019-05-08 14:05:42","v_verstappen@hotmail.com","","Burgemeester15a",
"Parool","2020-10-29 20:58:54","janine@demaat.info","","Parool1112@@",
"Mijn lcr inloggen","2019-04-29 21:54:01","VERSTAPPENV01","","Burgemeester15a",
"Marktplaats.nl","2019-04-28 14:04:39","janine@demaat.info","","MaRkTplaats2019$$#",
"Hopir","2019-04-25 08:25:58","janine@demaat.info","","Noorder2019",
"Secundum WIFI guests","2019-04-19 17:14:09","Secundum","Secundum","HH*20190405gg",
"Woonveilig app","2020-12-04 12:32:41","janinedemaat","","G7^Fddsr43#3 of pincode 6497",
"EHerkenning Cream Reconi de Maat","2019-04-05 14:35:36","janine@demaat.info","","64971",
"https://login.ns.nl/login NS","2021-05-24 13:21:27","janine@demaat.info","","NS2019ns@#!",
"Hudson Bay","2019-04-04 17:49:20","janine@demaat.info","","Hud2020Son@#$!",
"primus internet","2019-04-04 09:19:52","althome_2019*FF","","althome_2019*FF",
"Notaris unie 2","2019-03-25 19:28:01","janine@demaat.info","","XanderV20",
"Notaris unie","2019-03-25 19:19:31","Ignace.suy@gmail.com","","querijnv20",
"ParkMobile","2019-03-10 13:29:11","janine@demaat.info","","piaivtd",
"ASN bank","2020-12-02 19:22:25","janineasnbank","64971","asn!janine67DEMAAT",
"Overheid berichtenbox app","2019-02-14 18:48:23","Janine","Janine","64972",
"Dongel janine werk","2019-02-14 16:16:25","jdmaat","","1112",
"Dongel Janine thuus","2019-02-14 16:15:36","JdeMaat2","","2228",
"Dongel van co","2019-02-14 16:14:58","comuiden","","3333",
"Post.nl","2019-02-07 17:48:39","janine@demaat.info","","PosT2019@#6",
"Social deal","2019-02-07 10:14:33","janine@demaat.info","","SoCial2020$#$",
"FTO Online","2019-02-06 21:19:26","janine@demaat.info","","FtO2019#$6",
"Wachtwoorden praktijk c schijf facilitair wat wij belangrijk vinden","2019-02-06 15:33:13","Praktijk login c schijf","","Is er niet",
"Plex","2019-02-03 21:44:47","janine.de.maat@gmail.com","","Querijnp7",
"cloud https://www.suy.nu/cloud","2020-04-28 21:21:10","janine@demaat.info","","6767 pincode xanderj2",
"Werkgevers Loket","2020-03-09 13:28:12","janine@demaat.info","","Welkom01",
"DIGID","2020-05-01 14:10:28","JanineDigid","","Eninaj!2 67941",
"EZORG inloggen webmail: webmail.ezorg.nl ","2019-01-03 12:58:56","huisartsdemaat@ezorg.nl","","EZORG2017$%",
"nationale nederlanden nn.nl --> ZAKELIJK!","2019-01-03 12:48:28","CI4000025776","","NN2017HuisartsvanMuiden",
"Twiiter","2018-12-31 18:29:55","janine@demaat.info","","twetenisfun2018&",
"DIGIPAS Promedico 1112","2018-12-24 11:05:31","jdmaat","","1112",
"DIGIPAS Dongel Promedico 2228","2018-12-24 11:05:02","JdeMaat2","","2228",
"Primair Huisartsenpost","2020-08-23 10:38:30","janine@demaat.info","jdemaat","xanderjprimair",
"HAWEB","2022-12-14 06:05:30","janine@demaat.info","","HaWeb#2023&!",
"123INKT","2018-12-24 10:59:39","janine@demaat.info","","janine2012#123inkt",
"Nespresso","2018-12-24 10:52:06","janine@demaat.info","","nespresso12#",
"Herensokken.nl","2018-12-24 10:50:22","janine@demaat.info","","herensokken2013HAHA",
"GAIA https://www.pe-online.org/SPE001_PR_Inloggen.aspx?taalID=&Calenda","2018-12-24 10:47:57","BIG-19042868401","","weet ik niet",
"Wordfeut","2018-12-24 10:44:01","janinewordfeud67","","hallo67",
"Dropbox","2018-12-24 10:42:51","janine@demaat.info","","janinedropbox2014#$",
"NTVG inloggen","2018-12-24 10:34:45","jdemaat","","Ntvg2013demaat",
"FACEBOOK Facebook","2018-12-24 10:31:28","janine@demaat.info","","faceb2015@!@",
"ABN Amro Creditcard","2021-02-18 10:11:48","JDEMAAT1967","1381","creditin2015isnotBAD@",
"Linda TV","2018-12-24 10:21:06","janine@demaat.info","","HalloLindaTV2015",
"Toplenzen","2018-12-24 10:20:34","janine@demaat.info","","TopLenzen2015@#",
"Museumkaart","2018-12-24 10:19:57","janine@demaat.info",""," Museum2016$%",
"WDHMN","2018-12-24 10:19:28","jdemaat","","WDHMN2016$%",
"Nextdoor","2019-11-14 17:22:23","janine@demaat.info","","NextDoor201954@",
"Muidernieuws online lezen","2022-07-06 21:27:18","janine@demaat.info","","WEEsper2020&#",
"Managemenstboek","2018-12-24 10:17:54","janine@demaat.info","","manage2016@#",
"Volkskrant","2022-11-03 13:44:56","janine@demaat.info","","Nrcleuk!!!@",
"Airmiles","2020-03-12 13:07:49","JDEMAAT","","airmiles2016HIEPHOI!",
"Ticketveiling https://www.ticketveiling.nl","2022-03-25 19:15:17","jantje345","","ticket2022!)",
"Bonprix","2020-10-15 19:37:23","janine@demaat.info","","Bbonie21!",
"Vakantie Veiling","2018-12-24 10:14:12","janine@demaat.info","","vak2016veling@#",
"Pinterest","2018-12-24 10:13:17","jappie","","pint@@@2016ABC",
"Media Markt","2018-12-24 10:12:49","janine@demaat.info","","ongelovelijk2017#$%",
"Wijgergangs Medical www.wijgergangsmedical.nl","2018-12-24 10:12:07","janine@demaat.info","","Medische2016$%",
"Love For Rain https://www.loveforrain.nl/","2018-12-24 10:10:51","janine@demaat.info","","love2017welkom12",
"KRUIDVAT","2018-12-24 10:09:51","janine@demaat.info","","kruidvat2016#$%",
"Deen","2018-12-24 10:09:11","janine@demaat.info","","Deen2016$%6",
"gall gall","2018-12-24 10:08:23","janine@demaat.info","","GALL2016gall@#",
"Iens Seatme","2018-12-24 10:06:57","janine@demaat.info","","SeatMe2017$%!",
"Tui Mijntui www.tui.nl/mijntui","2019-10-24 18:42:48","janine@demaat.info","janine@demaat.info","TuiBonaire2019!!",
"Gmail inloggen","2018-12-24 10:04:26","janine.de.maat@gmail.com","","xanderj2",
"ANWB","2022-12-06 15:02:56","JaninedeMaatANWB","janine@demaat.info","ANWB2017#$",
"Appie Albert Heijn","2018-12-24 10:01:01","janine@demaat.info","","Appie2017Hallo!",
"FTO https://medicijngebruik.nl/","2018-12-24 09:59:15","janine@demaat.info","","FTO%&%2017!",
"Bol Com","2021-03-18 20:44:09","janine@demaat.info","","BolCC202123",
"Joviene Lourens Massage","2018-12-17 21:59:48","Janine67","","Loure2017@#$",
"Concertgebouw","2018-12-17 21:57:38","janine@demaat.info","","2017ConcertGeb$%",
"Hema.nl","2019-08-25 10:51:14","janine@demaat.info","","HemaTheBest2019!",
"koopjedeal","2018-12-17 21:55:23","janine@demaat.info","","koop2017je%^deal",
"Health Investment https://www.lpx.nl/healthinvestment/login","2018-12-17 21:54:12","janine@demaat.info","","HealthInvest2017^%",
"Medisch contact","2020-10-25 14:41:46","janine@demaat.info","","MeDisch2020@@",
"VVAA","2018-12-17 21:49:51","013265","","VvAa2017%$#",
"https://www.pil-nascholing.nl","2020-12-20 21:06:49","JaninePiL","","PIL2021Janinex!!",
"Groupon","2018-12-17 21:44:02","janine@demaat.info","","Groupon2017top67",
"Top Bloemen","2018-12-17 21:42:37","janine@demaat.info","","TipTop1967#$",
"Albert Heijn bestellen thuisbezorgen prive","2018-12-17 21:42:16","janine@demaat.info","","Appie2017Hallo!",
"Praxisdienst.nl","2018-12-17 21:40:06","janine@demaat.info","","Praxis2017Dienst#$",
"Frascati","2018-12-17 21:39:29","janine@demaat.info","","fRxVtz",
"Bijenkorf.nl","2018-12-17 21:36:43","janine@demaat.info","","BijBij2017Bij#$",
"https://medicijngebruik.nl/ verandwoord medicijngebruik","2018-12-17 21:35:40","janine@demaat.info","","FTO%&%2017!",
"https://branderwines.nl/wijnshop/customer/account/login/","2018-12-17 21:26:00","janine@demaat.info","","RRRSuU_K",
"Mijn Promedico","2018-12-17 21:25:20","janine@demaat.info","","yI8xtB_E",
"We Fashion","2018-12-17 21:22:09","janine@demaat.info","","WeFashion2018$%",
"actie van de dag","2018-12-17 21:20:25","janine@demaat.info","","AcTie2018Van$%",
"Geneeskundeboek.nl","2018-12-17 21:19:48","janine@demaat.info","","geneeskunde2017$%",
"administratie Ignace en janine","2018-12-17 21:18:12","janine","","Xanderj",
"https://www.daxtrio.nl/customer/account/login/ DAXTRIO","2021-05-02 20:43:22","janine@demaat.info","","DaX2021&#",
"NPO start","2018-12-17 21:13:09","janine@demaat.info","","StartNPOHallo123",
"Praktijkspiegel https://vektis.okta-emea.com/login/login.htm?fromURI=/","2023-06-14 19:18:40","01022281@vektis.nl","","Halh18@#18!xx!",
"GHO GO https://www.ghogo.nl/wp-login.php","2018-12-17 20:56:29","jdemaat","","3PWdU5Nt31Ts)pjgWA#FP)5s ",
"Soap Treatments","2019-07-03 15:56:53","janine@demaat.info","0624276531","HelloBotox!@",
"https://www.ah.nl/kies-moment/bezorgen albert heijn","2018-12-17 20:52:09","huisartsdemaat@ezorg.nl","","AHis2018TOP",
"Bel Centrale","2018-12-17 20:50:43","janine@demaat.info","","Bellen222!@",
"Bohn Stafleu en van Loghum","2018-12-17 20:50:04","janine@demaat.info","","bsl2018Yes!",
"https://www.myheritage.nl/","2018-12-17 20:48:52","janine@demaat.info","","AfKomst2018!@",
"Huisarts Vandaag","2018-12-17 20:46:07","demaat","","VanDaag2018@#7",
"Belastingdienst Janine de Maat","2018-12-16 15:29:47","NL0013176906","","HelpAangifteDoen2017$%",
"Belastingdienst Huisarts van Muiden","2018-12-16 15:28:58","NL0050922414","","Huisarts15A$ViJa",
"VIP live","2021-06-11 08:33:18","JdeMaat","","DeMaat1967#$7 pincode 64971",
"KPN https://account.kpn.com/#/","2022-03-03 20:49:05","janine@demaat.info","Puk 31777541","64646 KPN2020ha!@",
"Zilveren Kruis Verstappen","2021-12-21 12:22:04","400079996","","Burgemeester15a@#!",
"Zilveren Kruis de Maat","2022-12-23 10:59:17","400079997","","ZilvKruis2021#$#!",
"NHG.org","2018-12-16 15:13:50","janine@demaat.info","","2012HAweb@#",
"LinkedIn","2018-12-17 22:01:13","janine@demaat.info","","LinkeIn2017#$%5",
"Independer","2022-12-06 16:42:45","janine@demaat.info","","InDEPEND2018$%!",
"https://www.centraalbeheer.nl/Paginas/default.aspx Centraal beheer","2018-11-10 22:18:32","janine2018BeHEER","","CenTRAAL2018@#",
"Movir https://mijnmovir.nl/MyMovirTheme/NoPermission.aspx","2023-02-26 14:07:45","janine@demaat.info","","Mo2018Vir$%2!23",
"https://mijn.belastingdienst.nl/ppa/ belastingdienst janine zakelijk","2018-11-10 22:12:34","NL0013176906","","HelpAangifteDoen2017$%",
"https://www.etos.nl/ ETOS","2018-11-10 22:02:54","janine@demaat.info","","INetos2018!@",
"https://www.ghogo.nl/wp-login.php GHOGO","2018-11-10 21:58:46","jdemaat","","3PWdU5Nt31Ts)pjgWA#FP)5s ",
"www.doq.nl doq","2018-11-10 21:57:04","maatDOQ","","DOQ2017demaat67%!",
"Spotify","2018-11-10 21:56:05","janinespotify2013","","SpoTy2018$%",
"https://www.ah.nl/kies-moment/bezorgen/1398BE albert heijn","2018-11-10 21:52:31","huisartsdemaat@ezorg.nl","","AHis2018TOP",
"www.belcentrale.nl","2018-11-10 21:50:37","janine@demaat.info","","Bellen222!@",
"https://mijn.bsl.nl/nascholing","2018-11-10 21:50:02","janine@demaat.info","","bsl2018Yes!",
"My Heritage","2018-11-10 21:47:58","janine@demaat.info","","AfKomst2018!@",
"NVDA","2018-12-17 20:46:56","huisartsdemaat@ezorg.nl","","Huisartsvanmuiden2017!",
1 https://en.lespassionnesduvin.com/ 2023-07-23 15:05:32 janine@demaat.info HELLO2023&$
2 Www.kaartje2go.nl 2023-05-22 20:13:29 janine@demaat.info Kkart2211zs#
3 Ignace tel ontgrendelen 2023-04-30 19:17:14 janine@demaat.info 007662
4 www.almeerplant.nl 2023-04-17 20:00:44 janine@demaat.info kaart nummer 00089277 TISmeWHAT!@
5 www.spasereen.nl 2023-04-08 08:38:59 janine@demaat.info Massage Sport 25 min. Start
6 https://www.america-today.com 2023-03-28 15:38:35 janine@demaat.info 9yrtaqSXRUhx5Wm
7 komoot.nl 2023-03-08 07:55:02 janine@demaat.info K20k23@#&
8 Promedico.topdesk.net zelfservice portaal selfservice 2023-03-01 13:11:37 jdmaat Pro2020!
9 www.topgear.nl 2023-02-14 09:57:39 janine@demaat.info tttopGEAR#@
10 https://loket.loket.nl werkgevers loket 2023-02-02 14:52:33 janine@demaat.info Welkom01
11 https://gegevensportaal.belastingdienst.nl 2023-02-02 09:25:35 UBD002281 Muiden2023!!
12 www.eherkenning.nl Reconi 2023-01-26 17:23:34 janine@demaat.info Muiden2023#@!
13 www.eherkenning.nl 2023-01-26 16:57:57 janine@demaat.info Muiden2023#@!
14 https://waarneemapp.nl/companies/4708/schedules/openshifts 2023-01-26 15:46:15 janine@demaat.info HASamen2019
15 Loonheffing praktijk Belastingdienst Postbus 8738 4820 BA BREDA 2023-01-18 17:02:51 janine@demaat.info 857592683L02
16 Bureaublad waarnemer 2023-01-11 07:35:31 waarnemer Welkom2023
17 nationale nederlanden nn.nl --&amp;amp;gt; ZAKELIJK! 2023-01-09 16:27:05 ci4000025776 ci4000025776 NAT2023Burg15A
18 www.allesvoordesauna.nl 2023-01-08 22:25:54 janine@demaat.info SELdeVie202367
19 Www.mijngezondheidsmeter.nl 2023-01-03 06:20:53 janine@demaat.info PgOin2023@#!
20 https://www.milieubarometer.nl/csr/o/zhjws/i/88566/y1/n/0/ 2022-12-29 18:37:12 v_verstappen@hotmail.com Burgemeester15A
21 www.asr.nl 2022-12-20 21:26:06 janine@demaat.info 6497
22 www.debevlogenhuisarts.nl 2022-12-01 14:38:56 janine@demaat.info FlyFree2023#!
23 Https:/portaal.zorgvandezaak.nl/login 2022-11-25 11:13:42 Huisartsdemaat@ezorg.nl ZZZorg2023%!
24 www.gowah.nl 2022-11-20 21:45:22 janine@demaat.info LeD$&2022!
25 Www.123led.nl 2022-11-20 16:28:41 janine@demaat.info LeD$&2022!
26 www.uziregister.nl 2022-11-03 13:37:36 janine@demaat.info Intrek VwuS5neALLc8 Pin 283357 puk 231958
27 www.coolblue.com 2022-10-23 13:20:42 janine@demaat.info B2v-EPG-Cri-uu
28 www.FMS.nl 2022-10-09 09:54:32 janine@demaat.info FMSricht202144
29 Digitalis NHG rx 2022-10-04 21:35:30 v_verstappen@hotmail.com Burgemeester15a
30 www.1reaal.nl 2022-10-04 15:45:57 janine@demaat.info REa!@33X
31 MedGemak+ 2022-10-04 08:45:12 Janine 64971
32 ignaceontgrendelingtelefoon 2022-09-11 09:11:13 janine@demaat.info 070662
33 Inlog praktijk start scherm bureaublad desktop 2023-07-25 10:35:26 janine@demaat.info HUISarts67!@#$%!!!!
34 Dpg.nl 2022-07-12 16:52:54 janine@demaat.info DpppG2021#!
35 transferpunt-go.nl 2022-07-12 16:15:41 JdeMaat Muiden2022oke
36 www.arcusit.itclientportal.com 2022-07-08 12:27:28 Huisartsdemaat@ezorg.nl MuidenGez!!
37 Uber 2022-06-20 19:02:51 janine@demaat.info ZzGg56&#
38 https://mijnoproep.sanquin.nl/ 2022-06-15 16:07:04 janine@demaat.info SanQUIN2022&##
39 www.netflix.com 2022-06-03 18:06:00 ignace.suy@gmail.com querijnnf
40 GAIA https://www.pe-online.org/SPE001_PR_Inloggen.aspx?taalID=&amp;Calenda 2022-05-26 13:07:07 BIG-19042868401 GaIA2022$#
41 Moby parkeren 2022-05-08 08:48:19 janine@demaat.info MoBy2022$$
42 Www.Beowulf.nl 2022-05-01 18:40:38 janine@demaat.info BEoAlm2022!
43 Discord 2022-04-27 09:53:37 janinedemaat janine@demaat.info Pompen2022#
44 Inlog praktijk startscherm bureaublad 2022-11-25 07:01:05 janine@demaat.info HUISarts67!@#$%!!
45 ABN Amro Gold Creditcard 64971 2022-03-02 21:38:21 JDEMAAT1967 1381 creditin2015isnotBAD@
46 www.light in the box 2022-02-24 16:53:54 janine@demaat.info R9TC8cS
47 https://www.gowah.nl/default.htm 2022-02-22 15:13:00 janine@demaat.info GGowah3342&#
48 Medfeed 2022-02-20 15:50:29 janine@demaat.info ME21&&#@
49 https://www.neleman.org 2022-02-17 12:06:37 janine@demaat.info 87NEel&&&
50 www.gocards.nl 2022-02-03 08:24:40 Janinedm 44554xq!
51 Www.bezorgdehuisartsen.nl 2022-01-31 06:06:06 janine@demaat.info Bezorgdin2022!?&
52 Cees.bezorgdehuisartsen.nl 2022-01-31 06:05:40 janine@demaat.info Bezorgdin2022!?&
53 www.hkvi.nl 2022-01-28 15:00:34 Huisartsdemaat@ezorg.nl HuisartsvanMuiden2021!
54 IMDB 2022-01-01 20:05:41 janine@demaat.info IiMmDdBB2021!?
55 www.greetz.com 2021-12-10 17:22:32 janine@demaat.info GRRR2019&@ha
56 Administratiehuisartsvanmuiden@ezorg.nl 2021-12-02 14:53:33 janine@demaat.info LiesKa80
57 Www.vasco.nl 2021-11-28 11:36:50 janine@demaat.info RivmVasco2921## 64971
58 Inlog praktijk start scherm bureaublad 2022-07-26 12:58:56 janine@demaat.info HUISarts67!@#$%!
59 www.henryschein.nl 2021-10-26 08:10:21 janine@demaat.info HENry2021@@
60 www.denieuwebibliotheek.nl 2021-10-24 19:29:11 janinedemaat BiBlio2121!
61 www.wehkamp.nl 2021-10-17 07:09:50 janine@demaat.info WEH2021k!!
62 Www.doecksen.nl 2021-10-13 21:04:21 janine@demaat.info 2021Doecksen&&
63 Www.skge.nl 2021-10-13 16:25:10 janine@demaat.info VanKlacht2021$#
64 Spar.nl 2021-10-10 17:58:07 janine@demaat.info SpAr67$#!
65 Hopin.com 2021-10-05 16:44:07 janine@demaat.info HOPhop2021%$
66 Microsoft Teams.nl 2021-10-03 11:34:47 janine@demaat.info Xander@2
67 Kinepolis.nl bioscoop 2021-10-03 07:36:50 janine@demaat.info AlmKin67$$
68 Stocard.com 2021-09-30 11:15:26 janine@demaat.info 1112
69 DHL.nl app 2021-09-26 21:19:04 janine@demaat.info @3daH-55
70 Pharmeon beheer pagina 2022-07-12 13:26:55 assistenteverstappen@ezorg.nl Muiden2022!
71 persgroep.beleefklassiek.nl 2021-09-18 08:24:54 Janine.Maat.978 7fb5a18ca6
72 https://www.familienet.nl/client/katja-suy-linders/ 2021-09-12 10:54:13 janine@demaat.info KatjaMOERG2020!
73 Bureaublad praktijk waarnemer en assistentes 2021-09-10 13:59:14 Waarnemer Muiden2021!
74 Www.picknick.nl 2021-08-26 14:31:01 janine@demaat.info vooruitmetdegeit2021!
75 Promedico dongel wrnarts 2021-07-30 06:17:52 wrnarts 4444
76 Www.paul&pitalarm.nl 2021-07-22 07:59:35 janine@demaat.info Janine 102127
77 www.raamdecoratie.com 2021-07-04 17:38:04 janine@demaat.info r2021aam@&
78 https://www.supersaas.nl/schedule/login/hartforherAlmere/hart_for_her_ 2021-06-21 18:44:57 janine@demaat.info sport2021!!
79 Vecozo persoonlijk certificaat 30000000252756 2023-06-21 10:26:24 JdeMaat 2023Muiden!
80 www.ssfh.nl stichting sociaal fonds huisartsenzorg 2021-05-18 15:20:36 janine@demaat.info SSfh2020!9
81 https://open.viadesk.com/do/portal 2021-05-11 17:26:35 janine@demaat.info OPEN2020Janine$#
82 www.natuurhuisje.nl 2021-05-11 05:03:54 janine@demaat.info NAtuurr2021!
83 Promedico.topdesk.net zelfservice portaal 2021-05-02 18:03:37 jdmaat Pro2020!
84 www.tuinland.nl 2021-04-24 12:05:21 janine@demaat.info T@uinland!2
85 https://www.teunstuinposters.nl/ 2021-03-28 10:10:53 janine@demaat.info 857058d8
86 Owncloud https://www.suy.nu/cloud 2021-03-26 20:27:19 janine 6767 pincode, xanderj2
87 sparkmail inlog mijndomijn janine@demaat.info 2021-05-03 20:03:00 janine@demaat.info Xander^66Suy
88 mail inlog mijndomijn janine@demaat.info 2021-05-03 20:03:38 janine@demaat.info Xander^66Suy
89 Www.fagron.nl 2021-03-15 14:45:28 janine@demaat.info FGRN2021#@
90 financieelhuisartsvanmuiden@ezorg.nl webmail 2021-03-14 16:09:59 financieelhuisartsvanmuiden@ezorg.nl kr39S5q0lonc
91 huisartsvanmuiden@ezorg.nl webmail 2021-03-14 16:08:45 huisartsvanmuiden@ezorg.nl Ywlz9SWyuOLF
92 https://online.loket.nl/vso.prd.loket werkgevers loket 2021-03-11 15:21:10 janine@demaat.info Welkom01
93 Medi-access 2021-02-28 17:08:18 janine@demaat.info MeDI2021!Acc!$
94 intershift 2023-02-12 11:22:35 janine@demaat.info XanderJ2!
95 ABN Amro Gold Creditcard 2021-02-18 10:12:13 JDEMAAT1967 1381 creditin2015isnotBAD@
96 ABN NL65ABNA0247117560 pas 221 2021-02-14 21:26:34 janine@demaat.info pin 6783
97 ABN NL53ABNA0247355232 pas 441 2021-02-14 21:18:26 janine@demaat.info 2921
98 Geneeskunde boek.nl 2021-02-07 13:30:10 janine@demaat.info BSl2021xj!
99 Zorgdomein.nl 2023-06-08 19:39:55 Huisartsdemaat@ezorg.nl ZOrg2021!!!
100 Gast guest login 2021-02-01 21:49:20 Legio scipio althome_2019*FF
101 Login.WeSeeDo.nl 2021-02-01 08:20:15 Huisartsdemaat@ezorg.nl We2020SEE!
102 www.speld.nl 2021-01-28 15:42:03 janine@demaat.info Sspeld2021!!
103 Gold card 2021-01-25 18:42:58 janine@demaat.info 5341260091362308 425 2021secabn (3d security code)
104 Signal 2021-01-17 10:23:14 janine@demaat.info 6767
105 Amazon 2021-01-14 23:06:47 janine@demaat.info AMAzing2121&!
106 Amazon prime 2021-01-14 22:12:51 Ignace.suy@gmail.com querijnAP
107 https://landelijkeleeromgeving.nspoh.nl/local/nspoh_register/signup.ph 2021-01-14 15:52:22 janine@demaat.info CoViD2019@#
108 Stumpel 2021-01-14 10:37:33 janine@demaat.info ST2021u$$
109 beheer.pharmeon.nl/Inloggen/app/ 2021-01-14 09:00:05 v_verstappen@hotmail.com Burgemeester15a!
110 www.staatsloterijl.nl 2021-01-10 18:17:04 janine@demaat.info ST@aat!@2!35
111 Leeg worddocument 2021-01-07 10:15:58 janine@demaat.info Op de Fschijf Hierinstaanallewachtwoorden
112 Huisarts.mediq.nl/inloggen Mediq voorschrijfportaal hulpmiddelen 2020-12-21 07:39:17 MEDIQpatientdeMaat Mediq20211398
113 Mediq voorschrijfportaal hulpmiddelen 2020-12-18 10:10:24 Huisartsdemaat@ezorg.nl MEDIQpatientdeMaat
114 sum-up app 2020-11-13 11:59:42 v_verstappen@hotmail.com Burgemeester1398BE!
115 https://www.dokterandrebeautyworld.nl/ 2020-11-09 22:14:11 janine@demaat.info ##!2020jm!
116 Lanteltelefooninlogstoring 2020-11-02 11:36:49 janine@demaat.info toestel 16 16 3316572479
117 LHV panel 2020-10-30 19:05:34 janine@demaat.info LHv2222#@
118 Mcc gooi en Vechtstreek 2020-10-29 15:36:30 janine@demaat.info McC2019xj
119 Flitsmeister 2020-10-17 10:53:17 janine@demaat.info Flitzz!
120 Weesper nieuws 2020-10-16 20:29:56 janine@demaat.info WEEsper2020&#
121 Weesper nieuwa 2020-10-16 20:29:32 janine@demaat.info WEEsper2020&#
122 Natuurmonumenten 2020-10-15 13:37:03 janine@demaat.info 3996486 lidnummer
123 https://www.bambooimport.com 2020-10-01 20:22:00 janine@demaat.info Bbambooo2020!
124 onlinebibliotheek.nl 2020-09-03 13:54:23 20060004773818 BIEB2020@!67e
125 Mijn.euronature.nl 2020-09-03 08:34:35 janine@demaat.info rGPqNciD
126 DASHBOARD open 2020-08-22 11:54:04 janine@demaat.info DASH2020@#
127 Van Haren 2020-08-22 10:54:27 janine@demaat.info V5e11wONm
128 Zoom janine@demaat.info 2020-08-21 12:55:46 janine@demaat.info ZooM@#2020!
129 decathlon 2020-08-09 09:19:57 janine@demaat.info DE2020LL!
130 Faxhuisartsvanmuiden@ezorg.nl 2020-08-05 10:38:10 Faxhuisartsvanmuiden@ezorg.nl Welkom2020!
131 Promedico.topdesk.net 2020-07-28 11:32:25 jdmaat Pro2020!
132 www.voedingscentrum.nl 2020-07-19 15:40:23 janine@demaat.info Voe2020DD@
133 EZORG webmail inloggen assistenteverstappen@ezorg.nl 2020-07-14 06:17:29 assistenteverstappen@ezorg.nl Muiden2020
134 Bergman clinics app 2020-07-13 14:00:55 janine@demaat.info 676764
135 https://mijnhypotheek.lloydsbank.nl/hypotheek 2020-07-09 12:33:55 janine@demaat.info LLOY2019%#!
136 Flevo-landschap.nl 2020-06-30 21:00:59 janine@demaat.info Flevo2020!@
137 Rhogo.qarebase.nl/account/login 2020-06-30 17:50:46 janine@demaat.info Mcix+Q69
138 Zilveren kruis app persoonlijk 2020-06-28 11:42:37 janine@demaat.info 64971
139 Https://Promedico.topdesk.net 2020-06-19 14:58:02 jdmaat Muiden2020
140 Richtlijnendatabase.nl 2020-06-19 13:34:12 Huisartsdemaat@ezorg.nl MedSpeFed2020
141 EZORG webmail inloggen 2020-05-13 10:21:33 assistentedemaat@ezorg.nl Muiden2020
142 Mediq.nl 2020-05-04 05:47:30 Huisartsdemaat@ezorg.nl MedBis2020!
143 NPA Vincent 2021-08-03 08:33:23 v_verstappen@hotmail.com npaweb1398BE
144 www.avaya.com workplace 2020-04-30 13:25:13 Toestel 16 Muiden1398
145 www.avaya.com 2020-04-30 13:21:50 Toestel 16 Muiden1398
146 NPAweb.nl 2022-06-13 13:33:10 janine@demaat.info NPA2020Muiden1!!!
147 Groene Amsterdammer 2020-04-24 14:55:39 janine@demaat.info Groen22!
148 Open 2020-04-23 16:36:21 janine@demaat.info OPEN2020Janine$#
149 ISSUU 2020-04-13 17:02:19 janine@demaat.info ISSUU2020#@1
150 nationale nederlanden nn.nl --&amp;gt; ZAKELIJK! 2020-04-12 11:17:15 ci4000025776 v_verstappen@gmail.com Burgemeester1398B&
151 Https://covid19.u-diagnostics.com 2020-04-07 14:45:35 Huisartsdemaat@ezorg.nl GoFit2020#$2
152 WeSeeDo 2020-03-30 10:17:36 Huisartsdemaat@ezorg.nl We2020SEE!
153 Videoconsult.clickdoc.nl CGM videobellen 2020-03-27 09:39:39 jdemaat jdemaat CGMvideo2020$$
154 Zoom 2020-03-25 14:30:20 Huisartsdemaat@ezorg.nl ZZZoom2020!
155 Webmail.mijndomein.nl 2020-05-15 10:35:09 janine@demaat.info xanderJ2
156 CGM videobellen 2020-03-23 14:50:03 jdemaat CGMvideo2020$$
157 Siilo 2021-03-25 14:58:30 janine@demaat.info janine@demaat.info 64971
158 Wish 2020-03-22 10:28:33 janine@demaat.info janine@demaat.info WiSH2121#@
159 Medischescholing.nl 2020-05-12 18:19:45 janine@demaat.info janine@demaat.info MediCovid2020!
160 MedGemak 2020-03-03 09:12:38 Janine 64971
161 Zorgmail POH GGZ 2020-02-27 11:53:47 500110871 pjj4s-zb3s9-yzntx-62kvu-f2x7d
162 Zorgmail Huisarts van Muiden 2020-02-27 11:52:52 500107607 5wgza-ajpxv-h5j7j-2wpjm-28wny
163 Zorgmail Verstappen 2020-02-27 11:51:52 500107252 yup5s-sn62n-vmsvr-7wp68-j4ru7
164 Zorgmail de Maat 2020-05-22 10:18:39 xa3bm-x6uak-zsmw4-6fsra-jbdh8 500013469 ZorgMaildemaat2020!
165 De nieuwe bibliotheek 2020-02-20 19:42:42 JdeMaat BiebAlmere2020!
166 Bureaublad praktijk waarnemer 2021-01-27 06:54:56 Waarnemer Welkom2021
167 Waarneemapp 2019-12-28 11:29:57 janine@demaat.info janine@demaat.info HASamen2019
168 www.nvve.nl 2019-12-21 15:26:45 janine@demaat.info janine@demaat.info MaatNVVE2019
169 SNGP Griep 2021-10-11 12:21:09 0108030-01 janine@demaat.info MUIDEN1398BE!!
170 Computer praktijk Vincent 2020-02-26 13:45:33 Vincent Vincent Muiden2017!
171 GhoGo.nl 2019-11-13 22:37:35 janine@demaat.info janine@demaat.info GhoGo2019#$2
172 PIM inloggen telefonie huisartsenpost 2019-11-10 09:05:22 janine@demaat.info primair-bla-spreekkamer5 ( of een ander nummer) Pr1m@1r!
173 MX-5 Owners 2019-11-03 10:16:44 janine@demaat.info janine@demaat.info Owners445
174 MX-5 Iwners 2019-11-03 10:15:53 janine@demaat.info janine@demaat.info Owners445
175 Omzetbelasting nummer (ob-nummer) 2019-10-31 15:41:01 janine@demaat.info janine@demaat.info 101394585B01
176 BTW identificatienummer 2019-10-31 15:39:55 janine@demaat.info janine@demaat.info NL001387127B24
177 paspoort Janine de Maat 17 05 1967 2019-10-24 19:03:50 Janine paspoort tot 16 11 2027 janine@demaat.info NM87JHH81
178 paspoort Ignace Marie Lucien Suy 12 11 1964 2019-10-24 19:02:34 janine@demaat.info Ignace paspoort tot 17 10 2026 NT9DKR0C1
179 Eetmeter 2019-10-17 15:41:41 janine@demaat.info janine@demaat.info Eet!Eet
180 Body FX figure8 2019-09-26 16:40:09 janine@demaat.info 2019janinenew
181 Inlog praktijk start scherm 2021-07-14 05:54:56 janine@demaat.info HUISarts67!@#
182 Lantel cloud 2020-11-10 06:53:35 Huisartsdemaat@ezorg.nl Huisartsdemaat@ezorg.nl LanTel2019@@##
183 Lantel cliud 2019-08-14 15:26:51 Huisartsdemaat@ezorg.nl Huisartsdemaat@ezorg.nl LanTel2019@#3EZORG
184 Zelfstroom zonnepanelen 2019-08-02 16:08:01 janine@demaat.info Zelf2019&&
185 nationale nederlanden nn.nl --&gt; ZAKELIJK! 2019-11-28 12:07:53 ci4000025776 huisartsverstappen@ezorg.nl NAT2019Burg15A
186 Bayer medischwijzer.nl 2019-07-08 08:08:48 janine@demaat.info BaYer2019$$
187 Google 2020-03-22 13:46:51 janine.de.maat@gmail.com Xanderj2!
188 Vecozo 2023-06-02 12:27:06 Systeemcertificaat MUIDEN2021!@ 40000000127056pin MUIDEN2023!!
189 IC Taurus zelfservice portaal 2019-06-03 07:24:52 Huisartsverstappen@ezorg.nl W3Lkom@19!!
190 Vakantie piraten 2019-05-30 17:47:29 janine@demaat.info janinepir Vak2019Piraten#
191 Pharmeon 2021-09-07 06:40:54 assistenteverstappen@ezorg.nl 2DEjTsFsDtw1
192 Makro 2019-05-28 15:04:16 janine@demaat.info Makro&&2019
193 de la mar 2019-05-25 11:54:42 janine@demaat.info altijdLEUK2019!
194 CBOARDS caresharing 2019-05-27 10:48:47 Huisartsdemaat@ezorg.nl Huisartsdemaat@ezorg.nl CBOARDS janine 2019 pin 64971
195 Instituut verantwoord medicijn gebruik IVM 2019-05-16 14:54:02 janine@demaat.info IvM2019IvM!
196 Digitalis 2019-05-08 14:05:42 v_verstappen@hotmail.com Burgemeester15a
197 Parool 2020-10-29 20:58:54 janine@demaat.info Parool1112@@
198 Mijn lcr inloggen 2019-04-29 21:54:01 VERSTAPPENV01 Burgemeester15a
199 Marktplaats.nl 2019-04-28 14:04:39 janine@demaat.info MaRkTplaats2019$$#
200 Hopir 2019-04-25 08:25:58 janine@demaat.info Noorder2019
201 Secundum WIFI guests 2019-04-19 17:14:09 Secundum Secundum HH*20190405gg
202 Woonveilig app 2020-12-04 12:32:41 janinedemaat G7^Fddsr43#3 of pincode 6497
203 EHerkenning Cream Reconi de Maat 2019-04-05 14:35:36 janine@demaat.info 64971
204 https://login.ns.nl/login NS 2021-05-24 13:21:27 janine@demaat.info NS2019ns@#!
205 Hudson Bay 2019-04-04 17:49:20 janine@demaat.info Hud2020Son@#$!
206 primus internet 2019-04-04 09:19:52 althome_2019*FF althome_2019*FF
207 Notaris unie 2 2019-03-25 19:28:01 janine@demaat.info XanderV20
208 Notaris unie 2019-03-25 19:19:31 Ignace.suy@gmail.com querijnv20
209 ParkMobile 2019-03-10 13:29:11 janine@demaat.info piaivtd
210 ASN bank 2020-12-02 19:22:25 janineasnbank 64971 asn!janine67DEMAAT
211 Overheid berichtenbox app 2019-02-14 18:48:23 Janine Janine 64972
212 Dongel janine werk 2019-02-14 16:16:25 jdmaat 1112
213 Dongel Janine thuus 2019-02-14 16:15:36 JdeMaat2 2228
214 Dongel van co 2019-02-14 16:14:58 comuiden 3333
215 Post.nl 2019-02-07 17:48:39 janine@demaat.info PosT2019@#6
216 Social deal 2019-02-07 10:14:33 janine@demaat.info SoCial2020$#$
217 FTO Online 2019-02-06 21:19:26 janine@demaat.info FtO2019#$6
218 Wachtwoorden praktijk c schijf facilitair wat wij belangrijk vinden 2019-02-06 15:33:13 Praktijk login c schijf Is er niet
219 Plex 2019-02-03 21:44:47 janine.de.maat@gmail.com Querijnp7
220 cloud https://www.suy.nu/cloud 2020-04-28 21:21:10 janine@demaat.info 6767 pincode xanderj2
221 Werkgevers Loket 2020-03-09 13:28:12 janine@demaat.info Welkom01
222 DIGID 2020-05-01 14:10:28 JanineDigid Eninaj!2 67941
223 EZORG inloggen webmail: webmail.ezorg.nl 2019-01-03 12:58:56 huisartsdemaat@ezorg.nl EZORG2017$%
224 nationale nederlanden nn.nl --> ZAKELIJK! 2019-01-03 12:48:28 CI4000025776 NN2017HuisartsvanMuiden
225 Twiiter 2018-12-31 18:29:55 janine@demaat.info twetenisfun2018&
226 DIGIPAS Promedico 1112 2018-12-24 11:05:31 jdmaat 1112
227 DIGIPAS Dongel Promedico 2228 2018-12-24 11:05:02 JdeMaat2 2228
228 Primair Huisartsenpost 2020-08-23 10:38:30 janine@demaat.info jdemaat xanderjprimair
229 HAWEB 2022-12-14 06:05:30 janine@demaat.info HaWeb#2023&!
230 123INKT 2018-12-24 10:59:39 janine@demaat.info janine2012#123inkt
231 Nespresso 2018-12-24 10:52:06 janine@demaat.info nespresso12#
232 Herensokken.nl 2018-12-24 10:50:22 janine@demaat.info herensokken2013HAHA
233 GAIA https://www.pe-online.org/SPE001_PR_Inloggen.aspx?taalID=&Calenda 2018-12-24 10:47:57 BIG-19042868401 weet ik niet
234 Wordfeut 2018-12-24 10:44:01 janinewordfeud67 hallo67
235 Dropbox 2018-12-24 10:42:51 janine@demaat.info janinedropbox2014#$
236 NTVG inloggen 2018-12-24 10:34:45 jdemaat Ntvg2013demaat
237 FACEBOOK Facebook 2018-12-24 10:31:28 janine@demaat.info faceb2015@!@
238 ABN Amro Creditcard 2021-02-18 10:11:48 JDEMAAT1967 1381 creditin2015isnotBAD@
239 Linda TV 2018-12-24 10:21:06 janine@demaat.info HalloLindaTV2015
240 Toplenzen 2018-12-24 10:20:34 janine@demaat.info TopLenzen2015@#
241 Museumkaart 2018-12-24 10:19:57 janine@demaat.info Museum2016$%
242 WDHMN 2018-12-24 10:19:28 jdemaat WDHMN2016$%
243 Nextdoor 2019-11-14 17:22:23 janine@demaat.info NextDoor201954@
244 Muidernieuws online lezen 2022-07-06 21:27:18 janine@demaat.info WEEsper2020&#
245 Managemenstboek 2018-12-24 10:17:54 janine@demaat.info manage2016@#
246 Volkskrant 2022-11-03 13:44:56 janine@demaat.info Nrcleuk!!!@
247 Airmiles 2020-03-12 13:07:49 JDEMAAT airmiles2016HIEPHOI!
248 Ticketveiling https://www.ticketveiling.nl 2022-03-25 19:15:17 jantje345 ticket2022!)
249 Bonprix 2020-10-15 19:37:23 janine@demaat.info Bbonie21!
250 Vakantie Veiling 2018-12-24 10:14:12 janine@demaat.info vak2016veling@#
251 Pinterest 2018-12-24 10:13:17 jappie pint@@@2016ABC
252 Media Markt 2018-12-24 10:12:49 janine@demaat.info ongelovelijk2017#$%
253 Wijgergangs Medical www.wijgergangsmedical.nl 2018-12-24 10:12:07 janine@demaat.info Medische2016$%
254 Love For Rain https://www.loveforrain.nl/ 2018-12-24 10:10:51 janine@demaat.info love2017welkom12
255 KRUIDVAT 2018-12-24 10:09:51 janine@demaat.info kruidvat2016#$%
256 Deen 2018-12-24 10:09:11 janine@demaat.info Deen2016$%6
257 gall gall 2018-12-24 10:08:23 janine@demaat.info GALL2016gall@#
258 Iens Seatme 2018-12-24 10:06:57 janine@demaat.info SeatMe2017$%!
259 Tui Mijntui www.tui.nl/mijntui 2019-10-24 18:42:48 janine@demaat.info janine@demaat.info TuiBonaire2019!!
260 Gmail inloggen 2018-12-24 10:04:26 janine.de.maat@gmail.com xanderj2
261 ANWB 2022-12-06 15:02:56 JaninedeMaatANWB janine@demaat.info ANWB2017#$
262 Appie Albert Heijn 2018-12-24 10:01:01 janine@demaat.info Appie2017Hallo!
263 FTO https://medicijngebruik.nl/ 2018-12-24 09:59:15 janine@demaat.info FTO%&%2017!
264 Bol Com 2021-03-18 20:44:09 janine@demaat.info BolCC202123
265 Joviene Lourens Massage 2018-12-17 21:59:48 Janine67 Loure2017@#$
266 Concertgebouw 2018-12-17 21:57:38 janine@demaat.info 2017ConcertGeb$%
267 Hema.nl 2019-08-25 10:51:14 janine@demaat.info HemaTheBest2019!
268 koopjedeal 2018-12-17 21:55:23 janine@demaat.info koop2017je%^deal
269 Health Investment https://www.lpx.nl/healthinvestment/login 2018-12-17 21:54:12 janine@demaat.info HealthInvest2017^%
270 Medisch contact 2020-10-25 14:41:46 janine@demaat.info MeDisch2020@@
271 VVAA 2018-12-17 21:49:51 013265 VvAa2017%$#
272 https://www.pil-nascholing.nl 2020-12-20 21:06:49 JaninePiL PIL2021Janinex!!
273 Groupon 2018-12-17 21:44:02 janine@demaat.info Groupon2017top67
274 Top Bloemen 2018-12-17 21:42:37 janine@demaat.info TipTop1967#$
275 Albert Heijn bestellen thuisbezorgen prive 2018-12-17 21:42:16 janine@demaat.info Appie2017Hallo!
276 Praxisdienst.nl 2018-12-17 21:40:06 janine@demaat.info Praxis2017Dienst#$
277 Frascati 2018-12-17 21:39:29 janine@demaat.info fRxVtz
278 Bijenkorf.nl 2018-12-17 21:36:43 janine@demaat.info BijBij2017Bij#$
279 https://medicijngebruik.nl/ verandwoord medicijngebruik 2018-12-17 21:35:40 janine@demaat.info FTO%&%2017!
280 https://branderwines.nl/wijnshop/customer/account/login/ 2018-12-17 21:26:00 janine@demaat.info RRRSuU_K
281 Mijn Promedico 2018-12-17 21:25:20 janine@demaat.info yI8xtB_E
282 We Fashion 2018-12-17 21:22:09 janine@demaat.info WeFashion2018$%
283 actie van de dag 2018-12-17 21:20:25 janine@demaat.info AcTie2018Van$%
284 Geneeskundeboek.nl 2018-12-17 21:19:48 janine@demaat.info geneeskunde2017$%
285 administratie Ignace en janine 2018-12-17 21:18:12 janine Xanderj
286 https://www.daxtrio.nl/customer/account/login/ DAXTRIO 2021-05-02 20:43:22 janine@demaat.info DaX2021&#
287 NPO start 2018-12-17 21:13:09 janine@demaat.info StartNPOHallo123
288 Praktijkspiegel https://vektis.okta-emea.com/login/login.htm?fromURI=/ 2023-06-14 19:18:40 01022281@vektis.nl Halh18@#18!xx!
289 GHO GO https://www.ghogo.nl/wp-login.php 2018-12-17 20:56:29 jdemaat 3PWdU5Nt31Ts)pjgWA#FP)5s
290 Soap Treatments 2019-07-03 15:56:53 janine@demaat.info 0624276531 HelloBotox!@
291 https://www.ah.nl/kies-moment/bezorgen albert heijn 2018-12-17 20:52:09 huisartsdemaat@ezorg.nl AHis2018TOP
292 Bel Centrale 2018-12-17 20:50:43 janine@demaat.info Bellen222!@
293 Bohn Stafleu en van Loghum 2018-12-17 20:50:04 janine@demaat.info bsl2018Yes!
294 https://www.myheritage.nl/ 2018-12-17 20:48:52 janine@demaat.info AfKomst2018!@
295 Huisarts Vandaag 2018-12-17 20:46:07 demaat VanDaag2018@#7
296 Belastingdienst Janine de Maat 2018-12-16 15:29:47 NL0013176906 HelpAangifteDoen2017$%
297 Belastingdienst Huisarts van Muiden 2018-12-16 15:28:58 NL0050922414 Huisarts15A$ViJa
298 VIP live 2021-06-11 08:33:18 JdeMaat DeMaat1967#$7 pincode 64971
299 KPN https://account.kpn.com/#/ 2022-03-03 20:49:05 janine@demaat.info Puk 31777541 64646 KPN2020ha!@
300 Zilveren Kruis Verstappen 2021-12-21 12:22:04 400079996 Burgemeester15a@#!
301 Zilveren Kruis de Maat 2022-12-23 10:59:17 400079997 ZilvKruis2021#$#!
302 NHG.org 2018-12-16 15:13:50 janine@demaat.info 2012HAweb@#
303 LinkedIn 2018-12-17 22:01:13 janine@demaat.info LinkeIn2017#$%5
304 Independer 2022-12-06 16:42:45 janine@demaat.info InDEPEND2018$%!
305 https://www.centraalbeheer.nl/Paginas/default.aspx Centraal beheer 2018-11-10 22:18:32 janine2018BeHEER CenTRAAL2018@#
306 Movir https://mijnmovir.nl/MyMovirTheme/NoPermission.aspx 2023-02-26 14:07:45 janine@demaat.info Mo2018Vir$%2!23
307 https://mijn.belastingdienst.nl/ppa/ belastingdienst janine zakelijk 2018-11-10 22:12:34 NL0013176906 HelpAangifteDoen2017$%
308 https://www.etos.nl/ ETOS 2018-11-10 22:02:54 janine@demaat.info INetos2018!@
309 https://www.ghogo.nl/wp-login.php GHOGO 2018-11-10 21:58:46 jdemaat 3PWdU5Nt31Ts)pjgWA#FP)5s
310 www.doq.nl doq 2018-11-10 21:57:04 maatDOQ DOQ2017demaat67%!
311 Spotify 2018-11-10 21:56:05 janinespotify2013 SpoTy2018$%
312 https://www.ah.nl/kies-moment/bezorgen/1398BE albert heijn 2018-11-10 21:52:31 huisartsdemaat@ezorg.nl AHis2018TOP
313 www.belcentrale.nl 2018-11-10 21:50:37 janine@demaat.info Bellen222!@
314 https://mijn.bsl.nl/nascholing 2018-11-10 21:50:02 janine@demaat.info bsl2018Yes!
315 My Heritage 2018-11-10 21:47:58 janine@demaat.info AfKomst2018!@
316 NVDA 2018-12-17 20:46:56 huisartsdemaat@ezorg.nl Huisartsvanmuiden2017!
+2
View File
@@ -0,0 +1,2 @@
-r requirements.txt
pytest>=8.0,<10
+6
View File
@@ -0,0 +1,6 @@
Flask>=3.1,<4
fernet>=1.0,<2
gunicorn>=23.0,<24
PyMySQL>=1.1,<3
PyYAML>=6.0,<7
+6
View File
@@ -0,0 +1,6 @@
# Copy this file to secrets.yaml and replace both values.
flask:
secret_key: "replace-with-a-long-random-value"
database:
admin_password: "replace-with-the-flower-database-user-password"
BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 227 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 KiB

-682
View File
@@ -1,682 +0,0 @@
/***
MochiKit.Async 1.4.2
See <http://mochikit.com/> for documentation, downloads, license, etc.
(c) 2005 Bob Ippolito. All rights Reserved.
***/
MochiKit.Base._deps('Async', ['Base']);
MochiKit.Async.NAME = "MochiKit.Async";
MochiKit.Async.VERSION = "1.4.2";
MochiKit.Async.__repr__ = function () {
return "[" + this.NAME + " " + this.VERSION + "]";
};
MochiKit.Async.toString = function () {
return this.__repr__();
};
/** @id MochiKit.Async.Deferred */
MochiKit.Async.Deferred = function (/* optional */ canceller) {
this.chain = [];
this.id = this._nextId();
this.fired = -1;
this.paused = 0;
this.results = [null, null];
this.canceller = canceller;
this.silentlyCancelled = false;
this.chained = false;
};
MochiKit.Async.Deferred.prototype = {
/** @id MochiKit.Async.Deferred.prototype.repr */
repr: function () {
var state;
if (this.fired == -1) {
state = 'unfired';
} else if (this.fired === 0) {
state = 'success';
} else {
state = 'error';
}
return 'Deferred(' + this.id + ', ' + state + ')';
},
toString: MochiKit.Base.forwardCall("repr"),
_nextId: MochiKit.Base.counter(),
/** @id MochiKit.Async.Deferred.prototype.cancel */
cancel: function () {
var self = MochiKit.Async;
if (this.fired == -1) {
if (this.canceller) {
this.canceller(this);
} else {
this.silentlyCancelled = true;
}
if (this.fired == -1) {
this.errback(new self.CancelledError(this));
}
} else if ((this.fired === 0) && (this.results[0] instanceof self.Deferred)) {
this.results[0].cancel();
}
},
_resback: function (res) {
/***
The primitive that means either callback or errback
***/
this.fired = ((res instanceof Error) ? 1 : 0);
this.results[this.fired] = res;
this._fire();
},
_check: function () {
if (this.fired != -1) {
if (!this.silentlyCancelled) {
throw new MochiKit.Async.AlreadyCalledError(this);
}
this.silentlyCancelled = false;
return;
}
},
/** @id MochiKit.Async.Deferred.prototype.callback */
callback: function (res) {
this._check();
if (res instanceof MochiKit.Async.Deferred) {
throw new Error("Deferred instances can only be chained if they are the result of a callback");
}
this._resback(res);
},
/** @id MochiKit.Async.Deferred.prototype.errback */
errback: function (res) {
this._check();
var self = MochiKit.Async;
if (res instanceof self.Deferred) {
throw new Error("Deferred instances can only be chained if they are the result of a callback");
}
if (!(res instanceof Error)) {
res = new self.GenericError(res);
}
this._resback(res);
},
/** @id MochiKit.Async.Deferred.prototype.addBoth */
addBoth: function (fn) {
if (arguments.length > 1) {
fn = MochiKit.Base.partial.apply(null, arguments);
}
return this.addCallbacks(fn, fn);
},
/** @id MochiKit.Async.Deferred.prototype.addCallback */
addCallback: function (fn) {
if (arguments.length > 1) {
fn = MochiKit.Base.partial.apply(null, arguments);
}
return this.addCallbacks(fn, null);
},
/** @id MochiKit.Async.Deferred.prototype.addErrback */
addErrback: function (fn) {
if (arguments.length > 1) {
fn = MochiKit.Base.partial.apply(null, arguments);
}
return this.addCallbacks(null, fn);
},
/** @id MochiKit.Async.Deferred.prototype.addCallbacks */
addCallbacks: function (cb, eb) {
if (this.chained) {
throw new Error("Chained Deferreds can not be re-used");
}
this.chain.push([cb, eb]);
if (this.fired >= 0) {
this._fire();
}
return this;
},
_fire: function () {
/***
Used internally to exhaust the callback sequence when a result
is available.
***/
var chain = this.chain;
var fired = this.fired;
var res = this.results[fired];
var self = this;
var cb = null;
while (chain.length > 0 && this.paused === 0) {
// Array
var pair = chain.shift();
var f = pair[fired];
if (f === null) {
continue;
}
try {
res = f(res);
fired = ((res instanceof Error) ? 1 : 0);
if (res instanceof MochiKit.Async.Deferred) {
cb = function (res) {
self._resback(res);
self.paused--;
if ((self.paused === 0) && (self.fired >= 0)) {
self._fire();
}
};
this.paused++;
}
} catch (err) {
fired = 1;
if (!(err instanceof Error)) {
err = new MochiKit.Async.GenericError(err);
}
res = err;
}
}
this.fired = fired;
this.results[fired] = res;
if (cb && this.paused) {
// this is for "tail recursion" in case the dependent deferred
// is already fired
res.addBoth(cb);
res.chained = true;
}
}
};
MochiKit.Base.update(MochiKit.Async, {
/** @id MochiKit.Async.evalJSONRequest */
evalJSONRequest: function (req) {
return MochiKit.Base.evalJSON(req.responseText);
},
/** @id MochiKit.Async.succeed */
succeed: function (/* optional */result) {
var d = new MochiKit.Async.Deferred();
d.callback.apply(d, arguments);
return d;
},
/** @id MochiKit.Async.fail */
fail: function (/* optional */result) {
var d = new MochiKit.Async.Deferred();
d.errback.apply(d, arguments);
return d;
},
/** @id MochiKit.Async.getXMLHttpRequest */
getXMLHttpRequest: function () {
var self = arguments.callee;
if (!self.XMLHttpRequest) {
var tryThese = [
function () { return new XMLHttpRequest(); },
function () { return new ActiveXObject('Msxml2.XMLHTTP'); },
function () { return new ActiveXObject('Microsoft.XMLHTTP'); },
function () { return new ActiveXObject('Msxml2.XMLHTTP.4.0'); },
function () {
throw new MochiKit.Async.BrowserComplianceError("Browser does not support XMLHttpRequest");
}
];
for (var i = 0; i < tryThese.length; i++) {
var func = tryThese[i];
try {
self.XMLHttpRequest = func;
return func();
} catch (e) {
// pass
}
}
}
return self.XMLHttpRequest();
},
_xhr_onreadystatechange: function (d) {
// MochiKit.Logging.logDebug('this.readyState', this.readyState);
var m = MochiKit.Base;
if (this.readyState == 4) {
// IE SUCKS
try {
this.onreadystatechange = null;
} catch (e) {
try {
this.onreadystatechange = m.noop;
} catch (e) {
}
}
var status = null;
try {
status = this.status;
if (!status && m.isNotEmpty(this.responseText)) {
// 0 or undefined seems to mean cached or local
status = 304;
}
} catch (e) {
// pass
// MochiKit.Logging.logDebug('error getting status?', repr(items(e)));
}
// 200 is OK, 201 is CREATED, 204 is NO CONTENT
// 304 is NOT MODIFIED, 1223 is apparently a bug in IE
if (status == 200 || status == 201 || status == 204 ||
status == 304 || status == 1223) {
d.callback(this);
} else {
var err = new MochiKit.Async.XMLHttpRequestError(this, "Request failed");
if (err.number) {
// XXX: This seems to happen on page change
d.errback(err);
} else {
// XXX: this seems to happen when the server is unreachable
d.errback(err);
}
}
}
},
_xhr_canceller: function (req) {
// IE SUCKS
try {
req.onreadystatechange = null;
} catch (e) {
try {
req.onreadystatechange = MochiKit.Base.noop;
} catch (e) {
}
}
req.abort();
},
/** @id MochiKit.Async.sendXMLHttpRequest */
sendXMLHttpRequest: function (req, /* optional */ sendContent) {
if (typeof(sendContent) == "undefined" || sendContent === null) {
sendContent = "";
}
var m = MochiKit.Base;
var self = MochiKit.Async;
var d = new self.Deferred(m.partial(self._xhr_canceller, req));
try {
req.onreadystatechange = m.bind(self._xhr_onreadystatechange,
req, d);
req.send(sendContent);
} catch (e) {
try {
req.onreadystatechange = null;
} catch (ignore) {
// pass
}
d.errback(e);
}
return d;
},
/** @id MochiKit.Async.doXHR */
doXHR: function (url, opts) {
/*
Work around a Firefox bug by dealing with XHR during
the next event loop iteration. Maybe it's this one:
https://bugzilla.mozilla.org/show_bug.cgi?id=249843
*/
var self = MochiKit.Async;
return self.callLater(0, self._doXHR, url, opts);
},
_doXHR: function (url, opts) {
var m = MochiKit.Base;
opts = m.update({
method: 'GET',
sendContent: ''
/*
queryString: undefined,
username: undefined,
password: undefined,
headers: undefined,
mimeType: undefined
*/
}, opts);
var self = MochiKit.Async;
var req = self.getXMLHttpRequest();
if (opts.queryString) {
var qs = m.queryString(opts.queryString);
if (qs) {
url += "?" + qs;
}
}
// Safari will send undefined:undefined, so we have to check.
// We can't use apply, since the function is native.
if ('username' in opts) {
req.open(opts.method, url, true, opts.username, opts.password);
} else {
req.open(opts.method, url, true);
}
if (req.overrideMimeType && opts.mimeType) {
req.overrideMimeType(opts.mimeType);
}
req.setRequestHeader("X-Requested-With", "XMLHttpRequest");
if (opts.headers) {
var headers = opts.headers;
if (!m.isArrayLike(headers)) {
headers = m.items(headers);
}
for (var i = 0; i < headers.length; i++) {
var header = headers[i];
var name = header[0];
var value = header[1];
req.setRequestHeader(name, value);
}
}
return self.sendXMLHttpRequest(req, opts.sendContent);
},
_buildURL: function (url/*, ...*/) {
if (arguments.length > 1) {
var m = MochiKit.Base;
var qs = m.queryString.apply(null, m.extend(null, arguments, 1));
if (qs) {
return url + "?" + qs;
}
}
return url;
},
/** @id MochiKit.Async.doSimpleXMLHttpRequest */
doSimpleXMLHttpRequest: function (url/*, ...*/) {
var self = MochiKit.Async;
url = self._buildURL.apply(self, arguments);
return self.doXHR(url);
},
/** @id MochiKit.Async.loadJSONDoc */
loadJSONDoc: function (url/*, ...*/) {
var self = MochiKit.Async;
url = self._buildURL.apply(self, arguments);
var d = self.doXHR(url, {
'mimeType': 'text/plain',
'headers': [['Accept', 'application/json']]
});
d = d.addCallback(self.evalJSONRequest);
return d;
},
/** @id MochiKit.Async.wait */
wait: function (seconds, /* optional */value) {
var d = new MochiKit.Async.Deferred();
var m = MochiKit.Base;
if (typeof(value) != 'undefined') {
d.addCallback(function () { return value; });
}
var timeout = setTimeout(
m.bind("callback", d),
Math.floor(seconds * 1000));
d.canceller = function () {
try {
clearTimeout(timeout);
} catch (e) {
// pass
}
};
return d;
},
/** @id MochiKit.Async.callLater */
callLater: function (seconds, func) {
var m = MochiKit.Base;
var pfunc = m.partial.apply(m, m.extend(null, arguments, 1));
return MochiKit.Async.wait(seconds).addCallback(
function (res) { return pfunc(); }
);
}
});
/** @id MochiKit.Async.DeferredLock */
MochiKit.Async.DeferredLock = function () {
this.waiting = [];
this.locked = false;
this.id = this._nextId();
};
MochiKit.Async.DeferredLock.prototype = {
__class__: MochiKit.Async.DeferredLock,
/** @id MochiKit.Async.DeferredLock.prototype.acquire */
acquire: function () {
var d = new MochiKit.Async.Deferred();
if (this.locked) {
this.waiting.push(d);
} else {
this.locked = true;
d.callback(this);
}
return d;
},
/** @id MochiKit.Async.DeferredLock.prototype.release */
release: function () {
if (!this.locked) {
throw TypeError("Tried to release an unlocked DeferredLock");
}
this.locked = false;
if (this.waiting.length > 0) {
this.locked = true;
this.waiting.shift().callback(this);
}
},
_nextId: MochiKit.Base.counter(),
repr: function () {
var state;
if (this.locked) {
state = 'locked, ' + this.waiting.length + ' waiting';
} else {
state = 'unlocked';
}
return 'DeferredLock(' + this.id + ', ' + state + ')';
},
toString: MochiKit.Base.forwardCall("repr")
};
/** @id MochiKit.Async.DeferredList */
MochiKit.Async.DeferredList = function (list, /* optional */fireOnOneCallback, fireOnOneErrback, consumeErrors, canceller) {
// call parent constructor
MochiKit.Async.Deferred.apply(this, [canceller]);
this.list = list;
var resultList = [];
this.resultList = resultList;
this.finishedCount = 0;
this.fireOnOneCallback = fireOnOneCallback;
this.fireOnOneErrback = fireOnOneErrback;
this.consumeErrors = consumeErrors;
var cb = MochiKit.Base.bind(this._cbDeferred, this);
for (var i = 0; i < list.length; i++) {
var d = list[i];
resultList.push(undefined);
d.addCallback(cb, i, true);
d.addErrback(cb, i, false);
}
if (list.length === 0 && !fireOnOneCallback) {
this.callback(this.resultList);
}
};
MochiKit.Async.DeferredList.prototype = new MochiKit.Async.Deferred();
MochiKit.Async.DeferredList.prototype._cbDeferred = function (index, succeeded, result) {
this.resultList[index] = [succeeded, result];
this.finishedCount += 1;
if (this.fired == -1) {
if (succeeded && this.fireOnOneCallback) {
this.callback([index, result]);
} else if (!succeeded && this.fireOnOneErrback) {
this.errback(result);
} else if (this.finishedCount == this.list.length) {
this.callback(this.resultList);
}
}
if (!succeeded && this.consumeErrors) {
result = null;
}
return result;
};
/** @id MochiKit.Async.gatherResults */
MochiKit.Async.gatherResults = function (deferredList) {
var d = new MochiKit.Async.DeferredList(deferredList, false, true, false);
d.addCallback(function (results) {
var ret = [];
for (var i = 0; i < results.length; i++) {
ret.push(results[i][1]);
}
return ret;
});
return d;
};
/** @id MochiKit.Async.maybeDeferred */
MochiKit.Async.maybeDeferred = function (func) {
var self = MochiKit.Async;
var result;
try {
var r = func.apply(null, MochiKit.Base.extend([], arguments, 1));
if (r instanceof self.Deferred) {
result = r;
} else if (r instanceof Error) {
result = self.fail(r);
} else {
result = self.succeed(r);
}
} catch (e) {
result = self.fail(e);
}
return result;
};
MochiKit.Async.EXPORT = [
"AlreadyCalledError",
"CancelledError",
"BrowserComplianceError",
"GenericError",
"XMLHttpRequestError",
"Deferred",
"succeed",
"fail",
"getXMLHttpRequest",
"doSimpleXMLHttpRequest",
"loadJSONDoc",
"wait",
"callLater",
"sendXMLHttpRequest",
"DeferredLock",
"DeferredList",
"gatherResults",
"maybeDeferred",
"doXHR"
];
MochiKit.Async.EXPORT_OK = [
"evalJSONRequest"
];
MochiKit.Async.__new__ = function () {
var m = MochiKit.Base;
var ne = m.partial(m._newNamedError, this);
ne("AlreadyCalledError",
/** @id MochiKit.Async.AlreadyCalledError */
function (deferred) {
/***
Raised by the Deferred if callback or errback happens
after it was already fired.
***/
this.deferred = deferred;
}
);
ne("CancelledError",
/** @id MochiKit.Async.CancelledError */
function (deferred) {
/***
Raised by the Deferred cancellation mechanism.
***/
this.deferred = deferred;
}
);
ne("BrowserComplianceError",
/** @id MochiKit.Async.BrowserComplianceError */
function (msg) {
/***
Raised when the JavaScript runtime is not capable of performing
the given function. Technically, this should really never be
raised because a non-conforming JavaScript runtime probably
isn't going to support exceptions in the first place.
***/
this.message = msg;
}
);
ne("GenericError",
/** @id MochiKit.Async.GenericError */
function (msg) {
this.message = msg;
}
);
ne("XMLHttpRequestError",
/** @id MochiKit.Async.XMLHttpRequestError */
function (req, msg) {
/***
Raised when an XMLHttpRequest does not complete for any reason.
***/
this.req = req;
this.message = msg;
try {
// Strange but true that this can raise in some cases.
this.number = req.status;
} catch (e) {
// pass
}
}
);
this.EXPORT_TAGS = {
":common": this.EXPORT,
":all": m.concat(this.EXPORT, this.EXPORT_OK)
};
m.nameFunctions(this);
};
MochiKit.Async.__new__();
MochiKit.Base._exportSymbols(this, MochiKit.Async);
File diff suppressed because it is too large Load Diff
-863
View File
@@ -1,863 +0,0 @@
/***
MochiKit.Color 1.4.2
See <http://mochikit.com/> for documentation, downloads, license, etc.
(c) 2005 Bob Ippolito and others. All rights Reserved.
***/
MochiKit.Base._deps('Color', ['Base', 'DOM', 'Style']);
MochiKit.Color.NAME = "MochiKit.Color";
MochiKit.Color.VERSION = "1.4.2";
MochiKit.Color.__repr__ = function () {
return "[" + this.NAME + " " + this.VERSION + "]";
};
MochiKit.Color.toString = function () {
return this.__repr__();
};
/** @id MochiKit.Color.Color */
MochiKit.Color.Color = function (red, green, blue, alpha) {
if (typeof(alpha) == 'undefined' || alpha === null) {
alpha = 1.0;
}
this.rgb = {
r: red,
g: green,
b: blue,
a: alpha
};
};
// Prototype methods
MochiKit.Color.Color.prototype = {
__class__: MochiKit.Color.Color,
/** @id MochiKit.Color.Color.prototype.colorWithAlpha */
colorWithAlpha: function (alpha) {
var rgb = this.rgb;
var m = MochiKit.Color;
return m.Color.fromRGB(rgb.r, rgb.g, rgb.b, alpha);
},
/** @id MochiKit.Color.Color.prototype.colorWithHue */
colorWithHue: function (hue) {
// get an HSL model, and set the new hue...
var hsl = this.asHSL();
hsl.h = hue;
var m = MochiKit.Color;
// convert back to RGB...
return m.Color.fromHSL(hsl);
},
/** @id MochiKit.Color.Color.prototype.colorWithSaturation */
colorWithSaturation: function (saturation) {
// get an HSL model, and set the new hue...
var hsl = this.asHSL();
hsl.s = saturation;
var m = MochiKit.Color;
// convert back to RGB...
return m.Color.fromHSL(hsl);
},
/** @id MochiKit.Color.Color.prototype.colorWithLightness */
colorWithLightness: function (lightness) {
// get an HSL model, and set the new hue...
var hsl = this.asHSL();
hsl.l = lightness;
var m = MochiKit.Color;
// convert back to RGB...
return m.Color.fromHSL(hsl);
},
/** @id MochiKit.Color.Color.prototype.darkerColorWithLevel */
darkerColorWithLevel: function (level) {
var hsl = this.asHSL();
hsl.l = Math.max(hsl.l - level, 0);
var m = MochiKit.Color;
return m.Color.fromHSL(hsl);
},
/** @id MochiKit.Color.Color.prototype.lighterColorWithLevel */
lighterColorWithLevel: function (level) {
var hsl = this.asHSL();
hsl.l = Math.min(hsl.l + level, 1);
var m = MochiKit.Color;
return m.Color.fromHSL(hsl);
},
/** @id MochiKit.Color.Color.prototype.blendedColor */
blendedColor: function (other, /* optional */ fraction) {
if (typeof(fraction) == 'undefined' || fraction === null) {
fraction = 0.5;
}
var sf = 1.0 - fraction;
var s = this.rgb;
var d = other.rgb;
var df = fraction;
return MochiKit.Color.Color.fromRGB(
(s.r * sf) + (d.r * df),
(s.g * sf) + (d.g * df),
(s.b * sf) + (d.b * df),
(s.a * sf) + (d.a * df)
);
},
/** @id MochiKit.Color.Color.prototype.compareRGB */
compareRGB: function (other) {
var a = this.asRGB();
var b = other.asRGB();
return MochiKit.Base.compare(
[a.r, a.g, a.b, a.a],
[b.r, b.g, b.b, b.a]
);
},
/** @id MochiKit.Color.Color.prototype.isLight */
isLight: function () {
return this.asHSL().b > 0.5;
},
/** @id MochiKit.Color.Color.prototype.isDark */
isDark: function () {
return (!this.isLight());
},
/** @id MochiKit.Color.Color.prototype.toHSLString */
toHSLString: function () {
var c = this.asHSL();
var ccc = MochiKit.Color.clampColorComponent;
var rval = this._hslString;
if (!rval) {
var mid = (
ccc(c.h, 360).toFixed(0)
+ "," + ccc(c.s, 100).toPrecision(4) + "%"
+ "," + ccc(c.l, 100).toPrecision(4) + "%"
);
var a = c.a;
if (a >= 1) {
a = 1;
rval = "hsl(" + mid + ")";
} else {
if (a <= 0) {
a = 0;
}
rval = "hsla(" + mid + "," + a + ")";
}
this._hslString = rval;
}
return rval;
},
/** @id MochiKit.Color.Color.prototype.toRGBString */
toRGBString: function () {
var c = this.rgb;
var ccc = MochiKit.Color.clampColorComponent;
var rval = this._rgbString;
if (!rval) {
var mid = (
ccc(c.r, 255).toFixed(0)
+ "," + ccc(c.g, 255).toFixed(0)
+ "," + ccc(c.b, 255).toFixed(0)
);
if (c.a != 1) {
rval = "rgba(" + mid + "," + c.a + ")";
} else {
rval = "rgb(" + mid + ")";
}
this._rgbString = rval;
}
return rval;
},
/** @id MochiKit.Color.Color.prototype.asRGB */
asRGB: function () {
return MochiKit.Base.clone(this.rgb);
},
/** @id MochiKit.Color.Color.prototype.toHexString */
toHexString: function () {
var m = MochiKit.Color;
var c = this.rgb;
var ccc = MochiKit.Color.clampColorComponent;
var rval = this._hexString;
if (!rval) {
rval = ("#" +
m.toColorPart(ccc(c.r, 255)) +
m.toColorPart(ccc(c.g, 255)) +
m.toColorPart(ccc(c.b, 255))
);
this._hexString = rval;
}
return rval;
},
/** @id MochiKit.Color.Color.prototype.asHSV */
asHSV: function () {
var hsv = this.hsv;
var c = this.rgb;
if (typeof(hsv) == 'undefined' || hsv === null) {
hsv = MochiKit.Color.rgbToHSV(this.rgb);
this.hsv = hsv;
}
return MochiKit.Base.clone(hsv);
},
/** @id MochiKit.Color.Color.prototype.asHSL */
asHSL: function () {
var hsl = this.hsl;
var c = this.rgb;
if (typeof(hsl) == 'undefined' || hsl === null) {
hsl = MochiKit.Color.rgbToHSL(this.rgb);
this.hsl = hsl;
}
return MochiKit.Base.clone(hsl);
},
/** @id MochiKit.Color.Color.prototype.toString */
toString: function () {
return this.toRGBString();
},
/** @id MochiKit.Color.Color.prototype.repr */
repr: function () {
var c = this.rgb;
var col = [c.r, c.g, c.b, c.a];
return this.__class__.NAME + "(" + col.join(", ") + ")";
}
};
// Constructor methods
MochiKit.Base.update(MochiKit.Color.Color, {
/** @id MochiKit.Color.Color.fromRGB */
fromRGB: function (red, green, blue, alpha) {
// designated initializer
var Color = MochiKit.Color.Color;
if (arguments.length == 1) {
var rgb = red;
red = rgb.r;
green = rgb.g;
blue = rgb.b;
if (typeof(rgb.a) == 'undefined') {
alpha = undefined;
} else {
alpha = rgb.a;
}
}
return new Color(red, green, blue, alpha);
},
/** @id MochiKit.Color.Color.fromHSL */
fromHSL: function (hue, saturation, lightness, alpha) {
var m = MochiKit.Color;
return m.Color.fromRGB(m.hslToRGB.apply(m, arguments));
},
/** @id MochiKit.Color.Color.fromHSV */
fromHSV: function (hue, saturation, value, alpha) {
var m = MochiKit.Color;
return m.Color.fromRGB(m.hsvToRGB.apply(m, arguments));
},
/** @id MochiKit.Color.Color.fromName */
fromName: function (name) {
var Color = MochiKit.Color.Color;
// Opera 9 seems to "quote" named colors(?!)
if (name.charAt(0) == '"') {
name = name.substr(1, name.length - 2);
}
var htmlColor = Color._namedColors[name.toLowerCase()];
if (typeof(htmlColor) == 'string') {
return Color.fromHexString(htmlColor);
} else if (name == "transparent") {
return Color.transparentColor();
}
return null;
},
/** @id MochiKit.Color.Color.fromString */
fromString: function (colorString) {
var self = MochiKit.Color.Color;
var three = colorString.substr(0, 3);
if (three == "rgb") {
return self.fromRGBString(colorString);
} else if (three == "hsl") {
return self.fromHSLString(colorString);
} else if (colorString.charAt(0) == "#") {
return self.fromHexString(colorString);
}
return self.fromName(colorString);
},
/** @id MochiKit.Color.Color.fromHexString */
fromHexString: function (hexCode) {
if (hexCode.charAt(0) == '#') {
hexCode = hexCode.substring(1);
}
var components = [];
var i, hex;
if (hexCode.length == 3) {
for (i = 0; i < 3; i++) {
hex = hexCode.substr(i, 1);
components.push(parseInt(hex + hex, 16) / 255.0);
}
} else {
for (i = 0; i < 6; i += 2) {
hex = hexCode.substr(i, 2);
components.push(parseInt(hex, 16) / 255.0);
}
}
var Color = MochiKit.Color.Color;
return Color.fromRGB.apply(Color, components);
},
_fromColorString: function (pre, method, scales, colorCode) {
// parses either HSL or RGB
if (colorCode.indexOf(pre) === 0) {
colorCode = colorCode.substring(colorCode.indexOf("(", 3) + 1, colorCode.length - 1);
}
var colorChunks = colorCode.split(/\s*,\s*/);
var colorFloats = [];
for (var i = 0; i < colorChunks.length; i++) {
var c = colorChunks[i];
var val;
var three = c.substring(c.length - 3);
if (c.charAt(c.length - 1) == '%') {
val = 0.01 * parseFloat(c.substring(0, c.length - 1));
} else if (three == "deg") {
val = parseFloat(c) / 360.0;
} else if (three == "rad") {
val = parseFloat(c) / (Math.PI * 2);
} else {
val = scales[i] * parseFloat(c);
}
colorFloats.push(val);
}
return this[method].apply(this, colorFloats);
},
/** @id MochiKit.Color.Color.fromComputedStyle */
fromComputedStyle: function (elem, style) {
var d = MochiKit.DOM;
var cls = MochiKit.Color.Color;
for (elem = d.getElement(elem); elem; elem = elem.parentNode) {
var actualColor = MochiKit.Style.getStyle.apply(d, arguments);
if (!actualColor) {
continue;
}
var color = cls.fromString(actualColor);
if (!color) {
break;
}
if (color.asRGB().a > 0) {
return color;
}
}
return null;
},
/** @id MochiKit.Color.Color.fromBackground */
fromBackground: function (elem) {
var cls = MochiKit.Color.Color;
return cls.fromComputedStyle(
elem, "backgroundColor", "background-color") || cls.whiteColor();
},
/** @id MochiKit.Color.Color.fromText */
fromText: function (elem) {
var cls = MochiKit.Color.Color;
return cls.fromComputedStyle(
elem, "color", "color") || cls.blackColor();
},
/** @id MochiKit.Color.Color.namedColors */
namedColors: function () {
return MochiKit.Base.clone(MochiKit.Color.Color._namedColors);
}
});
// Module level functions
MochiKit.Base.update(MochiKit.Color, {
/** @id MochiKit.Color.clampColorComponent */
clampColorComponent: function (v, scale) {
v *= scale;
if (v < 0) {
return 0;
} else if (v > scale) {
return scale;
} else {
return v;
}
},
_hslValue: function (n1, n2, hue) {
if (hue > 6.0) {
hue -= 6.0;
} else if (hue < 0.0) {
hue += 6.0;
}
var val;
if (hue < 1.0) {
val = n1 + (n2 - n1) * hue;
} else if (hue < 3.0) {
val = n2;
} else if (hue < 4.0) {
val = n1 + (n2 - n1) * (4.0 - hue);
} else {
val = n1;
}
return val;
},
/** @id MochiKit.Color.hsvToRGB */
hsvToRGB: function (hue, saturation, value, alpha) {
if (arguments.length == 1) {
var hsv = hue;
hue = hsv.h;
saturation = hsv.s;
value = hsv.v;
alpha = hsv.a;
}
var red;
var green;
var blue;
if (saturation === 0) {
red = value;
green = value;
blue = value;
} else {
var i = Math.floor(hue * 6);
var f = (hue * 6) - i;
var p = value * (1 - saturation);
var q = value * (1 - (saturation * f));
var t = value * (1 - (saturation * (1 - f)));
switch (i) {
case 1: red = q; green = value; blue = p; break;
case 2: red = p; green = value; blue = t; break;
case 3: red = p; green = q; blue = value; break;
case 4: red = t; green = p; blue = value; break;
case 5: red = value; green = p; blue = q; break;
case 6: // fall through
case 0: red = value; green = t; blue = p; break;
}
}
return {
r: red,
g: green,
b: blue,
a: alpha
};
},
/** @id MochiKit.Color.hslToRGB */
hslToRGB: function (hue, saturation, lightness, alpha) {
if (arguments.length == 1) {
var hsl = hue;
hue = hsl.h;
saturation = hsl.s;
lightness = hsl.l;
alpha = hsl.a;
}
var red;
var green;
var blue;
if (saturation === 0) {
red = lightness;
green = lightness;
blue = lightness;
} else {
var m2;
if (lightness <= 0.5) {
m2 = lightness * (1.0 + saturation);
} else {
m2 = lightness + saturation - (lightness * saturation);
}
var m1 = (2.0 * lightness) - m2;
var f = MochiKit.Color._hslValue;
var h6 = hue * 6.0;
red = f(m1, m2, h6 + 2);
green = f(m1, m2, h6);
blue = f(m1, m2, h6 - 2);
}
return {
r: red,
g: green,
b: blue,
a: alpha
};
},
/** @id MochiKit.Color.rgbToHSV */
rgbToHSV: function (red, green, blue, alpha) {
if (arguments.length == 1) {
var rgb = red;
red = rgb.r;
green = rgb.g;
blue = rgb.b;
alpha = rgb.a;
}
var max = Math.max(Math.max(red, green), blue);
var min = Math.min(Math.min(red, green), blue);
var hue;
var saturation;
var value = max;
if (min == max) {
hue = 0;
saturation = 0;
} else {
var delta = (max - min);
saturation = delta / max;
if (red == max) {
hue = (green - blue) / delta;
} else if (green == max) {
hue = 2 + ((blue - red) / delta);
} else {
hue = 4 + ((red - green) / delta);
}
hue /= 6;
if (hue < 0) {
hue += 1;
}
if (hue > 1) {
hue -= 1;
}
}
return {
h: hue,
s: saturation,
v: value,
a: alpha
};
},
/** @id MochiKit.Color.rgbToHSL */
rgbToHSL: function (red, green, blue, alpha) {
if (arguments.length == 1) {
var rgb = red;
red = rgb.r;
green = rgb.g;
blue = rgb.b;
alpha = rgb.a;
}
var max = Math.max(red, Math.max(green, blue));
var min = Math.min(red, Math.min(green, blue));
var hue;
var saturation;
var lightness = (max + min) / 2.0;
var delta = max - min;
if (delta === 0) {
hue = 0;
saturation = 0;
} else {
if (lightness <= 0.5) {
saturation = delta / (max + min);
} else {
saturation = delta / (2 - max - min);
}
if (red == max) {
hue = (green - blue) / delta;
} else if (green == max) {
hue = 2 + ((blue - red) / delta);
} else {
hue = 4 + ((red - green) / delta);
}
hue /= 6;
if (hue < 0) {
hue += 1;
}
if (hue > 1) {
hue -= 1;
}
}
return {
h: hue,
s: saturation,
l: lightness,
a: alpha
};
},
/** @id MochiKit.Color.toColorPart */
toColorPart: function (num) {
num = Math.round(num);
var digits = num.toString(16);
if (num < 16) {
return '0' + digits;
}
return digits;
},
__new__: function () {
var m = MochiKit.Base;
/** @id MochiKit.Color.fromRGBString */
this.Color.fromRGBString = m.bind(
this.Color._fromColorString, this.Color, "rgb", "fromRGB",
[1.0/255.0, 1.0/255.0, 1.0/255.0, 1]
);
/** @id MochiKit.Color.fromHSLString */
this.Color.fromHSLString = m.bind(
this.Color._fromColorString, this.Color, "hsl", "fromHSL",
[1.0/360.0, 0.01, 0.01, 1]
);
var third = 1.0 / 3.0;
/** @id MochiKit.Color.colors */
var colors = {
// NSColor colors plus transparent
/** @id MochiKit.Color.blackColor */
black: [0, 0, 0],
/** @id MochiKit.Color.blueColor */
blue: [0, 0, 1],
/** @id MochiKit.Color.brownColor */
brown: [0.6, 0.4, 0.2],
/** @id MochiKit.Color.cyanColor */
cyan: [0, 1, 1],
/** @id MochiKit.Color.darkGrayColor */
darkGray: [third, third, third],
/** @id MochiKit.Color.grayColor */
gray: [0.5, 0.5, 0.5],
/** @id MochiKit.Color.greenColor */
green: [0, 1, 0],
/** @id MochiKit.Color.lightGrayColor */
lightGray: [2 * third, 2 * third, 2 * third],
/** @id MochiKit.Color.magentaColor */
magenta: [1, 0, 1],
/** @id MochiKit.Color.orangeColor */
orange: [1, 0.5, 0],
/** @id MochiKit.Color.purpleColor */
purple: [0.5, 0, 0.5],
/** @id MochiKit.Color.redColor */
red: [1, 0, 0],
/** @id MochiKit.Color.transparentColor */
transparent: [0, 0, 0, 0],
/** @id MochiKit.Color.whiteColor */
white: [1, 1, 1],
/** @id MochiKit.Color.yellowColor */
yellow: [1, 1, 0]
};
var makeColor = function (name, r, g, b, a) {
var rval = this.fromRGB(r, g, b, a);
this[name] = function () { return rval; };
return rval;
};
for (var k in colors) {
var name = k + "Color";
var bindArgs = m.concat(
[makeColor, this.Color, name],
colors[k]
);
this.Color[name] = m.bind.apply(null, bindArgs);
}
var isColor = function () {
for (var i = 0; i < arguments.length; i++) {
if (!(arguments[i] instanceof MochiKit.Color.Color)) {
return false;
}
}
return true;
};
var compareColor = function (a, b) {
return a.compareRGB(b);
};
m.nameFunctions(this);
m.registerComparator(this.Color.NAME, isColor, compareColor);
this.EXPORT_TAGS = {
":common": this.EXPORT,
":all": m.concat(this.EXPORT, this.EXPORT_OK)
};
}
});
MochiKit.Color.EXPORT = [
"Color"
];
MochiKit.Color.EXPORT_OK = [
"clampColorComponent",
"rgbToHSL",
"hslToRGB",
"rgbToHSV",
"hsvToRGB",
"toColorPart"
];
MochiKit.Color.__new__();
MochiKit.Base._exportSymbols(this, MochiKit.Color);
// Full table of css3 X11 colors <http://www.w3.org/TR/css3-color/#X11COLORS>
MochiKit.Color.Color._namedColors = {
aliceblue: "#f0f8ff",
antiquewhite: "#faebd7",
aqua: "#00ffff",
aquamarine: "#7fffd4",
azure: "#f0ffff",
beige: "#f5f5dc",
bisque: "#ffe4c4",
black: "#000000",
blanchedalmond: "#ffebcd",
blue: "#0000ff",
blueviolet: "#8a2be2",
brown: "#a52a2a",
burlywood: "#deb887",
cadetblue: "#5f9ea0",
chartreuse: "#7fff00",
chocolate: "#d2691e",
coral: "#ff7f50",
cornflowerblue: "#6495ed",
cornsilk: "#fff8dc",
crimson: "#dc143c",
cyan: "#00ffff",
darkblue: "#00008b",
darkcyan: "#008b8b",
darkgoldenrod: "#b8860b",
darkgray: "#a9a9a9",
darkgreen: "#006400",
darkgrey: "#a9a9a9",
darkkhaki: "#bdb76b",
darkmagenta: "#8b008b",
darkolivegreen: "#556b2f",
darkorange: "#ff8c00",
darkorchid: "#9932cc",
darkred: "#8b0000",
darksalmon: "#e9967a",
darkseagreen: "#8fbc8f",
darkslateblue: "#483d8b",
darkslategray: "#2f4f4f",
darkslategrey: "#2f4f4f",
darkturquoise: "#00ced1",
darkviolet: "#9400d3",
deeppink: "#ff1493",
deepskyblue: "#00bfff",
dimgray: "#696969",
dimgrey: "#696969",
dodgerblue: "#1e90ff",
firebrick: "#b22222",
floralwhite: "#fffaf0",
forestgreen: "#228b22",
fuchsia: "#ff00ff",
gainsboro: "#dcdcdc",
ghostwhite: "#f8f8ff",
gold: "#ffd700",
goldenrod: "#daa520",
gray: "#808080",
green: "#008000",
greenyellow: "#adff2f",
grey: "#808080",
honeydew: "#f0fff0",
hotpink: "#ff69b4",
indianred: "#cd5c5c",
indigo: "#4b0082",
ivory: "#fffff0",
khaki: "#f0e68c",
lavender: "#e6e6fa",
lavenderblush: "#fff0f5",
lawngreen: "#7cfc00",
lemonchiffon: "#fffacd",
lightblue: "#add8e6",
lightcoral: "#f08080",
lightcyan: "#e0ffff",
lightgoldenrodyellow: "#fafad2",
lightgray: "#d3d3d3",
lightgreen: "#90ee90",
lightgrey: "#d3d3d3",
lightpink: "#ffb6c1",
lightsalmon: "#ffa07a",
lightseagreen: "#20b2aa",
lightskyblue: "#87cefa",
lightslategray: "#778899",
lightslategrey: "#778899",
lightsteelblue: "#b0c4de",
lightyellow: "#ffffe0",
lime: "#00ff00",
limegreen: "#32cd32",
linen: "#faf0e6",
magenta: "#ff00ff",
maroon: "#800000",
mediumaquamarine: "#66cdaa",
mediumblue: "#0000cd",
mediumorchid: "#ba55d3",
mediumpurple: "#9370db",
mediumseagreen: "#3cb371",
mediumslateblue: "#7b68ee",
mediumspringgreen: "#00fa9a",
mediumturquoise: "#48d1cc",
mediumvioletred: "#c71585",
midnightblue: "#191970",
mintcream: "#f5fffa",
mistyrose: "#ffe4e1",
moccasin: "#ffe4b5",
navajowhite: "#ffdead",
navy: "#000080",
oldlace: "#fdf5e6",
olive: "#808000",
olivedrab: "#6b8e23",
orange: "#ffa500",
orangered: "#ff4500",
orchid: "#da70d6",
palegoldenrod: "#eee8aa",
palegreen: "#98fb98",
paleturquoise: "#afeeee",
palevioletred: "#db7093",
papayawhip: "#ffefd5",
peachpuff: "#ffdab9",
peru: "#cd853f",
pink: "#ffc0cb",
plum: "#dda0dd",
powderblue: "#b0e0e6",
purple: "#800080",
red: "#ff0000",
rosybrown: "#bc8f8f",
royalblue: "#4169e1",
saddlebrown: "#8b4513",
salmon: "#fa8072",
sandybrown: "#f4a460",
seagreen: "#2e8b57",
seashell: "#fff5ee",
sienna: "#a0522d",
silver: "#c0c0c0",
skyblue: "#87ceeb",
slateblue: "#6a5acd",
slategray: "#708090",
slategrey: "#708090",
snow: "#fffafa",
springgreen: "#00ff7f",
steelblue: "#4682b4",
tan: "#d2b48c",
teal: "#008080",
thistle: "#d8bfd8",
tomato: "#ff6347",
turquoise: "#40e0d0",
violet: "#ee82ee",
wheat: "#f5deb3",
white: "#ffffff",
whitesmoke: "#f5f5f5",
yellow: "#ffff00",
yellowgreen: "#9acd32"
};
File diff suppressed because it is too large Load Diff
-222
View File
@@ -1,222 +0,0 @@
/***
MochiKit.DateTime 1.4.2
See <http://mochikit.com/> for documentation, downloads, license, etc.
(c) 2005 Bob Ippolito. All rights Reserved.
***/
MochiKit.Base._deps('DateTime', ['Base']);
MochiKit.DateTime.NAME = "MochiKit.DateTime";
MochiKit.DateTime.VERSION = "1.4.2";
MochiKit.DateTime.__repr__ = function () {
return "[" + this.NAME + " " + this.VERSION + "]";
};
MochiKit.DateTime.toString = function () {
return this.__repr__();
};
/** @id MochiKit.DateTime.isoDate */
MochiKit.DateTime.isoDate = function (str) {
str = str + "";
if (typeof(str) != "string" || str.length === 0) {
return null;
}
var iso = str.split('-');
if (iso.length === 0) {
return null;
}
var date = new Date(iso[0], iso[1] - 1, iso[2]);
date.setFullYear(iso[0]);
date.setMonth(iso[1] - 1);
date.setDate(iso[2]);
return date;
};
MochiKit.DateTime._isoRegexp = /(\d{4,})(?:-(\d{1,2})(?:-(\d{1,2})(?:[T ](\d{1,2}):(\d{1,2})(?::(\d{1,2})(?:\.(\d+))?)?(?:(Z)|([+-])(\d{1,2})(?::(\d{1,2}))?)?)?)?)?/;
/** @id MochiKit.DateTime.isoTimestamp */
MochiKit.DateTime.isoTimestamp = function (str) {
str = str + "";
if (typeof(str) != "string" || str.length === 0) {
return null;
}
var res = str.match(MochiKit.DateTime._isoRegexp);
if (typeof(res) == "undefined" || res === null) {
return null;
}
var year, month, day, hour, min, sec, msec;
year = parseInt(res[1], 10);
if (typeof(res[2]) == "undefined" || res[2] === '') {
return new Date(year);
}
month = parseInt(res[2], 10) - 1;
day = parseInt(res[3], 10);
if (typeof(res[4]) == "undefined" || res[4] === '') {
return new Date(year, month, day);
}
hour = parseInt(res[4], 10);
min = parseInt(res[5], 10);
sec = (typeof(res[6]) != "undefined" && res[6] !== '') ? parseInt(res[6], 10) : 0;
if (typeof(res[7]) != "undefined" && res[7] !== '') {
msec = Math.round(1000.0 * parseFloat("0." + res[7]));
} else {
msec = 0;
}
if ((typeof(res[8]) == "undefined" || res[8] === '') && (typeof(res[9]) == "undefined" || res[9] === '')) {
return new Date(year, month, day, hour, min, sec, msec);
}
var ofs;
if (typeof(res[9]) != "undefined" && res[9] !== '') {
ofs = parseInt(res[10], 10) * 3600000;
if (typeof(res[11]) != "undefined" && res[11] !== '') {
ofs += parseInt(res[11], 10) * 60000;
}
if (res[9] == "-") {
ofs = -ofs;
}
} else {
ofs = 0;
}
return new Date(Date.UTC(year, month, day, hour, min, sec, msec) - ofs);
};
/** @id MochiKit.DateTime.toISOTime */
MochiKit.DateTime.toISOTime = function (date, realISO/* = false */) {
if (typeof(date) == "undefined" || date === null) {
return null;
}
var hh = date.getHours();
var mm = date.getMinutes();
var ss = date.getSeconds();
var lst = [
((realISO && (hh < 10)) ? "0" + hh : hh),
((mm < 10) ? "0" + mm : mm),
((ss < 10) ? "0" + ss : ss)
];
return lst.join(":");
};
/** @id MochiKit.DateTime.toISOTimeStamp */
MochiKit.DateTime.toISOTimestamp = function (date, realISO/* = false*/) {
if (typeof(date) == "undefined" || date === null) {
return null;
}
var sep = realISO ? "T" : " ";
var foot = realISO ? "Z" : "";
if (realISO) {
date = new Date(date.getTime() + (date.getTimezoneOffset() * 60000));
}
return MochiKit.DateTime.toISODate(date) + sep + MochiKit.DateTime.toISOTime(date, realISO) + foot;
};
/** @id MochiKit.DateTime.toISODate */
MochiKit.DateTime.toISODate = function (date) {
if (typeof(date) == "undefined" || date === null) {
return null;
}
var _padTwo = MochiKit.DateTime._padTwo;
var _padFour = MochiKit.DateTime._padFour;
return [
_padFour(date.getFullYear()),
_padTwo(date.getMonth() + 1),
_padTwo(date.getDate())
].join("-");
};
/** @id MochiKit.DateTime.americanDate */
MochiKit.DateTime.americanDate = function (d) {
d = d + "";
if (typeof(d) != "string" || d.length === 0) {
return null;
}
var a = d.split('/');
return new Date(a[2], a[0] - 1, a[1]);
};
MochiKit.DateTime._padTwo = function (n) {
return (n > 9) ? n : "0" + n;
};
MochiKit.DateTime._padFour = function(n) {
switch(n.toString().length) {
case 1: return "000" + n; break;
case 2: return "00" + n; break;
case 3: return "0" + n; break;
case 4:
default:
return n;
}
};
/** @id MochiKit.DateTime.toPaddedAmericanDate */
MochiKit.DateTime.toPaddedAmericanDate = function (d) {
if (typeof(d) == "undefined" || d === null) {
return null;
}
var _padTwo = MochiKit.DateTime._padTwo;
return [
_padTwo(d.getMonth() + 1),
_padTwo(d.getDate()),
d.getFullYear()
].join('/');
};
/** @id MochiKit.DateTime.toAmericanDate */
MochiKit.DateTime.toAmericanDate = function (d) {
if (typeof(d) == "undefined" || d === null) {
return null;
}
return [d.getMonth() + 1, d.getDate(), d.getFullYear()].join('/');
};
MochiKit.DateTime.EXPORT = [
"isoDate",
"isoTimestamp",
"toISOTime",
"toISOTimestamp",
"toISODate",
"americanDate",
"toPaddedAmericanDate",
"toAmericanDate"
];
MochiKit.DateTime.EXPORT_OK = [];
MochiKit.DateTime.EXPORT_TAGS = {
":common": MochiKit.DateTime.EXPORT,
":all": MochiKit.DateTime.EXPORT
};
MochiKit.DateTime.__new__ = function () {
// MochiKit.Base.nameFunctions(this);
var base = this.NAME + ".";
for (var k in this) {
var o = this[k];
if (typeof(o) == 'function' && typeof(o.NAME) == 'undefined') {
try {
o.NAME = base + k;
} catch (e) {
// pass
}
}
}
};
MochiKit.DateTime.__new__();
if (typeof(MochiKit.Base) != "undefined") {
MochiKit.Base._exportSymbols(this, MochiKit.DateTime);
} else {
(function (globals, module) {
if ((typeof(JSAN) == 'undefined' && typeof(dojo) == 'undefined')
|| (MochiKit.__export__ === false)) {
var all = module.EXPORT_TAGS[":all"];
for (var i = 0; i < all.length; i++) {
globals[all[i]] = module[all[i]];
}
}
})(this, MochiKit.DateTime);
}
-793
View File
@@ -1,793 +0,0 @@
/***
MochiKit.DragAndDrop 1.4.2
See <http://mochikit.com/> for documentation, downloads, license, etc.
Copyright (c) 2005 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
Mochi-ized By Thomas Herve (_firstname_@nimail.org)
***/
MochiKit.Base._deps('DragAndDrop', ['Base', 'Iter', 'DOM', 'Signal', 'Visual', 'Position']);
MochiKit.DragAndDrop.NAME = 'MochiKit.DragAndDrop';
MochiKit.DragAndDrop.VERSION = '1.4.2';
MochiKit.DragAndDrop.__repr__ = function () {
return '[' + this.NAME + ' ' + this.VERSION + ']';
};
MochiKit.DragAndDrop.toString = function () {
return this.__repr__();
};
MochiKit.DragAndDrop.EXPORT = [
"Droppable",
"Draggable"
];
MochiKit.DragAndDrop.EXPORT_OK = [
"Droppables",
"Draggables"
];
MochiKit.DragAndDrop.Droppables = {
/***
Manage all droppables. Shouldn't be used, use the Droppable object instead.
***/
drops: [],
remove: function (element) {
this.drops = MochiKit.Base.filter(function (d) {
return d.element != MochiKit.DOM.getElement(element);
}, this.drops);
},
register: function (drop) {
this.drops.push(drop);
},
unregister: function (drop) {
this.drops = MochiKit.Base.filter(function (d) {
return d != drop;
}, this.drops);
},
prepare: function (element) {
MochiKit.Base.map(function (drop) {
if (drop.isAccepted(element)) {
if (drop.options.activeclass) {
MochiKit.DOM.addElementClass(drop.element,
drop.options.activeclass);
}
drop.options.onactive(drop.element, element);
}
}, this.drops);
},
findDeepestChild: function (drops) {
deepest = drops[0];
for (i = 1; i < drops.length; ++i) {
if (MochiKit.DOM.isChildNode(drops[i].element, deepest.element)) {
deepest = drops[i];
}
}
return deepest;
},
show: function (point, element) {
if (!this.drops.length) {
return;
}
var affected = [];
if (this.last_active) {
this.last_active.deactivate();
}
MochiKit.Iter.forEach(this.drops, function (drop) {
if (drop.isAffected(point, element)) {
affected.push(drop);
}
});
if (affected.length > 0) {
drop = this.findDeepestChild(affected);
MochiKit.Position.within(drop.element, point.page.x, point.page.y);
drop.options.onhover(element, drop.element,
MochiKit.Position.overlap(drop.options.overlap, drop.element));
drop.activate();
}
},
fire: function (event, element) {
if (!this.last_active) {
return;
}
MochiKit.Position.prepare();
if (this.last_active.isAffected(event.mouse(), element)) {
this.last_active.options.ondrop(element,
this.last_active.element, event);
}
},
reset: function (element) {
MochiKit.Base.map(function (drop) {
if (drop.options.activeclass) {
MochiKit.DOM.removeElementClass(drop.element,
drop.options.activeclass);
}
drop.options.ondesactive(drop.element, element);
}, this.drops);
if (this.last_active) {
this.last_active.deactivate();
}
}
};
/** @id MochiKit.DragAndDrop.Droppable */
MochiKit.DragAndDrop.Droppable = function (element, options) {
var cls = arguments.callee;
if (!(this instanceof cls)) {
return new cls(element, options);
}
this.__init__(element, options);
};
MochiKit.DragAndDrop.Droppable.prototype = {
/***
A droppable object. Simple use is to create giving an element:
new MochiKit.DragAndDrop.Droppable('myelement');
Generally you'll want to define the 'ondrop' function and maybe the
'accept' option to filter draggables.
***/
__class__: MochiKit.DragAndDrop.Droppable,
__init__: function (element, /* optional */options) {
var d = MochiKit.DOM;
var b = MochiKit.Base;
this.element = d.getElement(element);
this.options = b.update({
/** @id MochiKit.DragAndDrop.greedy */
greedy: true,
/** @id MochiKit.DragAndDrop.hoverclass */
hoverclass: null,
/** @id MochiKit.DragAndDrop.activeclass */
activeclass: null,
/** @id MochiKit.DragAndDrop.hoverfunc */
hoverfunc: b.noop,
/** @id MochiKit.DragAndDrop.accept */
accept: null,
/** @id MochiKit.DragAndDrop.onactive */
onactive: b.noop,
/** @id MochiKit.DragAndDrop.ondesactive */
ondesactive: b.noop,
/** @id MochiKit.DragAndDrop.onhover */
onhover: b.noop,
/** @id MochiKit.DragAndDrop.ondrop */
ondrop: b.noop,
/** @id MochiKit.DragAndDrop.containment */
containment: [],
tree: false
}, options);
// cache containers
this.options._containers = [];
b.map(MochiKit.Base.bind(function (c) {
this.options._containers.push(d.getElement(c));
}, this), this.options.containment);
MochiKit.Style.makePositioned(this.element); // fix IE
MochiKit.DragAndDrop.Droppables.register(this);
},
/** @id MochiKit.DragAndDrop.isContained */
isContained: function (element) {
if (this.options._containers.length) {
var containmentNode;
if (this.options.tree) {
containmentNode = element.treeNode;
} else {
containmentNode = element.parentNode;
}
return MochiKit.Iter.some(this.options._containers, function (c) {
return containmentNode == c;
});
} else {
return true;
}
},
/** @id MochiKit.DragAndDrop.isAccepted */
isAccepted: function (element) {
return ((!this.options.accept) || MochiKit.Iter.some(
this.options.accept, function (c) {
return MochiKit.DOM.hasElementClass(element, c);
}));
},
/** @id MochiKit.DragAndDrop.isAffected */
isAffected: function (point, element) {
return ((this.element != element) &&
this.isContained(element) &&
this.isAccepted(element) &&
MochiKit.Position.within(this.element, point.page.x,
point.page.y));
},
/** @id MochiKit.DragAndDrop.deactivate */
deactivate: function () {
/***
A droppable is deactivate when a draggable has been over it and left.
***/
if (this.options.hoverclass) {
MochiKit.DOM.removeElementClass(this.element,
this.options.hoverclass);
}
this.options.hoverfunc(this.element, false);
MochiKit.DragAndDrop.Droppables.last_active = null;
},
/** @id MochiKit.DragAndDrop.activate */
activate: function () {
/***
A droppable is active when a draggable is over it.
***/
if (this.options.hoverclass) {
MochiKit.DOM.addElementClass(this.element, this.options.hoverclass);
}
this.options.hoverfunc(this.element, true);
MochiKit.DragAndDrop.Droppables.last_active = this;
},
/** @id MochiKit.DragAndDrop.destroy */
destroy: function () {
/***
Delete this droppable.
***/
MochiKit.DragAndDrop.Droppables.unregister(this);
},
/** @id MochiKit.DragAndDrop.repr */
repr: function () {
return '[' + this.__class__.NAME + ", options:" + MochiKit.Base.repr(this.options) + "]";
}
};
MochiKit.DragAndDrop.Draggables = {
/***
Manage draggables elements. Not intended to direct use.
***/
drags: [],
register: function (draggable) {
if (this.drags.length === 0) {
var conn = MochiKit.Signal.connect;
this.eventMouseUp = conn(document, 'onmouseup', this, this.endDrag);
this.eventMouseMove = conn(document, 'onmousemove', this,
this.updateDrag);
this.eventKeypress = conn(document, 'onkeypress', this,
this.keyPress);
}
this.drags.push(draggable);
},
unregister: function (draggable) {
this.drags = MochiKit.Base.filter(function (d) {
return d != draggable;
}, this.drags);
if (this.drags.length === 0) {
var disc = MochiKit.Signal.disconnect;
disc(this.eventMouseUp);
disc(this.eventMouseMove);
disc(this.eventKeypress);
}
},
activate: function (draggable) {
// allows keypress events if window is not currently focused
// fails for Safari
window.focus();
this.activeDraggable = draggable;
},
deactivate: function () {
this.activeDraggable = null;
},
updateDrag: function (event) {
if (!this.activeDraggable) {
return;
}
var pointer = event.mouse();
// Mozilla-based browsers fire successive mousemove events with
// the same coordinates, prevent needless redrawing (moz bug?)
if (this._lastPointer && (MochiKit.Base.repr(this._lastPointer.page) ==
MochiKit.Base.repr(pointer.page))) {
return;
}
this._lastPointer = pointer;
this.activeDraggable.updateDrag(event, pointer);
},
endDrag: function (event) {
if (!this.activeDraggable) {
return;
}
this._lastPointer = null;
this.activeDraggable.endDrag(event);
this.activeDraggable = null;
},
keyPress: function (event) {
if (this.activeDraggable) {
this.activeDraggable.keyPress(event);
}
},
notify: function (eventName, draggable, event) {
MochiKit.Signal.signal(this, eventName, draggable, event);
}
};
/** @id MochiKit.DragAndDrop.Draggable */
MochiKit.DragAndDrop.Draggable = function (element, options) {
var cls = arguments.callee;
if (!(this instanceof cls)) {
return new cls(element, options);
}
this.__init__(element, options);
};
MochiKit.DragAndDrop.Draggable.prototype = {
/***
A draggable object. Simple instantiate :
new MochiKit.DragAndDrop.Draggable('myelement');
***/
__class__ : MochiKit.DragAndDrop.Draggable,
__init__: function (element, /* optional */options) {
var v = MochiKit.Visual;
var b = MochiKit.Base;
options = b.update({
/** @id MochiKit.DragAndDrop.handle */
handle: false,
/** @id MochiKit.DragAndDrop.starteffect */
starteffect: function (innerelement) {
this._savedOpacity = MochiKit.Style.getStyle(innerelement, 'opacity') || 1.0;
new v.Opacity(innerelement, {duration:0.2, from:this._savedOpacity, to:0.7});
},
/** @id MochiKit.DragAndDrop.reverteffect */
reverteffect: function (innerelement, top_offset, left_offset) {
var dur = Math.sqrt(Math.abs(top_offset^2) +
Math.abs(left_offset^2))*0.02;
return new v.Move(innerelement,
{x: -left_offset, y: -top_offset, duration: dur});
},
/** @id MochiKit.DragAndDrop.endeffect */
endeffect: function (innerelement) {
new v.Opacity(innerelement, {duration:0.2, from:0.7, to:this._savedOpacity});
},
/** @id MochiKit.DragAndDrop.onchange */
onchange: b.noop,
/** @id MochiKit.DragAndDrop.zindex */
zindex: 1000,
/** @id MochiKit.DragAndDrop.revert */
revert: false,
/** @id MochiKit.DragAndDrop.scroll */
scroll: false,
/** @id MochiKit.DragAndDrop.scrollSensitivity */
scrollSensitivity: 20,
/** @id MochiKit.DragAndDrop.scrollSpeed */
scrollSpeed: 15,
// false, or xy or [x, y] or function (x, y){return [x, y];}
/** @id MochiKit.DragAndDrop.snap */
snap: false
}, options);
var d = MochiKit.DOM;
this.element = d.getElement(element);
if (options.handle && (typeof(options.handle) == 'string')) {
this.handle = d.getFirstElementByTagAndClassName(null,
options.handle, this.element);
}
if (!this.handle) {
this.handle = d.getElement(options.handle);
}
if (!this.handle) {
this.handle = this.element;
}
if (options.scroll && !options.scroll.scrollTo && !options.scroll.outerHTML) {
options.scroll = d.getElement(options.scroll);
this._isScrollChild = MochiKit.DOM.isChildNode(this.element, options.scroll);
}
MochiKit.Style.makePositioned(this.element); // fix IE
this.delta = this.currentDelta();
this.options = options;
this.dragging = false;
this.eventMouseDown = MochiKit.Signal.connect(this.handle,
'onmousedown', this, this.initDrag);
MochiKit.DragAndDrop.Draggables.register(this);
},
/** @id MochiKit.DragAndDrop.destroy */
destroy: function () {
MochiKit.Signal.disconnect(this.eventMouseDown);
MochiKit.DragAndDrop.Draggables.unregister(this);
},
/** @id MochiKit.DragAndDrop.currentDelta */
currentDelta: function () {
var s = MochiKit.Style.getStyle;
return [
parseInt(s(this.element, 'left') || '0'),
parseInt(s(this.element, 'top') || '0')];
},
/** @id MochiKit.DragAndDrop.initDrag */
initDrag: function (event) {
if (!event.mouse().button.left) {
return;
}
// abort on form elements, fixes a Firefox issue
var src = event.target();
var tagName = (src.tagName || '').toUpperCase();
if (tagName === 'INPUT' || tagName === 'SELECT' ||
tagName === 'OPTION' || tagName === 'BUTTON' ||
tagName === 'TEXTAREA') {
return;
}
if (this._revert) {
this._revert.cancel();
this._revert = null;
}
var pointer = event.mouse();
var pos = MochiKit.Position.cumulativeOffset(this.element);
this.offset = [pointer.page.x - pos.x, pointer.page.y - pos.y];
MochiKit.DragAndDrop.Draggables.activate(this);
event.stop();
},
/** @id MochiKit.DragAndDrop.startDrag */
startDrag: function (event) {
this.dragging = true;
if (this.options.selectclass) {
MochiKit.DOM.addElementClass(this.element,
this.options.selectclass);
}
if (this.options.zindex) {
this.originalZ = parseInt(MochiKit.Style.getStyle(this.element,
'z-index') || '0');
this.element.style.zIndex = this.options.zindex;
}
if (this.options.ghosting) {
this._clone = this.element.cloneNode(true);
this.ghostPosition = MochiKit.Position.absolutize(this.element);
this.element.parentNode.insertBefore(this._clone, this.element);
}
if (this.options.scroll) {
if (this.options.scroll == window) {
var where = this._getWindowScroll(this.options.scroll);
this.originalScrollLeft = where.left;
this.originalScrollTop = where.top;
} else {
this.originalScrollLeft = this.options.scroll.scrollLeft;
this.originalScrollTop = this.options.scroll.scrollTop;
}
}
MochiKit.DragAndDrop.Droppables.prepare(this.element);
MochiKit.DragAndDrop.Draggables.notify('start', this, event);
if (this.options.starteffect) {
this.options.starteffect(this.element);
}
},
/** @id MochiKit.DragAndDrop.updateDrag */
updateDrag: function (event, pointer) {
if (!this.dragging) {
this.startDrag(event);
}
MochiKit.Position.prepare();
MochiKit.DragAndDrop.Droppables.show(pointer, this.element);
MochiKit.DragAndDrop.Draggables.notify('drag', this, event);
this.draw(pointer);
this.options.onchange(this);
if (this.options.scroll) {
this.stopScrolling();
var p, q;
if (this.options.scroll == window) {
var s = this._getWindowScroll(this.options.scroll);
p = new MochiKit.Style.Coordinates(s.left, s.top);
q = new MochiKit.Style.Coordinates(s.left + s.width,
s.top + s.height);
} else {
p = MochiKit.Position.page(this.options.scroll);
p.x += this.options.scroll.scrollLeft;
p.y += this.options.scroll.scrollTop;
p.x += (window.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft || 0);
p.y += (window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop || 0);
q = new MochiKit.Style.Coordinates(p.x + this.options.scroll.offsetWidth,
p.y + this.options.scroll.offsetHeight);
}
var speed = [0, 0];
if (pointer.page.x > (q.x - this.options.scrollSensitivity)) {
speed[0] = pointer.page.x - (q.x - this.options.scrollSensitivity);
} else if (pointer.page.x < (p.x + this.options.scrollSensitivity)) {
speed[0] = pointer.page.x - (p.x + this.options.scrollSensitivity);
}
if (pointer.page.y > (q.y - this.options.scrollSensitivity)) {
speed[1] = pointer.page.y - (q.y - this.options.scrollSensitivity);
} else if (pointer.page.y < (p.y + this.options.scrollSensitivity)) {
speed[1] = pointer.page.y - (p.y + this.options.scrollSensitivity);
}
this.startScrolling(speed);
}
// fix AppleWebKit rendering
if (/AppleWebKit/.test(navigator.appVersion)) {
window.scrollBy(0, 0);
}
event.stop();
},
/** @id MochiKit.DragAndDrop.finishDrag */
finishDrag: function (event, success) {
var dr = MochiKit.DragAndDrop;
this.dragging = false;
if (this.options.selectclass) {
MochiKit.DOM.removeElementClass(this.element,
this.options.selectclass);
}
if (this.options.ghosting) {
// XXX: from a user point of view, it would be better to remove
// the node only *after* the MochiKit.Visual.Move end when used
// with revert.
MochiKit.Position.relativize(this.element, this.ghostPosition);
MochiKit.DOM.removeElement(this._clone);
this._clone = null;
}
if (success) {
dr.Droppables.fire(event, this.element);
}
dr.Draggables.notify('end', this, event);
var revert = this.options.revert;
if (revert && typeof(revert) == 'function') {
revert = revert(this.element);
}
var d = this.currentDelta();
if (revert && this.options.reverteffect) {
this._revert = this.options.reverteffect(this.element,
d[1] - this.delta[1], d[0] - this.delta[0]);
} else {
this.delta = d;
}
if (this.options.zindex) {
this.element.style.zIndex = this.originalZ;
}
if (this.options.endeffect) {
this.options.endeffect(this.element);
}
dr.Draggables.deactivate();
dr.Droppables.reset(this.element);
},
/** @id MochiKit.DragAndDrop.keyPress */
keyPress: function (event) {
if (event.key().string != "KEY_ESCAPE") {
return;
}
this.finishDrag(event, false);
event.stop();
},
/** @id MochiKit.DragAndDrop.endDrag */
endDrag: function (event) {
if (!this.dragging) {
return;
}
this.stopScrolling();
this.finishDrag(event, true);
event.stop();
},
/** @id MochiKit.DragAndDrop.draw */
draw: function (point) {
var pos = MochiKit.Position.cumulativeOffset(this.element);
var d = this.currentDelta();
pos.x -= d[0];
pos.y -= d[1];
if (this.options.scroll && (this.options.scroll != window && this._isScrollChild)) {
pos.x -= this.options.scroll.scrollLeft - this.originalScrollLeft;
pos.y -= this.options.scroll.scrollTop - this.originalScrollTop;
}
var p = [point.page.x - pos.x - this.offset[0],
point.page.y - pos.y - this.offset[1]];
if (this.options.snap) {
if (typeof(this.options.snap) == 'function') {
p = this.options.snap(p[0], p[1]);
} else {
if (this.options.snap instanceof Array) {
var i = -1;
p = MochiKit.Base.map(MochiKit.Base.bind(function (v) {
i += 1;
return Math.round(v/this.options.snap[i]) *
this.options.snap[i];
}, this), p);
} else {
p = MochiKit.Base.map(MochiKit.Base.bind(function (v) {
return Math.round(v/this.options.snap) *
this.options.snap;
}, this), p);
}
}
}
var style = this.element.style;
if ((!this.options.constraint) ||
(this.options.constraint == 'horizontal')) {
style.left = p[0] + 'px';
}
if ((!this.options.constraint) ||
(this.options.constraint == 'vertical')) {
style.top = p[1] + 'px';
}
if (style.visibility == 'hidden') {
style.visibility = ''; // fix gecko rendering
}
},
/** @id MochiKit.DragAndDrop.stopScrolling */
stopScrolling: function () {
if (this.scrollInterval) {
clearInterval(this.scrollInterval);
this.scrollInterval = null;
MochiKit.DragAndDrop.Draggables._lastScrollPointer = null;
}
},
/** @id MochiKit.DragAndDrop.startScrolling */
startScrolling: function (speed) {
if (!speed[0] && !speed[1]) {
return;
}
this.scrollSpeed = [speed[0] * this.options.scrollSpeed,
speed[1] * this.options.scrollSpeed];
this.lastScrolled = new Date();
this.scrollInterval = setInterval(MochiKit.Base.bind(this.scroll, this), 10);
},
/** @id MochiKit.DragAndDrop.scroll */
scroll: function () {
var current = new Date();
var delta = current - this.lastScrolled;
this.lastScrolled = current;
if (this.options.scroll == window) {
var s = this._getWindowScroll(this.options.scroll);
if (this.scrollSpeed[0] || this.scrollSpeed[1]) {
var dm = delta / 1000;
this.options.scroll.scrollTo(s.left + dm * this.scrollSpeed[0],
s.top + dm * this.scrollSpeed[1]);
}
} else {
this.options.scroll.scrollLeft += this.scrollSpeed[0] * delta / 1000;
this.options.scroll.scrollTop += this.scrollSpeed[1] * delta / 1000;
}
var d = MochiKit.DragAndDrop;
MochiKit.Position.prepare();
d.Droppables.show(d.Draggables._lastPointer, this.element);
d.Draggables.notify('drag', this);
if (this._isScrollChild) {
d.Draggables._lastScrollPointer = d.Draggables._lastScrollPointer || d.Draggables._lastPointer;
d.Draggables._lastScrollPointer.x += this.scrollSpeed[0] * delta / 1000;
d.Draggables._lastScrollPointer.y += this.scrollSpeed[1] * delta / 1000;
if (d.Draggables._lastScrollPointer.x < 0) {
d.Draggables._lastScrollPointer.x = 0;
}
if (d.Draggables._lastScrollPointer.y < 0) {
d.Draggables._lastScrollPointer.y = 0;
}
this.draw(d.Draggables._lastScrollPointer);
}
this.options.onchange(this);
},
_getWindowScroll: function (win) {
var vp, w, h;
MochiKit.DOM.withWindow(win, function () {
vp = MochiKit.Style.getViewportPosition(win.document);
});
if (win.innerWidth) {
w = win.innerWidth;
h = win.innerHeight;
} else if (win.document.documentElement && win.document.documentElement.clientWidth) {
w = win.document.documentElement.clientWidth;
h = win.document.documentElement.clientHeight;
} else {
w = win.document.body.offsetWidth;
h = win.document.body.offsetHeight;
}
return {top: vp.y, left: vp.x, width: w, height: h};
},
/** @id MochiKit.DragAndDrop.repr */
repr: function () {
return '[' + this.__class__.NAME + ", options:" + MochiKit.Base.repr(this.options) + "]";
}
};
MochiKit.DragAndDrop.__new__ = function () {
MochiKit.Base.nameFunctions(this);
this.EXPORT_TAGS = {
":common": this.EXPORT,
":all": MochiKit.Base.concat(this.EXPORT, this.EXPORT_OK)
};
};
MochiKit.DragAndDrop.__new__();
MochiKit.Base._exportSymbols(this, MochiKit.DragAndDrop);
-304
View File
@@ -1,304 +0,0 @@
/***
MochiKit.Format 1.4.2
See <http://mochikit.com/> for documentation, downloads, license, etc.
(c) 2005 Bob Ippolito. All rights Reserved.
***/
MochiKit.Base._deps('Format', ['Base']);
MochiKit.Format.NAME = "MochiKit.Format";
MochiKit.Format.VERSION = "1.4.2";
MochiKit.Format.__repr__ = function () {
return "[" + this.NAME + " " + this.VERSION + "]";
};
MochiKit.Format.toString = function () {
return this.__repr__();
};
MochiKit.Format._numberFormatter = function (placeholder, header, footer, locale, isPercent, precision, leadingZeros, separatorAt, trailingZeros) {
return function (num) {
num = parseFloat(num);
if (typeof(num) == "undefined" || num === null || isNaN(num)) {
return placeholder;
}
var curheader = header;
var curfooter = footer;
if (num < 0) {
num = -num;
} else {
curheader = curheader.replace(/-/, "");
}
var me = arguments.callee;
var fmt = MochiKit.Format.formatLocale(locale);
if (isPercent) {
num = num * 100.0;
curfooter = fmt.percent + curfooter;
}
num = MochiKit.Format.roundToFixed(num, precision);
var parts = num.split(/\./);
var whole = parts[0];
var frac = (parts.length == 1) ? "" : parts[1];
var res = "";
while (whole.length < leadingZeros) {
whole = "0" + whole;
}
if (separatorAt) {
while (whole.length > separatorAt) {
var i = whole.length - separatorAt;
//res = res + fmt.separator + whole.substring(i, whole.length);
res = fmt.separator + whole.substring(i, whole.length) + res;
whole = whole.substring(0, i);
}
}
res = whole + res;
if (precision > 0) {
while (frac.length < trailingZeros) {
frac = frac + "0";
}
res = res + fmt.decimal + frac;
}
return curheader + res + curfooter;
};
};
/** @id MochiKit.Format.numberFormatter */
MochiKit.Format.numberFormatter = function (pattern, placeholder/* = "" */, locale/* = "default" */) {
// http://java.sun.com/docs/books/tutorial/i18n/format/numberpattern.html
// | 0 | leading or trailing zeros
// | # | just the number
// | , | separator
// | . | decimal separator
// | % | Multiply by 100 and format as percent
if (typeof(placeholder) == "undefined") {
placeholder = "";
}
var match = pattern.match(/((?:[0#]+,)?[0#]+)(?:\.([0#]+))?(%)?/);
if (!match) {
throw TypeError("Invalid pattern");
}
var header = pattern.substr(0, match.index);
var footer = pattern.substr(match.index + match[0].length);
if (header.search(/-/) == -1) {
header = header + "-";
}
var whole = match[1];
var frac = (typeof(match[2]) == "string" && match[2] != "") ? match[2] : "";
var isPercent = (typeof(match[3]) == "string" && match[3] != "");
var tmp = whole.split(/,/);
var separatorAt;
if (typeof(locale) == "undefined") {
locale = "default";
}
if (tmp.length == 1) {
separatorAt = null;
} else {
separatorAt = tmp[1].length;
}
var leadingZeros = whole.length - whole.replace(/0/g, "").length;
var trailingZeros = frac.length - frac.replace(/0/g, "").length;
var precision = frac.length;
var rval = MochiKit.Format._numberFormatter(
placeholder, header, footer, locale, isPercent, precision,
leadingZeros, separatorAt, trailingZeros
);
var m = MochiKit.Base;
if (m) {
var fn = arguments.callee;
var args = m.concat(arguments);
rval.repr = function () {
return [
self.NAME,
"(",
map(m.repr, args).join(", "),
")"
].join("");
};
}
return rval;
};
/** @id MochiKit.Format.formatLocale */
MochiKit.Format.formatLocale = function (locale) {
if (typeof(locale) == "undefined" || locale === null) {
locale = "default";
}
if (typeof(locale) == "string") {
var rval = MochiKit.Format.LOCALE[locale];
if (typeof(rval) == "string") {
rval = arguments.callee(rval);
MochiKit.Format.LOCALE[locale] = rval;
}
return rval;
} else {
return locale;
}
};
/** @id MochiKit.Format.twoDigitAverage */
MochiKit.Format.twoDigitAverage = function (numerator, denominator) {
if (denominator) {
var res = numerator / denominator;
if (!isNaN(res)) {
return MochiKit.Format.twoDigitFloat(res);
}
}
return "0";
};
/** @id MochiKit.Format.twoDigitFloat */
MochiKit.Format.twoDigitFloat = function (aNumber) {
var res = roundToFixed(aNumber, 2);
if (res.indexOf(".00") > 0) {
return res.substring(0, res.length - 3);
} else if (res.charAt(res.length - 1) == "0") {
return res.substring(0, res.length - 1);
} else {
return res;
}
};
/** @id MochiKit.Format.lstrip */
MochiKit.Format.lstrip = function (str, /* optional */chars) {
str = str + "";
if (typeof(str) != "string") {
return null;
}
if (!chars) {
return str.replace(/^\s+/, "");
} else {
return str.replace(new RegExp("^[" + chars + "]+"), "");
}
};
/** @id MochiKit.Format.rstrip */
MochiKit.Format.rstrip = function (str, /* optional */chars) {
str = str + "";
if (typeof(str) != "string") {
return null;
}
if (!chars) {
return str.replace(/\s+$/, "");
} else {
return str.replace(new RegExp("[" + chars + "]+$"), "");
}
};
/** @id MochiKit.Format.strip */
MochiKit.Format.strip = function (str, /* optional */chars) {
var self = MochiKit.Format;
return self.rstrip(self.lstrip(str, chars), chars);
};
/** @id MochiKit.Format.truncToFixed */
MochiKit.Format.truncToFixed = function (aNumber, precision) {
var res = Math.floor(aNumber).toFixed(0);
if (aNumber < 0) {
res = Math.ceil(aNumber).toFixed(0);
if (res.charAt(0) != "-" && precision > 0) {
res = "-" + res;
}
}
if (res.indexOf("e") < 0 && precision > 0) {
var tail = aNumber.toString();
if (tail.indexOf("e") > 0) {
tail = ".";
} else if (tail.indexOf(".") < 0) {
tail = ".";
} else {
tail = tail.substring(tail.indexOf("."));
}
if (tail.length - 1 > precision) {
tail = tail.substring(0, precision + 1);
}
while (tail.length - 1 < precision) {
tail += "0";
}
res += tail;
}
return res;
};
/** @id MochiKit.Format.roundToFixed */
MochiKit.Format.roundToFixed = function (aNumber, precision) {
var upper = Math.abs(aNumber) + 0.5 * Math.pow(10, -precision);
var res = MochiKit.Format.truncToFixed(upper, precision);
if (aNumber < 0) {
res = "-" + res;
}
return res;
};
/** @id MochiKit.Format.percentFormat */
MochiKit.Format.percentFormat = function (aNumber) {
return MochiKit.Format.twoDigitFloat(100 * aNumber) + '%';
};
MochiKit.Format.EXPORT = [
"truncToFixed",
"roundToFixed",
"numberFormatter",
"formatLocale",
"twoDigitAverage",
"twoDigitFloat",
"percentFormat",
"lstrip",
"rstrip",
"strip"
];
MochiKit.Format.LOCALE = {
en_US: {separator: ",", decimal: ".", percent: "%"},
de_DE: {separator: ".", decimal: ",", percent: "%"},
pt_BR: {separator: ".", decimal: ",", percent: "%"},
fr_FR: {separator: " ", decimal: ",", percent: "%"},
"default": "en_US"
};
MochiKit.Format.EXPORT_OK = [];
MochiKit.Format.EXPORT_TAGS = {
':all': MochiKit.Format.EXPORT,
':common': MochiKit.Format.EXPORT
};
MochiKit.Format.__new__ = function () {
// MochiKit.Base.nameFunctions(this);
var base = this.NAME + ".";
var k, v, o;
for (k in this.LOCALE) {
o = this.LOCALE[k];
if (typeof(o) == "object") {
o.repr = function () { return this.NAME; };
o.NAME = base + "LOCALE." + k;
}
}
for (k in this) {
o = this[k];
if (typeof(o) == 'function' && typeof(o.NAME) == 'undefined') {
try {
o.NAME = base + k;
} catch (e) {
// pass
}
}
}
};
MochiKit.Format.__new__();
if (typeof(MochiKit.Base) != "undefined") {
MochiKit.Base._exportSymbols(this, MochiKit.Format);
} else {
(function (globals, module) {
if ((typeof(JSAN) == 'undefined' && typeof(dojo) == 'undefined')
|| (MochiKit.__export__ === false)) {
var all = module.EXPORT_TAGS[":all"];
for (var i = 0; i < all.length; i++) {
globals[all[i]] = module[all[i]];
}
}
})(this, MochiKit.Format);
}
-844
View File
@@ -1,844 +0,0 @@
/***
MochiKit.Iter 1.4.2
See <http://mochikit.com/> for documentation, downloads, license, etc.
(c) 2005 Bob Ippolito. All rights Reserved.
***/
MochiKit.Base._deps('Iter', ['Base']);
MochiKit.Iter.NAME = "MochiKit.Iter";
MochiKit.Iter.VERSION = "1.4.2";
MochiKit.Base.update(MochiKit.Iter, {
__repr__: function () {
return "[" + this.NAME + " " + this.VERSION + "]";
},
toString: function () {
return this.__repr__();
},
/** @id MochiKit.Iter.registerIteratorFactory */
registerIteratorFactory: function (name, check, iterfactory, /* optional */ override) {
MochiKit.Iter.iteratorRegistry.register(name, check, iterfactory, override);
},
/** @id MochiKit.Iter.isIterable */
isIterable: function(o) {
return o != null &&
(typeof(o.next) == "function" || typeof(o.iter) == "function");
},
/** @id MochiKit.Iter.iter */
iter: function (iterable, /* optional */ sentinel) {
var self = MochiKit.Iter;
if (arguments.length == 2) {
return self.takewhile(
function (a) { return a != sentinel; },
iterable
);
}
if (typeof(iterable.next) == 'function') {
return iterable;
} else if (typeof(iterable.iter) == 'function') {
return iterable.iter();
/*
} else if (typeof(iterable.__iterator__) == 'function') {
//
// XXX: We can't support JavaScript 1.7 __iterator__ directly
// because of Object.prototype.__iterator__
//
return iterable.__iterator__();
*/
}
try {
return self.iteratorRegistry.match(iterable);
} catch (e) {
var m = MochiKit.Base;
if (e == m.NotFound) {
e = new TypeError(typeof(iterable) + ": " + m.repr(iterable) + " is not iterable");
}
throw e;
}
},
/** @id MochiKit.Iter.count */
count: function (n) {
if (!n) {
n = 0;
}
var m = MochiKit.Base;
return {
repr: function () { return "count(" + n + ")"; },
toString: m.forwardCall("repr"),
next: m.counter(n)
};
},
/** @id MochiKit.Iter.cycle */
cycle: function (p) {
var self = MochiKit.Iter;
var m = MochiKit.Base;
var lst = [];
var iterator = self.iter(p);
return {
repr: function () { return "cycle(...)"; },
toString: m.forwardCall("repr"),
next: function () {
try {
var rval = iterator.next();
lst.push(rval);
return rval;
} catch (e) {
if (e != self.StopIteration) {
throw e;
}
if (lst.length === 0) {
this.next = function () {
throw self.StopIteration;
};
} else {
var i = -1;
this.next = function () {
i = (i + 1) % lst.length;
return lst[i];
};
}
return this.next();
}
}
};
},
/** @id MochiKit.Iter.repeat */
repeat: function (elem, /* optional */n) {
var m = MochiKit.Base;
if (typeof(n) == 'undefined') {
return {
repr: function () {
return "repeat(" + m.repr(elem) + ")";
},
toString: m.forwardCall("repr"),
next: function () {
return elem;
}
};
}
return {
repr: function () {
return "repeat(" + m.repr(elem) + ", " + n + ")";
},
toString: m.forwardCall("repr"),
next: function () {
if (n <= 0) {
throw MochiKit.Iter.StopIteration;
}
n -= 1;
return elem;
}
};
},
/** @id MochiKit.Iter.next */
next: function (iterator) {
return iterator.next();
},
/** @id MochiKit.Iter.izip */
izip: function (p, q/*, ...*/) {
var m = MochiKit.Base;
var self = MochiKit.Iter;
var next = self.next;
var iterables = m.map(self.iter, arguments);
return {
repr: function () { return "izip(...)"; },
toString: m.forwardCall("repr"),
next: function () { return m.map(next, iterables); }
};
},
/** @id MochiKit.Iter.ifilter */
ifilter: function (pred, seq) {
var m = MochiKit.Base;
seq = MochiKit.Iter.iter(seq);
if (pred === null) {
pred = m.operator.truth;
}
return {
repr: function () { return "ifilter(...)"; },
toString: m.forwardCall("repr"),
next: function () {
while (true) {
var rval = seq.next();
if (pred(rval)) {
return rval;
}
}
// mozilla warnings aren't too bright
return undefined;
}
};
},
/** @id MochiKit.Iter.ifilterfalse */
ifilterfalse: function (pred, seq) {
var m = MochiKit.Base;
seq = MochiKit.Iter.iter(seq);
if (pred === null) {
pred = m.operator.truth;
}
return {
repr: function () { return "ifilterfalse(...)"; },
toString: m.forwardCall("repr"),
next: function () {
while (true) {
var rval = seq.next();
if (!pred(rval)) {
return rval;
}
}
// mozilla warnings aren't too bright
return undefined;
}
};
},
/** @id MochiKit.Iter.islice */
islice: function (seq/*, [start,] stop[, step] */) {
var self = MochiKit.Iter;
var m = MochiKit.Base;
seq = self.iter(seq);
var start = 0;
var stop = 0;
var step = 1;
var i = -1;
if (arguments.length == 2) {
stop = arguments[1];
} else if (arguments.length == 3) {
start = arguments[1];
stop = arguments[2];
} else {
start = arguments[1];
stop = arguments[2];
step = arguments[3];
}
return {
repr: function () {
return "islice(" + ["...", start, stop, step].join(", ") + ")";
},
toString: m.forwardCall("repr"),
next: function () {
var rval;
while (i < start) {
rval = seq.next();
i++;
}
if (start >= stop) {
throw self.StopIteration;
}
start += step;
return rval;
}
};
},
/** @id MochiKit.Iter.imap */
imap: function (fun, p, q/*, ...*/) {
var m = MochiKit.Base;
var self = MochiKit.Iter;
var iterables = m.map(self.iter, m.extend(null, arguments, 1));
var map = m.map;
var next = self.next;
return {
repr: function () { return "imap(...)"; },
toString: m.forwardCall("repr"),
next: function () {
return fun.apply(this, map(next, iterables));
}
};
},
/** @id MochiKit.Iter.applymap */
applymap: function (fun, seq, self) {
seq = MochiKit.Iter.iter(seq);
var m = MochiKit.Base;
return {
repr: function () { return "applymap(...)"; },
toString: m.forwardCall("repr"),
next: function () {
return fun.apply(self, seq.next());
}
};
},
/** @id MochiKit.Iter.chain */
chain: function (p, q/*, ...*/) {
// dumb fast path
var self = MochiKit.Iter;
var m = MochiKit.Base;
if (arguments.length == 1) {
return self.iter(arguments[0]);
}
var argiter = m.map(self.iter, arguments);
return {
repr: function () { return "chain(...)"; },
toString: m.forwardCall("repr"),
next: function () {
while (argiter.length > 1) {
try {
var result = argiter[0].next();
return result;
} catch (e) {
if (e != self.StopIteration) {
throw e;
}
argiter.shift();
var result = argiter[0].next();
return result;
}
}
if (argiter.length == 1) {
// optimize last element
var arg = argiter.shift();
this.next = m.bind("next", arg);
return this.next();
}
throw self.StopIteration;
}
};
},
/** @id MochiKit.Iter.takewhile */
takewhile: function (pred, seq) {
var self = MochiKit.Iter;
seq = self.iter(seq);
return {
repr: function () { return "takewhile(...)"; },
toString: MochiKit.Base.forwardCall("repr"),
next: function () {
var rval = seq.next();
if (!pred(rval)) {
this.next = function () {
throw self.StopIteration;
};
this.next();
}
return rval;
}
};
},
/** @id MochiKit.Iter.dropwhile */
dropwhile: function (pred, seq) {
seq = MochiKit.Iter.iter(seq);
var m = MochiKit.Base;
var bind = m.bind;
return {
"repr": function () { return "dropwhile(...)"; },
"toString": m.forwardCall("repr"),
"next": function () {
while (true) {
var rval = seq.next();
if (!pred(rval)) {
break;
}
}
this.next = bind("next", seq);
return rval;
}
};
},
_tee: function (ident, sync, iterable) {
sync.pos[ident] = -1;
var m = MochiKit.Base;
var listMin = m.listMin;
return {
repr: function () { return "tee(" + ident + ", ...)"; },
toString: m.forwardCall("repr"),
next: function () {
var rval;
var i = sync.pos[ident];
if (i == sync.max) {
rval = iterable.next();
sync.deque.push(rval);
sync.max += 1;
sync.pos[ident] += 1;
} else {
rval = sync.deque[i - sync.min];
sync.pos[ident] += 1;
if (i == sync.min && listMin(sync.pos) != sync.min) {
sync.min += 1;
sync.deque.shift();
}
}
return rval;
}
};
},
/** @id MochiKit.Iter.tee */
tee: function (iterable, n/* = 2 */) {
var rval = [];
var sync = {
"pos": [],
"deque": [],
"max": -1,
"min": -1
};
if (arguments.length == 1 || typeof(n) == "undefined" || n === null) {
n = 2;
}
var self = MochiKit.Iter;
iterable = self.iter(iterable);
var _tee = self._tee;
for (var i = 0; i < n; i++) {
rval.push(_tee(i, sync, iterable));
}
return rval;
},
/** @id MochiKit.Iter.list */
list: function (iterable) {
// Fast-path for Array and Array-like
var rval;
if (iterable instanceof Array) {
return iterable.slice();
}
// this is necessary to avoid a Safari crash
if (typeof(iterable) == "function" &&
!(iterable instanceof Function) &&
typeof(iterable.length) == 'number') {
rval = [];
for (var i = 0; i < iterable.length; i++) {
rval.push(iterable[i]);
}
return rval;
}
var self = MochiKit.Iter;
iterable = self.iter(iterable);
var rval = [];
var a_val;
try {
while (true) {
a_val = iterable.next();
rval.push(a_val);
}
} catch (e) {
if (e != self.StopIteration) {
throw e;
}
return rval;
}
// mozilla warnings aren't too bright
return undefined;
},
/** @id MochiKit.Iter.reduce */
reduce: function (fn, iterable, /* optional */initial) {
var i = 0;
var x = initial;
var self = MochiKit.Iter;
iterable = self.iter(iterable);
if (arguments.length < 3) {
try {
x = iterable.next();
} catch (e) {
if (e == self.StopIteration) {
e = new TypeError("reduce() of empty sequence with no initial value");
}
throw e;
}
i++;
}
try {
while (true) {
x = fn(x, iterable.next());
}
} catch (e) {
if (e != self.StopIteration) {
throw e;
}
}
return x;
},
/** @id MochiKit.Iter.range */
range: function (/* [start,] stop[, step] */) {
var start = 0;
var stop = 0;
var step = 1;
if (arguments.length == 1) {
stop = arguments[0];
} else if (arguments.length == 2) {
start = arguments[0];
stop = arguments[1];
} else if (arguments.length == 3) {
start = arguments[0];
stop = arguments[1];
step = arguments[2];
} else {
throw new TypeError("range() takes 1, 2, or 3 arguments!");
}
if (step === 0) {
throw new TypeError("range() step must not be 0");
}
return {
next: function () {
if ((step > 0 && start >= stop) || (step < 0 && start <= stop)) {
throw MochiKit.Iter.StopIteration;
}
var rval = start;
start += step;
return rval;
},
repr: function () {
return "range(" + [start, stop, step].join(", ") + ")";
},
toString: MochiKit.Base.forwardCall("repr")
};
},
/** @id MochiKit.Iter.sum */
sum: function (iterable, start/* = 0 */) {
if (typeof(start) == "undefined" || start === null) {
start = 0;
}
var x = start;
var self = MochiKit.Iter;
iterable = self.iter(iterable);
try {
while (true) {
x += iterable.next();
}
} catch (e) {
if (e != self.StopIteration) {
throw e;
}
}
return x;
},
/** @id MochiKit.Iter.exhaust */
exhaust: function (iterable) {
var self = MochiKit.Iter;
iterable = self.iter(iterable);
try {
while (true) {
iterable.next();
}
} catch (e) {
if (e != self.StopIteration) {
throw e;
}
}
},
/** @id MochiKit.Iter.forEach */
forEach: function (iterable, func, /* optional */obj) {
var m = MochiKit.Base;
var self = MochiKit.Iter;
if (arguments.length > 2) {
func = m.bind(func, obj);
}
// fast path for array
if (m.isArrayLike(iterable) && !self.isIterable(iterable)) {
try {
for (var i = 0; i < iterable.length; i++) {
func(iterable[i]);
}
} catch (e) {
if (e != self.StopIteration) {
throw e;
}
}
} else {
self.exhaust(self.imap(func, iterable));
}
},
/** @id MochiKit.Iter.every */
every: function (iterable, func) {
var self = MochiKit.Iter;
try {
self.ifilterfalse(func, iterable).next();
return false;
} catch (e) {
if (e != self.StopIteration) {
throw e;
}
return true;
}
},
/** @id MochiKit.Iter.sorted */
sorted: function (iterable, /* optional */cmp) {
var rval = MochiKit.Iter.list(iterable);
if (arguments.length == 1) {
cmp = MochiKit.Base.compare;
}
rval.sort(cmp);
return rval;
},
/** @id MochiKit.Iter.reversed */
reversed: function (iterable) {
var rval = MochiKit.Iter.list(iterable);
rval.reverse();
return rval;
},
/** @id MochiKit.Iter.some */
some: function (iterable, func) {
var self = MochiKit.Iter;
try {
self.ifilter(func, iterable).next();
return true;
} catch (e) {
if (e != self.StopIteration) {
throw e;
}
return false;
}
},
/** @id MochiKit.Iter.iextend */
iextend: function (lst, iterable) {
var m = MochiKit.Base;
var self = MochiKit.Iter;
if (m.isArrayLike(iterable) && !self.isIterable(iterable)) {
// fast-path for array-like
for (var i = 0; i < iterable.length; i++) {
lst.push(iterable[i]);
}
} else {
iterable = self.iter(iterable);
try {
while (true) {
lst.push(iterable.next());
}
} catch (e) {
if (e != self.StopIteration) {
throw e;
}
}
}
return lst;
},
/** @id MochiKit.Iter.groupby */
groupby: function(iterable, /* optional */ keyfunc) {
var m = MochiKit.Base;
var self = MochiKit.Iter;
if (arguments.length < 2) {
keyfunc = m.operator.identity;
}
iterable = self.iter(iterable);
// shared
var pk = undefined;
var k = undefined;
var v;
function fetch() {
v = iterable.next();
k = keyfunc(v);
};
function eat() {
var ret = v;
v = undefined;
return ret;
};
var first = true;
var compare = m.compare;
return {
repr: function () { return "groupby(...)"; },
next: function() {
// iterator-next
// iterate until meet next group
while (compare(k, pk) === 0) {
fetch();
if (first) {
first = false;
break;
}
}
pk = k;
return [k, {
next: function() {
// subiterator-next
if (v == undefined) { // Is there something to eat?
fetch();
}
if (compare(k, pk) !== 0) {
throw self.StopIteration;
}
return eat();
}
}];
}
};
},
/** @id MochiKit.Iter.groupby_as_array */
groupby_as_array: function (iterable, /* optional */ keyfunc) {
var m = MochiKit.Base;
var self = MochiKit.Iter;
if (arguments.length < 2) {
keyfunc = m.operator.identity;
}
iterable = self.iter(iterable);
var result = [];
var first = true;
var prev_key;
var compare = m.compare;
while (true) {
try {
var value = iterable.next();
var key = keyfunc(value);
} catch (e) {
if (e == self.StopIteration) {
break;
}
throw e;
}
if (first || compare(key, prev_key) !== 0) {
var values = [];
result.push([key, values]);
}
values.push(value);
first = false;
prev_key = key;
}
return result;
},
/** @id MochiKit.Iter.arrayLikeIter */
arrayLikeIter: function (iterable) {
var i = 0;
return {
repr: function () { return "arrayLikeIter(...)"; },
toString: MochiKit.Base.forwardCall("repr"),
next: function () {
if (i >= iterable.length) {
throw MochiKit.Iter.StopIteration;
}
return iterable[i++];
}
};
},
/** @id MochiKit.Iter.hasIterateNext */
hasIterateNext: function (iterable) {
return (iterable && typeof(iterable.iterateNext) == "function");
},
/** @id MochiKit.Iter.iterateNextIter */
iterateNextIter: function (iterable) {
return {
repr: function () { return "iterateNextIter(...)"; },
toString: MochiKit.Base.forwardCall("repr"),
next: function () {
var rval = iterable.iterateNext();
if (rval === null || rval === undefined) {
throw MochiKit.Iter.StopIteration;
}
return rval;
}
};
}
});
MochiKit.Iter.EXPORT_OK = [
"iteratorRegistry",
"arrayLikeIter",
"hasIterateNext",
"iterateNextIter"
];
MochiKit.Iter.EXPORT = [
"StopIteration",
"registerIteratorFactory",
"iter",
"count",
"cycle",
"repeat",
"next",
"izip",
"ifilter",
"ifilterfalse",
"islice",
"imap",
"applymap",
"chain",
"takewhile",
"dropwhile",
"tee",
"list",
"reduce",
"range",
"sum",
"exhaust",
"forEach",
"every",
"sorted",
"reversed",
"some",
"iextend",
"groupby",
"groupby_as_array"
];
MochiKit.Iter.__new__ = function () {
var m = MochiKit.Base;
// Re-use StopIteration if exists (e.g. SpiderMonkey)
if (typeof(StopIteration) != "undefined") {
this.StopIteration = StopIteration;
} else {
/** @id MochiKit.Iter.StopIteration */
this.StopIteration = new m.NamedError("StopIteration");
}
this.iteratorRegistry = new m.AdapterRegistry();
// Register the iterator factory for arrays
this.registerIteratorFactory(
"arrayLike",
m.isArrayLike,
this.arrayLikeIter
);
this.registerIteratorFactory(
"iterateNext",
this.hasIterateNext,
this.iterateNextIter
);
this.EXPORT_TAGS = {
":common": this.EXPORT,
":all": m.concat(this.EXPORT, this.EXPORT_OK)
};
m.nameFunctions(this);
};
MochiKit.Iter.__new__();
//
// XXX: Internet Explorer blows
//
if (MochiKit.__export__) {
reduce = MochiKit.Iter.reduce;
}
MochiKit.Base._exportSymbols(this, MochiKit.Iter);
-315
View File
@@ -1,315 +0,0 @@
/***
MochiKit.Logging 1.4.2
See <http://mochikit.com/> for documentation, downloads, license, etc.
(c) 2005 Bob Ippolito. All rights Reserved.
***/
MochiKit.Base._deps('Logging', ['Base']);
MochiKit.Logging.NAME = "MochiKit.Logging";
MochiKit.Logging.VERSION = "1.4.2";
MochiKit.Logging.__repr__ = function () {
return "[" + this.NAME + " " + this.VERSION + "]";
};
MochiKit.Logging.toString = function () {
return this.__repr__();
};
MochiKit.Logging.EXPORT = [
"LogLevel",
"LogMessage",
"Logger",
"alertListener",
"logger",
"log",
"logError",
"logDebug",
"logFatal",
"logWarning"
];
MochiKit.Logging.EXPORT_OK = [
"logLevelAtLeast",
"isLogMessage",
"compareLogMessage"
];
/** @id MochiKit.Logging.LogMessage */
MochiKit.Logging.LogMessage = function (num, level, info) {
this.num = num;
this.level = level;
this.info = info;
this.timestamp = new Date();
};
MochiKit.Logging.LogMessage.prototype = {
/** @id MochiKit.Logging.LogMessage.prototype.repr */
repr: function () {
var m = MochiKit.Base;
return 'LogMessage(' +
m.map(
m.repr,
[this.num, this.level, this.info]
).join(', ') + ')';
},
/** @id MochiKit.Logging.LogMessage.prototype.toString */
toString: MochiKit.Base.forwardCall("repr")
};
MochiKit.Base.update(MochiKit.Logging, {
/** @id MochiKit.Logging.logLevelAtLeast */
logLevelAtLeast: function (minLevel) {
var self = MochiKit.Logging;
if (typeof(minLevel) == 'string') {
minLevel = self.LogLevel[minLevel];
}
return function (msg) {
var msgLevel = msg.level;
if (typeof(msgLevel) == 'string') {
msgLevel = self.LogLevel[msgLevel];
}
return msgLevel >= minLevel;
};
},
/** @id MochiKit.Logging.isLogMessage */
isLogMessage: function (/* ... */) {
var LogMessage = MochiKit.Logging.LogMessage;
for (var i = 0; i < arguments.length; i++) {
if (!(arguments[i] instanceof LogMessage)) {
return false;
}
}
return true;
},
/** @id MochiKit.Logging.compareLogMessage */
compareLogMessage: function (a, b) {
return MochiKit.Base.compare([a.level, a.info], [b.level, b.info]);
},
/** @id MochiKit.Logging.alertListener */
alertListener: function (msg) {
alert(
"num: " + msg.num +
"\nlevel: " + msg.level +
"\ninfo: " + msg.info.join(" ")
);
}
});
/** @id MochiKit.Logging.Logger */
MochiKit.Logging.Logger = function (/* optional */maxSize) {
this.counter = 0;
if (typeof(maxSize) == 'undefined' || maxSize === null) {
maxSize = -1;
}
this.maxSize = maxSize;
this._messages = [];
this.listeners = {};
this.useNativeConsole = false;
};
MochiKit.Logging.Logger.prototype = {
/** @id MochiKit.Logging.Logger.prototype.clear */
clear: function () {
this._messages.splice(0, this._messages.length);
},
/** @id MochiKit.Logging.Logger.prototype.logToConsole */
logToConsole: function (msg) {
if (typeof(window) != "undefined" && window.console
&& window.console.log) {
// Safari and FireBug 0.4
// Percent replacement is a workaround for cute Safari crashing bug
window.console.log(msg.replace(/%/g, '\uFF05'));
} else if (typeof(opera) != "undefined" && opera.postError) {
// Opera
opera.postError(msg);
} else if (typeof(printfire) == "function") {
// FireBug 0.3 and earlier
printfire(msg);
} else if (typeof(Debug) != "undefined" && Debug.writeln) {
// IE Web Development Helper (?)
// http://www.nikhilk.net/Entry.aspx?id=93
Debug.writeln(msg);
} else if (typeof(debug) != "undefined" && debug.trace) {
// Atlas framework (?)
// http://www.nikhilk.net/Entry.aspx?id=93
debug.trace(msg);
}
},
/** @id MochiKit.Logging.Logger.prototype.dispatchListeners */
dispatchListeners: function (msg) {
for (var k in this.listeners) {
var pair = this.listeners[k];
if (pair.ident != k || (pair[0] && !pair[0](msg))) {
continue;
}
pair[1](msg);
}
},
/** @id MochiKit.Logging.Logger.prototype.addListener */
addListener: function (ident, filter, listener) {
if (typeof(filter) == 'string') {
filter = MochiKit.Logging.logLevelAtLeast(filter);
}
var entry = [filter, listener];
entry.ident = ident;
this.listeners[ident] = entry;
},
/** @id MochiKit.Logging.Logger.prototype.removeListener */
removeListener: function (ident) {
delete this.listeners[ident];
},
/** @id MochiKit.Logging.Logger.prototype.baseLog */
baseLog: function (level, message/*, ...*/) {
if (typeof(level) == "number") {
if (level >= MochiKit.Logging.LogLevel.FATAL) {
level = 'FATAL';
} else if (level >= MochiKit.Logging.LogLevel.ERROR) {
level = 'ERROR';
} else if (level >= MochiKit.Logging.LogLevel.WARNING) {
level = 'WARNING';
} else if (level >= MochiKit.Logging.LogLevel.INFO) {
level = 'INFO';
} else {
level = 'DEBUG';
}
}
var msg = new MochiKit.Logging.LogMessage(
this.counter,
level,
MochiKit.Base.extend(null, arguments, 1)
);
this._messages.push(msg);
this.dispatchListeners(msg);
if (this.useNativeConsole) {
this.logToConsole(msg.level + ": " + msg.info.join(" "));
}
this.counter += 1;
while (this.maxSize >= 0 && this._messages.length > this.maxSize) {
this._messages.shift();
}
},
/** @id MochiKit.Logging.Logger.prototype.getMessages */
getMessages: function (howMany) {
var firstMsg = 0;
if (!(typeof(howMany) == 'undefined' || howMany === null)) {
firstMsg = Math.max(0, this._messages.length - howMany);
}
return this._messages.slice(firstMsg);
},
/** @id MochiKit.Logging.Logger.prototype.getMessageText */
getMessageText: function (howMany) {
if (typeof(howMany) == 'undefined' || howMany === null) {
howMany = 30;
}
var messages = this.getMessages(howMany);
if (messages.length) {
var lst = map(function (m) {
return '\n [' + m.num + '] ' + m.level + ': ' + m.info.join(' ');
}, messages);
lst.unshift('LAST ' + messages.length + ' MESSAGES:');
return lst.join('');
}
return '';
},
/** @id MochiKit.Logging.Logger.prototype.debuggingBookmarklet */
debuggingBookmarklet: function (inline) {
if (typeof(MochiKit.LoggingPane) == "undefined") {
alert(this.getMessageText());
} else {
MochiKit.LoggingPane.createLoggingPane(inline || false);
}
}
};
MochiKit.Logging.__new__ = function () {
this.LogLevel = {
ERROR: 40,
FATAL: 50,
WARNING: 30,
INFO: 20,
DEBUG: 10
};
var m = MochiKit.Base;
m.registerComparator("LogMessage",
this.isLogMessage,
this.compareLogMessage
);
var partial = m.partial;
var Logger = this.Logger;
var baseLog = Logger.prototype.baseLog;
m.update(this.Logger.prototype, {
debug: partial(baseLog, 'DEBUG'),
log: partial(baseLog, 'INFO'),
error: partial(baseLog, 'ERROR'),
fatal: partial(baseLog, 'FATAL'),
warning: partial(baseLog, 'WARNING')
});
// indirectly find logger so it can be replaced
var self = this;
var connectLog = function (name) {
return function () {
self.logger[name].apply(self.logger, arguments);
};
};
/** @id MochiKit.Logging.log */
this.log = connectLog('log');
/** @id MochiKit.Logging.logError */
this.logError = connectLog('error');
/** @id MochiKit.Logging.logDebug */
this.logDebug = connectLog('debug');
/** @id MochiKit.Logging.logFatal */
this.logFatal = connectLog('fatal');
/** @id MochiKit.Logging.logWarning */
this.logWarning = connectLog('warning');
this.logger = new Logger();
this.logger.useNativeConsole = true;
this.EXPORT_TAGS = {
":common": this.EXPORT,
":all": m.concat(this.EXPORT, this.EXPORT_OK)
};
m.nameFunctions(this);
};
if (typeof(printfire) == "undefined" &&
typeof(document) != "undefined" && document.createEvent &&
typeof(dispatchEvent) != "undefined") {
// FireBug really should be less lame about this global function
printfire = function () {
printfire.args = arguments;
var ev = document.createEvent("Events");
ev.initEvent("printfire", false, true);
dispatchEvent(ev);
};
}
MochiKit.Logging.__new__();
MochiKit.Base._exportSymbols(this, MochiKit.Logging);
-353
View File
@@ -1,353 +0,0 @@
/***
MochiKit.LoggingPane 1.4.2
See <http://mochikit.com/> for documentation, downloads, license, etc.
(c) 2005 Bob Ippolito. All rights Reserved.
***/
MochiKit.Base._deps('LoggingPane', ['Base', 'Logging']);
MochiKit.LoggingPane.NAME = "MochiKit.LoggingPane";
MochiKit.LoggingPane.VERSION = "1.4.2";
MochiKit.LoggingPane.__repr__ = function () {
return "[" + this.NAME + " " + this.VERSION + "]";
};
MochiKit.LoggingPane.toString = function () {
return this.__repr__();
};
/** @id MochiKit.LoggingPane.createLoggingPane */
MochiKit.LoggingPane.createLoggingPane = function (inline/* = false */) {
var m = MochiKit.LoggingPane;
inline = !(!inline);
if (m._loggingPane && m._loggingPane.inline != inline) {
m._loggingPane.closePane();
m._loggingPane = null;
}
if (!m._loggingPane || m._loggingPane.closed) {
m._loggingPane = new m.LoggingPane(inline, MochiKit.Logging.logger);
}
return m._loggingPane;
};
/** @id MochiKit.LoggingPane.LoggingPane */
MochiKit.LoggingPane.LoggingPane = function (inline/* = false */, logger/* = MochiKit.Logging.logger */) {
/* Use a div if inline, pop up a window if not */
/* Create the elements */
if (typeof(logger) == "undefined" || logger === null) {
logger = MochiKit.Logging.logger;
}
this.logger = logger;
var update = MochiKit.Base.update;
var updatetree = MochiKit.Base.updatetree;
var bind = MochiKit.Base.bind;
var clone = MochiKit.Base.clone;
var win = window;
var uid = "_MochiKit_LoggingPane";
if (typeof(MochiKit.DOM) != "undefined") {
win = MochiKit.DOM.currentWindow();
}
if (!inline) {
// name the popup with the base URL for uniqueness
var url = win.location.href.split("?")[0].replace(/[#:\/.><&%-]/g, "_");
var name = uid + "_" + url;
var nwin = win.open("", name, "dependent,resizable,height=200");
if (!nwin) {
alert("Not able to open debugging window due to pop-up blocking.");
return undefined;
}
nwin.document.write(
'<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" '
+ '"http://www.w3.org/TR/html4/loose.dtd">'
+ '<html><head><title>[MochiKit.LoggingPane]</title></head>'
+ '<body></body></html>'
);
nwin.document.close();
nwin.document.title += ' ' + win.document.title;
win = nwin;
}
var doc = win.document;
this.doc = doc;
// Connect to the debug pane if it already exists (i.e. in a window orphaned by the page being refreshed)
var debugPane = doc.getElementById(uid);
var existing_pane = !!debugPane;
if (debugPane && typeof(debugPane.loggingPane) != "undefined") {
debugPane.loggingPane.logger = this.logger;
debugPane.loggingPane.buildAndApplyFilter();
return debugPane.loggingPane;
}
if (existing_pane) {
// clear any existing contents
var child;
while ((child = debugPane.firstChild)) {
debugPane.removeChild(child);
}
} else {
debugPane = doc.createElement("div");
debugPane.id = uid;
}
debugPane.loggingPane = this;
var levelFilterField = doc.createElement("input");
var infoFilterField = doc.createElement("input");
var filterButton = doc.createElement("button");
var loadButton = doc.createElement("button");
var clearButton = doc.createElement("button");
var closeButton = doc.createElement("button");
var logPaneArea = doc.createElement("div");
var logPane = doc.createElement("div");
/* Set up the functions */
var listenerId = uid + "_Listener";
this.colorTable = clone(this.colorTable);
var messages = [];
var messageFilter = null;
/** @id MochiKit.LoggingPane.messageLevel */
var messageLevel = function (msg) {
var level = msg.level;
if (typeof(level) == "number") {
level = MochiKit.Logging.LogLevel[level];
}
return level;
};
/** @id MochiKit.LoggingPane.messageText */
var messageText = function (msg) {
return msg.info.join(" ");
};
/** @id MochiKit.LoggingPane.addMessageText */
var addMessageText = bind(function (msg) {
var level = messageLevel(msg);
var text = messageText(msg);
var c = this.colorTable[level];
var p = doc.createElement("span");
p.className = "MochiKit-LogMessage MochiKit-LogLevel-" + level;
p.style.cssText = "margin: 0px; white-space: -moz-pre-wrap; white-space: -o-pre-wrap; white-space: pre-wrap; white-space: pre-line; word-wrap: break-word; wrap-option: emergency; color: " + c;
p.appendChild(doc.createTextNode(level + ": " + text));
logPane.appendChild(p);
logPane.appendChild(doc.createElement("br"));
if (logPaneArea.offsetHeight > logPaneArea.scrollHeight) {
logPaneArea.scrollTop = 0;
} else {
logPaneArea.scrollTop = logPaneArea.scrollHeight;
}
}, this);
/** @id MochiKit.LoggingPane.addMessage */
var addMessage = function (msg) {
messages[messages.length] = msg;
addMessageText(msg);
};
/** @id MochiKit.LoggingPane.buildMessageFilter */
var buildMessageFilter = function () {
var levelre, infore;
try {
/* Catch any exceptions that might arise due to invalid regexes */
levelre = new RegExp(levelFilterField.value);
infore = new RegExp(infoFilterField.value);
} catch(e) {
/* If there was an error with the regexes, do no filtering */
logDebug("Error in filter regex: " + e.message);
return null;
}
return function (msg) {
return (
levelre.test(messageLevel(msg)) &&
infore.test(messageText(msg))
);
};
};
/** @id MochiKit.LoggingPane.clearMessagePane */
var clearMessagePane = function () {
while (logPane.firstChild) {
logPane.removeChild(logPane.firstChild);
}
};
/** @id MochiKit.LoggingPane.clearMessages */
var clearMessages = function () {
messages = [];
clearMessagePane();
};
/** @id MochiKit.LoggingPane.closePane */
var closePane = bind(function () {
if (this.closed) {
return;
}
this.closed = true;
if (MochiKit.LoggingPane._loggingPane == this) {
MochiKit.LoggingPane._loggingPane = null;
}
this.logger.removeListener(listenerId);
try {
try {
debugPane.loggingPane = null;
} catch(e) { logFatal("Bookmarklet was closed incorrectly."); }
if (inline) {
debugPane.parentNode.removeChild(debugPane);
} else {
this.win.close();
}
} catch(e) {}
}, this);
/** @id MochiKit.LoggingPane.filterMessages */
var filterMessages = function () {
clearMessagePane();
for (var i = 0; i < messages.length; i++) {
var msg = messages[i];
if (messageFilter === null || messageFilter(msg)) {
addMessageText(msg);
}
}
};
this.buildAndApplyFilter = function () {
messageFilter = buildMessageFilter();
filterMessages();
this.logger.removeListener(listenerId);
this.logger.addListener(listenerId, messageFilter, addMessage);
};
/** @id MochiKit.LoggingPane.loadMessages */
var loadMessages = bind(function () {
messages = this.logger.getMessages();
filterMessages();
}, this);
/** @id MochiKit.LoggingPane.filterOnEnter */
var filterOnEnter = bind(function (event) {
event = event || window.event;
key = event.which || event.keyCode;
if (key == 13) {
this.buildAndApplyFilter();
}
}, this);
/* Create the debug pane */
var style = "display: block; z-index: 1000; left: 0px; bottom: 0px; position: fixed; width: 100%; background-color: white; font: " + this.logFont;
if (inline) {
style += "; height: 10em; border-top: 2px solid black";
} else {
style += "; height: 100%;";
}
debugPane.style.cssText = style;
if (!existing_pane) {
doc.body.appendChild(debugPane);
}
/* Create the filter fields */
style = {"cssText": "width: 33%; display: inline; font: " + this.logFont};
updatetree(levelFilterField, {
"value": "FATAL|ERROR|WARNING|INFO|DEBUG",
"onkeypress": filterOnEnter,
"style": style
});
debugPane.appendChild(levelFilterField);
updatetree(infoFilterField, {
"value": ".*",
"onkeypress": filterOnEnter,
"style": style
});
debugPane.appendChild(infoFilterField);
/* Create the buttons */
style = "width: 8%; display:inline; font: " + this.logFont;
filterButton.appendChild(doc.createTextNode("Filter"));
filterButton.onclick = bind("buildAndApplyFilter", this);
filterButton.style.cssText = style;
debugPane.appendChild(filterButton);
loadButton.appendChild(doc.createTextNode("Load"));
loadButton.onclick = loadMessages;
loadButton.style.cssText = style;
debugPane.appendChild(loadButton);
clearButton.appendChild(doc.createTextNode("Clear"));
clearButton.onclick = clearMessages;
clearButton.style.cssText = style;
debugPane.appendChild(clearButton);
closeButton.appendChild(doc.createTextNode("Close"));
closeButton.onclick = closePane;
closeButton.style.cssText = style;
debugPane.appendChild(closeButton);
/* Create the logging pane */
logPaneArea.style.cssText = "overflow: auto; width: 100%";
logPane.style.cssText = "width: 100%; height: " + (inline ? "8em" : "100%");
logPaneArea.appendChild(logPane);
debugPane.appendChild(logPaneArea);
this.buildAndApplyFilter();
loadMessages();
if (inline) {
this.win = undefined;
} else {
this.win = win;
}
this.inline = inline;
this.closePane = closePane;
this.closed = false;
return this;
};
MochiKit.LoggingPane.LoggingPane.prototype = {
"logFont": "8pt Verdana,sans-serif",
"colorTable": {
"ERROR": "red",
"FATAL": "darkred",
"WARNING": "blue",
"INFO": "black",
"DEBUG": "green"
}
};
MochiKit.LoggingPane.EXPORT_OK = [
"LoggingPane"
];
MochiKit.LoggingPane.EXPORT = [
"createLoggingPane"
];
MochiKit.LoggingPane.__new__ = function () {
this.EXPORT_TAGS = {
":common": this.EXPORT,
":all": MochiKit.Base.concat(this.EXPORT, this.EXPORT_OK)
};
MochiKit.Base.nameFunctions(this);
MochiKit.LoggingPane._loggingPane = null;
};
MochiKit.LoggingPane.__new__();
MochiKit.Base._exportSymbols(this, MochiKit.LoggingPane);
-188
View File
@@ -1,188 +0,0 @@
/***
MochiKit.MochiKit 1.4.2
See <http://mochikit.com/> for documentation, downloads, license, etc.
(c) 2005 Bob Ippolito. All rights Reserved.
***/
if (typeof(MochiKit) == 'undefined') {
MochiKit = {};
}
if (typeof(MochiKit.MochiKit) == 'undefined') {
/** @id MochiKit.MochiKit */
MochiKit.MochiKit = {};
}
MochiKit.MochiKit.NAME = "MochiKit.MochiKit";
MochiKit.MochiKit.VERSION = "1.4.2";
MochiKit.MochiKit.__repr__ = function () {
return "[" + this.NAME + " " + this.VERSION + "]";
};
/** @id MochiKit.MochiKit.toString */
MochiKit.MochiKit.toString = function () {
return this.__repr__();
};
/** @id MochiKit.MochiKit.SUBMODULES */
MochiKit.MochiKit.SUBMODULES = [
"Base",
"Iter",
"Logging",
"DateTime",
"Format",
"Async",
"DOM",
"Selector",
"Style",
"LoggingPane",
"Color",
"Signal",
"Position",
"Visual",
"DragAndDrop",
"Sortable"
];
if (typeof(JSAN) != 'undefined' || typeof(dojo) != 'undefined') {
if (typeof(dojo) != 'undefined') {
dojo.provide('MochiKit.MochiKit');
(function (lst) {
for (var i = 0; i < lst.length; i++) {
dojo.require("MochiKit." + lst[i]);
}
})(MochiKit.MochiKit.SUBMODULES);
}
if (typeof(JSAN) != 'undefined') {
(function (lst) {
for (var i = 0; i < lst.length; i++) {
JSAN.use("MochiKit." + lst[i], []);
}
})(MochiKit.MochiKit.SUBMODULES);
}
(function () {
var extend = MochiKit.Base.extend;
var self = MochiKit.MochiKit;
var modules = self.SUBMODULES;
var EXPORT = [];
var EXPORT_OK = [];
var EXPORT_TAGS = {};
var i, k, m, all;
for (i = 0; i < modules.length; i++) {
m = MochiKit[modules[i]];
extend(EXPORT, m.EXPORT);
extend(EXPORT_OK, m.EXPORT_OK);
for (k in m.EXPORT_TAGS) {
EXPORT_TAGS[k] = extend(EXPORT_TAGS[k], m.EXPORT_TAGS[k]);
}
all = m.EXPORT_TAGS[":all"];
if (!all) {
all = extend(null, m.EXPORT, m.EXPORT_OK);
}
var j;
for (j = 0; j < all.length; j++) {
k = all[j];
self[k] = m[k];
}
}
self.EXPORT = EXPORT;
self.EXPORT_OK = EXPORT_OK;
self.EXPORT_TAGS = EXPORT_TAGS;
}());
} else {
if (typeof(MochiKit.__compat__) == 'undefined') {
MochiKit.__compat__ = true;
}
(function () {
if (typeof(document) == "undefined") {
return;
}
var scripts = document.getElementsByTagName("script");
var kXHTMLNSURI = "http://www.w3.org/1999/xhtml";
var kSVGNSURI = "http://www.w3.org/2000/svg";
var kXLINKNSURI = "http://www.w3.org/1999/xlink";
var kXULNSURI = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
var base = null;
var baseElem = null;
var allScripts = {};
var i;
var src;
for (i = 0; i < scripts.length; i++) {
src = null;
switch (scripts[i].namespaceURI) {
case kSVGNSURI:
src = scripts[i].getAttributeNS(kXLINKNSURI, "href");
break;
/*
case null: // HTML
case '': // HTML
case kXHTMLNSURI:
case kXULNSURI:
*/
default:
src = scripts[i].getAttribute("src");
break;
}
if (!src) {
continue;
}
allScripts[src] = true;
if (src.match(/MochiKit.js(\?.*)?$/)) {
base = src.substring(0, src.lastIndexOf('MochiKit.js'));
baseElem = scripts[i];
}
}
if (base === null) {
return;
}
var modules = MochiKit.MochiKit.SUBMODULES;
for (var i = 0; i < modules.length; i++) {
if (MochiKit[modules[i]]) {
continue;
}
var uri = base + modules[i] + '.js';
if (uri in allScripts) {
continue;
}
if (baseElem.namespaceURI == kSVGNSURI ||
baseElem.namespaceURI == kXULNSURI) {
// SVG, XUL
/*
SVG does not support document.write, so if Safari wants to
support SVG tests it should fix its deferred loading bug
(see following below).
*/
var s = document.createElementNS(baseElem.namespaceURI, 'script');
s.setAttribute("id", "MochiKit_" + base + modules[i]);
if (baseElem.namespaceURI == kSVGNSURI) {
s.setAttributeNS(kXLINKNSURI, 'href', uri);
} else {
s.setAttribute('src', uri);
}
s.setAttribute("type", "application/x-javascript");
baseElem.parentNode.appendChild(s);
} else {
// HTML, XHTML
/*
DOM can not be used here because Safari does
deferred loading of scripts unless they are
in the document or inserted with document.write
This is not XHTML compliant. If you want XHTML
compliance then you must use the packed version of MochiKit
or include each script individually (basically unroll
these document.write calls into your XHTML source)
*/
document.write('<' + baseElem.nodeName + ' src="' + uri +
'" type="text/javascript"></script>');
}
};
})();
}
-115
View File
@@ -1,115 +0,0 @@
/***
MochiKit.MockDOM 1.4.2
See <http://mochikit.com/> for documentation, downloads, license, etc.
(c) 2005 Bob Ippolito. All rights Reserved.
***/
if (typeof(MochiKit) == "undefined") {
MochiKit = {};
}
if (typeof(MochiKit.MockDOM) == "undefined") {
MochiKit.MockDOM = {};
}
MochiKit.MockDOM.NAME = "MochiKit.MockDOM";
MochiKit.MockDOM.VERSION = "1.4.2";
MochiKit.MockDOM.__repr__ = function () {
return "[" + this.NAME + " " + this.VERSION + "]";
};
/** @id MochiKit.MockDOM.toString */
MochiKit.MockDOM.toString = function () {
return this.__repr__();
};
/** @id MochiKit.MockDOM.createDocument */
MochiKit.MockDOM.createDocument = function () {
var doc = new MochiKit.MockDOM.MockElement("DOCUMENT");
doc.body = doc.createElement("BODY");
doc.appendChild(doc.body);
return doc;
};
/** @id MochiKit.MockDOM.MockElement */
MochiKit.MockDOM.MockElement = function (name, data, ownerDocument) {
this.tagName = this.nodeName = name.toUpperCase();
this.ownerDocument = ownerDocument || null;
if (name == "DOCUMENT") {
this.nodeType = 9;
this.childNodes = [];
} else if (typeof(data) == "string") {
this.nodeValue = data;
this.nodeType = 3;
} else {
this.nodeType = 1;
this.childNodes = [];
}
if (name.substring(0, 1) == "<") {
var nameattr = name.substring(
name.indexOf('"') + 1, name.lastIndexOf('"'));
name = name.substring(1, name.indexOf(" "));
this.tagName = this.nodeName = name.toUpperCase();
this.setAttribute("name", nameattr);
}
};
MochiKit.MockDOM.MockElement.prototype = {
/** @id MochiKit.MockDOM.MockElement.prototype.createElement */
createElement: function (tagName) {
return new MochiKit.MockDOM.MockElement(tagName, null, this.nodeType == 9 ? this : this.ownerDocument);
},
/** @id MochiKit.MockDOM.MockElement.prototype.createTextNode */
createTextNode: function (text) {
return new MochiKit.MockDOM.MockElement("text", text, this.nodeType == 9 ? this : this.ownerDocument);
},
/** @id MochiKit.MockDOM.MockElement.prototype.setAttribute */
setAttribute: function (name, value) {
this[name] = value;
},
/** @id MochiKit.MockDOM.MockElement.prototype.getAttribute */
getAttribute: function (name) {
return this[name];
},
/** @id MochiKit.MockDOM.MockElement.prototype.appendChild */
appendChild: function (child) {
this.childNodes.push(child);
},
/** @id MochiKit.MockDOM.MockElement.prototype.toString */
toString: function () {
return "MockElement(" + this.tagName + ")";
},
/** @id MochiKit.MockDOM.MockElement.prototype.getElementsByTagName */
getElementsByTagName: function (tagName) {
var foundElements = [];
MochiKit.Base.nodeWalk(this, function(node){
if (tagName == '*' || tagName == node.tagName) {
foundElements.push(node);
return node.childNodes;
}
});
return foundElements;
}
};
/** @id MochiKit.MockDOM.EXPORT_OK */
MochiKit.MockDOM.EXPORT_OK = [
"mockElement",
"createDocument"
];
/** @id MochiKit.MockDOM.EXPORT */
MochiKit.MockDOM.EXPORT = [
"document"
];
MochiKit.MockDOM.__new__ = function () {
this.document = this.createDocument();
};
MochiKit.MockDOM.__new__();
-236
View File
@@ -1,236 +0,0 @@
/***
MochiKit.Position 1.4.2
See <http://mochikit.com/> for documentation, downloads, license, etc.
(c) 2005-2006 Bob Ippolito and others. All rights Reserved.
***/
MochiKit.Base._deps('Position', ['Base', 'DOM', 'Style']);
MochiKit.Position.NAME = 'MochiKit.Position';
MochiKit.Position.VERSION = '1.4.2';
MochiKit.Position.__repr__ = function () {
return '[' + this.NAME + ' ' + this.VERSION + ']';
};
MochiKit.Position.toString = function () {
return this.__repr__();
};
MochiKit.Position.EXPORT_OK = [];
MochiKit.Position.EXPORT = [
];
MochiKit.Base.update(MochiKit.Position, {
// set to true if needed, warning: firefox performance problems
// NOT neeeded for page scrolling, only if draggable contained in
// scrollable elements
includeScrollOffsets: false,
/** @id MochiKit.Position.prepare */
prepare: function () {
var deltaX = window.pageXOffset
|| document.documentElement.scrollLeft
|| document.body.scrollLeft
|| 0;
var deltaY = window.pageYOffset
|| document.documentElement.scrollTop
|| document.body.scrollTop
|| 0;
this.windowOffset = new MochiKit.Style.Coordinates(deltaX, deltaY);
},
/** @id MochiKit.Position.cumulativeOffset */
cumulativeOffset: function (element) {
var valueT = 0;
var valueL = 0;
do {
valueT += element.offsetTop || 0;
valueL += element.offsetLeft || 0;
element = element.offsetParent;
} while (element);
return new MochiKit.Style.Coordinates(valueL, valueT);
},
/** @id MochiKit.Position.realOffset */
realOffset: function (element) {
var valueT = 0;
var valueL = 0;
do {
valueT += element.scrollTop || 0;
valueL += element.scrollLeft || 0;
element = element.parentNode;
} while (element);
return new MochiKit.Style.Coordinates(valueL, valueT);
},
/** @id MochiKit.Position.within */
within: function (element, x, y) {
if (this.includeScrollOffsets) {
return this.withinIncludingScrolloffsets(element, x, y);
}
this.xcomp = x;
this.ycomp = y;
this.offset = this.cumulativeOffset(element);
if (element.style.position == "fixed") {
this.offset.x += this.windowOffset.x;
this.offset.y += this.windowOffset.y;
}
return (y >= this.offset.y &&
y < this.offset.y + element.offsetHeight &&
x >= this.offset.x &&
x < this.offset.x + element.offsetWidth);
},
/** @id MochiKit.Position.withinIncludingScrolloffsets */
withinIncludingScrolloffsets: function (element, x, y) {
var offsetcache = this.realOffset(element);
this.xcomp = x + offsetcache.x - this.windowOffset.x;
this.ycomp = y + offsetcache.y - this.windowOffset.y;
this.offset = this.cumulativeOffset(element);
return (this.ycomp >= this.offset.y &&
this.ycomp < this.offset.y + element.offsetHeight &&
this.xcomp >= this.offset.x &&
this.xcomp < this.offset.x + element.offsetWidth);
},
// within must be called directly before
/** @id MochiKit.Position.overlap */
overlap: function (mode, element) {
if (!mode) {
return 0;
}
if (mode == 'vertical') {
return ((this.offset.y + element.offsetHeight) - this.ycomp) /
element.offsetHeight;
}
if (mode == 'horizontal') {
return ((this.offset.x + element.offsetWidth) - this.xcomp) /
element.offsetWidth;
}
},
/** @id MochiKit.Position.absolutize */
absolutize: function (element) {
element = MochiKit.DOM.getElement(element);
if (element.style.position == 'absolute') {
return;
}
MochiKit.Position.prepare();
var offsets = MochiKit.Position.positionedOffset(element);
var width = element.clientWidth;
var height = element.clientHeight;
var oldStyle = {
'position': element.style.position,
'left': offsets.x - parseFloat(element.style.left || 0),
'top': offsets.y - parseFloat(element.style.top || 0),
'width': element.style.width,
'height': element.style.height
};
element.style.position = 'absolute';
element.style.top = offsets.y + 'px';
element.style.left = offsets.x + 'px';
element.style.width = width + 'px';
element.style.height = height + 'px';
return oldStyle;
},
/** @id MochiKit.Position.positionedOffset */
positionedOffset: function (element) {
var valueT = 0, valueL = 0;
do {
valueT += element.offsetTop || 0;
valueL += element.offsetLeft || 0;
element = element.offsetParent;
if (element) {
p = MochiKit.Style.getStyle(element, 'position');
if (p == 'relative' || p == 'absolute') {
break;
}
}
} while (element);
return new MochiKit.Style.Coordinates(valueL, valueT);
},
/** @id MochiKit.Position.relativize */
relativize: function (element, oldPos) {
element = MochiKit.DOM.getElement(element);
if (element.style.position == 'relative') {
return;
}
MochiKit.Position.prepare();
var top = parseFloat(element.style.top || 0) -
(oldPos['top'] || 0);
var left = parseFloat(element.style.left || 0) -
(oldPos['left'] || 0);
element.style.position = oldPos['position'];
element.style.top = top + 'px';
element.style.left = left + 'px';
element.style.width = oldPos['width'];
element.style.height = oldPos['height'];
},
/** @id MochiKit.Position.clone */
clone: function (source, target) {
source = MochiKit.DOM.getElement(source);
target = MochiKit.DOM.getElement(target);
target.style.position = 'absolute';
var offsets = this.cumulativeOffset(source);
target.style.top = offsets.y + 'px';
target.style.left = offsets.x + 'px';
target.style.width = source.offsetWidth + 'px';
target.style.height = source.offsetHeight + 'px';
},
/** @id MochiKit.Position.page */
page: function (forElement) {
var valueT = 0;
var valueL = 0;
var element = forElement;
do {
valueT += element.offsetTop || 0;
valueL += element.offsetLeft || 0;
// Safari fix
if (element.offsetParent == document.body && MochiKit.Style.getStyle(element, 'position') == 'absolute') {
break;
}
} while (element = element.offsetParent);
element = forElement;
do {
valueT -= element.scrollTop || 0;
valueL -= element.scrollLeft || 0;
} while (element = element.parentNode);
return new MochiKit.Style.Coordinates(valueL, valueT);
}
});
MochiKit.Position.__new__ = function (win) {
var m = MochiKit.Base;
this.EXPORT_TAGS = {
':common': this.EXPORT,
':all': m.concat(this.EXPORT, this.EXPORT_OK)
};
m.nameFunctions(this);
};
MochiKit.Position.__new__(this);
MochiKit.Base._exportSymbols(this, MochiKit.Position);
-415
View File
@@ -1,415 +0,0 @@
/***
MochiKit.Selector 1.4.2
See <http://mochikit.com/> for documentation, downloads, license, etc.
(c) 2005 Bob Ippolito and others. All rights Reserved.
***/
MochiKit.Base._deps('Selector', ['Base', 'DOM', 'Iter']);
MochiKit.Selector.NAME = "MochiKit.Selector";
MochiKit.Selector.VERSION = "1.4.2";
MochiKit.Selector.__repr__ = function () {
return "[" + this.NAME + " " + this.VERSION + "]";
};
MochiKit.Selector.toString = function () {
return this.__repr__();
};
MochiKit.Selector.EXPORT = [
"Selector",
"findChildElements",
"findDocElements",
"$$"
];
MochiKit.Selector.EXPORT_OK = [
];
MochiKit.Selector.Selector = function (expression) {
this.params = {classNames: [], pseudoClassNames: []};
this.expression = expression.toString().replace(/(^\s+|\s+$)/g, '');
this.parseExpression();
this.compileMatcher();
};
MochiKit.Selector.Selector.prototype = {
/***
Selector class: convenient object to make CSS selections.
***/
__class__: MochiKit.Selector.Selector,
/** @id MochiKit.Selector.Selector.prototype.parseExpression */
parseExpression: function () {
function abort(message) {
throw 'Parse error in selector: ' + message;
}
if (this.expression == '') {
abort('empty expression');
}
var repr = MochiKit.Base.repr;
var params = this.params;
var expr = this.expression;
var match, modifier, clause, rest;
while (match = expr.match(/^(.*)\[([a-z0-9_:-]+?)(?:([~\|!^$*]?=)(?:"([^"]*)"|([^\]\s]*)))?\]$/i)) {
params.attributes = params.attributes || [];
params.attributes.push({name: match[2], operator: match[3], value: match[4] || match[5] || ''});
expr = match[1];
}
if (expr == '*') {
return this.params.wildcard = true;
}
while (match = expr.match(/^([^a-z0-9_-])?([a-z0-9_-]+(?:\([^)]*\))?)(.*)/i)) {
modifier = match[1];
clause = match[2];
rest = match[3];
switch (modifier) {
case '#':
params.id = clause;
break;
case '.':
params.classNames.push(clause);
break;
case ':':
params.pseudoClassNames.push(clause);
break;
case '':
case undefined:
params.tagName = clause.toUpperCase();
break;
default:
abort(repr(expr));
}
expr = rest;
}
if (expr.length > 0) {
abort(repr(expr));
}
},
/** @id MochiKit.Selector.Selector.prototype.buildMatchExpression */
buildMatchExpression: function () {
var repr = MochiKit.Base.repr;
var params = this.params;
var conditions = [];
var clause, i;
function childElements(element) {
return "MochiKit.Base.filter(function (node) { return node.nodeType == 1; }, " + element + ".childNodes)";
}
if (params.wildcard) {
conditions.push('true');
}
if (clause = params.id) {
conditions.push('element.id == ' + repr(clause));
}
if (clause = params.tagName) {
conditions.push('element.tagName.toUpperCase() == ' + repr(clause));
}
if ((clause = params.classNames).length > 0) {
for (i = 0; i < clause.length; i++) {
conditions.push('MochiKit.DOM.hasElementClass(element, ' + repr(clause[i]) + ')');
}
}
if ((clause = params.pseudoClassNames).length > 0) {
for (i = 0; i < clause.length; i++) {
var match = clause[i].match(/^([^(]+)(?:\((.*)\))?$/);
var pseudoClass = match[1];
var pseudoClassArgument = match[2];
switch (pseudoClass) {
case 'root':
conditions.push('element.nodeType == 9 || element === element.ownerDocument.documentElement'); break;
case 'nth-child':
case 'nth-last-child':
case 'nth-of-type':
case 'nth-last-of-type':
match = pseudoClassArgument.match(/^((?:(\d+)n\+)?(\d+)|odd|even)$/);
if (!match) {
throw "Invalid argument to pseudo element nth-child: " + pseudoClassArgument;
}
var a, b;
if (match[0] == 'odd') {
a = 2;
b = 1;
} else if (match[0] == 'even') {
a = 2;
b = 0;
} else {
a = match[2] && parseInt(match) || null;
b = parseInt(match[3]);
}
conditions.push('this.nthChild(element,' + a + ',' + b
+ ',' + !!pseudoClass.match('^nth-last') // Reverse
+ ',' + !!pseudoClass.match('of-type$') // Restrict to same tagName
+ ')');
break;
case 'first-child':
conditions.push('this.nthChild(element, null, 1)');
break;
case 'last-child':
conditions.push('this.nthChild(element, null, 1, true)');
break;
case 'first-of-type':
conditions.push('this.nthChild(element, null, 1, false, true)');
break;
case 'last-of-type':
conditions.push('this.nthChild(element, null, 1, true, true)');
break;
case 'only-child':
conditions.push(childElements('element.parentNode') + '.length == 1');
break;
case 'only-of-type':
conditions.push('MochiKit.Base.filter(function (node) { return node.tagName == element.tagName; }, ' + childElements('element.parentNode') + ').length == 1');
break;
case 'empty':
conditions.push('element.childNodes.length == 0');
break;
case 'enabled':
conditions.push('(this.isUIElement(element) && element.disabled === false)');
break;
case 'disabled':
conditions.push('(this.isUIElement(element) && element.disabled === true)');
break;
case 'checked':
conditions.push('(this.isUIElement(element) && element.checked === true)');
break;
case 'not':
var subselector = new MochiKit.Selector.Selector(pseudoClassArgument);
conditions.push('!( ' + subselector.buildMatchExpression() + ')')
break;
}
}
}
if (clause = params.attributes) {
MochiKit.Base.map(function (attribute) {
var value = 'MochiKit.DOM.getNodeAttribute(element, ' + repr(attribute.name) + ')';
var splitValueBy = function (delimiter) {
return value + '.split(' + repr(delimiter) + ')';
}
conditions.push(value + ' != null');
switch (attribute.operator) {
case '=':
conditions.push(value + ' == ' + repr(attribute.value));
break;
case '~=':
conditions.push('MochiKit.Base.findValue(' + splitValueBy(' ') + ', ' + repr(attribute.value) + ') > -1');
break;
case '^=':
conditions.push(value + '.substring(0, ' + attribute.value.length + ') == ' + repr(attribute.value));
break;
case '$=':
conditions.push(value + '.substring(' + value + '.length - ' + attribute.value.length + ') == ' + repr(attribute.value));
break;
case '*=':
conditions.push(value + '.match(' + repr(attribute.value) + ')');
break;
case '|=':
conditions.push(splitValueBy('-') + '[0].toUpperCase() == ' + repr(attribute.value.toUpperCase()));
break;
case '!=':
conditions.push(value + ' != ' + repr(attribute.value));
break;
case '':
case undefined:
// Condition already added above
break;
default:
throw 'Unknown operator ' + attribute.operator + ' in selector';
}
}, clause);
}
return conditions.join(' && ');
},
/** @id MochiKit.Selector.Selector.prototype.compileMatcher */
compileMatcher: function () {
var code = 'return (!element.tagName) ? false : ' +
this.buildMatchExpression() + ';';
this.match = new Function('element', code);
},
/** @id MochiKit.Selector.Selector.prototype.nthChild */
nthChild: function (element, a, b, reverse, sametag){
var siblings = MochiKit.Base.filter(function (node) {
return node.nodeType == 1;
}, element.parentNode.childNodes);
if (sametag) {
siblings = MochiKit.Base.filter(function (node) {
return node.tagName == element.tagName;
}, siblings);
}
if (reverse) {
siblings = MochiKit.Iter.reversed(siblings);
}
if (a) {
var actualIndex = MochiKit.Base.findIdentical(siblings, element);
return ((actualIndex + 1 - b) / a) % 1 == 0;
} else {
return b == MochiKit.Base.findIdentical(siblings, element) + 1;
}
},
/** @id MochiKit.Selector.Selector.prototype.isUIElement */
isUIElement: function (element) {
return MochiKit.Base.findValue(['input', 'button', 'select', 'option', 'textarea', 'object'],
element.tagName.toLowerCase()) > -1;
},
/** @id MochiKit.Selector.Selector.prototype.findElements */
findElements: function (scope, axis) {
var element;
if (axis == undefined) {
axis = "";
}
function inScope(element, scope) {
if (axis == "") {
return MochiKit.DOM.isChildNode(element, scope);
} else if (axis == ">") {
return element.parentNode === scope;
} else if (axis == "+") {
return element === nextSiblingElement(scope);
} else if (axis == "~") {
var sibling = scope;
while (sibling = nextSiblingElement(sibling)) {
if (element === sibling) {
return true;
}
}
return false;
} else {
throw "Invalid axis: " + axis;
}
}
if (element = MochiKit.DOM.getElement(this.params.id)) {
if (this.match(element)) {
if (!scope || inScope(element, scope)) {
return [element];
}
}
}
function nextSiblingElement(node) {
node = node.nextSibling;
while (node && node.nodeType != 1) {
node = node.nextSibling;
}
return node;
}
if (axis == "") {
scope = (scope || MochiKit.DOM.currentDocument()).getElementsByTagName(this.params.tagName || '*');
} else if (axis == ">") {
if (!scope) {
throw "> combinator not allowed without preceeding expression";
}
scope = MochiKit.Base.filter(function (node) {
return node.nodeType == 1;
}, scope.childNodes);
} else if (axis == "+") {
if (!scope) {
throw "+ combinator not allowed without preceeding expression";
}
scope = nextSiblingElement(scope) && [nextSiblingElement(scope)];
} else if (axis == "~") {
if (!scope) {
throw "~ combinator not allowed without preceeding expression";
}
var newscope = [];
while (nextSiblingElement(scope)) {
scope = nextSiblingElement(scope);
newscope.push(scope);
}
scope = newscope;
}
if (!scope) {
return [];
}
var results = MochiKit.Base.filter(MochiKit.Base.bind(function (scopeElt) {
return this.match(scopeElt);
}, this), scope);
return results;
},
/** @id MochiKit.Selector.Selector.prototype.repr */
repr: function () {
return 'Selector(' + this.expression + ')';
},
toString: MochiKit.Base.forwardCall("repr")
};
MochiKit.Base.update(MochiKit.Selector, {
/** @id MochiKit.Selector.findChildElements */
findChildElements: function (element, expressions) {
var uniq = function(arr) {
var res = [];
for (var i = 0; i < arr.length; i++) {
if (MochiKit.Base.findIdentical(res, arr[i]) < 0) {
res.push(arr[i]);
}
}
return res;
};
return MochiKit.Base.flattenArray(MochiKit.Base.map(function (expression) {
var nextScope = "";
var reducer = function (results, expr) {
if (match = expr.match(/^[>+~]$/)) {
nextScope = match[0];
return results;
} else {
var selector = new MochiKit.Selector.Selector(expr);
var elements = MochiKit.Iter.reduce(function (elements, result) {
return MochiKit.Base.extend(elements, selector.findElements(result || element, nextScope));
}, results, []);
nextScope = "";
return elements;
}
};
var exprs = expression.replace(/(^\s+|\s+$)/g, '').split(/\s+/);
return uniq(MochiKit.Iter.reduce(reducer, exprs, [null]));
}, expressions));
},
findDocElements: function () {
return MochiKit.Selector.findChildElements(MochiKit.DOM.currentDocument(), arguments);
},
__new__: function () {
var m = MochiKit.Base;
this.$$ = this.findDocElements;
this.EXPORT_TAGS = {
":common": this.EXPORT,
":all": m.concat(this.EXPORT, this.EXPORT_OK)
};
m.nameFunctions(this);
}
});
MochiKit.Selector.__new__();
MochiKit.Base._exportSymbols(this, MochiKit.Selector);
-897
View File
@@ -1,897 +0,0 @@
/***
MochiKit.Signal 1.4.2
See <http://mochikit.com/> for documentation, downloads, license, etc.
(c) 2006 Jonathan Gardner, Beau Hartshorne, Bob Ippolito. All rights Reserved.
***/
MochiKit.Base._deps('Signal', ['Base', 'DOM', 'Style']);
MochiKit.Signal.NAME = 'MochiKit.Signal';
MochiKit.Signal.VERSION = '1.4.2';
MochiKit.Signal._observers = [];
/** @id MochiKit.Signal.Event */
MochiKit.Signal.Event = function (src, e) {
this._event = e || window.event;
this._src = src;
};
MochiKit.Base.update(MochiKit.Signal.Event.prototype, {
__repr__: function () {
var repr = MochiKit.Base.repr;
var str = '{event(): ' + repr(this.event()) +
', src(): ' + repr(this.src()) +
', type(): ' + repr(this.type()) +
', target(): ' + repr(this.target());
if (this.type() &&
this.type().indexOf('key') === 0 ||
this.type().indexOf('mouse') === 0 ||
this.type().indexOf('click') != -1 ||
this.type() == 'contextmenu') {
str += ', modifier(): ' + '{alt: ' + repr(this.modifier().alt) +
', ctrl: ' + repr(this.modifier().ctrl) +
', meta: ' + repr(this.modifier().meta) +
', shift: ' + repr(this.modifier().shift) +
', any: ' + repr(this.modifier().any) + '}';
}
if (this.type() && this.type().indexOf('key') === 0) {
str += ', key(): {code: ' + repr(this.key().code) +
', string: ' + repr(this.key().string) + '}';
}
if (this.type() && (
this.type().indexOf('mouse') === 0 ||
this.type().indexOf('click') != -1 ||
this.type() == 'contextmenu')) {
str += ', mouse(): {page: ' + repr(this.mouse().page) +
', client: ' + repr(this.mouse().client);
if (this.type() != 'mousemove' && this.type() != 'mousewheel') {
str += ', button: {left: ' + repr(this.mouse().button.left) +
', middle: ' + repr(this.mouse().button.middle) +
', right: ' + repr(this.mouse().button.right) + '}';
}
if (this.type() == 'mousewheel') {
str += ', wheel: ' + repr(this.mouse().wheel);
}
str += '}';
}
if (this.type() == 'mouseover' || this.type() == 'mouseout' ||
this.type() == 'mouseenter' || this.type() == 'mouseleave') {
str += ', relatedTarget(): ' + repr(this.relatedTarget());
}
str += '}';
return str;
},
/** @id MochiKit.Signal.Event.prototype.toString */
toString: function () {
return this.__repr__();
},
/** @id MochiKit.Signal.Event.prototype.src */
src: function () {
return this._src;
},
/** @id MochiKit.Signal.Event.prototype.event */
event: function () {
return this._event;
},
/** @id MochiKit.Signal.Event.prototype.type */
type: function () {
if (this._event.type === "DOMMouseScroll") {
return "mousewheel";
} else {
return this._event.type || undefined;
}
},
/** @id MochiKit.Signal.Event.prototype.target */
target: function () {
return this._event.target || this._event.srcElement;
},
_relatedTarget: null,
/** @id MochiKit.Signal.Event.prototype.relatedTarget */
relatedTarget: function () {
if (this._relatedTarget !== null) {
return this._relatedTarget;
}
var elem = null;
if (this.type() == 'mouseover' || this.type() == 'mouseenter') {
elem = (this._event.relatedTarget ||
this._event.fromElement);
} else if (this.type() == 'mouseout' || this.type() == 'mouseleave') {
elem = (this._event.relatedTarget ||
this._event.toElement);
}
try {
if (elem !== null && elem.nodeType !== null) {
this._relatedTarget = elem;
return elem;
}
} catch (ignore) {
// Firefox 3 throws a permission denied error when accessing
// any property on XUL elements (e.g. scrollbars)...
}
return undefined;
},
_modifier: null,
/** @id MochiKit.Signal.Event.prototype.modifier */
modifier: function () {
if (this._modifier !== null) {
return this._modifier;
}
var m = {};
m.alt = this._event.altKey;
m.ctrl = this._event.ctrlKey;
m.meta = this._event.metaKey || false; // IE and Opera punt here
m.shift = this._event.shiftKey;
m.any = m.alt || m.ctrl || m.shift || m.meta;
this._modifier = m;
return m;
},
_key: null,
/** @id MochiKit.Signal.Event.prototype.key */
key: function () {
if (this._key !== null) {
return this._key;
}
var k = {};
if (this.type() && this.type().indexOf('key') === 0) {
/*
If you're looking for a special key, look for it in keydown or
keyup, but never keypress. If you're looking for a Unicode
chracter, look for it with keypress, but never keyup or
keydown.
Notes:
FF key event behavior:
key event charCode keyCode
DOWN ku,kd 0 40
DOWN kp 0 40
ESC ku,kd 0 27
ESC kp 0 27
a ku,kd 0 65
a kp 97 0
shift+a ku,kd 0 65
shift+a kp 65 0
1 ku,kd 0 49
1 kp 49 0
shift+1 ku,kd 0 0
shift+1 kp 33 0
IE key event behavior:
(IE doesn't fire keypress events for special keys.)
key event keyCode
DOWN ku,kd 40
DOWN kp undefined
ESC ku,kd 27
ESC kp 27
a ku,kd 65
a kp 97
shift+a ku,kd 65
shift+a kp 65
1 ku,kd 49
1 kp 49
shift+1 ku,kd 49
shift+1 kp 33
Safari key event behavior:
(Safari sets charCode and keyCode to something crazy for
special keys.)
key event charCode keyCode
DOWN ku,kd 63233 40
DOWN kp 63233 63233
ESC ku,kd 27 27
ESC kp 27 27
a ku,kd 97 65
a kp 97 97
shift+a ku,kd 65 65
shift+a kp 65 65
1 ku,kd 49 49
1 kp 49 49
shift+1 ku,kd 33 49
shift+1 kp 33 33
*/
/* look for special keys here */
if (this.type() == 'keydown' || this.type() == 'keyup') {
k.code = this._event.keyCode;
k.string = (MochiKit.Signal._specialKeys[k.code] ||
'KEY_UNKNOWN');
this._key = k;
return k;
/* look for characters here */
} else if (this.type() == 'keypress') {
/*
Special key behavior:
IE: does not fire keypress events for special keys
FF: sets charCode to 0, and sets the correct keyCode
Safari: sets keyCode and charCode to something stupid
*/
k.code = 0;
k.string = '';
if (typeof(this._event.charCode) != 'undefined' &&
this._event.charCode !== 0 &&
!MochiKit.Signal._specialMacKeys[this._event.charCode]) {
k.code = this._event.charCode;
k.string = String.fromCharCode(k.code);
} else if (this._event.keyCode &&
typeof(this._event.charCode) == 'undefined') { // IE
k.code = this._event.keyCode;
k.string = String.fromCharCode(k.code);
}
this._key = k;
return k;
}
}
return undefined;
},
_mouse: null,
/** @id MochiKit.Signal.Event.prototype.mouse */
mouse: function () {
if (this._mouse !== null) {
return this._mouse;
}
var m = {};
var e = this._event;
if (this.type() && (
this.type().indexOf('mouse') === 0 ||
this.type().indexOf('click') != -1 ||
this.type() == 'contextmenu')) {
m.client = new MochiKit.Style.Coordinates(0, 0);
if (e.clientX || e.clientY) {
m.client.x = (!e.clientX || e.clientX < 0) ? 0 : e.clientX;
m.client.y = (!e.clientY || e.clientY < 0) ? 0 : e.clientY;
}
m.page = new MochiKit.Style.Coordinates(0, 0);
if (e.pageX || e.pageY) {
m.page.x = (!e.pageX || e.pageX < 0) ? 0 : e.pageX;
m.page.y = (!e.pageY || e.pageY < 0) ? 0 : e.pageY;
} else {
/*
The IE shortcut can be off by two. We fix it. See:
http://msdn.microsoft.com/workshop/author/dhtml/reference/methods/getboundingclientrect.asp
This is similar to the method used in
MochiKit.Style.getElementPosition().
*/
var de = MochiKit.DOM._document.documentElement;
var b = MochiKit.DOM._document.body;
m.page.x = e.clientX +
(de.scrollLeft || b.scrollLeft) -
(de.clientLeft || 0);
m.page.y = e.clientY +
(de.scrollTop || b.scrollTop) -
(de.clientTop || 0);
}
if (this.type() != 'mousemove' && this.type() != 'mousewheel') {
m.button = {};
m.button.left = false;
m.button.right = false;
m.button.middle = false;
/* we could check e.button, but which is more consistent */
if (e.which) {
m.button.left = (e.which == 1);
m.button.middle = (e.which == 2);
m.button.right = (e.which == 3);
/*
Mac browsers and right click:
- Safari doesn't fire any click events on a right
click:
http://bugs.webkit.org/show_bug.cgi?id=6595
- Firefox fires the event, and sets ctrlKey = true
- Opera fires the event, and sets metaKey = true
oncontextmenu is fired on right clicks between
browsers and across platforms.
*/
} else {
m.button.left = !!(e.button & 1);
m.button.right = !!(e.button & 2);
m.button.middle = !!(e.button & 4);
}
}
if (this.type() == 'mousewheel') {
m.wheel = new MochiKit.Style.Coordinates(0, 0);
if (e.wheelDeltaX || e.wheelDeltaY) {
m.wheel.x = e.wheelDeltaX / -40 || 0;
m.wheel.y = e.wheelDeltaY / -40 || 0;
} else if (e.wheelDelta) {
m.wheel.y = e.wheelDelta / -40;
} else {
m.wheel.y = e.detail || 0;
}
}
this._mouse = m;
return m;
}
return undefined;
},
/** @id MochiKit.Signal.Event.prototype.stop */
stop: function () {
this.stopPropagation();
this.preventDefault();
},
/** @id MochiKit.Signal.Event.prototype.stopPropagation */
stopPropagation: function () {
if (this._event.stopPropagation) {
this._event.stopPropagation();
} else {
this._event.cancelBubble = true;
}
},
/** @id MochiKit.Signal.Event.prototype.preventDefault */
preventDefault: function () {
if (this._event.preventDefault) {
this._event.preventDefault();
} else if (this._confirmUnload === null) {
this._event.returnValue = false;
}
},
_confirmUnload: null,
/** @id MochiKit.Signal.Event.prototype.confirmUnload */
confirmUnload: function (msg) {
if (this.type() == 'beforeunload') {
this._confirmUnload = msg;
this._event.returnValue = msg;
}
}
});
/* Safari sets keyCode to these special values onkeypress. */
MochiKit.Signal._specialMacKeys = {
3: 'KEY_ENTER',
63289: 'KEY_NUM_PAD_CLEAR',
63276: 'KEY_PAGE_UP',
63277: 'KEY_PAGE_DOWN',
63275: 'KEY_END',
63273: 'KEY_HOME',
63234: 'KEY_ARROW_LEFT',
63232: 'KEY_ARROW_UP',
63235: 'KEY_ARROW_RIGHT',
63233: 'KEY_ARROW_DOWN',
63302: 'KEY_INSERT',
63272: 'KEY_DELETE'
};
/* for KEY_F1 - KEY_F12 */
(function () {
var _specialMacKeys = MochiKit.Signal._specialMacKeys;
for (i = 63236; i <= 63242; i++) {
// no F0
_specialMacKeys[i] = 'KEY_F' + (i - 63236 + 1);
}
})();
/* Standard keyboard key codes. */
MochiKit.Signal._specialKeys = {
8: 'KEY_BACKSPACE',
9: 'KEY_TAB',
12: 'KEY_NUM_PAD_CLEAR', // weird, for Safari and Mac FF only
13: 'KEY_ENTER',
16: 'KEY_SHIFT',
17: 'KEY_CTRL',
18: 'KEY_ALT',
19: 'KEY_PAUSE',
20: 'KEY_CAPS_LOCK',
27: 'KEY_ESCAPE',
32: 'KEY_SPACEBAR',
33: 'KEY_PAGE_UP',
34: 'KEY_PAGE_DOWN',
35: 'KEY_END',
36: 'KEY_HOME',
37: 'KEY_ARROW_LEFT',
38: 'KEY_ARROW_UP',
39: 'KEY_ARROW_RIGHT',
40: 'KEY_ARROW_DOWN',
44: 'KEY_PRINT_SCREEN',
45: 'KEY_INSERT',
46: 'KEY_DELETE',
59: 'KEY_SEMICOLON', // weird, for Safari and IE only
91: 'KEY_WINDOWS_LEFT',
92: 'KEY_WINDOWS_RIGHT',
93: 'KEY_SELECT',
106: 'KEY_NUM_PAD_ASTERISK',
107: 'KEY_NUM_PAD_PLUS_SIGN',
109: 'KEY_NUM_PAD_HYPHEN-MINUS',
110: 'KEY_NUM_PAD_FULL_STOP',
111: 'KEY_NUM_PAD_SOLIDUS',
144: 'KEY_NUM_LOCK',
145: 'KEY_SCROLL_LOCK',
186: 'KEY_SEMICOLON',
187: 'KEY_EQUALS_SIGN',
188: 'KEY_COMMA',
189: 'KEY_HYPHEN-MINUS',
190: 'KEY_FULL_STOP',
191: 'KEY_SOLIDUS',
192: 'KEY_GRAVE_ACCENT',
219: 'KEY_LEFT_SQUARE_BRACKET',
220: 'KEY_REVERSE_SOLIDUS',
221: 'KEY_RIGHT_SQUARE_BRACKET',
222: 'KEY_APOSTROPHE'
// undefined: 'KEY_UNKNOWN'
};
(function () {
/* for KEY_0 - KEY_9 */
var _specialKeys = MochiKit.Signal._specialKeys;
for (var i = 48; i <= 57; i++) {
_specialKeys[i] = 'KEY_' + (i - 48);
}
/* for KEY_A - KEY_Z */
for (i = 65; i <= 90; i++) {
_specialKeys[i] = 'KEY_' + String.fromCharCode(i);
}
/* for KEY_NUM_PAD_0 - KEY_NUM_PAD_9 */
for (i = 96; i <= 105; i++) {
_specialKeys[i] = 'KEY_NUM_PAD_' + (i - 96);
}
/* for KEY_F1 - KEY_F12 */
for (i = 112; i <= 123; i++) {
// no F0
_specialKeys[i] = 'KEY_F' + (i - 112 + 1);
}
})();
/* Internal object to keep track of created signals. */
MochiKit.Signal.Ident = function (ident) {
this.source = ident.source;
this.signal = ident.signal;
this.listener = ident.listener;
this.isDOM = ident.isDOM;
this.objOrFunc = ident.objOrFunc;
this.funcOrStr = ident.funcOrStr;
this.connected = ident.connected;
};
MochiKit.Signal.Ident.prototype = {};
MochiKit.Base.update(MochiKit.Signal, {
__repr__: function () {
return '[' + this.NAME + ' ' + this.VERSION + ']';
},
toString: function () {
return this.__repr__();
},
_unloadCache: function () {
var self = MochiKit.Signal;
var observers = self._observers;
for (var i = 0; i < observers.length; i++) {
if (observers[i].signal !== 'onload' && observers[i].signal !== 'onunload') {
self._disconnect(observers[i]);
}
}
},
_listener: function (src, sig, func, obj, isDOM) {
var self = MochiKit.Signal;
var E = self.Event;
if (!isDOM) {
/* We don't want to re-bind already bound methods */
if (typeof(func.im_self) == 'undefined') {
return MochiKit.Base.bindLate(func, obj);
} else {
return func;
}
}
obj = obj || src;
if (typeof(func) == "string") {
if (sig === 'onload' || sig === 'onunload') {
return function (nativeEvent) {
obj[func].apply(obj, [new E(src, nativeEvent)]);
var ident = new MochiKit.Signal.Ident({
source: src, signal: sig, objOrFunc: obj, funcOrStr: func});
MochiKit.Signal._disconnect(ident);
};
} else {
return function (nativeEvent) {
obj[func].apply(obj, [new E(src, nativeEvent)]);
};
}
} else {
if (sig === 'onload' || sig === 'onunload') {
return function (nativeEvent) {
func.apply(obj, [new E(src, nativeEvent)]);
var ident = new MochiKit.Signal.Ident({
source: src, signal: sig, objOrFunc: func});
MochiKit.Signal._disconnect(ident);
};
} else {
return function (nativeEvent) {
func.apply(obj, [new E(src, nativeEvent)]);
};
}
}
},
_browserAlreadyHasMouseEnterAndLeave: function () {
return /MSIE/.test(navigator.userAgent);
},
_browserLacksMouseWheelEvent: function () {
return /Gecko\//.test(navigator.userAgent);
},
_mouseEnterListener: function (src, sig, func, obj) {
var E = MochiKit.Signal.Event;
return function (nativeEvent) {
var e = new E(src, nativeEvent);
try {
e.relatedTarget().nodeName;
} catch (err) {
/* probably hit a permission denied error; possibly one of
* firefox's screwy anonymous DIVs inside an input element.
* Allow this event to propogate up.
*/
return;
}
e.stop();
if (MochiKit.DOM.isChildNode(e.relatedTarget(), src)) {
/* We've moved between our node and a child. Ignore. */
return;
}
e.type = function () { return sig; };
if (typeof(func) == "string") {
return obj[func].apply(obj, [e]);
} else {
return func.apply(obj, [e]);
}
};
},
_getDestPair: function (objOrFunc, funcOrStr) {
var obj = null;
var func = null;
if (typeof(funcOrStr) != 'undefined') {
obj = objOrFunc;
func = funcOrStr;
if (typeof(funcOrStr) == 'string') {
if (typeof(objOrFunc[funcOrStr]) != "function") {
throw new Error("'funcOrStr' must be a function on 'objOrFunc'");
}
} else if (typeof(funcOrStr) != 'function') {
throw new Error("'funcOrStr' must be a function or string");
}
} else if (typeof(objOrFunc) != "function") {
throw new Error("'objOrFunc' must be a function if 'funcOrStr' is not given");
} else {
func = objOrFunc;
}
return [obj, func];
},
/** @id MochiKit.Signal.connect */
connect: function (src, sig, objOrFunc/* optional */, funcOrStr) {
src = MochiKit.DOM.getElement(src);
var self = MochiKit.Signal;
if (typeof(sig) != 'string') {
throw new Error("'sig' must be a string");
}
var destPair = self._getDestPair(objOrFunc, funcOrStr);
var obj = destPair[0];
var func = destPair[1];
if (typeof(obj) == 'undefined' || obj === null) {
obj = src;
}
var isDOM = !!(src.addEventListener || src.attachEvent);
if (isDOM && (sig === "onmouseenter" || sig === "onmouseleave")
&& !self._browserAlreadyHasMouseEnterAndLeave()) {
var listener = self._mouseEnterListener(src, sig.substr(2), func, obj);
if (sig === "onmouseenter") {
sig = "onmouseover";
} else {
sig = "onmouseout";
}
} else if (isDOM && sig == "onmousewheel" && self._browserLacksMouseWheelEvent()) {
var listener = self._listener(src, sig, func, obj, isDOM);
sig = "onDOMMouseScroll";
} else {
var listener = self._listener(src, sig, func, obj, isDOM);
}
if (src.addEventListener) {
src.addEventListener(sig.substr(2), listener, false);
} else if (src.attachEvent) {
src.attachEvent(sig, listener); // useCapture unsupported
}
var ident = new MochiKit.Signal.Ident({
source: src,
signal: sig,
listener: listener,
isDOM: isDOM,
objOrFunc: objOrFunc,
funcOrStr: funcOrStr,
connected: true
});
self._observers.push(ident);
if (!isDOM && typeof(src.__connect__) == 'function') {
var args = MochiKit.Base.extend([ident], arguments, 1);
src.__connect__.apply(src, args);
}
return ident;
},
_disconnect: function (ident) {
// already disconnected
if (!ident.connected) {
return;
}
ident.connected = false;
var src = ident.source;
var sig = ident.signal;
var listener = ident.listener;
// check isDOM
if (!ident.isDOM) {
if (typeof(src.__disconnect__) == 'function') {
src.__disconnect__(ident, sig, ident.objOrFunc, ident.funcOrStr);
}
return;
}
if (src.removeEventListener) {
src.removeEventListener(sig.substr(2), listener, false);
} else if (src.detachEvent) {
src.detachEvent(sig, listener); // useCapture unsupported
} else {
throw new Error("'src' must be a DOM element");
}
},
/** @id MochiKit.Signal.disconnect */
disconnect: function (ident) {
var self = MochiKit.Signal;
var observers = self._observers;
var m = MochiKit.Base;
if (arguments.length > 1) {
// compatibility API
var src = MochiKit.DOM.getElement(arguments[0]);
var sig = arguments[1];
var obj = arguments[2];
var func = arguments[3];
for (var i = observers.length - 1; i >= 0; i--) {
var o = observers[i];
if (o.source === src && o.signal === sig && o.objOrFunc === obj && o.funcOrStr === func) {
self._disconnect(o);
if (!self._lock) {
observers.splice(i, 1);
} else {
self._dirty = true;
}
return true;
}
}
} else {
var idx = m.findIdentical(observers, ident);
if (idx >= 0) {
self._disconnect(ident);
if (!self._lock) {
observers.splice(idx, 1);
} else {
self._dirty = true;
}
return true;
}
}
return false;
},
/** @id MochiKit.Signal.disconnectAllTo */
disconnectAllTo: function (objOrFunc, /* optional */funcOrStr) {
var self = MochiKit.Signal;
var observers = self._observers;
var disconnect = self._disconnect;
var locked = self._lock;
var dirty = self._dirty;
if (typeof(funcOrStr) === 'undefined') {
funcOrStr = null;
}
for (var i = observers.length - 1; i >= 0; i--) {
var ident = observers[i];
if (ident.objOrFunc === objOrFunc &&
(funcOrStr === null || ident.funcOrStr === funcOrStr)) {
disconnect(ident);
if (locked) {
dirty = true;
} else {
observers.splice(i, 1);
}
}
}
self._dirty = dirty;
},
/** @id MochiKit.Signal.disconnectAll */
disconnectAll: function (src/* optional */, sig) {
src = MochiKit.DOM.getElement(src);
var m = MochiKit.Base;
var signals = m.flattenArguments(m.extend(null, arguments, 1));
var self = MochiKit.Signal;
var disconnect = self._disconnect;
var observers = self._observers;
var i, ident;
var locked = self._lock;
var dirty = self._dirty;
if (signals.length === 0) {
// disconnect all
for (i = observers.length - 1; i >= 0; i--) {
ident = observers[i];
if (ident.source === src) {
disconnect(ident);
if (!locked) {
observers.splice(i, 1);
} else {
dirty = true;
}
}
}
} else {
var sigs = {};
for (i = 0; i < signals.length; i++) {
sigs[signals[i]] = true;
}
for (i = observers.length - 1; i >= 0; i--) {
ident = observers[i];
if (ident.source === src && ident.signal in sigs) {
disconnect(ident);
if (!locked) {
observers.splice(i, 1);
} else {
dirty = true;
}
}
}
}
self._dirty = dirty;
},
/** @id MochiKit.Signal.signal */
signal: function (src, sig) {
var self = MochiKit.Signal;
var observers = self._observers;
src = MochiKit.DOM.getElement(src);
var args = MochiKit.Base.extend(null, arguments, 2);
var errors = [];
self._lock = true;
for (var i = 0; i < observers.length; i++) {
var ident = observers[i];
if (ident.source === src && ident.signal === sig &&
ident.connected) {
try {
ident.listener.apply(src, args);
} catch (e) {
errors.push(e);
}
}
}
self._lock = false;
if (self._dirty) {
self._dirty = false;
for (var i = observers.length - 1; i >= 0; i--) {
if (!observers[i].connected) {
observers.splice(i, 1);
}
}
}
if (errors.length == 1) {
throw errors[0];
} else if (errors.length > 1) {
var e = new Error("Multiple errors thrown in handling 'sig', see errors property");
e.errors = errors;
throw e;
}
}
});
MochiKit.Signal.EXPORT_OK = [];
MochiKit.Signal.EXPORT = [
'connect',
'disconnect',
'signal',
'disconnectAll',
'disconnectAllTo'
];
MochiKit.Signal.__new__ = function (win) {
var m = MochiKit.Base;
this._document = document;
this._window = win;
this._lock = false;
this._dirty = false;
try {
this.connect(window, 'onunload', this._unloadCache);
} catch (e) {
// pass: might not be a browser
}
this.EXPORT_TAGS = {
':common': this.EXPORT,
':all': m.concat(this.EXPORT, this.EXPORT_OK)
};
m.nameFunctions(this);
};
MochiKit.Signal.__new__(this);
//
// XXX: Internet Explorer blows
//
if (MochiKit.__export__) {
connect = MochiKit.Signal.connect;
disconnect = MochiKit.Signal.disconnect;
disconnectAll = MochiKit.Signal.disconnectAll;
signal = MochiKit.Signal.signal;
}
MochiKit.Base._exportSymbols(this, MochiKit.Signal);
-589
View File
@@ -1,589 +0,0 @@
/***
Copyright (c) 2005 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
Mochi-ized By Thomas Herve (_firstname_@nimail.org)
See scriptaculous.js for full license.
***/
MochiKit.Base._deps('Sortable', ['Base', 'Iter', 'DOM', 'Position', 'DragAndDrop']);
MochiKit.Sortable.NAME = 'MochiKit.Sortable';
MochiKit.Sortable.VERSION = '1.4.2';
MochiKit.Sortable.__repr__ = function () {
return '[' + this.NAME + ' ' + this.VERSION + ']';
};
MochiKit.Sortable.toString = function () {
return this.__repr__();
};
MochiKit.Sortable.EXPORT = [
];
MochiKit.Sortable.EXPORT_OK = [
];
MochiKit.Base.update(MochiKit.Sortable, {
/***
Manage sortables. Mainly use the create function to add a sortable.
***/
sortables: {},
_findRootElement: function (element) {
while (element.tagName.toUpperCase() != "BODY") {
if (element.id && MochiKit.Sortable.sortables[element.id]) {
return element;
}
element = element.parentNode;
}
},
_createElementId: function(element) {
if (element.id == null || element.id == "") {
var d = MochiKit.DOM;
var id;
var count = 1;
while (d.getElement(id = "sortable" + count) != null) {
count += 1;
}
d.setNodeAttribute(element, "id", id);
}
},
/** @id MochiKit.Sortable.options */
options: function (element) {
element = MochiKit.Sortable._findRootElement(MochiKit.DOM.getElement(element));
if (!element) {
return;
}
return MochiKit.Sortable.sortables[element.id];
},
/** @id MochiKit.Sortable.destroy */
destroy: function (element){
var s = MochiKit.Sortable.options(element);
var b = MochiKit.Base;
var d = MochiKit.DragAndDrop;
if (s) {
MochiKit.Signal.disconnect(s.startHandle);
MochiKit.Signal.disconnect(s.endHandle);
b.map(function (dr) {
d.Droppables.remove(dr);
}, s.droppables);
b.map(function (dr) {
dr.destroy();
}, s.draggables);
delete MochiKit.Sortable.sortables[s.element.id];
}
},
/** @id MochiKit.Sortable.create */
create: function (element, options) {
element = MochiKit.DOM.getElement(element);
var self = MochiKit.Sortable;
self._createElementId(element);
/** @id MochiKit.Sortable.options */
options = MochiKit.Base.update({
/** @id MochiKit.Sortable.element */
element: element,
/** @id MochiKit.Sortable.tag */
tag: 'li', // assumes li children, override with tag: 'tagname'
/** @id MochiKit.Sortable.dropOnEmpty */
dropOnEmpty: false,
/** @id MochiKit.Sortable.tree */
tree: false,
/** @id MochiKit.Sortable.treeTag */
treeTag: 'ul',
/** @id MochiKit.Sortable.overlap */
overlap: 'vertical', // one of 'vertical', 'horizontal'
/** @id MochiKit.Sortable.constraint */
constraint: 'vertical', // one of 'vertical', 'horizontal', false
// also takes array of elements (or ids); or false
/** @id MochiKit.Sortable.containment */
containment: [element],
/** @id MochiKit.Sortable.handle */
handle: false, // or a CSS class
/** @id MochiKit.Sortable.only */
only: false,
/** @id MochiKit.Sortable.hoverclass */
hoverclass: null,
/** @id MochiKit.Sortable.ghosting */
ghosting: false,
/** @id MochiKit.Sortable.scroll */
scroll: false,
/** @id MochiKit.Sortable.scrollSensitivity */
scrollSensitivity: 20,
/** @id MochiKit.Sortable.scrollSpeed */
scrollSpeed: 15,
/** @id MochiKit.Sortable.format */
format: /^[^_]*_(.*)$/,
/** @id MochiKit.Sortable.onChange */
onChange: MochiKit.Base.noop,
/** @id MochiKit.Sortable.onUpdate */
onUpdate: MochiKit.Base.noop,
/** @id MochiKit.Sortable.accept */
accept: null
}, options);
// clear any old sortable with same element
self.destroy(element);
// build options for the draggables
var options_for_draggable = {
revert: true,
ghosting: options.ghosting,
scroll: options.scroll,
scrollSensitivity: options.scrollSensitivity,
scrollSpeed: options.scrollSpeed,
constraint: options.constraint,
handle: options.handle
};
if (options.starteffect) {
options_for_draggable.starteffect = options.starteffect;
}
if (options.reverteffect) {
options_for_draggable.reverteffect = options.reverteffect;
} else if (options.ghosting) {
options_for_draggable.reverteffect = function (innerelement) {
innerelement.style.top = 0;
innerelement.style.left = 0;
};
}
if (options.endeffect) {
options_for_draggable.endeffect = options.endeffect;
}
if (options.zindex) {
options_for_draggable.zindex = options.zindex;
}
// build options for the droppables
var options_for_droppable = {
overlap: options.overlap,
containment: options.containment,
hoverclass: options.hoverclass,
onhover: self.onHover,
tree: options.tree,
accept: options.accept
}
var options_for_tree = {
onhover: self.onEmptyHover,
overlap: options.overlap,
containment: options.containment,
hoverclass: options.hoverclass,
accept: options.accept
}
// fix for gecko engine
MochiKit.DOM.removeEmptyTextNodes(element);
options.draggables = [];
options.droppables = [];
// drop on empty handling
if (options.dropOnEmpty || options.tree) {
new MochiKit.DragAndDrop.Droppable(element, options_for_tree);
options.droppables.push(element);
}
MochiKit.Base.map(function (e) {
// handles are per-draggable
var handle = options.handle ?
MochiKit.DOM.getFirstElementByTagAndClassName(null,
options.handle, e) : e;
options.draggables.push(
new MochiKit.DragAndDrop.Draggable(e,
MochiKit.Base.update(options_for_draggable,
{handle: handle})));
new MochiKit.DragAndDrop.Droppable(e, options_for_droppable);
if (options.tree) {
e.treeNode = element;
}
options.droppables.push(e);
}, (self.findElements(element, options) || []));
if (options.tree) {
MochiKit.Base.map(function (e) {
new MochiKit.DragAndDrop.Droppable(e, options_for_tree);
e.treeNode = element;
options.droppables.push(e);
}, (self.findTreeElements(element, options) || []));
}
// keep reference
self.sortables[element.id] = options;
options.lastValue = self.serialize(element);
options.startHandle = MochiKit.Signal.connect(MochiKit.DragAndDrop.Draggables, 'start',
MochiKit.Base.partial(self.onStart, element));
options.endHandle = MochiKit.Signal.connect(MochiKit.DragAndDrop.Draggables, 'end',
MochiKit.Base.partial(self.onEnd, element));
},
/** @id MochiKit.Sortable.onStart */
onStart: function (element, draggable) {
var self = MochiKit.Sortable;
var options = self.options(element);
options.lastValue = self.serialize(options.element);
},
/** @id MochiKit.Sortable.onEnd */
onEnd: function (element, draggable) {
var self = MochiKit.Sortable;
self.unmark();
var options = self.options(element);
if (options.lastValue != self.serialize(options.element)) {
options.onUpdate(options.element);
}
},
// return all suitable-for-sortable elements in a guaranteed order
/** @id MochiKit.Sortable.findElements */
findElements: function (element, options) {
return MochiKit.Sortable.findChildren(element, options.only, options.tree, options.tag);
},
/** @id MochiKit.Sortable.findTreeElements */
findTreeElements: function (element, options) {
return MochiKit.Sortable.findChildren(
element, options.only, options.tree ? true : false, options.treeTag);
},
/** @id MochiKit.Sortable.findChildren */
findChildren: function (element, only, recursive, tagName) {
if (!element.hasChildNodes()) {
return null;
}
tagName = tagName.toUpperCase();
if (only) {
only = MochiKit.Base.flattenArray([only]);
}
var elements = [];
MochiKit.Base.map(function (e) {
if (e.tagName &&
e.tagName.toUpperCase() == tagName &&
(!only ||
MochiKit.Iter.some(only, function (c) {
return MochiKit.DOM.hasElementClass(e, c);
}))) {
elements.push(e);
}
if (recursive) {
var grandchildren = MochiKit.Sortable.findChildren(e, only, recursive, tagName);
if (grandchildren && grandchildren.length > 0) {
elements = elements.concat(grandchildren);
}
}
}, element.childNodes);
return elements;
},
/** @id MochiKit.Sortable.onHover */
onHover: function (element, dropon, overlap) {
if (MochiKit.DOM.isChildNode(dropon, element)) {
return;
}
var self = MochiKit.Sortable;
if (overlap > .33 && overlap < .66 && self.options(dropon).tree) {
return;
} else if (overlap > 0.5) {
self.mark(dropon, 'before');
if (dropon.previousSibling != element) {
var oldParentNode = element.parentNode;
element.style.visibility = 'hidden'; // fix gecko rendering
dropon.parentNode.insertBefore(element, dropon);
if (dropon.parentNode != oldParentNode) {
self.options(oldParentNode).onChange(element);
}
self.options(dropon.parentNode).onChange(element);
}
} else {
self.mark(dropon, 'after');
var nextElement = dropon.nextSibling || null;
if (nextElement != element) {
var oldParentNode = element.parentNode;
element.style.visibility = 'hidden'; // fix gecko rendering
dropon.parentNode.insertBefore(element, nextElement);
if (dropon.parentNode != oldParentNode) {
self.options(oldParentNode).onChange(element);
}
self.options(dropon.parentNode).onChange(element);
}
}
},
_offsetSize: function (element, type) {
if (type == 'vertical' || type == 'height') {
return element.offsetHeight;
} else {
return element.offsetWidth;
}
},
/** @id MochiKit.Sortable.onEmptyHover */
onEmptyHover: function (element, dropon, overlap) {
var oldParentNode = element.parentNode;
var self = MochiKit.Sortable;
var droponOptions = self.options(dropon);
if (!MochiKit.DOM.isChildNode(dropon, element)) {
var index;
var children = self.findElements(dropon, {tag: droponOptions.tag,
only: droponOptions.only});
var child = null;
if (children) {
var offset = self._offsetSize(dropon, droponOptions.overlap) * (1.0 - overlap);
for (index = 0; index < children.length; index += 1) {
if (offset - self._offsetSize(children[index], droponOptions.overlap) >= 0) {
offset -= self._offsetSize(children[index], droponOptions.overlap);
} else if (offset - (self._offsetSize (children[index], droponOptions.overlap) / 2) >= 0) {
child = index + 1 < children.length ? children[index + 1] : null;
break;
} else {
child = children[index];
break;
}
}
}
dropon.insertBefore(element, child);
self.options(oldParentNode).onChange(element);
droponOptions.onChange(element);
}
},
/** @id MochiKit.Sortable.unmark */
unmark: function () {
var m = MochiKit.Sortable._marker;
if (m) {
MochiKit.Style.hideElement(m);
}
},
/** @id MochiKit.Sortable.mark */
mark: function (dropon, position) {
// mark on ghosting only
var d = MochiKit.DOM;
var self = MochiKit.Sortable;
var sortable = self.options(dropon.parentNode);
if (sortable && !sortable.ghosting) {
return;
}
if (!self._marker) {
self._marker = d.getElement('dropmarker') ||
document.createElement('DIV');
MochiKit.Style.hideElement(self._marker);
d.addElementClass(self._marker, 'dropmarker');
self._marker.style.position = 'absolute';
document.getElementsByTagName('body').item(0).appendChild(self._marker);
}
var offsets = MochiKit.Position.cumulativeOffset(dropon);
self._marker.style.left = offsets.x + 'px';
self._marker.style.top = offsets.y + 'px';
if (position == 'after') {
if (sortable.overlap == 'horizontal') {
self._marker.style.left = (offsets.x + dropon.clientWidth) + 'px';
} else {
self._marker.style.top = (offsets.y + dropon.clientHeight) + 'px';
}
}
MochiKit.Style.showElement(self._marker);
},
_tree: function (element, options, parent) {
var self = MochiKit.Sortable;
var children = self.findElements(element, options) || [];
for (var i = 0; i < children.length; ++i) {
var match = children[i].id.match(options.format);
if (!match) {
continue;
}
var child = {
id: encodeURIComponent(match ? match[1] : null),
element: element,
parent: parent,
children: [],
position: parent.children.length,
container: self._findChildrenElement(children[i], options.treeTag.toUpperCase())
}
/* Get the element containing the children and recurse over it */
if (child.container) {
self._tree(child.container, options, child)
}
parent.children.push (child);
}
return parent;
},
/* Finds the first element of the given tag type within a parent element.
Used for finding the first LI[ST] within a L[IST]I[TEM].*/
_findChildrenElement: function (element, containerTag) {
if (element && element.hasChildNodes) {
containerTag = containerTag.toUpperCase();
for (var i = 0; i < element.childNodes.length; ++i) {
if (element.childNodes[i].tagName.toUpperCase() == containerTag) {
return element.childNodes[i];
}
}
}
return null;
},
/** @id MochiKit.Sortable.tree */
tree: function (element, options) {
element = MochiKit.DOM.getElement(element);
var sortableOptions = MochiKit.Sortable.options(element);
options = MochiKit.Base.update({
tag: sortableOptions.tag,
treeTag: sortableOptions.treeTag,
only: sortableOptions.only,
name: element.id,
format: sortableOptions.format
}, options || {});
var root = {
id: null,
parent: null,
children: new Array,
container: element,
position: 0
}
return MochiKit.Sortable._tree(element, options, root);
},
/**
* Specifies the sequence for the Sortable.
* @param {Node} element Element to use as the Sortable.
* @param {Object} newSequence New sequence to use.
* @param {Object} options Options to use fro the Sortable.
*/
setSequence: function (element, newSequence, options) {
var self = MochiKit.Sortable;
var b = MochiKit.Base;
element = MochiKit.DOM.getElement(element);
options = b.update(self.options(element), options || {});
var nodeMap = {};
b.map(function (n) {
var m = n.id.match(options.format);
if (m) {
nodeMap[m[1]] = [n, n.parentNode];
}
n.parentNode.removeChild(n);
}, self.findElements(element, options));
b.map(function (ident) {
var n = nodeMap[ident];
if (n) {
n[1].appendChild(n[0]);
delete nodeMap[ident];
}
}, newSequence);
},
/* Construct a [i] index for a particular node */
_constructIndex: function (node) {
var index = '';
do {
if (node.id) {
index = '[' + node.position + ']' + index;
}
} while ((node = node.parent) != null);
return index;
},
/** @id MochiKit.Sortable.sequence */
sequence: function (element, options) {
element = MochiKit.DOM.getElement(element);
var self = MochiKit.Sortable;
var options = MochiKit.Base.update(self.options(element), options || {});
return MochiKit.Base.map(function (item) {
return item.id.match(options.format) ? item.id.match(options.format)[1] : '';
}, MochiKit.DOM.getElement(self.findElements(element, options) || []));
},
/**
* Serializes the content of a Sortable. Useful to send this content through a XMLHTTPRequest.
* These options override the Sortable options for the serialization only.
* @param {Node} element Element to serialize.
* @param {Object} options Serialization options.
*/
serialize: function (element, options) {
element = MochiKit.DOM.getElement(element);
var self = MochiKit.Sortable;
options = MochiKit.Base.update(self.options(element), options || {});
var name = encodeURIComponent(options.name || element.id);
if (options.tree) {
return MochiKit.Base.flattenArray(MochiKit.Base.map(function (item) {
return [name + self._constructIndex(item) + "[id]=" +
encodeURIComponent(item.id)].concat(item.children.map(arguments.callee));
}, self.tree(element, options).children)).join('&');
} else {
return MochiKit.Base.map(function (item) {
return name + "[]=" + encodeURIComponent(item);
}, self.sequence(element, options)).join('&');
}
}
});
// trunk compatibility
MochiKit.Sortable.Sortable = MochiKit.Sortable;
MochiKit.Sortable.__new__ = function () {
MochiKit.Base.nameFunctions(this);
this.EXPORT_TAGS = {
":common": this.EXPORT,
":all": MochiKit.Base.concat(this.EXPORT, this.EXPORT_OK)
};
};
MochiKit.Sortable.__new__();
MochiKit.Base._exportSymbols(this, MochiKit.Sortable);
-594
View File
@@ -1,594 +0,0 @@
/***
MochiKit.Style 1.4.2
See <http://mochikit.com/> for documentation, downloads, license, etc.
(c) 2005-2006 Bob Ippolito, Beau Hartshorne. All rights Reserved.
***/
MochiKit.Base._deps('Style', ['Base', 'DOM']);
MochiKit.Style.NAME = 'MochiKit.Style';
MochiKit.Style.VERSION = '1.4.2';
MochiKit.Style.__repr__ = function () {
return '[' + this.NAME + ' ' + this.VERSION + ']';
};
MochiKit.Style.toString = function () {
return this.__repr__();
};
MochiKit.Style.EXPORT_OK = [];
MochiKit.Style.EXPORT = [
'setStyle',
'setOpacity',
'getStyle',
'getElementDimensions',
'elementDimensions', // deprecated
'setElementDimensions',
'getElementPosition',
'elementPosition', // deprecated
'setElementPosition',
"makePositioned",
"undoPositioned",
"makeClipping",
"undoClipping",
'setDisplayForElement',
'hideElement',
'showElement',
'getViewportDimensions',
'getViewportPosition',
'Dimensions',
'Coordinates'
];
/*
Dimensions
*/
/** @id MochiKit.Style.Dimensions */
MochiKit.Style.Dimensions = function (w, h) {
this.w = w;
this.h = h;
};
MochiKit.Style.Dimensions.prototype.__repr__ = function () {
var repr = MochiKit.Base.repr;
return '{w: ' + repr(this.w) + ', h: ' + repr(this.h) + '}';
};
MochiKit.Style.Dimensions.prototype.toString = function () {
return this.__repr__();
};
/*
Coordinates
*/
/** @id MochiKit.Style.Coordinates */
MochiKit.Style.Coordinates = function (x, y) {
this.x = x;
this.y = y;
};
MochiKit.Style.Coordinates.prototype.__repr__ = function () {
var repr = MochiKit.Base.repr;
return '{x: ' + repr(this.x) + ', y: ' + repr(this.y) + '}';
};
MochiKit.Style.Coordinates.prototype.toString = function () {
return this.__repr__();
};
MochiKit.Base.update(MochiKit.Style, {
/** @id MochiKit.Style.getStyle */
getStyle: function (elem, cssProperty) {
var dom = MochiKit.DOM;
var d = dom._document;
elem = dom.getElement(elem);
cssProperty = MochiKit.Base.camelize(cssProperty);
if (!elem || elem == d) {
return undefined;
}
if (cssProperty == 'opacity' && typeof(elem.filters) != 'undefined') {
var opacity = (MochiKit.Style.getStyle(elem, 'filter') || '').match(/alpha\(opacity=(.*)\)/);
if (opacity && opacity[1]) {
return parseFloat(opacity[1]) / 100;
}
return 1.0;
}
if (cssProperty == 'float' || cssProperty == 'cssFloat' || cssProperty == 'styleFloat') {
if (elem.style["float"]) {
return elem.style["float"];
} else if (elem.style.cssFloat) {
return elem.style.cssFloat;
} else if (elem.style.styleFloat) {
return elem.style.styleFloat;
} else {
return "none";
}
}
var value = elem.style ? elem.style[cssProperty] : null;
if (!value) {
if (d.defaultView && d.defaultView.getComputedStyle) {
var css = d.defaultView.getComputedStyle(elem, null);
cssProperty = cssProperty.replace(/([A-Z])/g, '-$1'
).toLowerCase(); // from dojo.style.toSelectorCase
value = css ? css.getPropertyValue(cssProperty) : null;
} else if (elem.currentStyle) {
value = elem.currentStyle[cssProperty];
if (/^\d/.test(value) && !/px$/.test(value) && cssProperty != 'fontWeight') {
/* Convert to px using an hack from Dean Edwards */
var left = elem.style.left;
var rsLeft = elem.runtimeStyle.left;
elem.runtimeStyle.left = elem.currentStyle.left;
elem.style.left = value || 0;
value = elem.style.pixelLeft + "px";
elem.style.left = left;
elem.runtimeStyle.left = rsLeft;
}
}
}
if (cssProperty == 'opacity') {
value = parseFloat(value);
}
if (/Opera/.test(navigator.userAgent) && (MochiKit.Base.findValue(['left', 'top', 'right', 'bottom'], cssProperty) != -1)) {
if (MochiKit.Style.getStyle(elem, 'position') == 'static') {
value = 'auto';
}
}
return value == 'auto' ? null : value;
},
/** @id MochiKit.Style.setStyle */
setStyle: function (elem, style) {
elem = MochiKit.DOM.getElement(elem);
for (var name in style) {
switch (name) {
case 'opacity':
MochiKit.Style.setOpacity(elem, style[name]);
break;
case 'float':
case 'cssFloat':
case 'styleFloat':
if (typeof(elem.style["float"]) != "undefined") {
elem.style["float"] = style[name];
} else if (typeof(elem.style.cssFloat) != "undefined") {
elem.style.cssFloat = style[name];
} else {
elem.style.styleFloat = style[name];
}
break;
default:
elem.style[MochiKit.Base.camelize(name)] = style[name];
}
}
},
/** @id MochiKit.Style.setOpacity */
setOpacity: function (elem, o) {
elem = MochiKit.DOM.getElement(elem);
var self = MochiKit.Style;
if (o == 1) {
var toSet = /Gecko/.test(navigator.userAgent) && !(/Konqueror|AppleWebKit|KHTML/.test(navigator.userAgent));
elem.style["opacity"] = toSet ? 0.999999 : 1.0;
if (/MSIE/.test(navigator.userAgent)) {
elem.style['filter'] =
self.getStyle(elem, 'filter').replace(/alpha\([^\)]*\)/gi, '');
}
} else {
if (o < 0.00001) {
o = 0;
}
elem.style["opacity"] = o;
if (/MSIE/.test(navigator.userAgent)) {
elem.style['filter'] =
self.getStyle(elem, 'filter').replace(/alpha\([^\)]*\)/gi, '') + 'alpha(opacity=' + o * 100 + ')';
}
}
},
/*
getElementPosition is adapted from YAHOO.util.Dom.getXY v0.9.0.
Copyright: Copyright (c) 2006, Yahoo! Inc. All rights reserved.
License: BSD, http://developer.yahoo.net/yui/license.txt
*/
/** @id MochiKit.Style.getElementPosition */
getElementPosition: function (elem, /* optional */relativeTo) {
var self = MochiKit.Style;
var dom = MochiKit.DOM;
elem = dom.getElement(elem);
if (!elem ||
(!(elem.x && elem.y) &&
(!elem.parentNode === null ||
self.getStyle(elem, 'display') == 'none'))) {
return undefined;
}
var c = new self.Coordinates(0, 0);
var box = null;
var parent = null;
var d = MochiKit.DOM._document;
var de = d.documentElement;
var b = d.body;
if (!elem.parentNode && elem.x && elem.y) {
/* it's just a MochiKit.Style.Coordinates object */
c.x += elem.x || 0;
c.y += elem.y || 0;
} else if (elem.getBoundingClientRect) { // IE shortcut
/*
The IE shortcut can be off by two. We fix it. See:
http://msdn.microsoft.com/workshop/author/dhtml/reference/methods/getboundingclientrect.asp
This is similar to the method used in
MochiKit.Signal.Event.mouse().
*/
box = elem.getBoundingClientRect();
c.x += box.left +
(de.scrollLeft || b.scrollLeft) -
(de.clientLeft || 0);
c.y += box.top +
(de.scrollTop || b.scrollTop) -
(de.clientTop || 0);
} else if (elem.offsetParent) {
c.x += elem.offsetLeft;
c.y += elem.offsetTop;
parent = elem.offsetParent;
if (parent != elem) {
while (parent) {
c.x += parseInt(parent.style.borderLeftWidth) || 0;
c.y += parseInt(parent.style.borderTopWidth) || 0;
c.x += parent.offsetLeft;
c.y += parent.offsetTop;
parent = parent.offsetParent;
}
}
/*
Opera < 9 and old Safari (absolute) incorrectly account for
body offsetTop and offsetLeft.
*/
var ua = navigator.userAgent.toLowerCase();
if ((typeof(opera) != 'undefined' &&
parseFloat(opera.version()) < 9) ||
(ua.indexOf('AppleWebKit') != -1 &&
self.getStyle(elem, 'position') == 'absolute')) {
c.x -= b.offsetLeft;
c.y -= b.offsetTop;
}
// Adjust position for strange Opera scroll bug
if (elem.parentNode) {
parent = elem.parentNode;
} else {
parent = null;
}
while (parent) {
var tagName = parent.tagName.toUpperCase();
if (tagName === 'BODY' || tagName === 'HTML') {
break;
}
var disp = self.getStyle(parent, 'display');
// Handle strange Opera bug for some display
if (disp.search(/^inline|table-row.*$/i)) {
c.x -= parent.scrollLeft;
c.y -= parent.scrollTop;
}
if (parent.parentNode) {
parent = parent.parentNode;
} else {
parent = null;
}
}
}
if (typeof(relativeTo) != 'undefined') {
relativeTo = arguments.callee(relativeTo);
if (relativeTo) {
c.x -= (relativeTo.x || 0);
c.y -= (relativeTo.y || 0);
}
}
return c;
},
/** @id MochiKit.Style.setElementPosition */
setElementPosition: function (elem, newPos/* optional */, units) {
elem = MochiKit.DOM.getElement(elem);
if (typeof(units) == 'undefined') {
units = 'px';
}
var newStyle = {};
var isUndefNull = MochiKit.Base.isUndefinedOrNull;
if (!isUndefNull(newPos.x)) {
newStyle['left'] = newPos.x + units;
}
if (!isUndefNull(newPos.y)) {
newStyle['top'] = newPos.y + units;
}
MochiKit.DOM.updateNodeAttributes(elem, {'style': newStyle});
},
/** @id MochiKit.Style.makePositioned */
makePositioned: function (element) {
element = MochiKit.DOM.getElement(element);
var pos = MochiKit.Style.getStyle(element, 'position');
if (pos == 'static' || !pos) {
element.style.position = 'relative';
// Opera returns the offset relative to the positioning context,
// when an element is position relative but top and left have
// not been defined
if (/Opera/.test(navigator.userAgent)) {
element.style.top = 0;
element.style.left = 0;
}
}
},
/** @id MochiKit.Style.undoPositioned */
undoPositioned: function (element) {
element = MochiKit.DOM.getElement(element);
if (element.style.position == 'relative') {
element.style.position = element.style.top = element.style.left = element.style.bottom = element.style.right = '';
}
},
/** @id MochiKit.Style.makeClipping */
makeClipping: function (element) {
element = MochiKit.DOM.getElement(element);
var s = element.style;
var oldOverflow = { 'overflow': s.overflow,
'overflow-x': s.overflowX,
'overflow-y': s.overflowY };
if ((MochiKit.Style.getStyle(element, 'overflow') || 'visible') != 'hidden') {
element.style.overflow = 'hidden';
element.style.overflowX = 'hidden';
element.style.overflowY = 'hidden';
}
return oldOverflow;
},
/** @id MochiKit.Style.undoClipping */
undoClipping: function (element, overflow) {
element = MochiKit.DOM.getElement(element);
if (typeof(overflow) == 'string') {
element.style.overflow = overflow;
} else if (overflow != null) {
element.style.overflow = overflow['overflow'];
element.style.overflowX = overflow['overflow-x'];
element.style.overflowY = overflow['overflow-y'];
}
},
/** @id MochiKit.Style.getElementDimensions */
getElementDimensions: function (elem, contentSize/*optional*/) {
var self = MochiKit.Style;
var dom = MochiKit.DOM;
if (typeof(elem.w) == 'number' || typeof(elem.h) == 'number') {
return new self.Dimensions(elem.w || 0, elem.h || 0);
}
elem = dom.getElement(elem);
if (!elem) {
return undefined;
}
var disp = self.getStyle(elem, 'display');
// display can be empty/undefined on WebKit/KHTML
if (disp == 'none' || disp == '' || typeof(disp) == 'undefined') {
var s = elem.style;
var originalVisibility = s.visibility;
var originalPosition = s.position;
var originalDisplay = s.display;
s.visibility = 'hidden';
s.position = 'absolute';
s.display = self._getDefaultDisplay(elem);
var originalWidth = elem.offsetWidth;
var originalHeight = elem.offsetHeight;
s.display = originalDisplay;
s.position = originalPosition;
s.visibility = originalVisibility;
} else {
originalWidth = elem.offsetWidth || 0;
originalHeight = elem.offsetHeight || 0;
}
if (contentSize) {
var tableCell = 'colSpan' in elem && 'rowSpan' in elem;
var collapse = (tableCell && elem.parentNode && self.getStyle(
elem.parentNode, 'borderCollapse') == 'collapse')
if (collapse) {
if (/MSIE/.test(navigator.userAgent)) {
var borderLeftQuota = elem.previousSibling? 0.5 : 1;
var borderRightQuota = elem.nextSibling? 0.5 : 1;
}
else {
var borderLeftQuota = 0.5;
var borderRightQuota = 0.5;
}
} else {
var borderLeftQuota = 1;
var borderRightQuota = 1;
}
originalWidth -= Math.round(
(parseFloat(self.getStyle(elem, 'paddingLeft')) || 0)
+ (parseFloat(self.getStyle(elem, 'paddingRight')) || 0)
+ borderLeftQuota *
(parseFloat(self.getStyle(elem, 'borderLeftWidth')) || 0)
+ borderRightQuota *
(parseFloat(self.getStyle(elem, 'borderRightWidth')) || 0)
);
if (tableCell) {
if (/Gecko|Opera/.test(navigator.userAgent)
&& !/Konqueror|AppleWebKit|KHTML/.test(navigator.userAgent)) {
var borderHeightQuota = 0;
} else if (/MSIE/.test(navigator.userAgent)) {
var borderHeightQuota = 1;
} else {
var borderHeightQuota = collapse? 0.5 : 1;
}
} else {
var borderHeightQuota = 1;
}
originalHeight -= Math.round(
(parseFloat(self.getStyle(elem, 'paddingTop')) || 0)
+ (parseFloat(self.getStyle(elem, 'paddingBottom')) || 0)
+ borderHeightQuota * (
(parseFloat(self.getStyle(elem, 'borderTopWidth')) || 0)
+ (parseFloat(self.getStyle(elem, 'borderBottomWidth')) || 0))
);
}
return new self.Dimensions(originalWidth, originalHeight);
},
/** @id MochiKit.Style.setElementDimensions */
setElementDimensions: function (elem, newSize/* optional */, units) {
elem = MochiKit.DOM.getElement(elem);
if (typeof(units) == 'undefined') {
units = 'px';
}
var newStyle = {};
var isUndefNull = MochiKit.Base.isUndefinedOrNull;
if (!isUndefNull(newSize.w)) {
newStyle['width'] = newSize.w + units;
}
if (!isUndefNull(newSize.h)) {
newStyle['height'] = newSize.h + units;
}
MochiKit.DOM.updateNodeAttributes(elem, {'style': newStyle});
},
_getDefaultDisplay: function (elem) {
var self = MochiKit.Style;
var dom = MochiKit.DOM;
elem = dom.getElement(elem);
if (!elem) {
return undefined;
}
var tagName = elem.tagName.toUpperCase();
return self._defaultDisplay[tagName] || 'block';
},
/** @id MochiKit.Style.setDisplayForElement */
setDisplayForElement: function (display, element/*, ...*/) {
var elements = MochiKit.Base.extend(null, arguments, 1);
var getElement = MochiKit.DOM.getElement;
for (var i = 0; i < elements.length; i++) {
element = getElement(elements[i]);
if (element) {
element.style.display = display;
}
}
},
/** @id MochiKit.Style.getViewportDimensions */
getViewportDimensions: function () {
var d = new MochiKit.Style.Dimensions();
var w = MochiKit.DOM._window;
var b = MochiKit.DOM._document.body;
if (w.innerWidth) {
d.w = w.innerWidth;
d.h = w.innerHeight;
} else if (b && b.parentElement && b.parentElement.clientWidth) {
d.w = b.parentElement.clientWidth;
d.h = b.parentElement.clientHeight;
} else if (b && b.clientWidth) {
d.w = b.clientWidth;
d.h = b.clientHeight;
}
return d;
},
/** @id MochiKit.Style.getViewportPosition */
getViewportPosition: function () {
var c = new MochiKit.Style.Coordinates(0, 0);
var d = MochiKit.DOM._document;
var de = d.documentElement;
var db = d.body;
if (de && (de.scrollTop || de.scrollLeft)) {
c.x = de.scrollLeft;
c.y = de.scrollTop;
} else if (db) {
c.x = db.scrollLeft;
c.y = db.scrollTop;
}
return c;
},
__new__: function () {
var m = MochiKit.Base;
var inlines = ['A','ABBR','ACRONYM','B','BASEFONT','BDO','BIG','BR',
'CITE','CODE','DFN','EM','FONT','I','IMG','KBD','LABEL',
'Q','S','SAMP','SMALL','SPAN','STRIKE','STRONG','SUB',
'SUP','TEXTAREA','TT','U','VAR'];
this._defaultDisplay = { 'TABLE': 'table',
'THEAD': 'table-header-group',
'TBODY': 'table-row-group',
'TFOOT': 'table-footer-group',
'COLGROUP': 'table-column-group',
'COL': 'table-column',
'TR': 'table-row',
'TD': 'table-cell',
'TH': 'table-cell',
'CAPTION': 'table-caption',
'LI': 'list-item',
'INPUT': 'inline-block',
'SELECT': 'inline-block' };
// CSS 'display' support in IE6/7 is just broken...
if (/MSIE/.test(navigator.userAgent)) {
for (var k in this._defaultDisplay) {
var v = this._defaultDisplay[k];
if (v.indexOf('table') == 0) {
this._defaultDisplay[k] = 'block';
}
}
}
for (var i = 0; i < inlines.length; i++) {
this._defaultDisplay[inlines[i]] = 'inline';
}
this.elementPosition = this.getElementPosition;
this.elementDimensions = this.getElementDimensions;
this.hideElement = m.partial(this.setDisplayForElement, 'none');
// TODO: showElement could be improved by using getDefaultDisplay.
this.showElement = m.partial(this.setDisplayForElement, 'block');
this.EXPORT_TAGS = {
':common': this.EXPORT,
':all': m.concat(this.EXPORT, this.EXPORT_OK)
};
m.nameFunctions(this);
}
});
MochiKit.Style.__new__();
MochiKit.Base._exportSymbols(this, MochiKit.Style);
-162
View File
@@ -1,162 +0,0 @@
/***
MochiKit.Test 1.4.2
See <http://mochikit.com/> for documentation, downloads, license, etc.
(c) 2005 Bob Ippolito. All rights Reserved.
***/
MochiKit.Base._deps('Test', ['Base']);
MochiKit.Test.NAME = "MochiKit.Test";
MochiKit.Test.VERSION = "1.4.2";
MochiKit.Test.__repr__ = function () {
return "[" + this.NAME + " " + this.VERSION + "]";
};
MochiKit.Test.toString = function () {
return this.__repr__();
};
MochiKit.Test.EXPORT = ["runTests"];
MochiKit.Test.EXPORT_OK = [];
MochiKit.Test.runTests = function (obj) {
if (typeof(obj) == "string") {
obj = JSAN.use(obj);
}
var suite = new MochiKit.Test.Suite();
suite.run(obj);
};
MochiKit.Test.Suite = function () {
this.testIndex = 0;
MochiKit.Base.bindMethods(this);
};
MochiKit.Test.Suite.prototype = {
run: function (obj) {
try {
obj(this);
} catch (e) {
this.traceback(e);
}
},
traceback: function (e) {
var items = MochiKit.Iter.sorted(MochiKit.Base.items(e));
print("not ok " + this.testIndex + " - Error thrown");
for (var i = 0; i < items.length; i++) {
var kv = items[i];
if (kv[0] == "stack") {
kv[1] = kv[1].split(/\n/)[0];
}
this.print("# " + kv.join(": "));
}
},
print: function (s) {
print(s);
},
is: function (got, expected, /* optional */message) {
var res = 1;
var msg = null;
try {
res = MochiKit.Base.compare(got, expected);
} catch (e) {
msg = "Can not compare " + typeof(got) + ":" + typeof(expected);
}
if (res) {
msg = "Expected value did not compare equal";
}
if (!res) {
return this.testResult(true, message);
}
return this.testResult(false, message,
[[msg], ["got:", got], ["expected:", expected]]);
},
testResult: function (pass, msg, failures) {
this.testIndex += 1;
if (pass) {
this.print("ok " + this.testIndex + " - " + msg);
return;
}
this.print("not ok " + this.testIndex + " - " + msg);
if (failures) {
for (var i = 0; i < failures.length; i++) {
this.print("# " + failures[i].join(" "));
}
}
},
isDeeply: function (got, expected, /* optional */message) {
var m = MochiKit.Base;
var res = 1;
try {
res = m.compare(got, expected);
} catch (e) {
// pass
}
if (res === 0) {
return this.ok(true, message);
}
var gk = m.keys(got);
var ek = m.keys(expected);
gk.sort();
ek.sort();
if (m.compare(gk, ek)) {
// differing keys
var cmp = {};
var i;
for (i = 0; i < gk.length; i++) {
cmp[gk[i]] = "got";
}
for (i = 0; i < ek.length; i++) {
if (ek[i] in cmp) {
delete cmp[ek[i]];
} else {
cmp[ek[i]] = "expected";
}
}
var diffkeys = m.keys(cmp);
diffkeys.sort();
var gotkeys = [];
var expkeys = [];
while (diffkeys.length) {
var k = diffkeys.shift();
if (k in Object.prototype) {
continue;
}
(cmp[k] == "got" ? gotkeys : expkeys).push(k);
}
}
return this.testResult((!res), msg,
(msg ? [["got:", got], ["expected:", expected]] : undefined)
);
},
ok: function (res, message) {
return this.testResult(res, message);
}
};
MochiKit.Test.__new__ = function () {
var m = MochiKit.Base;
this.EXPORT_TAGS = {
":common": this.EXPORT,
":all": m.concat(this.EXPORT, this.EXPORT_OK)
};
m.nameFunctions(this);
};
MochiKit.Test.__new__();
MochiKit.Base._exportSymbols(this, MochiKit.Test);
File diff suppressed because it is too large Load Diff
-18
View File
@@ -1,18 +0,0 @@
dojo.kwCompoundRequire({
"common": [
"MochiKit.Base",
"MochiKit.Iter",
"MochiKit.Logging",
"MochiKit.DateTime",
"MochiKit.Format",
"MochiKit.Async",
"MochiKit.DOM",
"MochiKit.Style",
"MochiKit.LoggingPane",
"MochiKit.Color",
"MochiKit.Signal",
"MochiKit.Position",
"MochiKit.Visual"
]
});
dojo.provide("MochiKit.*");
BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 462 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 462 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 86 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 42 KiB

+130 -22
View File
@@ -1,31 +1,139 @@
tr.flowerlist:hover td {
background:#eee;
cursor: pointer;
:root {
--bg: #0b1010;
--panel: #131b1a;
--panel-2: #182321;
--line: #293735;
--text: #f3f4ec;
--muted: #98a6a1;
--accent: #e5ff78;
--accent-ink: #172000;
--danger: #ff8e85;
--radius: 18px;
font-family: Inter, ui-sans-serif, system-ui, sans-serif;
color: var(--text);
background: var(--bg);
font-synthesis: none;
}
* { box-sizing: border-box; }
body { margin: 0; min-height: 100vh; background: radial-gradient(circle at 12% 0%, #172522 0, transparent 35rem), var(--bg); }
button, input { font: inherit; }
a { color: inherit; }
.flowerlist {
width: 100%;
}
.site-header { min-height: 76px; padding: 16px clamp(20px, 5vw, 72px); display: flex; align-items: center; justify-content: space-between; gap: 24px; border-bottom: 1px solid var(--line); }
.brand { display: inline-flex; align-items: center; gap: 10px; font: 600 1.35rem Georgia, serif; text-decoration: none; }
.brand-logo { display: block; width: 34px; height: 34px; border-radius: 9px; }
.nav-actions { display: flex; align-items: center; gap: 8px; }
.nav-actions form { margin: 0; }
.text-link { color: var(--muted); text-decoration: none; font-size: .92rem; }
.text-link:hover { color: var(--text); }
tr.flowerlist a {
color: inherit; /* blue colors for links too */
text-decoration: inherit; /* no underline */
}
.page-shell { width: min(1040px, calc(100% - 40px)); margin: 0 auto; padding: clamp(44px, 7vw, 80px) 0; min-height: calc(100vh - 150px); }
footer { padding: 24px; color: #65716e; text-align: center; font-size: .8rem; }
h1, h2, p { margin-top: 0; }
h1 { margin-bottom: 18px; font: 600 clamp(1.125rem, 2.5vw, 2rem)/1.1 Inter, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; letter-spacing: -.025em; }
h2 { font: 600 1.55rem Georgia, serif; }
.eyebrow { margin-bottom: 10px; color: var(--muted); font-size: .82rem; font-weight: 600; letter-spacing: .01em; }
.muted, .intro p { color: var(--muted); line-height: 1.7; }
td.white {
color: #eee
}
.auth-layout { display: grid; grid-template-columns: minmax(0, 1.1fr) minmax(320px, 430px); align-items: center; gap: clamp(40px, 8vw, 96px); }
.intro { max-width: 620px; }
.intro p:not(.eyebrow) { max-width: 520px; font-size: 1.05rem; }
.card { background: linear-gradient(145deg, rgba(27, 39, 37, .94), rgba(16, 23, 22, .98)); border: 1px solid var(--line); border-radius: var(--radius); box-shadow: 0 26px 80px rgba(0, 0, 0, .25); }
.form-card { display: flex; flex-direction: column; padding: clamp(28px, 5vw, 44px); }
.form-card label { margin: 18px 0 8px; color: #c8cfcb; font-size: .82rem; font-weight: 600; }
.form-card label span { color: var(--muted); font-weight: 400; }
input { width: 100%; padding: 14px 15px; color: var(--text); background: #0d1413; border: 1px solid #344340; border-radius: 10px; outline: none; }
input:focus { border-color: var(--accent); box-shadow: 0 0 0 3px rgba(229, 255, 120, .1); }
input::placeholder { color: #61706c; }
.form-card .button { margin-top: 26px; }
.field-help { margin: 8px 0 0; color: var(--muted); font-size: .76rem; line-height: 1.5; }
.field-error { padding: 10px 12px; color: #ffd0cc; background: #3b1d1b; border-radius: 8px; font-size: .85rem; }
td.left {
text-align: left;
}
.button, .icon-button { border: 0; cursor: pointer; }
.button { display: inline-flex; justify-content: center; align-items: center; min-height: 46px; padding: 0 19px; border-radius: 10px; font-weight: 700; }
.button.primary { color: var(--accent-ink); background: var(--accent); }
.button.primary:hover { background: #efffa9; transform: translateY(-1px); }
.button.ghost { color: var(--text); background: transparent; border: 1px solid var(--line); }
.button.ghost:hover { background: var(--panel-2); }
.button.compact { min-height: 38px; padding: 0 14px; font-size: .82rem; }
.button.danger { color: #2c0906; background: var(--danger); }
td.right {
text-align: right;
}
.notices { position: fixed; z-index: 10; top: 88px; right: 24px; display: grid; gap: 8px; }
.notice { max-width: 380px; padding: 12px 16px; background: var(--panel-2); border: 1px solid var(--line); border-radius: 10px; box-shadow: 0 12px 35px #0008; font-size: .86rem; }
.notice-success { border-color: #53642f; }
.notice-error { border-color: #713b36; }
td.blue {
color: #208dd6;
.vault-header { display: flex; justify-content: space-between; align-items: end; gap: 32px; margin-bottom: 38px; }
.vault-header h1 { margin: 0; font-size: clamp(1.1rem, 2.5vw, 1.75rem); }
.search-field { width: min(100%, 360px); }
.entry-list { display: grid; gap: 10px; }
.entry-row { margin: 0; }
.entry-button { width: 100%; display: grid; grid-template-columns: 44px minmax(0, 1fr) auto 20px; align-items: center; gap: 15px; padding: 17px 18px; color: var(--text); text-align: left; background: rgba(19, 27, 26, .78); border: 1px solid var(--line); border-radius: 13px; cursor: pointer; }
.entry-button:hover { background: var(--panel-2); border-color: #42524f; transform: translateX(2px); }
.entry-icon { display: grid; place-items: center; width: 44px; height: 44px; color: var(--accent); background: #263020; border-radius: 12px; font: 600 1.15rem Georgia, serif; }
.entry-icon.large { width: 64px; height: 64px; font-size: 1.55rem; border-radius: 16px; }
.entry-copy { min-width: 0; display: grid; gap: 4px; }
.entry-copy strong, .entry-copy span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.entry-copy span, .entry-button time { color: var(--muted); font-size: .82rem; }
.chevron { color: #6e7d78; font-size: 1.6rem; }
.empty-state { padding: 72px 20px; color: var(--muted); text-align: center; border: 1px dashed var(--line); border-radius: var(--radius); }
.empty-state > span { color: var(--accent); font-size: 2rem; }
.empty-state h2 { margin: 12px 0 6px; color: var(--text); }
.detail-card { max-width: 760px; margin: 0 auto; padding: clamp(28px, 6vw, 58px); }
.detail-heading { display: flex; align-items: center; gap: 20px; padding-bottom: 32px; border-bottom: 1px solid var(--line); }
.detail-heading h1 { margin: 0 0 5px; font-size: clamp(.95rem, 2vw, 1.4rem); overflow-wrap: anywhere; }
.detail-heading p { margin-bottom: 6px; }
.details { margin: 0; }
.details > div { display: grid; grid-template-columns: 130px 1fr; gap: 20px; padding: 24px 0; border-bottom: 1px solid var(--line); }
.details dt { color: var(--muted); font-size: .8rem; }
.details dd { margin: 0; overflow-wrap: anywhere; }
.secret-line { display: flex; align-items: center; gap: 10px; }
.secret-line > span { flex: 1; font-family: ui-monospace, monospace; }
.icon-button { padding: 7px 10px; color: var(--accent); background: #263020; border-radius: 7px; font-size: .76rem; }
.detail-actions { display: flex; justify-content: flex-end; padding-top: 30px; }
.editor-layout { max-width: 760px; margin: 0 auto; }
.editor-layout > div:first-child { margin-bottom: 34px; }
.editor-layout h1 { font-size: clamp(1.1rem, 2.5vw, 1.75rem); }
.form-card.wide { padding: clamp(25px, 5vw, 44px); }
.danger-zone { display: flex; justify-content: flex-end; margin-top: 18px; }
.sr-only { position: absolute; width: 1px; height: 1px; padding: 0; overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0; }
[hidden] { display: none !important; }
@media (max-width: 760px) {
body { padding-bottom: 68px; }
.site-header { min-height: 64px; padding: 14px 16px; }
.brand { font-size: 1.15rem; }
.brand-logo { width: 32px; height: 32px; }
.nav-actions { position: fixed; z-index: 20; right: 0; bottom: 0; left: 0; min-height: 60px; padding: 8px 12px max(8px, env(safe-area-inset-bottom)); justify-content: center; gap: 6px; background: rgba(11, 16, 16, .97); border-top: 1px solid var(--line); }
.nav-actions .button { min-height: 42px; padding: 0 13px; }
.nav-actions .text-link { display: inline-flex; min-height: 42px; padding: 0 18px; align-items: center; color: var(--text); border: 1px solid var(--line); border-radius: 9px; }
.auth-layout { grid-template-columns: 1fr; }
.intro { max-width: 34rem; }
.intro h1 { font-size: 1.175rem; }
.intro p:not(.eyebrow) { font-size: .95rem; }
.page-shell { width: min(calc(100% - 28px), 680px); padding: 38px 0; min-height: auto; }
.form-card { padding: 24px 20px; }
input { min-height: 48px; font-size: 16px; }
.notices { top: 74px; right: 14px; left: 14px; }
.notice { max-width: none; }
.vault-header { align-items: stretch; flex-direction: column; }
.vault-header h1 { font-size: 1.175rem; }
.search-field { width: 100%; }
.entry-button { min-height: 72px; grid-template-columns: 40px minmax(0, 1fr) 14px; gap: 12px; padding: 14px 12px; }
.entry-icon { width: 40px; height: 40px; }
.entry-button time { display: none; }
.detail-card { padding: 24px 18px; }
.detail-heading { align-items: flex-start; gap: 14px; padding-bottom: 24px; }
.entry-icon.large { width: 48px; height: 48px; border-radius: 12px; font-size: 1.2rem; }
.detail-heading h1 { font-size: 1rem; }
.details > div { grid-template-columns: 1fr; gap: 8px; }
.secret-line { flex-wrap: wrap; }
.secret-line > span { flex-basis: 100%; min-height: 28px; }
.icon-button { min-height: 42px; padding: 8px 14px; }
.detail-actions .button, .danger-zone .button { min-height: 48px; width: 100%; }
.detail-actions, .detail-actions form, .danger-zone { width: 100%; }
footer { display: none; }
}
-1338
View File
File diff suppressed because it is too large Load Diff
-22
View File
@@ -1,22 +0,0 @@
/**
* Created by ignace on 29-9-15.
*/
function addMarker(map, latlong, text) {
var ll = latlong.split(',');
var myLatlng = new google.maps.LatLng(ll[0],ll[1]);
var marker = new google.maps.Marker({
position: myLatlng,
title: text
});
marker.setMap(map);
}
function makeGoogleMap() {
var mapOptions = {
center: new google.maps.LatLng(50,0),
zoom: 1,
mapTypeId: google.maps.MapTypeId.ROADMAP
};
var map = new google.maps.Map(document.getElementById("map-canvas"), mapOptions);
addAllMarkers(map);
}
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 164 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 89 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 92 B

-4
View File
File diff suppressed because one or more lines are too long
BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 MiB

BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 290 B

-281
View File
@@ -1,281 +0,0 @@
* {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
/*
* -- BASE STYLES --
* Most of these are inherited from Base, but I want to change a few.
*/
body {
line-height: 1.7em;
color: #7f8c8d;
font-size: 13px;
}
h1,
h2,
h3,
h4,
h5,
h6,
label {
color: #34495e;
}
.pure-img-responsive {
max-width: 100%;
height: auto;
}
/*
* -- LAYOUT STYLES --
* These are some useful classes which I will need
*/
.l-box {
padding: 1em;
}
.l-box-lrg {
padding: 2em;
border-bottom: 1px solid rgba(0,0,0,0.1);
}
.is-center {
text-align: center;
}
/*
* -- PURE FORM STYLES --
* Style the form inputs and labels
*/
.pure-form label {
margin: 1em 0 0;
font-weight: bold;
font-size: 100%;
}
.pure-form input[type] {
border: 2px solid #ddd;
box-shadow: none;
font-size: 100%;
width: 100%;
margin-bottom: 1em;
}
/*
* -- PURE BUTTON STYLES --
* I want my pure-button elements to look a little different
*/
.pure-button {
background-color: #1f8dd6;
color: white;
padding: 0.5em 2em;
border-radius: 5px;
}
a.pure-button-primary {
background: white;
color: #1f8dd6;
border-radius: 5px;
font-size: 120%;
}
/*
* -- MENU STYLES --
* I want to customize how my .pure-menu looks at the top of the page
*/
.home-menu {
padding: 0.5em;
text-align: center;
box-shadow: 0 1px 1px rgba(0,0,0, 0.10);
}
.home-menu {
background: #2d3e50;
}
.pure-menu.pure-menu-fixed {
/* Fixed menus normally have a border at the bottom. */
border-bottom: none;
/* I need a higher z-index here because of the scroll-over effect. */
z-index: 4;
}
.home-menu .pure-menu-heading {
color: white;
font-weight: 400;
font-size: 120%;
}
.home-menu .pure-menu-selected a {
color: white;
}
.home-menu a {
color: #6FBEF3;
}
.home-menu li a:hover,
.home-menu li a:focus {
background: none;
border: none;
color: #AECFE5;
}
/*
* -- SPLASH STYLES --
* This is the blue top section that appears on the page.
*/
.splash-container {
background: #1f8dd6;
z-index: 1;
overflow: hidden;
/* The following styles are required for the "scroll-over" effect */
width: 100%;
height: 88%;
top: 0;
left: 0;
position: fixed !important;
}
.splash {
/* absolute center .splash within .splash-container */
width: 80%;
height: 50%;
margin: auto;
position: absolute;
top: 100px; left: 0; bottom: 0; right: 0;
text-align: center;
}
/* This is the main heading that appears on the blue section */
.splash-head {
font-size: 20px;
font-weight: bold;
color: white;
border: 3px solid white;
padding: 1em 1.6em;
font-weight: 100;
border-radius: 5px;
line-height: 1em;
}
/* This is the subheading that appears on the blue section */
.splash-subhead {
color: white;
letter-spacing: 0.05em;
opacity: 0.8;
}
/*
* -- CONTENT STYLES --
* This represents the content area (everything below the blue section)
*/
.content-wrapper {
/* These styles are required for the "scroll-over" effect */
position: absolute;
top: 20%;
width: 100%;
min-height: 12%;
z-index: 2;
background: white;
}
/* This is the class used for the main content headers (<h2>) */
.content-head {
font-weight: 400;
text-transform: uppercase;
letter-spacing: 0.1em;
margin: 2em 0 1em;
}
/* This is a modifier class used when the content-head is inside a ribbon */
.content-head-ribbon {
color: white;
}
/* This is the class used for the content sub-headers (<h3>) */
.content-subhead {
color: #1f8dd6;
}
.content-subhead i {
margin-right: 7px;
}
/* This is the class used for the dark-background areas. */
.ribbon {
background: #2d3e50;
color: #aaa;
}
/* This is the class used for the footer */
.footer {
background: #111;
}
/*
* -- TABLET (AND UP) MEDIA QUERIES --
* On tablets and other medium-sized devices, we want to customize some
* of the mobile styles.
*/
@media (min-width: 48em) {
/* We increase the body font size */
body {
font-size: 16px;
}
/* We want to give the content area some more padding */
.content {
padding: 1em;
}
/* We can align the menu header to the left, but float the
menu items to the right. */
.home-menu {
text-align: left;
}
.home-menu ul {
float: right;
}
/* We increase the height of the splash-container */
/* .splash-container {
height: 500px;
}*/
/* We decrease the width of the .splash, since we have more width
to work with */
.splash {
width: 50%;
height: 50%;
}
.splash-head {
font-size: 250%;
}
/* We remove the border-separator assigned to .l-box-lrg */
.l-box-lrg {
border: none;
}
}
/*
* -- DESKTOP (AND UP) MEDIA QUERIES --
* On desktops and other large devices, we want to over-ride some
* of the mobile and tablet styles.
*/
@media (min-width: 78em) {
/* We increase the header font size even more */
.splash-head {
font-size: 300%;
}
}
-224
View File
@@ -1,224 +0,0 @@
ul#css3menu1,ul#css3menu1 ul{
margin:0;
list-style:none;
background-color:#C0C0C0;
background-image:url("mainbk.png");
background-repeat:repeat;
border-width:0px;
border-style:solid;
border-color:#999999;
-moz-border-radius:4px;
-webkit-border-radius:4px;
border-radius:4px;
}
ul#css3menu1 ul{
display:none;
position:absolute;
left:0;
top:100%;
-moz-box-shadow:0.7px 0.7px 1px #777777;
-webkit-box-shadow:0.7px 0.7px 1px #777777;
box-shadow:0.7px 0.7px 1px #777777;
padding:0 9px 9px;
background-color:#FFF;
background-image:none;
border-width:1px;
border-radius:4px;
-moz-border-radius:4px;
-webkit-border-radius:4px;
border-style:solid;
border-color:#d8d9da;
}
ul#css3menu1 li:hover>*{
display:block;
}
ul#css3menu1 li:hover{
position:relative;
}
ul#css3menu1 ul ul{
position:absolute;
left:100%;
top:0;
}
ul#css3menu1{
padding:1px 1px 1px 0;
display:block;
font-size:0;
float:left;
}
ul#css3menu1 li{
display:block;
white-space:nowrap;
font-size:0;
float:left;
}
ul#css3menu1>li,ul#css3menu1 li{
margin:0 0 0 1px;
}
ul#css3menu1 ul>li{
margin:1px 0 0;
}
ul#css3menu1 a:active, ul#css3menu1 a:focus{
outline-style:none;
}
ul#css3menu1 a{
display:block;
vertical-align:middle;
text-align:left;
text-decoration:none;
font:bold 12px Arial,sans-serif;
color:#262626;
cursor:default;
padding:6px;
background-color:#C0C0C0;
background-image:url("mainbk.png");
background-repeat:repeat;
background-position:0 200px;
border-width:0px;
border-style:none;
border-color:;
}
ul#css3menu1 ul li{
float:none;
margin:4px 0 0;
}
ul#css3menu1 ul a{
text-align:left;
padding:4px 0 0 0;
background-color:#FFF;
background-image:none;
border-width:1px 0 0 0;
border-style:solid;
border-color:#D9D9D9;
border-radius:0px;
-moz-border-radius:0px;
-webkit-border-radius:0px;
font:12px Arial,sans-serif;
color:#333333;
text-decoration:none;
}
ul#css3menu1 li:hover>a{
background-color:#C0C0C0;
border-style:none;
font:bold 12px Arial,sans-serif;
color:#efefef;
text-decoration:none;
background-image:url("mainbk.png");
background-position:0 100px;
}
ul#css3menu1 img{
border:none;
vertical-align:middle;
margin-right:10px;
}
ul#css3menu1 img.over{
display:none;
}
ul#css3menu1 li:hover > a img.def{
display:none;
}
ul#css3menu1 li:hover > a img.over{
display:inline;
}
ul#css3menu1 span{
display:block;
overflow:visible;
background-position:right center;
background-repeat:no-repeat;
padding-right:0px;
}
ul#css3menu1 ul span{
background-image:url("arrowsub.gif");
padding-right:27px;
}
ul#css3menu1 ul li:hover>a{
background-color:#FFF;
background-image:none;
border-style:solid;
border-color:#D9D9D9;
font:12px Arial,sans-serif;
color:#55de3d;
text-decoration:none;
}
ul#css3menu1 li.topfirst>a{
height:14px;
line-height:14px;
border-radius:4px 0 0 4px;
-moz-border-radius:4px 0 0 4px;
-webkit-border-radius:4px;
-webkit-border-top-right-radius:0;
-webkit-border-bottom-right-radius:0;
text-shadow:#d8d8d8 0px 1px 1px;
}
ul#css3menu1 li.topfirst:hover>a{
line-height:14px;
text-shadow:#3d3d3d 0px -1px 1px;
}
ul#css3menu1 li.topmenu>a{
height:14px;
line-height:14px;
text-shadow:#d8d8d8 0px 1px 1px;
}
ul#css3menu1 li.topmenu:hover>a{
line-height:14px;
text-shadow:#3d3d3d 0px -1px 1px;
}
ul#css3menu1 li.toplast>a{
height:14px;
line-height:14px;
border-radius:0 4px 4px 0;
-moz-border-radius:0 4px 4px 0;
-webkit-border-radius:0;
-webkit-border-top-right-radius:4px;
-webkit-border-bottom-right-radius:4px;
text-shadow:#d8d8d8 0px 1px 1px;
}
ul#css3menu1 li.toplast:hover>a{
line-height:14px;
text-shadow:#3d3d3d 0px -1px 1px;
}
ul#css3menu1 ._>li>a{
padding:0;
}
ul#css3menu1 li.subfirst>a{
border-width:0;
border-style:none;
padding:0;
}
ul#css3menu1 li.subfirst:hover>a{
border-style:none;
}
img.ico{
height: 1em;
width: 1em;
-384
View File
@@ -1,384 +0,0 @@
/* COOKIES */
var editModus = '';
var Plugins = new Array();
var PageAge = -1;
var PageTimer;
var PlugDispState=[]; // state 1=visible, 0=hidden
var blockStyle = "block"
var alias = '/dashboard'
var Cookies = {
init: function () {
var allCookies = document.cookie.split('; ');
for (var i=0;i<allCookies.length;i++) {
var cookiePair = allCookies[i].split('=');
this[cookiePair[0]] = cookiePair[1];
}
},
create: function (name,value,days) {
if (days) {
var date = new Date();
date.setTime(date.getTime()+(days*24*60*60*1000));
var expires = "; expires="+date.toGMTString();
}
else var expires = "";
document.cookie = name+"="+value+expires+"; path=/";
this[name] = value;
},
erase: function (name) {
this.create(name,'',-1);
this[name] = undefined;
}
};
Cookies.init();
function notXMLHttpRequest(x) {
//log('notXMLHttpRequest 1');
r = x
if (x instanceof XMLHttpRequest) {
r = evalJSONRequest(x);
}
return r;
}
function hide(element) {
getElement(element).style.display = 'None';
}
function unhide(element) {
getElement(element).style.display = blockStyle;
}
var Session = {
init: function(hostName) {
this.menuserver = hostName;
this.username = this.getUserId();
},
userid: function() {
return this.username+'@'+this.menuserver;
},
saveUserId: function(value) {
Cookies.create('userId', value, 300);
},
getUserId: function() {
return Cookies['userId'];
},
loadDispState: function() {
PlugDispState = [];
var states = Cookies['dispState'];
if (states) {
var slist = states.split('&');
for (i in slist) {
kv = slist[i].split(':');
PlugDispState[kv[0]]=kv[1];
}
}
},
saveDispState: function() {
var state = '';
for (k in PlugDispState) {
var v = PlugDispState[k];
state = state + k + ':' + v + '&';
}
Cookies.create('dispState', state, 300);
},
getDispState: function(plugin) {
return PlugDispState[plugin]+0;
},
setDispStateOff: function(plugin) {
PlugDispState[plugin]=0;
Session.saveDispState();
},
setDispStateOn: function(plugin) {
PlugDispState[plugin]=1;
Session.saveDispState();
}
}
var Ajax = {
ajaxFailed: function(err) {
// alert('Cannot fetch data from server, try again...');
Page.showServerError();
},
getConfig: function(userId, callback) {
// do a call to the server for the config for username@menuserver
//log('ajax: get menu as html');
var d = loadJSONDoc(alias+'/loadconfig?mode=html&userId=' + userId);
d.addCallbacks(callback, this.ajaxFailed);
},
getConfigAsText: function(userId, callback) {
// do a call to the server for the config for username@menuserver
var d = loadJSONDoc(alias+'/loadconfig?mode=text&userId=' + userId);
d.addCallbacks(callback, this.ajaxFailed);
},
saveMenuFromText: function(userId, menu, callback) {
var content = queryString({mode:'text',userId:userId, menu:menu})
var d = doXHR(alias+'/savemenu', {method:'POST', sendContent:content, headers:{"Content-Type":"application/x-www-form-urlencoded"}});
d.addCallbacks(callback, this.ajaxFailed);
},
savePlugsFromText: function(userId, plugs, callback) {
//log('Ajax.savePlugsFromText')
var content = queryString({mode:'text',userId:userId, plugs:plugs})
var d = doXHR(alias+'/saveplugs', {method:'POST', sendContent:content, headers:{"Content-Type":"application/x-www-form-urlencoded"}});
d.addCallbacks(callback, this.ajaxFailed);
},
loadPlugin: function(userId, pluginName, parameters, callbackFunction) {
// do a call to the server for the config for username@menuserver
//log('ajax: get pluginbody for ' + pluginName);
var d = loadJSONDoc(alias+'/loadPlugin?plugin='+pluginName+'&parameters='+urlEncode(parameters)+'&userId=' + Session.userid());
d.addCallbacks(callbackFunction, this.ajaxFailed);
//log(' cbtostr: '+callback.toString());
}
}
var Page = {
start: function(hostName) {
Session.init(hostName);
connect('username', 'onchange', this, 'userNameChanged');
//log('Page.start');
EditArea.init(this);
getElement('username').value = Session.username;
Session.loadDispState();
Ajax.getConfig(Session.userid(), this.redrawPage);
},
userNameChanged: function() {
Session.saveUserId(getElement('username').value); // stored in cookie
Ajax.getConfig(Session.userid(), Page.redrawPage);
},
redrawPage: function(transport) {
Page.redrawMenu(transport);
Page.redrawPlugs(transport);
},
redrawMenu: function(transport) {
Page.hideServerError();
//log('Page.redrawMenu ');
transport = notXMLHttpRequest(transport);
//getElement('menu3').innerHTML = transport.menu;
},
redrawPlugs: function(transport) {
Page.hideServerError();
transport = notXMLHttpRequest(transport);
log('Page.redrawPlugs'+transport.plugs);
Plugins = [];
var html = '';
var column = 1;
var plist = transport.plugs.split('\n');
var nr = 0;
for (i in plist) {
var plug = plist[i].replace(/^\s+|\s+$/g,"");
log('running along plist ' + plug);
if (plug.length<10) {
getElement('column'+column).innerHTML = html;
html = '';
column = column + 1;
} else {
if (plug[0]!='#') {
p = new Plugin(nr, plug);
Plugins[nr]=p;
html = html + '<div id="plugin'+nr+'" class="plugindiv"></div>';
nr += 1;
}
}
}
//log('Page - end of redraw');
// reset
Page.refreshPlugins();
},
refreshPlugins: function() {
//log('Page.refreshPlugins age='+PageAge);
PageAge += 1;
PageTimer = callLater(60, Page.refreshPlugins);
//log('triggered ....' + PageAge);
for (p in Plugins) {
Plugins[p].refresh(PageAge);
}
},
editMenu: function() {
EditArea.edit('m');
},
editMenuItem: function() {
EditArea.edit();
},
editPlugins: function() {
EditArea.edit('p');
},
showServerError: function() {
getElement('servererror').style.display = blockStyle;
},
hideServerError: function() {
getElement('servererror').style.display = 'None';
}
};
var EditArea = {
init: function(caller) {
this.page=caller
connect('savemenu', 'onclick', EditArea, 'save');
connect('saveexitmenu', 'onclick', EditArea, 'saveExit');
connect('closemenu', 'onclick', EditArea, 'hide');
},
edit: function(modus) {
editModus = modus
getElement('editarea').style.display = blockStyle;
if (editModus=='m') {
Ajax.getConfigAsText(Session.userid(), EditArea.redrawMenu);
}
if (editModus=='p') {
Ajax.getConfigAsText(Session.userid(), EditArea.redrawPlugs);
}
},
save: function() {
menu = getElement('menulines').value;
getElement('editarea').style.display = blockStyle;
if (editModus=='m') {
//log('Editarea.save: saving menu');
Ajax.saveMenuFromText(Session.userid(), getElement('menulines').value, Page.redrawMenu);
}
if (editModus=='p') {
//log('Editarea.save: saving plugins');
if (PageTimer) {
PageTimer.cancel;
}
PageAge=-1;
Ajax.savePlugsFromText(Session.userid(), getElement('menulines').value, Page.redrawPlugs);
}
},
saveExit: function() {
this.save();
this.hide();
},
hide: function() {
getElement('editarea').style.display = 'None';
},
redrawMenu: function(transport) {
Page.hideServerError();
//Page.redrawMenu(transport);
getElement('menulines').value = transport.menu;
},
redrawPlugs: function(transport) {
Page.hideServerError();
//Page.redrawPlugs(transport);
getElement('menulines').value = transport.plugs;
}
};
var EditPage = {
start: function(hostName) {
Session.init(hostName);
//log('start page');
EditArea.init(this);
Ajax.getConfig(Session.userid(), this.redrawPage);
},
redrawPage: function(transport) {
Page.hideServerError();
//log('ep: redraw page');
transport = notXMLHttpRequest(transport);
EditPage.redrawMenu(transport);
EditArea.edit();
},
redrawMenu: function(transport) {
Page.hideServerError();
//log('ep: redraw menu');
transport = notXMLHttpRequest(transport);
//log('redrawPage: ' + transport.menu);
//alert(transport);
getElement('menu3').innerHTML = transport.menu;
}
}
/********************* plugin object *********************/
function Plugin(nr, initstring) { // Define super class
// set divname, name, serverquery and timer
this.nr = nr;
this.divname = 'plugin' + nr;
// the initstrig should look like:
// <name>:<functionname>([<param1>[, param2 ..]]),<refreshrate in minutes>
var objRegExp = /^(\w+):.*$/;
this.title = initstring.replace(objRegExp, "$1");
objRegExp = /^\w*:(\w+)\(.*$/;
this.func = initstring.replace(objRegExp, "$1");
objRegExp = /^[^(]+\(([^)]*).*$/;
this.params = initstring.replace(objRegExp, "$1");
//log(this.params);
objRegExp = /.+\),(\d+)$/;
this.refreshrate = parseInt(initstring.replace(objRegExp, "$1"));
this.nextrefreshage = 0;
//log('created plugin '+this.title + ', '+this.func);
}
Plugin.prototype.refresh = function(age) { // Define Method
//log(' Refresh ' + this.divname );
if (age >= this.nextrefreshage) {
//log(' Refresh 2 ' + this.divname );
this.nextrefreshage += this.refreshrate;
Ajax.loadPlugin(Session.userid, this.func, this.params, bind(this.redraw, this))
}
}
Plugin.prototype.redraw = function(transport) { // Define Method
//log('redraw '+this.nr);
Page.hideServerError();
var body = '<div id="plugbody'+this.nr+'" class="plugbody">'+transport.plugin+'</div>';
var header = '<a class="plugheader" href="javascript:Plugins['+this.nr+'].toggle();"><img id="toggle'+this.nr+'" src=alias+"/static/icon_minus.gif"/></a>'
var html = '<table class="big"><tr><td class="plugtitle">'+this.title+'</td><td class="plugheader">'+header+'</td></tr><td class="plugbody" colspan="2">'+body+'</td></table>';
getElement(this.divname).innerHTML = html;
this.setDispState(Session.getDispState(this.title));
//log('REDRAW');
}
Plugin.prototype.toggle = function() { // Define Method
var button = getElement('toggle'+this.nr).src;
// could be a plus or a minus button
if (button.indexOf('minus')>=0) {
this.setDispState(0);
} else {
this.setDispState(1);
}
}
Plugin.prototype.setDispState = function(state) { // Define Method
var div = 'plugbody'+this.nr;
if (state == 0) {
hide(div);
getElement('toggle'+this.nr).src=alias+"/static/icon_plus.gif";
Session.setDispStateOff(this.title);
} else {
unhide(div);
getElement('toggle'+this.nr).src=alias+"/static/icon_minus.gif";
Session.setDispStateOn(this.title);
}
}
-11
View File
File diff suppressed because one or more lines are too long
-113
View File
@@ -1,113 +0,0 @@
body {
background-color: #f6f6f6;
background-image: url("logo.png");
background-repeat: no-repeat;
}
#namespace {
top: 15px;
left: 90%;
width: 10%;
height: 20px;
position: absolute;
}
#servererror {
top: 15px;
left: 75%;
width: 10%;
position: absolute;
color: orange;
font-family: Verdana;
font-size: 0.7em;
border: 1px solid red;
padding: 4px;
}
input#username {
width: 80%;
border: none;
border-bottom: 1px solid #999;
color: #999;
background-color: #fefefe;
}
.icon {
width: 12px;
height: 12px;
}
#pluginArea {
padding-top: 50px;
}
#intern1 {
width: 100%;
background-color: #fefefe;
}
table.big {
width: 100%;
}
td.column {
width: 33.33%;
vertical-align: top;
}
#editarea {
display: none;
top: 100px;
left: 30px;
width: 80%;
position: absolute;
}
textarea {
width: 70em;
height: 40em;
}
.plugtitle, .plugheader{
background-color: #ccc;
font-family: Verdana;
font-size: 0.9em;
}
.plugheader {
text-align: right;
}
div.plugbody {
width: 100%;
background-color: #fefefe;
font-family: Helvetica;
font-size: 0.8em;
}
div.textblock {
background-color: #fefefe;
width: 100%;
}
a.rss {
text-decoration: none;
color: #222;
}
a.rss:hover {
text-decoration: none;
color: green;
}
img {
border-style: none;
}
img.plugbody {
width: 100%;
}
-135
View File
@@ -1,135 +0,0 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Flowers</title>
<!-- link rel="stylesheet" href="http://yui.yahooapis.com/pure/0.6.0/pure-min.css">
<link rel="stylesheet" href="http://yui.yahooapis.com/pure/0.6.0/grids-responsive-min.css">
<link rel="stylesheet" href="http://netdna.bootstrapcdn.com/font-awesome/4.0.3/css/font-awesome.css">
<link rel=stylesheet type=text/css href="/static/marketing.css">
<link rel=stylesheet type=text/css href="/static/flower.css">
<!-- script type="text/javascript" src="/static/jquery-min.js"></script -->
</head>
<body>
<div class="header">
<div class="home-menu pure-menu pure-menu-horizontal pure-menu-fixed">
<a class="pure-menu-heading" href="">Flowers</a>
<ul class="pure-menu-list">
<input type="text" id="search" placeholder="search..." value="">
<li class="pure-menu-item pure-menu-selected"><a href="javascript:DoSubmit('new')" class="pure-menu-link">New</a></li>
<li class="pure-menu-item"><a href="javascript:DoSubmit('logout')" class="pure-menu-link">Logout</a></li>
</ul>
</div>
</div>
<div class="content-wrapper">
<div class="content">
<div class="pure-g">
<div class="l-box pure-u-1 pure-u-md-1-2 pure-u-lg-1-5">
</div>
<div class="l-box pure-u-1 pure-u-md-1-2 pure-u-lg-3-5">
<table id="flowerlist" class="flowerlist pure-table pure-table-horizontal">
<tr class="flowerlist">
<td class="flowerlist">
<a href='www.google.com'>
org2, login2
</a>
</td>
<td class="right"><span style="white-space: nowrap;">2016-11-30</span></td>
</tr>
<tr class="flowerlist">
<td class="flowerlist>
<a href="javascript:DoSubmit('show', 'RABO creditcard', '2001-03-17 13:24:07' , '')">
RABO creditcard,
</a>
</td>
<td class="right"><span style="white-space: nowrap;">2001-03-17</span></td>
</tr>
<tr class="flowerlist">
<td class="flowerlist>
<a href="javascript:DoSubmit('show', 'ABN AMRO creditcard', '2001-03-17 13:23:25' , '')">
ABN AMRO creditcard, 5422 2300 0373 7907
</a>
</td>
<td class="right"><span style="white-space: nowrap;">2001-03-17</span></td>
</tr>
</table>
</div>
<div class="l-box pure-u-1 pure-u-md-1-2 pure-u-lg-1-5">
</div>
</div>
</div>
</div>
<!-- script language="javascript">
var $rows = $('#flowerlist tr');
$('#search').keyup(function() {
var val = $.trim($(this).val()).replace(/ +/g, ' ').toLowerCase();
$rows.show().filter(function() {
var text = $(this).text().replace(/\s+/g, ' ').toLowerCase();
return !~text.indexOf(val);
}).hide();
});
$('#search').keyup();
</script -->
<form id="gotopage" action="/app" method="POST">
<input type="hidden" id="action" name="action" value="">
<input type="hidden" id="organization" name="organization" value="">
<input type="hidden" id="myid" name="myid" value="">
<input type="hidden" id="datetime" name="datetime" value="">
<input type="hidden" id="filter" name="filter" value="">
</form>
<!-- script language="javascript">
function DoSubmit(action, org, datetime, filter) {
$('#action').val(action);
$('#organization').val(org);
$('#datetime').val(datetime);
$('#filter').val( $('#search').val() );
$('#gotopage').submit();
}
</script -->
<div class="footer l-box is-center">
Thank you for using the flowershop.
</div>
</body>
</html>
Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

+27 -65
View File
@@ -1,75 +1,37 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
<meta name="viewport" content="user-scalable=no, width=device-width, initial-scale=1.0" />
<title>{% block title %}Flowers{% endblock %}</title>
<!-- link rel="stylesheet" href="http://yui.yahooapis.com/pure/0.6.0/pure-min.css" -->
<link rel="stylesheet" href="static/pure-min.css">
<link rel="stylesheet" href="static/grids-responsive-min.css">
<link rel="stylesheet" href="static/font-awesome.css">
<link rel=stylesheet type=text/css href="static/marketing.css">
<link rel=stylesheet type=text/css href="static/flower.css">
<script type="text/javascript" src="static/jquery-min.js"></script>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="color-scheme" content="dark">
<title>{% block title %}Flowers{% endblock %}</title>
<link rel="stylesheet" href="{{ url_for('flower_vase.static', filename='flower.css') }}">
</head>
<body>
<header class="site-header">
<a class="brand" href="{{ url_for('flower_vase.index') }}" aria-label="Flowers home">
<img class="brand-logo" src="{{ url_for('flower_vase.static', filename='wwwsuynl.png') }}" width="34" height="34" alt="">
<span>Flowers</span>
</a>
<nav class="nav-actions" aria-label="Bouquet actions">
{% block menuoptions %}{% endblock %}
</nav>
</header>
{% block headandmenu %}
<div class="header">
<div class="home-menu pure-menu pure-menu-horizontal pure-menu-fixed">
<a class="pure-menu-heading" href="">Flowers</a>
<ul class="pure-menu-list">
{% block menuoptions %}
<input type="text" id="search" placeholder="search..." value="{{filter}}">
<li class="pure-menu-item pure-menu-selected"><a href="javascript:DoSubmit('new')" class="pure-menu-link">New</a></li>
<li class="pure-menu-item"><a href="javascript:DoSubmit('logout')" class="pure-menu-link">Logout</a></li>
<li class="pure-menu-item"><a href="javascript:DoSubmit('rehush')" class="pure-menu-link">Password</a></li>
{% endblock menuoptions %}
</ul>
</div>
</div>
{% endblock headandmenu %}
{% block content %}
{% endblock %}
<form id="gotopage" action="{{ url_for('flower_vase.application') }}" method="POST">
<input type="hidden" id="_action" name="action" value="">
<input type="hidden" id="_organization" name="organization" value="">
<input type="hidden" id="_myid" name="myid" value="">
<input type="hidden" id="_datetime" name="datetime" value="">
<input type="hidden" id="_filter" name="filter" value="">
</form>
<script language="javascript">
function DoSubmit(action, org, datetime, filter) {
$('#_action').val(action);
$('#_organization').val(org);
$('#_datetime').val(datetime);
$('#_filter').val( $('#search').val() );
$('#gotopage').submit();
}
</script>
{% block footer %}
<div class="footer l-box is-center">
Thank you for using the flowershop.
</div>
{% endblock %}
{% with messages = get_flashed_messages(with_categories=true) %}
{% if messages %}
<div class="notices" aria-live="polite">
{% for category, message in messages %}
<div class="notice notice-{{ category }}">{{ message }}</div>
{% endfor %}
</div>
{% endif %}
{% endwith %}
<main class="page-shell">
{% block content %}{% endblock %}
</main>
<footer>Private by design. Stored in your existing Flowers bouquet.</footer>
</body>
</html>
+21 -33
View File
@@ -1,35 +1,23 @@
{% extends "common.html" %}
{% block headandmenu %}
<div class="header">
<div class="home-menu pure-menu pure-menu-horizontal pure-menu-fixed">
<a class="pure-menu-heading" href="">Flowers</a>
</div>
</div>
{% endblock headandmenu %}
{% block title %}Create a bouquet · Flowers{% endblock %}
{% block menuoptions %}<a class="text-link" href="{{ url_for('flower_vase.index') }}">Sign in</a>{% endblock %}
{% block content %}
<div class="splash-container">
<div class="splash">
<form class="pure-form pure-form-aligned" action="{{ url_for('flower_vase.create') }}" method="post">
<fieldset>
<div class="pure-control-group">
<input maxlength="32" name="name" type="text" placeholder="make up your username">
</div>
<div class="pure-control-group">
<input maxlength="10" name="password" type="password" placeholder="make up you password, the longer the better">
</div>
<div class="pure-controls">
<button type="submit" class="pure-button pure-button-primary">Create Vase</button>
</div>
</fieldset>
</form>
{{ message }}
</div>
</div>
{% endblock content %}
<section class="auth-layout">
<div class="intro">
<p class="eyebrow">New bouquet</p>
<h1>Create a bouquet</h1>
<p>This uses the existing Flowers database structure so it remains readable by compatible installations.</p>
</div>
<form class="card form-card" action="{{ url_for('flower_vase.create') }}" method="post">
<input type="hidden" name="csrf_token" value="{{ csrf_token }}">
<h2>New bouquet</h2>
{% if message %}<p class="field-error">{{ message }}</p>{% endif %}
<label for="name">Username</label>
<input maxlength="31" id="name" name="name" type="text" pattern="[A-Za-z0-9_]+" autocomplete="username" required>
<label for="password">Password</label>
<input maxlength="43" id="password" name="password" type="password" pattern="[A-Za-z0-9_+/-]+" autocomplete="new-password" required>
<p class="field-help">Use Base64-compatible characters for legacy encryption compatibility.</p>
<button class="button primary" type="submit">Create bouquet</button>
</form>
</section>
{% endblock %}
+38 -42
View File
@@ -1,45 +1,41 @@
{% extends "common.html" %}
{% block title %}{% if flower.organization %}Edit{% else %}New entry{% endif %} · Flowers{% endblock %}
{% block menuoptions %}
<li class="pure-menu-item pure-menu-selected"><a href="javascript:$('#newFlower').submit()" class="pure-menu-link">Save</a></li>
<li class="pure-menu-item pure-menu-selected"><a href="javascript:DoSubmit('deactivate','{{ flower.organization }}','{{ flower.dateCreated }}','')" class="pure-menu-link">Delete</a></li>
<li class="pure-menu-item pure-menu-selected"><a href="javascript:DoSubmit('list','','','')" class="pure-menu-link">Cancel</a></li>
{% endblock menuoptions %}
{% block content %}
<div class="splash-container">
<div class="splash">
<form class="pure-form pure-form-stacked" id="newFlower" action="{{ url_for('flower_vase.application') }}" method="post">
<fieldset>
<div class="pure-control-group">
<input maxlength="70" size="50" id="organization" name="organization" type="text" value="{{ flower.organization }}" placeholder="Organization">
</div>
<div class="pure-control-group">
<input maxlength="70" id="myname" name="myname" type="text" value="{{ flower.myName }}" placeholder="Your name (optional)">
</div>
<div class="pure-control-group">
<input maxlength="70" id="myid" name="myid" type="text" value="{{ flower.myID }}" placeholder="Your Login">
</div>
<div class="pure-control-group">
<input maxlength="30" id="secret" name="secret" type="text" placeholder="Your secret">
</div>
<input type="hidden" id="action" name="action" value="save">
<input type="hidden" id="filter" name="filter" value="DoNotSetFilterinCookie">
</fieldset>
</form>
</div>
</div>
<script language="javascript">
</script>
<form action="{{ url_for('flower_vase.application') }}" method="post">
<input type="hidden" name="csrf_token" value="{{ csrf_token }}">
<input type="hidden" name="action" value="list">
<button class="button ghost compact" type="submit">Cancel</button>
</form>
{% endblock %}
{% block content %}
<section class="editor-layout">
<div>
<p class="eyebrow">{% if flower.organization %}New version{% else %}New flower{% endif %}</p>
<h1>{% if flower.organization %}Edit entry{% else %}Add an entry{% endif %}</h1>
<p class="muted">Saving creates a new version. Your historical rows remain untouched.</p>
</div>
<form class="card form-card wide" action="{{ url_for('flower_vase.application') }}" method="post">
<input type="hidden" name="csrf_token" value="{{ csrf_token }}">
<input type="hidden" name="action" value="save">
<input type="hidden" name="filter" value="{{ filter|default('') }}">
<label for="organization">Organization</label>
<input maxlength="80" id="organization" name="organization" type="text" value="{{ flower.organization }}" autocomplete="organization" required>
<label for="myname">Your name <span>optional</span></label>
<input maxlength="70" id="myname" name="myname" type="text" value="{{ flower.myName }}" autocomplete="name">
<label for="myid">Login</label>
<input maxlength="70" id="myid" name="myid" type="text" value="{{ flower.myID }}" autocomplete="username" required>
<label for="secret">Secret</label>
<input maxlength="120" id="secret" name="secret" type="password" autocomplete="new-password" required>
<button class="button primary" type="submit">Save new version</button>
</form>
{% if flower.dateCreated %}
<form class="danger-zone" action="{{ url_for('flower_vase.application') }}" method="post" onsubmit="return confirm('Remove this entry from the active list?')">
<input type="hidden" name="csrf_token" value="{{ csrf_token }}">
<input type="hidden" name="action" value="deactivate">
<input type="hidden" name="organization" value="{{ flower.organization }}">
<input type="hidden" name="datetime" value="{{ flower.dateCreated }}">
<button class="button danger" type="submit">Deactivate entry</button>
</form>
{% endif %}
</section>
{% endblock %}
+22 -35
View File
@@ -1,37 +1,24 @@
{% extends "common.html" %}
{% block headandmenu %}
<div class="header">
<div class="home-menu pure-menu pure-menu-horizontal pure-menu-fixed">
<a class="pure-menu-heading" href="">Flowers</a>
</div>
</div>
{% endblock headandmenu %}
{% block title %}Sign in · Flowers{% endblock %}
{% block menuoptions %}
<a class="text-link" href="{{ url_for('flower_vase.create') }}">Create a bouquet</a>
{% endblock %}
{% block content %}
<div class="splash-container">
<div class="splash">
<form class="pure-form pure-form-aligned" action="{{ url_for('flower_vase.application') }}" method="post">
<fieldset>
<div class="pure-control-group">
<input name="name" type="text" placeholder="{{ name_suggestion }}">
</div>
<div class="pure-control-group">
<input name="password" type="password" placeholder="{{ pwd_suggestion }}">
</div>
<div class="pure-controls">
<button type="submit" class="pure-button pure-button-primary">Submit</button>
</div>
</fieldset>
<input type="hidden" id="action" name="action" value="login">
<input type="hidden" id="filter" name="filter" value="DoNotSetFilterinCookie">
</form>
</div>
</div>
{% endblock content %}
<section class="auth-layout">
<div class="intro">
<p class="eyebrow">Private bouquet</p>
<h1>Your flowers</h1>
<p>Sign in to open your encrypted records.</p>
</div>
<form class="card form-card" action="{{ url_for('flower_vase.application') }}" method="post">
<input type="hidden" name="csrf_token" value="{{ csrf_token }}">
<input type="hidden" name="action" value="login">
<h2>Sign in</h2>
<label for="name">Username</label>
<input id="name" name="name" type="text" autocomplete="username" placeholder="{{ name_suggestion }}" required autofocus>
<label for="password">Password</label>
<input id="password" name="password" type="password" autocomplete="current-password" placeholder="{{ pwd_suggestion }}" required>
<button class="button primary" type="submit">Open bouquet</button>
</form>
</section>
{% endblock %}
+71 -45
View File
@@ -1,51 +1,77 @@
{% extends "common.html" %}
{% block title %}Your bouquet · Flowers{% endblock %}
{% block menuoptions %}
<form action="{{ url_for('flower_vase.application') }}" method="post">
<input type="hidden" name="csrf_token" value="{{ csrf_token }}">
<input type="hidden" name="action" value="new">
<button class="button primary compact" type="submit">New entry</button>
</form>
<form action="{{ url_for('flower_vase.application') }}" method="post">
<input type="hidden" name="csrf_token" value="{{ csrf_token }}">
<input type="hidden" name="action" value="rehush">
<button class="button ghost compact" type="submit">Password</button>
</form>
<form action="{{ url_for('flower_vase.application') }}" method="post">
<input type="hidden" name="csrf_token" value="{{ csrf_token }}">
<input type="hidden" name="action" value="logout">
<button class="button ghost compact" type="submit">Sign out</button>
</form>
{% endblock %}
{% block content %}
<section class="vault-header">
<div>
<h1>Your bouquet</h1>
</div>
<label class="search-field" for="search">
<span class="sr-only">Search entries</span>
<input id="search" type="search" placeholder="Search organization or login" value="{{ filter|default('') }}" autocomplete="off">
</label>
</section>
<div class="content-wrapper">
<div class="content">
<div class="pure-g">
<div class="l-box pure-u-1 pure-u-md-1-2 pure-u-lg-1-5">
</div>
<div class="l-box pure-u-1 pure-u-md-1-2 pure-u-lg-3-5">
<table id="flowerlist" class="flowerlist pure-table pure-table-horizontal">
{% for flower in flowers %}
<tr class="flowerlist">
<td class="flowerlist">
<a href="javascript:DoSubmit('show', '{{flower.organization}}', '{{flower.dateCreated}}' , '')">
{{ flower.organization }}, {{ flower.myID }}
</a>
</td>
<td class="right"><span style="white-space: nowrap;">{{ flower.dateCreated[:10] }}</span></td>
</tr>
{% endfor %}
</table>
</div>
<div class="l-box pure-u-1 pure-u-md-1-2 pure-u-lg-1-5">
</div>
</div>
</div>
<div class="entry-list" id="entry-list">
{% for flower in flowers %}
<form class="entry-row" data-search="{{ flower.organization }} {{ flower.myID }}" action="{{ url_for('flower_vase.application') }}" method="post">
<input type="hidden" name="csrf_token" value="{{ csrf_token }}">
<input type="hidden" name="action" value="show">
<input type="hidden" name="organization" value="{{ flower.organization }}">
<input type="hidden" name="datetime" value="{{ flower.dateCreated }}">
<input type="hidden" name="filter" class="current-filter" value="{{ filter|default('') }}">
<button type="submit" class="entry-button">
<span class="entry-icon" aria-hidden="true">{{ flower.organization[:1]|upper }}</span>
<span class="entry-copy">
<strong>{{ flower.organization }}</strong>
<span>{{ flower.myID }}</span>
</span>
<time datetime="{{ flower.dateCreated }}">{{ flower.dateCreated[:10] }}</time>
<span class="chevron" aria-hidden="true"></span>
</button>
</form>
{% else %}
<div class="empty-state">
<span aria-hidden="true"></span>
<h2>No active entries</h2>
<p>Create an entry to start your collection.</p>
</div>
{% endfor %}
</div>
<p class="empty-state filtered-empty" id="filtered-empty" hidden>No entries match that search.</p>
<script language="javascript">
var $rows = $('#flowerlist tr');
$('#search').keyup(function() {
var val = $.trim($(this).val()).replace(/ +/g, ' ').toLowerCase();
$rows.show().filter(function() {
var text = $(this).text().replace(/\s+/g, ' ').toLowerCase();
return !~text.indexOf(val);
}).hide();
});
$('#search').keyup();
<script>
const search = document.querySelector('#search');
const rows = [...document.querySelectorAll('.entry-row')];
const filteredEmpty = document.querySelector('#filtered-empty');
function filterRows() {
const query = search.value.trim().toLocaleLowerCase();
let visible = 0;
rows.forEach((row) => {
const match = row.dataset.search.toLocaleLowerCase().includes(query);
row.hidden = !match;
row.querySelector('.current-filter').value = search.value;
if (match) visible += 1;
});
filteredEmpty.hidden = visible !== 0 || rows.length === 0;
}
search.addEventListener('input', filterRows);
filterRows();
</script>
{% endblock content %}
{% endblock %}
+22 -38
View File
@@ -1,40 +1,24 @@
{% extends "common.html" %}
{% block headandmenu %}
<div class="header">
<div class="home-menu pure-menu pure-menu-horizontal pure-menu-fixed">
<a class="pure-menu-heading" href="">Flowers</a>
</div>
</div>
{% endblock headandmenu %}
{% block title %}Change password · Flowers{% endblock %}
{% block menuoptions %}<a class="text-link" href="{{ url_for('flower_vase.index') }}">Back to sign in</a>{% endblock %}
{% block content %}
<div class="splash-container">
<div class="splash">
<form class="pure-form pure-form-aligned" action="{{ url_for('flower_vase.update_pwd') }}" method="post">
<fieldset>
<div class="pure-control-group">
<input name="name" type="text" placeholder="your existing name">
</div>
<div class="pure-control-group">
<input name="old_password" type="password" placeholder="your existing password">
</div>
<div class="pure-control-group">
<input maxlength="10" name="new_password" type="password" placeholder="make up you password, the longer the better">
</div>
<div class="pure-controls">
<button type="submit" class="pure-button pure-button-primary">Update Password</button>
</div>
</fieldset>
</form>
{{ message }}
</div>
</div>
{% endblock content %}
<section class="auth-layout">
<div class="intro">
<p class="eyebrow">Bouquet security</p>
<h1>Change password</h1>
<p>Every existing encrypted field will be rewritten with the new legacy-compatible key.</p>
</div>
<form class="card form-card" action="{{ url_for('flower_vase.update_pwd') }}" method="post">
<input type="hidden" name="csrf_token" value="{{ csrf_token }}">
<h2>Bouquet flowers</h2>
{% if message %}<p class="field-error">{{ message }}</p>{% endif %}
<label for="name">Username</label>
<input id="name" name="name" type="text" autocomplete="username" required>
<label for="old-password">Current password</label>
<input id="old-password" name="old_password" type="password" autocomplete="current-password" required>
<label for="new-password">New password</label>
<input maxlength="43" id="new-password" name="new_password" type="password" pattern="[A-Za-z0-9_+/-]+" autocomplete="new-password" required>
<button class="button primary" type="submit">Re-encrypt bouquet</button>
</form>
</section>
{% endblock %}
+79 -44
View File
@@ -1,47 +1,82 @@
{% extends "common.html" %}
{% block title %}{{ flower.organization }} · Flowers{% endblock %}
{% block menuoptions %}
<li class="pure-menu-item pure-menu-selected"><a href="javascript:editFlower()" class="pure-menu-link">Edit</a></li>
{% endblock menuoptions %}
{% block content %}
<div class="splash-container">
<div class="splash">
<table class="pure-table" style="width: 100%">
<tr><td class="white right">Org</td><td class="white left">{{ flower.organization }}</td> </tr>
<tr><td class="white right">You</td><td class="white left">{{ flower.myName }}</td> </tr>
<tr><td class="white right">Login</td><td class="white left">{{ flower.myID }}</td> </tr>
<tr><td class="white right">Hash</td><td id="secrettd" class="white left"><div id="secret" value="{{ flower.mySecret }}" onclick="myCopyFunction()">{{ flower.mySecret }}</div></td></tr>
<tr><td class="white">{{ flower.dateCreated[:10] }}</td><td></td> </tr>
</table>
</div>
</div>
<script language="javascript">
setTimeout(function(){
DoSubmit('list', '{{flower.organization}}', '{{flower.dateCreated}}', 'DoNotSetFilterinCookie')
}, 5000);
function editFlower() {
DoSubmit('edit', '{{flower.organization}}', '{{flower.dateCreated}}', 'DoNotSetFilterinCookie')
}
function myCopyFunction() {
var copyText = document.getElementById("secret");
// Copy the text inside the text field
navigator.clipboard.writeText(copyText.getAttribute("value"));
// alert("Copied the text: "+copyText.getAttribute("value"));
$("#secrettd").removeClass("white");
$("#secrettd").addClass("blue");
}
</script>
<form action="{{ url_for('flower_vase.application') }}" method="post">
<input type="hidden" name="csrf_token" value="{{ csrf_token }}">
<input type="hidden" name="action" value="list">
<input type="hidden" name="filter" value="{{ filter|default('') }}">
<button class="button ghost compact" type="submit">Back to bouquet</button>
</form>
{% endblock %}
{% block content %}
<section class="detail-card card">
<div class="detail-heading">
<span class="entry-icon large" aria-hidden="true">{{ flower.organization[:1]|upper }}</span>
<div>
<p class="eyebrow">Flower</p>
<h1>{{ flower.organization }}</h1>
{% if flower.dateCreated not in ('STORED', 'FAILED') %}<p class="muted">Version from {{ flower.dateCreated[:10] }}</p>{% endif %}
</div>
</div>
<dl class="details">
<div><dt>Name</dt><dd>{{ flower.myName or '—' }}</dd></div>
<div><dt>Login</dt><dd>{{ flower.myID }}</dd></div>
<div>
<dt>Secret</dt>
<dd class="secret-line">
<span id="secret" data-secret="{{ flower.mySecret }}">••••••••••••</span>
<button class="icon-button" id="reveal" type="button">Reveal</button>
<button class="icon-button" id="copy" type="button">Copy</button>
</dd>
</div>
</dl>
{% if flower.dateCreated not in ('STORED', 'FAILED') %}
<div class="detail-actions">
<form id="edit-form" action="{{ url_for('flower_vase.application') }}" method="post">
<input type="hidden" name="csrf_token" value="{{ csrf_token }}">
<input type="hidden" name="action" value="edit">
<input type="hidden" name="organization" value="{{ flower.organization }}">
<input type="hidden" name="datetime" value="{{ flower.dateCreated }}">
<button class="button primary" type="submit">Edit entry</button>
</form>
</div>
{% endif %}
</section>
<script>
const secret = document.querySelector('#secret');
const reveal = document.querySelector('#reveal');
const copy = document.querySelector('#copy');
const editForm = document.querySelector('#edit-form');
let visible = false;
const returnToList = window.setTimeout(() => {
window.location.assign('{{ url_for("flower_vase.application") }}');
}, 8000);
if (editForm) {
editForm.addEventListener('submit', () => window.clearTimeout(returnToList));
}
reveal.addEventListener('click', () => {
visible = !visible;
secret.textContent = visible ? secret.dataset.secret : '••••••••••••';
reveal.textContent = visible ? 'Hide' : 'Reveal';
});
copy.addEventListener('click', async () => {
try {
await navigator.clipboard.writeText(secret.dataset.secret);
copy.textContent = 'Copied';
} catch (_) {
const field = document.createElement('textarea');
field.value = secret.dataset.secret;
field.style.position = 'fixed';
field.style.opacity = '0';
document.body.appendChild(field);
field.select();
copy.textContent = document.execCommand('copy') ? 'Copied' : 'Select and copy';
field.remove();
}
window.setTimeout(() => copy.textContent = 'Copy', 1400);
});
</script>
{% endblock %}
-39
View File
@@ -1,39 +0,0 @@
# from flask import Flask
import datetime
import pytz
from Config import *
import sys
import datetime
from FlowerServices import Flower,SuperFlower
from AccessControl import Access
import json
# from flask import Flask, request, session, g, redirect, url_for, abort, render_template, flash, json, make_response
# from werkzeug.exceptions import HTTPException
newuser = 'janine'
newhush = 'demaat196'
# login db with generic user
#f = SuperFlower(newuser, newhush)
#print(f)
#if f.createNewTable():
# login as new user
# u = Flower(newuser, newhush)
# add one line
# u.add('Demo organisation', 'Demo name', 'Demo login', 'Demo hush')
# add 1 pwd
# u = Flower(newuser, newhush)
# # add one line
# u.add('Demo2 organisation', 'Demo name', 'Demo login', 'Demo hush')
# read one line
u = Flower(newuser, newhush)
#flower=u.one('webmail catch-all-email@suy.nu', '2023-03-13 20:25:52')
flowers=u.numberOfEntries()
print(flowers)
#update pwd
#u = Flower(newuser, newhush)
#u.update_pwd('white')
-33
View File
@@ -1,33 +0,0 @@
CREATE TABLE `sjaak` (
`organization` varchar(50) NOT NULL,
`myID` varchar(50) NOT NULL,
`myName` varchar(50) NOT NULL,
`mySecret` varchar(50) NOT NULL,
`dateCreated` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`deleted` int(11) DEFAULT '0',
PRIMARY KEY (`organization`,`dateCreated`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
MariaDB [Flowers]> create user ignace@localhost identified by 'ignace';
Query OK, 0 rows affected (0.00 sec)
MariaDB [Flowers]> grant create,update,insert on Flowers.ignace to ignace@localhost identified by 'ignace';
ERROR 1044 (42000): Access denied for user 'dude'@'localhost' to database 'mysql'
MariaDB [Flowers]> grant create,update,insert on Flowers.ignace to ignace@localhost;
# as root:
create database Flowers;
grant create,select,update,insert,grant option on Flowers.* to flower@localhost identified by '608f0b988db4a96066af7dd8870de96c';
grant create user,reload on *.* to flower@localhost;
flush privileges;
create user {0}@localhost identified by '{1}';
grant select,update,insert on Flowers.{0} to {0}@localhost;
flush privileges;
delete from ignace where organization in ('myRepository', 'Nero', 'office XP', 'SwisH');
-29
View File
@@ -1,29 +0,0 @@
from fernet import Fernet
# Generate a Fernet key
key = b'XBxB603cX_mULEXxfavOg3FDc0Ox3gChwYEY-Uxd3tE='
pwd = 'black'
key = bytes((pwd*10)[:43]+"=", "ascii")
print(key)
# Create a Fernet object with that key
f = Fernet(key)
# Input string to be encrypted
input_string = "Hello World!Hello World!Hello World!Hello World!Hello World!"
# Encrypt the string
encrypted_string = f.encrypt(input_string.encode()).decode()
print(encrypted_string)
# Decrypt the encrypted string
decrypted_string = f.decrypt(encrypted_string.encode()).decode()
# Print the original and decrypted strings
print("Original String:", input_string)
print("Decrypted String:", decrypted_string)
+74
View File
@@ -0,0 +1,74 @@
import json
import unittest
from unittest.mock import patch
from flowers import create_app
class FakeVault:
def __init__(self, *args):
pass
def authenticate(self):
return True
def all(self):
return [
{
"organization": "Acme",
"myID": "alice@example.test",
"dateCreated": "2024-02-03 12:00:00",
}
]
class AppTests(unittest.TestCase):
def setUp(self):
self.app = create_app({"TESTING": True, "SECRET_KEY": "test-secret"})
self.client = self.app.test_client()
def csrf(self):
self.client.get("/")
with self.client.session_transaction() as browser_session:
return browser_session["csrf_token"]
def test_login_form_requires_csrf(self):
response = self.client.post(
"/browser",
data={"action": "login", "name": "alice", "password": "legacy_pwd"},
)
self.assertEqual(response.status_code, 400)
@patch("flower_vase.Flower", FakeVault)
def test_login_renders_existing_entries(self):
response = self.client.post(
"/browser",
data={
"csrf_token": self.csrf(),
"action": "login",
"name": "alice",
"password": "legacy_pwd",
},
follow_redirects=True,
)
self.assertEqual(response.status_code, 200)
self.assertIn(b"Acme", response.data)
with self.client.session_transaction() as browser_session:
self.assertNotIn("dbpwd", browser_session)
self.assertNotIn("password", browser_session)
self.assertIn("auth_token", browser_session)
@patch("flower_vase.Flower", FakeVault)
def test_legacy_api_keeps_double_encoded_list(self):
response = self.client.post(
"/app",
data={"action": "list", "name": "alice", "password": "legacy_pwd"},
)
payload = response.get_json()
nested = json.loads(payload["list"])
self.assertEqual(payload["result"], 1)
self.assertEqual(nested[0]["organization"], "Acme")
if __name__ == "__main__":
unittest.main()
+120
View File
@@ -0,0 +1,120 @@
import unittest
from FlowerServices import Flower, InvalidCredentials, legacy_key
class FakeCursor:
def __init__(self, one=None, many=(), changed=1):
self.one = one
self.many = many
self.changed = changed
self.calls = []
def __enter__(self):
return self
def __exit__(self, *args):
return False
def execute(self, sql, parameters=None):
self.calls.append((" ".join(sql.split()), parameters))
return self.changed
def fetchone(self):
return self.one
def fetchall(self):
return self.many
class FakeConnection:
def __init__(self, cursor):
self.fake_cursor = cursor
self.commits = 0
self.rollbacks = 0
self.closed = 0
def cursor(self):
return self.fake_cursor
def commit(self):
self.commits += 1
def rollback(self):
self.rollbacks += 1
def close(self):
self.closed += 1
class FlowerCompatibilityTests(unittest.TestCase):
def make_vault(self, cursor):
connection = FakeConnection(cursor)
calls = []
def connect(**kwargs):
calls.append(kwargs)
return connection
return Flower("alice", "legacy_pwd", connect), connection, calls
def test_legacy_key_derivation_is_unchanged(self):
self.assertEqual(legacy_key("black"), "blackblackblackblackblackblackblackblackbla=")
def test_legacy_ciphertext_round_trip(self):
vault, _, _ = self.make_vault(FakeCursor())
token = vault.encode("existing database secret")
self.assertEqual(vault.decode(token), "existing database secret")
def test_existing_row_is_decrypted_without_schema_changes(self):
seed, _, _ = self.make_vault(FakeCursor())
row = (seed.encode("secret"), seed.encode("login"), seed.encode("Alice"))
cursor = FakeCursor(one=row)
vault, _, calls = self.make_vault(cursor)
item = vault.one("Acme", "2024-02-03 12:00:00")
self.assertEqual(item["mySecret"], "secret")
self.assertEqual(item["myID"], "login")
self.assertEqual(item["myName"], "Alice")
self.assertEqual(
cursor.calls[0][1], ("Acme", "2024-02-03 12:00:00")
)
self.assertEqual(calls[0]["user"], "alice_")
self.assertEqual(calls[0]["db"], "Flowers")
def test_writes_use_parameters_and_existing_columns(self):
cursor = FakeCursor()
vault, connection, _ = self.make_vault(cursor)
hostile_label = 'Acme"; DROP TABLE alice_; --'
result = vault.add(hostile_label, "Alice", "login", "secret")
sql, parameters = cursor.calls[0]
self.assertIn("organization, myID, myName, mySecret, deleted", sql)
self.assertNotIn(hostile_label, sql)
self.assertEqual(parameters[0], hostile_label)
self.assertEqual(result["dateCreated"], "STORED")
self.assertEqual(connection.commits, 1)
def test_latest_active_list_keeps_legacy_query_semantics(self):
seed, _, _ = self.make_vault(FakeCursor())
cursor = FakeCursor(
many=(("Acme", seed.encode("login"), "2024-02-03 12:00:00"),)
)
vault, _, _ = self.make_vault(cursor)
items = vault.all()
self.assertEqual(items[0]["organization"], "Acme")
self.assertEqual(items[0]["myID"], "login")
self.assertIn("MAX(dateCreated)", cursor.calls[0][0])
self.assertEqual(cursor.calls[0][1], (0,))
def test_unsafe_table_identifier_is_rejected(self):
with self.assertRaises(InvalidCredentials):
Flower("alice`; DROP DATABASE Flowers", "legacy_pwd")
if __name__ == "__main__":
unittest.main()