archive/
data/
*~
+*.min.js
+!lib/jquery-2.1.0.min.js
+*.min.css
require_once('../init.php');
+$mask = NULL;
+
function fetch($mask)
{
global $db;
implode(',', $fields),
$mask['table'], $_POST['id']);
- $sth = $db->query($sql);
- if ($sth === false) return false;
-
- $row = $sth->fetch();
+ $row = $db->fetchAssoc($sql);
+ if ($row === false) return false;
foreach ($mask['edit'] as $field => $info)
if ($info['type'] == 'boolean')
return $row;
}
+function load_edit($mask)
+{
+ require_once($_SESSION['sys']['basedir'].'/lib/mask.php');
+ $form = build_form($mask);
+
+ return array('content' => $form['form'],
+ 'checks' => $form['checks']);
+}
+
function format_date($value)
{
$d = explode('.', $value);
'A PHP extension stopped the file upload.'
);
+function unique_pathname($subdir, $filename)
+{
+ $base = $_SESSION['sys']['basedir'] . 'archive';
+ if (!is_dir($base))
+ ajax_error('Archivpfad nicht vorhanden');
+
+ $base .= '/' . $subdir;
+ if (!is_dir($base))
+ ajax_error('Dokumentenpfad nicht vorhanden');
+
+ $base .= '/';
+
+ $path = date('Y');
+ if (!is_dir($base.$path))
+ if (mkdir($base.$path) === false)
+ ajax_error('Kann Verzeichnis nicht anlegen: ' . $path);
+
+ $path .= '/' . date('m');
+ if (!is_dir($base.$path))
+ if (mkdir($base.$path) === false)
+ ajax_error('Kann Verzeichnis nicht anlegen: ' . $path);
+
+ $parts = pathinfo($filename);
+
+ $parts['filename'] = $parts['filename'];
+ if (!empty($parts['extension'])) $parts['extension'] = strtolower($parts['extension']);
+ $path .= '/' . $parts['filename'];
+
+ $max = 100;
+ for ($i=0; $i < $max; $i++) {
+ $fname = $path;
+ if ($i > 0) $fname .= '('.$i.')';
+ if (!empty($parts['extension']))
+ $fname .= '.' . $parts['extension'];
+
+ if (!is_file($base.$fname))
+ return array($base, $fname);
+ }
+
+ ajax_error("Zu viele ähnliche Dateien");
+}
+
function store_file($field, $info)
{
global $upload_error;
return array('error' => "Fehler beim Upload einer Datei:\n" . $upload_error[$_FILES[$field]['error']],
'errormsg' => 'Fehler beim Upload einer Datei');
+ if ($_FILES[$field]['size'] == 0)
+ return array('error' => "Datei hat keinen Inhalt\nEventuell falsch kodierte Umlaute im Dateinamen",
+ 'errormsg' => 'Datei hat keinen Inhalt');
+
if (empty($_FILES[$field]['tmp_name']))
return array('error' => 'Keine temporäre Datei erzeugt',
'errormsg' => 'Keine temporäre Datei erzeugt');
return array('error' => 'Kein Pfadname konfiguriert',
'errormsg' => 'Kein Pfadname konfiguriert');
- $parts = pathinfo($_FILES[$field]['name']);
-
- $base = $_SESSION['sys']['basedir'] . 'archive';
- if (!is_dir($base))
- return array('error' => 'Archivpfad nicht vorhanden',
- 'errormsg' => 'Archivpfad nicht vorhanden');
-
- $base .= '/' . $info['path'];
- if (!is_dir($base))
- return array('error' => 'Dokumentenpfad nicht vorhanden',
- 'errormsg' => 'Dokumentenpfad nicht vorhanden');
- $base .= '/';
-
- $path = date('Y');
- if (!is_dir($base.$path))
- if (mkdir($base.$path) === false)
- return array('error' => 'Kann Verzeichnis nicht anlegen: ' . $path,
- 'errormsg' => 'Kann Verzeichnis nicht anlegen');
-
- $path .= '/' . date('m');
- if (!is_dir($base.$path))
- if (mkdir($base.$path) === false)
- return array('error' => 'Kann Verzeichnis nicht anlegen: ' . $path,
- 'errormsg' => 'Kann Verzeichnis nicht anlegen');
-
- $parts['filename'] = utf8_encode($parts['filename']);
- $path .= '/' . $parts['filename'];
-
- $max = 100;
- for ($i=0; $i < $max; $i++) {
- $fname = $path;
- if ($i > 0) $fname .= '('.$i.')';
- if (!empty($parts['extension']))
- $fname .= '.' . $parts['extension'];
-
- if (!is_file($base.$fname)) {
- if (move_uploaded_file($_FILES[$field]['tmp_name'], $base.$fname) === false)
- return array('error' => 'Kann Datei nicht speichern ',
- 'errormsg' => 'Kann Datei nicht speichern');
-
- chmod($base.$fname, 0640);
- return $fname;
- }
+ list($base, $fname) = unique_pathname($info['path'], $_FILES[$field]['name']);
+
+ if (move_uploaded_file($_FILES[$field]['tmp_name'], $base.$fname) === false)
+ return array('error' => 'Kann Datei nicht speichern ',
+ 'errormsg' => 'Kann Datei nicht speichern');
+
+ if (filesize($base.$fname) == 0) {
+ unlink($base.$fname);
+ return array('error' => "Datei konnte nicht gespeichert werden,\nhat keinen Inhalt (Größe 0)",
+ 'errormsg' => 'Datei hat keinen Inhalt');
+ }
+
+ if ($_POST['func_use_send'] == 1) {
+ $content = utf8_decode(file_get_contents($base.$fname));
+ file_put_contents($base.$fname, $content);
}
- return array('error' => 'Kann Datei nicht anlegen',
- 'errormsg' => 'Kann Datei nicht anlegen');
+ chmod($base.$fname, 0640);
+ return $fname;
}
function save($mask)
return array('error' => sprintf('Pflichtfeld %s nicht ausgefüllt', $info['name']),
'errormsg' => 'Pflichtfelder nicht ausgefüllt');
+ if (array_key_exists('ignore', $info) && $info['ignore'])
+ continue;
+
if ($info['type'] == 'boolean') {
$update[] = sprintf("%s=%d", $field, $_POST[$field] == 'on'?1:0);
} elseif ($info['type'] == 'hidden') {
return array('error' => sprintf('Pflichtfeld %s nicht ausgefüllt', $info['name']),
'errormsg' => 'Pflichtfelder nicht ausgefüllt');
+ if (array_key_exists('ignore', $info) && $info['ignore'])
+ continue;
+
if ($info['type'] == 'boolean') {
$fields[] = $field;
$values[] = $_POST[$field] == 'on'?1:0;
$fields[] = $field;
if (empty($_FILES[$field]) && $info['null'] === true)
$values[] = 'NULL';
+ elseif (empty($_FILES[$field]) && array_key_exists('source', $info) && is_callable($info['source'])) {
+ $fname = call_user_func_array($info['source'], array($field, $info));
+ if (is_array($fname))
+ return $fname;
+ $values[] = $db->quote($fname);
+ }
elseif (empty($_FILES[$field]))
$values[] = "''";
else {
return $fname;
$values[] = $db->quote($fname);
}
-
- } else {
+ } elseif (!array_key_exists('ignore', $info) || !$info['ignore']) {
$fields[] = $field;
if (empty($_POST[$field]) && isset($info['null']) && $info['null'] === true)
$values[] = 'NULL';
else
- $values[] = $db->quote(utf8_encode($_POST[$field]));
+ $values[] = $db->quote($_POST[$field]);
}
}
function custom_function($mask)
{
- if (!array_key_exists('callbacks',$mask))
- return array('error' => 'Unknown callback ' . htmlspecialchars($_POST['callback']));
+ $callback = false;
+
+ if (array_key_exists('callbacks',$mask)) {
+ if (!array_key_exists($_POST['callback'],$mask['callbacks']))
+ return array('error' => 'Unknown callback ' . htmlspecialchars($_POST['callback']));
+
+ $callback = $mask['callbacks'][$_POST['callback']];
+ } else {
+ $callback = 'cb_' . $_POST['callback'];
+
+ if (!function_exists($callback))
+ $callback = false;
+ }
+
+ if (!$callback)
+ throw new Exception(sprintf("Unknown callback %s", htmlspecialchars($_POST['callback'])));
+
+ return $callback();
+}
- if (!array_key_exists($_POST['callback'],$mask['callbacks']))
- return array('error' => 'Unknown callback ' . htmlspecialchars($_POST['callback']));
+function menu($base, $source)
+{
+ $menu = new MenuItem($base);
+ $menu->setSource($source);
- return $mask['callbacks'][$_POST['callback']]();
+ return array('title' => $menu->getTitle(),
+ 'menu' => $menu->render());
}
-function send_file($fname)
+function send_file($fname, $inline=NULL)
{
+ if ($inline === true) {
+ $disposition = 'inline';
+ } elseif ($inline === false) {
+ $disposition = 'attachment';
+ } else {
+ if (isset($_GET['attachment']) && $_GET['attachment']) {
+ $disposition = 'attachment';
+ } else {
+ $disposition = 'inline';
+ }
+ }
+
if (($f = fopen($fname,'r')) === false)
return sprintf("Cannot open file %s", $fname);
$basename = basename($fname);
$filesize = filesize($fname);
+ $mtime = filemtime($fname);
$content_type = mime_content_type($fname);
- if ($content_type == 'text/plain' || $content_type == 'text/html')
- $content_type .= '; charset=UTF-8';
+ if ($content_type == 'text/plain' || $content_type == 'text/html') {
+ $data = fread($f, 1024);
+ fseek($f, 0);
- header(sprintf('Content-disposition: inline; filename="%s"', $basename));
+ if (mb_detect_encoding($data) != 'UTF-8' || mb_check_encoding($data, 'UTF-8') == false)
+ $content_type .= '; charset=ISO-8859-1';
+ else
+ $content_type .= '; charset=UTF-8';
+ }
+
+
+ header(sprintf('Last-Modified: %s', date('r', $mtime)));
+ header(sprintf('Content-disposition: %s; filename="%s"', $disposition, $basename));
header(sprintf('Content-Length: %d', $filesize));
header(sprintf('Content-Type: %s', $content_type));
header("Cache-Control: ");
fclose($f);
}
-function download_file($table,$column,$path,$id)
+function download_file($table,$column,$path,$id,$inline=NULL)
{
global $db;
global $mask;
if (!file_exists($fname))
return sprintf("File not found\n%s", $fname);
- return send_file($fname);
+ return send_file($fname, $inline);
}
function process_file($mask)
exit;
}
-if (empty($_REQUEST['func']))
+function process_listedit($mask, $action)
+{
+ global $db;
+
+ $list = false;
+ if ($_REQUEST['second'] === true) {
+ $secondName = substr($_REQUEST['source'],strrpos($_REQUEST['source'], '__')+2);
+ foreach ($mask['second'] as $name => $second)
+ if ($name == $secondName)
+ $list = $second;
+ } else {
+ $list = $mask['list'];
+ }
+
+ if ($list === false) {
+ error_log('Grid not found for ' . $_REQUEST['source']);
+ ajax_error('Grid not found for ' . $_REQUEST['source']);
+ exit;
+ }
+
+ $values = array();
+ foreach ($_POST as $k => $v)
+ if (substr($k,0,10) == 'listinput_')
+ $values[substr($k,10)] = $v;
+
+ switch ($action) {
+ case 'upd':
+ $update = sprintf("sys_user='%s', sys_edit=now()", $_SESSION['sys']['login']);
+ foreach ($values as $c => $v) {
+ if (!array_key_exists('edit', $list['list'][$c])) continue;
+ if (!strlen($v) && array_key_exists('isNullable', $list['list'][$c]['edit']) && $list['list'][$c]['edit']['isNullable'] === true)
+ $v = NULL;
+ $update .= sprintf(", %s = %s", $c, $db->quote($v));
+ }
+ $sql = sprintf("UPDATE %s SET %s WHERE id = %d",
+ $list['table_edit'],
+ $update,
+ $_POST['_k0']);
+
+ if ($db->query($sql))
+ format_ajax(array('status' => true));
+ else
+ ajax_error('Cannot save item');
+ break;
+ }
+}
+
+function load_grid($mask)
+{
+ require_once($_SESSION['sys']['basedir'].'/lib/mask.php');
+
+ if ($_POST['name'] == 'main') {
+ if (!array_key_exists('list', $mask))
+ ajax_error('Missing grid definition');
+
+ $data = grid_details($_POST['source'], $_POST['name'], $mask);
+ } else {
+ if (!array_key_exists('second', $mask))
+ ajax_error('Missing grid definition');
+ if (!array_key_exists($_POST['name'], $mask['second']))
+ ajax_error('Missing grid definition');
+
+ $data = grid_details($_POST['source'], $_POST['name'], $mask['second'][$_POST['name']]);
+ }
+
+ return $data;
+}
+
+if (!empty($_REQUEST['_k0'])) {
+ db_connect();
+
+ foreach ($_POST as $k => $v)
+ if (substr($k,0,13) == '_action_grid_') {
+ $_REQUEST['source'] = substr($k,13);
+ $action = $v;
+ }
+
+ if (substr($_REQUEST['source'],-8) == '__second') {
+ $_REQUEST['source'] = substr($_REQUEST['source'],0,-8);
+ $_REQUEST['second'] = true;
+ } else {
+ $_REQUEST['second'] = false;
+ }
+
+ if (load_mask(Hallinta::instance()->module(),Hallinta::instance()->page()) === false) exit;
+ process_listedit($mask, $action);
exit;
+}
+
+function render_template($mask)
+{
+ require_once($_SESSION['sys']['basedir'].'/lib/mask.php');
+
+ try {
+ $template = new Template($_POST['template']);
+ } catch (Exception $e) {
+ ajax_error(sprintf('Template %s cannot be loaded',
+ htmlspecialchars($_POST['template'])));
+ }
+
+ $template->addData($_POST);
+ return $template->fillIn();
+}
+
+function process_function($function, $mask)
+{
+ if ($function == 'menu') {
+ $data = menu($_POST['base'], $_POST['source']);
+ } elseif ($function == 'fetch') {
+ $data = fetch($mask);
+ } elseif ($function == 'details') {
+ $data = details($mask);
+ } elseif ($function == 'edit') {
+ $data = load_edit($mask);
+ } elseif ($function == 'save') {
+ $data = save($mask);
+ } elseif ($function == 'insert') {
+ $data = insert($mask);
+ } elseif ($function == 'delete') {
+ $data = delete_or_copy($mask);
+ } elseif ($function == 'setvar') {
+ $data = set_variable($_POST['source'],$mask);
+ } elseif ($function == 'info') {
+ $data = get_infos($mask);
+ } elseif ($function == 'grid') {
+ $data = load_grid($mask);
+ } elseif ($function == 'template') {
+ $data = render_template($mask);
+ } elseif ($function == 'function') {
+ $data = custom_function($mask);
+ } else {
+ throw new Exception("Unknown function ".htmlspecialchars($function));
+ }
+
+ return $data;
+}
+
+function route_request($route, $mask)
+{
+ $data = $_POST;
+ unset($data['source']);
+ unset($data['route']);
+ unset($data['token']);
+ unset($data['id']);
+
+ list($class, $action) = explode('/', $_POST['route']);
+
+ $reflection = new ReflectionClass($class);
+
+ if (array_key_exists('id', $_POST) && strlen($_POST['id'])) {
+ $object = $reflection->newInstanceArgs([$_POST['id']]);
+
+ if (!$object->id())
+ throw new Exception(sprintf('Object %s not found', htmlspecialchars($_POST['id'])));
+ } else {
+ $object = $reflection->newInstance();
+ }
+
+ $method = 'ajax' . $action;
+ if (!method_exists($object, $method))
+ throw new Exception(sprintf("AJAX backend %s not found", htmlspecialchars($action)));
+
+ return $object->$method($data);
+}
+
+if ($_SERVER['REQUEST_METHOD'] == 'POST' &&
+ empty($_POST) && empty($_FILES) &&
+ $_SERVER['CONTENT_LENGTH'] > 0)
+ ajax_error(sprintf('Content size probably exeeded limit of %s', ini_get('post_max_size')));
if (empty($_REQUEST['source']))
- exit;
+ ajax_error('Missing source');
db_connect();
-if (load_mask($_REQUEST['source']) === false) exit;
+if ($_REQUEST['source'] != 'start' && load_mask(Hallinta::instance()->module(),Hallinta::instance()->page()) === false)
+ ajax_error('Loading source failed');
$data = array('error' => 'Unknown function');
if (isset($_GET['func']) && $_GET['func'] == 'file' && !empty($_GET['name']))
$data = process_file($mask);
+elseif (empty($_SESSION['sys']['login']) || $_POST['token'] != $_SESSION['token'])
+ ajax_error('Your session has been expired');
+
+
+try {
+ if (isset($_POST['func']))
+ $data = process_function($_POST['func'], $mask);
+ elseif (isset($_POST['route']))
+ $data = route_request($_POST['route'], $mask);
+ else
+ throw new Exception("Unknown backend call");
+} catch (Exception $e) {
+ debug($e->getMessage());
+ debug($e->getTraceAsString());
+ ajax_error($e->getMessage());
+} catch (Error $e) {
+ debug($e->getMessage());
+ debug($e->getTraceAsString());
+ ajax_error($e->getMessage());
+}
+
+if (is_null($data))
+ $data = [];
+elseif (is_scalar($data))
+ $data = ['data' => $data];
-if ($_POST['func'] == 'fetch') {
- $data = fetch($mask);
-} elseif ($_POST['func'] == 'details') {
- $data = details($mask);
-} elseif ($_POST['func'] == 'save') {
- $data = save($mask);
-} elseif ($_POST['func'] == 'insert') {
- $data = insert($mask);
-} elseif ($_POST['func'] == 'delete') {
- $data = delete_or_copy($mask);
-} elseif ($_POST['func'] == 'setvar') {
- $data = set_variable($_POST['source'],$mask);
-} elseif ($_POST['func'] == 'info') {
- $data = get_infos($mask);
-} elseif ($_POST['func'] == 'function') {
- $data = custom_function($mask);
+if (is_array($data)) {
+ if (isset($_POST['func']) && !array_key_exists('func', $data))
+ $data['func'] = $_POST['func'];
+ elseif (isset($_POST['route']) && !array_key_exists('route', $data))
+ $data['route'] = $_POST['route'];
}
format_ajax($data);
-
-?>
if (empty($_POST['table']))
exit;
+$hallinta = Hallinta::instance();
db_connect();
-if (load_mask(substr($_POST['table'],5)) === false) exit;
+if (load_mask($hallinta->module(),$hallinta->page()) === false) exit;
$fields = array_keys($mask['list']);
$column = $fields[$_POST['column']];
if ($sth === false)
error_log($sql . ': ' . db_error());
-?>
$sql = sprintf("DELETE FROM %s WHERE %s = %d AND %s IN (SELECT %s FROM %s%s%s)",
$details['table'],
$details['basecol'], $details['baseval'],
- $details['refcol'], $details['refid'],
+ $details['refcol'], $details['refid'],
$details['reftable'],
array_key_exists('join', $mask) ? ' JOIN ' . join(' JOIN ', $mask['join']) : '',
strlen($where) ? ' WHERE ' . $where : '');
- else
+ else {
+ $sql = sprintf("DELETE FROM %s WHERE %s = %d AND %s IN (SELECT %s FROM %s%s%s)",
+ $details['table'],
+ $details['basecol'], $details['baseval'],
+ $details['refcol'], $details['refid'],
+ $details['reftable'],
+ array_key_exists('join', $mask) ? ' JOIN ' . join(' JOIN ', $mask['join']) : '',
+ strlen($where) ? ' WHERE ' . $where : '');
+ $db->execute($sql);
$sql = sprintf("INSERT INTO %s (%s,%s,sys_user,sys_edit) SELECT %s,%s,%s,now() FROM %s%s " .
"LEFT JOIN %s ON %s.%s = 1 AND %s.%s = %s.id WHERE %s.id IS NULL%s",
$details['table'],
$details['reftable'],
$details['table'],
strlen($where) ? ' AND ' . $where : '');
+ }
return $sql;
}
if (empty($_POST['table']))
exit;
+$hallinta = Hallinta::instance();
db_connect();
-if (load_mask(substr($_POST['table'],5)) === false) exit;
+if (load_mask($hallinta->module(),$hallinta->page()) === false) exit;
+
+if ($hallinta->isSecond()) {
+ if (!array_key_exists('second', $mask) ||
+ !array_key_exists($hallinta->second(), $mask['second']))
+ exit;
+ $list = $mask['second'][$hallinta->second()]['list'];
+} else {
+ $list = $mask['list'];
+}
-$fields = array_keys($mask['list']);
+$fields = array_keys($list);
$field = $fields[$_POST['column']];
if (empty($field)) exit;
-if (!is_array($mask['list'][$field]['update'])) return;
+if (!is_array($list[$field]['update'])) exit;
+
+if (!array_key_exists('baseval', $list[$field]['update']))
+ $list[$field]['update']['baseval'] = $_POST['main_id'];
if (isset($_POST['reference']))
- $sql = build_simple_query($mask['list'][$field]['update']);
+ $sql = build_simple_query($list[$field]['update']);
else
- $sql = build_query($mask['list'][$field]['update'],$mask);
+ $sql = build_query($list[$field]['update'],$mask);
$sth = $db->query($sql);
if ($sth === false)
error_log($sql . ': ' . db_error());
-?>
header("Pragma: no-cache");\r
header("Expires: ".gmdate("D, d M Y H:i:s",time()+(-1*60))." GMT");\r
header("Content-type: text/xml");\r
-echo "<?xml version='1.0' encoding='UTF-8'?".">\n";\r
\r
require_once('../lib/dbase.php');\r
require_once('../lib/dbClass.php');\r
-require_once('../lib/rico/ricoXmlResponse.php');\r
+require_once('../lib/rico3/plugins/php/ricoResponse.php');\r
\r
$id=isset($_GET["id"]) ? $_GET["id"] : "";\r
-$offset=isset($_GET["offset"]) ? $_GET["offset"] : "0";\r
-$size=isset($_GET["page_size"]) ? $_GET["page_size"] : "";\r
-$total=isset($_GET["get_total"]) ? strtolower($_GET["get_total"]) : "false";\r
-$distinct=isset($_GET["distinct"]) ? $_GET["distinct"] : "";\r
+$filters=isset($_SESSION[$id . ".filters"]) ? $_SESSION[$id . ".filters"] : array();\r
+$oXmlResp= new ricoXmlResponse();\r
+$errmsg='';\r
+$query='';\r
\r
-echo "\n<ajax-response><response type='object' id='".$id."_updater'>";\r
-if (empty($id)) {\r
- ErrorResponse("No ID provided!");\r
-} elseif ($distinct=="" && !is_numeric($offset)) {\r
- ErrorResponse("Invalid offset!");\r
-} elseif ($distinct=="" && !is_numeric($size)) {\r
- ErrorResponse("Invalid size!");\r
-} elseif ($distinct!="" && !is_numeric($distinct)) {\r
- ErrorResponse("Invalid distinct parameter!");\r
-} elseif (!isset($_SESSION[$id])) {\r
- ErrorResponse("Your connection with the server was idle for too long and timed out. Please refresh this page and try again.");\r
+if (!isset($_SESSION[$id])) {\r
+ $errmsg="Your connection with the server was idle for too long and timed out. Please refresh this page and try again.";\r
} elseif (!OpenDB()) {\r
- ErrorResponse(htmlspecialchars($oDB->LastErrorMsg));\r
+ $errmsg=$oDB->LastErrorMsg;\r
} else {\r
- if (empty($_GET['second_id'])) {\r
- $fname = substr($id,5);\r
- load_mask($fname);\r
- grid_sql($fname, $mask);\r
- }\r
-\r
- $filters=isset($_SESSION[$id . ".filters"]) ? $_SESSION[$id . ".filters"] : array();\r
- $oDB->DisplayErrors=false;\r
- $oDB->ErrMsgFmt="MULTILINE";\r
- $oXmlResp= new ricoXmlResponse();\r
+ $query=$_SESSION[$id];\r
+ if (isset($_SESSION[$id . ".filters"])) $filters=$_SESSION[$id . ".filters"];\r
+ $oXmlResp->SetDbConn($oDB);\r
$oXmlResp->sendDebugMsgs=true;\r
- $oXmlResp->convertCharSet=false; // Database is already in UTF-8\r
-\r
- if (isset($_GET['second_id']))\r
- $query = str_replace('{id}', $_GET['second_id'], $_SESSION[$id]);\r
- else\r
- $query = $_SESSION[$id];\r
-\r
- if ($distinct=="") {\r
- $oXmlResp->Query2xml($query, intval($offset), intval($size), $total!="false", $filters);\r
- } else {\r
- if (isset($_SESSION[$id.'_distinct_'.$distinct]))\r
- $oXmlResp->Query2xmlDistinct($query, intval($distinct), -1, $filters, $_SESSION[$id.'_distinct_'.$distinct]);\r
- else\r
- $oXmlResp->Query2xmlDistinct($query, intval($distinct), -1, $filters);\r
- }\r
- if (!empty($oDB->LastErrorMsg)) {\r
- echo "\n<error>";\r
- echo "\n".htmlspecialchars($oDB->LastErrorMsg);\r
- echo "\n</error>";\r
- }\r
- $oXmlResp=NULL;\r
- # CloseApp();\r
+ $oXmlResp->convertCharSet=false;\r
}\r
-echo "\n</response></ajax-response>";\r
\r
+if (isset($_GET['second_id']))\r
+ $query = str_replace('{id}', $_GET['second_id'], $_SESSION[$id]);\r
+else\r
+ $query = $_SESSION[$id];\r
\r
-function ErrorResponse($msg) {\r
- echo "\n<rows update_ui='false' /><error>" . $msg . "</error>";\r
-}\r
+$distinctquery = false;\r
+$distinct = isset($_GET["distinct"]) ? $_GET["distinct"] : false;\r
+if ($distinct !== false && isset($_SESSION[$id.'_distinct_'.$distinct]))\r
+ $distinctquery = $_SESSION[$id.'_distinct_'.$distinct];\r
\r
-?>\r
+$oXmlResp->SetGridDefinition(grid_definition($id));\r
+$oXmlResp->ProcessQuery($id, $query, $filters, $errmsg, $distinctquery);\r
+$oXmlResp=NULL;\r
--- /dev/null
+<?php
+
+class Actions extends Singleton {
+ protected static $instance = false;
+ private $actions = array();
+ private $selects = array();
+
+ public function addLink(Link $info)
+ {
+ $this->actions[] = $info;
+ }
+
+ public function addSelect(Select $info)
+ {
+ $this->selects[] = $info;
+ }
+
+ public function toString()
+ {
+ $ret = '';
+ $code = array();
+ foreach (array_reverse($this->selects) as $item) {
+ $code[] = sprintf('<span class="item">%s</span>', $item->toString());
+ }
+ foreach (array_reverse($this->actions) as $item) {
+ $code[] = sprintf('<span class="item">%s</span>', $item->toString());
+ }
+ $ret .= implode('', $code);
+
+ return $ret;
+ }
+
+}
--- /dev/null
+<?php
+
+class Autoload {
+ protected static $instance;
+ private $basedir;
+
+ public static function get()
+ {
+ if (is_null(static::$instance))
+ static::$instance = new static();
+
+ return static::$instance;
+ }
+
+ private function __construct()
+ {
+ $this->basedir = dirname(__DIR__);
+ }
+
+ public function loadClassModule($class)
+ {
+ $module = false;
+
+ if (class_exists('Hallinta', false)) {
+ $module = Hallinta::instance()->module();
+ } elseif (!empty($_REQUEST['source']) && strpos($_REQUEST['source'], '__')) {
+ $name = sanitise_filename($_REQUEST['source']);
+ list($module,$fname) = explode('__', $name);
+ }
+
+ if ($module) {
+ $path = sprintf("%s/%s/%s/class/%s.class.php", $this->basedir,
+ HALLINTA_MODULEDIR, $module, strtolower($class));
+ if (file_exists($path))
+ require_once($path);
+ }
+ }
+
+ public function loadClass($class)
+ {
+ $path = sprintf("%s/class/%s.class.php", $this->basedir,
+ strtolower($class));
+ if (file_exists($path))
+ require_once($path);
+ }
+}
+
+spl_autoload_register([Autoload::get(), 'loadClassModule']);
+spl_autoload_register([Autoload::get(), 'loadClass']);
<?php
class Database {
+ private static $instance = NULL;
private $db;
private $error_log = false;
private $error_mail = false;
# $this->db->query("SET CHARACTER SET 'utf8'");
# $this->db->query("SET collation_connection = 'utf8_general_ci'");
# $this->db->query("SET lc_time_names = 'de_DE'");
+
+ static::registerFirst($this);
+ }
+
+ public static function get()
+ {
+ if (is_null(static::$instance))
+ throw new Exception("No database object available");
+
+ return static::$instance;
+ }
+
+ private static function registerFirst($db)
+ {
+ if (is_null(static::$instance))
+ static::$instance = $db;
}
public function enableErrorLog()
$mail->send($body);
}
+ return $sth;
}
public function errorInfo()
$this->logQuery($sql);
$sth = $this->db->query($sql);
- if ($sth === false) $this->handleError($sth,$sql);
+ if ($sth === false) return $this->handleError($sth,$sql);
if (preg_match('/INSERT\s+INTO\s+(\S+)\s+/i', $sql, $matches))
$this->lastInsertTable = $matches[1];
}
}
-
-?>
--- /dev/null
+<?php
+
+abstract class DatabaseTable {
+ protected $db;
+ protected $idcolumn = 'id';
+ protected $username = 'class';
+ protected $table;
+ protected $data;
+ protected $id;
+
+ public function __construct($table, $id=false, $column=false)
+ {
+ global $db;
+
+ $this->db = $db;
+ $this->table = $table;
+
+ if (isset($_SESSION['sys']['login']))
+ $this->username = $_SESSION['sys']['login'];
+
+ if ($id) {
+ if ($column)
+ $this->loadByColumn($id, $column);
+ else
+ $this->load($id);
+ }
+ }
+
+ protected function postLoad() {}
+
+ protected function load($id)
+ {
+ $sql = sprintf("SELECT * FROM %s WHERE %s = %d LIMIT 1",
+ $this->table, $this->idcolumn, $id);
+ $this->data = $this->db->fetchObject($sql);
+ if ($this->data) {
+ $idcolumn = $this->idcolumn;
+ $this->id = $this->data->$idcolumn;
+ $this->postLoad();
+ return true;
+ }
+ return false;
+ }
+
+ protected function loadByColumn($id,$column)
+ {
+ $sql = sprintf("SELECT * FROM %s WHERE `%s` = %s",
+ $this->table, $column, $this->db->quote($id));
+ $this->data = $this->db->fetchObject($sql);
+ if ($this->data) {
+ $idcolumn = $this->idcolumn;
+ $this->id = $this->data->$idcolumn;
+ $this->postLoad();
+ }
+ }
+
+ public function id()
+ {
+ return $this->id;
+ }
+
+ public function get($name)
+ {
+ if (array_key_exists($name, $this->data))
+ return $this->data->$name;
+
+ return NULL;
+ }
+}
\ No newline at end of file
--- /dev/null
+<?php
+
+class Hallinta extends Singleton {
+ protected static $instance = false;
+ protected $db = null;
+ protected $module = null;
+ protected $page = null;
+ protected $urlbase = null;
+ protected $second = null;
+ protected $title = null;
+
+ protected function ___construct()
+ {
+ global $db;
+
+ $this->db = $db;
+
+ if (empty($_SESSION['sys']['baseurl']) && substr($_SERVER['SCRIPT_FILENAME'],-10) == '/index.php') {
+ $this->urlbase = substr(substr($_SERVER['SCRIPT_FILENAME'],0,-9), strlen($_SERVER['DOCUMENT_ROOT']));
+ } else {
+ if (substr($_SESSION['sys']['baseurl'],0,1) != '/')
+ $_SESSION['sys']['baseurl'] = '/' . $_SESSION['sys']['baseurl'];
+ if (substr($_SESSION['sys']['baseurl'],-1) != '/')
+ $_SESSION['sys']['baseurl'] .= '/';
+ $this->urlbase = $_SESSION['sys']['baseurl'];
+ }
+
+ if (!empty($_REQUEST['table']) && empty($_REQUEST['source']) && substr($_REQUEST['table'],0,5) == 'grid_') {
+ $_REQUEST['source'] = substr($_POST['table'],5);
+ }
+
+ if (!empty($_REQUEST['source'])) {
+ $parts = explode('__', $_REQUEST['source']);
+ if (count($parts) > 1) {
+ $this->module = $parts[0];
+ $this->page = $parts[1];
+ if (count($parts) == 4) {
+ $this->second = $parts[2];
+ }
+ }
+ } elseif (!empty($_GET['mask'])) {
+ list($this->module, $this->page) = explode('__', $_GET['mask']);
+ } elseif (basename($_SERVER['SCRIPT_FILENAME']) == 'ricoXMLquery.php' && !empty($_GET['id'])) {
+ list($this->module, $this->page) = explode('__', substr($_GET['id'],5));
+ } elseif (!empty($_SERVER['REQUEST_URI']) && isset($_SESSION['sys']['baseurl'])) {
+ $uri = rtrim(substr($_SERVER['REQUEST_URI'], strlen($_SESSION['sys']['baseurl'])), '/');
+ $parts = explode('/', $uri);
+ if (count($parts) == 2) {
+ $this->module = $parts[0];
+ $this->page = $parts[1];
+ }
+ }
+ }
+
+ public function basedir()
+ {
+ if (isset($_SESSION['sys']['basedir']))
+ return $_SESSION['sys']['basedir'];
+
+ return $_SERVER['DOCUMENT_ROOT'] . $this->urlbase();
+ }
+
+ public function urlbase()
+ {
+ return $this->urlbase;
+ }
+
+ public function module()
+ {
+ return $this->module;
+ }
+
+ public function page()
+ {
+ return $this->page;
+ }
+
+ public function second()
+ {
+ return $this->second;
+ }
+
+ public function isSecond()
+ {
+ return !is_null($this->second);
+ }
+
+ public function isMobile()
+ {
+ return strpos($_SERVER['HTTP_USER_AGENT'], 'Android') !== false || strpos($_SERVER['HTTP_USER_AGENT'], 'iPhone') !== false;
+ }
+
+ public function parentMenu()
+ {
+ $sql = sprintf("SELECT parent FROM sys_menuitem WHERE module = %s AND page = %s",
+ $this->db->quote($this->module),
+ $this->db->quote($this->page));
+ $parent = $this->db->fetchValue($sql);
+
+ if ($parent === 0) return '';
+
+ return $parent;
+ }
+
+ public function setTitle($title)
+ {
+ $this->title = $title;
+ }
+
+ public function getTitle()
+ {
+ if (is_null($this->title) && isset($_GET['login']) && $_GET['login'] == 'true')
+ return '';
+
+ return $this->title;
+ }
+}
--- /dev/null
+<?php
+
+class JavaScript extends Singleton {
+ protected static $instance = false;
+ protected $code = array();
+ protected $onload = array();
+ protected $files = array();
+
+ public function add($code)
+ {
+ $this->code[] = $code;
+ }
+
+ public function onLoad($code)
+ {
+ $this->onload[] = $code;
+ }
+
+ public function file($path)
+ {
+ $hallinta = Hallinta::instance();
+
+ if (strpos($path, '/') === false)
+ $path = sprintf('%s/%s/%s', HALLINTA_MODULEDIR, $hallinta->module(), $path);
+
+ $info = pathinfo($path);
+
+ $minfile = sprintf('%s%s/%s.min.%s', $hallinta->basedir(), $info['dirname'], $info['filename'], $info['extension']);
+ if (file_exists($minfile)) {
+ $origpath = $hallinta->basedir().$path;
+ if (filemtime($minfile) > filemtime($origpath))
+ $path = sprintf('%s/%s.min.%s', $info['dirname'], $info['filename'], $info['extension']);
+ }
+
+ $this->files[$path] = true;
+ }
+
+ public function toString()
+ {
+ $ret = '';
+ foreach (array_keys($this->files) as $file)
+ $ret .= sprintf('<script type="text/javascript" src="%s%s"></script>'."\n", Hallinta::instance()->urlbase(), $file);
+
+ if (count($this->code) || count($this->onload)) {
+ $ret .= '<script type="text/javascript">'."\n";
+
+ if (count($this->code))
+ $ret .= implode("\n", $this->code) . "\n";
+
+ if (count($this->onload)) {
+ $ret .= "\$(function(){\n";
+ $ret .= ' ' . str_replace("\n", "\n ", implode("\n", $this->onload)) . "\n";
+ $ret .= "});\n";
+ }
+ $ret .= "</script>\n";
+ }
+
+ return $ret;
+ }
+
+}
--- /dev/null
+<?php
+
+class Link {
+ protected $id = false;
+ protected $icon;
+ protected $title;
+ protected $link = false;
+ protected $function = false;
+ protected $anchor = false;
+
+ public function __construct(array $info)
+ {
+ if (!array_key_exists('icon', $info))
+ throw new Exception('Property icon missing');
+ else $this->icon = $info['icon'];
+
+ if (!array_key_exists('title', $info))
+ throw new Exception('Property title missing');
+ else $this->title = $info['title'];
+
+ if (!array_key_exists('link', $info) && !array_key_exists('function', $info))
+ throw new Exception('Property link and function missing');
+
+ if (array_key_exists('id', $info)) $this->id = $info['id'];
+ if (array_key_exists('link', $info)) $this->link = $info['link'];
+ if (array_key_exists('function', $info)) $this->function = $info['function'];
+ if (array_key_exists('anchor', $info)) $this->anchor = $info['anchor'];
+ }
+
+ public function toString()
+ {
+ if ($this->anchor) {
+ $imgattr = array('border="0"');
+ $attr = array();
+ if ($this->id) $attr[] = sprintf('id="%s"', $this->id);
+ if ($this->title) $attr[] = sprintf('title="%s"', $this->title);
+ if ($this->icon) $imgattr[] = sprintf('src="%s"', $this->icon);
+ if ($this->function) {
+ $attr[] = 'href="#"';
+ $attr[] = sprintf('onclick="return %s(event)"', $this->function);
+ } elseif ($this->link)
+ $attr[] = sprintf('href="%s"', $this->link);
+ $code = sprintf('<a %s><img %s></a>', implode(' ', $attr), implode(' ', $imgattr));
+ } else {
+ $attr = array('border="0"');
+ if ($this->id) $attr[] = sprintf('id="%s"', $this->id);
+ if ($this->title) $attr[] = sprintf('title="%s"', $this->title);
+ if ($this->icon) $attr[] = sprintf('src="%s"', $this->icon);
+ if ($this->function)
+ $attr[] = sprintf('onclick="return %s(event)"', $this->function);
+ elseif ($this->link)
+ $attr[] = sprintf("onclick=\"function(){ window.href.location = '%s'; }\"", $this->link);
+ $code = sprintf('<img %s>', implode(' ', $attr));
+ }
+ return $code;
+ }
+}
class Mail {
protected $header = array();
protected $env_from = false;
+ protected $attachments = array();
+ protected $CRLF = "\r\n";
public function set($name, $value)
{
$this->env_from = $value;
}
- public function send($body)
+ protected function contentType($path)
+ {
+ if (($fh = popen('/usr/bin/file -i -b ' . escapeshellarg(realpath($path)), 'r')) !== false) {
+ $type = fread($fh, 1024);
+ fclose($fh);
+ $parts = explode(';', $type);
+ return trim($parts[0]);
+ } else
+ return mime_content_type($file);
+ }
+
+ public function attach($content, $type=false, $first=false)
+ {
+ $part = new stdClass();
+
+ if ($type === false) {
+ if (file_exists($content)) {
+ $part->content = chunk_split(base64_encode(file_get_contents($content)));
+ $part->header = 'Content-Type: ' . $this->contentType($content) . '; name="'.basename($content).'"'. $this->CRLF .
+ 'Content-Transfer-Encoding: base64' . $this->CRLF .
+ 'Content-Disposition: attachment';
+ }
+ } elseif (substr($type, 0, 10) == 'text/plain' ||
+ substr($type, 0, 9) == 'text/html') {
+ if (strpos($type, 'charset=') === false)
+ $type .= '; charset="UTF-8"';
+ $part->content = $content;
+ $part->header = 'Content-Type: ' . $type . $this->CRLF .
+ 'Content-Transfer-Encoding: 8bit';
+ } else {
+ $part->content = chunk_split(base64_encode($content));
+ $part->header = 'Content-Type: ' . $type . $this->CRLF .
+ 'Content-Transfer-Encoding: base64' . $this->CRLF .
+ 'Content-Disposition: attachment';
+ }
+
+ if (!empty($part->content)) {
+ if ($first)
+ array_unshift($this->attachments, $part);
+ else
+ $this->attachments[] = $part;
+ }
+ }
+
+ public function send($body=false)
{
if (!array_key_exists('From', $this->header))
throw new Exception('No sender given.');
throw new Exception('No recipient given.');
if (!array_key_exists('Subject', $this->header))
throw new Exception('No subject given.');
- if (empty($body))
- throw new Exception('Mail body empty.');
+ if (!count($this->attachments) && empty($body))
+ throw new Exception('Mail body empty and no attachments.');
- if (!array_key_exists('Content-Type', $this->header))
- $this->set('Content-Type', 'text/plain; charset=UTF-8');
- if (!array_key_exists('Content-Disposition', $this->header))
- $this->set('Content-Disposition', 'inline');
- if (!array_key_exists('Content-Transfer-Encoding', $this->header))
- $this->set('Content-Transfer-Encoding', '8bit');
+ if (count($this->attachments)) {
+ $boundary = md5(uniqid(time()));
+ $this->header['MIME-Version'] = array('1.0');
+ $this->header['Content-Type'] = array('multipart/mixed; boundary="'.$boundary.'"');
+ if ($body)
+ $this->attach($body, substr($body,0,1) == '<' ? 'text/html' : 'text/plain', true);
+ } else {
+ if (!array_key_exists('Content-Type', $this->header)) {
+ if ($body && substr($body,0,1) == '<')
+ $this->set('Content-Type', 'text/html; charset=UTF-8');
+ else
+ $this->set('Content-Type', 'text/plain; charset=UTF-8');
+ }
+ if (!array_key_exists('Content-Disposition', $this->header))
+ $this->set('Content-Disposition', 'inline');
+ if (!array_key_exists('Content-Transfer-Encoding', $this->header))
+ $this->set('Content-Transfer-Encoding', '8bit');
+ }
$header = '';
+ $to = implode(', ', $this->header['To']);
+ if (defined('MAIL_DISABLED') && MAIL_DISABLED == true) {
+ $header .= 'Orig-To: ' . $to . $this->CRLF;
+ $to = MAIL_DISABLED;
+
+ if (array_key_exists('Cc', $this->header)) {
+ $this->header['Orig-Cc'] = $this->header['Cc'];
+ unset($this->header['Cc']);
+ }
+ if (array_key_exists('Bcc', $this->header)) {
+ $this->header['Orig-Bcc'] = $this->header['Bcc'];
+ unset($this->header['Bcc']);
+ }
+ }
foreach ($this->header as $name => $values) {
if ($name == 'To' || $name == 'Subject')
continue;
else
- $header .= $name . ': ' . implode(', ', $values) . "\r\n";
+ $header .= $name . ': ' . implode(', ', $values) . $this->CRLF;
}
$opts = '-t';
$opts .= strlen($this->env_from) ? ' -f '.$this->env_from : '';
- $result = mail(implode(',',$this->header['To']), $this->header['Subject'][0], $body, $header, $opts);
+
+ $header = substr($header,0,-strlen($this->CRLF));
+ if (count($this->attachments)) {
+ $header .= $this->CRLF . "This is a MIME encoded message." . $this->CRLF;
+
+ foreach ($this->attachments as $part) {
+ $header .= "--$boundary" . $this->CRLF;
+ $header .= $part->header . $this->CRLF;
+ $header .= $this->CRLF . $part->content . $this->CRLF;
+ }
+ $header .= "--$boundary--";
+
+ $result = mail($to, $this->header['Subject'][0], '', $header, $opts);
+ } else {
+ $result = mail($to, $this->header['Subject'][0], $body, $header, $opts);
+ }
return $result;
}
--- /dev/null
+<?php
+
+class MenuItem {
+ protected $db = null;
+ protected $parent = false;
+ protected $source = false;
+
+ public function __construct($parent=false)
+ {
+ global $db;
+ $this->db = $db;
+ $this->parent = $parent;
+ }
+
+ public function setSource($source)
+ {
+ $this->source = $source;
+ }
+
+ protected function getItems()
+ {
+ $sql = "
+ SELECT DISTINCT sys_menuitem.id, title, tooltip,
+ module, page,
+ priority,
+ module IS NULL AND page IS NULL AS submenu
+ FROM sys_menuitem
+ JOIN sys_group_menuitem ON sys_menuitem.id = sys_menuitem_id
+ JOIN sys_group ON sys_group.id = sys_group_menuitem.sys_group_id
+ JOIN sys_group_user ON sys_group.id = sys_group_user.sys_group_id
+ WHERE parent = %d AND shadow = 0 AND sys_user_id = %d
+ ORDER BY priority
+ ";
+ $sql = sprintf($sql, $this->parent, $_SESSION['sys']['uid']);
+
+ return $this->db->fetchObjectList($sql);
+ }
+
+ public function getTitle()
+ {
+ if (empty($this->parent))
+ return 'Hauptmenü';
+
+ $sql = sprintf("SELECT title FROM sys_menuitem WHERE id = %d", $this->parent);
+ return $this->db->fetchValue($sql);
+ }
+
+ protected function getParent()
+ {
+ $sql = sprintf("SELECT parent FROM sys_menuitem WHERE id = %d", $this->parent);
+
+ return $this->db->fetchValue($sql);
+ }
+
+ public function render()
+ {
+ $result = array();
+ if (empty($this->parent))
+ $result[] = sprintf('<li%s><a href="%s" title="Zurück zur Hauptseite">Start</a></li>',
+ $this->source == 'start' ? ' class="current"' : '',
+ Hallinta::instance()->urlbase());
+
+ $rows = $this->getItems();
+
+ foreach ($rows as $row) {
+ if ($row->submenu) {
+ $result[] = sprintf('<li><a href="#" onclick="return display_menu(event,%d)" title="%s">%s...</a></li>',
+ $row->id, $row->tooltip, $row->title);
+ } else {
+ if (defined('REWRITE_URLS') && REWRITE_URLS)
+ $url = sprintf('%s%s/%s', Hallinta::instance()->urlbase(), $row->module, $row->page);
+ else
+ $url = sprintf('./?mask=%s__%s', $row->module, $row->page);
+ $result[] = sprintf('<li%s><a href="%s" title="%s">%s</a></li>',
+ $this->source == ($row->module.'__'.$row->page) ? ' class="current"' : '',
+ $url,
+ $row->tooltip,
+ $row->title);
+ }
+ }
+
+
+ if (empty($this->parent))
+ $result[] = sprintf('<li><a href="%s?logout=true" title="Abmelden">Logout</a></li>', Hallinta::instance()->urlbase());
+ else
+ $result[] = sprintf('<li><a href="#" onclick="return display_menu(event,\'%s\')" title="Zurück">Zurück</a></li>',
+ $this->getParent());
+
+ if (!count($result)) return '';
+
+ return '<ul class="menu">' . implode($result) . '</ul>';
+ }
+
+ public function getMenus()
+ {
+ $sql = "SELECT id,title AS text FROM sys_menuitem WHERE module IS NULL AND page IS NULL";
+
+ return $this->db->fetchAssocList($sql);
+ }
+
+ public function getModules()
+ {
+ $list = [];
+ $dir = Hallinta::instance()->basedir() . HALLINTA_MODULEDIR;
+
+ foreach (new DirectoryIterator($dir) as $fileInfo) {
+ if ($fileInfo->isDot()) continue;
+ if (!$fileInfo->isDir()) continue;
+ if (file_exists($dir . '/' . $fileInfo->getFileName() . '/' . '.moduleignore')) continue;
+ $list[] = ['id' => $fileInfo->getFileName(), 'text' => $fileInfo->getFileName()];
+ }
+
+ usort($list, function($a, $b){ return strcmp($a['text'], $b['text']); });
+
+ return $list;
+ }
+
+ public function getPages($module)
+ {
+ $list = [];
+ $module = str_replace('/', '', $module);
+
+ $dir = Hallinta::instance()->basedir() . HALLINTA_MODULEDIR . '/' . $module;
+
+ if (!is_dir($dir)) return [];
+ foreach (new DirectoryIterator($dir) as $fileInfo) {
+ if ($fileInfo->isDot()) continue;
+ if (!$fileInfo->isFile()) continue;
+ if (substr($fileInfo->getFileName(), -4) != '.php') continue;
+
+ $page = substr($fileInfo->getFileName(),0,-4);
+ $list[] = ['id' => $page, 'text' => $page];
+ }
+
+ usort($list, function($a, $b){ return strcmp($a['text'], $b['text']); });
+
+ return $list;
+ }
+
+ public function hasPermission()
+ {
+ $hallinta = Hallinta::instance();
+
+ $sql = <<<EOS
+ SELECT count(*)
+ FROM sys_menuitem
+ JOIN sys_group_menuitem ON sys_menuitem.id = sys_menuitem_id
+ JOIN sys_group ON sys_group.id = sys_group_menuitem.sys_group_id
+ JOIN sys_group_user ON sys_group.id = sys_group_user.sys_group_id
+ WHERE sys_user_id = %d
+ AND sys_menuitem.module = %s AND sys_menuitem.page = %s
+EOS;
+ $sql = sprintf($sql, $_SESSION['sys']['uid'], $this->db->quote($hallinta->module()), $this->db->quote($hallinta->page()));
+
+ return $this->db->fetchValue($sql) > 0;
+ }
+
+ public function mayEdit()
+ {
+ $hallinta = Hallinta::instance();
+
+ $sql = <<<EOS
+ SELECT count(*)
+ FROM sys_menuitem
+ JOIN sys_group_menuitem ON sys_menuitem.id = sys_menuitem_id
+ JOIN sys_group ON sys_group.id = sys_group_menuitem.sys_group_id
+ JOIN sys_group_user ON sys_group.id = sys_group_user.sys_group_id
+ WHERE sys_menuitem.edit = 1 AND sys_user_id = %d
+ AND sys_menuitem.module = %s AND sys_menuitem.page = %s
+EOS;
+ $sql = sprintf($sql, $_SESSION['sys']['uid'], $this->db->quote($hallinta->module()), $this->db->quote($hallinta->page()));
+
+ return $this->db->fetchValue($sql) > 0;
+ }
+
+ public function isRegular()
+ {
+ $hallinta = Hallinta::instance();
+
+ $sql = <<<EOS
+ SELECT count(*)
+ FROM sys_menuitem
+ JOIN sys_group_menuitem ON sys_menuitem.id = sys_menuitem_id
+ JOIN sys_group ON sys_group.id = sys_group_menuitem.sys_group_id
+ JOIN sys_group_user ON sys_group.id = sys_group_user.sys_group_id
+ WHERE sys_menuitem.shadow = 0 AND sys_user_id = %d
+ AND sys_menuitem.module = %s AND sys_menuitem.page = %s
+EOS;
+ $sql = sprintf($sql, $_SESSION['sys']['uid'], $this->db->quote($hallinta->module()), $this->db->quote($hallinta->page()));
+
+ return $this->db->fetchValue($sql) > 0;
+ }
+
+ public function ajaxGetParent(Array $data)
+ {
+ return ['list' => $this->getMenus()];
+ }
+
+
+ public function ajaxGetModules(Array $data)
+ {
+ return ['list' => $this->getModules()];
+ }
+
+ public function ajaxGetPages(Array $data)
+ {
+ return ['list' => $this->getPages($data['module'])];
+ }
+}
--- /dev/null
+<?php
+
+class ScannerBase implements ScannerInterface {
+ public const LEFT = 1;
+ public const FLIP = 2;
+ public const RIGHT = 3;
+ protected static $scanner = false;
+
+ public static function getScanner()
+ {
+ if (static::$scanner === false) {
+ $ScannerClass = defined('DOCUMENT_FILES_SCANNER_CLASS') ? DOCUMENT_FILES_SCANNER_CLASS : 'ScannerBase';
+ static::$scanner = new $ScannerClass();
+
+ if (!is_a(static::$scanner, 'ScannerInterface'))
+ throw new Exception("DOCUMENT_FILES_SCANNER_CLASS does not implement ScannerInterface");
+ }
+
+ return static::$scanner;
+ }
+
+ public function hasScanner()
+ {
+ return false;
+ }
+
+ public function getResolutionList()
+ {
+ }
+
+ public function setResolution($id)
+ {
+ }
+
+ public function scanIntoPNM($outfile)
+ {
+ $scanimage = '/usr/bin/scanimage';
+
+ if (!file_exists($scanimage))
+ throw new Exception("Package sane-utils not installed");
+
+ if (!is_executable($scanimage))
+ throw new Exception("$scanimage not executable");
+
+ $cmd = sprintf("%s --format pnm > %s",
+ $scanimage,
+ escapeshellarg($outfile));
+
+ $this->execute($cmd);
+ }
+
+ public function convertPNMtoPNG($infile, $outfile)
+ {
+ $pnmtopng = '/usr/bin/pnmtopng';
+
+ if (!file_exists($pnmtopng))
+ throw new Exception("Package netpbm not installed");
+
+ if (!is_executable($pnmtopng))
+ throw new Exception("$pnmtopng not executable");
+
+ $cmd = sprintf("cat %s | %s > %s",
+ escapeshellarg($infile),
+ $pnmtopng,
+ escapeshellarg($outfile));
+
+ $this->execute($cmd);
+ }
+
+ public function rotatePNM($file, $direction)
+ {
+ $convert = '/usr/bin/convert';
+
+ if (!file_exists($convert))
+ throw new Exception("Package imagemagick not installed");
+
+ if (!is_executable($convert))
+ throw new Exception("$scanimage not executable");
+
+ switch (intval($direction)) {
+ case static::RIGHT: $degrees = 90; break;
+ case static::FLIP: $degrees = 180; break;
+ case static::LEFT: $degrees = 270; break;
+ default: throw new Exception("Invalid rotation command");
+ }
+
+ $cmd = sprintf("convert -rotate %d %s %s && mv -f %s %s",
+ $degrees,
+ escapeshellarg($file), escapeshellarg($file.'.pnm'),
+ escapeshellarg($file.'.pnm'), escapeshellarg($file));
+
+ $this->execute($cmd);
+ }
+
+ public function convertPNMtoPDF($infile, $outfile)
+ {
+ $pnmtops = '/usr/bin/pnmtops';
+ $pstopdf = '/usr/bin/ps2pdf';
+
+ if (!file_exists($pnmtops))
+ throw new Exception("Package netpbm not installed");
+
+ if (!is_executable($pnmtops))
+ throw new Exception("$pnmtops not executable");
+
+ if (!file_exists($pstopdf))
+ throw new Exception("Package ghostscript not installed");
+
+ if (!is_executable($pstopdf))
+ throw new Exception("$pnmtops not executable");
+
+ $cmd = sprintf("cat %s | %s | %s - > %s",
+ escapeshellarg($infile),
+ $pnmtops,
+ $pstopdf,
+ escapeshellarg($outfile));
+
+ $this->execute($cmd);
+ }
+
+ public function mergePDF(Array $infiles, $outfile)
+ {
+ $pdftk = '/usr/bin/pdftk';
+
+ if (!file_exists($pdftk))
+ throw new Exception("Package pdftk not installed");
+
+ if (!is_executable($pdftk))
+ throw new Exception("$pdftk not executable");
+
+ $cmd = $pdftk;
+ foreach ($infiles as $infile)
+ $cmd .= ' ' . escapeshellarg($infile);
+ $cmd .= ' cat output ' . escapeshellarg($outfile);
+
+ $this->execute($cmd);
+ }
+
+ /***********************************************************************/
+ protected function execute($cmd)
+ {
+ if (defined('DEBUG') && DEBUG == true)
+ debug($cmd);
+
+ system($cmd, $ret);
+
+ if ($ret != 0) {
+ $text = sprintf("Program execution resulted in exit code %d", $ret);
+ error_log($text);
+ error_log($cmd);
+ throw new Exception($text);
+ }
+
+ return true;
+ }
+
+ public function getPDF(Array $infiles)
+ {
+ }
+}
\ No newline at end of file
--- /dev/null
+<?php
+
+interface ScannerInterface {
+
+ public function hasScanner();
+
+ public function getResolutionList();
+
+ public function setResolution($id);
+
+ public function scanIntoPNM($outfile);
+
+ public function rotatePNM($file, $direction);
+
+ public function convertPNMtoPNG($infile, $outfile);
+
+ public function convertPNMtoPDF($infile, $outfile);
+
+ public function mergePDF(Array $infiles, $outfile);
+}
\ No newline at end of file
--- /dev/null
+<?php
+
+class Select {
+ protected $id = false;
+ protected $title = false;
+ protected $default = false;
+ protected $options = array();
+ protected $function = false;
+ protected $selected = false;
+
+ public function __construct(array $info)
+ {
+ if (!array_key_exists('function', $info))
+ throw new Exception('Property function missing');
+ else $this->function = $info['function'];
+
+ if (array_key_exists('id', $info)) $this->id = $info['id'];
+ if (array_key_exists('title', $info)) $this->title = $info['title'];
+ if (array_key_exists('default', $info)) $this->default = $info['default'];
+ if (array_key_exists('selected', $info)) $this->selected = $info['selected'];
+
+ if (array_key_exists('options', $info)) {
+ if (is_array($info['options'])) {
+ foreach ($info['options'] as $option) {
+ if (is_array($option))
+ $this->options[] = array($option[0], $option[1]);
+ else
+ $this->options[] = array($option, $option);
+ }
+ } elseif (is_string($info['options'])) {
+ $this->loadOptions($info['options']);
+ } else
+ throw new Exception('Unknown options type');
+ }
+ }
+
+ protected function loadOptions($sql)
+ {
+ global $db;
+ foreach ($db->fetchObjectList($sql) as $row)
+ $this->options[] = array($row->id, $row->text);
+ }
+
+ public function toString()
+ {
+ $attr = array();
+ if ($this->id) $attr[] = sprintf('id="%s"', $this->id);
+ if ($this->title) $attr[] = sprintf('title="%s"', $this->title);
+ if ($this->function) $attr[] = sprintf('onchange="%s(event, this)"', $this->function);
+
+ $code = array();
+ $code[] = sprintf('<select %s>', implode(' ', $attr));
+ if ($this->default) $code[] = sprintf('<option value="">%s</option>', $this->default);
+ foreach ($this->options as $option)
+ $code[] = sprintf('<option value="%s"%s>%s</option>',
+ $option[0],
+ $this->selected !== false && $this->selected == $option[0] ? ' selected' : '',
+ $option[1]);
+ $code[] = '</select>';
+
+ return implode('', $code);
+ }
+}
--- /dev/null
+<?php
+
+abstract class Singleton {
+ protected static $instance = false;
+
+ final public static function instance()
+ {
+ if (static::$instance === false) {
+ $className = get_called_class();
+ static::$instance = new $className();
+ }
+
+ return static::$instance;
+ }
+
+ final private function __construct() {
+ if (method_exists($this, '___construct'))
+ $this->___construct();
+ }
+}
--- /dev/null
+<?php
+
+class Styles extends Singleton {
+ protected static $instance = false;
+ protected $code = array();
+ protected $files = array();
+
+ public function add($code)
+ {
+ $this->code[] = $code;
+ }
+
+ public function file($path)
+ {
+ $hallinta = Hallinta::instance();
+
+ if (strpos($path, '/') === false) {
+ if (!file_exists($hallinta->basedir() . $path))
+ $path = sprintf('%s/%s/%s', HALLINTA_MODULEDIR, $hallinta->module(), $path);
+ }
+
+ $info = pathinfo($path);
+
+ $minfile = sprintf('%s%s/%s.min.%s', $hallinta->basedir(), $info['dirname'], $info['filename'], $info['extension']);
+ if (file_exists($minfile)) {
+ $origpath = $hallinta->basedir().$path;
+ if (filemtime($minfile) > filemtime($origpath))
+ $path = sprintf('%s/%s.min.%s', $info['dirname'], $info['filename'], $info['extension']);
+ }
+
+ $this->files[$path] = true;
+ }
+
+ public function toString()
+ {
+ $ret = '';
+ foreach (array_keys($this->files) as $file)
+ $ret .= sprintf('<link href="%s%s" rel="stylesheet" type="text/css">'."\n", Hallinta::instance()->urlbase(), $file);
+
+ if (count($this->code)) {
+ $ret .= '<style type="text/css">'."\n";
+ $ret .= implode("\n", $this->code);
+ $ret .= "</style>\n";
+ }
+
+ return $ret;
+ }
+
+}
--- /dev/null
+<?php
+
+class Template {
+ private $path;
+ private $data = array();
+
+ public static function render($name, Array $data)
+ {
+ $template = new Template($name);
+ $template->addData($data);
+ return $template->fillIn();
+ }
+
+ public function __construct($name)
+ {
+ if (strpos($name, '../') !== false)
+ throw new Exception("Template name contains illegal path component.");
+
+ $this->path = $this->getPath($name);
+
+ if ($this->path === false)
+ throw new Exception("Template $name not found in templates/ directory.");
+
+ if (!is_readable($this->path))
+ throw new Exception("Template $name not readable.");
+ }
+
+ public function id()
+ {
+ return $this->path;
+ }
+
+ protected function getPath($name)
+ {
+ $hallinta = Hallinta::instance();
+
+ $path = $hallinta->basedir() . 'masks/' . $hallinta->module() . '/templates/' . $name . '.phtml';
+ if (file_exists($path)) return $path;
+
+ $path = $hallinta->basedir() . 'templates/' . $name . '.phtml';
+ if (file_exists($path)) return $path;
+
+ return false;
+ }
+
+ public function add($name, $value)
+ {
+ $this->data[$name] = $value;
+ }
+
+ public function addData(Array $data)
+ {
+ foreach ($data as $name => $value)
+ $this->data[$name] = $value;
+ }
+
+ public function fillIn()
+ {
+ extract($this->data);
+
+ try {
+ ob_start();
+ include($this->path);
+ $text = ob_get_clean();
+ } catch (Exception $e) {
+ $text = ob_get_clean();
+ throw new Exception($e->getMessage());
+ } catch (Error $e) {
+ $text = ob_get_clean();
+ throw new Exception($e->getMessage());
+ }
+
+ return $text;
+ }
+
+ public function ajaxLoad(Array $data)
+ {
+ $this->addData($data);
+ return $this->fillIn();
+ }
+}
# define('SESSION_PATH', '/hallinta/');
# Cookie lifetime, defaults to 24 hours
# define('SESSION_LIFETIME', 60*60*2);
+# define('FAVICON', 'images/favicon.ico');
+
+# Use rewriting via .htaccess
+define('REWRITE_URLS', true);
# defaults to images/login.jpg
# define('LOGIN_IMG', 'images/login_neu.jpg');
define('MAIL_FROM_NAME', 'Infodrom Virka');
define('MAIL_ERROR', 'joey@finlandia.infodrom.org');
+# Copy a deleted row into <table>_deleted
define('DELETE_COPY', true);
+# Allow access to document scanner
+# define('DOCUMENT_FILES_SCANNER_CLASS', 'ScannerBase');
+
define('DEBUG', false);
-?>
+++ /dev/null
-@charset "UTF-8";
-
-/**
- * Horizontal CSS Drop-Down Menu Module
- *
- * @file dropdown.css
- * @package Dropdown
- * @version 0.7.1
- * @type Transitional
- * @stacks 597-599
- * @browsers Windows: IE6+, Opera7+, Firefox1+
- * Mac OS: Safari2+, Firefox2+
- *
- * @link http://www.lwis.net/
- * @copyright 2006-2008 Live Web Institute. All Rights Reserved.
- *
- * http://lwis.net/free-css-drop-down-menu/dropdown.simple.horizontal.html
- *
- */
-
-div.menu {
- padding-left: 20px;
- height: 27px;
-}
-
-ul.dropdown,
-ul.dropdown li,
-ul.dropdown ul {
- list-style: none;
- margin: 0;
- padding: 0;
-}
-
-ul.dropdown {
- position: relative;
- z-index: 597;
- float: left;
-}
-
-ul.dropdown li {
- float: left;
- line-height: 1.0em;
- vertical-align: middle;
- zoom: 1;
-}
-
-ul.dropdown li.hover,
-ul.dropdown li:hover {
- position: relative;
- z-index: 599;
- cursor: default;
-}
-
-ul.dropdown ul {
- visibility: hidden;
- position: absolute;
- top: 100%;
- left: 0;
- z-index: 598;
- width: 100%;
-}
-
-ul.dropdown ul li {
- float: none;
-}
-
-ul.dropdown ul ul {
- top: 1px;
- left: 99%;
-}
-
-ul.dropdown li:hover > ul {
- visibility: visible;
-}
-
-/* top menu items */
-ul.dropdown {
- font-weight: normal;
-}
-
-ul.dropdown li {
- padding: 7px 10px;
- border-style: solid;
- border-width: 1px 1px 1px 0;
- border-color: #fff #d9d9d9 #d9d9d9;
- background-color: #f6f6f6;
- color: #000;
-}
-
-ul.dropdown li.hover,
-ul.dropdown li:hover {
- background-color: #eee;
- color: #000;
-}
-
-ul.dropdown a:link,
-ul.dropdown a:visited { color: #000; text-decoration: none; }
-ul.dropdown a:hover { color: #000; }
-ul.dropdown a:active { color: #ffa500; }
-
-
-/* -- level mark -- */
-
-ul.dropdown ul {
- width: 150px;
- margin-top: 1px;
-}
-
-ul.dropdown ul li {
- font-weight: normal;
-}
-
<?php
require_once('init.php');
-require_once('lib/menu.php');
-$jsfiles = array('lib/json_parse.js');
-$jscode = '';
-$menu = menu();
+$styles = Styles::instance();
+$javascript = JavaScript::instance();
+
+$javascript->file('lib/jquery-2.1.0.min.js');
+$javascript->file('lib/jquery.event.ue.js');
+$javascript->file('lib/jquery.udraggable.js');
+
+$javascript->file('lib/json_parse.js');
+$styles->file('stylesheet.css');
+$styles->file('style.css');
+if (!empty($_SESSION['sys']['login']))
+ $styles->file('theme.php');
$html = process();
$debug = debug_info();
# max 8h
-$gcml = ini_get('session.gc_maxlifetime');
-$refresh = $gcml < 8*60*60 ? $gcml - 60 : 8*60*60 - 60;
-
+if (!empty($_SESSION['sys']['login'])) {
+ $gcml = ini_get('session.gc_maxlifetime');
+ $refresh = $gcml < 8*60*60 ? $gcml : 8*60*60;
+ $javascript->add(sprintf('Hallinta.autoLogoutTimeout = %d;', $refresh));
+ $javascript->add(sprintf('Hallinta.token = \'%s\';', $_SESSION['token']));
+ $javascript->add('Hallinta.baseURL = "'.Hallinta::instance()->urlbase().'";');
+ $javascript->add("Hallinta.menuBase = '".Hallinta::instance()->parentMenu()."';");
+}
?>
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="de">
<head>
<title><?=PAGETITLE?></title>
+<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
-<?=load_js($jsfiles, $jscode);?>
-<link href="stylesheet.css" rel="stylesheet" type="text/css">
-<link href="style.css" rel="stylesheet" type="text/css">
-<link href="dropdown.css" rel="stylesheet" type="text/css">
-<link href="theme.php" rel="stylesheet" type="text/css">
-<?=load_style($style);?>
+<?php if (defined('FAVICON')) printf('<link rel="shortcut icon" href="%s">', FAVICON); ?>
+<?=$styles->toString()?>
</head>
<body>
+<?php if (isset($refresh)): ?>
<div id="logout_refresh" style="display: none;"><?=$refresh?></div>
+<?php endif ?>
<div id="header">
-<h1><?=TITLE?></h1>
-<?=$menu; ?>
+<div id="actionbox"><?=Actions::instance()->toString()?></div>
+<div id="title"><?=TITLE?></div>
+<div id="titlesep"><?=strlen(Hallinta::instance()->getTitle())?'—':'';?></div>
+<div id="pagetitle"><?=Hallinta::instance()->getTitle()?></div>
</div>
<div class="content">
</div>
<?=$debug; ?>
+<?=$javascript->toString()?>
</body>
</html>
<?php
require_once('config.php');
+require_once('class/autoload.class.php');
if (!defined('SESSION_PATH')) define('SESSION_PATH', '/');
if (!defined('SESSION_LIFETIME')) define('SESSION_LIFETIME', 60*60*56);
session_set_cookie_params(SESSION_LIFETIME, SESSION_PATH);
session_start();
+define('HALLINTA_MODULEDIR', 'masks');
+
require_once('lib/general.php');
+check_empty_session();
db_connect();
check_session();
-
-?>
+var Hallinta = {
+ /**
+ * Options
+ *
+ * closeDialogAfterInsert [bool] close details dialog after inserting a new item
+ * clearDialogAfterInsert [bool] clear details dialog after inserting a new item
+ * closeDialogAfterSave [bool] close details dialog after saving a item
+ * clearDialogAfterSave [bool] clear details dialog after saving a item
+ * closeDialogAfterDelete [bool] close details dialog after deleting a item
+ * fetchItemAfterInsert [bool] fetch recently inserted item after inserting
+ *
+ * pageInit [function()] Function to be called after page has been loaded
+ * postLoadForm [function(data)] Function to be called after edit form has been loaded
+ * postFetch [function(data)] Function to be called after fetching an item
+ * preSave [function()] Function to be called before saving an item
+ * postSave [function(data)] Function to be called after saving an item
+ * preInsert [function()] Function to be called before inserting a new item
+ * postInsert [function(data)] Function to be called after inserting a new item
+ * preDelete [function()] Function to be called before deleting an item
+ * postDelete [function(data)] Function to be called after deleting an item
+ * drillDown [function(e,id)] Function to be called after clicking on a cell
+ */
+ closeDialogAfterInsert: true,
+ clearDialogAfterInsert: true,
+ closeDialogAfterSave: true,
+ clearDialogAfterSave: true,
+ closeDialogAfterDelete: true,
+ fetchItemAfterInsert: false,
+ pageInit: false,
+ postLoadForm: false,
+ postFetch: false,
+ preSave: false,
+ postSave: false,
+ preInsert: false,
+ postInsert: false,
+ postDelete: false,
+ drillDown: false,
+ /* End options */
+ grid: false,
+ mainId: false,
+ pageSource: false,
+ baseURL: '',
+ menuBase: '',
+ autoLogoutTimeout: 15*60,
+ autoLogoutDialog: false,
+ isMobile: false,
+ canEdit: false,
+ editDialog: false,
+ editFormCheck: {},
+ gridMenuColumns: {},
+ seconds: {},
+ messageDiv: false,
+ menuDialog: false
+};
/*
* Small AJAX framework
*/
+function ajax_request_response(data, oncomplete)
+{
+ if (typeof data.error == 'string') {
+ if (typeof data.errormsg == 'string')
+ error(data.errormsg);
+ else
+ error(data.error);
+ Hallinta.hideMsg();
+ alert(data.error);
+
+ if (typeof data.logout != 'undefined' && data.logout == true)
+ window.location.href = 'index.php?logout=true&auto=true';
+ } else {
+ if (typeof oncomplete == 'function')
+ oncomplete(data);
+ }
+
+ reset_logout();
+}
+
function ajax_request_callback(req)
{
if (req.readyState == 4 && req.status == 200) {
var data = json_parse(req.responseText);
- if (data && typeof data.error == 'string') {
- if (typeof data.errormsg == 'string')
- error(data.errormsg);
- else
- error(data.error);
- alert(data.error);
- if (typeof data.logout != 'undefined' && data.logout == true)
- window.location.href = 'index.php?logout=true';
- } else if (req.oncomplete)
- req.oncomplete(data);
+ if (data) {
+ ajax_request_response(data, req.oncomplete)
+ } else {
+ alert("Unparsable response");
+ }
}
}
function ajax_request(func,params,oncomplete)
{
+ if (func.indexOf('/') > -1) {
+ if (params === null || params == '') {
+ params = {route: func};
+ if (Hallinta.token) params['token'] = Hallinta.token;
+ if (Hallinta.pageSource) params['source'] = Hallinta.pageSource;
+ } else if (typeof params == 'object') {
+ params['route'] = func;
+ if (Hallinta.token) params['token'] = Hallinta.token;
+ if (Hallinta.pageSource) params['source'] = Hallinta.pageSource;
+ } else {
+ params = 'route='+func+'&'+params
+ if (Hallinta.token) params += '&token=' + Hallinta.token;
+ if (Hallinta.pageSource) params += '&source=' + Hallinta.pageSource;
+ }
+
+ $.ajax({
+ method: 'POST',
+ url: Hallinta.baseURL + 'ajax/ajax.php',
+ data: params,
+ dataType: 'json'
+ }).done(function(data){
+ ajax_request_response(data, oncomplete);
+ });
+
+ return;
+ }
+
var req = new XMLHttpRequest();
if (!req) return;
- var params = 'func=' + func + '&' + params;
- req.open ("POST", 'ajax/ajax.php');
+ var reqParams = 'func=' + func;
+ if (Hallinta.token) reqParams += '&token=' + Hallinta.token;
+ if (Hallinta.pageSource) reqParams += '&source=' + Hallinta.pageSource;
+ if (typeof params == 'string') {
+ if (params && params.length) reqParams +='&' + params;
+ } else if (typeof params == 'object') {
+ for (name in params)
+ reqParams += '&' + name + '=' + escape(params[name]);
+ }
+
+ req.open ("POST", Hallinta.baseURL + 'ajax/ajax.php');
req.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
- req.setRequestHeader("Content-length", params.length);
- req.setRequestHeader("Connection", "close");
req.onreadystatechange = function() { ajax_request_callback(req); }
if (typeof oncomplete == 'function')
req.oncomplete = oncomplete;
- req.send(params);
+ req.send(reqParams);
info('');
- reset_logout();
}
-var logout_timer = false;
-window.setTimeout(reset_logout, 4000);
+function ajax_callback(name,params,oncomplete)
+{
+ if (typeof params == 'string' && params.length)
+ params = 'callback=' + name + '&' + params;
+ else if (params !== null && typeof params == 'object')
+ params['callback'] = name;
+ else
+ params = 'callback=' + name;
+
+ ajax_request('function', params, oncomplete);
+}
+
+Hallinta.popupMobilePosition = function(popup) {
+ if (!Hallinta.isMobile) return;
+
+ $(popup.contentDiv).parents('div.ricoShadow').css('top', '25px')
+};
+
+Hallinta.openEditDialog = function() {
+ Hallinta.editDialog.openPopup();
+ focus_first_element('#form_edit');
+};
+
+Hallinta.enhanceGridOptions = function(options) {
+ if (typeof options.onscroll == 'string') {
+ if (options.onscroll == 'gridOnScroll')
+ options.onscroll = gridOnScroll;
+ else error('Unknown options.onscroll');
+ }
+ if (typeof options.click == 'string') {
+ options.click = eval(options.click);
+ }
+
+ for (var i=0; i < options.columnSpecs.length; i++) {
+ if (typeof options.columnSpecs[i].control == 'string')
+ options.columnSpecs[i].control = eval(options.columnSpecs[i].control);
+ }
+};
+
+Hallinta.fixGridColumns = function(gridname) {
+ $('div#grid_' + gridname + '_outerDiv tr.ricoLG_hdg div.ricoLG_col').each(function(i,e){
+ if (typeof $(e).attr('style') !== 'undefined') {
+ var width = $(e).css('width');
+ width = parseInt(width.substr(0,width.length-2),10);
+ $(e).css('width', (width+1).toString());
+ }
+ });
+
+ $('div#grid_' + gridname + '_scrollContainerDiv .ricoLG_scrollTabDiv div.ricoLG_col').each(function(i,e){
+ if (typeof $(e).attr('style') !== 'undefined') {
+ var width = $(e).css('width');
+ width = parseInt(width.substr(0,width.length-2),10);
+ $(e).css('width', (width+1).toString());
+ }
+ });
+};
+
+Hallinta.loadMainGridCallback = function(json) {
+ Hallinta.showMsg('Die Liste wird aufgebaut...');
+ $('div#div_grid').html(json.html);
+ Hallinta.enhanceGridOptions(json.options);
+ Hallinta.grid = new Rico.LiveGrid('grid_'+json.gridname,
+ new Rico.Buffer.AjaxSQL(Hallinta.baseURL + 'ajax/ricoXMLquery.php'),
+ json.options);
+ Hallinta.grid.menu = new Rico.GridMenu();
+ Hallinta.grid.edit = new Rico.TableEdit(Hallinta.grid);
+ Hallinta.grid.edit.responseHandler = function(xhr) { Hallinta.gridEditHandler(Hallinta.grid, xhr); };
+ Hallinta.grid.menu.options.dataMenuHandlerOriginal = Hallinta.grid.menu.options.dataMenuHandler;
+ Hallinta.grid.menu.options.dataMenuHandler = Hallinta.dataMenuHandler;
+ Hallinta.fixGridColumns(json.gridname);
+ Hallinta.hideMsg();
+};
+
+Hallinta.loadMainGrid = function() {
+ Hallinta.showMsg('Die Liste wird geladen...');
+ ajax_request('grid', 'name=main', Hallinta.loadMainGridCallback);
+};
+
+Hallinta.openSecondaryGridCallback = function(json) {
+ Hallinta.enhanceGridOptions(json.options);
+ Hallinta.seconds[json.name] = {};
+ var window_options = {};
+ if (typeof json.width !== 'undefined')
+ window_options['width'] = json.width + 'px';
+ Hallinta.seconds[json.name].popup = new Rico.Window(json.title, window_options);
+ Rico.addClass(Hallinta.seconds[json.name].popup.container, 'gridPopup');
+
+ $(Hallinta.seconds[json.name].popup.contentDiv).html(json.html);
+ Hallinta.seconds[json.name].popup.openPopup();
+
+ var p = 'second_id=' + (Hallinta.mainId ? Hallinta.mainId : 0);
+ Hallinta.seconds[json.name].grid = new Rico.LiveGrid('grid_'+json.gridname,
+ new Rico.Buffer.AjaxSQL(Hallinta.baseURL + 'ajax/ricoXMLquery.php',
+ {requestParameters: [p]}),
+ json.options);
+ Hallinta.seconds[json.name].grid.menu = new Rico.GridMenu();
+ Hallinta.seconds[json.name].edit = new Rico.TableEdit(Hallinta.seconds[json.name].grid);
+ Hallinta.seconds[json.name].edit.responseHandler = function(xhr) { Hallinta.gridEditHandler(Hallinta.seconds[json.name].grid, xhr); };
+ Hallinta.seconds[json.name].grid.menu.options.dataMenuHandlerOriginal = Hallinta.seconds[json.name].grid.menu.options.dataMenuHandler;
+ Hallinta.seconds[json.name].grid.menu.options.dataMenuHandler = Hallinta.dataMenuHandler;
+ Hallinta.fixGridColumns(json.gridname);
+
+ Hallinta.seconds[json.name].popup.centerPopup();
+};
+
+Hallinta.openSecondaryGrid = function(event, name) {
+ if (typeof Hallinta.seconds[name] == 'undefined') {
+ ajax_request('grid', 'name='+name, Hallinta.openSecondaryGridCallback);
+ } else {
+ var p = 'second_id=' + (Hallinta.mainId ? Hallinta.mainId : 0);
+ Hallinta.seconds[name].grid.buffer.options.requestParameters = [p];
+ grid_update(Hallinta.seconds[name].grid);
+
+ Hallinta.seconds[name].popup.openPopup();
+ }
+};
+
+Hallinta.registerGridMenu = function(name, col, options) {
+ if (typeof Hallinta.gridMenuColumns[name] != 'object')
+ Hallinta.gridMenuColumns[name] = {};
+ Hallinta.gridMenuColumns[name][col] = options;
+};
+
+Hallinta.gridEditHandler = function(grid, xhr)
+{
+ var data = $.parseJSON(xhr.responseText);
+
+ $('#'+grid.tableId+'_editResponseDiv').hide();
+ if (typeof data.error == 'string')
+ Hallinta.showMsg('ERROR: ' + data.error, {timeout: 10});
+ else
+ Hallinta.showMsg('Item successfully saved', {timeout: 2});
+
+ grid_update(grid);
+}
+
+/**
+ * Hallinta.showMsg(text, opts)
+ *
+ * Options:
+ * timeout Seconds until auto-closing message window
+*/
+Hallinta.showMsg = function(text, opts) {
+ var options = {
+ timeout: false
+ };
+ if (typeof options == 'undefined') options = {};
+ Rico.extend(options, opts);
+
+ if (!Hallinta.messageDiv) {
+ Hallinta.messageDiv = $('<div>');
+ Hallinta.messageDiv.attr('id', 'message');
+ Hallinta.messageDiv.hide();
+ $(document.body).append(Hallinta.messageDiv);
+ }
+
+ Hallinta.messageDiv.text(text);
+ Hallinta.messageDiv.show();
+
+ Hallinta.messageDiv.css('position','absolute')
+ .css('top', ((window.innerHeight / 2) - (Hallinta.messageDiv.height() / 2)) + 'px')
+ .css('left', ((window.innerWidth / 2) - (Hallinta.messageDiv.width() / 2)) + 'px');
+
+ if (options.timeout)
+ setTimeout(Hallinta.hideMsg, options.timeout * 1000);
+
+ return false;
+};
+
+Hallinta.hideMsg = function() {
+ if (!Hallinta.messageDiv) return;
+ Hallinta.messageDiv.hide();
+};
+
+function page_init()
+{
+ if ($('div#div_grid').length) Hallinta.loadMainGrid();
+ if (Hallinta.canEdit) setTimeout(load_edit_form, 500);
+ if (typeof Hallinta.pageInit == 'function')
+ Hallinta.pageInit();
+}
+
+function seconds2time(seconds)
+{
+ var mins = Math.floor(seconds/60);
+ var secs = (seconds - mins*60).toString();
+ secs = (secs.length == 1 ? '0' : '') + secs;
+ return mins + ':' + secs;
+}
+
+function do_logout()
+{
+ window.location.href = 'index.php?logout=true&auto=true';
+ return false;
+}
+
+function prevent_logout()
+{
+ Hallinta.skipLogout = true;
+ ajax_request('menu', 'base=');
+ Hallinta.autoLogoutDialog.closePopup();
+}
+
+function prepare_logout()
+{
+ var centerDialog = false;
+ if (!Hallinta.autoLogoutDialog) {
+ Hallinta.autoLogoutDialog = new Rico.Window('Automatische Abmeldung', {zIndex: 100});
+ Rico.addClass(Hallinta.autoLogoutDialog.container, 'logoutDialog');
+ centerDialog = true;;
+ }
+
+ Hallinta.autoLogoutTimer = 60;
+
+ $(Hallinta.autoLogoutDialog.contentDiv).html([
+ '<div style="padding:10px">',
+ '<p>Keine Aktivität seit '+seconds2time(Hallinta.autoLogoutTimeout)+' Minuten.</p>',
+ '<p>Sie werden in <span id="autoLogoutTimer">'+seconds2time(Hallinta.autoLogoutTimer)+'</span> automatisch abgemeldet.</p>',
+ '<div style="text-align:center;">',
+ '<button style="padding:3px" onclick="return do_logout()">Abmelden</button>',
+ ' ',
+ '<button style="padding:3px" onclick="return prevent_logout()">Fortfahren</button>',
+ '</div>',
+ '</div>'
+ ].join(''));
+
+ if (centerDialog)
+ Hallinta.autoLogoutDialog.centerPopup();
+ else
+ Hallinta.autoLogoutDialog.openPopup();
+
+ Hallinta.skipLogout = false;
+ prepare_logout_timer();
+}
+
+function prepare_logout_timer()
+{
+ if (!Hallinta.autoLogoutTimer) {
+ do_logout();
+ return;
+ }
+
+ if (Hallinta.skipLogout)
+ return;
+
+ $('#autoLogoutTimer').text(seconds2time(Hallinta.autoLogoutTimer));
+ Hallinta.autoLogoutTimer--;
+ window.setTimeout(prepare_logout_timer, 1000);
+}
+
function reset_logout()
{
- if (logout_timer)
- window.clearTimeout(logout_timer);
+ if (Hallinta.autoLogoutTimeoutTimer)
+ window.clearTimeout(Hallinta.autoLogoutTimeoutTimer);
- logout_timer = window.setTimeout(function() {
- window.location.href = 'index.php?logout=true';
- }, parseInt(document.getElementById('logout_refresh').innerHTML)*1000);
+ Hallinta.autoLogoutTimeoutTimer = window.setTimeout(function() {
+ prepare_logout();
+ }, (Hallinta.autoLogoutTimeout-60)*1000);
}
+window.setTimeout(reset_logout,1000);
var edit_hidden = false;
-var form_file_name = null;
-var form_file_content = null;
+var form_file_content = {};
function form_file_change_onloadstart(e)
{
var button = document.getElementById('button_insert');
info('');
}
-function form_file_change_onload(e)
+function form_file_change_onload(id,e)
{
- form_file_content = new Uint8ClampedArray(e.target.result);
+ form_file_content[id] = new Uint8ClampedArray(e.target.result);
}
function form_file_change(e)
{
var file = e.target.files[0];
var reader = new FileReader();
- reader.onload = form_file_change_onload;
+ reader.onload = form_file_change_onload.bind(this,this.id);
reader.onloadend = form_file_change_onloadend;
reader.onloadstart = form_file_change_onloadstart;
reader.readAsArrayBuffer(file);
- form_file_filename = file.name;
}
-function ajax_form_submit(func,form,oncomplete)
+function build_multipart_data(func,formname,boundary)
{
- var boundary = "---------------------------" + (new Date).getTime();
var CRLF = "\r\n";
- var req = new XMLHttpRequest();
- if (!req) return;
var parts = new Array();
+ var part = 'Content-Disposition: form-data; ';
+ part += 'name="source"' + CRLF + CRLF;
+ part += Hallinta.pageSource + CRLF;
+ parts.push(part);
+
+ var part = 'Content-Disposition: form-data; ';
+ part += 'name="token"' + CRLF + CRLF;
+ part += Hallinta.token + CRLF;
+ parts.push(part);
+
if (func && func.length) {
var part = 'Content-Disposition: form-data; ';
part += 'name="func"' + CRLF + CRLF;
parts.push(part);
}
- for (var i=0; i < form.childNodes.length; i++) {
+ var req = new XMLHttpRequest();
+ if (!req) return;
+ if (typeof req.sendAsBinary == 'undefined' && typeof req.send == 'function')
+ var func_use_send = '1';
+ else
+ var func_use_send = '0';
+
+ var part = 'Content-Disposition: form-data; ';
+ part += 'name="func_use_send"' + CRLF + CRLF;
+ part += func_use_send + CRLF;
+ parts.push(part);
+ part = '';
+
+ if (!$(formname).length) {
+ error('Formular nicht gefunden');
+ alert('Formular nicht gefunden');
+ return;
+ }
+
+ var childNodes = $(formname).get(0).childNodes;
+ for (var i=0; i < childNodes.length; i++) {
var part = '';
- var element = form.childNodes[i];
+ var element = childNodes[i];
var fieldName = element.name;
if (element.nodeName.toLowerCase() == 'input' &&
- element.type.toLowerCase() == 'file') {
+ element.type.toLowerCase() == 'file' &&
+ element.files.length) {
if (typeof element.files[0].getAsBinary != 'function' &&
typeof window.FileReader == 'undefined') {
var binary = element.files[0].getAsBinary();
var filename = element.files[0].fileName;
} catch(err) {
- if (form_file_content) {
+ if (form_file_content[element.id]) {
var binary = '';
- for (var j=0; j < form_file_content.length; j++)
- binary += String.fromCharCode(form_file_content[j]);
+ for (var j=0; j < form_file_content[element.id].length; j++)
+ binary += String.fromCharCode(form_file_content[element.id][j]);
- var filename = form_file_filename;
+ var filename = element.files[0].name;
} else {
error('Problem beim Lesen der Datei');
alert("Problem beim Lesen der Datei\n" +
- element.files[0].fileName + "\n" +
+ element.files[0].name + "\n" +
"Eventuell stimmt das Encoding nicht\n" +
"Die Daten wurden nicht gespeichert");
return;
parts.push(part);
}
+ if (typeof filename == 'string')
+ Hallinta.showMsg('Die Daten werden gespeichert. Das kann etwas dauern...');
+
var params = "--" + boundary + CRLF;
params += parts.join("--" + boundary + CRLF);
params += "--" + boundary + "--" + CRLF;
- req.open ("POST", 'ajax/ajax.php');
+ return params;
+}
+
+function ajax_form_submit(func,formname,oncomplete)
+{
+ var boundary = "---------------------------" + (new Date).getTime();
+ var params = build_multipart_data(func,formname,boundary);
+
+ var req = new XMLHttpRequest();
+ if (!req) return;
+
+ req.open ("POST", Hallinta.baseURL + 'ajax/ajax.php');
req.setRequestHeader("Content-Type", "multipart/form-data; boundary=" + boundary);
- req.setRequestHeader("Connection", "close");
req.onreadystatechange = function() { ajax_request_callback(req); }
if (typeof oncomplete == 'function')
req.oncomplete = oncomplete;
- req.sendAsBinary(params);
-
- info('');
- form_clear(form);
+ if (typeof req.sendAsBinary == 'function')
+ req.sendAsBinary(params);
+ else if (typeof req.send == 'function')
+ req.send(params);
+ else
+ error('No send function available in XMLHttpRequest');
}
function info(msg)
{
- var status = document.getElementById('status');
- if (!status) return;
+ var status = $('#status');
+ if (!status.length) return;
- status.innerHTML = msg;
- status.className = 'status_ok';
+ status.text(msg).attr('class', 'status_ok');
}
function error(msg)
{
- var status = document.getElementById('status');
- if (!status) return;
+ var status = $('#status');
+ if (!status.length) return;
- status.innerHTML = msg;
- status.className = 'status_error';
+ status.text(msg).attr('class', 'status_error');
}
function button_enable(id)
{
- var button = document.getElementById(id);
- if (!button) return;
+ var button = $('#'+id);
+ if (!button.length) return;
- button.className = '';
- button.disabled = false;
+ button.removeClass('disabled').attr('disabled', false);
}
function button_disable(id)
{
- var button = document.getElementById(id);
- if (!button) return;
+ var button = $('#'+id);
+ if (!button.length) return;
- button.className = 'disabled';
- button.disabled = true;
+ button.addClass('disabled').attr('disabled', true);
}
function set_value(id, value)
if (obj.type.toLowerCase() == 'checkbox') {
if (value) obj.checked = true;
else obj.checked = false;
+ obj.value = 'on';
} else if (obj.type.toLowerCase() == 'file')
return;
else
/*
* Form functions
*/
-function form_clear(form)
+function form_allow_toggle(id)
{
- if (!form) return;
+ $(id+' label.toggle').click(function(e){
+ var name = $(this).attr('for');
+ if (!name) return;
+ if ($('#'+name).css('display') == 'none')
+ $('#'+name).css('display', '');
+ else
+ $('#'+name).css('display', 'none');
+ });
+}
- for (var i=0; i < form.childNodes.length; i++)
- if (form.childNodes[i].nodeName.toLowerCase() == 'input'
- && (form.childNodes[i].type.toLowerCase() == 'password' ||
- form.childNodes[i].type.toLowerCase() == 'file'))
- form.childNodes[i].value = '';
+function load_edit_form()
+{
+ if (Hallinta.editDialog) return;
- var id = document.getElementById('edit_id');
- if (id) id.value = '';
+ Hallinta.editDialog = new Rico.Window('Datensatz bearbeiten', {zIndex: 10});
+ Rico.addClass(Hallinta.editDialog.container, 'editDialog');
+
+ ajax_request('edit', '', load_edit_form_callback);
}
-var form_first_use = true;
-function form_init()
+function load_edit_form_callback(data)
{
- var form = document.getElementById('form_edit');
+ $(Hallinta.editDialog.contentDiv).html(data.content);
+ Hallinta.editFormCheck = data.checks;
+ form_init('#form_edit');
+ form_allow_toggle('#form_edit');
+ $('#edit_id').val('');
+ button_disable('button_save');
+ button_disable('button_delete');
+
+ Hallinta.editDialog.centerPopup();
+ Hallinta.popupMobilePosition(Hallinta.editDialog);
+ Hallinta.editDialog.closePopup();
+
+ if (typeof Hallinta.postLoadForm == 'function')
+ Hallinta.postLoadForm(data);
+}
- if (!form) return;
+function focus_first_element(name)
+{
+ $(name+' input:visible,'+name+' select:visible,'+name+' textarea:visible').first().focus();
+}
- form_clear(form);
+function enable_file_upload(name)
+{
+ $(name+' input[type="file"]').change(function(e){
+ $(name+' input[data-for="'+$(this).attr('id')+'"]').val(e.target.files[0].name);
+ });
+ $(name+' input.file-upload').click(function(e){
+ $(name+' #'+$(this).attr('data-for')).click();
+ });
+ $(name+' input.file-upload').keyup(function(e){
+ if (e.keyCode == 32)
+ $(name+' #'+$(this).attr('data-for')).click();
+ });
+}
- var elem = form.findFirstElement();
- if (elem) elem.activate();
+function form_clear(name)
+{
+ $(name+' input,'+name+' textarea').each(function(i,e){
+ $(e).val('');
+ });
+
+ $(name+' select').each(function(i,e){
+ if ($(e).find('option').length == 2 && $(e).find('option[value=""]').length == 1) {
+ $(e).val($(e).find('option:nth-child(2)').attr('value'));
+ } else {
+ $(e).val('');
+ }
+ });
+}
+
+var form_first_use = true;
+function form_init(formname)
+{
+ if (!$(formname).length) return;
+
+ form_clear(formname);
+ $(formname + ' input[type="file"]').each(function(i,e){
+ $(e).change(form_file_change);
+ });
+ enable_file_upload(formname);
+ focus_first_element(formname);
}
function form_elem_error(elem,text)
{
+ if (typeof elem == 'string')
+ elem = document.getElementById(elem);
+ if (!elem) return;
elem.style.borderColor = 'red';
elem.style.borderWidth = '1px';
elem.style.borderStyle = 'solid';
function form_elem_ok(elem)
{
+ if (typeof elem == 'string')
+ elem = document.getElementById(elem);
+ if (!elem) return;
elem.style.borderColor = '';
elem.style.borderWidth = '';
elem.style.borderStyle = '';
function form_reset_errors()
{
- for (name in form_check) {
- var elem = document.getElementById('edit_' + name);
- form_elem_ok(elem);
+ for (name in Hallinta.editFormCheck) {
+ form_elem_ok('edit_' + name);
}
}
var form_check_regexp = {
number: /^\d+$/,
decimal: /^\d*([,\.]\d+)?$/,
+ time: /^(\d\d?:\d\d?(:\d\d?)?)$/,
date: /^(\d\d?\.\d\d?\.[1-9]\d\d\d)|([1-9]\d\d\d-\d\d?-\d\d?)$/
};
function form_elem_onblur(e)
{
- var first_use = form_first_use;
- form_first_use = false;
-
- var elem = document.getElementById('form_edit').findFirstElement();
- if (first_use && elem == e.originalTarget && !e.originalTarget.length) return;
-
- if (form_check[e.originalTarget.name]) {
- var error = form_elem_check(e.originalTarget, form_check[e.originalTarget.name]);
+ if (Hallinta.editFormCheck[e.originalTarget.name]) {
+ var error = form_elem_check(e.originalTarget, Hallinta.editFormCheck[e.originalTarget.name]);
if (error.length)
form_elem_error(e.originalTarget, error);
+ else
+ info('');
}
}
function form_checks(form)
{
var errors = '';
- for (name in form_check) {
+ for (name in Hallinta.editFormCheck) {
var elem = document.getElementById('edit_' + name);
- var error = form_elem_check(elem, form_check[name]);
+ var error = form_elem_check(elem, Hallinta.editFormCheck[name]);
if (error.length) {
form_elem_error(elem, error);
errors += '. ' + error + "\n";
if (typeof empty == 'undefined') empty = 0;
+ if (typeof obj.options == 'undefined') return;
+
obj.options.length = empty;
for (var i=0; i < options.length; i++)
obj.options[empty+i] = new Option(options[i].text,options[i].id,false,false);
}
-var pre_save = false;
-var pre_insert = false;
-var post_save = function() { grid_update(grid); }
-var post_delete = function() { grid_update(grid); }
-
function save_callback(data)
{
info('Datensatz gespeichert');
+ Hallinta.hideMsg();
+
+ if (Hallinta.grid)
+ grid_update(Hallinta.grid);
- if (typeof post_save == 'function')
- post_save();
+ if ($('#form_edit').length) {
+ $('#edit_id').val('');
+ button_disable('button_save');
+ button_disable('button_delete');
+ focus_first_element('#form_edit')
+ }
- var form = document.getElementById('form_edit');
+ if (data.func == 'save') {
+ if (typeof Hallinta.postSave == 'function')
+ Hallinta.postSave(data);
- if (!form) return;
+ if (Hallinta.clearDialogAfterSave)
+ form_clear('#form_edit');
- form_clear(form);
- Form.focusFirstElement(form);
+ if (Hallinta.closeDialogAfterSave)
+ Hallinta.editDialog.closePopup();
+ }
+
+ if (data.func == 'insert') {
+ if (typeof Hallinta.postInsert == 'function')
+ Hallinta.postInsert(data);
+
+ if (Hallinta.fetchItemAfterInsert) {
+ ajax_request('fetch', 'id=' + data.id, fetch_callback);
+ form_reset_errors();
+ }
+
+ if (Hallinta.clearDialogAfterInsert)
+ form_clear('#form_edit');
+
+ if (Hallinta.closeDialogAfterInsert)
+ Hallinta.editDialog.closePopup();
+ }
+
+ button_enable('button_insert');
}
function delete_callback(data)
{
info('Datensatz gelöscht');
- if (typeof post_delete == 'function')
- post_delete();
+ if (Hallinta.grid)
+ grid_update(Hallinta.grid);
+
+ if (Hallinta.closeDialogAfterDelete)
+ Hallinta.editDialog.closePopup();
+
+ if (typeof Hallinta.postDelete == 'function')
+ Hallinta.postDelete(data);
}
function form_save(obj)
{
- var id = document.getElementById('edit_id');
-
- if (!id.value.length)
+ if (!$('#edit_id').val().length)
return form_insert(obj);
if (!form_checks(obj.form))
info('');
- if (typeof pre_save == 'function')
- if (!pre_save())
+ if (typeof Hallinta.preSave == 'function')
+ if (!Hallinta.preSave())
return false;
-
- ajax_request('save', Form.serialize(obj.form), save_callback);
+ Hallinta.showMsg('Die Daten werden gespeichert...');
+ ajax_request('save', $('#form_edit').serialize(), save_callback);
return false;
}
info('');
- if (typeof pre_insert == 'function')
- if (!pre_insert())
+ button_disable('button_insert');
+ if (typeof Hallinta.preInsert == 'function')
+ if (!Hallinta.preInsert()) {
+ button_enable('button_insert');
return false;
+ }
+
+ Hallinta.showMsg('Die Daten werden gespeichert...');
+ ajax_form_submit('insert', '#form_edit', save_callback);
+
+ info('');
+ $('#edit_id').val('');
+ button_disable('button_save');
+ button_disable('button_delete');
- ajax_form_submit('insert', obj.form, save_callback);
return false;
}
if (!id.value.length) return false;
- var source = document.getElementById('edit_source');
+ if (typeof Hallinta.preDelete == 'function')
+ if (!Hallinta.preDelete())
+ return false;
+
info('');
- var params = 'id='+id.value + '&source='+source.value;
- ajax_request('delete', params, delete_callback);
+ ajax_request('delete', 'id='+id.value, delete_callback);
return false;
}
function fetch_callback(data)
{
- for (var id in data)
- set_value('edit_'+id, data[id]);
+ for (var id in data) {
+ if (data[id] === null)
+ set_value('edit_'+id, '');
+ else
+ set_value('edit_'+id, data[id]);
+ }
- var status = document.getElementById('form_status');
- status.innerHTML = 'Geändert: ' + data.sys_edit + ' von ' + data.sys_user;
+ $('#form_status').text(data.sys_edit + ' (' + data.sys_user + ')');
+ button_enable('button_save');
+ button_enable('button_delete');
- var form = document.getElementById('form_edit');
- Form.focusFirstElement(form);
+ Hallinta.editDialog.openPopup();
+ focus_first_element('#form_edit');
+
+ if (typeof Hallinta.postFetch == 'function')
+ Hallinta.postFetch(data);
+}
+
+/*
+ * Template functions
+ */
+function load_template(name, payload, callback)
+{
+ if (payload === null || (typeof payload == 'string' && payload == '')) {
+ payload ='template=' + name;
+ } else if (typeof payload == 'string') {
+ payload +='&template=' + name;
+ } else if (typeof payload == 'object') {
+ payload['template'] = name;
+ } else {
+ error('Template '+name+' error');
+ return;
+ }
+
+ ajax_request('template', payload, function(data){
+ if (typeof callback == 'function') {
+ callback(name, data);
+ }
+ });
}
/*
*/
function gridDrillDown(e)
{
- if (e.originalTarget && e.originalTarget.target && e.originalTarget.target == '_top')
+ if (e.target && !$(e.target).hasClass('ricoLG_cell') &&
+ !(e.target.id && e.target.id.search('_desc_') != -1))
+ return
+
+ if (e.originalTarget && e.originalTarget.target && e.originalTarget.target == '_new')
return;
if (e.originalTarget &&
(!e.originalTarget.className || (e.originalTarget.className.split('_'))[0] !== 'ricoLG'))
return;
+ Hallinta.mainId = false;
var id = 0; // Column 0 contains ID
- var row = grid.edit.drillDown(e,0,0);
- var cell = grid.columns[id].cell(row);
+ var row = Hallinta.grid.edit.drillDown(e,0,0);
+ var cell = Hallinta.grid.columns[id].cell(row);
if (!cell) return;
var value = cell.innerHTML;
if (!value.length || value == ' ') return;
+ Hallinta.mainId = value;
if (document.getElementById('details')) {
- var params = 'source=' + grid.tableId.substr(5) + '&id=' + value;
+ var params = 'source=' + Hallinta.grid.tableId.substr(5) + '&id=' + Hallinta.mainId;
ajax_request('details', params, details_callback);
}
- if (document.getElementById('form_edit')) {
- var status = document.getElementById('form_status');
- if (status.style.display == '') {
- var params = 'source=' + grid.tableId.substr(5) + '&id=' + value;
- ajax_request('fetch', params, fetch_callback);
- form_reset_errors();
-
- if (edit_hidden) edit_show();
- }
+ if (Hallinta.canEdit) {
+ ajax_request('fetch', 'id=' + Hallinta.mainId, fetch_callback);
+ form_reset_errors();
}
- if (second_visible()) {
- second.buffer.options.requestParameters = ['second_id=' + value];
- grid_update(second);
+ for (var id in Hallinta.seconds) {
+ if (Hallinta.seconds[id].popup.visible()) {
+ Hallinta.seconds[id].grid.buffer.options.requestParameters = ['second_id=' + Hallinta.mainId];
+ grid_update(Hallinta.seconds[id].grid);
+ }
}
- if (typeof drilldown == 'function')
- drilldown(e,value);
+ if (typeof Hallinta.drillDown == 'function')
+ Hallinta.drillDown(e, Hallinta.mainId);
}
var grid_offset = 0;
var max = Math.min(offset+grid.pageSize, grid.buffer.totalRows);
var info = document.getElementById('info_' + grid.tableId);
info.innerHTML = 'Datensatz ' + (offset+1) + ' - ' + max + ' von ' + grid.buffer.totalRows;
+ reset_logout();
}
/* Update an existing grid
$(grid.filterId(c)).options.length = 1;
var options = {};
- Object.extend(options, grid.buffer.ajaxOptions);
+ Rico.extend(options, grid.buffer.ajaxOptions);
var colnum = typeof(fmt.filterCol)=='number' ? fmt.filterCol : c;
options.parameters = 'id='+grid.tableId+'&distinct='+colnum;
}
options.onComplete = grid.filterValuesUpdate.bind(grid,c);
- new Ajax.Request(grid.buffer.dataSource, options);
+ new Rico.Request(grid.buffer.dataSource, options);
}
}
function grid_cell_save(id,col,value)
{
- var source = document.getElementById('source');
-
- if (!source) return false;
-
- var parms = 'source=' + source.innerHTML;
- parms += '&callback=cellsave';
+ var parms = 'callback=cellsave';
parms += '&id=' + id;
parms += '&column=' + col;
parms += '&value=' + value;
- ajax_request('function', parms, false);
+ ajax_request('function', parms, function(data){
+ if (typeof Hallinta.gridMenuColumns['main'][col]['callback'] == 'function')
+ Hallinta.gridMenuColumns['main'][col]['callback'](data);
+ });
}
function grid_cell_value()
grid_cell_save(this.grid.buffer.getCell(bufRow,0), this.col, this.value);
}
-function grid_dataMenuHandler(grid,row,col,onBlankRow)
-{
- var default_menu = true;
+Hallinta.dataMenuHandler = function(grid,row,col,onBlankRow) {
+ var defaultMenu = true;
- if (grid_column_edit[col] &&
- typeof grid_column_edit[col].default_menu !== 'undefined' &&
- grid_column_edit[col].default_menu == false)
- default_menu = false;
+ if (grid == Hallinta.grid)
+ var name = 'main';
+ else {
+ var name = grid.tableId.substring(Hallinta.grid.tableId.length+2).split('__')[0];
+ }
- if (default_menu && typeof grid.menu.options.dataMenuHandlerOriginal == 'function') {
+ if (typeof Hallinta.gridMenuColumns[name] == 'object' &&
+ typeof Hallinta.gridMenuColumns[name][col] == 'object' &&
+ typeof Hallinta.gridMenuColumns[name][col].defaultMenu != 'undefined' &&
+ Hallinta.gridMenuColumns[name][col].defaultMenu == false)
+ defaultMenu = false;
+
+ if (defaultMenu && typeof grid.menu.options.dataMenuHandlerOriginal == 'function') {
grid.menu.options.dataMenuHandlerOriginal(grid,row,col,onBlankRow);
- grid.menu.div.style.width = '17em';
+ grid.menu.content.style.width = '17em';
}
- if (grid_column_edit[col]) {
+ if (typeof Hallinta.gridMenuColumns[name] == 'object' &&
+ typeof Hallinta.gridMenuColumns[name][col] == 'object') {
var submenu;
- if (default_menu) {
- var submenu = new Rico.Menu(grid_column_edit[col].width);
+ if (defaultMenu) {
+ submenu = new Rico.Menu(Hallinta.gridMenuColumns[name][col].width);
submenu.createDiv();
} else
submenu = grid.menu;
- for (i=0; i < grid_column_edit[col].values.length; i++)
- submenu.addMenuItem(grid_column_edit[col].values[i][0],
+ for (var i=0; i < Hallinta.gridMenuColumns[name][col].values.length; i++)
+ submenu.addMenuItem(Hallinta.gridMenuColumns[name][col].values[i][0],
grid_cell_value.bind({grid: grid, row: row, col: col,
- visible: grid_column_edit[col].values[i][1],
- value: grid_column_edit[col].values[i][2]}));
+ visible: Hallinta.gridMenuColumns[name][col].values[i][1],
+ value: Hallinta.gridMenuColumns[name][col].values[i][2]}));
- if (!default_menu && typeof grid_column_edit[col].width !== 'undefined')
- grid.menu.div.style.width = grid_column_edit[col].width;
+ if (!defaultMenu && typeof Hallinta.gridMenuColumns[name][col].width !== 'undefined')
+ grid.menu.content.style.width = Hallinta.gridMenuColumns[name][col].width;
- if (default_menu)
+ if (defaultMenu)
grid.menu.addSubMenuItem('Wert setzen', submenu, true);
}
- if (default_menu)
+ if (defaultMenu)
return true;
else
return false;
-}
+};
var calendars = new Array();
function calendar_callback(value)
calendars[name] = new Rico.CalendarControl('calendar_'+name,
{startAt: 1,
dateFmt: 'dd.mm.yyyy',
+ zIndex: 20,
showWeekNumber: 1});
- calendars[name].atLoad();
calendars[name].returnValue = calendar_callback;
- RicoUtil.positionCtlOverIcon(calendars[name].container,input);
+ Rico.positionCtlOverIcon(calendars[name].container,input);
calendars[name].open(input.value);
calendars[name].input = input;
} else {
- if (Element.visible(calendars[name].container))
+ if ($('#calendar_'+name+':visible').length) {
calendars[name].close();
- else
+ } else {
+ Rico.positionCtlOverIcon(calendars[name].container,input);
calendars[name].open(input.value);
+ }
}
- Event.stop(event);
}
-function edit_hide()
-{
- var col_edit = document.getElementById("column_edit");
- var col_grid = document.getElementById("column_grid");
- col_edit.style.display = 'none';
- col_grid.style.width = '100%';
-
- edit_hidden = true;
-
- grid.sizeDivs();
- grid.resizeWindow();
-}
-
-function edit_show()
+/*
+ * Menu
+ */
+function display_menu(event, base)
{
- var col_edit = document.getElementById("column_edit");
- var col_grid = document.getElementById("column_grid");
- col_edit.style.display = '';
- col_grid.style.width = '';
-
- edit_hidden = false;
-
- grid.sizeDivs();
- grid.resizeWindow();
-}
+ if (!Hallinta.menuDialog) {
+ Hallinta.menuDialog = new Rico.Window('Menü', {width: 'auto', zIndex: 100});
+ Rico.addClass(Hallinta.menuDialog.container, 'menuDialog');
+ }
-function resize_grids()
-{
- var div_grid = document.getElementById('div_grid');
- var info = document.getElementById('info_'+second.tableId);
- var height = RicoUtil.windowHeight() - (info.offsetTop - div_grid.offsetTop) - 60;
- div_grid.style.height = height + 'px';
- grid.resizeWindow();
-}
+ var page = '';
+ if (typeof base == 'undefined') {
+ base = Hallinta.menuBase;
+ if (Hallinta.pageSource != 'start')
+ page = Hallinta.pageSource;
+ }
-function second_visible()
-{
- if (typeof second == 'undefined') return false;
- var div_second = document.getElementById('second');
- return div_second.style.display == '';
+ ajax_request('menu', 'base='+base+'&page='+page, display_menu_callback);
+ return false;
}
-var div_grid_height = '';
-function second_toggle()
+function display_menu_callback(data)
{
- var div_grid = document.getElementById('div_grid');
- var div_second = document.getElementById('second');
- var toggle_icon = document.getElementById('icon_toggle');
+ var centerDialog = true;
+ if ($(Hallinta.menuDialog.contentDiv).text().length)
+ centerDialog = false;
- if (second_visible()) {
- div_grid_height = div_grid.style.height;
- div_second.style.display = 'none';
+ $(Hallinta.menuDialog.titleDiv).find('.ricoTitleSpan').text(data.title);
+ $(Hallinta.menuDialog.contentDiv).html(data.menu);
- var height = RicoUtil.windowHeight() - div_grid.offsetTop - 10;
- div_grid.style.height = height + 'px';
- grid.resizeWindow();
- toggle_icon.style.display = '';
- } else {
- div_grid.style.height = div_grid_height;
- div_second.style.display = '';
- grid.resizeWindow();
- second.clearRows();
- second.resizeWindow();
- toggle_icon.style.display = 'none';
- }
+ if (centerDialog) {
+ var pos = $('#btn_menu').offset();
+ Hallinta.menuDialog.openPopup(pos.left,pos.top+20);
+ Hallinta.menuDialog.openPopup(pos.left-5-$(Hallinta.menuDialog.contentDiv).width(),pos.top+20);
+ } else
+ Hallinta.menuDialog.openPopup();
}
require_once('db.php');
-function __autoload($class)
-{
- $found = false;
-
- if (empty($_GLOBALS['module'])) {
- if (!empty($_REQUEST['source'])) $name = sanitise_filename($_REQUEST['source']);
- if (!empty($_GET['msak'])) $name = sanitise_filename($_GET['mask']);
- list($module,$fname) = explode('__', $name);
- if (!empty($module)) $_GLOBALS['module'] = $module;
- }
-
- if (!$found &&
- !empty($_REQUEST['source']) &&
- !empty($_GLOBALS['module']) &&
- is_dir($_SESSION['sys']['basedir'].'masks/'.$_GLOBALS['module'].'/class') &&
- file_exists($_SESSION['sys']['basedir'].'masks/'.$_GLOBALS['module'].'/class/'.strtolower($class).'.class.php')) {
- include_once($_SESSION['sys']['basedir'].'masks/'.$_GLOBALS['module'].'/class/'.strtolower($class).'.class.php');
- $found = true;
- }
-
- if (!$found &&
- is_dir($_SESSION['sys']['basedir'].'class') &&
- file_exists($_SESSION['sys']['basedir'].'class/'.strtolower($class).'.class.php')) {
- include_once($_SESSION['sys']['basedir'].'class/'.strtolower($class).'.class.php');
- $found = true;
- }
-
- if (!$found) {
- $text = sprintf('Class %s not found%',
- $class,
- defined(MODULNAME) ? ' in module ' . MODULNAME : '');
- die($text);
- }
-}
-
function passwd($login,$pass)
{
return md5(md5($pass).$login);
function format_ajax($data)
{
header('Content-type: application/json; charset=UTF-8');
- echo json_encode($data);
+
+ $return = json_encode($data);
+
+ if ($return === false) {
+ error_log('Return ' . var_export($data,true));
+ $return = json_encode(array('status' => false, 'error' => 'Rückgabedaten können nicht kodiert werden.'));
+ }
+
+ echo $return;
exit;
}
+function ajax_error($text)
+{
+ format_ajax(array('error' => $text));
+}
+
function format_xml($errmsg)
{
header("Cache-Control: no-cache");
exit;
}
-function check_permissions($name)
+function check_permissions()
{
- global $db;
+ $menu = new MenuItem();
- $parts = explode('__', $name);
- $form = $parts[0] . '|' . $parts[1];
+ if (!$menu->hasPermission()) {
+ $hallinta = Hallinta::instance();
+ error_log(sprintf('Unauthorised access to %s/%s', $hallinta->module(), $hallinta->page()));
+ return false;
+ }
- $sql = sprintf("SELECT count(*) AS count FROM sys_mask "
- . "JOIN sys_menu ON sys_mask.menu = sys_menu.id "
- . "JOIN sys_group_mask ON sys_mask.id = sys_group_mask.mask "
- . "WHERE sys_group_mask.gid = %d AND fname = %s",
- $_SESSION['sys']['group'], $db->quote($form));
+ return true;
+}
- $count = $db->fetchValue($sql);
+function check_empty_session()
+{
+ if (!empty($_SESSION['sys']['login'])) return;
- if ($count === false) {
- error_log('Unauthorised access to ' . $form);
- return false;
- }
+ if (substr($_SERVER["SCRIPT_FILENAME"],-10) == '/index.php' &&
+ !empty($_POST['login']) && !empty($_POST['passwd']))
+ return;
- if ($count == 0) {
- error_log('Unauthorised access to ' . $form);
- return false;
- }
+ if (isset($_GET['login']) && $_GET['login'] == 'true') return;
- return true;
+ /* table data */
+ if (substr($_SERVER["SCRIPT_FILENAME"],-17) == '/ricoXMLquery.php' &&
+ !empty($_GET['id']) && substr($_GET['id'],0,5) == 'grid_')
+ format_xml("No permission to access data.\nNo active session found.\nYou may need to re-login.");
+
+ /* table connections */
+ if (substr($_SERVER["SCRIPT_FILENAME"],-25) == '/ricoUpdateConnection.php' &&
+ !empty($_GET['id']) && substr($_GET['id'],0,5) == 'grid_')
+ format_ajax(array('error' => 'No permission to access data'));
+
+ /* ajax calls */
+ if (substr($_SERVER["SCRIPT_FILENAME"],-9) == '/ajax.php' &&
+ !empty($_POST['source']))
+ format_ajax(array('error' => "No permission to access data.\nNo active session found.\nYou need to re-login.",
+ 'logout' => true));
+
+ header(sprintf('Location: %s?login=true', Hallinta::instance()->urlbase()));
+ echo "No permission to access data.\nNo active session found.\nYou need to re-login.";
+ exit();
}
function check_session()
/* table data */
if (substr($_SERVER["SCRIPT_FILENAME"],-17) == '/ricoXMLquery.php' &&
!empty($_GET['id']) && substr($_GET['id'],0,5) == 'grid_') {
- if (check_permissions(substr($_GET['id'],5)))
+ if (check_permissions())
return true;
else {
if (empty($_SESSION['sys']['login']))
/* table connections */
if (substr($_SERVER["SCRIPT_FILENAME"],-25) == '/ricoUpdateConnection.php' &&
!empty($_GET['id']) && substr($_GET['id'],0,5) == 'grid_') {
- if (check_permissions(substr($_GET['id'],5)))
+ if (check_permissions())
return true;
else
format_ajax(array('error' => 'No permission to access data'));
/* ajax calls */
if (substr($_SERVER["SCRIPT_FILENAME"],-9) == '/ajax.php' &&
+ $_POST['func'] != 'menu' &&
!empty($_POST['source'])) {
- if (check_permissions($_POST['source']))
+ if (check_permissions())
return true;
else {
if (empty($_SESSION['sys']['login']))
}
if (!empty($_SESSION['sys']['login']) && !empty($_GET['logout'])) {
+ if (empty($_GET['auto']))
+ clear_page_log();
+ $_SESSION = array();
session_destroy();
- header('Location: ./?login=true');
+ header(sprintf('Location: %s?login=true', Hallinta::instance()->urlbase()));
exit();
}
!empty($_POST['login']) && !empty($_POST['passwd'])) {
require_once('lib/login.php');
if (check_passwd()) {
- header('Location: ./');
+ if (strlen($_SESSION['sys']['page'])) {
+ $parts = explode('__', $_SESSION['sys']['page']);
+ $url = sprintf("%s%s/%s", Hallinta::instance()->urlbase(), $parts[0], $parts[1]);
+ } else {
+ $url = Hallinta::instance()->urlbase();
+ }
+ header(sprintf('Location: %s', $url));
exit();
}
}
if (empty($_SESSION['sys']['login']) && empty($_GET['login'])) {
- header('Location: ./?login=true');
+ header(sprintf('Location: %s?login=true', Hallinta::instance()->urlbase()));
exit();
}
/* regular mask */
if (!empty($_GET['mask'])) {
- if (check_permissions($_GET['mask']))
+ if (check_permissions())
return true;
else {
header('Location: ./');
return str_replace('./','x',$file);
}
-function load_mask($name)
+function load_mask($module, $page)
{
global $mask;
- global $jscode;
- global $style;
+ global $javascript;
+ global $styles;
- $name = sanitise_filename($name);
- list($module,$fname) = explode('__', $name);
$_SESSION['module'] = $module;
+ $_SESSION['mask'] = $page;
- $file = $_SESSION['sys']['basedir'] . 'masks/' . $module . '/' . $fname . '.php';
+ $file = sprintf('%s%s/%s/%s.php', $_SESSION['sys']['basedir'], HALLINTA_MODULEDIR,
+ $module, sanitise_filename($page));
if (!file_exists($file))
return false;
return true;
}
-function load_js($jsfiles, $jscode)
+function grid_definition($id)
{
- $ret = '';
- foreach ($jsfiles as $file)
- $ret .= sprintf('<script type="text/javascript" src="%s"></script>'."\n", $file);
-
- if (!empty($jscode))
- $ret .= sprintf('<script type="text/javascript">'."\n%s\n</script>\n", implode("\n",$jscode));
+ global $mask;
+ $hallinta = Hallinta::instance();
+ $maskName = substr($id,5);
+ $secondName = false;
+
+ if (substr($maskName, -8) == '__second') {
+ $maskName = substr($maskName,0,-8);
+ $secondName = substr($maskName,strrpos($maskName, '__')+2);
+ $maskName = substr($maskName,0,strrpos($maskName, '__'));
+ }
- return $ret;
+ load_mask($hallinta->module(), $hallinta->page());
+ if ($secondName)
+ return $mask['second'][$secondName];
+ return $mask;
}
-function load_style($style)
+function load_start()
{
- $ret = '';
- if (!empty($style))
- $ret .= sprintf('<style type="text/css">'."\n%s\n</style>\n", implode("\n",$style));
+ global $styles;
+ global $javascript;
- return $ret;
+ $styles->file('lib/rico3/ricoClient/css/rico.css');
+ $styles->file('lib/rico3/ui-cupertino/jquery-ui.css');
+ $styles->file('lib/rico3/ui-cupertino/jquery-ui_hallinta.css');
+
+ $javascript->file('lib/rico3/ricoClient/js/rico2jqu.js');
+ $javascript->file('lib/rico3/minsrc/rico.js');
+ $javascript->file('lib/rico3/minsrc/ricoLocale_en.js');
+ $javascript->file('lib/rico3/minsrc/ricoUI.js');
+ $javascript->file('lib/rico3/ricoClient/js/ricoThemeroller.js');
+ $javascript->add('Hallinta.pageSource = "start";');
+ $javascript->add(sprintf('Hallinta.isMobile = %s;', Hallinta::instance()->isMobile()?'true':'false'));
+
+ $ret = '';
+ $fname = $_SESSION['sys']['basedir'] . 'data/misc/start.js';
+ if (file_exists($fname))
+ $javascript->onLoad(file_get_contents($fname));
+ $fname = $_SESSION['sys']['basedir'] . 'data/misc/start.html';
+ if (file_exists($fname))
+ return file_get_contents($fname);
}
function process()
{
+ $hallinta = Hallinta::instance();
+
if (!empty($_GET['login'])) {
require_once('lib/login.php');
return mask_login();
}
- if (!empty($_GET['mask'])) {
- require_once('lib/mask.php');
- return mask($_GET['mask']);
+ Javascript::instance()->file('lib/functions.js');
+ Actions::instance()->addLink(new Link(array('id' => 'btn_menu',
+ 'icon' => $hallinta->urlbase().'images/icons/menu.png',
+ 'title' => 'Menü',
+ 'function' => 'display_menu')));
+
+ $module = $hallinta->module();
+ if (!is_null($module)) {
+ if ($hallinta->isMobile()) {
+ Actions::instance()->addLink(new Link(array('id' => 'btn_columns',
+ 'icon' => $hallinta->urlbase().'images/icons/liste.gif',
+ 'title' => 'Spalten',
+ 'function' => 'Hallinta.grid.chooseColumns')));
+ }
+
+ save_page_log();
+ require_once('lib/mask.php');
+ return mask($module, $hallinta->page());
}
- $ret = '';
- $fname = $_SESSION['sys']['basedir'] . 'data/misc/start.html';
- if (file_exists($fname))
- return file_get_contents($fname);
-
+ $ret = load_start();
return $ret;
}
+$debug_file = false;
+function debug($name, $text=false)
+{
+ global $debug_file;
+
+ if (!$debug_file) {
+ $dir = $_SESSION['sys']['basedir'].'/archive/debug';
+ if (!is_dir($dir))
+ if (!@mkdir($path, 0770))
+ return;
+
+ $debug_file = fopen($dir.'/debug.log', 'a');
+ }
+
+ if ($text === false) {
+ $text = $name;
+ $name = false;
+ }
+
+ if (!is_string($text))
+ $text = var_export($text,true);
+
+ if ($debug_file) {
+ fputs($debug_file, sprintf("%s %s: %s%s\n", date('Y-m-d'), $_SESSION['sys']['login'],
+ $name === false ? '' : $name . ' = ',
+ $text));
+ }
+}
+
function debug_log($text)
{
global $debug_info;
return $ret;
}
-function grid_lookup_sql($table,$id,$text)
+function grid_lookup_sql($table,$id,$text,$map=false)
{
global $db;
- if (empty($_GET['mask'])) return;
+ if (empty($_POST['func'])) return;
+ if ($_POST['func'] != 'grid') return;
- $sql = "SELECT $id,$text FROM $table ORDER BY $text";
+ $sql = "SELECT $id,$text AS text FROM $table ORDER BY text";
$sth = $db->query($sql);
$result = array();
+ if (is_array($map))
+ foreach ($map as $k => $v)
+ $result[] = sprintf("%d: '%s'", $k, $v);
while ($row = $sth->fetch())
- $result[] = sprintf("%d: '%s'", $row[$id], $row[$text]);
+ $result[] = sprintf("%d: '%s'", $row[$id], $row['text']);
return '{' . implode(', ', $result) . '}';
}
if (array_key_exists('where', $mask)) $_SESSION['grid_' . $name] .= ' WHERE ' . $mask['where'];
}
-?>
+function date_iso2german($date)
+{
+ if (empty($date) || $date=='0000-00-00') return "";
+ list($jahr, $monat, $tag) = explode("-", $date);
+ if ($jahr<100) $jahr += 2000;
+
+ return sprintf("%02d.%02d.%04d", $tag, $monat, $jahr);
+}
+
+function date_german2iso($date)
+{
+ if ($date=='00.00.0000') return "";
+ list($tag, $monat, $jahr) = explode(".", $date);
+ if ($jahr<100) $jahr += 2000;
+
+ return sprintf("%04d-%02d-%02d", $jahr, $monat, $tag);
+}
+
+function save_page_log()
+{
+ global $db;
+
+ $hallinta = Hallinta::instance();
+
+ $menu = new MenuItem();
+ if ($menu->isRegular()) {
+ $sql = sprintf("UPDATE sys_user SET page = '%s__%s' WHERE id = %d",
+ $hallinta->module(), $hallinta->page(),
+ $_SESSION['sys']['uid']);
+
+ $db->query($sql);
+ }
+}
+
+function clear_page_log()
+{
+ global $db;
+
+ $sql = sprintf("UPDATE sys_user SET page = NULL WHERE id = %d", $_SESSION['sys']['uid']);
+
+ $db->query($sql);
+}
\ No newline at end of file
--- /dev/null
+/*! jQuery v2.1.0 | (c) 2005, 2014 jQuery Foundation, Inc. | jquery.org/license */
+!function(a,b){"object"==typeof module&&"object"==typeof module.exports?module.exports=a.document?b(a,!0):function(a){if(!a.document)throw new Error("jQuery requires a window with a document");return b(a)}:b(a)}("undefined"!=typeof window?window:this,function(a,b){var c=[],d=c.slice,e=c.concat,f=c.push,g=c.indexOf,h={},i=h.toString,j=h.hasOwnProperty,k="".trim,l={},m=a.document,n="2.1.0",o=function(a,b){return new o.fn.init(a,b)},p=/^-ms-/,q=/-([\da-z])/gi,r=function(a,b){return b.toUpperCase()};o.fn=o.prototype={jquery:n,constructor:o,selector:"",length:0,toArray:function(){return d.call(this)},get:function(a){return null!=a?0>a?this[a+this.length]:this[a]:d.call(this)},pushStack:function(a){var b=o.merge(this.constructor(),a);return b.prevObject=this,b.context=this.context,b},each:function(a,b){return o.each(this,a,b)},map:function(a){return this.pushStack(o.map(this,function(b,c){return a.call(b,c,b)}))},slice:function(){return this.pushStack(d.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(a){var b=this.length,c=+a+(0>a?b:0);return this.pushStack(c>=0&&b>c?[this[c]]:[])},end:function(){return this.prevObject||this.constructor(null)},push:f,sort:c.sort,splice:c.splice},o.extend=o.fn.extend=function(){var a,b,c,d,e,f,g=arguments[0]||{},h=1,i=arguments.length,j=!1;for("boolean"==typeof g&&(j=g,g=arguments[h]||{},h++),"object"==typeof g||o.isFunction(g)||(g={}),h===i&&(g=this,h--);i>h;h++)if(null!=(a=arguments[h]))for(b in a)c=g[b],d=a[b],g!==d&&(j&&d&&(o.isPlainObject(d)||(e=o.isArray(d)))?(e?(e=!1,f=c&&o.isArray(c)?c:[]):f=c&&o.isPlainObject(c)?c:{},g[b]=o.extend(j,f,d)):void 0!==d&&(g[b]=d));return g},o.extend({expando:"jQuery"+(n+Math.random()).replace(/\D/g,""),isReady:!0,error:function(a){throw new Error(a)},noop:function(){},isFunction:function(a){return"function"===o.type(a)},isArray:Array.isArray,isWindow:function(a){return null!=a&&a===a.window},isNumeric:function(a){return a-parseFloat(a)>=0},isPlainObject:function(a){if("object"!==o.type(a)||a.nodeType||o.isWindow(a))return!1;try{if(a.constructor&&!j.call(a.constructor.prototype,"isPrototypeOf"))return!1}catch(b){return!1}return!0},isEmptyObject:function(a){var b;for(b in a)return!1;return!0},type:function(a){return null==a?a+"":"object"==typeof a||"function"==typeof a?h[i.call(a)]||"object":typeof a},globalEval:function(a){var b,c=eval;a=o.trim(a),a&&(1===a.indexOf("use strict")?(b=m.createElement("script"),b.text=a,m.head.appendChild(b).parentNode.removeChild(b)):c(a))},camelCase:function(a){return a.replace(p,"ms-").replace(q,r)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toLowerCase()===b.toLowerCase()},each:function(a,b,c){var d,e=0,f=a.length,g=s(a);if(c){if(g){for(;f>e;e++)if(d=b.apply(a[e],c),d===!1)break}else for(e in a)if(d=b.apply(a[e],c),d===!1)break}else if(g){for(;f>e;e++)if(d=b.call(a[e],e,a[e]),d===!1)break}else for(e in a)if(d=b.call(a[e],e,a[e]),d===!1)break;return a},trim:function(a){return null==a?"":k.call(a)},makeArray:function(a,b){var c=b||[];return null!=a&&(s(Object(a))?o.merge(c,"string"==typeof a?[a]:a):f.call(c,a)),c},inArray:function(a,b,c){return null==b?-1:g.call(b,a,c)},merge:function(a,b){for(var c=+b.length,d=0,e=a.length;c>d;d++)a[e++]=b[d];return a.length=e,a},grep:function(a,b,c){for(var d,e=[],f=0,g=a.length,h=!c;g>f;f++)d=!b(a[f],f),d!==h&&e.push(a[f]);return e},map:function(a,b,c){var d,f=0,g=a.length,h=s(a),i=[];if(h)for(;g>f;f++)d=b(a[f],f,c),null!=d&&i.push(d);else for(f in a)d=b(a[f],f,c),null!=d&&i.push(d);return e.apply([],i)},guid:1,proxy:function(a,b){var c,e,f;return"string"==typeof b&&(c=a[b],b=a,a=c),o.isFunction(a)?(e=d.call(arguments,2),f=function(){return a.apply(b||this,e.concat(d.call(arguments)))},f.guid=a.guid=a.guid||o.guid++,f):void 0},now:Date.now,support:l}),o.each("Boolean Number String Function Array Date RegExp Object Error".split(" "),function(a,b){h["[object "+b+"]"]=b.toLowerCase()});function s(a){var b=a.length,c=o.type(a);return"function"===c||o.isWindow(a)?!1:1===a.nodeType&&b?!0:"array"===c||0===b||"number"==typeof b&&b>0&&b-1 in a}var t=function(a){var b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s="sizzle"+-new Date,t=a.document,u=0,v=0,w=eb(),x=eb(),y=eb(),z=function(a,b){return a===b&&(j=!0),0},A="undefined",B=1<<31,C={}.hasOwnProperty,D=[],E=D.pop,F=D.push,G=D.push,H=D.slice,I=D.indexOf||function(a){for(var b=0,c=this.length;c>b;b++)if(this[b]===a)return b;return-1},J="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",K="[\\x20\\t\\r\\n\\f]",L="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",M=L.replace("w","w#"),N="\\["+K+"*("+L+")"+K+"*(?:([*^$|!~]?=)"+K+"*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|("+M+")|)|)"+K+"*\\]",O=":("+L+")(?:\\(((['\"])((?:\\\\.|[^\\\\])*?)\\3|((?:\\\\.|[^\\\\()[\\]]|"+N.replace(3,8)+")*)|.*)\\)|)",P=new RegExp("^"+K+"+|((?:^|[^\\\\])(?:\\\\.)*)"+K+"+$","g"),Q=new RegExp("^"+K+"*,"+K+"*"),R=new RegExp("^"+K+"*([>+~]|"+K+")"+K+"*"),S=new RegExp("="+K+"*([^\\]'\"]*?)"+K+"*\\]","g"),T=new RegExp(O),U=new RegExp("^"+M+"$"),V={ID:new RegExp("^#("+L+")"),CLASS:new RegExp("^\\.("+L+")"),TAG:new RegExp("^("+L.replace("w","w*")+")"),ATTR:new RegExp("^"+N),PSEUDO:new RegExp("^"+O),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+K+"*(even|odd|(([+-]|)(\\d*)n|)"+K+"*(?:([+-]|)"+K+"*(\\d+)|))"+K+"*\\)|)","i"),bool:new RegExp("^(?:"+J+")$","i"),needsContext:new RegExp("^"+K+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+K+"*((?:-\\d)?\\d*)"+K+"*\\)|)(?=[^-]|$)","i")},W=/^(?:input|select|textarea|button)$/i,X=/^h\d$/i,Y=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,$=/[+~]/,_=/'|\\/g,ab=new RegExp("\\\\([\\da-f]{1,6}"+K+"?|("+K+")|.)","ig"),bb=function(a,b,c){var d="0x"+b-65536;return d!==d||c?b:0>d?String.fromCharCode(d+65536):String.fromCharCode(d>>10|55296,1023&d|56320)};try{G.apply(D=H.call(t.childNodes),t.childNodes),D[t.childNodes.length].nodeType}catch(cb){G={apply:D.length?function(a,b){F.apply(a,H.call(b))}:function(a,b){var c=a.length,d=0;while(a[c++]=b[d++]);a.length=c-1}}}function db(a,b,d,e){var f,g,h,i,j,m,p,q,u,v;if((b?b.ownerDocument||b:t)!==l&&k(b),b=b||l,d=d||[],!a||"string"!=typeof a)return d;if(1!==(i=b.nodeType)&&9!==i)return[];if(n&&!e){if(f=Z.exec(a))if(h=f[1]){if(9===i){if(g=b.getElementById(h),!g||!g.parentNode)return d;if(g.id===h)return d.push(g),d}else if(b.ownerDocument&&(g=b.ownerDocument.getElementById(h))&&r(b,g)&&g.id===h)return d.push(g),d}else{if(f[2])return G.apply(d,b.getElementsByTagName(a)),d;if((h=f[3])&&c.getElementsByClassName&&b.getElementsByClassName)return G.apply(d,b.getElementsByClassName(h)),d}if(c.qsa&&(!o||!o.test(a))){if(q=p=s,u=b,v=9===i&&a,1===i&&"object"!==b.nodeName.toLowerCase()){m=ob(a),(p=b.getAttribute("id"))?q=p.replace(_,"\\$&"):b.setAttribute("id",q),q="[id='"+q+"'] ",j=m.length;while(j--)m[j]=q+pb(m[j]);u=$.test(a)&&mb(b.parentNode)||b,v=m.join(",")}if(v)try{return G.apply(d,u.querySelectorAll(v)),d}catch(w){}finally{p||b.removeAttribute("id")}}}return xb(a.replace(P,"$1"),b,d,e)}function eb(){var a=[];function b(c,e){return a.push(c+" ")>d.cacheLength&&delete b[a.shift()],b[c+" "]=e}return b}function fb(a){return a[s]=!0,a}function gb(a){var b=l.createElement("div");try{return!!a(b)}catch(c){return!1}finally{b.parentNode&&b.parentNode.removeChild(b),b=null}}function hb(a,b){var c=a.split("|"),e=a.length;while(e--)d.attrHandle[c[e]]=b}function ib(a,b){var c=b&&a,d=c&&1===a.nodeType&&1===b.nodeType&&(~b.sourceIndex||B)-(~a.sourceIndex||B);if(d)return d;if(c)while(c=c.nextSibling)if(c===b)return-1;return a?1:-1}function jb(a){return function(b){var c=b.nodeName.toLowerCase();return"input"===c&&b.type===a}}function kb(a){return function(b){var c=b.nodeName.toLowerCase();return("input"===c||"button"===c)&&b.type===a}}function lb(a){return fb(function(b){return b=+b,fb(function(c,d){var e,f=a([],c.length,b),g=f.length;while(g--)c[e=f[g]]&&(c[e]=!(d[e]=c[e]))})})}function mb(a){return a&&typeof a.getElementsByTagName!==A&&a}c=db.support={},f=db.isXML=function(a){var b=a&&(a.ownerDocument||a).documentElement;return b?"HTML"!==b.nodeName:!1},k=db.setDocument=function(a){var b,e=a?a.ownerDocument||a:t,g=e.defaultView;return e!==l&&9===e.nodeType&&e.documentElement?(l=e,m=e.documentElement,n=!f(e),g&&g!==g.top&&(g.addEventListener?g.addEventListener("unload",function(){k()},!1):g.attachEvent&&g.attachEvent("onunload",function(){k()})),c.attributes=gb(function(a){return a.className="i",!a.getAttribute("className")}),c.getElementsByTagName=gb(function(a){return a.appendChild(e.createComment("")),!a.getElementsByTagName("*").length}),c.getElementsByClassName=Y.test(e.getElementsByClassName)&&gb(function(a){return a.innerHTML="<div class='a'></div><div class='a i'></div>",a.firstChild.className="i",2===a.getElementsByClassName("i").length}),c.getById=gb(function(a){return m.appendChild(a).id=s,!e.getElementsByName||!e.getElementsByName(s).length}),c.getById?(d.find.ID=function(a,b){if(typeof b.getElementById!==A&&n){var c=b.getElementById(a);return c&&c.parentNode?[c]:[]}},d.filter.ID=function(a){var b=a.replace(ab,bb);return function(a){return a.getAttribute("id")===b}}):(delete d.find.ID,d.filter.ID=function(a){var b=a.replace(ab,bb);return function(a){var c=typeof a.getAttributeNode!==A&&a.getAttributeNode("id");return c&&c.value===b}}),d.find.TAG=c.getElementsByTagName?function(a,b){return typeof b.getElementsByTagName!==A?b.getElementsByTagName(a):void 0}:function(a,b){var c,d=[],e=0,f=b.getElementsByTagName(a);if("*"===a){while(c=f[e++])1===c.nodeType&&d.push(c);return d}return f},d.find.CLASS=c.getElementsByClassName&&function(a,b){return typeof b.getElementsByClassName!==A&&n?b.getElementsByClassName(a):void 0},p=[],o=[],(c.qsa=Y.test(e.querySelectorAll))&&(gb(function(a){a.innerHTML="<select t=''><option selected=''></option></select>",a.querySelectorAll("[t^='']").length&&o.push("[*^$]="+K+"*(?:''|\"\")"),a.querySelectorAll("[selected]").length||o.push("\\["+K+"*(?:value|"+J+")"),a.querySelectorAll(":checked").length||o.push(":checked")}),gb(function(a){var b=e.createElement("input");b.setAttribute("type","hidden"),a.appendChild(b).setAttribute("name","D"),a.querySelectorAll("[name=d]").length&&o.push("name"+K+"*[*^$|!~]?="),a.querySelectorAll(":enabled").length||o.push(":enabled",":disabled"),a.querySelectorAll("*,:x"),o.push(",.*:")})),(c.matchesSelector=Y.test(q=m.webkitMatchesSelector||m.mozMatchesSelector||m.oMatchesSelector||m.msMatchesSelector))&&gb(function(a){c.disconnectedMatch=q.call(a,"div"),q.call(a,"[s!='']:x"),p.push("!=",O)}),o=o.length&&new RegExp(o.join("|")),p=p.length&&new RegExp(p.join("|")),b=Y.test(m.compareDocumentPosition),r=b||Y.test(m.contains)?function(a,b){var c=9===a.nodeType?a.documentElement:a,d=b&&b.parentNode;return a===d||!(!d||1!==d.nodeType||!(c.contains?c.contains(d):a.compareDocumentPosition&&16&a.compareDocumentPosition(d)))}:function(a,b){if(b)while(b=b.parentNode)if(b===a)return!0;return!1},z=b?function(a,b){if(a===b)return j=!0,0;var d=!a.compareDocumentPosition-!b.compareDocumentPosition;return d?d:(d=(a.ownerDocument||a)===(b.ownerDocument||b)?a.compareDocumentPosition(b):1,1&d||!c.sortDetached&&b.compareDocumentPosition(a)===d?a===e||a.ownerDocument===t&&r(t,a)?-1:b===e||b.ownerDocument===t&&r(t,b)?1:i?I.call(i,a)-I.call(i,b):0:4&d?-1:1)}:function(a,b){if(a===b)return j=!0,0;var c,d=0,f=a.parentNode,g=b.parentNode,h=[a],k=[b];if(!f||!g)return a===e?-1:b===e?1:f?-1:g?1:i?I.call(i,a)-I.call(i,b):0;if(f===g)return ib(a,b);c=a;while(c=c.parentNode)h.unshift(c);c=b;while(c=c.parentNode)k.unshift(c);while(h[d]===k[d])d++;return d?ib(h[d],k[d]):h[d]===t?-1:k[d]===t?1:0},e):l},db.matches=function(a,b){return db(a,null,null,b)},db.matchesSelector=function(a,b){if((a.ownerDocument||a)!==l&&k(a),b=b.replace(S,"='$1']"),!(!c.matchesSelector||!n||p&&p.test(b)||o&&o.test(b)))try{var d=q.call(a,b);if(d||c.disconnectedMatch||a.document&&11!==a.document.nodeType)return d}catch(e){}return db(b,l,null,[a]).length>0},db.contains=function(a,b){return(a.ownerDocument||a)!==l&&k(a),r(a,b)},db.attr=function(a,b){(a.ownerDocument||a)!==l&&k(a);var e=d.attrHandle[b.toLowerCase()],f=e&&C.call(d.attrHandle,b.toLowerCase())?e(a,b,!n):void 0;return void 0!==f?f:c.attributes||!n?a.getAttribute(b):(f=a.getAttributeNode(b))&&f.specified?f.value:null},db.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)},db.uniqueSort=function(a){var b,d=[],e=0,f=0;if(j=!c.detectDuplicates,i=!c.sortStable&&a.slice(0),a.sort(z),j){while(b=a[f++])b===a[f]&&(e=d.push(f));while(e--)a.splice(d[e],1)}return i=null,a},e=db.getText=function(a){var b,c="",d=0,f=a.nodeType;if(f){if(1===f||9===f||11===f){if("string"==typeof a.textContent)return a.textContent;for(a=a.firstChild;a;a=a.nextSibling)c+=e(a)}else if(3===f||4===f)return a.nodeValue}else while(b=a[d++])c+=e(b);return c},d=db.selectors={cacheLength:50,createPseudo:fb,match:V,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(a){return a[1]=a[1].replace(ab,bb),a[3]=(a[4]||a[5]||"").replace(ab,bb),"~="===a[2]&&(a[3]=" "+a[3]+" "),a.slice(0,4)},CHILD:function(a){return a[1]=a[1].toLowerCase(),"nth"===a[1].slice(0,3)?(a[3]||db.error(a[0]),a[4]=+(a[4]?a[5]+(a[6]||1):2*("even"===a[3]||"odd"===a[3])),a[5]=+(a[7]+a[8]||"odd"===a[3])):a[3]&&db.error(a[0]),a},PSEUDO:function(a){var b,c=!a[5]&&a[2];return V.CHILD.test(a[0])?null:(a[3]&&void 0!==a[4]?a[2]=a[4]:c&&T.test(c)&&(b=ob(c,!0))&&(b=c.indexOf(")",c.length-b)-c.length)&&(a[0]=a[0].slice(0,b),a[2]=c.slice(0,b)),a.slice(0,3))}},filter:{TAG:function(a){var b=a.replace(ab,bb).toLowerCase();return"*"===a?function(){return!0}:function(a){return a.nodeName&&a.nodeName.toLowerCase()===b}},CLASS:function(a){var b=w[a+" "];return b||(b=new RegExp("(^|"+K+")"+a+"("+K+"|$)"))&&w(a,function(a){return b.test("string"==typeof a.className&&a.className||typeof a.getAttribute!==A&&a.getAttribute("class")||"")})},ATTR:function(a,b,c){return function(d){var e=db.attr(d,a);return null==e?"!="===b:b?(e+="","="===b?e===c:"!="===b?e!==c:"^="===b?c&&0===e.indexOf(c):"*="===b?c&&e.indexOf(c)>-1:"$="===b?c&&e.slice(-c.length)===c:"~="===b?(" "+e+" ").indexOf(c)>-1:"|="===b?e===c||e.slice(0,c.length+1)===c+"-":!1):!0}},CHILD:function(a,b,c,d,e){var f="nth"!==a.slice(0,3),g="last"!==a.slice(-4),h="of-type"===b;return 1===d&&0===e?function(a){return!!a.parentNode}:function(b,c,i){var j,k,l,m,n,o,p=f!==g?"nextSibling":"previousSibling",q=b.parentNode,r=h&&b.nodeName.toLowerCase(),t=!i&&!h;if(q){if(f){while(p){l=b;while(l=l[p])if(h?l.nodeName.toLowerCase()===r:1===l.nodeType)return!1;o=p="only"===a&&!o&&"nextSibling"}return!0}if(o=[g?q.firstChild:q.lastChild],g&&t){k=q[s]||(q[s]={}),j=k[a]||[],n=j[0]===u&&j[1],m=j[0]===u&&j[2],l=n&&q.childNodes[n];while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if(1===l.nodeType&&++m&&l===b){k[a]=[u,n,m];break}}else if(t&&(j=(b[s]||(b[s]={}))[a])&&j[0]===u)m=j[1];else while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if((h?l.nodeName.toLowerCase()===r:1===l.nodeType)&&++m&&(t&&((l[s]||(l[s]={}))[a]=[u,m]),l===b))break;return m-=e,m===d||m%d===0&&m/d>=0}}},PSEUDO:function(a,b){var c,e=d.pseudos[a]||d.setFilters[a.toLowerCase()]||db.error("unsupported pseudo: "+a);return e[s]?e(b):e.length>1?(c=[a,a,"",b],d.setFilters.hasOwnProperty(a.toLowerCase())?fb(function(a,c){var d,f=e(a,b),g=f.length;while(g--)d=I.call(a,f[g]),a[d]=!(c[d]=f[g])}):function(a){return e(a,0,c)}):e}},pseudos:{not:fb(function(a){var b=[],c=[],d=g(a.replace(P,"$1"));return d[s]?fb(function(a,b,c,e){var f,g=d(a,null,e,[]),h=a.length;while(h--)(f=g[h])&&(a[h]=!(b[h]=f))}):function(a,e,f){return b[0]=a,d(b,null,f,c),!c.pop()}}),has:fb(function(a){return function(b){return db(a,b).length>0}}),contains:fb(function(a){return function(b){return(b.textContent||b.innerText||e(b)).indexOf(a)>-1}}),lang:fb(function(a){return U.test(a||"")||db.error("unsupported lang: "+a),a=a.replace(ab,bb).toLowerCase(),function(b){var c;do if(c=n?b.lang:b.getAttribute("xml:lang")||b.getAttribute("lang"))return c=c.toLowerCase(),c===a||0===c.indexOf(a+"-");while((b=b.parentNode)&&1===b.nodeType);return!1}}),target:function(b){var c=a.location&&a.location.hash;return c&&c.slice(1)===b.id},root:function(a){return a===m},focus:function(a){return a===l.activeElement&&(!l.hasFocus||l.hasFocus())&&!!(a.type||a.href||~a.tabIndex)},enabled:function(a){return a.disabled===!1},disabled:function(a){return a.disabled===!0},checked:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&!!a.checked||"option"===b&&!!a.selected},selected:function(a){return a.parentNode&&a.parentNode.selectedIndex,a.selected===!0},empty:function(a){for(a=a.firstChild;a;a=a.nextSibling)if(a.nodeType<6)return!1;return!0},parent:function(a){return!d.pseudos.empty(a)},header:function(a){return X.test(a.nodeName)},input:function(a){return W.test(a.nodeName)},button:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&"button"===a.type||"button"===b},text:function(a){var b;return"input"===a.nodeName.toLowerCase()&&"text"===a.type&&(null==(b=a.getAttribute("type"))||"text"===b.toLowerCase())},first:lb(function(){return[0]}),last:lb(function(a,b){return[b-1]}),eq:lb(function(a,b,c){return[0>c?c+b:c]}),even:lb(function(a,b){for(var c=0;b>c;c+=2)a.push(c);return a}),odd:lb(function(a,b){for(var c=1;b>c;c+=2)a.push(c);return a}),lt:lb(function(a,b,c){for(var d=0>c?c+b:c;--d>=0;)a.push(d);return a}),gt:lb(function(a,b,c){for(var d=0>c?c+b:c;++d<b;)a.push(d);return a})}},d.pseudos.nth=d.pseudos.eq;for(b in{radio:!0,checkbox:!0,file:!0,password:!0,image:!0})d.pseudos[b]=jb(b);for(b in{submit:!0,reset:!0})d.pseudos[b]=kb(b);function nb(){}nb.prototype=d.filters=d.pseudos,d.setFilters=new nb;function ob(a,b){var c,e,f,g,h,i,j,k=x[a+" "];if(k)return b?0:k.slice(0);h=a,i=[],j=d.preFilter;while(h){(!c||(e=Q.exec(h)))&&(e&&(h=h.slice(e[0].length)||h),i.push(f=[])),c=!1,(e=R.exec(h))&&(c=e.shift(),f.push({value:c,type:e[0].replace(P," ")}),h=h.slice(c.length));for(g in d.filter)!(e=V[g].exec(h))||j[g]&&!(e=j[g](e))||(c=e.shift(),f.push({value:c,type:g,matches:e}),h=h.slice(c.length));if(!c)break}return b?h.length:h?db.error(a):x(a,i).slice(0)}function pb(a){for(var b=0,c=a.length,d="";c>b;b++)d+=a[b].value;return d}function qb(a,b,c){var d=b.dir,e=c&&"parentNode"===d,f=v++;return b.first?function(b,c,f){while(b=b[d])if(1===b.nodeType||e)return a(b,c,f)}:function(b,c,g){var h,i,j=[u,f];if(g){while(b=b[d])if((1===b.nodeType||e)&&a(b,c,g))return!0}else while(b=b[d])if(1===b.nodeType||e){if(i=b[s]||(b[s]={}),(h=i[d])&&h[0]===u&&h[1]===f)return j[2]=h[2];if(i[d]=j,j[2]=a(b,c,g))return!0}}}function rb(a){return a.length>1?function(b,c,d){var e=a.length;while(e--)if(!a[e](b,c,d))return!1;return!0}:a[0]}function sb(a,b,c,d,e){for(var f,g=[],h=0,i=a.length,j=null!=b;i>h;h++)(f=a[h])&&(!c||c(f,d,e))&&(g.push(f),j&&b.push(h));return g}function tb(a,b,c,d,e,f){return d&&!d[s]&&(d=tb(d)),e&&!e[s]&&(e=tb(e,f)),fb(function(f,g,h,i){var j,k,l,m=[],n=[],o=g.length,p=f||wb(b||"*",h.nodeType?[h]:h,[]),q=!a||!f&&b?p:sb(p,m,a,h,i),r=c?e||(f?a:o||d)?[]:g:q;if(c&&c(q,r,h,i),d){j=sb(r,n),d(j,[],h,i),k=j.length;while(k--)(l=j[k])&&(r[n[k]]=!(q[n[k]]=l))}if(f){if(e||a){if(e){j=[],k=r.length;while(k--)(l=r[k])&&j.push(q[k]=l);e(null,r=[],j,i)}k=r.length;while(k--)(l=r[k])&&(j=e?I.call(f,l):m[k])>-1&&(f[j]=!(g[j]=l))}}else r=sb(r===g?r.splice(o,r.length):r),e?e(null,g,r,i):G.apply(g,r)})}function ub(a){for(var b,c,e,f=a.length,g=d.relative[a[0].type],i=g||d.relative[" "],j=g?1:0,k=qb(function(a){return a===b},i,!0),l=qb(function(a){return I.call(b,a)>-1},i,!0),m=[function(a,c,d){return!g&&(d||c!==h)||((b=c).nodeType?k(a,c,d):l(a,c,d))}];f>j;j++)if(c=d.relative[a[j].type])m=[qb(rb(m),c)];else{if(c=d.filter[a[j].type].apply(null,a[j].matches),c[s]){for(e=++j;f>e;e++)if(d.relative[a[e].type])break;return tb(j>1&&rb(m),j>1&&pb(a.slice(0,j-1).concat({value:" "===a[j-2].type?"*":""})).replace(P,"$1"),c,e>j&&ub(a.slice(j,e)),f>e&&ub(a=a.slice(e)),f>e&&pb(a))}m.push(c)}return rb(m)}function vb(a,b){var c=b.length>0,e=a.length>0,f=function(f,g,i,j,k){var m,n,o,p=0,q="0",r=f&&[],s=[],t=h,v=f||e&&d.find.TAG("*",k),w=u+=null==t?1:Math.random()||.1,x=v.length;for(k&&(h=g!==l&&g);q!==x&&null!=(m=v[q]);q++){if(e&&m){n=0;while(o=a[n++])if(o(m,g,i)){j.push(m);break}k&&(u=w)}c&&((m=!o&&m)&&p--,f&&r.push(m))}if(p+=q,c&&q!==p){n=0;while(o=b[n++])o(r,s,g,i);if(f){if(p>0)while(q--)r[q]||s[q]||(s[q]=E.call(j));s=sb(s)}G.apply(j,s),k&&!f&&s.length>0&&p+b.length>1&&db.uniqueSort(j)}return k&&(u=w,h=t),r};return c?fb(f):f}g=db.compile=function(a,b){var c,d=[],e=[],f=y[a+" "];if(!f){b||(b=ob(a)),c=b.length;while(c--)f=ub(b[c]),f[s]?d.push(f):e.push(f);f=y(a,vb(e,d))}return f};function wb(a,b,c){for(var d=0,e=b.length;e>d;d++)db(a,b[d],c);return c}function xb(a,b,e,f){var h,i,j,k,l,m=ob(a);if(!f&&1===m.length){if(i=m[0]=m[0].slice(0),i.length>2&&"ID"===(j=i[0]).type&&c.getById&&9===b.nodeType&&n&&d.relative[i[1].type]){if(b=(d.find.ID(j.matches[0].replace(ab,bb),b)||[])[0],!b)return e;a=a.slice(i.shift().value.length)}h=V.needsContext.test(a)?0:i.length;while(h--){if(j=i[h],d.relative[k=j.type])break;if((l=d.find[k])&&(f=l(j.matches[0].replace(ab,bb),$.test(i[0].type)&&mb(b.parentNode)||b))){if(i.splice(h,1),a=f.length&&pb(i),!a)return G.apply(e,f),e;break}}}return g(a,m)(f,b,!n,e,$.test(a)&&mb(b.parentNode)||b),e}return c.sortStable=s.split("").sort(z).join("")===s,c.detectDuplicates=!!j,k(),c.sortDetached=gb(function(a){return 1&a.compareDocumentPosition(l.createElement("div"))}),gb(function(a){return a.innerHTML="<a href='#'></a>","#"===a.firstChild.getAttribute("href")})||hb("type|href|height|width",function(a,b,c){return c?void 0:a.getAttribute(b,"type"===b.toLowerCase()?1:2)}),c.attributes&&gb(function(a){return a.innerHTML="<input/>",a.firstChild.setAttribute("value",""),""===a.firstChild.getAttribute("value")})||hb("value",function(a,b,c){return c||"input"!==a.nodeName.toLowerCase()?void 0:a.defaultValue}),gb(function(a){return null==a.getAttribute("disabled")})||hb(J,function(a,b,c){var d;return c?void 0:a[b]===!0?b.toLowerCase():(d=a.getAttributeNode(b))&&d.specified?d.value:null}),db}(a);o.find=t,o.expr=t.selectors,o.expr[":"]=o.expr.pseudos,o.unique=t.uniqueSort,o.text=t.getText,o.isXMLDoc=t.isXML,o.contains=t.contains;var u=o.expr.match.needsContext,v=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,w=/^.[^:#\[\.,]*$/;function x(a,b,c){if(o.isFunction(b))return o.grep(a,function(a,d){return!!b.call(a,d,a)!==c});if(b.nodeType)return o.grep(a,function(a){return a===b!==c});if("string"==typeof b){if(w.test(b))return o.filter(b,a,c);b=o.filter(b,a)}return o.grep(a,function(a){return g.call(b,a)>=0!==c})}o.filter=function(a,b,c){var d=b[0];return c&&(a=":not("+a+")"),1===b.length&&1===d.nodeType?o.find.matchesSelector(d,a)?[d]:[]:o.find.matches(a,o.grep(b,function(a){return 1===a.nodeType}))},o.fn.extend({find:function(a){var b,c=this.length,d=[],e=this;if("string"!=typeof a)return this.pushStack(o(a).filter(function(){for(b=0;c>b;b++)if(o.contains(e[b],this))return!0}));for(b=0;c>b;b++)o.find(a,e[b],d);return d=this.pushStack(c>1?o.unique(d):d),d.selector=this.selector?this.selector+" "+a:a,d},filter:function(a){return this.pushStack(x(this,a||[],!1))},not:function(a){return this.pushStack(x(this,a||[],!0))},is:function(a){return!!x(this,"string"==typeof a&&u.test(a)?o(a):a||[],!1).length}});var y,z=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,A=o.fn.init=function(a,b){var c,d;if(!a)return this;if("string"==typeof a){if(c="<"===a[0]&&">"===a[a.length-1]&&a.length>=3?[null,a,null]:z.exec(a),!c||!c[1]&&b)return!b||b.jquery?(b||y).find(a):this.constructor(b).find(a);if(c[1]){if(b=b instanceof o?b[0]:b,o.merge(this,o.parseHTML(c[1],b&&b.nodeType?b.ownerDocument||b:m,!0)),v.test(c[1])&&o.isPlainObject(b))for(c in b)o.isFunction(this[c])?this[c](b[c]):this.attr(c,b[c]);return this}return d=m.getElementById(c[2]),d&&d.parentNode&&(this.length=1,this[0]=d),this.context=m,this.selector=a,this}return a.nodeType?(this.context=this[0]=a,this.length=1,this):o.isFunction(a)?"undefined"!=typeof y.ready?y.ready(a):a(o):(void 0!==a.selector&&(this.selector=a.selector,this.context=a.context),o.makeArray(a,this))};A.prototype=o.fn,y=o(m);var B=/^(?:parents|prev(?:Until|All))/,C={children:!0,contents:!0,next:!0,prev:!0};o.extend({dir:function(a,b,c){var d=[],e=void 0!==c;while((a=a[b])&&9!==a.nodeType)if(1===a.nodeType){if(e&&o(a).is(c))break;d.push(a)}return d},sibling:function(a,b){for(var c=[];a;a=a.nextSibling)1===a.nodeType&&a!==b&&c.push(a);return c}}),o.fn.extend({has:function(a){var b=o(a,this),c=b.length;return this.filter(function(){for(var a=0;c>a;a++)if(o.contains(this,b[a]))return!0})},closest:function(a,b){for(var c,d=0,e=this.length,f=[],g=u.test(a)||"string"!=typeof a?o(a,b||this.context):0;e>d;d++)for(c=this[d];c&&c!==b;c=c.parentNode)if(c.nodeType<11&&(g?g.index(c)>-1:1===c.nodeType&&o.find.matchesSelector(c,a))){f.push(c);break}return this.pushStack(f.length>1?o.unique(f):f)},index:function(a){return a?"string"==typeof a?g.call(o(a),this[0]):g.call(this,a.jquery?a[0]:a):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(a,b){return this.pushStack(o.unique(o.merge(this.get(),o(a,b))))},addBack:function(a){return this.add(null==a?this.prevObject:this.prevObject.filter(a))}});function D(a,b){while((a=a[b])&&1!==a.nodeType);return a}o.each({parent:function(a){var b=a.parentNode;return b&&11!==b.nodeType?b:null},parents:function(a){return o.dir(a,"parentNode")},parentsUntil:function(a,b,c){return o.dir(a,"parentNode",c)},next:function(a){return D(a,"nextSibling")},prev:function(a){return D(a,"previousSibling")},nextAll:function(a){return o.dir(a,"nextSibling")},prevAll:function(a){return o.dir(a,"previousSibling")},nextUntil:function(a,b,c){return o.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return o.dir(a,"previousSibling",c)},siblings:function(a){return o.sibling((a.parentNode||{}).firstChild,a)},children:function(a){return o.sibling(a.firstChild)},contents:function(a){return a.contentDocument||o.merge([],a.childNodes)}},function(a,b){o.fn[a]=function(c,d){var e=o.map(this,b,c);return"Until"!==a.slice(-5)&&(d=c),d&&"string"==typeof d&&(e=o.filter(d,e)),this.length>1&&(C[a]||o.unique(e),B.test(a)&&e.reverse()),this.pushStack(e)}});var E=/\S+/g,F={};function G(a){var b=F[a]={};return o.each(a.match(E)||[],function(a,c){b[c]=!0}),b}o.Callbacks=function(a){a="string"==typeof a?F[a]||G(a):o.extend({},a);var b,c,d,e,f,g,h=[],i=!a.once&&[],j=function(l){for(b=a.memory&&l,c=!0,g=e||0,e=0,f=h.length,d=!0;h&&f>g;g++)if(h[g].apply(l[0],l[1])===!1&&a.stopOnFalse){b=!1;break}d=!1,h&&(i?i.length&&j(i.shift()):b?h=[]:k.disable())},k={add:function(){if(h){var c=h.length;!function g(b){o.each(b,function(b,c){var d=o.type(c);"function"===d?a.unique&&k.has(c)||h.push(c):c&&c.length&&"string"!==d&&g(c)})}(arguments),d?f=h.length:b&&(e=c,j(b))}return this},remove:function(){return h&&o.each(arguments,function(a,b){var c;while((c=o.inArray(b,h,c))>-1)h.splice(c,1),d&&(f>=c&&f--,g>=c&&g--)}),this},has:function(a){return a?o.inArray(a,h)>-1:!(!h||!h.length)},empty:function(){return h=[],f=0,this},disable:function(){return h=i=b=void 0,this},disabled:function(){return!h},lock:function(){return i=void 0,b||k.disable(),this},locked:function(){return!i},fireWith:function(a,b){return!h||c&&!i||(b=b||[],b=[a,b.slice?b.slice():b],d?i.push(b):j(b)),this},fire:function(){return k.fireWith(this,arguments),this},fired:function(){return!!c}};return k},o.extend({Deferred:function(a){var b=[["resolve","done",o.Callbacks("once memory"),"resolved"],["reject","fail",o.Callbacks("once memory"),"rejected"],["notify","progress",o.Callbacks("memory")]],c="pending",d={state:function(){return c},always:function(){return e.done(arguments).fail(arguments),this},then:function(){var a=arguments;return o.Deferred(function(c){o.each(b,function(b,f){var g=o.isFunction(a[b])&&a[b];e[f[1]](function(){var a=g&&g.apply(this,arguments);a&&o.isFunction(a.promise)?a.promise().done(c.resolve).fail(c.reject).progress(c.notify):c[f[0]+"With"](this===d?c.promise():this,g?[a]:arguments)})}),a=null}).promise()},promise:function(a){return null!=a?o.extend(a,d):d}},e={};return d.pipe=d.then,o.each(b,function(a,f){var g=f[2],h=f[3];d[f[1]]=g.add,h&&g.add(function(){c=h},b[1^a][2].disable,b[2][2].lock),e[f[0]]=function(){return e[f[0]+"With"](this===e?d:this,arguments),this},e[f[0]+"With"]=g.fireWith}),d.promise(e),a&&a.call(e,e),e},when:function(a){var b=0,c=d.call(arguments),e=c.length,f=1!==e||a&&o.isFunction(a.promise)?e:0,g=1===f?a:o.Deferred(),h=function(a,b,c){return function(e){b[a]=this,c[a]=arguments.length>1?d.call(arguments):e,c===i?g.notifyWith(b,c):--f||g.resolveWith(b,c)}},i,j,k;if(e>1)for(i=new Array(e),j=new Array(e),k=new Array(e);e>b;b++)c[b]&&o.isFunction(c[b].promise)?c[b].promise().done(h(b,k,c)).fail(g.reject).progress(h(b,j,i)):--f;return f||g.resolveWith(k,c),g.promise()}});var H;o.fn.ready=function(a){return o.ready.promise().done(a),this},o.extend({isReady:!1,readyWait:1,holdReady:function(a){a?o.readyWait++:o.ready(!0)},ready:function(a){(a===!0?--o.readyWait:o.isReady)||(o.isReady=!0,a!==!0&&--o.readyWait>0||(H.resolveWith(m,[o]),o.fn.trigger&&o(m).trigger("ready").off("ready")))}});function I(){m.removeEventListener("DOMContentLoaded",I,!1),a.removeEventListener("load",I,!1),o.ready()}o.ready.promise=function(b){return H||(H=o.Deferred(),"complete"===m.readyState?setTimeout(o.ready):(m.addEventListener("DOMContentLoaded",I,!1),a.addEventListener("load",I,!1))),H.promise(b)},o.ready.promise();var J=o.access=function(a,b,c,d,e,f,g){var h=0,i=a.length,j=null==c;if("object"===o.type(c)){e=!0;for(h in c)o.access(a,b,h,c[h],!0,f,g)}else if(void 0!==d&&(e=!0,o.isFunction(d)||(g=!0),j&&(g?(b.call(a,d),b=null):(j=b,b=function(a,b,c){return j.call(o(a),c)})),b))for(;i>h;h++)b(a[h],c,g?d:d.call(a[h],h,b(a[h],c)));return e?a:j?b.call(a):i?b(a[0],c):f};o.acceptData=function(a){return 1===a.nodeType||9===a.nodeType||!+a.nodeType};function K(){Object.defineProperty(this.cache={},0,{get:function(){return{}}}),this.expando=o.expando+Math.random()}K.uid=1,K.accepts=o.acceptData,K.prototype={key:function(a){if(!K.accepts(a))return 0;var b={},c=a[this.expando];if(!c){c=K.uid++;try{b[this.expando]={value:c},Object.defineProperties(a,b)}catch(d){b[this.expando]=c,o.extend(a,b)}}return this.cache[c]||(this.cache[c]={}),c},set:function(a,b,c){var d,e=this.key(a),f=this.cache[e];if("string"==typeof b)f[b]=c;else if(o.isEmptyObject(f))o.extend(this.cache[e],b);else for(d in b)f[d]=b[d];return f},get:function(a,b){var c=this.cache[this.key(a)];return void 0===b?c:c[b]},access:function(a,b,c){var d;return void 0===b||b&&"string"==typeof b&&void 0===c?(d=this.get(a,b),void 0!==d?d:this.get(a,o.camelCase(b))):(this.set(a,b,c),void 0!==c?c:b)},remove:function(a,b){var c,d,e,f=this.key(a),g=this.cache[f];if(void 0===b)this.cache[f]={};else{o.isArray(b)?d=b.concat(b.map(o.camelCase)):(e=o.camelCase(b),b in g?d=[b,e]:(d=e,d=d in g?[d]:d.match(E)||[])),c=d.length;while(c--)delete g[d[c]]}},hasData:function(a){return!o.isEmptyObject(this.cache[a[this.expando]]||{})},discard:function(a){a[this.expando]&&delete this.cache[a[this.expando]]}};var L=new K,M=new K,N=/^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,O=/([A-Z])/g;function P(a,b,c){var d;if(void 0===c&&1===a.nodeType)if(d="data-"+b.replace(O,"-$1").toLowerCase(),c=a.getAttribute(d),"string"==typeof c){try{c="true"===c?!0:"false"===c?!1:"null"===c?null:+c+""===c?+c:N.test(c)?o.parseJSON(c):c}catch(e){}M.set(a,b,c)}else c=void 0;return c}o.extend({hasData:function(a){return M.hasData(a)||L.hasData(a)},data:function(a,b,c){return M.access(a,b,c)},removeData:function(a,b){M.remove(a,b)},_data:function(a,b,c){return L.access(a,b,c)},_removeData:function(a,b){L.remove(a,b)}}),o.fn.extend({data:function(a,b){var c,d,e,f=this[0],g=f&&f.attributes;if(void 0===a){if(this.length&&(e=M.get(f),1===f.nodeType&&!L.get(f,"hasDataAttrs"))){c=g.length;
+while(c--)d=g[c].name,0===d.indexOf("data-")&&(d=o.camelCase(d.slice(5)),P(f,d,e[d]));L.set(f,"hasDataAttrs",!0)}return e}return"object"==typeof a?this.each(function(){M.set(this,a)}):J(this,function(b){var c,d=o.camelCase(a);if(f&&void 0===b){if(c=M.get(f,a),void 0!==c)return c;if(c=M.get(f,d),void 0!==c)return c;if(c=P(f,d,void 0),void 0!==c)return c}else this.each(function(){var c=M.get(this,d);M.set(this,d,b),-1!==a.indexOf("-")&&void 0!==c&&M.set(this,a,b)})},null,b,arguments.length>1,null,!0)},removeData:function(a){return this.each(function(){M.remove(this,a)})}}),o.extend({queue:function(a,b,c){var d;return a?(b=(b||"fx")+"queue",d=L.get(a,b),c&&(!d||o.isArray(c)?d=L.access(a,b,o.makeArray(c)):d.push(c)),d||[]):void 0},dequeue:function(a,b){b=b||"fx";var c=o.queue(a,b),d=c.length,e=c.shift(),f=o._queueHooks(a,b),g=function(){o.dequeue(a,b)};"inprogress"===e&&(e=c.shift(),d--),e&&("fx"===b&&c.unshift("inprogress"),delete f.stop,e.call(a,g,f)),!d&&f&&f.empty.fire()},_queueHooks:function(a,b){var c=b+"queueHooks";return L.get(a,c)||L.access(a,c,{empty:o.Callbacks("once memory").add(function(){L.remove(a,[b+"queue",c])})})}}),o.fn.extend({queue:function(a,b){var c=2;return"string"!=typeof a&&(b=a,a="fx",c--),arguments.length<c?o.queue(this[0],a):void 0===b?this:this.each(function(){var c=o.queue(this,a,b);o._queueHooks(this,a),"fx"===a&&"inprogress"!==c[0]&&o.dequeue(this,a)})},dequeue:function(a){return this.each(function(){o.dequeue(this,a)})},clearQueue:function(a){return this.queue(a||"fx",[])},promise:function(a,b){var c,d=1,e=o.Deferred(),f=this,g=this.length,h=function(){--d||e.resolveWith(f,[f])};"string"!=typeof a&&(b=a,a=void 0),a=a||"fx";while(g--)c=L.get(f[g],a+"queueHooks"),c&&c.empty&&(d++,c.empty.add(h));return h(),e.promise(b)}});var Q=/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,R=["Top","Right","Bottom","Left"],S=function(a,b){return a=b||a,"none"===o.css(a,"display")||!o.contains(a.ownerDocument,a)},T=/^(?:checkbox|radio)$/i;!function(){var a=m.createDocumentFragment(),b=a.appendChild(m.createElement("div"));b.innerHTML="<input type='radio' checked='checked' name='t'/>",l.checkClone=b.cloneNode(!0).cloneNode(!0).lastChild.checked,b.innerHTML="<textarea>x</textarea>",l.noCloneChecked=!!b.cloneNode(!0).lastChild.defaultValue}();var U="undefined";l.focusinBubbles="onfocusin"in a;var V=/^key/,W=/^(?:mouse|contextmenu)|click/,X=/^(?:focusinfocus|focusoutblur)$/,Y=/^([^.]*)(?:\.(.+)|)$/;function Z(){return!0}function $(){return!1}function _(){try{return m.activeElement}catch(a){}}o.event={global:{},add:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,n,p,q,r=L.get(a);if(r){c.handler&&(f=c,c=f.handler,e=f.selector),c.guid||(c.guid=o.guid++),(i=r.events)||(i=r.events={}),(g=r.handle)||(g=r.handle=function(b){return typeof o!==U&&o.event.triggered!==b.type?o.event.dispatch.apply(a,arguments):void 0}),b=(b||"").match(E)||[""],j=b.length;while(j--)h=Y.exec(b[j])||[],n=q=h[1],p=(h[2]||"").split(".").sort(),n&&(l=o.event.special[n]||{},n=(e?l.delegateType:l.bindType)||n,l=o.event.special[n]||{},k=o.extend({type:n,origType:q,data:d,handler:c,guid:c.guid,selector:e,needsContext:e&&o.expr.match.needsContext.test(e),namespace:p.join(".")},f),(m=i[n])||(m=i[n]=[],m.delegateCount=0,l.setup&&l.setup.call(a,d,p,g)!==!1||a.addEventListener&&a.addEventListener(n,g,!1)),l.add&&(l.add.call(a,k),k.handler.guid||(k.handler.guid=c.guid)),e?m.splice(m.delegateCount++,0,k):m.push(k),o.event.global[n]=!0)}},remove:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,n,p,q,r=L.hasData(a)&&L.get(a);if(r&&(i=r.events)){b=(b||"").match(E)||[""],j=b.length;while(j--)if(h=Y.exec(b[j])||[],n=q=h[1],p=(h[2]||"").split(".").sort(),n){l=o.event.special[n]||{},n=(d?l.delegateType:l.bindType)||n,m=i[n]||[],h=h[2]&&new RegExp("(^|\\.)"+p.join("\\.(?:.*\\.|)")+"(\\.|$)"),g=f=m.length;while(f--)k=m[f],!e&&q!==k.origType||c&&c.guid!==k.guid||h&&!h.test(k.namespace)||d&&d!==k.selector&&("**"!==d||!k.selector)||(m.splice(f,1),k.selector&&m.delegateCount--,l.remove&&l.remove.call(a,k));g&&!m.length&&(l.teardown&&l.teardown.call(a,p,r.handle)!==!1||o.removeEvent(a,n,r.handle),delete i[n])}else for(n in i)o.event.remove(a,n+b[j],c,d,!0);o.isEmptyObject(i)&&(delete r.handle,L.remove(a,"events"))}},trigger:function(b,c,d,e){var f,g,h,i,k,l,n,p=[d||m],q=j.call(b,"type")?b.type:b,r=j.call(b,"namespace")?b.namespace.split("."):[];if(g=h=d=d||m,3!==d.nodeType&&8!==d.nodeType&&!X.test(q+o.event.triggered)&&(q.indexOf(".")>=0&&(r=q.split("."),q=r.shift(),r.sort()),k=q.indexOf(":")<0&&"on"+q,b=b[o.expando]?b:new o.Event(q,"object"==typeof b&&b),b.isTrigger=e?2:3,b.namespace=r.join("."),b.namespace_re=b.namespace?new RegExp("(^|\\.)"+r.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,b.result=void 0,b.target||(b.target=d),c=null==c?[b]:o.makeArray(c,[b]),n=o.event.special[q]||{},e||!n.trigger||n.trigger.apply(d,c)!==!1)){if(!e&&!n.noBubble&&!o.isWindow(d)){for(i=n.delegateType||q,X.test(i+q)||(g=g.parentNode);g;g=g.parentNode)p.push(g),h=g;h===(d.ownerDocument||m)&&p.push(h.defaultView||h.parentWindow||a)}f=0;while((g=p[f++])&&!b.isPropagationStopped())b.type=f>1?i:n.bindType||q,l=(L.get(g,"events")||{})[b.type]&&L.get(g,"handle"),l&&l.apply(g,c),l=k&&g[k],l&&l.apply&&o.acceptData(g)&&(b.result=l.apply(g,c),b.result===!1&&b.preventDefault());return b.type=q,e||b.isDefaultPrevented()||n._default&&n._default.apply(p.pop(),c)!==!1||!o.acceptData(d)||k&&o.isFunction(d[q])&&!o.isWindow(d)&&(h=d[k],h&&(d[k]=null),o.event.triggered=q,d[q](),o.event.triggered=void 0,h&&(d[k]=h)),b.result}},dispatch:function(a){a=o.event.fix(a);var b,c,e,f,g,h=[],i=d.call(arguments),j=(L.get(this,"events")||{})[a.type]||[],k=o.event.special[a.type]||{};if(i[0]=a,a.delegateTarget=this,!k.preDispatch||k.preDispatch.call(this,a)!==!1){h=o.event.handlers.call(this,a,j),b=0;while((f=h[b++])&&!a.isPropagationStopped()){a.currentTarget=f.elem,c=0;while((g=f.handlers[c++])&&!a.isImmediatePropagationStopped())(!a.namespace_re||a.namespace_re.test(g.namespace))&&(a.handleObj=g,a.data=g.data,e=((o.event.special[g.origType]||{}).handle||g.handler).apply(f.elem,i),void 0!==e&&(a.result=e)===!1&&(a.preventDefault(),a.stopPropagation()))}return k.postDispatch&&k.postDispatch.call(this,a),a.result}},handlers:function(a,b){var c,d,e,f,g=[],h=b.delegateCount,i=a.target;if(h&&i.nodeType&&(!a.button||"click"!==a.type))for(;i!==this;i=i.parentNode||this)if(i.disabled!==!0||"click"!==a.type){for(d=[],c=0;h>c;c++)f=b[c],e=f.selector+" ",void 0===d[e]&&(d[e]=f.needsContext?o(e,this).index(i)>=0:o.find(e,this,null,[i]).length),d[e]&&d.push(f);d.length&&g.push({elem:i,handlers:d})}return h<b.length&&g.push({elem:this,handlers:b.slice(h)}),g},props:"altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),fixHooks:{},keyHooks:{props:"char charCode key keyCode".split(" "),filter:function(a,b){return null==a.which&&(a.which=null!=b.charCode?b.charCode:b.keyCode),a}},mouseHooks:{props:"button buttons clientX clientY offsetX offsetY pageX pageY screenX screenY toElement".split(" "),filter:function(a,b){var c,d,e,f=b.button;return null==a.pageX&&null!=b.clientX&&(c=a.target.ownerDocument||m,d=c.documentElement,e=c.body,a.pageX=b.clientX+(d&&d.scrollLeft||e&&e.scrollLeft||0)-(d&&d.clientLeft||e&&e.clientLeft||0),a.pageY=b.clientY+(d&&d.scrollTop||e&&e.scrollTop||0)-(d&&d.clientTop||e&&e.clientTop||0)),a.which||void 0===f||(a.which=1&f?1:2&f?3:4&f?2:0),a}},fix:function(a){if(a[o.expando])return a;var b,c,d,e=a.type,f=a,g=this.fixHooks[e];g||(this.fixHooks[e]=g=W.test(e)?this.mouseHooks:V.test(e)?this.keyHooks:{}),d=g.props?this.props.concat(g.props):this.props,a=new o.Event(f),b=d.length;while(b--)c=d[b],a[c]=f[c];return a.target||(a.target=m),3===a.target.nodeType&&(a.target=a.target.parentNode),g.filter?g.filter(a,f):a},special:{load:{noBubble:!0},focus:{trigger:function(){return this!==_()&&this.focus?(this.focus(),!1):void 0},delegateType:"focusin"},blur:{trigger:function(){return this===_()&&this.blur?(this.blur(),!1):void 0},delegateType:"focusout"},click:{trigger:function(){return"checkbox"===this.type&&this.click&&o.nodeName(this,"input")?(this.click(),!1):void 0},_default:function(a){return o.nodeName(a.target,"a")}},beforeunload:{postDispatch:function(a){void 0!==a.result&&(a.originalEvent.returnValue=a.result)}}},simulate:function(a,b,c,d){var e=o.extend(new o.Event,c,{type:a,isSimulated:!0,originalEvent:{}});d?o.event.trigger(e,null,b):o.event.dispatch.call(b,e),e.isDefaultPrevented()&&c.preventDefault()}},o.removeEvent=function(a,b,c){a.removeEventListener&&a.removeEventListener(b,c,!1)},o.Event=function(a,b){return this instanceof o.Event?(a&&a.type?(this.originalEvent=a,this.type=a.type,this.isDefaultPrevented=a.defaultPrevented||void 0===a.defaultPrevented&&a.getPreventDefault&&a.getPreventDefault()?Z:$):this.type=a,b&&o.extend(this,b),this.timeStamp=a&&a.timeStamp||o.now(),void(this[o.expando]=!0)):new o.Event(a,b)},o.Event.prototype={isDefaultPrevented:$,isPropagationStopped:$,isImmediatePropagationStopped:$,preventDefault:function(){var a=this.originalEvent;this.isDefaultPrevented=Z,a&&a.preventDefault&&a.preventDefault()},stopPropagation:function(){var a=this.originalEvent;this.isPropagationStopped=Z,a&&a.stopPropagation&&a.stopPropagation()},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=Z,this.stopPropagation()}},o.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(a,b){o.event.special[a]={delegateType:b,bindType:b,handle:function(a){var c,d=this,e=a.relatedTarget,f=a.handleObj;return(!e||e!==d&&!o.contains(d,e))&&(a.type=f.origType,c=f.handler.apply(this,arguments),a.type=b),c}}}),l.focusinBubbles||o.each({focus:"focusin",blur:"focusout"},function(a,b){var c=function(a){o.event.simulate(b,a.target,o.event.fix(a),!0)};o.event.special[b]={setup:function(){var d=this.ownerDocument||this,e=L.access(d,b);e||d.addEventListener(a,c,!0),L.access(d,b,(e||0)+1)},teardown:function(){var d=this.ownerDocument||this,e=L.access(d,b)-1;e?L.access(d,b,e):(d.removeEventListener(a,c,!0),L.remove(d,b))}}}),o.fn.extend({on:function(a,b,c,d,e){var f,g;if("object"==typeof a){"string"!=typeof b&&(c=c||b,b=void 0);for(g in a)this.on(g,b,c,a[g],e);return this}if(null==c&&null==d?(d=b,c=b=void 0):null==d&&("string"==typeof b?(d=c,c=void 0):(d=c,c=b,b=void 0)),d===!1)d=$;else if(!d)return this;return 1===e&&(f=d,d=function(a){return o().off(a),f.apply(this,arguments)},d.guid=f.guid||(f.guid=o.guid++)),this.each(function(){o.event.add(this,a,d,c,b)})},one:function(a,b,c,d){return this.on(a,b,c,d,1)},off:function(a,b,c){var d,e;if(a&&a.preventDefault&&a.handleObj)return d=a.handleObj,o(a.delegateTarget).off(d.namespace?d.origType+"."+d.namespace:d.origType,d.selector,d.handler),this;if("object"==typeof a){for(e in a)this.off(e,b,a[e]);return this}return(b===!1||"function"==typeof b)&&(c=b,b=void 0),c===!1&&(c=$),this.each(function(){o.event.remove(this,a,c,b)})},trigger:function(a,b){return this.each(function(){o.event.trigger(a,b,this)})},triggerHandler:function(a,b){var c=this[0];return c?o.event.trigger(a,b,c,!0):void 0}});var ab=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,bb=/<([\w:]+)/,cb=/<|&#?\w+;/,db=/<(?:script|style|link)/i,eb=/checked\s*(?:[^=]|=\s*.checked.)/i,fb=/^$|\/(?:java|ecma)script/i,gb=/^true\/(.*)/,hb=/^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g,ib={option:[1,"<select multiple='multiple'>","</select>"],thead:[1,"<table>","</table>"],col:[2,"<table><colgroup>","</colgroup></table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],_default:[0,"",""]};ib.optgroup=ib.option,ib.tbody=ib.tfoot=ib.colgroup=ib.caption=ib.thead,ib.th=ib.td;function jb(a,b){return o.nodeName(a,"table")&&o.nodeName(11!==b.nodeType?b:b.firstChild,"tr")?a.getElementsByTagName("tbody")[0]||a.appendChild(a.ownerDocument.createElement("tbody")):a}function kb(a){return a.type=(null!==a.getAttribute("type"))+"/"+a.type,a}function lb(a){var b=gb.exec(a.type);return b?a.type=b[1]:a.removeAttribute("type"),a}function mb(a,b){for(var c=0,d=a.length;d>c;c++)L.set(a[c],"globalEval",!b||L.get(b[c],"globalEval"))}function nb(a,b){var c,d,e,f,g,h,i,j;if(1===b.nodeType){if(L.hasData(a)&&(f=L.access(a),g=L.set(b,f),j=f.events)){delete g.handle,g.events={};for(e in j)for(c=0,d=j[e].length;d>c;c++)o.event.add(b,e,j[e][c])}M.hasData(a)&&(h=M.access(a),i=o.extend({},h),M.set(b,i))}}function ob(a,b){var c=a.getElementsByTagName?a.getElementsByTagName(b||"*"):a.querySelectorAll?a.querySelectorAll(b||"*"):[];return void 0===b||b&&o.nodeName(a,b)?o.merge([a],c):c}function pb(a,b){var c=b.nodeName.toLowerCase();"input"===c&&T.test(a.type)?b.checked=a.checked:("input"===c||"textarea"===c)&&(b.defaultValue=a.defaultValue)}o.extend({clone:function(a,b,c){var d,e,f,g,h=a.cloneNode(!0),i=o.contains(a.ownerDocument,a);if(!(l.noCloneChecked||1!==a.nodeType&&11!==a.nodeType||o.isXMLDoc(a)))for(g=ob(h),f=ob(a),d=0,e=f.length;e>d;d++)pb(f[d],g[d]);if(b)if(c)for(f=f||ob(a),g=g||ob(h),d=0,e=f.length;e>d;d++)nb(f[d],g[d]);else nb(a,h);return g=ob(h,"script"),g.length>0&&mb(g,!i&&ob(a,"script")),h},buildFragment:function(a,b,c,d){for(var e,f,g,h,i,j,k=b.createDocumentFragment(),l=[],m=0,n=a.length;n>m;m++)if(e=a[m],e||0===e)if("object"===o.type(e))o.merge(l,e.nodeType?[e]:e);else if(cb.test(e)){f=f||k.appendChild(b.createElement("div")),g=(bb.exec(e)||["",""])[1].toLowerCase(),h=ib[g]||ib._default,f.innerHTML=h[1]+e.replace(ab,"<$1></$2>")+h[2],j=h[0];while(j--)f=f.lastChild;o.merge(l,f.childNodes),f=k.firstChild,f.textContent=""}else l.push(b.createTextNode(e));k.textContent="",m=0;while(e=l[m++])if((!d||-1===o.inArray(e,d))&&(i=o.contains(e.ownerDocument,e),f=ob(k.appendChild(e),"script"),i&&mb(f),c)){j=0;while(e=f[j++])fb.test(e.type||"")&&c.push(e)}return k},cleanData:function(a){for(var b,c,d,e,f,g,h=o.event.special,i=0;void 0!==(c=a[i]);i++){if(o.acceptData(c)&&(f=c[L.expando],f&&(b=L.cache[f]))){if(d=Object.keys(b.events||{}),d.length)for(g=0;void 0!==(e=d[g]);g++)h[e]?o.event.remove(c,e):o.removeEvent(c,e,b.handle);L.cache[f]&&delete L.cache[f]}delete M.cache[c[M.expando]]}}}),o.fn.extend({text:function(a){return J(this,function(a){return void 0===a?o.text(this):this.empty().each(function(){(1===this.nodeType||11===this.nodeType||9===this.nodeType)&&(this.textContent=a)})},null,a,arguments.length)},append:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=jb(this,a);b.appendChild(a)}})},prepend:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=jb(this,a);b.insertBefore(a,b.firstChild)}})},before:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this)})},after:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this.nextSibling)})},remove:function(a,b){for(var c,d=a?o.filter(a,this):this,e=0;null!=(c=d[e]);e++)b||1!==c.nodeType||o.cleanData(ob(c)),c.parentNode&&(b&&o.contains(c.ownerDocument,c)&&mb(ob(c,"script")),c.parentNode.removeChild(c));return this},empty:function(){for(var a,b=0;null!=(a=this[b]);b++)1===a.nodeType&&(o.cleanData(ob(a,!1)),a.textContent="");return this},clone:function(a,b){return a=null==a?!1:a,b=null==b?a:b,this.map(function(){return o.clone(this,a,b)})},html:function(a){return J(this,function(a){var b=this[0]||{},c=0,d=this.length;if(void 0===a&&1===b.nodeType)return b.innerHTML;if("string"==typeof a&&!db.test(a)&&!ib[(bb.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(ab,"<$1></$2>");try{for(;d>c;c++)b=this[c]||{},1===b.nodeType&&(o.cleanData(ob(b,!1)),b.innerHTML=a);b=0}catch(e){}}b&&this.empty().append(a)},null,a,arguments.length)},replaceWith:function(){var a=arguments[0];return this.domManip(arguments,function(b){a=this.parentNode,o.cleanData(ob(this)),a&&a.replaceChild(b,this)}),a&&(a.length||a.nodeType)?this:this.remove()},detach:function(a){return this.remove(a,!0)},domManip:function(a,b){a=e.apply([],a);var c,d,f,g,h,i,j=0,k=this.length,m=this,n=k-1,p=a[0],q=o.isFunction(p);if(q||k>1&&"string"==typeof p&&!l.checkClone&&eb.test(p))return this.each(function(c){var d=m.eq(c);q&&(a[0]=p.call(this,c,d.html())),d.domManip(a,b)});if(k&&(c=o.buildFragment(a,this[0].ownerDocument,!1,this),d=c.firstChild,1===c.childNodes.length&&(c=d),d)){for(f=o.map(ob(c,"script"),kb),g=f.length;k>j;j++)h=c,j!==n&&(h=o.clone(h,!0,!0),g&&o.merge(f,ob(h,"script"))),b.call(this[j],h,j);if(g)for(i=f[f.length-1].ownerDocument,o.map(f,lb),j=0;g>j;j++)h=f[j],fb.test(h.type||"")&&!L.access(h,"globalEval")&&o.contains(i,h)&&(h.src?o._evalUrl&&o._evalUrl(h.src):o.globalEval(h.textContent.replace(hb,"")))}return this}}),o.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){o.fn[a]=function(a){for(var c,d=[],e=o(a),g=e.length-1,h=0;g>=h;h++)c=h===g?this:this.clone(!0),o(e[h])[b](c),f.apply(d,c.get());return this.pushStack(d)}});var qb,rb={};function sb(b,c){var d=o(c.createElement(b)).appendTo(c.body),e=a.getDefaultComputedStyle?a.getDefaultComputedStyle(d[0]).display:o.css(d[0],"display");return d.detach(),e}function tb(a){var b=m,c=rb[a];return c||(c=sb(a,b),"none"!==c&&c||(qb=(qb||o("<iframe frameborder='0' width='0' height='0'/>")).appendTo(b.documentElement),b=qb[0].contentDocument,b.write(),b.close(),c=sb(a,b),qb.detach()),rb[a]=c),c}var ub=/^margin/,vb=new RegExp("^("+Q+")(?!px)[a-z%]+$","i"),wb=function(a){return a.ownerDocument.defaultView.getComputedStyle(a,null)};function xb(a,b,c){var d,e,f,g,h=a.style;return c=c||wb(a),c&&(g=c.getPropertyValue(b)||c[b]),c&&(""!==g||o.contains(a.ownerDocument,a)||(g=o.style(a,b)),vb.test(g)&&ub.test(b)&&(d=h.width,e=h.minWidth,f=h.maxWidth,h.minWidth=h.maxWidth=h.width=g,g=c.width,h.width=d,h.minWidth=e,h.maxWidth=f)),void 0!==g?g+"":g}function yb(a,b){return{get:function(){return a()?void delete this.get:(this.get=b).apply(this,arguments)}}}!function(){var b,c,d="padding:0;margin:0;border:0;display:block;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box",e=m.documentElement,f=m.createElement("div"),g=m.createElement("div");g.style.backgroundClip="content-box",g.cloneNode(!0).style.backgroundClip="",l.clearCloneStyle="content-box"===g.style.backgroundClip,f.style.cssText="border:0;width:0;height:0;position:absolute;top:0;left:-9999px;margin-top:1px",f.appendChild(g);function h(){g.style.cssText="-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%",e.appendChild(f);var d=a.getComputedStyle(g,null);b="1%"!==d.top,c="4px"===d.width,e.removeChild(f)}a.getComputedStyle&&o.extend(l,{pixelPosition:function(){return h(),b},boxSizingReliable:function(){return null==c&&h(),c},reliableMarginRight:function(){var b,c=g.appendChild(m.createElement("div"));return c.style.cssText=g.style.cssText=d,c.style.marginRight=c.style.width="0",g.style.width="1px",e.appendChild(f),b=!parseFloat(a.getComputedStyle(c,null).marginRight),e.removeChild(f),g.innerHTML="",b}})}(),o.swap=function(a,b,c,d){var e,f,g={};for(f in b)g[f]=a.style[f],a.style[f]=b[f];e=c.apply(a,d||[]);for(f in b)a.style[f]=g[f];return e};var zb=/^(none|table(?!-c[ea]).+)/,Ab=new RegExp("^("+Q+")(.*)$","i"),Bb=new RegExp("^([+-])=("+Q+")","i"),Cb={position:"absolute",visibility:"hidden",display:"block"},Db={letterSpacing:0,fontWeight:400},Eb=["Webkit","O","Moz","ms"];function Fb(a,b){if(b in a)return b;var c=b[0].toUpperCase()+b.slice(1),d=b,e=Eb.length;while(e--)if(b=Eb[e]+c,b in a)return b;return d}function Gb(a,b,c){var d=Ab.exec(b);return d?Math.max(0,d[1]-(c||0))+(d[2]||"px"):b}function Hb(a,b,c,d,e){for(var f=c===(d?"border":"content")?4:"width"===b?1:0,g=0;4>f;f+=2)"margin"===c&&(g+=o.css(a,c+R[f],!0,e)),d?("content"===c&&(g-=o.css(a,"padding"+R[f],!0,e)),"margin"!==c&&(g-=o.css(a,"border"+R[f]+"Width",!0,e))):(g+=o.css(a,"padding"+R[f],!0,e),"padding"!==c&&(g+=o.css(a,"border"+R[f]+"Width",!0,e)));return g}function Ib(a,b,c){var d=!0,e="width"===b?a.offsetWidth:a.offsetHeight,f=wb(a),g="border-box"===o.css(a,"boxSizing",!1,f);if(0>=e||null==e){if(e=xb(a,b,f),(0>e||null==e)&&(e=a.style[b]),vb.test(e))return e;d=g&&(l.boxSizingReliable()||e===a.style[b]),e=parseFloat(e)||0}return e+Hb(a,b,c||(g?"border":"content"),d,f)+"px"}function Jb(a,b){for(var c,d,e,f=[],g=0,h=a.length;h>g;g++)d=a[g],d.style&&(f[g]=L.get(d,"olddisplay"),c=d.style.display,b?(f[g]||"none"!==c||(d.style.display=""),""===d.style.display&&S(d)&&(f[g]=L.access(d,"olddisplay",tb(d.nodeName)))):f[g]||(e=S(d),(c&&"none"!==c||!e)&&L.set(d,"olddisplay",e?c:o.css(d,"display"))));for(g=0;h>g;g++)d=a[g],d.style&&(b&&"none"!==d.style.display&&""!==d.style.display||(d.style.display=b?f[g]||"":"none"));return a}o.extend({cssHooks:{opacity:{get:function(a,b){if(b){var c=xb(a,"opacity");return""===c?"1":c}}}},cssNumber:{columnCount:!0,fillOpacity:!0,fontWeight:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":"cssFloat"},style:function(a,b,c,d){if(a&&3!==a.nodeType&&8!==a.nodeType&&a.style){var e,f,g,h=o.camelCase(b),i=a.style;return b=o.cssProps[h]||(o.cssProps[h]=Fb(i,h)),g=o.cssHooks[b]||o.cssHooks[h],void 0===c?g&&"get"in g&&void 0!==(e=g.get(a,!1,d))?e:i[b]:(f=typeof c,"string"===f&&(e=Bb.exec(c))&&(c=(e[1]+1)*e[2]+parseFloat(o.css(a,b)),f="number"),null!=c&&c===c&&("number"!==f||o.cssNumber[h]||(c+="px"),l.clearCloneStyle||""!==c||0!==b.indexOf("background")||(i[b]="inherit"),g&&"set"in g&&void 0===(c=g.set(a,c,d))||(i[b]="",i[b]=c)),void 0)}},css:function(a,b,c,d){var e,f,g,h=o.camelCase(b);return b=o.cssProps[h]||(o.cssProps[h]=Fb(a.style,h)),g=o.cssHooks[b]||o.cssHooks[h],g&&"get"in g&&(e=g.get(a,!0,c)),void 0===e&&(e=xb(a,b,d)),"normal"===e&&b in Db&&(e=Db[b]),""===c||c?(f=parseFloat(e),c===!0||o.isNumeric(f)?f||0:e):e}}),o.each(["height","width"],function(a,b){o.cssHooks[b]={get:function(a,c,d){return c?0===a.offsetWidth&&zb.test(o.css(a,"display"))?o.swap(a,Cb,function(){return Ib(a,b,d)}):Ib(a,b,d):void 0},set:function(a,c,d){var e=d&&wb(a);return Gb(a,c,d?Hb(a,b,d,"border-box"===o.css(a,"boxSizing",!1,e),e):0)}}}),o.cssHooks.marginRight=yb(l.reliableMarginRight,function(a,b){return b?o.swap(a,{display:"inline-block"},xb,[a,"marginRight"]):void 0}),o.each({margin:"",padding:"",border:"Width"},function(a,b){o.cssHooks[a+b]={expand:function(c){for(var d=0,e={},f="string"==typeof c?c.split(" "):[c];4>d;d++)e[a+R[d]+b]=f[d]||f[d-2]||f[0];return e}},ub.test(a)||(o.cssHooks[a+b].set=Gb)}),o.fn.extend({css:function(a,b){return J(this,function(a,b,c){var d,e,f={},g=0;if(o.isArray(b)){for(d=wb(a),e=b.length;e>g;g++)f[b[g]]=o.css(a,b[g],!1,d);return f}return void 0!==c?o.style(a,b,c):o.css(a,b)},a,b,arguments.length>1)},show:function(){return Jb(this,!0)},hide:function(){return Jb(this)},toggle:function(a){return"boolean"==typeof a?a?this.show():this.hide():this.each(function(){S(this)?o(this).show():o(this).hide()})}});function Kb(a,b,c,d,e){return new Kb.prototype.init(a,b,c,d,e)}o.Tween=Kb,Kb.prototype={constructor:Kb,init:function(a,b,c,d,e,f){this.elem=a,this.prop=c,this.easing=e||"swing",this.options=b,this.start=this.now=this.cur(),this.end=d,this.unit=f||(o.cssNumber[c]?"":"px")},cur:function(){var a=Kb.propHooks[this.prop];return a&&a.get?a.get(this):Kb.propHooks._default.get(this)},run:function(a){var b,c=Kb.propHooks[this.prop];return this.pos=b=this.options.duration?o.easing[this.easing](a,this.options.duration*a,0,1,this.options.duration):a,this.now=(this.end-this.start)*b+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),c&&c.set?c.set(this):Kb.propHooks._default.set(this),this}},Kb.prototype.init.prototype=Kb.prototype,Kb.propHooks={_default:{get:function(a){var b;return null==a.elem[a.prop]||a.elem.style&&null!=a.elem.style[a.prop]?(b=o.css(a.elem,a.prop,""),b&&"auto"!==b?b:0):a.elem[a.prop]},set:function(a){o.fx.step[a.prop]?o.fx.step[a.prop](a):a.elem.style&&(null!=a.elem.style[o.cssProps[a.prop]]||o.cssHooks[a.prop])?o.style(a.elem,a.prop,a.now+a.unit):a.elem[a.prop]=a.now}}},Kb.propHooks.scrollTop=Kb.propHooks.scrollLeft={set:function(a){a.elem.nodeType&&a.elem.parentNode&&(a.elem[a.prop]=a.now)}},o.easing={linear:function(a){return a},swing:function(a){return.5-Math.cos(a*Math.PI)/2}},o.fx=Kb.prototype.init,o.fx.step={};var Lb,Mb,Nb=/^(?:toggle|show|hide)$/,Ob=new RegExp("^(?:([+-])=|)("+Q+")([a-z%]*)$","i"),Pb=/queueHooks$/,Qb=[Vb],Rb={"*":[function(a,b){var c=this.createTween(a,b),d=c.cur(),e=Ob.exec(b),f=e&&e[3]||(o.cssNumber[a]?"":"px"),g=(o.cssNumber[a]||"px"!==f&&+d)&&Ob.exec(o.css(c.elem,a)),h=1,i=20;if(g&&g[3]!==f){f=f||g[3],e=e||[],g=+d||1;do h=h||".5",g/=h,o.style(c.elem,a,g+f);while(h!==(h=c.cur()/d)&&1!==h&&--i)}return e&&(g=c.start=+g||+d||0,c.unit=f,c.end=e[1]?g+(e[1]+1)*e[2]:+e[2]),c}]};function Sb(){return setTimeout(function(){Lb=void 0}),Lb=o.now()}function Tb(a,b){var c,d=0,e={height:a};for(b=b?1:0;4>d;d+=2-b)c=R[d],e["margin"+c]=e["padding"+c]=a;return b&&(e.opacity=e.width=a),e}function Ub(a,b,c){for(var d,e=(Rb[b]||[]).concat(Rb["*"]),f=0,g=e.length;g>f;f++)if(d=e[f].call(c,b,a))return d}function Vb(a,b,c){var d,e,f,g,h,i,j,k=this,l={},m=a.style,n=a.nodeType&&S(a),p=L.get(a,"fxshow");c.queue||(h=o._queueHooks(a,"fx"),null==h.unqueued&&(h.unqueued=0,i=h.empty.fire,h.empty.fire=function(){h.unqueued||i()}),h.unqueued++,k.always(function(){k.always(function(){h.unqueued--,o.queue(a,"fx").length||h.empty.fire()})})),1===a.nodeType&&("height"in b||"width"in b)&&(c.overflow=[m.overflow,m.overflowX,m.overflowY],j=o.css(a,"display"),"none"===j&&(j=tb(a.nodeName)),"inline"===j&&"none"===o.css(a,"float")&&(m.display="inline-block")),c.overflow&&(m.overflow="hidden",k.always(function(){m.overflow=c.overflow[0],m.overflowX=c.overflow[1],m.overflowY=c.overflow[2]}));for(d in b)if(e=b[d],Nb.exec(e)){if(delete b[d],f=f||"toggle"===e,e===(n?"hide":"show")){if("show"!==e||!p||void 0===p[d])continue;n=!0}l[d]=p&&p[d]||o.style(a,d)}if(!o.isEmptyObject(l)){p?"hidden"in p&&(n=p.hidden):p=L.access(a,"fxshow",{}),f&&(p.hidden=!n),n?o(a).show():k.done(function(){o(a).hide()}),k.done(function(){var b;L.remove(a,"fxshow");for(b in l)o.style(a,b,l[b])});for(d in l)g=Ub(n?p[d]:0,d,k),d in p||(p[d]=g.start,n&&(g.end=g.start,g.start="width"===d||"height"===d?1:0))}}function Wb(a,b){var c,d,e,f,g;for(c in a)if(d=o.camelCase(c),e=b[d],f=a[c],o.isArray(f)&&(e=f[1],f=a[c]=f[0]),c!==d&&(a[d]=f,delete a[c]),g=o.cssHooks[d],g&&"expand"in g){f=g.expand(f),delete a[d];for(c in f)c in a||(a[c]=f[c],b[c]=e)}else b[d]=e}function Xb(a,b,c){var d,e,f=0,g=Qb.length,h=o.Deferred().always(function(){delete i.elem}),i=function(){if(e)return!1;for(var b=Lb||Sb(),c=Math.max(0,j.startTime+j.duration-b),d=c/j.duration||0,f=1-d,g=0,i=j.tweens.length;i>g;g++)j.tweens[g].run(f);return h.notifyWith(a,[j,f,c]),1>f&&i?c:(h.resolveWith(a,[j]),!1)},j=h.promise({elem:a,props:o.extend({},b),opts:o.extend(!0,{specialEasing:{}},c),originalProperties:b,originalOptions:c,startTime:Lb||Sb(),duration:c.duration,tweens:[],createTween:function(b,c){var d=o.Tween(a,j.opts,b,c,j.opts.specialEasing[b]||j.opts.easing);return j.tweens.push(d),d},stop:function(b){var c=0,d=b?j.tweens.length:0;if(e)return this;for(e=!0;d>c;c++)j.tweens[c].run(1);return b?h.resolveWith(a,[j,b]):h.rejectWith(a,[j,b]),this}}),k=j.props;for(Wb(k,j.opts.specialEasing);g>f;f++)if(d=Qb[f].call(j,a,k,j.opts))return d;return o.map(k,Ub,j),o.isFunction(j.opts.start)&&j.opts.start.call(a,j),o.fx.timer(o.extend(i,{elem:a,anim:j,queue:j.opts.queue})),j.progress(j.opts.progress).done(j.opts.done,j.opts.complete).fail(j.opts.fail).always(j.opts.always)}o.Animation=o.extend(Xb,{tweener:function(a,b){o.isFunction(a)?(b=a,a=["*"]):a=a.split(" ");for(var c,d=0,e=a.length;e>d;d++)c=a[d],Rb[c]=Rb[c]||[],Rb[c].unshift(b)},prefilter:function(a,b){b?Qb.unshift(a):Qb.push(a)}}),o.speed=function(a,b,c){var d=a&&"object"==typeof a?o.extend({},a):{complete:c||!c&&b||o.isFunction(a)&&a,duration:a,easing:c&&b||b&&!o.isFunction(b)&&b};return d.duration=o.fx.off?0:"number"==typeof d.duration?d.duration:d.duration in o.fx.speeds?o.fx.speeds[d.duration]:o.fx.speeds._default,(null==d.queue||d.queue===!0)&&(d.queue="fx"),d.old=d.complete,d.complete=function(){o.isFunction(d.old)&&d.old.call(this),d.queue&&o.dequeue(this,d.queue)},d},o.fn.extend({fadeTo:function(a,b,c,d){return this.filter(S).css("opacity",0).show().end().animate({opacity:b},a,c,d)},animate:function(a,b,c,d){var e=o.isEmptyObject(a),f=o.speed(b,c,d),g=function(){var b=Xb(this,o.extend({},a),f);(e||L.get(this,"finish"))&&b.stop(!0)};return g.finish=g,e||f.queue===!1?this.each(g):this.queue(f.queue,g)},stop:function(a,b,c){var d=function(a){var b=a.stop;delete a.stop,b(c)};return"string"!=typeof a&&(c=b,b=a,a=void 0),b&&a!==!1&&this.queue(a||"fx",[]),this.each(function(){var b=!0,e=null!=a&&a+"queueHooks",f=o.timers,g=L.get(this);if(e)g[e]&&g[e].stop&&d(g[e]);else for(e in g)g[e]&&g[e].stop&&Pb.test(e)&&d(g[e]);for(e=f.length;e--;)f[e].elem!==this||null!=a&&f[e].queue!==a||(f[e].anim.stop(c),b=!1,f.splice(e,1));(b||!c)&&o.dequeue(this,a)})},finish:function(a){return a!==!1&&(a=a||"fx"),this.each(function(){var b,c=L.get(this),d=c[a+"queue"],e=c[a+"queueHooks"],f=o.timers,g=d?d.length:0;for(c.finish=!0,o.queue(this,a,[]),e&&e.stop&&e.stop.call(this,!0),b=f.length;b--;)f[b].elem===this&&f[b].queue===a&&(f[b].anim.stop(!0),f.splice(b,1));for(b=0;g>b;b++)d[b]&&d[b].finish&&d[b].finish.call(this);delete c.finish})}}),o.each(["toggle","show","hide"],function(a,b){var c=o.fn[b];o.fn[b]=function(a,d,e){return null==a||"boolean"==typeof a?c.apply(this,arguments):this.animate(Tb(b,!0),a,d,e)}}),o.each({slideDown:Tb("show"),slideUp:Tb("hide"),slideToggle:Tb("toggle"),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(a,b){o.fn[a]=function(a,c,d){return this.animate(b,a,c,d)}}),o.timers=[],o.fx.tick=function(){var a,b=0,c=o.timers;for(Lb=o.now();b<c.length;b++)a=c[b],a()||c[b]!==a||c.splice(b--,1);c.length||o.fx.stop(),Lb=void 0},o.fx.timer=function(a){o.timers.push(a),a()?o.fx.start():o.timers.pop()},o.fx.interval=13,o.fx.start=function(){Mb||(Mb=setInterval(o.fx.tick,o.fx.interval))},o.fx.stop=function(){clearInterval(Mb),Mb=null},o.fx.speeds={slow:600,fast:200,_default:400},o.fn.delay=function(a,b){return a=o.fx?o.fx.speeds[a]||a:a,b=b||"fx",this.queue(b,function(b,c){var d=setTimeout(b,a);c.stop=function(){clearTimeout(d)}})},function(){var a=m.createElement("input"),b=m.createElement("select"),c=b.appendChild(m.createElement("option"));a.type="checkbox",l.checkOn=""!==a.value,l.optSelected=c.selected,b.disabled=!0,l.optDisabled=!c.disabled,a=m.createElement("input"),a.value="t",a.type="radio",l.radioValue="t"===a.value}();var Yb,Zb,$b=o.expr.attrHandle;o.fn.extend({attr:function(a,b){return J(this,o.attr,a,b,arguments.length>1)},removeAttr:function(a){return this.each(function(){o.removeAttr(this,a)})}}),o.extend({attr:function(a,b,c){var d,e,f=a.nodeType;if(a&&3!==f&&8!==f&&2!==f)return typeof a.getAttribute===U?o.prop(a,b,c):(1===f&&o.isXMLDoc(a)||(b=b.toLowerCase(),d=o.attrHooks[b]||(o.expr.match.bool.test(b)?Zb:Yb)),void 0===c?d&&"get"in d&&null!==(e=d.get(a,b))?e:(e=o.find.attr(a,b),null==e?void 0:e):null!==c?d&&"set"in d&&void 0!==(e=d.set(a,c,b))?e:(a.setAttribute(b,c+""),c):void o.removeAttr(a,b))},removeAttr:function(a,b){var c,d,e=0,f=b&&b.match(E);if(f&&1===a.nodeType)while(c=f[e++])d=o.propFix[c]||c,o.expr.match.bool.test(c)&&(a[d]=!1),a.removeAttribute(c)},attrHooks:{type:{set:function(a,b){if(!l.radioValue&&"radio"===b&&o.nodeName(a,"input")){var c=a.value;return a.setAttribute("type",b),c&&(a.value=c),b}}}}}),Zb={set:function(a,b,c){return b===!1?o.removeAttr(a,c):a.setAttribute(c,c),c}},o.each(o.expr.match.bool.source.match(/\w+/g),function(a,b){var c=$b[b]||o.find.attr;$b[b]=function(a,b,d){var e,f;
+return d||(f=$b[b],$b[b]=e,e=null!=c(a,b,d)?b.toLowerCase():null,$b[b]=f),e}});var _b=/^(?:input|select|textarea|button)$/i;o.fn.extend({prop:function(a,b){return J(this,o.prop,a,b,arguments.length>1)},removeProp:function(a){return this.each(function(){delete this[o.propFix[a]||a]})}}),o.extend({propFix:{"for":"htmlFor","class":"className"},prop:function(a,b,c){var d,e,f,g=a.nodeType;if(a&&3!==g&&8!==g&&2!==g)return f=1!==g||!o.isXMLDoc(a),f&&(b=o.propFix[b]||b,e=o.propHooks[b]),void 0!==c?e&&"set"in e&&void 0!==(d=e.set(a,c,b))?d:a[b]=c:e&&"get"in e&&null!==(d=e.get(a,b))?d:a[b]},propHooks:{tabIndex:{get:function(a){return a.hasAttribute("tabindex")||_b.test(a.nodeName)||a.href?a.tabIndex:-1}}}}),l.optSelected||(o.propHooks.selected={get:function(a){var b=a.parentNode;return b&&b.parentNode&&b.parentNode.selectedIndex,null}}),o.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){o.propFix[this.toLowerCase()]=this});var ac=/[\t\r\n\f]/g;o.fn.extend({addClass:function(a){var b,c,d,e,f,g,h="string"==typeof a&&a,i=0,j=this.length;if(o.isFunction(a))return this.each(function(b){o(this).addClass(a.call(this,b,this.className))});if(h)for(b=(a||"").match(E)||[];j>i;i++)if(c=this[i],d=1===c.nodeType&&(c.className?(" "+c.className+" ").replace(ac," "):" ")){f=0;while(e=b[f++])d.indexOf(" "+e+" ")<0&&(d+=e+" ");g=o.trim(d),c.className!==g&&(c.className=g)}return this},removeClass:function(a){var b,c,d,e,f,g,h=0===arguments.length||"string"==typeof a&&a,i=0,j=this.length;if(o.isFunction(a))return this.each(function(b){o(this).removeClass(a.call(this,b,this.className))});if(h)for(b=(a||"").match(E)||[];j>i;i++)if(c=this[i],d=1===c.nodeType&&(c.className?(" "+c.className+" ").replace(ac," "):"")){f=0;while(e=b[f++])while(d.indexOf(" "+e+" ")>=0)d=d.replace(" "+e+" "," ");g=a?o.trim(d):"",c.className!==g&&(c.className=g)}return this},toggleClass:function(a,b){var c=typeof a;return"boolean"==typeof b&&"string"===c?b?this.addClass(a):this.removeClass(a):this.each(o.isFunction(a)?function(c){o(this).toggleClass(a.call(this,c,this.className,b),b)}:function(){if("string"===c){var b,d=0,e=o(this),f=a.match(E)||[];while(b=f[d++])e.hasClass(b)?e.removeClass(b):e.addClass(b)}else(c===U||"boolean"===c)&&(this.className&&L.set(this,"__className__",this.className),this.className=this.className||a===!1?"":L.get(this,"__className__")||"")})},hasClass:function(a){for(var b=" "+a+" ",c=0,d=this.length;d>c;c++)if(1===this[c].nodeType&&(" "+this[c].className+" ").replace(ac," ").indexOf(b)>=0)return!0;return!1}});var bc=/\r/g;o.fn.extend({val:function(a){var b,c,d,e=this[0];{if(arguments.length)return d=o.isFunction(a),this.each(function(c){var e;1===this.nodeType&&(e=d?a.call(this,c,o(this).val()):a,null==e?e="":"number"==typeof e?e+="":o.isArray(e)&&(e=o.map(e,function(a){return null==a?"":a+""})),b=o.valHooks[this.type]||o.valHooks[this.nodeName.toLowerCase()],b&&"set"in b&&void 0!==b.set(this,e,"value")||(this.value=e))});if(e)return b=o.valHooks[e.type]||o.valHooks[e.nodeName.toLowerCase()],b&&"get"in b&&void 0!==(c=b.get(e,"value"))?c:(c=e.value,"string"==typeof c?c.replace(bc,""):null==c?"":c)}}}),o.extend({valHooks:{select:{get:function(a){for(var b,c,d=a.options,e=a.selectedIndex,f="select-one"===a.type||0>e,g=f?null:[],h=f?e+1:d.length,i=0>e?h:f?e:0;h>i;i++)if(c=d[i],!(!c.selected&&i!==e||(l.optDisabled?c.disabled:null!==c.getAttribute("disabled"))||c.parentNode.disabled&&o.nodeName(c.parentNode,"optgroup"))){if(b=o(c).val(),f)return b;g.push(b)}return g},set:function(a,b){var c,d,e=a.options,f=o.makeArray(b),g=e.length;while(g--)d=e[g],(d.selected=o.inArray(o(d).val(),f)>=0)&&(c=!0);return c||(a.selectedIndex=-1),f}}}}),o.each(["radio","checkbox"],function(){o.valHooks[this]={set:function(a,b){return o.isArray(b)?a.checked=o.inArray(o(a).val(),b)>=0:void 0}},l.checkOn||(o.valHooks[this].get=function(a){return null===a.getAttribute("value")?"on":a.value})}),o.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error contextmenu".split(" "),function(a,b){o.fn[b]=function(a,c){return arguments.length>0?this.on(b,null,a,c):this.trigger(b)}}),o.fn.extend({hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)},bind:function(a,b,c){return this.on(a,null,b,c)},unbind:function(a,b){return this.off(a,null,b)},delegate:function(a,b,c,d){return this.on(b,a,c,d)},undelegate:function(a,b,c){return 1===arguments.length?this.off(a,"**"):this.off(b,a||"**",c)}});var cc=o.now(),dc=/\?/;o.parseJSON=function(a){return JSON.parse(a+"")},o.parseXML=function(a){var b,c;if(!a||"string"!=typeof a)return null;try{c=new DOMParser,b=c.parseFromString(a,"text/xml")}catch(d){b=void 0}return(!b||b.getElementsByTagName("parsererror").length)&&o.error("Invalid XML: "+a),b};var ec,fc,gc=/#.*$/,hc=/([?&])_=[^&]*/,ic=/^(.*?):[ \t]*([^\r\n]*)$/gm,jc=/^(?:about|app|app-storage|.+-extension|file|res|widget):$/,kc=/^(?:GET|HEAD)$/,lc=/^\/\//,mc=/^([\w.+-]+:)(?:\/\/(?:[^\/?#]*@|)([^\/?#:]*)(?::(\d+)|)|)/,nc={},oc={},pc="*/".concat("*");try{fc=location.href}catch(qc){fc=m.createElement("a"),fc.href="",fc=fc.href}ec=mc.exec(fc.toLowerCase())||[];function rc(a){return function(b,c){"string"!=typeof b&&(c=b,b="*");var d,e=0,f=b.toLowerCase().match(E)||[];if(o.isFunction(c))while(d=f[e++])"+"===d[0]?(d=d.slice(1)||"*",(a[d]=a[d]||[]).unshift(c)):(a[d]=a[d]||[]).push(c)}}function sc(a,b,c,d){var e={},f=a===oc;function g(h){var i;return e[h]=!0,o.each(a[h]||[],function(a,h){var j=h(b,c,d);return"string"!=typeof j||f||e[j]?f?!(i=j):void 0:(b.dataTypes.unshift(j),g(j),!1)}),i}return g(b.dataTypes[0])||!e["*"]&&g("*")}function tc(a,b){var c,d,e=o.ajaxSettings.flatOptions||{};for(c in b)void 0!==b[c]&&((e[c]?a:d||(d={}))[c]=b[c]);return d&&o.extend(!0,a,d),a}function uc(a,b,c){var d,e,f,g,h=a.contents,i=a.dataTypes;while("*"===i[0])i.shift(),void 0===d&&(d=a.mimeType||b.getResponseHeader("Content-Type"));if(d)for(e in h)if(h[e]&&h[e].test(d)){i.unshift(e);break}if(i[0]in c)f=i[0];else{for(e in c){if(!i[0]||a.converters[e+" "+i[0]]){f=e;break}g||(g=e)}f=f||g}return f?(f!==i[0]&&i.unshift(f),c[f]):void 0}function vc(a,b,c,d){var e,f,g,h,i,j={},k=a.dataTypes.slice();if(k[1])for(g in a.converters)j[g.toLowerCase()]=a.converters[g];f=k.shift();while(f)if(a.responseFields[f]&&(c[a.responseFields[f]]=b),!i&&d&&a.dataFilter&&(b=a.dataFilter(b,a.dataType)),i=f,f=k.shift())if("*"===f)f=i;else if("*"!==i&&i!==f){if(g=j[i+" "+f]||j["* "+f],!g)for(e in j)if(h=e.split(" "),h[1]===f&&(g=j[i+" "+h[0]]||j["* "+h[0]])){g===!0?g=j[e]:j[e]!==!0&&(f=h[0],k.unshift(h[1]));break}if(g!==!0)if(g&&a["throws"])b=g(b);else try{b=g(b)}catch(l){return{state:"parsererror",error:g?l:"No conversion from "+i+" to "+f}}}return{state:"success",data:b}}o.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:fc,type:"GET",isLocal:jc.test(ec[1]),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":pc,text:"text/plain",html:"text/html",xml:"application/xml, text/xml",json:"application/json, text/javascript"},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText",json:"responseJSON"},converters:{"* text":String,"text html":!0,"text json":o.parseJSON,"text xml":o.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(a,b){return b?tc(tc(a,o.ajaxSettings),b):tc(o.ajaxSettings,a)},ajaxPrefilter:rc(nc),ajaxTransport:rc(oc),ajax:function(a,b){"object"==typeof a&&(b=a,a=void 0),b=b||{};var c,d,e,f,g,h,i,j,k=o.ajaxSetup({},b),l=k.context||k,m=k.context&&(l.nodeType||l.jquery)?o(l):o.event,n=o.Deferred(),p=o.Callbacks("once memory"),q=k.statusCode||{},r={},s={},t=0,u="canceled",v={readyState:0,getResponseHeader:function(a){var b;if(2===t){if(!f){f={};while(b=ic.exec(e))f[b[1].toLowerCase()]=b[2]}b=f[a.toLowerCase()]}return null==b?null:b},getAllResponseHeaders:function(){return 2===t?e:null},setRequestHeader:function(a,b){var c=a.toLowerCase();return t||(a=s[c]=s[c]||a,r[a]=b),this},overrideMimeType:function(a){return t||(k.mimeType=a),this},statusCode:function(a){var b;if(a)if(2>t)for(b in a)q[b]=[q[b],a[b]];else v.always(a[v.status]);return this},abort:function(a){var b=a||u;return c&&c.abort(b),x(0,b),this}};if(n.promise(v).complete=p.add,v.success=v.done,v.error=v.fail,k.url=((a||k.url||fc)+"").replace(gc,"").replace(lc,ec[1]+"//"),k.type=b.method||b.type||k.method||k.type,k.dataTypes=o.trim(k.dataType||"*").toLowerCase().match(E)||[""],null==k.crossDomain&&(h=mc.exec(k.url.toLowerCase()),k.crossDomain=!(!h||h[1]===ec[1]&&h[2]===ec[2]&&(h[3]||("http:"===h[1]?"80":"443"))===(ec[3]||("http:"===ec[1]?"80":"443")))),k.data&&k.processData&&"string"!=typeof k.data&&(k.data=o.param(k.data,k.traditional)),sc(nc,k,b,v),2===t)return v;i=k.global,i&&0===o.active++&&o.event.trigger("ajaxStart"),k.type=k.type.toUpperCase(),k.hasContent=!kc.test(k.type),d=k.url,k.hasContent||(k.data&&(d=k.url+=(dc.test(d)?"&":"?")+k.data,delete k.data),k.cache===!1&&(k.url=hc.test(d)?d.replace(hc,"$1_="+cc++):d+(dc.test(d)?"&":"?")+"_="+cc++)),k.ifModified&&(o.lastModified[d]&&v.setRequestHeader("If-Modified-Since",o.lastModified[d]),o.etag[d]&&v.setRequestHeader("If-None-Match",o.etag[d])),(k.data&&k.hasContent&&k.contentType!==!1||b.contentType)&&v.setRequestHeader("Content-Type",k.contentType),v.setRequestHeader("Accept",k.dataTypes[0]&&k.accepts[k.dataTypes[0]]?k.accepts[k.dataTypes[0]]+("*"!==k.dataTypes[0]?", "+pc+"; q=0.01":""):k.accepts["*"]);for(j in k.headers)v.setRequestHeader(j,k.headers[j]);if(k.beforeSend&&(k.beforeSend.call(l,v,k)===!1||2===t))return v.abort();u="abort";for(j in{success:1,error:1,complete:1})v[j](k[j]);if(c=sc(oc,k,b,v)){v.readyState=1,i&&m.trigger("ajaxSend",[v,k]),k.async&&k.timeout>0&&(g=setTimeout(function(){v.abort("timeout")},k.timeout));try{t=1,c.send(r,x)}catch(w){if(!(2>t))throw w;x(-1,w)}}else x(-1,"No Transport");function x(a,b,f,h){var j,r,s,u,w,x=b;2!==t&&(t=2,g&&clearTimeout(g),c=void 0,e=h||"",v.readyState=a>0?4:0,j=a>=200&&300>a||304===a,f&&(u=uc(k,v,f)),u=vc(k,u,v,j),j?(k.ifModified&&(w=v.getResponseHeader("Last-Modified"),w&&(o.lastModified[d]=w),w=v.getResponseHeader("etag"),w&&(o.etag[d]=w)),204===a||"HEAD"===k.type?x="nocontent":304===a?x="notmodified":(x=u.state,r=u.data,s=u.error,j=!s)):(s=x,(a||!x)&&(x="error",0>a&&(a=0))),v.status=a,v.statusText=(b||x)+"",j?n.resolveWith(l,[r,x,v]):n.rejectWith(l,[v,x,s]),v.statusCode(q),q=void 0,i&&m.trigger(j?"ajaxSuccess":"ajaxError",[v,k,j?r:s]),p.fireWith(l,[v,x]),i&&(m.trigger("ajaxComplete",[v,k]),--o.active||o.event.trigger("ajaxStop")))}return v},getJSON:function(a,b,c){return o.get(a,b,c,"json")},getScript:function(a,b){return o.get(a,void 0,b,"script")}}),o.each(["get","post"],function(a,b){o[b]=function(a,c,d,e){return o.isFunction(c)&&(e=e||d,d=c,c=void 0),o.ajax({url:a,type:b,dataType:e,data:c,success:d})}}),o.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(a,b){o.fn[b]=function(a){return this.on(b,a)}}),o._evalUrl=function(a){return o.ajax({url:a,type:"GET",dataType:"script",async:!1,global:!1,"throws":!0})},o.fn.extend({wrapAll:function(a){var b;return o.isFunction(a)?this.each(function(b){o(this).wrapAll(a.call(this,b))}):(this[0]&&(b=o(a,this[0].ownerDocument).eq(0).clone(!0),this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstElementChild)a=a.firstElementChild;return a}).append(this)),this)},wrapInner:function(a){return this.each(o.isFunction(a)?function(b){o(this).wrapInner(a.call(this,b))}:function(){var b=o(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){var b=o.isFunction(a);return this.each(function(c){o(this).wrapAll(b?a.call(this,c):a)})},unwrap:function(){return this.parent().each(function(){o.nodeName(this,"body")||o(this).replaceWith(this.childNodes)}).end()}}),o.expr.filters.hidden=function(a){return a.offsetWidth<=0&&a.offsetHeight<=0},o.expr.filters.visible=function(a){return!o.expr.filters.hidden(a)};var wc=/%20/g,xc=/\[\]$/,yc=/\r?\n/g,zc=/^(?:submit|button|image|reset|file)$/i,Ac=/^(?:input|select|textarea|keygen)/i;function Bc(a,b,c,d){var e;if(o.isArray(b))o.each(b,function(b,e){c||xc.test(a)?d(a,e):Bc(a+"["+("object"==typeof e?b:"")+"]",e,c,d)});else if(c||"object"!==o.type(b))d(a,b);else for(e in b)Bc(a+"["+e+"]",b[e],c,d)}o.param=function(a,b){var c,d=[],e=function(a,b){b=o.isFunction(b)?b():null==b?"":b,d[d.length]=encodeURIComponent(a)+"="+encodeURIComponent(b)};if(void 0===b&&(b=o.ajaxSettings&&o.ajaxSettings.traditional),o.isArray(a)||a.jquery&&!o.isPlainObject(a))o.each(a,function(){e(this.name,this.value)});else for(c in a)Bc(c,a[c],b,e);return d.join("&").replace(wc,"+")},o.fn.extend({serialize:function(){return o.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var a=o.prop(this,"elements");return a?o.makeArray(a):this}).filter(function(){var a=this.type;return this.name&&!o(this).is(":disabled")&&Ac.test(this.nodeName)&&!zc.test(a)&&(this.checked||!T.test(a))}).map(function(a,b){var c=o(this).val();return null==c?null:o.isArray(c)?o.map(c,function(a){return{name:b.name,value:a.replace(yc,"\r\n")}}):{name:b.name,value:c.replace(yc,"\r\n")}}).get()}}),o.ajaxSettings.xhr=function(){try{return new XMLHttpRequest}catch(a){}};var Cc=0,Dc={},Ec={0:200,1223:204},Fc=o.ajaxSettings.xhr();a.ActiveXObject&&o(a).on("unload",function(){for(var a in Dc)Dc[a]()}),l.cors=!!Fc&&"withCredentials"in Fc,l.ajax=Fc=!!Fc,o.ajaxTransport(function(a){var b;return l.cors||Fc&&!a.crossDomain?{send:function(c,d){var e,f=a.xhr(),g=++Cc;if(f.open(a.type,a.url,a.async,a.username,a.password),a.xhrFields)for(e in a.xhrFields)f[e]=a.xhrFields[e];a.mimeType&&f.overrideMimeType&&f.overrideMimeType(a.mimeType),a.crossDomain||c["X-Requested-With"]||(c["X-Requested-With"]="XMLHttpRequest");for(e in c)f.setRequestHeader(e,c[e]);b=function(a){return function(){b&&(delete Dc[g],b=f.onload=f.onerror=null,"abort"===a?f.abort():"error"===a?d(f.status,f.statusText):d(Ec[f.status]||f.status,f.statusText,"string"==typeof f.responseText?{text:f.responseText}:void 0,f.getAllResponseHeaders()))}},f.onload=b(),f.onerror=b("error"),b=Dc[g]=b("abort"),f.send(a.hasContent&&a.data||null)},abort:function(){b&&b()}}:void 0}),o.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/(?:java|ecma)script/},converters:{"text script":function(a){return o.globalEval(a),a}}}),o.ajaxPrefilter("script",function(a){void 0===a.cache&&(a.cache=!1),a.crossDomain&&(a.type="GET")}),o.ajaxTransport("script",function(a){if(a.crossDomain){var b,c;return{send:function(d,e){b=o("<script>").prop({async:!0,charset:a.scriptCharset,src:a.url}).on("load error",c=function(a){b.remove(),c=null,a&&e("error"===a.type?404:200,a.type)}),m.head.appendChild(b[0])},abort:function(){c&&c()}}}});var Gc=[],Hc=/(=)\?(?=&|$)|\?\?/;o.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var a=Gc.pop()||o.expando+"_"+cc++;return this[a]=!0,a}}),o.ajaxPrefilter("json jsonp",function(b,c,d){var e,f,g,h=b.jsonp!==!1&&(Hc.test(b.url)?"url":"string"==typeof b.data&&!(b.contentType||"").indexOf("application/x-www-form-urlencoded")&&Hc.test(b.data)&&"data");return h||"jsonp"===b.dataTypes[0]?(e=b.jsonpCallback=o.isFunction(b.jsonpCallback)?b.jsonpCallback():b.jsonpCallback,h?b[h]=b[h].replace(Hc,"$1"+e):b.jsonp!==!1&&(b.url+=(dc.test(b.url)?"&":"?")+b.jsonp+"="+e),b.converters["script json"]=function(){return g||o.error(e+" was not called"),g[0]},b.dataTypes[0]="json",f=a[e],a[e]=function(){g=arguments},d.always(function(){a[e]=f,b[e]&&(b.jsonpCallback=c.jsonpCallback,Gc.push(e)),g&&o.isFunction(f)&&f(g[0]),g=f=void 0}),"script"):void 0}),o.parseHTML=function(a,b,c){if(!a||"string"!=typeof a)return null;"boolean"==typeof b&&(c=b,b=!1),b=b||m;var d=v.exec(a),e=!c&&[];return d?[b.createElement(d[1])]:(d=o.buildFragment([a],b,e),e&&e.length&&o(e).remove(),o.merge([],d.childNodes))};var Ic=o.fn.load;o.fn.load=function(a,b,c){if("string"!=typeof a&&Ic)return Ic.apply(this,arguments);var d,e,f,g=this,h=a.indexOf(" ");return h>=0&&(d=a.slice(h),a=a.slice(0,h)),o.isFunction(b)?(c=b,b=void 0):b&&"object"==typeof b&&(e="POST"),g.length>0&&o.ajax({url:a,type:e,dataType:"html",data:b}).done(function(a){f=arguments,g.html(d?o("<div>").append(o.parseHTML(a)).find(d):a)}).complete(c&&function(a,b){g.each(c,f||[a.responseText,b,a])}),this},o.expr.filters.animated=function(a){return o.grep(o.timers,function(b){return a===b.elem}).length};var Jc=a.document.documentElement;function Kc(a){return o.isWindow(a)?a:9===a.nodeType&&a.defaultView}o.offset={setOffset:function(a,b,c){var d,e,f,g,h,i,j,k=o.css(a,"position"),l=o(a),m={};"static"===k&&(a.style.position="relative"),h=l.offset(),f=o.css(a,"top"),i=o.css(a,"left"),j=("absolute"===k||"fixed"===k)&&(f+i).indexOf("auto")>-1,j?(d=l.position(),g=d.top,e=d.left):(g=parseFloat(f)||0,e=parseFloat(i)||0),o.isFunction(b)&&(b=b.call(a,c,h)),null!=b.top&&(m.top=b.top-h.top+g),null!=b.left&&(m.left=b.left-h.left+e),"using"in b?b.using.call(a,m):l.css(m)}},o.fn.extend({offset:function(a){if(arguments.length)return void 0===a?this:this.each(function(b){o.offset.setOffset(this,a,b)});var b,c,d=this[0],e={top:0,left:0},f=d&&d.ownerDocument;if(f)return b=f.documentElement,o.contains(b,d)?(typeof d.getBoundingClientRect!==U&&(e=d.getBoundingClientRect()),c=Kc(f),{top:e.top+c.pageYOffset-b.clientTop,left:e.left+c.pageXOffset-b.clientLeft}):e},position:function(){if(this[0]){var a,b,c=this[0],d={top:0,left:0};return"fixed"===o.css(c,"position")?b=c.getBoundingClientRect():(a=this.offsetParent(),b=this.offset(),o.nodeName(a[0],"html")||(d=a.offset()),d.top+=o.css(a[0],"borderTopWidth",!0),d.left+=o.css(a[0],"borderLeftWidth",!0)),{top:b.top-d.top-o.css(c,"marginTop",!0),left:b.left-d.left-o.css(c,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var a=this.offsetParent||Jc;while(a&&!o.nodeName(a,"html")&&"static"===o.css(a,"position"))a=a.offsetParent;return a||Jc})}}),o.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(b,c){var d="pageYOffset"===c;o.fn[b]=function(e){return J(this,function(b,e,f){var g=Kc(b);return void 0===f?g?g[c]:b[e]:void(g?g.scrollTo(d?a.pageXOffset:f,d?f:a.pageYOffset):b[e]=f)},b,e,arguments.length,null)}}),o.each(["top","left"],function(a,b){o.cssHooks[b]=yb(l.pixelPosition,function(a,c){return c?(c=xb(a,b),vb.test(c)?o(a).position()[b]+"px":c):void 0})}),o.each({Height:"height",Width:"width"},function(a,b){o.each({padding:"inner"+a,content:b,"":"outer"+a},function(c,d){o.fn[d]=function(d,e){var f=arguments.length&&(c||"boolean"!=typeof d),g=c||(d===!0||e===!0?"margin":"border");return J(this,function(b,c,d){var e;return o.isWindow(b)?b.document.documentElement["client"+a]:9===b.nodeType?(e=b.documentElement,Math.max(b.body["scroll"+a],e["scroll"+a],b.body["offset"+a],e["offset"+a],e["client"+a])):void 0===d?o.css(b,c,g):o.style(b,c,d,g)},b,f?d:void 0,f,null)}})}),o.fn.size=function(){return this.length},o.fn.andSelf=o.fn.addBack,"function"==typeof define&&define.amd&&define("jquery",[],function(){return o});var Lc=a.jQuery,Mc=a.$;return o.noConflict=function(b){return a.$===o&&(a.$=Mc),b&&a.jQuery===o&&(a.jQuery=Lc),o},typeof b===U&&(a.jQuery=a.$=o),o});
--- /dev/null
+/*
+ * Jquery plugin for unified mouse and touch events
+ *
+ * Copyright (c) 2013 Michael S. Mikowski
+ * (mike[dot]mikowski[at]gmail[dotcom])
+ *
+ * Dual licensed under the MIT or GPL Version 2
+ * http://jquery.org/license
+ *
+ * Versions
+ * 0.3.0 - Initial jQuery plugin site release
+ * - Replaced scrollwheel zoom with drag motion.
+ * This resolved a conflict with scrollable areas.
+ * 0.3.1 - Change for jQuery plugins site
+ * 0.3.2 - Updated to jQuery 1.9.1.
+ * Confirmed 1.7.0-1.9.1 compatibility.
+ * 0.4.2 - Updated documentation
+ * 0.4.3 - Removed fatal execption possibility if originalEvent
+ * is not defined on event object
+ *
+*/
+
+/*jslint browser : true, continue : true,
+ devel : true, indent : 2, maxerr : 50,
+ newcap : true, plusplus : true, regexp : true,
+ sloppy : true, vars : true, white : true
+*/
+/*global jQuery, sl */
+
+(function ( $ ) {
+ //---------------- BEGIN MODULE SCOPE VARIABLES --------------
+ var
+ $Special = $.event.special, // shortcut for special event
+ motionMapMap = {}, // map of pointer motions by cursor
+ isMoveBound = false, // flag if move handlers bound
+ pxPinchZoom = -1, // distance between pinch-zoom points
+ optionKey = 'ue_bound', // data key for storing options
+ doDisableMouse = false, // flag to discard mouse input
+ defaultOptMap = { // Default option hash
+ bound_ns_map : {}, // namspace hash e.g. bound_ns_map.utap.fred
+ wheel_ratio : 15, // multiplier for mousewheel delta
+ px_radius : 3, // 'distance' dragged before dragstart
+ ignore_class : ':input', // 'not' suppress matching elements
+ tap_time : 200, // millisecond max time to consider tap
+ held_tap_time : 300 // millisecond min time to consider taphold
+ },
+ callbackList = [], // global callback stack
+ zoomMouseNum = 1, // multiplier for mouse zoom
+ zoomTouchNum = 4, // multiplier for touch zoom
+
+ boundList, Ue,
+ motionDragId, motionHeldId, motionDzoomId,
+ motion1ZoomId, motion2ZoomId,
+
+ checkMatchVal, removeListVal, pushUniqVal, makeListPlus,
+ fnHeld, fnMotionStart, fnMotionMove,
+ fnMotionEnd, onMouse, onTouch,
+ onMousewheel
+ ;
+ //----------------- END MODULE SCOPE VARIABLES ---------------
+
+ //------------------- BEGIN UTILITY METHODS ------------------
+ // Begin utiltity /makeListPlus/
+ // Returns an array with much desired methods:
+ // * remove_val(value) : remove element that matches
+ // the provided value. Returns number of elements
+ // removed.
+ // * match_val(value) : shows if a value exists
+ // * push_uniq(value) : pushes a value onto the stack
+ // iff it does not already exist there
+ // Note: the reason I need this is to compare objects to
+ // objects (perhaps jQuery has something similar?)
+ checkMatchVal = function ( data ) {
+ var match_count = 0, idx;
+ for ( idx = this.length; idx; 0 ) {
+ if ( this[--idx] === data ) { match_count++; }
+ }
+ return match_count;
+ };
+ removeListVal = function ( data ) {
+ var removed_count = 0, idx;
+ for ( idx = this.length; idx; 0 ) {
+ if ( this[--idx] === data ) {
+ this.splice(idx, 1);
+ removed_count++;
+ idx++;
+ }
+ }
+ return removed_count;
+ };
+ pushUniqVal = function ( data ) {
+ if ( checkMatchVal.call(this, data ) ) { return false; }
+ this.push( data );
+ return true;
+ };
+ // primary utility
+ makeListPlus = function ( input_list ) {
+ if ( input_list && $.isArray(input_list) ) {
+ if ( input_list.remove_val ) {
+ console.warn( 'The array appears to already have listPlus capabilities' );
+ return input_list;
+ }
+ }
+ else {
+ input_list = [];
+ }
+ input_list.remove_val = removeListVal;
+ input_list.match_val = checkMatchVal;
+ input_list.push_uniq = pushUniqVal;
+
+ return input_list;
+ };
+ // End utility /makeListPlus/
+ //-------------------- END UTILITY METHODS -------------------
+
+ //--------------- BEGIN JQUERY SPECIAL EVENTS ----------------
+ // Unique array for bound objects
+ boundList = makeListPlus();
+
+ // Begin define special event handlers
+ Ue = {
+ setup : function( data, a_names, fn_bind ) {
+ var
+ this_el = this,
+ $to_bind = $(this_el),
+ seen_map = {},
+ option_map, idx, namespace_key, ue_namespace_code, namespace_list
+ ;
+
+ // if previous related event bound do not rebind, but do add to
+ // type of event bound to this element, if not already noted
+ if ( $.data( this, optionKey ) ) { return; }
+
+ option_map = {};
+ $.extend( true, option_map, defaultOptMap );
+ $.data( this_el, optionKey, option_map );
+
+ namespace_list = makeListPlus(a_names.slice(0));
+ if ( ! namespace_list.length
+ || namespace_list[0] === ""
+ ) { namespace_list = ["000"]; }
+
+ NSPACE_00:
+ for ( idx = 0; idx < namespace_list.length; idx++ ) {
+ namespace_key = namespace_list[idx];
+
+ if ( ! namespace_key ) { continue NSPACE_00; }
+ if ( seen_map.hasOwnProperty(namespace_key) ) { continue NSPACE_00; }
+
+ seen_map[namespace_key] = true;
+
+ ue_namespace_code = '.__ue' + namespace_key;
+
+ $to_bind.bind( 'mousedown' + ue_namespace_code, onMouse );
+ $to_bind.bind( 'touchstart' + ue_namespace_code, onTouch );
+ $to_bind.bind( 'mousewheel' + ue_namespace_code, onMousewheel );
+ }
+
+ boundList.push_uniq( this_el ); // record as bound element
+
+ if ( ! isMoveBound ) {
+ // console.log('first element bound - adding global binds');
+ $(document).bind( 'mousemove.__ue', onMouse );
+ $(document).bind( 'touchmove.__ue', onTouch );
+ $(document).bind( 'mouseup.__ue' , onMouse );
+ $(document).bind( 'touchend.__ue' , onTouch );
+ $(document).bind( 'touchcancel.__ue', onTouch );
+ isMoveBound = true;
+ }
+ },
+
+ // arg_map.type = string - name of event to bind
+ // arg_map.data = poly - whatever (optional) data was passed when binding
+ // arg_map.namespace = string - A sorted, dot-delimited list of namespaces
+ // specified when binding the event
+ // arg_map.handler = fn - the event handler the developer wishes to be bound
+ // to the event. This function should be called whenever the event
+ // is triggered
+ // arg_map.guid = number - unique ID for event handler, provided by jQuery
+ // arg_map.selector = string - selector used by 'delegate' or 'live' jQuery
+ // methods. Only available when these methods are used.
+ //
+ // this - the element to which the event handler is being bound
+ // this always executes immediate after setup (if first binding)
+ add : function ( arg_map ) {
+ var
+ this_el = this,
+ option_map = $.data( this_el, optionKey ),
+ namespace_str = arg_map.namespace,
+ event_type = arg_map.type,
+ bound_ns_map, namespace_list, idx, namespace_key
+ ;
+ if ( ! option_map ) { return; }
+
+ bound_ns_map = option_map.bound_ns_map;
+
+ if ( ! bound_ns_map[event_type] ) {
+ // this indicates a non-namespaced entry
+ bound_ns_map[event_type] = {};
+ }
+
+ if ( ! namespace_str ) { return; }
+
+ namespace_list = namespace_str.split('.');
+
+ for ( idx = 0; idx < namespace_list.length; idx++ ) {
+ namespace_key = namespace_list[idx];
+ bound_ns_map[event_type][namespace_key] = true;
+ }
+ },
+
+ remove : function ( arg_map ) {
+ var
+ elem_bound = this,
+ option_map = $.data( elem_bound, optionKey ),
+ bound_ns_map = option_map.bound_ns_map,
+ event_type = arg_map.type,
+ namespace_str = arg_map.namespace,
+ namespace_list, idx, namespace_key
+ ;
+
+ if ( ! bound_ns_map[event_type] ) { return; }
+
+ // No namespace(s) provided:
+ // Remove complete record for custom event type (e.g. utap)
+ if ( ! namespace_str ) {
+ delete bound_ns_map[event_type];
+ return;
+ }
+
+ // Namespace(s) provided:
+ // Remove namespace flags from each custom event typei (e.g. utap)
+ // record. If all claimed namespaces are removed, remove
+ // complete record.
+ namespace_list = namespace_str.split('.');
+
+ for ( idx = 0; idx < namespace_list.length; idx++ ) {
+ namespace_key = namespace_list[idx];
+ if (bound_ns_map[event_type][namespace_key]) {
+ delete bound_ns_map[event_type][namespace_key];
+ }
+ }
+
+ if ( $.isEmptyObject( bound_ns_map[event_type] ) ) {
+ delete bound_ns_map[event_type];
+ }
+ },
+
+ teardown : function( a_names ) {
+ var
+ elem_bound = this,
+ $bound = $(elem_bound),
+ option_map = $.data( elem_bound, optionKey ),
+ bound_ns_map = option_map.bound_ns_map,
+ idx, namespace_key, ue_namespace_code, namespace_list
+ ;
+
+ // do not tear down if related handlers are still bound
+ if ( ! $.isEmptyObject( bound_ns_map ) ) { return; }
+
+ namespace_list = makeListPlus(a_names);
+ namespace_list.push_uniq('000');
+
+ NSPACE_01:
+ for ( idx = 0; idx < namespace_list.length; idx++ ) {
+ namespace_key = namespace_list[idx];
+
+ if ( ! namespace_key ) { continue NSPACE_01; }
+
+ ue_namespace_code = '.__ue' + namespace_key;
+ $bound.unbind( 'mousedown' + ue_namespace_code );
+ $bound.unbind( 'touchstart' + ue_namespace_code );
+ $bound.unbind( 'mousewheel' + ue_namespace_code );
+ }
+
+ $.removeData( elem_bound, optionKey );
+
+ // Unbind document events only after last element element is removed
+ boundList.remove_val(this);
+ if ( boundList.length === 0 ) {
+ // console.log('last bound element removed - removing global binds');
+ $(document).unbind( 'mousemove.__ue');
+ $(document).unbind( 'touchmove.__ue');
+ $(document).unbind( 'mouseup.__ue');
+ $(document).unbind( 'touchend.__ue');
+ $(document).unbind( 'touchcancel.__ue');
+ isMoveBound = false;
+ }
+ }
+ };
+ // End define special event handlers
+ //--------------- BEGIN JQUERY SPECIAL EVENTS ----------------
+
+ //------------------ BEGIN MOTION CONTROLS -------------------
+ // Begin motion control /fnHeld/
+ fnHeld = function ( arg_map ) {
+ var
+ timestamp = +new Date(),
+ motion_id = arg_map.motion_id,
+ motion_map = arg_map.motion_map,
+ bound_ns_map = arg_map.bound_ns_map,
+ event_ue
+ ;
+
+ delete motion_map.idto_tapheld;
+
+ if ( ! motion_map.do_allow_tap ) { return; }
+
+ motion_map.px_end_x = motion_map.px_start_x;
+ motion_map.px_end_y = motion_map.px_start_y;
+ motion_map.ms_timestop = timestamp;
+ motion_map.ms_elapsed = timestamp - motion_map.ms_timestart;
+
+ if ( bound_ns_map.uheld ) {
+ event_ue = $.Event('uheld');
+ $.extend( event_ue, motion_map );
+ $(motion_map.elem_bound).trigger(event_ue);
+ }
+
+ // remove tracking, as we want no futher action on this motion
+ if ( bound_ns_map.uheldstart ) {
+ event_ue = $.Event('uheldstart');
+ $.extend( event_ue, motion_map );
+ $(motion_map.elem_bound).trigger(event_ue);
+ motionHeldId = motion_id;
+ }
+ else {
+ delete motionMapMap[motion_id];
+ }
+ };
+ // End motion control /fnHeld/
+
+
+ // Begin motion control /fnMotionStart/
+ fnMotionStart = function ( arg_map ) {
+ var
+ motion_id = arg_map.motion_id,
+ event_src = arg_map.event_src,
+ request_dzoom = arg_map.request_dzoom,
+
+ option_map = $.data( arg_map.elem, optionKey ),
+ bound_ns_map = option_map.bound_ns_map,
+ $target = $(event_src.target ),
+ do_zoomstart = false,
+ motion_map, cb_map, do_allow_tap, event_ue
+ ;
+
+ // this should never happen, but it does
+ if ( motionMapMap[ motion_id ] ) { return; }
+
+ if ( request_dzoom && ! bound_ns_map.uzoomstart ) { return; }
+
+ // :input selector includes text areas
+ if ( $target.is( option_map.ignore_class ) ) { return; }
+
+ do_allow_tap = bound_ns_map.utap
+ || bound_ns_map.uheld || bound_ns_map.uheldstart
+ ? true : false;
+
+ cb_map = callbackList.pop();
+
+ while ( cb_map ) {
+ if ( $target.is( cb_map.selector_str )
+ || $( arg_map.elem ).is( cb_map.selector_str )
+ ) {
+ if ( cb_map.callback_match ) {
+ cb_map.callback_match( arg_map );
+ }
+ }
+ else {
+ if ( cb_map.callback_nomatch ) {
+ cb_map.callback_nomatch( arg_map );
+ }
+ }
+ cb_map = callbackList.pop();
+ }
+
+ motion_map = {
+ do_allow_tap : do_allow_tap,
+ elem_bound : arg_map.elem,
+ elem_target : event_src.target,
+ ms_elapsed : 0,
+ ms_timestart : event_src.timeStamp,
+ ms_timestop : undefined,
+ option_map : option_map,
+ orig_target : event_src.target,
+ px_current_x : event_src.clientX,
+ px_current_y : event_src.clientY,
+ px_end_x : undefined,
+ px_end_y : undefined,
+ px_start_x : event_src.clientX,
+ px_start_y : event_src.clientY,
+ timeStamp : event_src.timeStamp
+ };
+
+ motionMapMap[ motion_id ] = motion_map;
+
+ if ( bound_ns_map.uzoomstart ) {
+ if ( request_dzoom ) {
+ motionDzoomId = motion_id;
+ }
+ else if ( ! motion1ZoomId ) {
+ motion1ZoomId = motion_id;
+ }
+ else if ( ! motion2ZoomId ) {
+ motion2ZoomId = motion_id;
+ event_ue = $.Event('uzoomstart');
+ do_zoomstart = true;
+ }
+
+ if ( do_zoomstart ) {
+ event_ue = $.Event( 'uzoomstart' );
+ motion_map.px_delta_zoom = 0;
+ $.extend( event_ue, motion_map );
+ $(motion_map.elem_bound).trigger(event_ue);
+ return;
+ }
+ }
+
+ if ( bound_ns_map.uheld || bound_ns_map.uheldstart ) {
+ motion_map.idto_tapheld = setTimeout(
+ function() {
+ fnHeld({
+ motion_id : motion_id,
+ motion_map : motion_map,
+ bound_ns_map : bound_ns_map
+ });
+ },
+ option_map.held_tap_time
+ );
+ }
+ };
+ // End motion control /fnMotionStart/
+
+ // Begin motion control /fnMotionMove/
+ fnMotionMove = function ( arg_map ) {
+ var
+ motion_id = arg_map.motion_id,
+ event_src = arg_map.event_src,
+ do_zoommove = false,
+ motion_map, option_map, bound_ns_map,
+ event_ue, px_pinch_zoom, px_delta_zoom,
+ mzoom1_map, mzoom2_map
+ ;
+
+ if ( ! motionMapMap[motion_id] ) { return; }
+
+ motion_map = motionMapMap[motion_id];
+ option_map = motion_map.option_map;
+ bound_ns_map = option_map.bound_ns_map;
+
+ motion_map.timeStamp = event_src.timeStamp;
+ motion_map.elem_target = event_src.target;
+ motion_map.ms_elapsed = event_src.timeStamp - motion_map.ms_timestart;
+
+ motion_map.px_delta_x = event_src.clientX - motion_map.px_current_x;
+ motion_map.px_delta_y = event_src.clientY - motion_map.px_current_y;
+
+ motion_map.px_current_x = event_src.clientX;
+ motion_map.px_current_y = event_src.clientY;
+
+ // native event object override
+ motion_map.timeStamp = event_src.timeStamp;
+
+ // disallow tap if outside of zone or time elapsed
+ // we use this for other events, so we do it every time
+ if ( motion_map.do_allow_tap ) {
+ if ( Math.abs(motion_map.px_delta_x) > option_map.px_radius
+ || Math.abs(motion_map.pd_delta_y) > option_map.px_radius
+ || motion_map.ms_elapsed > option_map.tap_time
+ ) { motion_map.do_allow_tap = false; }
+ }
+
+ if ( motion1ZoomId && motion2ZoomId
+ && ( motion_id === motion1ZoomId
+ || motion_id === motion2ZoomId
+ )) {
+ motionMapMap[motion_id] = motion_map;
+ mzoom1_map = motionMapMap[motion1ZoomId];
+ mzoom2_map = motionMapMap[motion2ZoomId];
+
+ px_pinch_zoom = Math.floor(
+ Math.sqrt(
+ Math.pow((mzoom1_map.px_current_x - mzoom2_map.px_current_x),2)
+ + Math.pow((mzoom1_map.px_current_y - mzoom2_map.px_current_y),2)
+ ) +0.5
+ );
+
+ if ( pxPinchZoom === -1 ) { px_delta_zoom = 0; }
+ else { px_delta_zoom = ( px_pinch_zoom - pxPinchZoom ) * zoomTouchNum;}
+
+ // save value for next iteration delta comparison
+ pxPinchZoom = px_pinch_zoom;
+ do_zoommove = true;
+ }
+ else if ( motionDzoomId === motion_id ) {
+ if ( bound_ns_map.uzoommove ) {
+ px_delta_zoom = motion_map.px_delta_y * zoomMouseNum;
+ do_zoommove = true;
+ }
+ }
+
+ if ( do_zoommove ){
+ event_ue = $.Event('uzoommove');
+ motion_map.px_delta_zoom = px_delta_zoom;
+ $.extend( event_ue, motion_map );
+ $(motion_map.elem_bound).trigger(event_ue);
+ return;
+ }
+
+ if ( motionHeldId === motion_id ) {
+ if ( bound_ns_map.uheldmove ) {
+ event_ue = $.Event('uheldmove');
+ $.extend( event_ue, motion_map );
+ $(motion_map.elem_bound).trigger(event_ue);
+ event_src.preventDefault();
+ }
+ }
+ else if ( motionDragId === motion_id ) {
+ if ( bound_ns_map.udragmove ) {
+ event_ue = $.Event('udragmove');
+ $.extend( event_ue, motion_map );
+ $(motion_map.elem_bound).trigger(event_ue);
+ event_src.preventDefault();
+ }
+ }
+
+ if ( ! motionDragId
+ && ! motionHeldId
+ && bound_ns_map.udragstart
+ && motion_map.do_allow_tap === false
+ ) {
+ motionDragId = motion_id;
+ event_ue = $.Event('udragstart');
+ $.extend( event_ue, motion_map );
+ $(motion_map.elem_bound).trigger(event_ue);
+ event_src.preventDefault();
+
+ if ( motion_map.idto_tapheld ) {
+ clearTimeout(motion_map.idto_tapheld);
+ delete motion_map.idto_tapheld;
+ }
+ }
+ };
+ // End motion control /fnMotionMove/
+
+ // Begin motion control /fnMotionEnd/
+ fnMotionEnd = function ( arg_map ) {
+ var
+ motion_id = arg_map.motion_id,
+ event_src = arg_map.event_src,
+ do_zoomend = false,
+ motion_map, option_map, bound_ns_map, event_ue
+ ;
+
+ doDisableMouse = false;
+
+ if ( ! motionMapMap[motion_id] ) { return; }
+
+ motion_map = motionMapMap[motion_id];
+ option_map = motion_map.option_map;
+ bound_ns_map = option_map.bound_ns_map;
+
+ motion_map.elem_target = event_src.target;
+ motion_map.ms_elapsed = event_src.timeStamp - motion_map.ms_timestart;
+ motion_map.ms_timestop = event_src.timeStamp;
+
+ if ( motion_map.px_current_x ) {
+ motion_map.px_delta_x = event_src.clientX - motion_map.px_current_x;
+ motion_map.px_delta_y = event_src.clientY - motion_map.px_current_y;
+ }
+
+ motion_map.px_current_x = event_src.clientX;
+ motion_map.px_current_y = event_src.clientY;
+
+ motion_map.px_end_x = event_src.clientX;
+ motion_map.px_end_y = event_src.clientY;
+
+ // native event object override
+ motion_map.timeStamp = event_src.timeStamp
+ ;
+
+ // clear-out any long-hold tap timer
+ if ( motion_map.idto_tapheld ) {
+ clearTimeout(motion_map.idto_tapheld);
+ delete motion_map.idto_tapheld;
+ }
+
+ // trigger utap
+ if ( bound_ns_map.utap
+ && motion_map.ms_elapsed <= option_map.tap_time
+ && motion_map.do_allow_tap
+ ) {
+ event_ue = $.Event('utap');
+ $.extend( event_ue, motion_map );
+ $(motion_map.elem_bound).trigger(event_ue);
+ }
+
+ // trigger udragend
+ if ( motion_id === motionDragId ) {
+ if ( bound_ns_map.udragend ) {
+ event_ue = $.Event('udragend');
+ $.extend( event_ue, motion_map );
+ $(motion_map.elem_bound).trigger(event_ue);
+ event_src.preventDefault();
+ }
+ motionDragId = undefined;
+ }
+
+ // trigger heldend
+ if ( motion_id === motionHeldId ) {
+ if ( bound_ns_map.uheldend ) {
+ event_ue = $.Event('uheldend');
+ $.extend( event_ue, motion_map );
+ $(motion_map.elem_bound).trigger(event_ue);
+ }
+ motionHeldId = undefined;
+ }
+
+ // trigger uzoomend
+ if ( motion_id === motionDzoomId ) {
+ do_zoomend = true;
+ motionDzoomId = undefined;
+ }
+
+ // cleanup zoom info
+ else if ( motion_id === motion1ZoomId ) {
+ if ( motion2ZoomId ) {
+ motion1ZoomId = motion2ZoomId;
+ motion2ZoomId = undefined;
+ do_zoomend = true;
+ }
+ else { motion1ZoomId = undefined; }
+ pxPinchZoom = -1;
+ }
+ if ( motion_id === motion2ZoomId ) {
+ motion2ZoomId = undefined;
+ pxPinchZoom = -1;
+ do_zoomend = true;
+ }
+
+ if ( do_zoomend && bound_ns_map.uzoomend ) {
+ event_ue = $.Event('uzoomend');
+ motion_map.px_delta_zoom = 0;
+ $.extend( event_ue, motion_map );
+ $(motion_map.elem_bound).trigger(event_ue);
+ }
+ // remove pointer from consideration
+ delete motionMapMap[motion_id];
+ };
+ // End motion control /fnMotionEnd/
+ //------------------ END MOTION CONTROLS -------------------
+
+ //------------------- BEGIN EVENT HANDLERS -------------------
+ // Begin event handler /onTouch/ for all touch events.
+ // We use the 'type' attribute to dispatch to motion control
+ onTouch = function ( event ) {
+ var
+ this_el = this,
+ timestamp = +new Date(),
+ o_event = event.originalEvent,
+ touch_list = o_event ? o_event.changedTouches || [] : [],
+ touch_count = touch_list.length,
+ idx, touch_event, motion_id, handler_fn
+ ;
+
+ doDisableMouse = true;
+
+ event.timeStamp = timestamp;
+
+ switch ( event.type ) {
+ case 'touchstart' :
+ handler_fn = fnMotionStart;
+ event.preventDefault();
+ break;
+ case 'touchmove' :
+ handler_fn = fnMotionMove;
+ break;
+ case 'touchend' :
+ case 'touchcancel' : handler_fn = fnMotionEnd; break;
+ default : handler_fn = null;
+ }
+
+ if ( ! handler_fn ) { return; }
+
+ for ( idx = 0; idx < touch_count; idx++ ) {
+ touch_event = touch_list[idx];
+
+ motion_id = 'touch' + String(touch_event.identifier);
+
+ event.clientX = touch_event.clientX;
+ event.clientY = touch_event.clientY;
+ handler_fn({
+ elem : this_el,
+ motion_id : motion_id,
+ event_src : event
+ });
+ }
+ };
+ // End event handler /onTouch/
+
+
+ // Begin event handler /onMouse/ for all mouse events
+ // We use the 'type' attribute to dispatch to motion control
+ onMouse = function ( event ) {
+ var
+ this_el = this,
+ motion_id = 'mouse' + String(event.button),
+ request_dzoom = false,
+ handler_fn
+ ;
+
+ if ( doDisableMouse ) {
+ event.stopImmediatePropagation();
+ return;
+ }
+
+ if ( event.shiftKey ) { request_dzoom = true; }
+
+ // skip left or middle clicks
+ if ( event.type !== 'mousemove' ) {
+ if ( event.button !== 0 ) { return true; }
+ }
+
+ switch ( event.type ) {
+ case 'mousedown' :
+ handler_fn = fnMotionStart;
+ event.preventDefault();
+ break;
+ case 'mouseup' :
+ handler_fn = fnMotionEnd;
+ break;
+ case 'mousemove' :
+ handler_fn = fnMotionMove;
+ break;
+ default:
+ handler_fn = null;
+ }
+
+ if ( ! handler_fn ) { return; }
+
+ handler_fn({
+ elem : this_el,
+ event_src : event,
+ request_dzoom : request_dzoom,
+ motion_id : motion_id
+ });
+ };
+ // End event handler /onMouse/
+ //-------------------- END EVENT HANDLERS --------------------
+
+
+ // Export special events through jQuery API
+ $Special.ue
+ = $Special.utap = $Special.uheld
+ = $Special.uzoomstart = $Special.uzoommove = $Special.uzoomend
+ = $Special.udragstart = $Special.udragmove = $Special.udragend
+ = $Special.uheldstart = $Special.uheldmove = $Special.uheldend
+ = Ue
+ ;
+ $.ueSetGlobalCb = function ( selector_str, callback_match, callback_nomatch ) {
+ callbackList.push( {
+ selector_str : selector_str || '',
+ callback_match : callback_match || null,
+ callback_nomatch : callback_nomatch || null
+ });
+ };
+
+}(jQuery));
--- /dev/null
+/*
+ * jQuery udraggable plugin v0.3.0
+ * Copyright (c) 2013-2014 Grant McLean (grant@mclean.net.nz)
+ *
+ * Homepage: https://github.com/grantm/jquery-udraggable
+ *
+ * Dual licensed under the MIT and GPL (v2.0 or later) licenses:
+ * http://opensource.org/licenses/MIT
+ * http://opensource.org/licenses/GPL-2.0
+ *
+ * This library requires Michael S. Mikowski's unified mouse and touch
+ * event plugin: https://github.com/mmikowski/jquery.event.ue
+ *
+ */
+
+(function($) {
+ "use strict";
+
+ var floor = Math.floor;
+ var min = Math.min;
+ var max = Math.max;
+
+ window.requestAnimationFrame = window.requestAnimationFrame || function(work) {
+ return setTimeout(work, 10);
+ };
+
+ window.cancelAnimationFrame = window.cancelAnimationFrame || function(id) {
+ return clearTimeout(id);
+ };
+
+
+ // Constructor function
+
+ var UDraggable = function (el, options) {
+ var that = this;
+ this.el = el;
+ this.$el = $(el);
+ this.options = $.extend({}, $.fn.udraggable.defaults, options);
+ this.positionElement = this.options.positionElement || this.positionElement;
+ this.getStartPosition = this.options.getStartPosition || this.getStartPosition;
+ this.updatePositionFrameHandler = function() {
+ delete that.queuedUpdate;
+ var pos = that.ui.position;
+ that.positionElement(that.$el, that.started, pos.left, pos.top);
+ if (that.options.dragUpdate) {
+ that.options.dragUpdate.apply(that.el, [that.ui]);
+ }
+ };
+ this.queuePositionUpdate = function() {
+ if (!that.queuedUpdate) {
+ that.queuedUpdate = window.requestAnimationFrame(that.updatePositionFrameHandler);
+ }
+ };
+ this.init();
+ };
+
+ UDraggable.prototype = {
+
+ constructor: UDraggable,
+
+ init: function() {
+ var that = this;
+ this.disabled = false;
+ this.started = false;
+ this.normalisePosition();
+ var $target = this.options.handle ?
+ this.$el.find( this.options.handle ) :
+ this.$el;
+ if (this.options.longPress) {
+ $target
+ .on('uheldstart.udraggable', function(e) { that.start(e); })
+ .on('uheldmove.udraggable', function(e) { that.move(e); })
+ .on('uheldend.udraggable', function(e) { that.end(e); });
+ }
+ else {
+ $target
+ .on('udragstart.udraggable', function(e) { that.start(e); })
+ .on('udragmove.udraggable', function(e) { that.move(e); })
+ .on('udragend.udraggable', function(e) { that.end(e); });
+ }
+ },
+
+ destroy: function() {
+ var $target = this.options.handle ?
+ this.$el.find( this.options.handle ) :
+ this.$el;
+ $target.off('.udraggable');
+ this.$el.removeData('udraggable');
+ },
+
+ disable: function() {
+ this.disabled = true;
+ },
+
+ enable: function() {
+ this.disabled = false;
+ },
+
+ option: function() {
+ var name;
+ if (arguments.length === 0) {
+ return this.options;
+ }
+ if (arguments.length === 2) {
+ this.options[ arguments[0] ] = arguments[1];
+ return;
+ }
+ if (arguments.length === 1) {
+ if (typeof arguments[0] === 'string') {
+ return this.options[ arguments[0] ];
+ }
+ if (typeof arguments[0] === 'object') {
+ for(name in arguments[0]) {
+ if (arguments[0].hasOwnProperty(name)) {
+ this.options[name] = arguments[0][name];
+ }
+ }
+ }
+ }
+ if (this.options.containment) {
+ this._initContainment();
+ }
+ },
+
+ normalisePosition: function() {
+ var pos = this.$el.position();
+ this.$el.css({
+ position: 'absolute',
+ top: pos.top,
+ left: pos.left,
+ right: 'auto',
+ bottom: 'auto'
+ });
+ },
+
+ start: function(e) {
+ if (this.disabled) {
+ return;
+ }
+ var start = this.getStartPosition(this.$el);
+ this._initContainment();
+ this.ui = {
+ helper: this.$el,
+ offset: { top: start.y, left: start.x},
+ originalPosition: { top: start.y, left: start.x},
+ position: { top: start.y, left: start.x},
+ };
+ if (this.options.longPress) {
+ this._start(e);
+ }
+ return this._stopPropagation(e);
+ },
+
+ move: function(e) {
+ if (this.disabled || (!this.started && !this._start(e))) {
+ return;
+ }
+ var delta_x = e.px_current_x - e.px_start_x;
+ var delta_y = e.px_current_y - e.px_start_y;
+ var axis = this.options.axis;
+ if (axis && axis === "x") {
+ delta_y = 0;
+ }
+ if (axis && axis === "y") {
+ delta_x = 0;
+ }
+ var cur = {
+ left: this.ui.originalPosition.left,
+ top: this.ui.originalPosition.top
+ };
+ if (!axis || (axis === "x")) {
+ cur.left += delta_x;
+ }
+ if (!axis || (axis === "y")) {
+ cur.top += delta_y;
+ }
+ this._applyGrid(cur);
+ this._applyContainment(cur);
+ var pos = this.ui.position;
+ if ((cur.top !== pos.top) || (cur.left !== pos.left)) {
+ this.ui.position.left = cur.left;
+ this.ui.position.top = cur.top;
+ this.ui.offset.left = cur.left;
+ this.ui.offset.top = cur.top;
+ if (this.options.drag) {
+ this.options.drag.apply(this.el, [e, this.ui]);
+ }
+ this.queuePositionUpdate();
+ }
+ return this._stopPropagation(e);
+ },
+
+ end: function(e) {
+ if (this.started || this._start(e)) {
+ this.$el.removeClass("udraggable-dragging");
+ this.started = false;
+ if (this.queuedUpdate) {
+ window.cancelAnimationFrame(this.queuedUpdate);
+ }
+ this.updatePositionFrameHandler();
+ if (this.options.stop) {
+ this.options.stop.apply(this.el, [e, this.ui]);
+ }
+ }
+ return this._stopPropagation(e);
+ },
+
+ // helper methods
+
+ _stopPropagation: function(e) {
+ e.stopPropagation();
+ e.preventDefault();
+ return false;
+ },
+
+ _start: function(e) {
+ if (!this._mouseDistanceMet(e) || !this._mouseDelayMet(e)) {
+ return;
+ }
+ this.started = true;
+ this.queuePositionUpdate();
+ if (this.options.start) {
+ this.options.start.apply(this.el, [e, this.ui]);
+ }
+ this.$el.addClass("udraggable-dragging");
+ return true;
+ },
+
+ _mouseDistanceMet: function(e) {
+ return max(
+ Math.abs(e.px_start_x - e.px_current_x),
+ Math.abs(e.px_start_y - e.px_current_y)
+ ) >= this.options.distance;
+ },
+
+ _mouseDelayMet: function(e) {
+ return e.ms_elapsed > this.options.delay;
+ },
+
+ _initContainment: function() {
+ var o = this.options;
+ var $c, ce;
+
+ if (!o.containment) {
+ this.containment = null;
+ return;
+ }
+
+ if (o.containment.constructor === Array) {
+ this.containment = o.containment;
+ return;
+ }
+
+ if (o.containment === "parent") {
+ o.containment = this.$el.offsetParent();
+ }
+
+ $c = $( o.containment );
+ ce = $c[ 0 ];
+ if (!ce) {
+ return;
+ }
+
+ this.containment = [
+ 0,
+ 0,
+ $c.innerWidth() - this.$el.outerWidth(),
+ $c.innerHeight() - this.$el.outerHeight(),
+ ];
+ },
+
+ _applyGrid: function(cur) {
+ if (this.options.grid) {
+ var gx = this.options.grid[0];
+ var gy = this.options.grid[1];
+ cur.left = floor( (cur.left + gx / 2) / gx ) * gx;
+ cur.top = floor( (cur.top + gy / 2) / gy ) * gy;
+ }
+ },
+
+ _applyContainment: function(cur) {
+ var cont = this.containment;
+ if (cont) {
+ cur.left = min( max(cur.left, cont[0]), cont[2] );
+ cur.top = min( max(cur.top, cont[1]), cont[3] );
+ }
+ },
+
+ getStartPosition: function($el) {
+ return {
+ x: parseInt($el.css('left'), 10) || 0,
+ y: parseInt($el.css('top'), 10) || 0
+ };
+ },
+
+ positionElement: function($el, dragging, left, top) {
+ $el.css({ left: left, top: top });
+ }
+
+ };
+
+
+ // jQuery plugin function
+
+ $.fn.udraggable = function(option) {
+ var args = Array.prototype.slice.call(arguments, 1);
+ var results = [];
+ this.each(function () {
+ var $this = $(this);
+ var data = $this.data('udraggable');
+ if (!data) {
+ data = new UDraggable(this, option);
+ $this.data('udraggable', data);
+ }
+ if (typeof option === 'string') { // option is a method - call it
+ if(typeof data[option] !== 'function') {
+ throw "jquery.udraggable has no '" + option + "' method";
+ }
+ var result = data[option].apply(data, args);
+ if (result !== undefined) {
+ results.push( result );
+ }
+ }
+ });
+ return results.length > 0 ? results[0] : this;
+ };
+
+ $.fn.udraggable.defaults = {
+ axis: null,
+ delay: 0,
+ distance: 0,
+ longPress: false,
+ // callbacks
+ drag: null,
+ start: null,
+ stop: null
+ };
+
+
+})(jQuery);
+
if (empty($_POST['login']) || empty($_POST['passwd']))
return false;
+ if ($_POST['auth_token'] != $_SESSION['token'])
+ return false;
+
$sql = sprintf("SELECT * FROM sys_user WHERE login = %s AND passwd = %s",
$db->quote($_POST['login']), $db->quote(passwd($_POST['login'], $_POST['passwd'])));
'login' => $row['login'],
'name' => $row['name'],
'email' => $row['email'],
- 'group' => $row['gid'],
'theme' => $row['theme'],
+ 'page' => $row['page'],
'basedir' => substr($_SERVER['SCRIPT_FILENAME'],0,-9));
+ $_SESSION['sys']['baseurl'] = substr($_SESSION['sys']['basedir'], strlen($_SERVER['DOCUMENT_ROOT']));
return true;
}
function mask_login()
{
+ $styles = Styles::instance();
+ $javascript = JavaScript::instance();
+
+ $styles->file('lib/rico3/ricoClient/css/rico.css');
+ $styles->file('lib/rico3/ricoClient/css/rico_icon.css');
+ $styles->file('lib/rico3/ricoClient/css/striping_cupertino.css');
+ $styles->file('lib/rico3/ui-cupertino/jquery-ui.css');
+ $styles->file('lib/rico3/ui-cupertino/jquery-ui_hallinta.css');
+
+ $javascript->file('lib/rico3/ricoClient/js/rico2jqu.js');
+ $javascript->file('lib/rico3/minsrc/rico.js');
+ $javascript->file('lib/rico3/minsrc/ricoLocale_en.js');
+ $javascript->file('lib/rico3/minsrc/ricoUI.js');
+ $javascript->file('lib/rico3/ricoClient/js/ricoThemeroller.js');
+
$LOGIN_IMG = 'images/login.jpg';
if (defined('LOGIN_IMG')) $LOGIN_IMG = LOGIN_IMG;
$HEIGHT = $info[1];
}
-$html = <<<EOC
-<style type="text/css">
-div.login {
- background-image: url('$LOGIN_IMG');
- background-repeat: no-repeat;
- background-position: center center;
- margin: -15px;
-}
-
-table.login {
- border: 1px solid #7b7b7b;
- background: #f7f7f7;
- position: relative;
- top: 290px;
-}
-</style>
-
-<div class="login" id="background">
-<div align="center">
-<form action="index.php" method="POST">
-<table id="logintab" class="login" cellpadding="5">
-<tr><th align="left" colspan="2" style="background: #48b4f8;">Anmeldung</th></tr>
-<tr><th align="right">Login</th><td><input type="text" name="login" id="login" size="15"></td></tr>
-<tr><th align="right">Passwort</th><td><input type="password" name="passwd" size="15"></td></tr>
-<tr><td colspan="2" align="center"><input type="submit" value="Anmelden"></td></tr>
-</table>
-</form>
-</div>
-</div>
-
-<script type="text/javascript">
-var img_height = $HEIGHT;
-var inner_height = window.innerHeight - 50;
-var height = img_height <= inner_height ? img_height : inner_height;
-
-var div = document.getElementById("background");
-div.style.height = height + 'px';
-
-var login = document.getElementById("logintab");
-login.style.position = 'absolute';
-login.style.top = ((window.innerHeight / 2) - (130 / 2)) + 'px';
-login.style.left = ((window.innerWidth / 2) - (120 / 2)) + 'px';
-
-var inp = document.getElementById("login");
-inp.focus();
-</script>
-EOC;
-
- return $html;
+ $_SESSION = array('token' => md5(microtime().$_SERVER['DOCUMENT_ROOT']));
+ $fname = 'data/misc/login.js';
+ if (file_exists($fname))
+ $javascript->onLoad(str_replace(array('$LOGIN_IMG', '$HEIGHT', '$TOKEN'),
+ array($LOGIN_IMG, $HEIGHT, $_SESSION['token']),
+ file_get_contents($fname)));
+ $fname = 'data/misc/login.html';
+ if (file_exists($fname))
+ return str_replace(array('$LOGIN_IMG', '$HEIGHT', '$TOKEN'),
+ array($LOGIN_IMG, $HEIGHT, $_SESSION['token']),
+ file_get_contents($fname));
+ else
+ error_log('data/misc/login.html missing');
}
-?>
<?php
+require_once('php.php');
+
function check_edit($name)
{
- global $db;
-
- $sql = sprintf("SELECT sys_mask.id,edit FROM sys_mask "
- . "JOIN sys_group_mask ON sys_mask.id = sys_group_mask.mask "
- . "WHERE gid = %d AND fname = %s "
- . "ORDER BY edit DESC LIMIT 1",
- $_SESSION['sys']['group'], $db->quote(str_replace('__','|',$name)));
-
- $sth = $db->query($sql);
-
- if ($sth === false) return false;
+ $menu = new MenuItem();
- $row = $sth->fetch();
- if ($row === false) return false;
-
- if ($row['edit'] == '0')
- return false;
-
- return true;
+ return $menu->mayEdit();
}
-function build_form($name, $mask)
+function build_form($mask)
{
- global $jscode;
$ret = array();
+ $form_checks = array();
+ $label_class = '';
+ $hallinta = Hallinta::instance();
- $jscode[] = "var form_check = {};";
-
- $ret[] = '<div class="form">';
- $toggle = '<img src="images/icons/minimise.gif" title="Show second table" id="icon_toggle" onclick="second_toggle()" style="right: 13px; display: none"/>';
- $close = '<img src="lib/rico/images/close.gif" title="Close" onclick="edit_hide()" />';
- $edit_title = empty($mask['edit_title']) ? 'Datensatz bearbeiten' : $mask['edit_title'];
- $ret[] = sprintf('<div class="ricoTitle" style="position: relative;" id="mask_edit_title" class="title"><strong>%s</strong>%s%s</div>',
- $edit_title, $toggle, $close);
- $ret[] = '<form id="form_edit">';
+ $ret[] = '<div style="position: relative; overflow: hidden;">';
+ $ret[] = '<form id="form_edit" style="padding: 2px;">';
$ret[] = '<input type="hidden" id="edit_id" name="id" value="">';
- $ret[] = sprintf('<input type="hidden" id="edit_source" name="source" value="%s">', $name);
foreach ($mask['edit'] as $id => $info) {
if ($info['type'] == 'hidden')
$ret[] = sprintf('<input type="hidden" id="edit_%s" name="%s" value="%s">', $id, $id,
- empty($info['default'])?'':$info['default']);
+ !array_key_exists('default', $info)?'':$info['default']);
elseif ($info['type'] == 'html')
$ret[] = $info['code'];
else {
- $ret[] = sprintf('<label id="label_%s" for="edit_%s">%s</label><br>', $id, $id, $info['name']);
- $v = array('id="edit_'.$id.'"',
+ $v = array('id="edit_'.$id."\"",
'name="'.$id.'"');
+ if (isset($info['visible'])) {
+ if ($info['visible'] == 'desktop' && $hallinta->isMobile()) return;
+ if ($info['visible'] == 'mobile' && !$hallinta->isMobile()) return;
+ if (($info['visible'] == 'mobile-optional' && $hallinta->isMobile()) ||
+ ($info['visible'] == 'desktop-optional' && !$hallinta->isMobile())) {
+ $label_class = ' class="toggle"';
+ $v[] = 'style="display:none;"';
+ }
+ }
$checks = array();
+ $ret[] = sprintf('<label id="label_%s" for="edit_%s"%s>%s</label>', $id, $id, $label_class, $info['name']);
+
if (isset($info['required']) && $info['required'] === true) {
$checks[] = 'required';
$v[] = 'onblur="form_elem_onblur(event)"';
}
+ if ($info['type'] != 'date')
+ $v[] = 'class="maxwidth"';
+
if ($info['type'] == 'text' || $info['type'] == 'passwd' ||
$info['type'] == 'decimal' || $info['type'] == 'number') {
- $v[] = 'size="'.(empty($info['size'])?'10':$info['size']).'"';
+ $v[] = 'size="'.(!array_key_exists('size', $info)?'10':$info['size']).'"';
$v[] = 'type="'.($info['type']=='passwd'?'password':'text').'"';
- $v[] = 'value="'.(empty($info['default'])?'':$info['default']).'"';
+ $v[] = 'value="'.(!array_key_exists('default', $info)?'':$info['default']).'"';
$ret[] = sprintf('<input %s>', implode(' ', $v));
if ($info['type'] == 'decimal') $checks[] = 'decimal';
} elseif ($info['type'] == 'date') {
$v[] = 'size="8"';
$ret[] = sprintf('<input %s> ', implode(' ', $v));
- $ret[] = sprintf('<img class="calendar" src="images/icons/calendar.gif" onclick="calendar(\'edit_%s\',event)" />',
+ $ret[] = sprintf('<img class="calendar" src="%simages/icons/calendar.gif" onclick="calendar(\'edit_%s\',event)" />',
+ Hallinta::instance()->urlbase(),
$id, $id, $id);
$checks[] = 'date';
- } elseif ($info['type'] == 'boolean' || $info['type'] == 'file') {
- $v[] = 'type="'.($info['type']=='boolean'?'checkbox':'file').'"';
+ } elseif ($info['type'] == 'time') {
+ $v[] = 'size="5"';
+ $ret[] = sprintf('<input %s> ', implode(' ', $v));
+ $checks[] = 'time';
+ } elseif ($info['type'] == 'boolean') {
+ $v[] = 'type="checkbox"';
+ $ret[] = sprintf('<input %s>', implode(' ', $v));
+ } elseif ($info['type'] == 'file') {
+ $v[] = 'type="file"';
+ $v[] = 'style="display:none;"';
+ $ret[] = sprintf('<input %s>', implode(' ', $v));
+
+ $v = array('id="edit_real_'.$id.'"',
+ 'name="real_'.$id.'"');
+ $v[] = 'type="text"';
+ $v[] = 'data-for="edit_'.$id.'"';
+ $v[] = 'class="maxwidth file-upload"';
+ $v[] = 'readonly="readonly"';
+ $v[] = 'placeholder="Browse..."';
+ $v[] = sprintf('title="Max %s"', bytes_to_php(upload_max_filesize()));
$ret[] = sprintf('<input %s>', implode(' ', $v));
- if ($info['type'] == 'file')
- $js_file = sprintf(" var finput = document.getElementById('edit_%s');\n" .
- " if (finput) finput.addEventListener('change', form_file_change, false);",
- $id);
} elseif ($info['type'] == 'select') {
if (array_key_exists('onchange',$info))
$v[] = sprintf('onchange="%s"', $info['onchange']);
foreach ($options as $row)
$ret[] = sprintf('<option value="%s"%s>%s</option>',
$row['id'],
- !empty($info['selected']) && $row['id'] == $info['selected'] ? ' selected' : '',
+ array_key_exists('selected', $info) && $row['id'] == $info['selected'] ? ' selected' : '',
$row['text']);
$ret[] = '</select>';
} elseif ($info['type'] == 'textarea') {
- $v[] = sprintf('cols="%d"', empty($info['columns'])?33:$info['columns']);
- $v[] = sprintf('rows="%d"', empty($info['rows'])?5:$info['rows']);
+ $v[] = sprintf('cols="%d"', !array_key_exists('columns', $info)?33:$info['columns']);
+ $v[] = sprintf('rows="%d"', !array_key_exists('rows', $info)?5:$info['rows']);
$ret[] = sprintf('<textarea %s></textarea>', implode(' ', $v));
}
if (array_key_exists('comment',$info))
$ret[] = sprintf('<span class="comment">%s</span>', $info['comment']);
- $ret[] = '<br>';
if (count($checks))
- $jscode[] = sprintf('form_check["%s"] = "%s";', $id, implode(',', $checks));
+ $form_checks[$id] = implode(',', $checks);
}
}
- $jscode[] = 'Rico.onLoad( function() {';
- $jscode[] = " form_init();";
- if (isset($js_file))
- $jscode[] = $js_file;
- $jscode[] = '});';
-
$v_save = array('id="button_save"',
'onclick="return form_save(this);"');
if (isset($mask['buttons']) && isset($mask['buttons']['save']) && $mask['buttons']['save'] === false) $v_save[] = 'style="display: none"';
'onclick="return form_delete(this);"');
if (isset($mask['buttons']) && isset($mask['buttons']['delete']) && $mask['buttons']['delete'] === false) $v_delete[] = 'style="display: none"';
- $v_changes = array('id="form_status"');
+ $v_changes = array('id="form_status"', 'title="Last modified"');
if (isset($mask['buttons']) && isset($mask['buttons']['changes']) && $mask['buttons']['changes'] === false) $v_changes[] = 'style="display: none"';
$ret[] = sprintf('<p %s> </p>', implode(' ', $v_changes));
$ret[] = '</form>';
$ret[] = '</div>';
- return $ret;
+ return array('form' => implode('', $ret), 'checks' => $form_checks);;
}
-function build_grid($name, $mask, $gridname = false)
+function grid_details($source, $name, $def)
{
- $jscode = array();;
- $ret = array();
-
- if ($gridname == false) {
- $gridname = 'grid';
- $opts = array("click: gridDrillDown");
- } else {
- $name = $name . '__' . $gridname;
- $opts = array();
- if (array_key_exists('onclick', $mask)) $opts[] = 'click: ' . $mask['onclick'];
- }
-
- $opts[] = "onscroll: gridOnScroll";
- $opts[] = "menuEvent: 'contextmenu'";
- $opts[] = "highlightElem: 'menuRow'";
-
- if (array_key_exists('maxprint', $mask)) $opts[] = 'maxPrint: ' . $mask['maxprint'];
- else $opts[] = 'maxPrint: 100000';
- if (array_key_exists('rows', $mask)) $opts[] = 'visibleRows: ' . $mask['rows'];
- if (array_key_exists('sort', $mask)) $opts[] = 'sortCol: ' . $mask['sort'];
- if (isset($mask['prefetch']) && $mask['prefetch'] === false) $opts[] = 'prefetchBuffer: false';
- # $opts[] = 'frozenColumns: ' . count($mask['list']);
- $opts[] = 'saveColumnInfo: {width: true, filter: true, sort: true}';
-
- $ret[] = sprintf('<table id="grid_%s" class="ricoLiveGrid">', $name);
- $ret[] = ' <tr>';
- $specs = array();
- $fields = array();
- foreach ($mask['list'] as $field => $data) {
- $ret[] = sprintf(' <th>%s</th>', $data['name']);
- $s = array(sprintf("FieldName: 'input_%s'", $field),
- sprintf("ColName: 'input_%s'", $data['name']));
- $s = array();
- if (isset($data['visible']) && $data['visible'] === false) $s[] = 'visible: false';
- if (isset($data['width']) && $data['width'] > 0) $s[] = 'width: ' . $data['width'];
- if (array_key_exists('type', $data)) $s[] = "type: '" . $data['type'] . "'";
- if (array_key_exists('specs', $data)) $s[] = $data['specs'];
- if (array_key_exists('control', $data)) $s[] = 'control: ' . $data['control'];
- $specs[] = '{' . implode(', ', $s) . '}';
-
- if (array_key_exists('sql', $data))
- $fields[] = $data['sql'] . ' AS ' . $field;
- else
- $fields[] = $field;
+ $hallinta = Hallinta::instance();
+ if ($name == 'main')
+ $gridName = $source;
+ else
+ $gridName = $source . '__' . $name . '__second';
+
+ $options = array();
+ $options['onscroll'] = 'gridOnScroll';
+ $options['menuEvent'] = 'contextmenu';
+ $options['highlightElem'] = 'menuRow';
+
+ if ($name == 'main') $options['click'] = 'gridDrillDown';
+ if (array_key_exists('onclick', $def)) $options['click'] = $def['onclick'];
+ if (array_key_exists('rows', $def)) $options['visibleRows'] = intval($def['rows']);
+ if (array_key_exists('sort', $def)) $options['sortCol'] = intval($def['sort']);
+ if (array_key_exists('sortdir', $def)) $options['sortDir'] = $def['sortdir'];
+ if (array_key_exists('prefetch', $def) && $def['prefetch'] == false) $options['prefetchBuffer'] = false;
+ if (array_key_exists('maxprint', $def)) $options['maxPrint'] = intval($def['maxprint']);
+ else $options['maxPrint'] = 100000;
+ $options['saveColumnInfo'] = array('width' => true, 'filter' => true, 'sort' => true);
+
+ $canEdit = array_key_exists('table_edit', $def);
+ if ($canEdit) {
+ $options['canEdit'] = true;
+ $options['updateURL'] = $hallinta->urlbase().'ajax/ajax.php';
}
- grid_sql($name, $mask);
-
- $ret[] = ' </tr>';
- $ret[] = '</table>';
- $ret[] = '<div>';
- $ret[] = sprintf('<div class="info" id="info_grid_%s">Datensatz 0</div>', $name);
- if ($gridname == 'grid')
- $ret[] = '<div class="status"><span id="status"></span></div>';
- $ret[] = '</div>';
- $ret[] = '<br style="clear:both;">';
-
- $opts[] = 'columnSpecs: [' . implode(', ', $specs) . ']';
-
- if (strstr($opts[count($opts)-1], 'filterUI') !== false) $opts[] = 'FilterLocation: -1';
+ $hasFilter = false;
+ $columnSpecs = array();
+ $html = array();
+ $html[] = sprintf('<table id="grid_%s" class="ricoLiveGrid">', $gridName);
+ $html[] = '<tr>';
+ foreach ($def['list'] as $field => $data) {
+ $html[] = sprintf('<th>%s</th>', $data['name']);
+ if ($canEdit && array_key_exists('edit', $data)) {
+ if (!is_array($data['edit']))
+ throw new Exception(sprintf('Grid %s column %s edit is not an array', $name, $data['name']));
+ $s = $data['edit'];
+ $s['FieldName'] = sprintf('listinput_%s', $field);
+ $s['ColName'] = $data['name'];
+ } else {
+ $s = array();
+ }
+ if (isset($data['visible'])) {
+ if ($data['visible'] === false)
+ $s['visible'] = false;
+ elseif ($data['visible'] === 'mobile' && !$hallinta->isMobile())
+ $s['visible'] = false;
+ elseif ($data['visible'] === 'desktop' && $hallinta->isMobile())
+ $s['visible'] = false;
+ }
+ if (isset($data['width']) && $data['width'] > 0) $s['width'] = intval($data['width']);
+ if (array_key_exists('type', $data)) $s['type'] = $data['type'];
+ if (array_key_exists('filter', $data)) {
+ $s['filterUI'] = $data['filter'];
+ $hasFilter = true;
+ }
+ if (array_key_exists('control', $data)) $s['control'] = $data['control'];
+ if (array_key_exists('specs', $data)) {
+ if (!is_array($data['specs']))
+ throw new Exception(sprintf('Grid %s column %s specs is not an array', $name, $data['name']));
+ $s = array_merge($s, $data['specs']);
+ }
- $jscode[] = sprintf('var %s;', $gridname);;
- $jscode[] = 'Rico.onLoad( function() {';
- $jscode[] = sprintf("var %s_opts = {\n %s\n};", $name, implode(",\n ", $opts));
- $jscode[] = sprintf("%s = new Rico.LiveGrid ('grid_%s', new Rico.Buffer.AjaxSQL('ajax/ricoXMLquery.php'), %s_opts);", $gridname, $name, $name);
- $jscode[] = sprintf("%s.menu = new Rico.GridMenu();", $gridname);
- $jscode[] = sprintf("%s.edit = new Rico.TableEdit(%s);", $gridname, $gridname);
- if ($gridname == 'grid') {
- $jscode[] = sprintf("%s.menu.options.dataMenuHandlerOriginal = %s.menu.options.dataMenuHandler;", $gridname, $gridname);
- $jscode[] = sprintf("%s.menu.options.dataMenuHandler = grid_dataMenuHandler;", $gridname);
+ $columnSpecs[] = $s;
}
- $jscode[] = '});';
-
- return array($ret, $jscode);
-}
-
-function build_details($name, $details)
-{
- $ret = array();
+ $options['columnSpecs'] = $columnSpecs;
- $ret[] = '<div class="box" id="details">';
- $ret[] = sprintf('<h3>%s</h3>', $details['title']);
- if (array_key_exists('subtitle', $details))
- $ret[] = sprintf('<p class="subtitle">%s</p>', $details['subtitle']);
- if (array_key_exists('html',$details)) {
- $ret[] = $details['html'];
- } elseif (array_key_exists('list',$details)) {
- $ret[] = '<ul>';
- foreach ($details['list'] as $name => $info) {
- $ret[] = sprintf('<li>%s: <span id="detail_%s"></span></li>', $info['name'], $name);
- }
- $ret[] = '</ul>';
+ if ($hasFilter) {
+ $options['AutoFilter'] = true;
+ $options['FilterLocation'] = -1;
}
- $ret[] = '</div>';
- return $ret;
-}
-
-function build_select($name, $details)
-{
- $ret = array();
+ $html[] = '</tr>';
+ $html[] = '</table>';
- $ret[] = '<div class="form">';
- $ret[] = sprintf('<p class="title">%s</p>', $details['title']);
- $ret[] = sprintf ('<select%s>', array_key_exists('onchange',$details)?sprintf(' onchange="%s"',$details['onchange']):'');
- if (is_array($details['options']))
- $options = $details['options'];
- else
- $options = query_db($details['options']);
+ $html[] = '<div>';
+ $html[] = sprintf('<div class="info" id="info_grid_%s">Datensatz 0</div>', $gridName);
+ if ($name == 'main') $html[] = '<div class="status"><span id="status"></span></div>';
+ $html[] = '</div>';
- if (array_key_exists('default',$details))
- $ret[] = sprintf('<option value="">%s</option>', $details['default']);
+ grid_sql($gridName, $def);
- foreach ($options as $row) {
- $selected = array_key_exists('selected',$details) && $details['selected'] == $row['id'] ? true : false;
- $ret[] = sprintf('<option value="%s"%s>%s</option>', $row['id'], $selected?' selected':'',$row['text']);
- }
+ $grid = array('name' => $name,
+ 'gridname' => $gridName,
+ 'title' => $def['title'],
+ 'html' => implode('',$html),
+ 'options' => $options);
- $ret[] = '</select>';
- $ret[] = '</div>';
+ if (array_key_exists('width', $def))
+ $grid['width'] = $def['width'];
- return $ret;
+ return $grid;
}
-function build_mask($name, $mask)
+function build_mask($module, $page, $mask)
{
- global $jscode;
- $jscode[] = 'Rico.writeDebugMsg = function(msg, resetFlag) {};';
+ if (array_key_exists('edit', $mask) && check_edit($module, $page)) {
+ JavaScript::instance()->add('Hallinta.canEdit = true;');
+ Actions::instance()->addLink(new Link(array('id' => 'btn_edit',
+ 'icon' => Hallinta::instance()->urlbase().'images/icons/edit.png',
+ 'title' => 'Edit dialog',
+ 'function' => 'Hallinta.openEditDialog')));
+ }
if (array_key_exists('list', $mask)) {
- $jscode[] = "Rico.acceptLanguage('de-de,de;q=0.8,en;q=0.5,en-us;q=0.3');";
- $jscode[] = "Rico.loadModule('Effect','Calendar','LiveGridForms','LiveGridAjax','LiveGridMenu');";
-
- if (array_key_exists('second', $mask) && !array_key_exists('rows', $mask))
- $mask['rows'] = "'parent'";
-
- list($grid,$js) = build_grid($name, $mask);
- $grid = array_merge(array('<div id="div_grid">'), $grid, array('</div>'));
+ $grid = array('<div id="div_grid">', '</div>');
if (array_key_exists('second', $mask)) {
- $mask['second']['prefetch'] = false;
-
- list($second,$secondjs) = build_grid($name, $mask['second'], 'second');
- $jscode = array_merge($jscode, $secondjs);
-
- $grid[] = '<div id="second" class="second">';
- $close = '<img src="images/icons/minimise.gif" title="Hide" onclick="second_toggle()" />';
- $title = array_key_exists('title', $mask['second']) ? $mask['second']['title'] : '';
- $grid[] = sprintf('<div style="position: relative;" id="second_title" class="ricoTitle title"><strong>%s</strong>%s</div>', $title, $close);
-
- $grid = array_merge($grid, array('<div id="div_second">'), $second, array('</div>'));
-
- $grid[] = '</div>';
+ foreach ($mask['second'] as $sname => $second) {
+ if (!array_key_exists('title', $second)) throw new Exception('No title for secondary grid');
+
+ JavaScript::instance()->add(sprintf("Hallinta.openSecondaryGrid_%s = function(e) { Hallinta.openSecondaryGrid(e, '%s'); } ",
+ $sname, $sname));
+ Actions::instance()->addLink(new Link(array('id' => 'btn_' . $sname,
+ 'icon' => Hallinta::instance()->urlbase().'images/icons/liste.gif',
+ 'title' => 'Open ' . $second['title'],
+ 'function' => sprintf("Hallinta.openSecondaryGrid_%s", $sname))));
+ }
}
- $jscode = array_merge($jscode, $js);
- if ($mask['rows'] == "'parent'")
- $jscode[] = 'Rico.onLoad(function() {resize_grids()});';
} else
$grid = array();
- if (array_key_exists('details', $mask))
- $details = build_details($name, $mask['details']);
- else
- $details = array();
-
- if (array_key_exists('select', $mask))
- $select = build_select($name, $mask['select']);
- else
- $select = array();
-
- if (array_key_exists('edit', $mask) && check_edit($name))
- $edit = build_form($name, $mask);
- else
- $edit = array();
-
$title = $mask['title'];
if (array_key_exists('subtitle', $mask))
$title .= ' – ' . $mask['subtitle'];
+ Hallinta::instance()->setTitle($title);
$head = array();
- $head[] = sprintf('<h3 class="title">%s</h3>', $title);
if (array_key_exists('html', $mask) &&
- !array_key_exists('details', $mask) &&
- !array_key_exists('select', $mask) &&
!array_key_exists('edit', $mask))
return array_merge($head,
array($mask['html']),
array('<span id="status"></span><br>'));
- if (empty($details) && empty($select) && empty($edit))
+ if (empty($details))
return array_merge($head,
array('<div id="column_grid" class="grid">'),
$grid,
array('</div>'));
- else
- return array_merge($head,
- array('<div id="column_grid" class="right grid">'),
- $grid,
- array('</div>','<div id="column_edit" class="left">'),
- $details,
- $select,
- $edit,
- array('</div>'));
}
-function mask($name)
+function mask($module, $page)
{
- global $jsfiles;
global $mask;
$ret = array();
- if (load_mask($name) === false)
+ $styles = Styles::instance();
+ $styles->file('lib/rico3/ricoClient/css/rico.css');
+ $styles->file('lib/rico3/ricoClient/css/rico_icon.css');
+ $styles->file('lib/rico3/ricoClient/css/striping_cupertino.css');
+ $styles->file('lib/rico3/ui-cupertino/jquery-ui.css');
+ $styles->file('lib/rico3/ui-cupertino/jquery-ui_hallinta.css');
+
+ $javascript = JavaScript::instance();
+ $javascript->file('lib/rico3/ricoClient/js/rico2jqu.js');
+ $javascript->file('lib/rico3/minsrc/rico.js');
+ $javascript->file('lib/rico3/minsrc/ricoGridCommon.js');
+ $javascript->file('lib/rico3/minsrc/ricoLiveGrid.js');
+ $javascript->file('lib/rico3/minsrc/ricoLiveGridForms.js');
+ $javascript->file('lib/rico3/minsrc/ricoLiveGridAjax.js');
+ $javascript->file('lib/rico3/minsrc/ricoLiveGridMenu.js');
+ $javascript->file('lib/rico3/minsrc/ricoLiveGridControls.js');
+ $javascript->file('lib/rico3/minsrc/ricoLocale_en.js');
+ $javascript->file('lib/rico3/minsrc/ricoUI.js');
+ $javascript->file('lib/rico3/ricoClient/js/ricoThemeroller.js');
+ $javascript->file('lib/rico3/minsrc/ricoCalendar.js');
+ $javascript->onLoad('page_init();');
+
+ if (load_mask($module, $page) === false)
return;
- $jsfiles[] = 'lib/functions.js';
- $jsfiles[] = 'lib/rico/rico.js';
-
- if (array_key_exists('table',$mask))
- $ret = build_mask($name, $mask);
+ if (array_key_exists('table',$mask) || array_key_exists('html',$mask))
+ $ret = build_mask($module, $page, $mask);
- return sprintf('<span id="source" style="display: none;">%s</span>', $_GET['mask'])
- . implode("\n", $ret);
+ $javascript->add(sprintf('Hallinta.pageSource = "%s__%s";', $module, $page));
+ $javascript->add(sprintf('Hallinta.isMobile = %s;', Hallinta::instance()->isMobile()?'true':'false'));
+ return implode("\n", $ret);
}
-
-?>
+++ /dev/null
-<?php
-
-# Menu from http://lwis.net/free-css-drop-down-menu/dropdown.simple.horizontal.html
-
-function menu()
-{
- global $db;
-
- if (empty($_SESSION['sys']['login'])) return '';
-
- $ret = '<div class="menu">';
-
- $ret .= '<ul id="nav" class="dropdown dropdown-horizontal">';
-
- $ret .= '<li class="dir">Home';
- $ret .= '<ul>';
- $ret .= '<li><a href="./" title="Zurück zur Hauptseite">Start</a></li>';
- $ret .= '<li><a href="./?logout=true" title="Abmelden">Logout</a></li>';
-
- $sql = "SELECT fname,menutitle,sys_menu.name,title FROM sys_mask "
- . "JOIN sys_menu ON sys_mask.menu = sys_menu.id "
- . "JOIN sys_group_mask ON sys_mask.id = sys_group_mask.mask "
- . "WHERE sys_group_mask.gid = ".$_SESSION['sys']['group']." "
- . "AND shadow = 0 "
- . "ORDER BY sys_menu.priority,sys_menu.name,sys_mask.priority,sys_mask.menutitle";
- $list = $db->fetchObjectList($sql);
-
- if (count($list)) {
- $menu = 'Start';
-
- foreach ($list as $row) {
- if ($menu != $row->name) {
- $ret .= '</ul></li>';
- $ret .= sprintf('<li class="dir">%s', $row->name);
- $ret .= '<ul>';
- $menu = $row->name;
- }
- $ret .= sprintf('<li><a href="./?mask=%s"%s>%s</a></li>', str_replace('|','__',$row->fname),
- empty($row->title) ? '' : ' title="'.$row->title.'"',
- $row->menutitle);
- }
- $ret .= '</ul>';
- $ret .= '</li>';
- }
-
- $ret .= '</ul>';
- $ret .= '</div>';
-
- return $ret;
-}
-
-?>
\ No newline at end of file
<?php
-$jscode[] = <<<EOC
+$jscode = <<<EOC
function select_year_calback(data)
{
}
EOC;
+$javascript->add($jscode);
+
function discover_years()
{
if (!is_array($_SESSION['years'])) {
--- /dev/null
+<?php
+
+function php_to_bytes($value)
+{
+ $value = trim($value);
+ if (is_numeric($value)) {
+ return $value;
+ } else {
+ $value_length = strlen($value);
+ $qty = substr($value, 0, $value_length - 1);
+ $unit = strtolower(substr($value, $value_length - 1));
+ switch ($unit) {
+ case 'k':
+ $qty *= 1024;
+ break;
+ case 'm':
+ $qty *= 1048576;
+ break;
+ case 'g':
+ $qty *= 1073741824;
+ break;
+ }
+ return $qty;
+ }
+}
+
+function php_round($qty)
+{
+ if ($qty - intval($qty) != 0)
+ $qty = sprintf('%.2f', $qty);
+ return $qty;
+}
+
+function bytes_to_php($value)
+{
+ if ($value > 1073741824)
+ return php_round($value / 1073741824) . 'GB';
+ elseif ($value > 1048576)
+ return php_round($value / 1048576) . 'MB';
+ elseif ($value > 1024)
+ return php_round($value / 1024) . 'KB';
+ else
+ return $value . 'B';
+}
+
+function upload_max_filesize($limit=false)
+{
+ $values = array(php_to_bytes(ini_get('upload_max_filesize')),
+ php_to_bytes(ini_get('post_max_size')),
+ php_to_bytes(ini_get('memory_limit')));
+ if ($limit) $values[] = $limit;
+
+ return min($values);
+}
+
+?>
_getEncodedContent: function(parentNode) {
if (parentNode.innerHTML) {
- if (Prototype.Browser.Gecko && navigator.productSub >= "20100101")
+ if ((Prototype.Browser.Gecko && navigator.productSub >= "20100101") ||
+ Prototype.Browser.WebKit)
parentNode.innerHTML.replace(/</g,'<').replace(/>/g,'>').replace(/&/g,'&');
else
return parentNode.innerHTML;
positionCtlOverIcon: function(ctl,icon) {
var offsets=Position.page(icon);
var scrTop=this.docScrollTop();
+ var scrLeft=this.docScrollLeft();
var winHt=this.windowHeight();
if (ctl.style.display=='none') ctl.style.display='block';
var correction=Prototype.Browser.IE ? 1 : 2; // based on a 1px border
var lpad=this.nan2zero(Element.getStyle(icon,'padding-left'));
- ctl.style.left = (offsets[0]+lpad+correction)+'px';
+ ctl.style.left = (offsets[0]+lpad+correction+scrLeft)+'px';
var newTop=offsets[1] + correction + scrTop;
var ctlht=ctl.offsetHeight;
var iconht=icon.offsetHeight;
//var colnum = rowsElement.getAttribute("distinct");
var col=this.columns[parseInt(colnum,10)];
var rows = this.buffer.dom2jstable(rowsElement);
+ var found = !col.filterValues || !col.filterValues.length;
+ if (!found) for (var i=0; i<rows.length; i++) {
+ if (rows[i][0] == col.filterValues[0]) {
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ col.setUnfiltered(true);
+ if (this.options.filterHandler)
+ this.options.filterHandler();
+ }
var c0,c1,opt,v, field=$(this.filterId(colnum));
if (col.filterType==Rico.TableColumn.USERFILTER && col.filterOp=='EQ') v=col.filterValues[0];
Rico.writeDebugMsg('filterValuesUpdate: col='+colnum+' rows='+rows.length);
c1=RegExp.leftContext;
}
if (col._getdesc) c1 = col._getdesc(c1);
+ if (c1 == ' ') c1 = '';
opt=RicoUtil.addSelectOption(field,c0,c1 || RicoTranslate.getPhraseById("filterBlank"));
if (col.filterType==Rico.TableColumn.USERFILTER && c0==v) opt.selected=true;
}
processResponse: function() {
var responseText,success=true;
var respNodes=Element.select(this.responseDiv,'.ricoFormResponse');
- if (respNodes) {
+ if (respNodes && respNodes.length) {
// generate a translated response
var phraseId=$w(respNodes[0].className)[1];
responseText=RicoTranslate.getPhraseById(phraseId,this.options.RecordName);
//print_r($value);
foreach($value as $i => $filter) {
if ($i<0 || $i>=count($this->oParse->arSelList)) break;
- $newfilter=$this->oParse->arSelList[$i];
+ switch ($this->objDB->Dialect) {
+ case "PostgreSQL":
+ global $mask;
+ if ($filter['op'] == 'LIKE' &&
+ array_key_exists($this->oParse->arSelList[$i], $mask['list']) &&
+ array_key_exists('sqltype', $mask['list'][$this->oParse->arSelList[$i]]) &&
+ in_array($mask['list'][$this->oParse->arSelList[$i]]['sqltype'], array('date','int'))) {
+ $newfilter=sprintf('cast(%s as varchar(100))', $this->oParse->arSelList[$i]);
+ } else
+ $newfilter=$this->oParse->arSelList[$i];
+ break;
+ default:
+ $newfilter=$this->oParse->arSelList[$i];
+ break;
+ }
+
$this->setCondType($newfilter);
switch ($filter['op']) {
case "EQ":
+++ /dev/null
-/*****************************************************************
- Page : ricoLocale_ua.js
- Description : ukrainian localization strings
- Version 0.1 (revisions by Alexey Uvarov,Illiya Gannitskiy)
- If you would like to include translations for another language,
- please send them to dowdybrown@yahoo.com
-******************************************************************/
-RicoTranslate.langCode='ua';
-
-// used in ricoLiveGrid.js
-
-RicoTranslate.addPhraseId('bookmarkExact',"Перегляд записів $1 - $2 з $3");
-RicoTranslate.addPhraseId('bookmarkAbout',"Перегляд записів $1 - $2 з більш ніж $3");
-RicoTranslate.addPhraseId('bookmarkNoRec',"Немає записів");
-RicoTranslate.addPhraseId('bookmarkNoMatch',"Немає збігів");
-RicoTranslate.addPhraseId('bookmarkLoading',"Завантаження...");
-RicoTranslate.addPhraseId('sorting',"Сортування...");
-RicoTranslate.addPhraseId('exportStatus',"Експортується запис $1");
-RicoTranslate.addPhraseId('filterAll',"(всі)");
-RicoTranslate.addPhraseId('filterBlank',"(чистий)");
-RicoTranslate.addPhraseId('filterEmpty',"(порожній)");
-RicoTranslate.addPhraseId('filterNotEmpty',"(не порожній)");
-RicoTranslate.addPhraseId('filterLike',"як: $1");
-RicoTranslate.addPhraseId('filterNot',"не: $1");
-RicoTranslate.addPhraseId('requestError',"Запит даних повернув помилку:\n$1");
-RicoTranslate.addPhraseId('keywordPrompt',"Шукати по ключу (Використовуйте * для всіх записів):");
-
-// used in ricoLiveGridMenu.js
-
-RicoTranslate.addPhraseId('gridmenuSortBy',"Сортування по: $1");
-RicoTranslate.addPhraseId('gridmenuSortAsc',"Зростаюча");
-RicoTranslate.addPhraseId('gridmenuSortDesc',"Убутна");
-RicoTranslate.addPhraseId('gridmenuFilterBy',"Фільтрація по: $1");
-RicoTranslate.addPhraseId('gridmenuRefresh',"Обновити");
-RicoTranslate.addPhraseId('gridmenuChgKeyword',"Змінити ключове слово...");
-RicoTranslate.addPhraseId('gridmenuExcludeAlso',"Виключити також це значення");
-RicoTranslate.addPhraseId('gridmenuInclude',"Включити тільки це значення");
-RicoTranslate.addPhraseId('gridmenuGreaterThan',"Більше або дорівнює даному значенню");
-RicoTranslate.addPhraseId('gridmenuLessThan',"Менше або дорівнює даному значенню");
-RicoTranslate.addPhraseId('gridmenuContains',"Містить значення...");
-RicoTranslate.addPhraseId('gridmenuExclude',"Виключити це значення");
-RicoTranslate.addPhraseId('gridmenuRemoveFilter',"Вилучити фільтр");
-RicoTranslate.addPhraseId('gridmenuRemoveAll',"Вилучити всі фільтри");
-
-RicoTranslate.addPhraseId('gridmenuExport',"Друк/Експорт"");
-RicoTranslate.addPhraseId('gridmenuExportVis2Web',"Видимі записи на веб-сторінку");
-RicoTranslate.addPhraseId('gridmenuExportAll2Web',"Усі записи на веб-сторінку");
-RicoTranslate.addPhraseId('gridmenuExportVis2SS',"Видимі записи в аркуш excel");
-RicoTranslate.addPhraseId('gridmenuExportAll2SS',"Усі записи в аркуш excel");
-
-RicoTranslate.addPhraseId('gridmenuHideShow',"Сховати/Показати");
-RicoTranslate.addPhraseId('gridmenuChooseCols',"Виберіть колонку...");
-RicoTranslate.addPhraseId('gridmenuHide',"Сховати: $1");
-RicoTranslate.addPhraseId('gridmenuShow',"Показати: $1");
-RicoTranslate.addPhraseId('gridmenuShowAll',"Показати всі");
-
-// used in ricoLiveGridAjax.js
-
-RicoTranslate.addPhraseId('sessionExpireMinutes',"хвилин до закінчення сесії");
-RicoTranslate.addPhraseId('sessionExpired',"МИНУЛА");
-RicoTranslate.addPhraseId('requestTimedOut',"Перевищений інтервал очікування даних!");
-RicoTranslate.addPhraseId('waitForData',"Очікування даних...");
-RicoTranslate.addPhraseId('httpError',"Отримана HTTP помилка: $1");
-RicoTranslate.addPhraseId('invalidResponse',"Сервер повернув неправильну відповідь");
-
-// used in ricoLiveGridCommon.js
-
-RicoTranslate.addPhraseId('gridChooseCols',"Вибрати колонку");
-RicoTranslate.addPhraseId('exportComplete',"Експорт завершений");
-RicoTranslate.addPhraseId('exportInProgress',"Експортування...");
-RicoTranslate.addPhraseId('showFilterRow',"Показати відфільтровані записи"); // img alt text
-RicoTranslate.addPhraseId('hideFilterRow',"Сховати відфільтровані записи"); // img alt text
-
-// used in ricoLiveGridForms.js
-
-RicoTranslate.addPhraseId('selectNone',"(нічого)");
-RicoTranslate.addPhraseId('selectNewVal',"(нове значення)");
-RicoTranslate.addPhraseId('record',"запис");
-RicoTranslate.addPhraseId('thisRecord',"ця $1");
-RicoTranslate.addPhraseId('confirmDelete',"Ви впевнені,що бажаєте видалити $1?");
-RicoTranslate.addPhraseId('deleting',"Видалення...");
-RicoTranslate.addPhraseId('formPleaseEnter',"Будь ласка, введіть значення для $1");
-RicoTranslate.addPhraseId('formInvalidFmt',"Неправильний формат для $1");
-RicoTranslate.addPhraseId('formOutOfRange',"Значення знаходиться поза діапазоном для $1");
-RicoTranslate.addPhraseId('formNewValue',"нове значення:");
-RicoTranslate.addPhraseId('saving',"Збереження...");
-RicoTranslate.addPhraseId('clear',"очистити");
-RicoTranslate.addPhraseId('close',"Закрити");
-RicoTranslate.addPhraseId('saveRecord',"Зберегти $1");
-RicoTranslate.addPhraseId('cancel',"Скасування");
-RicoTranslate.addPhraseId('editRecord',"Редагувати цю $1");
-RicoTranslate.addPhraseId('deleteRecord',"Вилучити цю $1");
-RicoTranslate.addPhraseId('cloneRecord',"Копіювати цю $1");
-RicoTranslate.addPhraseId('addRecord',"Додати нову $1");
-RicoTranslate.addPhraseId('addedSuccessfully',"$1 додана успішно");
-RicoTranslate.addPhraseId('deletedSuccessfully',"$1 вилучена успішно");
-RicoTranslate.addPhraseId('updatedSuccessfully',"$1 оновлена успішно");
-
-// used in ricoTree.js
-
-RicoTranslate.addPhraseId('treeSave',"Зберегти виділення");
-RicoTranslate.addPhraseId('treeClear',"Очистити все");
-
-// used in ricoCalendar.js
-
-RicoTranslate.addPhraseId('calToday',"Сьогодні $1 $2 $3"); // $1=day, $2=monthabbr, $3=year, $4=month number
-RicoTranslate.addPhraseId('calWeekHdg',"Тд");
-RicoTranslate.addPhraseId('calYearRange',"Рік ($1-$2)");
-RicoTranslate.addPhraseId('calInvalidYear',"Неправильний рік");
-
-// Date & number formats
-
-RicoTranslate.thouSep=","
-RicoTranslate.decPoint="."
-RicoTranslate.dateFmt="dd/mm/yyyy"
-
-RicoTranslate.monthNames=['Січень','Лютий','Березень','Квітень','Травень','Червень','Липень','Серпень','Вересень','Жовтень','Листопад','Грудень']
-RicoTranslate.dayNames=['Неділя','Понеділок','Вівторок','Середа','Четвер','П'ятниця','Субота']
--- /dev/null
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
--- /dev/null
+/*
+ * (c) 2005-2012 Richard Cowin (http://openrico.org)
+ * (c) 2005-2012 Matt Brown (http://dowdybrown.com)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this
+ * file except in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the specific language governing permissions
+ * and limitations under the License.
+ */
+
+Rico.Version='3.0';
+Rico.theme={};
+Rico.onLoadCallbacks=[];
+Rico.windowIsLoaded=false;
+Rico.inputtypes={search: 0, number: 0, range: 0, color: 0, tel: 0, url: 0, email: 0, date: 0, month: 0, week: 0, time: 0, datetime: 0, 'datetime-local': 0};
+
+// called by the document onload event
+Rico.windowLoaded=function() {
+ this.windowIsLoaded=true;
+ if (typeof Rico_CONFIG == 'object') {
+ if (Rico_CONFIG.enableLogging) this.enableLogging();
+ if (Rico_CONFIG.enableHTML5) this._CheckInputTypes();
+ }
+ Rico.writeDebugMsg=Rico.log; // for backwards compatibility
+ Rico.log('Processing callbacks');
+ while (this.onLoadCallbacks.length > 0) {
+ var callback=this.onLoadCallbacks.shift();
+ if (callback) callback();
+ }
+};
+
+// check for availability of HTML5 input types
+Rico._CheckInputTypes=function() {
+ var i = document.createElement("input");
+ for (var itype in this.inputtypes) {
+ i.setAttribute("type", "text");
+ i.setAttribute("type", itype);
+ this.inputtypes[itype]=(i.type !== "text");
+ }
+};
+
+Rico.onLoad=function(callback,frontOfQ) {
+ if (this.windowIsLoaded)
+ callback();
+ else if (frontOfQ)
+ this.onLoadCallbacks.unshift(callback);
+ else
+ this.onLoadCallbacks.push(callback);
+};
+
+Rico.isKonqueror=navigator.userAgent.toLowerCase().indexOf("konqueror") > -1;
+Rico.isIE=!!(window.attachEvent && navigator.userAgent.indexOf('Opera') === -1);
+Rico.isOpera=navigator.userAgent.indexOf('Opera') > -1;
+Rico.isWebKit=navigator.userAgent.indexOf('AppleWebKit/') > -1;
+Rico.isGecko=navigator.userAgent.indexOf('Gecko') > -1 && navigator.userAgent.indexOf('KHTML') === -1;
+Rico.ieVersion=/MSIE (\d+\.\d+);/.test(navigator.userAgent) ? new Number(RegExp.$1) : null;
+
+// logging funtions
+
+Rico.startTime=new Date();
+
+Rico.timeStamp=function() {
+ var stamp = new Date();
+ return (stamp.getTime()-this.startTime.getTime())+": ";
+};
+
+Rico.setDebugArea=function(id, forceit) {
+ if (!this.debugArea || forceit) {
+ var newarea=document.getElementById(id);
+ if (!newarea) return;
+ this.debugArea=newarea;
+ newarea.value='';
+ }
+};
+
+Rico.log=function() {};
+
+Rico.enableLogging=function() {
+ if (this.debugArea) {
+ this.log = function(msg, resetFlag) {
+ if (resetFlag) this.debugArea.value='';
+ this.debugArea.value+=this.timeStamp()+msg+"\n";
+ };
+ } else if (window.console) {
+ if (window.console.firebug)
+ this.log = function(msg) { window.console.log(this.timeStamp(),msg); };
+ else
+ this.log = function(msg) { window.console.log(this.timeStamp()+msg); };\r
+ } else if (window.opera) {
+ this.log = function(msg) { window.opera.postError(this.timeStamp()+msg); };
+ }
+};
+
+Rico.$=function(e) {
+ return typeof e == 'string' ? document.getElementById(e) : e;
+};
+
+Rico.runLater=function() {
+ var args = Array.prototype.slice.call(arguments);
+ var msec = args.shift();
+ var object = args.shift();
+ var method = args.shift();
+ return setTimeout(function() { object[method].apply(object,args); },msec);
+};
+
+Rico.visible=function(element) {
+ return Rico.getStyle(element,"display") != 'none';
+};
+
+Rico.show=function(element) {
+ element.style.display = '';
+};
+
+Rico.hide=function(element) {
+ element.style.display = 'none';
+};
+
+Rico.toggle=function(element) {
+ element.style.display = element.style.display == 'none' ? '' : 'none';
+};
+
+// ltr or rtl
+Rico.direction=function(element) {
+ return (Rico.getStyle(element,'direction') || 'ltr').toLowerCase();
+};
+
+Rico.viewportOffset=function(element) {
+ var offset=Rico.cumulativeOffset(element);
+ offset.left -= this.docScrollLeft();
+ offset.top -= this.docScrollTop();
+ return offset;
+};
+
+/**
+ * Return text within an html element
+ * @param el DOM node
+ * @param xImg true to exclude img tag info
+ * @param xForm true to exclude input, select, and textarea tags
+ * @param xClass exclude elements with a class name of xClass
+ */
+Rico.getInnerText=function(el,xImg,xForm,xClass) {
+ switch (typeof el) {
+ case 'string': return el;
+ case 'undefined': return el;
+ case 'number': return el.toString();
+ }
+ var cs = el.childNodes;
+ var l = cs.length;
+ var str = "";
+ for (var i = 0; i < l; i++) {
+ switch (cs[i].nodeType) {
+ case 1: //ELEMENT_NODE
+ if (this.getStyle(cs[i],'display')=='none') continue;
+ if (xClass && this.hasClass(cs[i],xClass)) continue;
+ switch (cs[i].tagName.toLowerCase()) {
+ case 'img': if (!xImg) str += cs[i].alt || cs[i].title || cs[i].src; break;
+ case 'input': if (!xForm && !cs[i].disabled && cs[i].type.toLowerCase()=='text') str += cs[i].value; break;
+ case 'select': if (!xForm && cs[i].selectedIndex>=0) str += cs[i].options[cs[i].selectedIndex].text; break;
+ case 'textarea': if (!xForm && !cs[i].disabled) str += cs[i].value; break;
+ default: str += this.getInnerText(cs[i],xImg,xForm,xClass); break;
+ }
+ break;
+ case 3: //TEXT_NODE
+ str += cs[i].nodeValue;
+ break;
+ }
+ }
+ return str;
+};
+
+/**
+ * Return value of a node in an XML response.
+ * For Konqueror 3.5, isEncoded must be true.
+ */
+Rico.getContentAsString=function( parentNode, isEncoded ) {
+ if (isEncoded) return this._getEncodedContent(parentNode);
+ if (typeof parentNode.xml != 'undefined') return this._getContentAsStringIE(parentNode);
+ return this._getContentAsStringMozilla(parentNode);
+};
+
+Rico._getEncodedContent=function(parentNode) {
+ if (parentNode.innerHTML) {
+ if (Rico.isGecko && navigator.productSub >= "20100101" || Rico.isWebKit)
+ parentNode.innerHTML.replace(/</g,'<').replace(/>/g,'>').replace(/&/g,'&');
+ else
+ return parentNode.innerHTML;
+ }
+
+ switch (parentNode.childNodes.length) {
+ case 0: return "";
+ case 1: return parentNode.firstChild.nodeValue;
+ default: return parentNode.childNodes[1].nodeValue;
+ }
+};
+
+Rico._getContentAsStringIE=function(parentNode) {
+ var contentStr = "";
+ for ( var i = 0 ; i < parentNode.childNodes.length ; i++ ) {
+ var n = parentNode.childNodes[i];
+ contentStr += (n.nodeType == 4) ? n.nodeValue : n.xml;
+ }
+ return contentStr;
+};
+
+Rico._getContentAsStringMozilla=function(parentNode) {
+ var xmlSerializer = new XMLSerializer();
+ var contentStr = "";
+ for ( var i = 0 ; i < parentNode.childNodes.length ; i++ ) {
+ var n = parentNode.childNodes[i];
+ if (n.nodeType == 4) { // CDATA node
+ contentStr += n.nodeValue;
+ }
+ else {
+ contentStr += xmlSerializer.serializeToString(n);
+ }
+ }
+ return contentStr;
+};
+
+/**
+ * @param n a number (or a string to be converted using parseInt)
+ * @returns the integer value of n, or 0 if n is not a number
+ */
+Rico.nan2zero=function(n) {
+ if (typeof(n)=='string') n=parseInt(n,10);
+ return isNaN(n) || typeof(n)=='undefined' ? 0 : n;
+};
+
+Rico.stripTags=function(s) {
+ return s.replace(/<\/?[^>]+>/gi, '');
+};
+
+Rico.truncate=function(s,length) {
+ return s.length > length ? s.substr(0, length - 3) + '...' : s;
+};
+
+Rico.zFill=function(n,slen, radix) {
+ var s=n.toString(radix || 10);
+ while (s.length<slen) s='0'+s;
+ return s;
+};
+
+Rico.keys=function(obj) {
+ var objkeys=[];
+ for(var k in obj)
+ objkeys.push(k);
+ return objkeys;
+};
+
+/**
+ * @param e event object
+ * @returns the key code stored in the event
+ */
+Rico.eventKey=function(e) {
+ if( typeof( e.keyCode ) == 'number' ) {
+ return e.keyCode; //DOM
+ } else if( typeof( e.which ) == 'number' ) {
+ return e.which; //NS 4 compatible
+ } else if( typeof( e.charCode ) == 'number' ) {
+ return e.charCode; //also NS 6+, Mozilla 0.9+
+ }
+ return -1; //total failure, we have no way of obtaining the key code
+};
+
+Rico.eventLeftClick=function(e) {
+ return (((e.which) && (e.which == 1)) ||
+ ((e.button) && (e.button == 1)));
+};
+
+Rico.eventRelatedTarget=function(e) {
+ return e.relatedTarget;
+};
+
+ /**
+ * Return the previous sibling that has the specified tagName
+ */
+ Rico.getPreviosSiblingByTagName=function(el,tagName) {
+ var sib=el.previousSibling;
+ while (sib) {
+ if ((sib.tagName==tagName) && (sib.style.display!='none')) return sib;
+ sib=sib.previousSibling;
+ }
+ return null;
+ };
+
+/**
+ * Return the parent of el that has the specified tagName.
+ * @param el DOM node
+ * @param tagName tag to search for
+ * @param className optional
+ */
+Rico.getParentByTagName=function(el,tagName,className) {
+ var par=el;
+ tagName=tagName.toLowerCase();
+ while (par) {
+ if (par.tagName && par.tagName.toLowerCase()==tagName) {
+ if (!className || par.className.indexOf(className)>=0) return par;
+ }
+ par=par.parentNode;
+ }
+ return null;
+};
+
+/**
+ * Wrap the children of a DOM element in a new element
+ * @param el the element whose children are to be wrapped
+ * @param cls class name of the wrapper (optional)
+ * @param id id of the wrapper (optional)
+ * @param wrapperTag type of wrapper element to be created (optional, defaults to DIV)
+ * @returns new wrapper element
+ */
+Rico.wrapChildren=function(el,cls,id,wrapperTag) {
+ var wrapper = document.createElement(wrapperTag || 'div');
+ if (id) wrapper.id=id;
+ if (cls) wrapper.className=cls;
+ while (el.firstChild) {
+ wrapper.appendChild(el.firstChild);
+ }
+ el.appendChild(wrapper);
+ return wrapper;
+};
+
+/**
+ * Positions ctl over icon
+ * @param ctl (div with position:absolute)
+ * @param icon element (img, button, etc) that ctl should be displayed next to
+ */
+Rico.positionCtlOverIcon=function(ctl,icon) {
+ icon=this.$(icon);
+ var offsets=this.cumulativeOffset(icon);
+ var scrTop=this.docScrollTop();
+ var scrLeft=this.docScrollLeft();
+ var winHt=this.windowHeight();
+ if (ctl.style.display=='none') ctl.style.display='block';
+ var correction=2; // based on a 1px border
+ if (Rico.direction(icon) == 'rtl') {
+ //var margin=this.nan2zero(this.getStyle(icon,'marginRight'));
+ ctl.style.left = (offsets.left + icon.offsetWidth - ctl.offsetWidth)+'px';
+ } else {
+ var margin=this.nan2zero(this.getStyle(icon,'marginLeft'));
+ ctl.style.left = (offsets.left+margin+correction+scrLeft)+'px';
+ }
+ var newTop=offsets.top + correction;// + scrTop;
+ var ctlht=ctl.offsetHeight;
+ var iconht=icon.offsetHeight;
+ var margin=10; // account for shadow
+ if (newTop+iconht+ctlht+margin < winHt+scrTop) {
+ newTop+=iconht; // display below icon
+ } else {
+ newTop=Math.max(newTop-ctlht,scrTop); // display above icon
+ }
+ ctl.style.top = newTop+'px';
+};
+
+/**
+ * Creates a form element
+ * @param parent new element will be appended to this node
+ * @param elemTag element to be created (input, button, select, textarea, ...)
+ * @param elemType for input tag this specifies the type (checkbox, radio, text, ...)
+ * @param id id for new element
+ * @param name name for new element, if not specified then name will be the same as the id
+ * @returns new element
+ */
+Rico.createFormField=function(parent,elemTag,elemType,id,name) {
+ var field;
+ if (typeof name!='string') name=id;
+ if (this.isIE && this.ieVersion < 8) {
+ // IE cannot set NAME attribute on dynamically created elements
+ var s=elemTag+' id="'+id+'"';
+ if (elemType) {
+ s+=' type="'+elemType+'"';
+ }
+ if (elemTag.match(/^(form|input|select|textarea|object|button|img)$/)) {
+ s+=' name="'+name+'"';
+ }
+ field=document.createElement('<'+s+' />');
+ } else {
+ field=document.createElement(elemTag);
+ if (elemType) {
+ field.type=elemType;
+ }
+ field.id=id;
+ if (typeof field.name=='string') {
+ field.name=name;
+ }
+ }
+ parent.appendChild(field);
+ return field;
+};
+
+/**
+ * Adds a new option to the end of a select list
+ * @returns new option element
+ */
+Rico.addSelectOption=function(elem,value,text) {
+ var opt=document.createElement('option');
+ if (typeof value=='string') opt.value=value;
+ opt.text=text;
+ if (this.isIE) {
+ elem.add(opt);
+ } else {
+ elem.add(opt,null);
+ }
+ return opt;
+};
+
+/**
+ * @returns the value of the specified cookie (or null if it doesn't exist)
+ */
+Rico.getCookie=function(itemName) {
+ var arg = itemName+'=';
+ var alen = arg.length;
+ var clen = document.cookie.length;
+ var i = 0;
+ while (i < clen) {
+ var j = i + alen;
+ if (document.cookie.substring(i, j) == arg) {
+ var endstr = document.cookie.indexOf (';', j);
+ if (endstr == -1) {
+ endstr=document.cookie.length;
+ }
+ return unescape(document.cookie.substring(j, endstr));
+ }
+ i = document.cookie.indexOf(' ', i) + 1;
+ if (i == 0) break;
+ }
+ return null;
+};
+
+Rico.getTBody=function(tab) {
+ return tab.tBodies.length==0 ? tab.appendChild(document.createElement("tbody")) : tab.tBodies[0];
+};
+
+/**
+ * Write information to a cookie.
+ * For cookies to be retained for the current session only, set daysToKeep=null.
+ * To erase a cookie, pass a negative daysToKeep value.
+ * @see <a href="http://www.quirksmode.org/js/cookies.html">Quirksmode article</a> for more information about cookies.
+ */
+Rico.setCookie=function(itemName,itemValue,daysToKeep,cookiePath,cookieDomain) {
+ var c = itemName+"="+escape(itemValue);
+ if (typeof(daysToKeep)=='number') {
+ var date = new Date();
+ date.setTime(date.getTime()+(daysToKeep*24*60*60*1000));
+ c+="; expires="+date.toGMTString();
+ }
+ if (typeof(cookiePath)=='string') {
+ c+="; path="+cookiePath;
+ }
+ if (typeof(cookieDomain)=='string') {
+ c+="; domain="+cookieDomain;
+ }
+ document.cookie = c;
+};
+
+Rico.phrasesById = {};
+/** thousands separator for number formatting */
+Rico.thouSep = ",";
+/** decimal point for number formatting */
+Rico.decPoint = ".";
+/** target language (2 character code) */
+Rico.langCode = "en";
+/** date format */
+Rico.dateFmt = "mm/dd/yyyy";
+/** time format */
+Rico.timeFmt = "hh:nn:ss a/pm";
+/** month name array (Jan is at index 0) */
+Rico.monthNames = ['January','February','March','April','May','June','July','August','September','October','November','December'];
+/** day of week array (Sunday is at index 0) */
+Rico.dayNames = ['Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday'];
+
+/**
+ * @param monthIdx 0-11
+ * @returns month abbreviation
+ */
+Rico.monthAbbr=function(monthIdx) {
+ return this.monthNamesShort ? this.monthNamesShort[monthIdx] : this.monthNames[monthIdx].substr(0,3);
+};
+
+/**
+ * @param dayIdx 0-6 (Sunday=0)
+ * @returns day of week abbreviation
+ */
+Rico.dayAbbr=function(dayIdx) {
+ return this.dayNamesShort ? this.dayNamesShort[dayIdx] : this.dayNames[dayIdx].substr(0,3);
+};
+
+Rico.addPhraseId=function(phraseId, phrase) {
+ this.phrasesById[phraseId]=phrase;
+};
+
+Rico.getPhraseById=function(phraseId) {
+ var phrase=this.phrasesById[phraseId];
+ if (!phrase) {
+ alert('Error: missing phrase for '+phraseId);
+ return '';
+ }
+ if (arguments.length <= 1) return phrase;
+ var a=arguments;
+ return phrase.replace(/(\$\d)/g,
+ function($1) {
+ var idx=parseInt($1.charAt(1),10);
+ return (idx < a.length) ? a[idx] : '';
+ }
+ );
+};
+
+/**
+ * Format a positive number (integer or float)
+ * @param posnum number to format
+ * @param decPlaces the number of digits to display after the decimal point
+ * @param thouSep boolean indicating whether to insert thousands separator
+ * @returns formatted string
+ */
+Rico.formatPosNumber=function(posnum,decPlaces,thouSep) {
+ var a=posnum.toFixed(decPlaces).split(/\./);
+ if (thouSep) {
+ var rgx = /(\d+)(\d{3})/;
+ while (rgx.test(a[0])) {
+ a[0]=a[0].replace(rgx, '$1'+Rico.thouSep+'$2');
+ }
+ }
+ return a.join(Rico.decPoint);
+};
+
+/**
+ * Format a number according to the specs in fmt object.
+ * @returns string, wrapped in a span element with a class of: negNumber, zeroNumber, posNumber
+ * These classes can be set in CSS to display negative numbers in red, for example.
+ *
+ * @param n number to be formatted
+ * @param fmt may contain any of the following:<dl>
+ * <dt>multiplier </dt><dd> the original number is multiplied by this amount before formatting</dd>
+ * <dt>decPlaces </dt><dd> number of digits to the right of the decimal point</dd>
+ * <dt>thouSep </dt><dd> boolean indicating whether to insert thousands separator</dd>
+ * <dt>prefix </dt><dd> string added to the beginning of the result (e.g. a currency symbol)</dd>
+ * <dt>suffix </dt><dd> string added to the end of the result (e.g. % symbol)</dd>
+ * <dt>negSign </dt><dd> specifies format for negative numbers: L=leading minus, T=trailing minus, P=parens</dd>
+ *</dl>
+ */
+Rico.formatNumber=function(n,fmt) {
+ if (typeof n=='string') n=parseFloat(n.replace(/,/,'.'),10);
+ if (isNaN(n)) return 'NaN';
+ if (typeof fmt.multiplier=='number') n*=fmt.multiplier;
+ var decPlaces=typeof fmt.decPlaces=='number' ? fmt.decPlaces : 0;
+ var thouSep=typeof fmt.thouSep=='undefined' ? true : fmt.thouSep;
+ var prefix=fmt.prefix || "";
+ var suffix=fmt.suffix || "";
+ var negSign=typeof fmt.negSign=='string' ? fmt.negSign : "L";
+ negSign=negSign.toUpperCase();
+ var s,cls;
+ if (n<0.0) {
+ s=this.formatPosNumber(-n,decPlaces,thouSep);
+ if (negSign=="P") s="("+s+")";
+ s=prefix+s;
+ if (negSign=="L") s="-"+s;
+ if (negSign=="T") s+="-";
+ cls='negNumber';
+ } else {
+ cls=n==0.0 ? 'zeroNumber' : 'posNumber';
+ s=prefix+this.formatPosNumber(n,decPlaces,thouSep);
+ }
+ return "<span class='"+cls+"'>"+s+suffix+"</span>";
+};
+
+/**
+ * Converts a date to a string according to specs in fmt
+ * @returns formatted string
+ * @param d date to be formatted
+ * @param fmt string specifying the output format, may be one of the following:<dl>
+ * <dt>locale or localeDateTime</dt>
+ * <dd>use javascript's built-in toLocaleString() function</dd>
+ * <dt>localeDate or 'Long Date'</dt>
+ * <dd>use javascript's built-in toLocaleDateString() function</dd>
+ * <dt>translate or translateDateTime</dt>
+ * <dd>use the formats specified in the Rico.dateFmt and Rico.timeFmt properties</dd>
+ * <dt>translateDate or 'Short Date'</dt>
+ * <dd>use the date format specified in the Rico.dateFmt property</dd>
+ * <dt>Otherwise</dt>
+ * <dd>Any combination of: yyyy, yy, mmmm, mmm, mm, m, dddd, ddd, dd, d, hh, h, HH, H, nn, ss, a/p</dd>
+ *</dl>
+ */
+Rico.formatDate=function(d,fmt) {
+ var datefmt=(typeof fmt=='string') ? fmt : 'translateDate';
+ switch (datefmt) {
+ case 'locale':
+ case 'localeDateTime':
+ return d.toLocaleString();
+ case 'Long Date':
+ case 'localeDate':
+ return d.toLocaleDateString();
+ case 'translate':
+ case 'translateDateTime':
+ datefmt=this.dateFmt+' '+this.timeFmt;
+ break;
+ case 'Short Date':
+ case 'translateDate':
+ datefmt=this.dateFmt;
+ break;
+ }
+ return datefmt.replace(/(yyyy|yy|mmmm|mmm|mm|dddd|ddd|dd|d|hh|nn|ss|a\/p)/gi,
+ function($1) {
+ var h;
+ switch ($1) {
+ case 'yyyy': return d.getFullYear();
+ case 'yy': return d.getFullYear().toString().substr(2);
+ case 'mmmm': return Rico.monthNames[d.getMonth()];
+ case 'mmm': return Rico.monthAbbr(d.getMonth());
+ case 'mm': return Rico.zFill(d.getMonth() + 1, 2);
+ case 'm': return (d.getMonth() + 1);
+ case 'dddd': return Rico.dayNames[d.getDay()];
+ case 'ddd': return Rico.dayAbbr(d.getDay());
+ case 'dd': return Rico.zFill(d.getDate(), 2);
+ case 'd': return d.getDate();
+ case 'hh': return Rico.zFill((h = d.getHours() % 12) ? h : 12, 2);
+ case 'h': return ((h = d.getHours() % 12) ? h : 12);
+ case 'HH': return Rico.zFill(d.getHours(), 2);
+ case 'H': return d.getHours();
+ case 'nn': return Rico.zFill(d.getMinutes(), 2);
+ case 'ss': return Rico.zFill(d.getSeconds(), 2);
+ case 'a/p': return d.getHours() < 12 ? 'a' : 'p';
+ }
+ }
+ );
+};
+
+/**
+ * Converts a string in ISO 8601 format to a date object.
+ * @returns date object, or false if string is not a valid date or date-time.
+ * @param string value to be converted
+ * @param offset can be used to bias the conversion and must be in minutes if provided
+ * @see Based on <a href='http://delete.me.uk/2005/03/iso8601.html'>delete.me.uk article</a>
+ */
+Rico.setISO8601=function (string,offset) {
+ if (!string) return false;
+ var d = string.match(/(\d\d\d\d)(?:-?(\d\d)(?:-?(\d\d)(?:[T ](\d\d)(?::?(\d\d)(?::?(\d\d)(?:\.(\d+))?)?)?(Z|(?:([-+])(\d\d)(?::?(\d\d))?)?)?)?)?)?/);
+ if (!d) return false;
+ if (!offset) offset=0;
+ var date = new Date(d[1], 0, 1);
+
+ if (d[2]) { date.setMonth(d[2] - 1); }
+ if (d[3]) { date.setDate(d[3]); }
+ if (d[4]) { date.setHours(d[4]); }
+ if (d[5]) { date.setMinutes(d[5]); }
+ if (d[6]) { date.setSeconds(d[6]); }
+ if (d[7]) { date.setMilliseconds(Number("0." + d[7]) * 1000); }
+ if (d[8]) {
+ if (d[10] && d[11]) {
+ offset = (Number(d[10]) * 60) + Number(d[11]);
+ }
+ offset *= ((d[9] == '-') ? 1 : -1);
+ offset -= date.getTimezoneOffset();
+ }
+ var time = (Number(date) + (offset * 60 * 1000));
+ date.setTime(Number(time));
+ return date;
+};
+
+/**
+ * Convert date to an ISO 8601 formatted string.
+ * @param date date object to be converted
+ * @param format an integer in the range 1-6 (default is 6):<dl>
+ * <dt>1 (year)</dt>
+ * <dd>YYYY (eg 1997)</dd>
+ * <dt>2 (year and month)</dt>
+ * <dd>YYYY-MM (eg 1997-07)</dd>
+ * <dt>3 (complete date)</dt>
+ * <dd>YYYY-MM-DD (eg 1997-07-16)</dd>
+ * <dt>4 (complete date plus hours and minutes)</dt>
+ * <dd>YYYY-MM-DDThh:mmTZD (eg 1997-07-16T19:20+01:00)</dd>
+ * <dt>5 (complete date plus hours, minutes and seconds)</dt>
+ * <dd>YYYY-MM-DDThh:mm:ssTZD (eg 1997-07-16T19:20:30+01:00)</dd>
+ * <dt>6 (complete date plus hours, minutes, seconds and a decimal
+ * fraction of a second)</dt>
+ * <dd>YYYY-MM-DDThh:mm:ss.sTZD (eg 1997-07-16T19:20:30.45+01:00)</dd>
+ *</dl>
+ * @see Based on: <a href='http://www.codeproject.com/jscript/dateformat.asp'>codeproject.com article</a>
+ */
+Rico.toISO8601String=function (date, format, offset) {
+ if (!format) format=6;
+ if (!offset) {
+ offset = 'Z';
+ } else {
+ var d = offset.match(/([-+])([0-9]{2}):([0-9]{2})/);
+ var offsetnum = (Number(d[2]) * 60) + Number(d[3]);
+ offsetnum *= ((d[1] == '-') ? -1 : 1);
+ date = new Date(Number(Number(date) + (offsetnum * 60000)));
+ }
+
+ var zeropad = function (num) { return ((num < 10) ? '0' : '') + num; };
+
+ var str = date.getUTCFullYear();
+ if (format > 1) { str += "-" + zeropad(date.getUTCMonth() + 1); }
+ if (format > 2) { str += "-" + zeropad(date.getUTCDate()); }
+ if (format > 3) {
+ str += "T" + zeropad(date.getUTCHours()) +
+ ":" + zeropad(date.getUTCMinutes());
+ }
+ if (format > 5) {
+ var secs = Number(date.getUTCSeconds() + "." +
+ ((date.getUTCMilliseconds() < 100) ? '0' : '') +
+ zeropad(date.getUTCMilliseconds()));
+ str += ":" + zeropad(secs);
+ } else if (format > 4) {
+ str += ":" + zeropad(date.getUTCSeconds());
+ }
+
+ if (format > 3) { str += offset; }
+ return str;
+};
+
+/**
+ * Returns a new XML document object
+ */
+Rico.createXmlDocument=function() {
+ if (document.implementation && document.implementation.createDocument) {
+ var doc = document.implementation.createDocument("", "", null);
+ // some older versions of Moz did not support the readyState property
+ // and the onreadystate event so we patch it!
+ if (doc.readyState == null) {
+ doc.readyState = 1;
+ doc.addEventListener("load", function () {
+ doc.readyState = 4;
+ if (typeof doc.onreadystatechange == "function") {
+ doc.onreadystatechange();
+ }
+ }, false);
+ }
+ return doc;
+ }
+
+ if (window.ActiveXObject)
+ return Rico.tryFunctions(
+ function() { return new ActiveXObject('MSXML2.DomDocument'); },
+ function() { return new ActiveXObject('Microsoft.DomDocument');},
+ function() { return new ActiveXObject('MSXML.DomDocument'); },
+ function() { return new ActiveXObject('MSXML3.DomDocument'); }
+ ) || false;
+ return null;
+};
+
+/**
+ * Update the contents of an HTML element via an AJAX call
+ */
+Rico.ajaxUpdater = function(elem,url,options) {
+ this.updateSend(elem,url,options);
+};
+
+Rico.ajaxUpdater.prototype = {
+ updateSend : function(elem,url,options) {
+ this.element=elem;
+ this.onComplete=options.onComplete;
+ var self=this;
+ options.onComplete=function(xhr) { self.updateComplete(xhr); };
+ new Rico.ajaxRequest(url,options);
+ },
+
+ updateComplete : function(xhr) {
+ this.element.innerHTML=xhr.responseText;
+ if (this.onComplete) this.onComplete(xhr);
+ }
+};
+
+try { // fix IE background image flicker (credit: www.mister-pixel.com)
+ document.execCommand("BackgroundImageCache", false, true);
+} catch(err) {}
+Rico.eventBind(window,"load", Rico.eventHandle(Rico,'windowLoaded'));
--- /dev/null
+/*
+ * (c) 2005-2011 Richard Cowin (http://openrico.org)
+ * (c) 2005-2011 Matt Brown (http://dowdybrown.com)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this
+ * file except in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the specific language governing permissions
+ * and limitations under the License.
+ */
+
+// Inspired by code originally written by Tan Ling Wee on 2 Dec 2001
+
+Rico.CalendarControl = function(id,options) {
+ this.initialize(id,options);
+};
+
+Rico.CalendarControl.prototype = {
+/**
+ * @class Implements a pop-up Gregorian calendar.
+ * Dates of adoption of the Gregorian calendar vary by country - accurate as a US & British calendar from 14 Sept 1752 to present.
+ * Mark special dates with calls to addHoliday()
+ * @extends Rico.Popup
+ * @constructs
+ * @param id unique identifier
+ * @param options object may contain any of the following:<dl>
+ * <dt>startAt </dt><dd> week starts with 0=sunday, 1=monday? default=0</dd>
+ * <dt>showWeekNumber</dt><dd> show week number in first column? default=0</dd>
+ * <dt>showToday </dt><dd> show "Today is..." in footer? default=1</dd>
+ * <dt>dateFmt </dt><dd> date format for return value (one of values accepted by {@link Date#formatDate}), default=ISO8601</dd>
+ * <dt>minDate </dt><dd> earliest selectable date? default=today-50 years</dd>
+ * <dt>maxDate </dt><dd> last selectable date? default=today+50 years</dd>
+ *</dl>
+ */
+ initialize: function(id,options) {
+ this.id=id;
+ var today=new Date();
+ this.defaultMin = new Date(today.getFullYear()-50,0,1);
+ this.defaultMax = new Date(today.getFullYear()+50,11,31);
+ Rico.extend(this, new Rico.Popup());
+ Rico.extend(this.options, {
+ ignoreClicks:true,
+ startAt : 0,
+ showWeekNumber : 0,
+ showToday : 1,
+ dateFmt : 'ISO8601',
+ minDate : this.defaultMin,
+ maxDate : this.defaultMax
+ });
+ Rico.extend(this.options, options || {});
+ this.bPageLoaded=false;
+ this.Holidays={};
+ this.re=/^\s*(\w+)(\W)(\w+)(\W)(\w+)/i;
+ this.setDateFmt(this.options.dateFmt);
+ var self=this;
+ Rico.onLoad(function() { self.atLoad(); })
+ },
+
+
+ setDateFmt: function(fmt) {
+ this.dateFmt=(fmt=='rico') ? Rico.dateFmt : fmt;
+ Rico.log(this.id+' date format set to '+this.dateFmt);
+ this.dateParts={};
+ if (this.re.exec(this.dateFmt)) {
+ this.dateParts[RegExp.$1]=0;
+ this.dateParts[RegExp.$3]=1;
+ this.dateParts[RegExp.$5]=2;
+ }
+ },
+
+/**
+ * Call before displaying calendar to highlight special days
+ * @param d day (1-31)
+ * @param m month (1-12)
+ * @param y year (0 implies a repeating holiday)
+ * @param desc description
+ * @param bgColor background color for cell displaying this day (CSS value, defaults to '#DDF')
+ * @param txtColor text color for cell displaying this day (CSS value), if not specified it is displayed with the same color as other days
+ */
+ addHoliday : function(d, m, y, desc, bgColor, txtColor) {
+ this.Holidays[this.holidayKey(y,m-1,d)]={desc:desc, txtColor:txtColor, bgColor:bgColor || '#DDF'};
+ },
+
+/** @private */
+ holidayKey : function(y,m,d) {
+ return 'h'+Rico.zFill(y,4)+Rico.zFill(m,2)+Rico.zFill(d,2);
+ },
+
+ atLoad : function() {
+ Rico.log('Calendar#atLoad: '+this.id);
+ var div=Rico.$(this.id);
+ if (div) {
+ this.setDiv(div);
+ } else {
+ this.createContainer();
+ this.container.id=this.id;
+ }
+ Rico.addClass(this.content, Rico.theme.calendar || 'ricoCalContainer');
+ this.direction=Rico.direction(this.container);
+
+ var r,c,i,j,dow,a,s,tab;
+ this.colStart=this.options.showWeekNumber ? 1 : 0;
+ var colcnt=7+this.colStart
+ this.maintab=document.createElement("table");
+ this.maintab.cellSpacing=2;
+ this.maintab.cellPadding=0;
+ this.maintab.border=0;
+ this.maintab.style.borderCollapse='separate';
+ this.maintab.className=Rico.theme.calendarTable || 'ricoCalTab';
+
+ // thead (Navigation controls)
+ this.thead=this.maintab.createTHead();
+ r=this.thead.insertRow(-1);
+ this.heading=r.insertCell(-1);
+ this.heading.colSpan=colcnt;
+ //this.heading=this.content.appendChild(document.createElement("div"));
+ this.heading.className='RicoCalHeading';
+ if (Rico.theme.calendarHeading) Rico.addClass(this.heading,Rico.theme.calendarHeading)
+
+ // table footer (today)
+ if (this.options.showToday) {
+ this.tfoot=this.maintab.createTFoot();
+ this.tfoot.className='ricoCalFoot';
+ r=this.tfoot.insertRow(-1);
+ this.todayCell=r.insertCell(-1);
+ this.todayCell.colSpan=colcnt;
+ this.todayCell.className=Rico.theme.calendarFooter || 'ricoCalFoot';
+ Rico.eventBind(this.todayCell,"click", Rico.eventHandle(this,'selectNow'), false);
+ }
+
+ this.tbody=Rico.getTBody(this.maintab);
+ this.tbody.className='ricoCalBody';
+
+ this.content.style.display='block';
+ if (this.position == 'absolute') {
+ this.content.style.width='auto';
+ this.maintab.style.width='auto';
+ } else {
+ this.container.style.position='relative';
+ this.heading.style.position='static'; // fixes issue with ie7
+ this.content.style.padding='0px';
+ this.content.style.width='15em';
+ this.maintab.style.width='100%';
+ }
+
+ this.styles=[];
+ for (i=0; i<7; i++) {
+ r=this.tbody.insertRow(-1);
+ r.className=i==0 ? 'ricoCalDayNames' : 'row'+i;
+ if (this.options.showWeekNumber) {
+ c=r.insertCell(-1);
+ c.className='ricoCalWeekNum';
+ if (i==0) c.innerHTML=Rico.getPhraseById("calWeekHdg");
+ }
+ for (j=0; j<7; j++) {
+ c=r.insertCell(-1);
+ if (i==0) {
+ dow=(j+this.options.startAt) % 7;
+ c.innerHTML=Rico.dayAbbr(dow);
+ this.styles[j]='ricoCal'+dow;
+ } else {
+ c.className=this.styles[j];
+ if (Rico.theme.calendarDay) Rico.addClass(c,Rico.theme.calendarDay);
+ }
+ }
+ }
+
+ this.content.appendChild(this.maintab);
+ new Rico.HoverSet(this.tbody.getElementsByTagName('td'),{ hoverNodes: function(e) { return e.innerHTML.match(/^\d+$/) ? [e] : []; } });
+
+ this.navtab=this.heading.appendChild(document.createElement("table"));
+ this.navrow=this.navtab.insertRow(-1);
+ this._createTitleSection('Month');
+ this.navrow.insertCell(-1).innerHTML=" ";
+ this._createTitleSection('Year');
+ new Rico.HoverSet(this.heading.getElementsByTagName('a'));
+ if (this.position == 'absolute') this.heading.appendChild(Rico.closeButton(Rico.eventHandle(this,'close')));
+
+ // month selector
+ this.monthPopup=new Rico.Popup(document.createElement("div"),{shim:false,zIndex:10});
+ this.monthPopup.content.className='ricoCalMonthPrompt';
+ tab=document.createElement("table");
+ tab.className='ricoCalMenu';
+ if (Rico.theme.calendarPopdown) Rico.addClass(tab,Rico.theme.calendarPopdown);
+ tab.cellPadding=2;
+ tab.cellSpacing=0;
+ tab.border=0;
+ tab.style.borderCollapse='separate';
+ tab.style.margin='0px';
+ for (i=0; i<4; i++) {
+ r=tab.insertRow(-1);
+ for (j=0; j<3; j++) {
+ c=r.insertCell(-1);
+ a=document.createElement("a");
+ a.innerHTML=Rico.monthAbbr(i*3+j);
+ a.name=i*3+j;
+ if (Rico.theme.calendarDay) Rico.addClass(a,Rico.theme.calendarDay);
+ c.appendChild(a);
+ Rico.eventBind(a,"click", Rico.eventHandle(this,'selectMonth'), false);
+ }
+ }
+ new Rico.HoverSet(tab.getElementsByTagName('a'));
+ this.monthPopup.content.appendChild(tab);
+ this.container.appendChild(this.monthPopup.container);
+ this.monthPopup.closePopup();
+
+ // year selector
+ this.yearPopup=new Rico.Popup(document.createElement("div"),{shim:false,zIndex:10});
+ this.yearPopup.content.className='ricoCalYearPrompt';
+ if (Rico.theme.calendarPopdown) Rico.addClass(this.yearPopup.content,Rico.theme.calendarPopdown);
+ this.yearPrompt=document.createElement("p");
+ this.yearPrompt.innerHTML=" ";
+ var p2=document.createElement("p");
+ this.yearInput=p2.appendChild(document.createElement("input"));
+ this.yearInput.maxlength=4;
+ this.yearInput.size=4;
+ Rico.eventBind(this.yearInput,"keyup", Rico.eventHandle(this,'yearKey'), false);
+ a=Rico.floatButton('Checkmark', Rico.eventHandle(this,'processPopUpYear'));
+ p2.appendChild(a);
+ a=Rico.floatButton('Cancel', Rico.eventHandle(this,'popDownYear'));
+ p2.appendChild(a);
+ this.yearPopup.content.appendChild(this.yearPrompt);
+ this.yearPopup.content.appendChild(p2);
+ this.container.appendChild(this.yearPopup.container);
+ this.yearPopup.closePopup();
+
+ // fix anchors so they work in IE6
+ a=this.content.getElementsByTagName('a');
+ for (i=0; i<a.length; i++) {
+ a[i].href='javascript:void(0)';
+ }
+
+ Rico.eventBind(this.tbody,"click", Rico.eventHandle(this,'saveAndClose'));
+ this.bPageLoaded=true;
+ },
+
+ _createTitleSection : function(section) {
+ var arrows=['left','right'];
+ if (this.direction=='rtl') arrows.reverse();
+ var c=this.navrow.insertCell(-1);
+ var a=c.appendChild(document.createElement("a"));
+ a.className='Rico_'+arrows[0]+'Arrow';
+ a.appendChild(this._createNavArrow(arrows[0]));
+ Rico.eventBind(a,"click", Rico.eventHandle(this,'dec'+section), false);
+
+ c=this.navrow.insertCell(-1);
+ a=c.appendChild(document.createElement("a"));
+ Rico.eventBind(a,"click", Rico.eventHandle(this,'popUp'+section), false);
+ this['title'+section]=a;
+
+ c=this.navrow.insertCell(-1);
+ a=c.appendChild(document.createElement("a"));
+ a.className='Rico_'+arrows[1]+'Arrow';
+ a.appendChild(this._createNavArrow(arrows[1]));
+ Rico.eventBind(a,"click", Rico.eventHandle(this,'inc'+section), false);
+ },
+
+ _createNavArrow: function(direction) {
+ var span=document.createElement("span");
+ span.className=Rico.theme[direction+'Arrow'] || 'rico-icon Rico_'+direction+'Arrow';
+ span.style.display="inline-block";
+ return span;
+ },
+
+ selectNow : function() {
+ var today = new Date();
+ this.dateNow = today.getDate();
+ this.monthNow = today.getMonth();
+ this.yearNow = today.getFullYear();
+ this.monthSelected=this.monthNow;
+ this.yearSelected=this.yearNow;
+ this.constructCalendar();
+ },
+
+/**
+ * @returns true if yr/mo is within minDate/MaxDate
+ */
+ isValidMonth : function(yr,mo) {
+ if (yr < this.options.minDate.getFullYear()) return false;
+ if (yr == this.options.minDate.getFullYear() && mo < this.options.minDate.getMonth()) return false;
+ if (yr > this.options.maxDate.getFullYear()) return false;
+ if (yr == this.options.maxDate.getFullYear() && mo > this.options.maxDate.getMonth()) return false;
+ return true;
+ },
+
+ incMonth : function(e) {
+ if (e) Rico.eventStop(e);
+ var newMonth=this.monthSelected+1;
+ var newYear=this.yearSelected;
+ if (newMonth>11) {
+ newMonth=0;
+ newYear++;
+ }
+ if (!this.isValidMonth(newYear,newMonth)) return;
+ this.monthSelected=newMonth;
+ this.yearSelected=newYear;
+ this.constructCalendar();
+ },
+
+ decMonth : function(e) {
+ if (e) Rico.eventStop(e);
+ var newMonth=this.monthSelected-1;
+ var newYear=this.yearSelected;
+ if (newMonth<0) {
+ newMonth=11;
+ newYear--;
+ }
+ if (!this.isValidMonth(newYear,newMonth)) return;
+ this.monthSelected=newMonth;
+ this.yearSelected=newYear;
+ this.constructCalendar();
+ },
+
+/** @private */
+ selectMonth : function(e) {
+ var el=Rico.eventElement(e);
+ this.monthSelected=parseInt(el.name,10);
+ this.constructCalendar();
+ Rico.eventStop(e);
+ },
+
+ // position: 0=left, 1=right
+ openYrMo : function(popup,position) {
+ if (this.direction=='rtl') position=1-position;
+ popup.openPopup();
+ var left=position ? this.content.offsetWidth - popup.container.offsetWidth - 5 : 3;
+ popup.move(left, this.heading.offsetHeight+2);
+ },
+
+ popUpMonth : function(e) {
+ Rico.eventStop(e);
+ if (this.monthPopup.visible()) {
+ this.popDownMonth();
+ return false;
+ }
+ this.popDownYear();
+ this.openYrMo(this.monthPopup,0);
+ return false;
+ },
+
+ popDownMonth : function() {
+ this.monthPopup.closePopup();
+ },
+
+ popDownYear : function() {
+ this.yearPopup.closePopup();
+ this.yearInput.disabled=true; // make sure this does not get submitted
+ },
+
+/**
+ * Prompt for year
+ */
+ popUpYear : function(e) {
+ Rico.eventStop(e);
+ if (this.yearPopup.visible()) {
+ this.popDownYear();
+ return false;
+ }
+ this.popDownMonth();
+ this.yearPrompt.innerHTML=Rico.getPhraseById("calYearRange",this.options.minDate.getFullYear(),this.options.maxDate.getFullYear());
+ this.yearInput.disabled=false;
+ this.yearInput.value=''; // this.yearSelected
+ this.openYrMo(this.yearPopup,1);
+ var self=this;
+ setTimeout(function() { self.yearInput.focus(); }, 10); // ie8 has issues without this delay
+ return false;
+ },
+
+ yearKey : function(e) {
+ switch (Rico.eventKey(e)) {
+ case 27: this.popDownYear(); Rico.eventStop(e); return false;
+ case 13: this.processPopUpYear(); Rico.eventStop(e); return false;
+ }
+ return true;
+ },
+
+ processPopUpYear : function() {
+ var newYear=this.yearInput.value;
+ newYear=parseInt(newYear,10);
+ if (isNaN(newYear) || newYear<this.options.minDate.getFullYear() || newYear>this.options.maxDate.getFullYear()) {
+ alert(Rico.getPhraseById("calInvalidYear"));
+ } else {
+ this.yearSelected=newYear;
+ this.popDownYear();
+ this.constructCalendar();
+ }
+ },
+
+ incYear : function(e) {
+ if (e) Rico.eventStop(e);
+ if (this.yearSelected>=this.options.maxDate.getFullYear()) return;
+ this.yearSelected++;
+ this.constructCalendar();
+ },
+
+ decYear : function(e) {
+ if (e) Rico.eventStop(e);
+ if (this.yearSelected<=this.options.minDate.getFullYear()) return;
+ this.yearSelected--;
+ this.constructCalendar();
+ },
+
+ // tried a number of different week number functions posted on the net
+ // this is the only one that produced consistent results when comparing week numbers for December and the following January
+ WeekNbr : function(year,month,day) {
+ var when = new Date(year,month,day);
+ var newYear = new Date(year,0,1);
+ var offset = 7 + 1 - newYear.getDay();
+ if (offset == 8) offset = 1;
+ var daynum = ((Date.UTC(year,when.getMonth(),when.getDate(),0,0,0) - Date.UTC(year,0,1,0,0,0)) /1000/60/60/24) + 1;
+ var weeknum = Math.floor((daynum-offset+7)/7);
+ if (weeknum == 0) {
+ year--;
+ var prevNewYear = new Date(year,0,1);
+ var prevOffset = 7 + 1 - prevNewYear.getDay();
+ weeknum = (prevOffset == 2 || prevOffset == 8) ? 53 : 52;
+ }
+ return weeknum;
+ },
+
+ constructCalendar : function() {
+ var aNumDays = [31,0,31,30,31,30,31,31,30,31,30,31];
+ var startDate = new Date (this.yearSelected,this.monthSelected,1);
+ var endDate,numDaysInMonth,i,colnum;
+
+ if (typeof this.monthSelected!='number' || this.monthSelected>=12 || this.monthSelected<0) {
+ alert('ERROR in calendar: monthSelected='+this.monthSelected);
+ return;
+ }
+
+ if (this.monthSelected==1) {
+ endDate = new Date (this.yearSelected,this.monthSelected+1,1);
+ endDate = new Date (endDate - (24*60*60*1000));
+ numDaysInMonth = endDate.getDate();
+ } else {
+ numDaysInMonth = aNumDays[this.monthSelected];
+ }
+ var dayPointer = startDate.getDay() - this.options.startAt;
+ if (dayPointer<0) dayPointer+=7;
+ this.popDownMonth();
+ this.popDownYear();
+
+ //this.bgcolor=Rico.getStyle(this.tbody,'background-color');
+ //this.bgcolor=this.bgcolor.replace(/\"/g,'');
+ if (this.options.showWeekNumber) {
+ for (i=1; i<7; i++) {
+ this.tbody.rows[i].cells[0].innerHTML=' ';
+ }
+ }
+ for ( i=0; i<dayPointer; i++ ) {
+ this.resetCell(this.tbody.rows[1].cells[i+this.colStart]);
+ }
+
+ for ( var datePointer=1,r=1; datePointer<=numDaysInMonth; datePointer++,dayPointer++ ) {
+ colnum=dayPointer % 7;
+ if (this.options.showWeekNumber && colnum==0) {
+ this.tbody.rows[r].cells[0].innerHTML=this.WeekNbr(this.yearSelected,this.monthSelected,datePointer);
+ }
+ var c=this.tbody.rows[r].cells[colnum+this.colStart];
+ c.innerHTML=datePointer;
+ c.className=this.styles[colnum];
+ if ((datePointer==this.dateNow)&&(this.monthSelected==this.monthNow)&&(this.yearSelected==this.yearNow)) {
+ Rico.addClass(c,Rico.theme.calendarToday || 'ricoCalToday');
+ }
+ if (Rico.theme.calendarDay) Rico.addClass(c,Rico.theme.calendarDay);
+ if ((datePointer==this.odateSelected) && (this.monthSelected==this.omonthSelected) && (this.yearSelected==this.oyearSelected)) {
+ Rico.addClass(c,Rico.theme.calendarSelectedDay || 'ricoSelectedDay');
+ }
+ var h=this.Holidays[this.holidayKey(this.yearSelected,this.monthSelected,datePointer)];
+ if (!h) {
+ h=this.Holidays[this.holidayKey(0,this.monthSelected,datePointer)];
+ }
+ c.style.color=h ? h.txtColor : '';
+ c.style.backgroundColor=h ? h.bgColor : '';
+ c.title=h ? h.desc : '';
+ c.style.visibility='visible';
+ if (colnum==6) r++;
+ }
+ while (dayPointer<42) {
+ colnum=dayPointer % 7;
+ this.resetCell(this.tbody.rows[r].cells[colnum+this.colStart]);
+ dayPointer++;
+ if (colnum==6) r++;
+ }
+
+ this.titleMonth.innerHTML = Rico.monthAbbr(this.monthSelected);
+ this.titleYear.innerHTML = this.yearSelected;
+ if (this.todayCell) {
+ this.todayCell.innerHTML = Rico.getPhraseById("calToday",this.dateNow,Rico.monthAbbr(this.monthNow),this.yearNow,this.monthNow+1);
+ }
+ },
+
+/** @private */
+ resetCell: function(c) {
+ c.innerHTML=" ";
+ c.title='';
+ c.style.visibility='hidden';
+ },
+
+ close: function(e) {
+ if (e) Rico.eventStop(e);
+ this.closePopup();
+ },
+
+/** @private */
+ saveAndClose : function(e) {
+ Rico.eventStop(e);
+ var el=Rico.eventElement(e);
+ var s=el.innerHTML.replace(/ /g,'');
+ if (s=='' || el.className=='ricoCalWeekNum') return;
+ var day=parseInt(s,10);
+ if (isNaN(day)) return;
+ var d=new Date(this.yearSelected,this.monthSelected,day);
+ var dateStr=Rico.formatDate(d,this.dateFmt=='ISO8601' ? 'yyyy-mm-dd' : this.dateFmt);
+ if (this.returnValue) {
+ this.returnValue(dateStr);
+ this.closePopup();
+ }
+ },
+
+ open : function(curval,column) {
+ if (!this.bPageLoaded) return;
+ if (column) {
+ this.setDateFmt(column.format.dateFmt);
+ this.options.minDate=column.format.min || this.defaultMin;
+ this.options.maxDate=column.format.max || this.defaultMax;
+ }
+ var today = new Date();
+ this.dateNow = today.getDate();
+ this.monthNow = today.getMonth();
+ this.yearNow = today.getFullYear();
+ this.oyearSelected = -1;
+ if (typeof curval=='object') {
+ this.odateSelected = curval.getDate();
+ this.omonthSelected = curval.getMonth();
+ this.oyearSelected = curval.getFullYear();
+ } else if (this.dateFmt=='ISO8601') {
+ var d=Rico.setISO8601(curval);
+ if (d) {
+ this.odateSelected = d.getDate();
+ this.omonthSelected = d.getMonth();
+ this.oyearSelected = d.getFullYear();
+ }
+ } else if (this.re.exec(curval)) {
+ var aDate = [ RegExp.$1, RegExp.$3, RegExp.$5 ];
+ this.odateSelected = parseInt(aDate[this.dateParts.dd], 10);
+ this.omonthSelected = parseInt(aDate[this.dateParts.mm], 10) - 1;
+ this.oyearSelected = parseInt(aDate[this.dateParts.yyyy], 10);
+ if (this.oyearSelected < 100) {
+ // apply a century to 2-digit years
+ this.oyearSelected+=this.yearNow - (this.yearNow % 100);
+ var maxyr=this.options.maxDate.getFullYear();
+ while (this.oyearSelected > maxyr) this.oyearSelected-=100;
+ }
+ } else {
+ if (curval) {
+ alert('ERROR: invalid date passed to calendar ('+curval+')');
+ }
+ }
+ if (this.oyearSelected > 0) {
+ this.dateSelected=this.odateSelected;
+ this.monthSelected=this.omonthSelected;
+ this.yearSelected=this.oyearSelected;
+ } else {
+ this.dateSelected=this.dateNow;
+ this.monthSelected=this.monthNow;
+ this.yearSelected=this.yearNow;
+ }
+ this.constructCalendar();
+ this.openPopup();
+ }
+};
--- /dev/null
+/*
+ * (c) 2005-2009 Richard Cowin (http://openrico.org)
+ * (c) 2005-2009 Matt Brown (http://dowdybrown.com)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this
+ * file except in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the specific language governing permissions
+ * and limitations under the License.
+ */
+
+if(typeof Rico=='undefined') throw("GridCommon requires the Rico JavaScript framework");
+
+/**
+ * Define methods that are common to both SimpleGrid and LiveGrid
+ */
+Rico.GridCommon = {
+
+ baseInit: function() {
+ this.options = {
+ saveColumnInfo : {width:true, filter:false, sort:false}, // save info in cookies?
+ cookiePrefix : 'RicoGrid.',
+ allowColResize : true, // allow user to resize columns
+ windowResize : true, // Resize grid on window.resize event? Set to false when embedded in an accordian.
+ click : null,
+ dblclick : null,
+ contextmenu : null,
+ menuEvent : null, // event that triggers menus - click, dblclick, contextmenu, or none (no menus)
+ defaultWidth : -1, // if -1, then use unformatted column width
+ scrollBarWidth : 19, // this is the value used in positioning calculations, it does not actually change the width of the scrollbar
+ minScrollWidth : 100, // min scroll area width when width of frozen columns exceeds window width
+ frozenColumns : 0,
+ exportWindow : "height=400,width=500,scrollbars=1,menubar=1,resizable=1,location=0,toolbar=0,status=0",
+ exportStyleList : ['background-color','color','text-align','font-weight','font-size','font-family'],
+ exportImgTags : false, // applies to grid header and to SimpleGrid cells (not LiveGrid cells)
+ exportFormFields : true,
+ FilterLocation : null, // heading row number to place filters. -1=add a new heading row.
+ FilterAllToken : '___ALL___', // select box value to use to indicate ALL
+ columnSpecs : []
+ };
+ this.hdrCells=[];
+ this.headerColCnt=0;
+ this.headerRowIdx=0; // row in header which gets resizers (no colspan's in this row)
+ this.tabs=new Array(2);
+ this.thead=new Array(2);
+ this.tbody=new Array(2);
+ },
+
+ attachMenuEvents: function() {
+ var i;
+ if (!this.options.menuEvent || this.options.menuEvent=='none') return;
+ this.hideScroll=navigator.userAgent.match(/Macintosh\b.*\b(Firefox|Camino)\b/i) || (Rico.isOpera && parseFloat(window.opera.version())<9.5);
+ this.options[this.options.menuEvent]=Rico.eventHandle(this,'handleMenuClick');
+ if (this.highlightDiv) {
+ switch (this.options.highlightElem) {
+ case 'cursorRow':
+ this.attachMenu(this.highlightDiv[0]);
+ break;
+ case 'cursorCell':
+ for (i=0; i<2; i++) {
+ this.attachMenu(this.highlightDiv[i]);
+ }
+ break;
+ }
+ }
+ for (i=0; i<2; i++) {
+ this.attachMenu(this.tbody[i]);
+ }
+ },
+
+ attachMenu: function(elem) {
+ if (this.options.click)
+ Rico.eventBind(elem, 'click', this.options.click, false);
+ if (this.options.dblclick) {
+ if (Rico.isWebKit || Rico.isOpera)
+ Rico.eventBind(elem, 'click', Rico.eventHandle(this,'handleDblClick'), false);
+ else
+ Rico.eventBind(elem, 'dblclick', this.options.dblclick, false);
+ }
+ if (this.options.contextmenu) {
+ if (Rico.isOpera || Rico.isKonqueror)
+ Rico.eventBind(elem, 'click', Rico.eventHandle(this,'handleContextMenu'), false);
+ else
+ Rico.eventBind(elem, 'contextmenu', this.options.contextmenu, false);
+ }
+ },
+
+/**
+ * implement double-click for browsers that don't support a double-click event (e.g. Safari)
+ */
+ handleDblClick: function(e) {
+ var elem=Rico.eventElement(e);
+ if (this.dblClickElem == elem) {
+ this.options.dblclick(e);
+ } else {
+ this.dblClickElem = elem;
+ this.safariTimer=Rico.runLater(300,this,'clearDblClick');
+ }
+ },
+
+ clearDblClick: function() {
+ this.dblClickElem=null;
+ },
+
+/**
+ * implement right-click for browsers that don't support contextmenu event (e.g. Opera, Konqueror)
+ * use control-click instead
+ */
+ handleContextMenu: function(e) {
+ var b;
+ if( typeof( e.which ) == 'number' )
+ b = e.which; //Netscape compatible
+ else if( typeof( e.button ) == 'number' )
+ b = e.button; //DOM
+ else
+ return;
+ if (b==1 && e.ctrlKey) {
+ this.options.contextmenu(e);
+ }
+ },
+
+ cancelMenu: function() {
+ if (this.menu) this.menu.cancelmenu();
+ },
+
+/**
+ * gather info from original headings
+ */
+ getColumnInfo: function(hdrSrc) {
+ Rico.log('getColumnInfo: len='+hdrSrc.length);
+ if (hdrSrc.length == 0) return 0;
+ this.headerRowCnt=hdrSrc.length;
+ var r,c,colcnt;
+ for (r=0; r<this.headerRowCnt; r++) {
+ var headerRow = hdrSrc[r];
+ var headerCells=headerRow.cells;
+ if (r >= this.hdrCells.length) this.hdrCells[r]=[];
+ for (c=0; c<headerCells.length; c++) {
+ var obj={};
+ obj.cell=headerCells[c];
+ obj.colSpan=headerCells[c].colSpan || 1; // Safari & Konqueror return default colspan of 0
+ if (this.options.defaultWidth < 0) obj.initWidth=headerCells[c].offsetWidth;
+ this.hdrCells[r].push(obj);
+ }
+ if (headerRow.id.slice(-5)=='_main') {
+ colcnt=this.hdrCells[r].length;
+ this.headerRowIdx=r;
+ }
+ }
+ if (!colcnt) {
+ this.headerRowIdx=this.headerRowCnt-1;
+ colcnt=this.hdrCells[this.headerRowIdx].length;
+ }
+ Rico.log("getColumnInfo: colcnt="+colcnt);
+ return colcnt;
+ },
+
+ addHeadingRow: function(className) {
+ var r=this.headerRowCnt++;
+ this.hdrCells[r]=[];
+ for( var h=0; h < 2; h++ ) {
+ var row = this.thead[h].insertRow(-1);
+ var newClass='ricoLG_hdg '+this.tableId+'_hdg'+r;
+ if (className) newClass+=' '+className;
+ row.className=newClass;
+ var limit= h==0 ? this.options.frozenColumns : this.headerColCnt-this.options.frozenColumns;
+ for( var c=0; c < limit; c++ ) {
+ var hdrCell=row.insertCell(-1);
+ var colDiv=Rico.wrapChildren(hdrCell,'ricoLG_col');
+ Rico.wrapChildren(colDiv,'ricoLG_cell');
+ this.hdrCells[r].push({cell:hdrCell,colSpan:1});
+ }
+ }
+ return r;
+ },
+
+/**
+ * create column array
+ */
+ createColumnArray: function(columnType) {
+ this.direction=Rico.getStyle(this.outerDiv,'direction').toLowerCase(); // ltr or rtl
+ this.align=this.direction=='rtl' ? ['right','left'] : ['left','right'];
+ Rico.log('createColumnArray: dir='+this.direction);
+ for (var i=0; i<2; i++) Rico.addClass(this.thead[i].rows[this.headerRowIdx],'rico_ResizeRow');
+ this.columns = [];
+ for (var c=0; c < this.headerColCnt; c++) {
+ Rico.log("createColumnArray: c="+c);
+ var tabidx=c<this.options.frozenColumns ? 0 : 1;
+ var col=new Rico[columnType](this, c, this.hdrCells[this.headerRowIdx][c], tabidx);
+ this.columns.push(col);
+ if (c > 0) this.columns[c-1].next=col;
+ }
+ this.getCookie();
+ Rico.runLater(100,this,'insertResizers'); // avoids peek-a-boo bug in column 1 in IE6/7
+ },
+
+/**
+ * Insert resizing handles
+ */
+ insertResizers: function() {
+ if (!this.options.allowColResize) return;
+ for (var x=0;x<this.columns.length;x++) {
+ this.columns[x].insertResizer();
+ }
+ },
+
+/**
+ * Create div structure
+ */
+ createDivs: function() {
+ Rico.log("createDivs start");
+ this.outerDiv = this.createDiv("outer");
+ if (Rico.theme.gridContainer) Rico.addClass(this.outerDiv,Rico.theme.gridContainer);
+ if (this.outerDiv.firstChild && this.outerDiv.firstChild.tagName && this.outerDiv.firstChild.tagName.toUpperCase()=='TABLE') {
+ this.structTab=this.outerDiv.firstChild;
+ this.structTabLeft=this.structTab.rows[0].cells[0];
+ this.structTabUR=this.structTab.rows[0].cells[1];
+ this.structTabLR=this.structTab.rows[1].cells[0];
+ } else {
+ this.structTab = document.createElement("table");
+ this.structTab.border=0;
+ this.structTab.cellPadding=0;
+ this.structTab.cellSpacing=0;
+ var tr1=this.structTab.insertRow(-1);
+ tr1.vAlign='top';
+ this.structTabLeft=tr1.insertCell(-1);
+ this.structTabLeft.rowSpan=2;
+ this.structTabLeft.style.padding='0px';
+ this.structTabLeft.style.border='none';
+ var tr2=this.structTab.insertRow(-1);
+ tr2.vAlign='top';
+ this.structTabUR=tr1.insertCell(-1);
+ this.structTabUR.style.padding='0px';
+ this.structTabUR.style.border='none';
+ this.structTabLR=tr2.insertCell(-1);
+ this.structTabLR.style.padding='0px';
+ this.structTabLR.style.border='none';
+ this.outerDiv.appendChild(this.structTab);
+ }
+ Rico.addClass(this.structTab,'ricoLG_StructTab');
+ //this.structTabLR.style.overflow='hidden';
+ //if (Rico.isOpera) this.outerDiv.style.overflow="hidden";
+ this.frozenTabs = this.createDiv("frozenTabs",this.structTabLeft);
+ this.innerDiv = this.createDiv("inner",this.structTabUR);
+ this.scrollDiv = this.createDiv("scroll",this.structTabLR);
+ this.resizeDiv = this.createDiv("resize",this.outerDiv,true);
+
+ this.messagePopup=new Rico.Popup();
+ this.messagePopup.createContainer({hideOnEscape:false, hideOnClick:false, parent:this.outerDiv});
+ this.messagePopup.content.className='ricoLG_messageDiv';
+ if (Rico.theme.gridMessage) Rico.addClass(this.messagePopup.content,Rico.theme.gridMessage);
+
+ this.keywordPopup=new Rico.Window('', {zIndex:-1, parent:this.outerDiv});
+ Rico.addClass(this.keywordPopup.container, 'ricoLG_keywordDiv');
+ var instructions=this.keywordPopup.contentDiv.appendChild(document.createElement("p"));
+ instructions.innerHTML=Rico.getPhraseById("keywordPrompt");
+ this.keywordBox=this.keywordPopup.contentDiv.appendChild(document.createElement("input"));
+ this.keywordBox.size=20;
+ Rico.eventBind(this.keywordBox,"keypress", Rico.eventHandle(this,'keywordKey'), false);
+ this.keywordPopup.contentDiv.appendChild(Rico.floatButton('Checkmark', Rico.eventHandle(this,'processKeyword')));
+ var s=this.keywordPopup.contentDiv.appendChild(document.createElement("p"));
+ Rico.setStyle(s,{clear:'both'});
+
+ //this.frozenTabs.style[this.align[0]]='0px';
+ //this.innerDiv.style[this.align[0]]='0px';
+ Rico.log("createDivs end");
+ },
+
+ keywordKey: function(e) {
+ switch (Rico.eventKey(e)) {
+ case 27: this.closeKeyword(); Rico.eventStop(e); return false;
+ case 13: this.processKeyword(); Rico.eventStop(e); return false;
+ }
+ return true;
+ },
+
+ openKeyword: function(colnum) {
+ this.keywordCol=colnum;
+ this.keywordBox.value='';
+ this.keywordPopup.setTitle(this.columns[colnum].displayName);
+ this.keywordPopup.centerPopup();
+ this.keywordBox.focus();
+ },
+
+ closeKeyword: function() {
+ this.keywordPopup.closePopup();
+ this.cancelMenu();
+ },
+
+ processKeyword: function() {
+ var keyword=this.keywordBox.value;
+ this.closeKeyword();
+ this.columns[this.keywordCol].setFilterKW(keyword);
+ },
+
+/**
+ * Create a div and give it a standardized id and class name.
+ * If the div already exists, then just assign the class name.
+ */
+ createDiv: function(elemName,elemParent,hidden) {
+ var id=this.tableId+"_"+elemName+"Div";
+ var newdiv=document.getElementById(id);
+ if (!newdiv) {
+ newdiv = document.createElement("div");
+ newdiv.id = id;
+ if (elemParent) elemParent.appendChild(newdiv);
+ }
+ newdiv.className = "ricoLG_"+elemName+"Div";
+ if (hidden) Rico.hide(newdiv);
+ return newdiv;
+ },
+
+/**
+ * Common code used to size & position divs in both SimpleGrid & LiveGrid
+ */
+ baseSizeDivs: function() {
+ this.setOtherHdrCellWidths();
+
+ if (this.options.frozenColumns) {
+ Rico.show(this.tabs[0]);
+ Rico.show(this.frozenTabs);
+ // order of next 3 lines is critical in IE6
+ this.hdrHt=Math.max(Rico.nan2zero(this.thead[0].offsetHeight),this.thead[1].offsetHeight);
+ this.dataHt=Math.max(Rico.nan2zero(this.tbody[0].offsetHeight),this.tbody[1].offsetHeight);
+ this.frzWi=this.borderWidth(this.tabs[0]);
+ } else {
+ Rico.hide(this.tabs[0]);
+ Rico.hide(this.frozenTabs);
+ this.frzWi=0;
+ this.hdrHt=this.thead[1].offsetHeight;
+ this.dataHt=this.tbody[1].offsetHeight;
+ }
+
+ var wiLimit,i;
+ var borderWi=this.borderWidth(this.columns[0].dataCell);
+ Rico.log('baseSizeDivs '+this.tableId+': hdrHt='+this.hdrHt+' dataHt='+this.dataHt);
+ Rico.log(this.tableId+' frzWi='+this.frzWi+' borderWi='+borderWi);
+ for (i=0; i<this.options.frozenColumns; i++) {
+ if (this.columns[i].visible) this.frzWi+=parseInt(this.columns[i].colWidth,10)+borderWi;
+ }
+ this.scrTabWi=this.borderWidth(this.tabs[1]);
+ this.scrTabWi0=this.scrTabWi;
+ Rico.log('scrTabWi: '+this.scrTabWi);
+ for (i=this.options.frozenColumns; i<this.columns.length; i++) {
+ if (this.columns[i].visible) this.scrTabWi+=parseInt(this.columns[i].colWidth,10)+borderWi;
+ }
+ this.scrWi=this.scrTabWi+this.options.scrollBarWidth;
+ if (this.sizeTo=='parent') {
+ if (Rico.isIE) Rico.hide(this.outerDiv);
+ wiLimit=this.outerDiv.parentNode.offsetWidth;
+ if (Rico.isIE) Rico.show(this.outerDiv);
+ } else {
+ if (!Rico.isWebKit)
+ wiLimit=Rico.windowWidth()-this.options.scrollBarWidth-8;
+ }
+ if (this.outerDiv.parentNode.clientWidth > 0)
+ wiLimit=Math.min(this.outerDiv.parentNode.clientWidth, wiLimit);
+ var overage=this.frzWi+this.scrWi-wiLimit;
+ Rico.log('baseSizeDivs '+this.tableId+': scrWi='+this.scrWi+' wiLimit='+wiLimit+' overage='+overage+' clientWidth='+this.outerDiv.parentNode.clientWidth);
+ if (overage > 0 && this.options.frozenColumns < this.columns.length)
+ this.scrWi=Math.max(this.scrWi-overage, this.options.minScrollWidth);
+ this.scrollDiv.style.width=this.scrWi+'px';
+ //this.scrollDiv.style.top=this.hdrHt+'px';
+ //this.frozenTabs.style.width=this.scrollDiv.style[this.align[0]]=this.innerDiv.style[this.align[0]]=this.frzWi+'px';
+ this.frozenTabs.style.width=this.frzWi+'px';
+ this.outerDiv.style.width=(this.frzWi+this.scrWi)+'px';
+ },
+
+/**
+ * Returns the sum of the left & right border widths of an element
+ */
+ borderWidth: function(elem) {
+ var l=Rico.nan2zero(Rico.getStyle(elem,'borderLeftWidth'));
+ var r=Rico.nan2zero(Rico.getStyle(elem,'borderRightWidth'));
+ Rico.log((elem.id || elem.tagName)+' borderWidth: L='+l+', R='+r);
+ return l + r;
+// return Rico.nan2zero(Rico.getStyle(elem,'borderLeftWidth')) + Rico.nan2zero(Rico.getStyle(elem,'borderRightWidth'));
+ },
+
+ setOtherHdrCellWidths: function() {
+ var c,i,j,r,w,hdrcell,cell,origSpan,newSpan,divs;
+ for (r=0; r<this.hdrCells.length; r++) {
+ if (r==this.headerRowIdx) continue;
+ Rico.log('setOtherHdrCellWidths: r='+r);
+ c=i=0;
+ while (i<this.headerColCnt && c<this.hdrCells[r].length) {
+ hdrcell=this.hdrCells[r][c];
+ cell=hdrcell.cell;
+ origSpan=newSpan=hdrcell.colSpan;
+ for (w=j=0; j<origSpan; j++, i++) {
+ if (this.columns[i].hdrCell.style.display=='none')
+ newSpan--;
+ else if (this.columns[i].hdrColDiv.style.display!='none')
+ w+=parseInt(this.columns[i].colWidth,10);
+ }
+ if (!hdrcell.hdrColDiv || !hdrcell.hdrCellDiv) {
+ divs=cell.getElementsByTagName('div');
+ hdrcell.hdrColDiv=(divs.length<1) ? Rico.wrapChildren(cell,'ricoLG_col') : divs[0];
+ hdrcell.hdrCellDiv=(divs.length<2) ? Rico.wrapChildren(hdrcell.hdrColDiv,'ricoLG_cell') : divs[1];
+ }
+ if (newSpan==0) {
+ cell.style.display='none';
+ } else if (w==0) {
+ hdrcell.hdrColDiv.style.display='none';
+ cell.colSpan=newSpan;
+ } else {
+ cell.style.display='';
+ hdrcell.hdrColDiv.style.display='';
+ cell.colSpan=newSpan;
+ hdrcell.hdrColDiv.style.width=w+'px';
+ }
+ c++;
+ }
+ }
+ },
+
+ initFilterImage: function(filterRowNum){
+ this.filterAnchor=document.getElementById(this.tableId+'_filterLink');
+ if (!this.filterAnchor) return;
+ this.filterRows=Rico.select('tr.'+this.tableId+'_hdg'+filterRowNum);
+ if (this.filterRows.length!=2) return;
+ for (var i=0, r=[]; i<2; i++) r[i]=Rico.select('.ricoLG_cell',this.filterRows[i]);
+ this.filterElements=r[0].concat(r[1]);
+ this.saveHeight = this.filterElements[0].offsetHeight;
+ var pt=Rico.getStyle(this.filterElements[0],'paddingTop');
+ var pb=Rico.getStyle(this.filterElements[0],'paddingBottom');
+ if (pt) this.saveHeight-=parseInt(pt,10);
+ if (pb) this.saveHeight-=parseInt(pb,10);
+ this.rowNum = filterRowNum;
+ this.setFilterImage(false);
+ //Rico.eventBind(this.filterAnchor, 'click', Rico.eventHandle(this,'toggleFilterRow'), false);
+ },
+
+ toggleFilterRow: function() {
+ if ( Rico.visible(this.filterRows[0]) )
+ this.slideFilterUp();
+ else
+ this.slideFilterDown();
+ },
+
+ setFilterImage: function(expandFlag) {
+ var altText=Rico.getPhraseById((expandFlag ? 'show' : 'hide')+'FilterRow');
+ this.filterAnchor.innerHTML = '<img src="'+Rico.imgDir+'tableFilter'+(expandFlag ? 'Expand' : 'Collapse')+'.gif" alt="'+altText+'" border="0">';
+ },
+
+/**
+ * Returns a div for the cell at the specified row and column index.
+ * In SimpleGrid, r can refer to any row in the grid.
+ * In LiveGrid, r refers to a visible row (row 0 is the first visible row).
+ */
+ cell: function(r,c) {
+ return (0<=c && c<this.columns.length && r>=0) ? this.columns[c].cell(r) : null;
+ },
+
+/**
+ * Returns the screen height available for a grid
+ */
+ availHt: function() {
+ var divPos=Rico.cumulativeOffset(this.outerDiv);
+ return Rico.windowHeight()-divPos.top-2*this.options.scrollBarWidth-15; // allow for scrollbar and some margin
+ },
+
+ hideMsg: function() {
+ this.messagePopup.closePopup();
+ },
+
+ showMsg: function(msg) {
+ this.messagePopup.setContent(msg);
+ this.messagePopup.centerPopup();
+ Rico.log("showMsg: "+msg);
+ },
+
+/**
+ * @return array of column objects which have invisible status
+ */
+ listInvisible: function(attr) {
+ var hiddenColumns=[];
+ for (var x=0;x<this.columns.length;x++) {
+ if (!this.columns[x].visible)
+ hiddenColumns.push(attr ? this.columns[x][attr] : this.columns[x]);
+ }
+ return hiddenColumns;
+ },
+
+/**
+ * @return index of left-most visibile column, or -1 if there are no visible columns
+ */
+ firstVisible: function() {
+ for (var x=0;x<this.columns.length;x++) {
+ if (this.columns[x].visible) return x;
+ }
+ return -1;
+ },
+
+/**
+ * Show all columns
+ */
+ showAll: function() {
+ var invisible=this.listInvisible();
+ for (var x=0;x<invisible.length;x++)
+ invisible[x].showColumn();
+ },
+
+ chooseColumns: function() {
+ this.menu.cancelmenu();
+ var x,z,col,itemDiv,span,contentDiv;\r
+ if (!this.columnChooser) {
+ Rico.log('creating columnChooser');
+ z=Rico.getStyle(this.outerDiv.offsetParent,'zIndex');
+ if (typeof z!='number') z=0;
+ this.columnChooser=new Rico.Window(Rico.getPhraseById('gridChooseCols'), {zIndex:z+2, parent:this.outerDiv});
+ Rico.addClass(this.columnChooser.container, 'ricoLG_chooserDiv');
+ contentDiv=this.columnChooser.contentDiv;
+ for (x=0;x<this.columns.length;x++) {
+ col=this.columns[x];
+ itemDiv=contentDiv.appendChild(document.createElement('div'));
+ col.ChooserBox=Rico.createFormField(itemDiv,'input','checkbox');
+ span=itemDiv.appendChild(document.createElement('span'));
+ span.innerHTML=col.displayName;
+ Rico.eventBind(col.ChooserBox, 'click', Rico.eventHandle(col,'chooseColumn'), false);
+ }
+ }
+ Rico.log('opening columnChooser');
+ this.columnChooser.openPopup(3,this.hdrHt+3);
+ for (x=0;x<this.columns.length;x++) {
+ this.columns[x].ChooserBox.checked=this.columns[x].visible;
+ this.columns[x].ChooserBox.disabled = !this.columns[x].canHideShow();
+ }
+ },
+
+ blankRow: function(r) {
+ for (var c=0; c < this.columns.length; c++) {
+ this.columns[c].clearCell(r);
+ }
+ },
+
+ getExportStyles: function(chkelem) {
+ var exportStyles=this.options.exportStyleList;
+ var bgImg=Rico.getStyle(chkelem,'backgroundImage');
+ if (!bgImg || bgImg=='none') return exportStyles;
+ for (var styles=[],i=0; i<exportStyles.length; i++)
+ if (exportStyles[i]!='background-color' && exportStyles[i]!='color') styles.push(exportStyles[i]);
+ return styles;
+ },
+
+/**
+ * Support function for printVisible()
+ */
+ exportStart: function() {
+ var r,c,i,j,hdrcell,newSpan,divs,cell;
+ var exportStyles=this.getExportStyles(this.thead[0]);
+ //alert(exportStyles.join('\n'));
+ this.exportRows=[];
+ this.exportText="<html><head></head><body><table border='1' cellspacing='0'>";\r
+ for (c=0; c<this.columns.length; c++) {\r
+ if (this.columns[c].visible) this.exportText+="<col width='"+parseInt(this.columns[c].colWidth,10)+"'>";
+ }\r
+ this.exportText+="<thead style='display: table-header-group;'>";
+ if (this.exportHeader) this.exportText+=this.exportHeader;
+ for (r=0; r<this.hdrCells.length; r++) {
+ if (this.hdrCells[r].length==0 || !Rico.visible(this.hdrCells[r][0].cell.parentNode)) continue;
+ this.exportText+="<tr>";
+ for (c=0,i=0; c<this.hdrCells[r].length; c++) {
+ hdrcell=this.hdrCells[r][c];
+ newSpan=hdrcell.colSpan;
+ for (j=0; j<hdrcell.colSpan; j++, i++) {
+ if (!this.columns[i].visible) newSpan--;
+ }
+ if (newSpan > 0) {
+ divs=Rico.select('.ricoLG_cell',hdrcell.cell);
+ cell=divs && divs.length>0 ? divs[0] : hdrcell.cell;
+ this.exportText+="<td style='"+this.exportStyle(cell,exportStyles)+"'";
+ if (hdrcell.colSpan > 1) this.exportText+=" colspan='"+newSpan+"'";
+ this.exportText+=">"+Rico.getInnerText(cell,!this.options.exportImgTags, !this.options.exportFormFields, 'NoExport')+"</td>";
+ }
+ }
+ this.exportText+="</tr>";
+ }
+ this.exportText+="</thead><tbody>";
+ },
+
+/**
+ * Support function for printVisible().
+ */
+ exportFinish: function() {
+ if (this.hideMsg) this.hideMsg();
+ window.status=Rico.getPhraseById('exportComplete');
+ if (this.exportRows.length > 0) this.exportText+='<tr>'+this.exportRows.join('</tr><tr>')+'</tr>';
+ if (this.exportFooter) this.exportText+=this.exportFooter;
+ this.exportText+="</tbody></table></body></html>";
+ if (this.cancelMenu) this.cancelMenu();
+ var w=window.open('','_blank',this.options.exportWindow);
+ if (w == null) {
+ alert(Rico.getPhraseById('disableBlocker'));
+ } else {
+ w.document.open();
+ w.document.write(this.exportText);
+ w.document.close();
+ }
+ this.exportText=undefined;
+ this.exportRows=undefined;
+ },
+
+/**
+ * Support function for printVisible()
+ */
+ exportStyle: function(elem,styleList) {
+ for (var i=0,s=''; i < styleList.length; i++) {
+ try {
+ var curstyle=Rico.getStyle(elem,styleList[i]);
+ if (curstyle) s+=styleList[i]+':'+curstyle+';';
+ } catch(e) {};
+ }
+ return s;
+ },
+
+/**
+ * Gets the value of the grid cookie and interprets the contents.
+ * All information for a particular grid is stored in a single cookie.
+ * This may include column widths, column hide/show status, current sort, and any column filters.
+ */
+ getCookie: function() {
+ var c=Rico.getCookie(this.options.cookiePrefix+this.tableId);
+ if (!c) return;
+ var cookieVals=c.split(',');
+ for (var i=0; i<cookieVals.length; i++) {
+ var v=cookieVals[i].split(':');
+ if (v.length!=2) continue;
+ var colnum=parseInt(v[0].slice(1),10);
+ if (colnum < 0 || colnum >= this.columns.length) continue;
+ var col=this.columns[colnum];
+ switch (v[0].charAt(0)) {
+ case 'w':
+ col.setColWidth(v[1]);
+ col.customWidth=true;
+ break;
+ case 'h':
+ if (v[1].toLowerCase()=='true')
+ col.hideshow(true,true);
+ else
+ col.hideshow(false,true);
+ break;
+ case 's':
+ if (!this.options.saveColumnInfo.sort || !col.sortable) break;
+ col.setSorted(v[1]);
+ break;
+ case 'f':
+ if (!this.options.saveColumnInfo.filter || !col.filterable) break;
+ var filterTemp=v[1].split('~');
+ col.filterOp=filterTemp.shift();
+ col.filterValues = [];
+ col.filterType = Rico.ColumnConst.USERFILTER;
+ for (var j=0; j<filterTemp.length; j++)
+ col.filterValues.push(unescape(filterTemp[j]));
+ break;
+ }
+ }
+ },
+
+/**
+ * Sets the grid cookie.
+ * All information for a particular grid is stored in a single cookie.
+ * This may include column widths, column hide/show status, current sort, and any column filters.
+ */
+ setCookie: function() {
+ var cookieVals=[];
+ for (var i=0; i<this.columns.length; i++) {
+ var col=this.columns[i];
+ if (this.options.saveColumnInfo.width) {
+ if (col.customWidth) cookieVals.push('w'+i+':'+col.colWidth);
+ if (col.customVisible) cookieVals.push('h'+i+':'+col.visible);
+ }
+ if (this.options.saveColumnInfo.sort) {
+ if (col.currentSort != Rico.ColumnConst.UNSORTED)
+ cookieVals.push('s'+i+':'+col.currentSort);
+ }
+ if (this.options.saveColumnInfo.filter && col.filterType == Rico.ColumnConst.USERFILTER) {
+ var filterTemp=[col.filterOp];
+ for (var j=0; j<col.filterValues.length; j++)
+ filterTemp.push(escape(col.filterValues[j]));
+ cookieVals.push('f'+i+':'+filterTemp.join('~'));
+ }
+ }
+ Rico.setCookie(this.options.cookiePrefix+this.tableId, cookieVals.join(','), this.options.cookieDays, this.options.cookiePath, this.options.cookieDomain);
+ }
+
+};
+
+
+Rico.ColumnConst = {
+ UNFILTERED: 0,
+ SYSTEMFILTER: 1,
+ USERFILTER: 2,
+
+ UNSORTED: 0,
+ SORT_ASC: "ASC",
+ SORT_DESC: "DESC",
+
+ MINWIDTH: 10
+}
+
+
+/**
+ * @class Define methods that are common to columns in both SimpleGrid and LiveGrid
+ */
+Rico.TableColumnBase = function() {};
+
+Rico.TableColumnBase.prototype = {
+
+/**
+ * Common code used to initialize the column in both SimpleGrid & LiveGrid
+ */
+ baseInit: function(liveGrid,colIdx,hdrInfo,tabIdx) {
+ Rico.log("TableColumnBase.baseInit index="+colIdx+" tabIdx="+tabIdx);
+ this.liveGrid = liveGrid;
+ this.index = colIdx;
+ this.hideWidth = Rico.isKonqueror || Rico.isWebKit || liveGrid.headerRowCnt>1 ? 5 : 2; // column width used for "hidden" columns. Anything less than 5 causes problems with Konqueror. Best to keep this greater than padding used inside cell.
+ this.options = liveGrid.options;
+ this.tabIdx = tabIdx;
+ this.hdrCell = hdrInfo.cell;
+ this.body = document.getElementsByTagName("body")[0];
+ this.displayName = this.getDisplayName(this.hdrCell);
+ var divs=this.hdrCell.getElementsByTagName('div');
+ this.hdrColDiv=(divs.length<1) ? Rico.wrapChildren(this.hdrCell,'ricoLG_col') : divs[0];
+ this.hdrCellDiv=(divs.length<2) ? Rico.wrapChildren(this.hdrColDiv,'ricoLG_cell') : divs[1];
+ var sectionIndex= tabIdx==0 ? colIdx : colIdx-liveGrid.options.frozenColumns;
+ this.dataCell = liveGrid.tbody[tabIdx].rows[0].cells[sectionIndex];
+ divs=this.dataCell.getElementsByTagName('div');
+ this.dataColDiv=(divs.length<1) ? Rico.wrapChildren(this.dataCell,'ricoLG_col') : divs[0];
+
+ this.mouseDownHandler= Rico.eventHandle(this,'handleMouseDown');
+ this.mouseMoveHandler= Rico.eventHandle(this,'handleMouseMove');
+ this.mouseUpHandler = Rico.eventHandle(this,'handleMouseUp');
+ this.mouseOutHandler = Rico.eventHandle(this,'handleMouseOut');
+
+ this.format={type:"text"};
+ var spec = liveGrid.options.columnSpecs[colIdx];
+ if (typeof spec == 'object') Rico.extend(this.format, spec);
+ Rico.addClass(this.dataColDiv, this.colClassName());
+ this.visible=true;
+ if (typeof this.format.visible=='boolean') this.visible=this.format.visible;
+ this.sortable = typeof this.format.canSort=='boolean' ? this.format.canSort : liveGrid.options.canSortDefault;
+ this.currentSort = Rico.ColumnConst.UNSORTED;
+ this.filterable = typeof this.format.canFilter=='boolean' ? this.format.canFilter : liveGrid.options.canFilterDefault;
+ this.filterType = Rico.ColumnConst.UNFILTERED;
+ this.hideable = typeof this.format.canHide=='boolean' ? this.format.canHide : liveGrid.options.canHideDefault;
+
+ var wi;
+ switch (typeof this.format.width) {
+ case 'number': wi=this.format.width; break;
+ case 'string': wi=parseInt(this.format.width,10); break;
+ default: wi=hdrInfo.initWidth; break;
+ }
+ wi=(typeof(wi)=='number') ? Math.max(wi,Rico.ColumnConst.MINWIDTH) : liveGrid.options.defaultWidth;
+ this.setColWidth(wi);
+ if (!this.visible) this.setDisplay('none');
+ },
+
+ colClassName: function() {
+ return this.format.ClassName ? this.format.ClassName : this.liveGrid.tableId+'_col'+this.index;
+ },
+
+ insertResizer: function() {
+ //this.hdrCell.style.width='';
+ if (this.format.noResize) return;
+ var resizer=document.createElement('div');
+ resizer.className='ricoLG_Resize';
+ resizer.style[this.liveGrid.align[1]]='0px';
+ this.hdrCellDiv.appendChild(resizer);
+ Rico.eventBind(resizer,"mousedown", this.mouseDownHandler, false);
+ },
+
+/**
+ * get the display name of a column
+ */
+ getDisplayName: function(el) {
+ var anchors=el.getElementsByTagName("A");
+ var s=anchors.length > 0 ? anchors[0].innerHTML : Rico.stripTags(el.innerHTML);
+ return Rico.trim(s);
+ },
+
+ _clear: function(gridCell) {
+ gridCell.innerHTML=' ';
+ },
+
+ clearCell: function(rowIndex) {
+ var gridCell=this.cell(rowIndex);
+ this._clear(gridCell,rowIndex);
+ if (this.liveGrid.buffer && this.liveGrid.buffer.options.acceptStyle) gridCell.style.cssText='';
+ },
+
+ dataTable: function() {
+ return this.liveGrid.tabs[this.tabIdx];
+ },
+
+ numRows: function() {
+ return this.dataColDiv.childNodes.length;
+ },
+
+ clearColumn: function() {
+ var childCnt=this.numRows();
+ for (var r=0; r<childCnt; r++)
+ this.clearCell(r);
+ },
+
+ cell: function(r) {
+ return this.dataColDiv.childNodes[r];
+ },
+
+ getFormattedValue: function(r,xImg,xForm,xClass) {
+ return Rico.getInnerText(this.cell(r),xImg,xForm,xClass);
+ },
+
+ setColWidth: function(wi) {
+ if (typeof wi=='number') {
+ wi=parseInt(wi,10);
+ if (wi < Rico.ColumnConst.MINWIDTH) return;
+ wi=wi+'px';
+ }
+ Rico.log('setColWidth '+this.index+': '+wi);
+ this.colWidth=wi;
+ this.hdrColDiv.style.width=wi;
+ this.dataColDiv.style.width=wi;
+ },
+
+ pluginMouseEvents: function() {
+ if (this.mousePluggedIn==true) return;
+ Rico.eventBind(this.body,"mousemove", this.mouseMoveHandler, false);
+ Rico.eventBind(this.body,"mouseup", this.mouseUpHandler , false);
+ Rico.eventBind(this.body,"mouseout", this.mouseOutHandler , false);
+ this.mousePluggedIn=true;
+ },
+
+ unplugMouseEvents: function() {
+ Rico.eventUnbind(this.body,"mousemove", this.mouseMoveHandler, false);
+ Rico.eventUnbind(this.body,"mouseup", this.mouseUpHandler , false);
+ Rico.eventUnbind(this.body,"mouseout", this.mouseOutHandler , false);
+ this.mousePluggedIn=false;
+ },
+
+ handleMouseDown: function(e) {
+ this.resizeStart=Rico.eventClient(e).x;
+ this.origWidth=parseInt(this.colWidth,10);
+ var p=Rico.positionedOffset(this.hdrCell);
+ if (this.liveGrid.direction=='rtl') {
+ this.edge=p.left;
+ switch (this.tabIdx) {
+ case 0: this.edge+=this.liveGrid.innerDiv.offsetWidth; break;
+ case 1: this.edge-=this.liveGrid.scrollDiv.scrollLeft; break;
+ }
+ } else {
+ this.edge=p.left+this.hdrCell.offsetWidth;
+ if (this.tabIdx>0) this.edge+=Rico.nan2zero(this.liveGrid.tabs[0].offsetWidth);
+ }
+ this.liveGrid.resizeDiv.style.left=this.edge+"px";
+ this.liveGrid.resizeDiv.style.display="";
+ this.liveGrid.outerDiv.style.cursor='e-resize';
+ this.tmpHighlight=this.liveGrid.highlightEnabled;
+ this.liveGrid.highlightEnabled=false;
+ this.pluginMouseEvents();
+ Rico.eventStop(e);
+ },
+
+ handleMouseMove: function(e) {
+ var delta=Rico.eventClient(e).x-this.resizeStart;
+ var newWidth=(this.liveGrid.direction=='rtl') ? this.origWidth-delta : this.origWidth+delta;
+ if (newWidth < Rico.ColumnConst.MINWIDTH) return;
+ this.liveGrid.resizeDiv.style.left=(this.edge+delta)+"px";
+ this.colWidth=newWidth;
+ Rico.eventStop(e);
+ },
+
+ handleMouseUp: function(e) {
+ this.unplugMouseEvents();
+ Rico.log('handleMouseUp '+this.liveGrid.tableId);
+ this.liveGrid.outerDiv.style.cursor='';
+ this.liveGrid.resizeDiv.style.display="none";
+ this.setColWidth(this.colWidth);
+ this.customWidth=true;
+ this.liveGrid.setCookie();
+ this.liveGrid.highlightEnabled=this.tmpHighlight;
+ this.liveGrid.sizeDivs();
+ Rico.eventStop(e);
+ },
+
+ handleMouseOut: function(e) {
+ var reltg = Rico.eventRelatedTarget(e) || e.toElement;
+ while (reltg != null && reltg.nodeName.toLowerCase() != 'body')
+ reltg=reltg.parentNode;
+ if (reltg!=null && reltg.nodeName.toLowerCase() == 'body') return true;
+ this.handleMouseUp(e);
+ return true;
+ },
+
+ setDisplay: function(d) {
+ this.hdrCell.style.display=d;
+ this.hdrColDiv.style.display=d;
+ this.dataCell.style.display=d;
+ this.dataColDiv.style.display=d;
+ },
+
+ hideshow: function(visible,noresize) {
+ this.setDisplay(visible ? '' : 'none');
+ this.liveGrid.cancelMenu();
+ this.visible=visible;
+ this.customVisible=true;
+ if (noresize) return;
+ this.liveGrid.setCookie();
+ this.liveGrid.sizeDivs();
+ },
+
+ hideColumn: function() {
+ Rico.log('hideColumn '+this.liveGrid.tableId);
+ this.hideshow(false,false);
+ },
+
+ showColumn: function() {
+ Rico.log('showColumn '+this.liveGrid.tableId);
+ this.hideshow(true,false);
+ },
+
+ chooseColumn: function(e) {
+ var elem=Rico.eventElement(e);
+ this.hideshow(elem.checked,false);
+ },
+
+ setImage: function() {
+ if ( this.currentSort == Rico.ColumnConst.SORT_ASC ) {
+ this.imgSort.style.display='inline-block';
+ this.imgSort.className=Rico.theme.sortAsc || 'rico-icon ricoLG_sortAsc';
+ } else if ( this.currentSort == Rico.ColumnConst.SORT_DESC ) {
+ this.imgSort.style.display='inline-block';
+ this.imgSort.className=Rico.theme.sortDesc || 'rico-icon ricoLG_sortDesc';
+ } else {
+ this.imgSort.style.display='none';
+ }
+ if (this.filterType == Rico.ColumnConst.USERFILTER) {
+ this.imgFilter.style.display='inline-block';
+ this.imgFilter.title=this.getFilterText();
+ } else {
+ this.imgFilter.style.display='none';
+ }
+ },
+
+ canHideShow: function() {
+ return this.hideable;
+ }
+
+};
--- /dev/null
+/*
+ * (c) 2005-2011 Richard Cowin (http://openrico.org)
+ * (c) 2005-2011 Matt Brown (http://dowdybrown.com)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this
+ * file except in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the specific language governing permissions
+ * and limitations under the License.
+ */
+
+/** @namespace */
+if (!Rico.Buffer) Rico.Buffer = {};
+
+Rico.Buffer.Base = function(dataTable, options) {
+ this.initialize(dataTable, options);
+}
+/** @lends Rico.Buffer.Base# */
+Rico.Buffer.Base.prototype = {
+/**
+ * @class Defines the static buffer class (no AJAX).
+ * Loads buffer with data that already exists in the document as an HTML table or passed via javascript.
+ * Also serves as a base class for AJAX-enabled buffers.
+ * @constructs
+ */
+ initialize: function(dataTable, options) {
+ this.clear();
+ this.updateInProgress = false;
+ this.lastOffset = 0;
+ this.rcvdRowCount = false; // true if an eof element was included in the last response
+ this.foundRowCount = false; // true if a response is ever received with eof true
+ this.totalRows = 0;
+ this.rowcntContent = "";
+ this.rcvdOffset = -1;
+ this.options = {
+ fixedHdrRows : 0,
+ canFilter : true, // does buffer object support filtering?
+ isEncoded : true, // is the data received via ajax html encoded?
+ acceptStyle : false, // copy style from original/ajax data?
+ canRefresh : false // should "refresh" be shown on filter menu?
+ };
+ Rico.extend(this.options, options || {});
+ if (dataTable) {
+ this.loadRowsFromTable(dataTable,this.options.fixedHdrRows);
+ dataTable.parentNode.removeChild(dataTable); // delete the data once it has been loaded
+ }
+ },
+
+ registerGrid: function(liveGrid) {
+ this.liveGrid = liveGrid;
+ },
+
+ setTotalRows: function( newTotalRows ) {
+ if (typeof(newTotalRows)!='number') newTotalRows=this.size;
+ if (this.totalRows == newTotalRows) return;
+ this.totalRows = newTotalRows;
+ if (!this.liveGrid) return;
+ Rico.log("setTotalRows, newTotalRows="+newTotalRows);
+ switch (this.liveGrid.sizeTo) {
+ case 'data':
+ this.liveGrid.resizeWindow();
+ break;
+ case 'datamax':
+ this.liveGrid.setPageSize(newTotalRows);
+ break;
+ default:
+ this.liveGrid.updateHeightDiv();
+ break;
+ }
+ },
+
+ loadRowsFromTable: function(tableElement,firstRow) {
+ var newRows = [];
+ var trs = tableElement.getElementsByTagName("tr");
+ for ( var i=firstRow || 0; i < trs.length; i++ ) {
+ var row = [];
+ var cells = trs[i].getElementsByTagName("td");
+ for ( var j=0; j < cells.length ; j++ )
+ row[j]=cells[j].innerHTML;
+ newRows.push( row );
+ }
+ this.loadRows(newRows);
+ },
+
+ loadRowsFromArray: function(array2D) {
+ for ( var i=0; i < array2D.length; i++ ) {
+ for ( var j=0; j < array2D[i].length ; j++ ) {
+ array2D[i][j]=array2D[i][j].toString();
+ }
+ }
+ this.loadRows(array2D);
+ },
+
+ loadRows: function(jstable) {
+ this.baseRows = jstable;
+ this.startPos = 0;
+ this.size = this.baseRows.length;
+ },
+
+ dom2jstable: function(rowsElement) {
+ Rico.log('dom2jstable: encoded='+this.options.isEncoded);
+ var newRows = [];
+ var trs = rowsElement.getElementsByTagName("tr");
+ for ( var i=0; i < trs.length; i++ ) {
+ var row = [];
+ var cells = trs[i].getElementsByTagName("td");
+ for ( var j=0; j < cells.length ; j++ )
+ row[j]=Rico.getContentAsString(cells[j],this.options.isEncoded);
+ newRows.push( row );
+ }
+ return newRows;
+ },
+
+ _blankRow: function() {
+ var newRow=[];
+ for (var i=0; i<this.liveGrid.columns.length; i++) {
+ newRow[i]='';
+ }
+ return newRow;
+ },
+
+ deleteRows: function(rowIndex,cnt) {
+ this.baseRows.splice(rowIndex,typeof(cnt)=='number' ? cnt : 1);
+ this.liveGrid.isPartialBlank=true;
+ this.size=this.baseRows.length;
+ },
+
+ insertRow: function(beforeRowIndex) {
+ var r=this._blankRow();
+ this.baseRows.splice(beforeRowIndex,0,r);
+ this.size=this.baseRows.length;
+ this.liveGrid.isPartialBlank=true;
+ if (this.startPos < 0) this.startPos=0;
+ return r;
+ },
+
+ appendRows: function(cnt) {
+ var newRows=[];
+ for (var i=0; i<cnt; i++) {
+ var r=this._blankRow();
+ this.baseRows.push(r);
+ newRows.push(r);
+ }
+ this.size=this.baseRows.length;
+ this.liveGrid.isPartialBlank=true;
+ if (this.startPos < 0) this.startPos=0;
+ return newRows;
+ },
+
+ sortFunc: function(coltype) {
+ var self=this;
+ switch (coltype) {
+ case 'number': return function(a,b) { return self._sortNumeric(a,b); };
+ case 'control':return function(a,b) { return self._sortControl(a,b); };
+ default: return function(a,b) { return self._sortAlpha(a,b); };
+ }
+ },
+
+ sortBuffer: function(colnum) {
+ if (!this.baseRows) {
+ this.delayedSortCol=colnum;
+ return;
+ }
+ this.liveGrid.showMsg(Rico.getPhraseById("sorting"));
+ this.sortColumn=colnum;
+ var col=this.liveGrid.columns[colnum];
+ this.getValFunc=col._sortfunc;
+ this.baseRows.sort(this.sortFunc(col.format.type));
+ if (col.getSortDirection()=='DESC') this.baseRows.reverse();
+ },
+
+ _sortAlpha: function(a,b) {
+ var aa = this.sortColumn<a.length ? Rico.getInnerText(a[this.sortColumn]) : '';
+ var bb = this.sortColumn<b.length ? Rico.getInnerText(b[this.sortColumn]) : '';
+ if (aa==bb) return 0;
+ if (aa<bb) return -1;
+ return 1;
+ },
+
+ _sortNumeric: function(a,b) {
+ var aa = this.sortColumn<a.length ? this.nan2zero(Rico.getInnerText(a[this.sortColumn])) : 0;
+ var bb = this.sortColumn<b.length ? this.nan2zero(Rico.getInnerText(b[this.sortColumn])) : 0;
+ return aa-bb;
+ },
+
+ nan2zero: function(n) {
+ if (typeof(n)=='string') n=parseFloat(n);
+ return isNaN(n) || typeof(n)=='undefined' ? 0 : n;
+ },
+
+ _sortControl: function(a,b) {
+ var aa = this.sortColumn<a.length ? Rico.getInnerText(a[this.sortColumn]) : '';
+ var bb = this.sortColumn<b.length ? Rico.getInnerText(b[this.sortColumn]) : '';
+ if (this.getValFunc) {
+ aa=this.getValFunc(aa);
+ bb=this.getValFunc(bb);
+ }
+ if (aa==bb) return 0;
+ if (aa<bb) return -1;
+ return 1;
+ },
+
+ clear: function() {
+ this.baseRows = [];
+ this.rows = [];
+ this.modified = [];
+ this.attr = null;
+ this.startPos = -1;
+ this.size = 0;
+ this.windowPos = 0;
+ },
+
+ isInRange: function(position) {
+ var lastRow=Math.min(this.totalRows, position + this.liveGrid.pageSize);
+ return (position >= this.startPos) && (lastRow <= this.endPos()); // && (this.size != 0);
+ },
+
+ endPos: function() {
+ return this.startPos + this.rows.length;
+ },
+
+ fetch: function(offset) {
+ Rico.log('fetch '+this.liveGrid.tableId+': offset='+offset);
+ this.applyFilters();
+ this.setTotalRows();
+ this.rcvdRowCount = true;
+ this.foundRowCount = true;
+ if (offset < 0) offset=0;
+ this.liveGrid.refreshContents(offset);
+ return;
+ },
+
+/**
+ * @return a 2D array of buffer data representing the rows that are currently visible on the grid
+ */
+ visibleRows: function() {
+ return this.rows.slice(this.windowStart,this.windowEnd);
+ },
+
+ setWindow: function(startrow, endrow) {
+ this.windowStart = startrow - this.startPos; // position in the buffer of first visible row
+ Rico.log('setWindow '+this.liveGrid.tableId+': '+startrow+', '+endrow+', newstart='+this.windowStart);
+ this.windowEnd = Math.min(endrow,this.size); // position in the buffer of last visible row containing data+1
+ this.windowPos = startrow; // position in the dataset of first visible row
+ },
+
+/**
+ * @return true if bufRow is currently visible in the grid
+ */
+ isVisible: function(bufRow) {
+ return bufRow < this.rows.length && bufRow >= this.windowStart && bufRow < this.windowEnd;
+ },
+
+/**
+ * takes a window row index and returns the corresponding buffer row index
+ */
+ bufferRow: function(windowRow) {
+ return this.windowStart+windowRow;
+ },
+
+/**
+ * @return buffer cell at the specified visible row/col index
+ */
+ getWindowCell: function(windowRow,col) {
+ var bufrow=this.bufferRow(windowRow);
+ return this.isVisible(bufrow) && col < this.rows[bufrow].length ? this.rows[bufrow][col] : null;
+ },
+
+ getWindowStyle: function(windowRow,col) {
+ var bufrow=this.bufferRow(windowRow);
+ return this.attr && this.isVisible(bufrow) && this.attr[bufrow] && col < this.attr[bufrow].length ? this.attr[bufrow][col] : '';
+ },
+
+ getWindowValue: function(windowRow,col) {
+ return this.getWindowCell(windowRow,col);
+ },
+
+ setWindowValue: function(windowRow,col,newval) {
+ var bufrow=this.bufferRow(windowRow);
+ if (bufrow >= this.windowEnd) return false;
+ return this.setValue(bufrow,col,newval);
+ },
+
+ getCell: function(bufRow,col) {
+ return bufRow < this.size ? this.rows[bufRow][col] : null;
+ },
+
+ getValue: function(bufRow,col) {
+ return this.getCell(bufRow,col);
+ },
+
+ setValue: function(bufRow,col,newval,newstyle) {
+ if (bufRow>=this.size) return false;
+ if (!this.rows[bufRow][col]) this.rows[bufRow][col]={};
+ this.rows[bufRow][col]=newval;
+ if (this.options.acceptStyle && typeof newstyle=='string') {
+ if (!this.attr) this.attr=[];
+ if (!this.attr[bufRow]) this.attr[bufRow]=[];
+ this.attr[bufRow][col]=newstyle;
+ }
+ if (!this.modified[bufRow]) this.modified[bufRow]=[];
+ this.modified[bufRow][col]=true;
+ return true;
+ },
+
+ getRows: function(start, count) {
+ var begPos = start - this.startPos;
+ var endPos = Math.min(begPos + count,this.size);
+ var results = [];
+ for ( var i=begPos; i < endPos; i++ ) {
+ results.push(this.rows[i]);
+ }
+ return results;
+ },
+
+ applyFilters: function() {
+ var newRows=[],re=[];
+ var r,c,n,i,showRow,filtercnt;
+ var cols=this.liveGrid.columns;
+ for (n=0,filtercnt=0; n<cols.length; n++) {
+ c=cols[n];
+ if (c.filterType == Rico.ColumnConst.UNFILTERED) continue;
+ filtercnt++;
+ if (c.filterOp=='LIKE') re[n]=new RegExp(c.filterValues[0],'i');
+ }
+ Rico.log('applyFilters: # of filters='+filtercnt);
+ if (filtercnt==0) {
+ this.rows = this.baseRows;
+ } else {
+ for (r=0; r<this.baseRows.length; r++) {
+ showRow=true;
+ for (n=0; n<cols.length && showRow; n++) {
+ c=cols[n];
+ if (c.filterType == Rico.ColumnConst.UNFILTERED) continue;
+ switch (c.filterOp) {
+ case 'LIKE':
+ showRow=re[n].test(this.baseRows[r][n]);
+ break;
+ case 'EQ':
+ showRow=this.baseRows[r][n]==c.filterValues[0];
+ break;
+ case 'NE':
+ for (i=0; i<c.filterValues.length && showRow; i++)
+ showRow=this.baseRows[r][n]!=c.filterValues[i];
+ break;
+ case 'LE':
+ if (c.format.type=='number')
+ showRow=this.nan2zero(this.baseRows[r][n])<=this.nan2zero(c.filterValues[0]);
+ else
+ showRow=this.baseRows[r][n]<=c.filterValues[0];
+ break;
+ case 'GE':
+ if (c.format.type=='number')
+ showRow=this.nan2zero(this.baseRows[r][n])>=this.nan2zero(c.filterValues[0]);
+ else
+ showRow=this.baseRows[r][n]>=c.filterValues[0];
+ break;
+ case 'NULL':
+ showRow=this.baseRows[r][n]=='';
+ break;
+ case 'NOTNULL':
+ showRow=this.baseRows[r][n]!='';
+ break;
+ }
+ }
+ if (showRow) newRows.push(this.baseRows[r]);
+ }
+ this.rows = newRows;
+ }
+ this.rowcntContent = this.size = this.rows.length;
+ },
+
+ printAll: function() {
+ this.liveGrid.showMsg(Rico.getPhraseById('exportInProgress'));
+ Rico.runLater(10,this,'_printAll'); // allow message to paint
+ },
+
+/**
+ * Support function for printAll()
+ */
+ _printAll: function() {
+ this.liveGrid.exportStart();
+ this.exportBuffer(this.getRows(0,this.totalRows));
+ this.liveGrid.exportFinish();
+ },
+
+/**
+ * Copies visible rows to a new window as a simple html table.
+ */
+ printVisible: function() {
+ this.liveGrid.showMsg(Rico.getPhraseById('exportInProgress'));
+ Rico.runLater(10,this,'_printVisible'); // allow message to paint
+ },
+
+ _printVisible: function() {
+ this.liveGrid.exportStart();
+ this.exportBuffer(this.visibleRows());
+ this.liveGrid.exportFinish();
+ },
+
+/**
+ * Send all rows to print/export window
+ */
+ exportBuffer: function(rows,startPos) {
+ var r,c,v,col,exportText;
+ Rico.log("exportBuffer: "+rows.length+" rows");
+ var exportStyles=this.liveGrid.getExportStyles(this.liveGrid.tbody[0]);
+ var tdstyle=[];
+ var totalcnt=startPos || 0;
+ var cols=this.liveGrid.columns;
+ for (c=0; c<cols.length; c++) {
+ if (cols[c].visible) tdstyle[c]=this.liveGrid.exportStyle(cols[c].cell(0),exportStyles); // assumes row 0 style applies to all rows
+ }
+ for(r=0; r < rows.length; r++) {
+ exportText='';
+ for (c=0; c<cols.length; c++) {
+ if (!cols[c].visible) continue;
+ col=cols[c];
+ col.expStyle=tdstyle[c];
+ v=col._export(rows[r][c],rows[r]);
+ if (v=='') v=' ';
+ exportText+="<td style='"+col.expStyle+"'>"+v+"</td>";
+ }
+ this.liveGrid.exportRows.push(exportText);
+ totalcnt++;
+ if (totalcnt % 10 == 0) window.status=Rico.getPhraseById('exportStatus',totalcnt);
+ }
+ }
+
+};
+
+
+// Rico.LiveGrid -----------------------------------------------------
+
+Rico.LiveGrid = function(tableId, buffer, options) {
+ this.initialize(tableId, buffer, options);
+}
+
+/**
+ * @lends Rico.LiveGrid#
+ * @property tableId id string for this grid
+ * @property options the options object passed to the constructor extended with defaults
+ * @property buffer the buffer object containing the data for this grid
+ * @property columns array of {@link Rico.LiveGridColumn} objects
+ */
+Rico.LiveGrid.prototype = {
+/**
+ * @class Buffered LiveGrid component
+ * @extends Rico.GridCommon
+ * @constructs
+ */
+ initialize: function( tableId, buffer, options ) {
+ Rico.extend(this, Rico.GridCommon);
+ Rico.extend(this, Rico.LiveGridMethods);
+ this.baseInit();
+ this.tableId = tableId;
+ this.buffer = buffer;
+ this.actionId='_action_'+tableId;
+ Rico.setDebugArea(tableId+"_debugmsgs"); // if used, this should be a textarea
+
+ Rico.extend(this.options, {
+ visibleRows : -3, // -1 or 'window'=size grid to client window; -2 or 'data'=size grid to min(window,data); -3 or 'body'=size so body does not have a scrollbar; -4 or 'parent'=size to parent element (e.g. if grid is inside a div)
+ frozenColumns : 0,
+ offset : 0, // first row to be displayed
+ prefetchBuffer : true, // load table on page load?
+ minPageRows : 2,
+ maxPageRows : 50,
+ canSortDefault : true, // can be overridden in the column specs
+ canFilterDefault : buffer.options.canFilter, // can be overridden in the column specs
+ canHideDefault : true, // can be overridden in the column specs
+
+ // highlight & selection parameters
+ highlightElem : 'none',// what gets highlighted/selected (cursorRow, cursorCell, menuRow, menuCell, selection, or none)
+ highlightSection : 3, // which section gets highlighted (frozen=1, scrolling=2, all=3, none=0)
+ highlightMethod : 'class', // outline, class, both (outline is less CPU intensive on the client)
+ highlightClass : Rico.theme.gridHighlightClass || 'ricoLG_selection',
+
+ // export/print parameters
+ maxPrint : 5000, // max # of rows that can be printed/exported, 0=disable print/export feature
+
+ // heading parameters
+ headingSort : 'link', // link: make headings a link that will sort column, hover: make headings a hoverset, none: events on headings are disabled
+ hdrIconsFirst : true // true: put sort & filter icons before header text, false: after
+ });
+ // other options:
+ // sortCol: initial sort column
+
+ var self=this;
+ this.options.sortHandler = function() { self.sortHandler(); };
+ this.options.filterHandler = function() { self.filterHandler(); };
+ this.options.onRefreshComplete = function(firstrow,lastrow) { self.bookmarkHandler(firstrow,lastrow); };
+ this.options.rowOverHandler = Rico.eventHandle(this,'rowMouseOver');
+ this.options.mouseDownHandler = Rico.eventHandle(this,'selectMouseDown');
+ this.options.mouseOverHandler = Rico.eventHandle(this,'selectMouseOver');
+ this.options.mouseUpHandler = Rico.eventHandle(this,'selectMouseUp');
+ Rico.extend(this.options, options || {});
+
+ switch (typeof this.options.visibleRows) {
+ case 'string':
+ this.sizeTo=this.options.visibleRows;
+ switch (this.options.visibleRows) {
+ case 'data': this.options.visibleRows=-2; break;
+ case 'body': this.options.visibleRows=-3; break;
+ case 'parent': this.options.visibleRows=-4; break;
+ case 'datamax':this.options.visibleRows=-5; break;
+ default: this.options.visibleRows=-1; break;
+ }
+ break;
+ case 'number':
+ switch (this.options.visibleRows) {
+ case -1: this.sizeTo='window'; break;
+ case -2: this.sizeTo='data'; break;
+ case -3: this.sizeTo='body'; break;
+ case -4: this.sizeTo='parent'; break;
+ case -5: this.sizeTo='datamax'; break;
+ default: this.sizeTo='fixed'; break;
+ }
+ break;
+ default:
+ this.sizeTo='body';
+ this.options.visibleRows=-3;
+ break;
+ }
+ this.highlightEnabled=this.options.highlightSection>0;
+ this.pageSize=0;
+ this.createTables();
+ if (this.headerColCnt==0) {
+ alert('ERROR: no columns found in "'+this.tableId+'"');
+ return;
+ }
+ this.createColumnArray('LiveGridColumn');
+ if (this.options.headingSort=='hover')
+ this.createHoverSet();
+
+ this.bookmark=document.getElementById(this.tableId+"_bookmark");
+ this.sizeDivs();
+ var filterUIrow=-1;
+ if (this.buffer.options.canFilter && this.options.AutoFilter)
+ filterUIrow=this.addHeadingRow('ricoLG_FilterRow');
+ this.createDataCells(this.options.visibleRows);
+ if (this.pageSize == 0) return;
+ this.buffer.registerGrid(this);
+ if (this.buffer.setBufferSize) this.buffer.setBufferSize(this.pageSize);
+ this.scrollTimeout = null;
+ this.lastScrollPos = 0;
+ this.attachMenuEvents();
+
+ this.setSortUI( this.options.sortCol, this.options.sortDir );
+ this.setImages();
+ if (this.listInvisible().length==this.columns.length)
+ this.columns[0].showColumn();
+ this.sizeDivs();
+ this.scrollDiv.style.display="";
+ if (this.buffer.totalRows>0)
+ this.updateHeightDiv();
+ if (this.options.prefetchBuffer) {
+ if (this.bookmark) this.bookmark.innerHTML = Rico.getPhraseById('bookmarkLoading');
+ if (this.options.canFilterDefault && this.options.getQueryParms)
+ this.checkForFilterParms();
+ this.scrollToRow(this.options.offset);
+ this.buffer.fetch(this.options.offset);
+ }
+ if (filterUIrow >= 0)
+ this.createFilters(filterUIrow);
+ this.scrollEventFunc=Rico.eventHandle(this,'handleScroll');
+ this.wheelEventFunc=Rico.eventHandle(this,'handleWheel');
+ this.wheelEvent=(Rico.isIE || Rico.isOpera || Rico.isWebKit) ? 'mousewheel' : 'DOMMouseScroll';
+ if (this.options.offset && this.options.offset < this.buffer.totalRows)
+ Rico.runLater(50,this,'scrollToRow',this.options.offset); // Safari requires a delay
+ this.pluginScroll();
+ this.setHorizontalScroll();
+ Rico.log("setHorizontalScroll done");
+ if (this.options.windowResize)
+ Rico.runLater(100,this,'pluginWindowResize');
+ Rico.log("initialize complete for "+this.tableId);
+ //alert('clientLeft='+this.scrollDiv.clientLeft);
+ if (this.direction=='rtl' && (!Rico.isWebKit || this.scrollDiv.clientLeft > 0)) {
+ this.scrollTab.style.right='0px';
+ } else {
+ this.scrollTab.style.left='0px';
+ Rico.setStyle(this.tabs[1], {'float': 'left'});
+ }
+ }
+};
+
+
+Rico.LiveGridMethods = {
+/** @lends Rico.LiveGrid# */
+
+ createHoverSet: function() {
+ var hdrs=[];
+ for( var c=0; c < this.headerColCnt; c++ ) {
+ if (this.columns[c].sortable) {\r
+ hdrs.push(this.columns[c].hdrCellDiv);
+ }
+ }
+ this.hoverSet = new Rico.HoverSet(hdrs);
+ },
+
+ checkForFilterParms: function() {
+ var s=window.location.search;
+ if (s.charAt(0)=='?') s=s.substring(1);
+ var pairs = s.split('&');
+ for (var i=0; i<pairs.length; i++) {
+ if (pairs[i].match(/^f\[\d+\]/)) {
+ this.buffer.options.requestParameters.push(pairs[i]);
+ }
+ }
+ },
+
+/**
+ * Refreshes a detail grid from a master grid
+ * @returns row index on master table on success, -1 otherwise
+ */
+ drillDown: function(e,masterColNum,detailColNum) {
+ var cell=Rico.eventElement(e || window.event);
+ cell=Rico.getParentByTagName(cell,'div','ricoLG_cell');
+ if (!cell) return -1;
+ var idx=this.winCellIndex(cell);
+ if (idx.row >= this.buffer.totalRows) return -1
+ this.unhighlight();
+ this.menuIdx=idx; // ensures selection gets cleared when menu is displayed
+ this.highlight(idx);
+ var drillValue=this.buffer.getWindowCell(idx.row,masterColNum);
+ for (var i=3; i<arguments.length; i++)
+ arguments[i].setDetailFilter(detailColNum,drillValue);
+ return idx.row;
+ },
+
+/**
+ * set filter on a detail grid that is in a master-detail relationship
+ */
+ setDetailFilter: function(colNumber,filterValue) {
+ var c=this.columns[colNumber];
+ c.format.ColData=filterValue;
+ c.setSystemFilter('EQ',filterValue);
+ },
+
+/**
+ * Create one table for frozen columns and one for scrolling columns.
+ * Also create div's to contain them.
+ * @returns true on success
+ */
+ createTables: function() {
+ var insertloc,hdrSrc,i;
+ var table = document.getElementById(this.tableId) || document.getElementById(this.tableId+'_outerDiv');
+ if (!table) return false;
+ if (table.tagName.toLowerCase()=='table') {
+ var theads=table.getElementsByTagName("thead");
+ if (theads.length == 1) {
+ Rico.log("createTables: using thead section, id="+this.tableId);
+ if (this.options.ColGroupsOnTabHdr && this.options.ColGroups) {
+ var r=theads[0].insertRow(0);
+ this.insertPanelNames(r, 0, this.options.frozenColumns, 'ricoFrozen');
+ this.insertPanelNames(r, this.options.frozenColumns, this.options.columnSpecs.length);
+ }
+ hdrSrc=theads[0].rows;
+ } else {
+ Rico.log("createTables: using tbody section, id="+this.tableId);
+ hdrSrc=new Array(table.rows[0]);
+ }
+ insertloc=table;
+ } else if (this.options.columnSpecs.length > 0) {
+ if (!table.id.match(/_outerDiv$/)) insertloc=table;
+ Rico.log("createTables: inserting at "+table.tagName+", id="+this.tableId);
+ } else {
+ alert("ERROR!\n\nUnable to initialize '"+this.tableId+"'\n\nLiveGrid terminated");
+ return false;
+ }
+
+ this.createDivs();
+ this.scrollContainer = this.createDiv("scrollContainer",this.structTabLR);
+ this.scrollContainer.appendChild(this.scrollDiv); // move scrollDiv
+ this.scrollTab = this.createDiv("scrollTab",this.scrollContainer);
+ this.shadowDiv = this.createDiv("shadow",this.scrollDiv);
+ this.shadowDiv.style.direction='ltr'; // avoid FF bug
+ this.scrollDiv.style.display="none";
+ this.scrollDiv.scrollTop=0;
+ if (this.options.highlightMethod!='class') {
+ this.highlightDiv=[];
+ switch (this.options.highlightElem) {
+ case 'menuRow':
+ case 'cursorRow':
+ this.highlightDiv[0] = this.createDiv("highlight",this.outerDiv);
+ this.highlightDiv[0].style.display="none";
+ break;
+ case 'menuCell':
+ case 'cursorCell':
+ for (i=0; i<2; i++) {
+ this.highlightDiv[i] = this.createDiv("highlight",i==0 ? this.frozenTabs : this.scrollTab);
+ this.highlightDiv[i].style.display="none";
+ this.highlightDiv[i].id+=i;
+ }
+ break;
+ case 'selection':
+ // create one div for each side of the rectangle
+ var parentDiv=this.options.highlightSection==1 ? this.frozenTabs : this.scrollTab;
+ for (i=0; i<4; i++) {
+ this.highlightDiv[i] = this.createDiv("highlight",parentDiv);
+ this.highlightDiv[i].style.display="none";
+ this.highlightDiv[i].style.overflow="hidden";
+ this.highlightDiv[i].id+=i;
+ this.highlightDiv[i].style[i % 2==0 ? 'height' : 'width']="0px";
+ }
+ break;
+ }
+ }
+
+ // create new tables
+ for (i=0; i<3; i++) {
+ this.tabs[i] = document.createElement("table");
+ this.tabs[i].className = (i < 2) ? 'ricoLG_table' : 'ricoLG_scrollTab';
+ this.tabs[i].border=0;
+ this.tabs[i].cellPadding=0;
+ this.tabs[i].cellSpacing=0;
+ this.tabs[i].id = this.tableId+"_tab"+i;
+ }
+ // set headings
+ for (i=0; i<2; i++) {
+ this.thead[i]=this.tabs[i].createTHead();
+ this.thead[i].className='ricoLG_top';
+ if (Rico.theme.gridheader) Rico.addClass(this.thead[i],Rico.theme.gridheader);
+ }
+ // set bodies
+ for (i=0; i<2; i++) {
+ this.tbody[i]=Rico.getTBody(this.tabs[i==0?0:2]);
+ this.tbody[i].className='ricoLG_bottom';
+ if (Rico.theme.gridcontent) Rico.addClass(this.tbody[i],Rico.theme.gridcontent);
+ this.tbody[i].insertRow(-1);
+ }
+ this.frozenTabs.appendChild(this.tabs[0]);
+ this.innerDiv.appendChild(this.tabs[1]);
+ this.scrollTab.appendChild(this.tabs[2]);
+ if (insertloc) insertloc.parentNode.insertBefore(this.outerDiv,insertloc);
+ if (hdrSrc) {
+ this.headerColCnt = this.getColumnInfo(hdrSrc);
+ this.loadHdrSrc(hdrSrc);
+ } else {
+ this.createHdr(0,0,this.options.frozenColumns);
+ this.createHdr(1,this.options.frozenColumns,this.options.columnSpecs.length);
+ if (this.options.ColGroupsOnTabHdr && this.options.ColGroups) {
+ this.insertPanelNames(this.thead[0].insertRow(0), 0, this.options.frozenColumns);
+ this.insertPanelNames(this.thead[1].insertRow(0), this.options.frozenColumns, this.options.columnSpecs.length);
+ }
+ for (i=0; i<2; i++)
+ this.headerColCnt = this.getColumnInfo(this.thead[i].rows);
+ }
+ for( var c=0; c < this.headerColCnt; c++ )
+ this.tbody[c<this.options.frozenColumns ? 0 : 1].rows[0].insertCell(-1);
+ if (insertloc) table.parentNode.removeChild(table);
+ Rico.log('createTables end');
+ return true;
+ },
+
+ createDataCells: function(visibleRows) {
+ if (visibleRows < 0) {
+ for (var i=0; i<this.options.minPageRows; i++)
+ this.appendBlankRow();
+ this.sizeDivs();
+ this.autoAppendRows(this.remainingHt());
+ } else {
+ for( var r=0; r < visibleRows; r++ )
+ this.appendBlankRow();
+ }
+ var s=this.options.highlightSection;
+ if (s & 1) this.attachHighlightEvents(this.tbody[0]);
+ if (s & 2) this.attachHighlightEvents(this.tbody[1]);
+ },
+
+/**
+ * @param colnum column number
+ * @return id string for a filter element
+ */
+ filterId: function(colnum) {
+ return 'RicoFilter_'+this.tableId+'_'+colnum;
+ },
+
+/**
+ * Create filter elements in heading
+ * Reads this.columns[].filterUI to determine type of filter element for each column (t=text box, s=select list, c=custom)
+ * @param r heading row where filter elements will be placed
+ */
+ createFilters: function(r) {
+ for( var c=0; c < this.headerColCnt; c++ ) {
+ var col=this.columns[c];
+ var fmt=col.format;
+ if (typeof fmt.filterUI!='string') continue;
+ var cell=this.hdrCells[r][c].cell;
+ var field,name=this.filterId(c);\r
+ var divs=cell.getElementsByTagName('div');
+ // copy text alignment from data cell
+ var align=Rico.getStyle(this.cell(0,c),'textAlign');
+ divs[1].style.textAlign=align;
+ switch (fmt.filterUI.charAt(0)) {
+ case 't':
+ // text field
+ field=Rico.createFormField(divs[1],'input',Rico.inputtypes.search ? 'search' : 'text',name,'RicoFilter');
+ var size=fmt.filterUI.match(/\d+/);
+ field.maxLength=fmt.Length || 50;\r
+ field.size=size ? parseInt(size,10) : 10;
+ if (field.type != 'search') divs[1].appendChild(Rico.clearButton(Rico.eventHandle(col,'filterClear')));
+ if (col.filterType==Rico.ColumnConst.USERFILTER && col.filterOp=='LIKE') {
+ var v=col.filterValues[0];
+ if (v.charAt(0)=='*') v=v.substr(1);
+ if (v.slice(-1)=='*') v=v.slice(0,-1);
+ field.value=v;
+ col.lastKeyFilter=v;
+ }
+ Rico.eventBind(field,'keyup',Rico.eventHandle(col,'filterKeypress'),false);
+ Rico.eventBind(field,'change',Rico.eventHandle(col,'filterKeypress'),false);
+ col.filterField=field;\r
+ break;\r
+ case 'm':
+ // multi-select
+ case 's':
+ // drop-down select
+ field=Rico.createFormField(divs[1],'select',null,name,'RicoFilter');\r
+ Rico.addSelectOption(field,this.options.FilterAllToken,Rico.getPhraseById("filterAll"));\r
+ col.filterField=field;
+ var options={};\r
+ Rico.extend(options, this.buffer.ajaxOptions);
+ var colnum=typeof(fmt.filterCol)=='number' ? fmt.filterCol : c;
+ options.parameters = this.buffer.formQueryHashXML(0,-1);
+ options.parameters.distinct = colnum;
+ options.onComplete = this.filterValuesUpdateFunc(c);
+ new Rico.ajaxRequest(this.buffer.dataSource, options);
+ break;\r
+ case 'n':
+ field=Rico.createFormField(divs[1],'select',null,name,'RicoFilter');
+ Rico.addSelectOption(field,this.options.FilterAllToken,Rico.getPhraseById("filterAll"));
+ col.filterField=field;
+ var choices=fmt.filterUI.length == 1 ? "-0+" : fmt.filterUI.substr(1);
+ if (choices.indexOf("-") >= 0) Rico.addSelectOption(field,"LT0","< 0");
+ if (choices.indexOf("0") >= 0) Rico.addSelectOption(field,"EQ0","= 0");
+ if (choices.indexOf("+") >= 0) Rico.addSelectOption(field,"GT0","> 0");
+ Rico.eventBind(col.filterField,'change',Rico.eventHandle(col,'nFilterChange'));
+ break;
+ case 'c':
+ // custom
+ if (typeof col._createFilters == 'function')
+ col._createFilters(divs[1], name);
+ break;
+ }
+ }
+ this.initFilterImage(r);
+ },
+
+ filterValuesUpdateFunc: function(colnum) {
+ var self=this;
+ return function (request) { self.filterValuesUpdate(colnum,request); };
+ },
+
+/**
+ * update select list filter with values in AJAX response
+ * @returns true on success
+ */
+ filterValuesUpdate: function(colnum,request) {
+ var response = request.responseXML.getElementsByTagName("ajax-response");
+ Rico.log("filterValuesUpdate: "+request.status);
+ if (response == null || response.length != 1) return false;
+ response=response[0];
+ var error = response.getElementsByTagName('error');
+ if (error.length > 0) {
+ Rico.log("Data provider returned an error:\n"+Rico.getContentAsString(error[0],this.buffer.isEncoded));
+ alert(Rico.getPhraseById("requestError",Rico.getContentAsString(error[0],this.buffer.isEncoded)));
+ return false;
+ }\r
+ response=response.getElementsByTagName('response')[0];\r
+ var rowsElement = response.getElementsByTagName('rows')[0];\r
+ var col=this.columns[parseInt(colnum,10)];
+ var rows = this.buffer.dom2jstable(rowsElement);\r
+ var found = !col.filterValues || !col.filterValues.length;
+ if (!found) for (var i=0; i<rows.length; i++) {
+ if (rows[i][0] == col.filterValues[0]) {
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ col.setUnfiltered(true);
+ if (this.options.filterHandler)
+ this.options.filterHandler();
+ }
+ var c,opt,v;
+ if (col.filterType==Rico.ColumnConst.USERFILTER && col.filterOp=='EQ') v=col.filterValues[0];
+ Rico.log('filterValuesUpdate: col='+colnum+' rows='+rows.length);
+ switch (col.format.filterUI.charAt(0)) {
+ case 'm':
+ // multi-select
+ col.mFilter = document.body.appendChild(document.createElement("div"));
+ col.mFilter.className = 'ricoLG_mFilter'
+ Rico.hide(col.mFilter);
+ var contentDiv = col.mFilter.appendChild(document.createElement("div"));
+ contentDiv.className = 'ricoLG_mFilter_content'
+ var buttonDiv = col.mFilter.appendChild(document.createElement("div"));
+ buttonDiv.className = 'ricoLG_mFilter_button'
+ col.mFilterButton=buttonDiv.appendChild(document.createElement("button"));
+ col.mFilterButton.innerHTML=Rico.getPhraseById("apply");
+ var eventName=Rico.isWebKit ? 'mousedown' : 'click';
+ Rico.eventBind(col.filterField,eventName,Rico.eventHandle(col,'mFilterSelectClick'));
+ Rico.eventBind(col.mFilterButton,'click',Rico.eventHandle(col,'mFilterFinish'));
+ //col.filterField.options[0].text=$('AllLabel').innerHTML;
+ tab = contentDiv.appendChild(document.createElement("table"));
+ tab.border=0;
+ tab.cellPadding=2;
+ tab.cellSpacing=0;
+ //tbody=(tab.tBodies.length==0) ? tab.appendChild(document.createElement("tbody")) : tab.tBodies[0];
+ var baseId=this.filterId(colnum)+'_';
+ this.createMFilterItem(tab,this.options.FilterAllToken,Rico.getPhraseById("filterAll"),baseId+'all',Rico.eventHandle(col,'mFilterAllClick'));
+ var handle=Rico.eventHandle(col,'mFilterOtherClick')
+ for (var i=0; i<rows.length; i++) {
+ if (rows[i].length>0) {
+ c=rows[i][0];
+ this.createMFilterItem(tab,c,c || Rico.getPhraseById("filterBlank"),baseId+i,handle);
+ }
+ }
+ col.mFilterInputs=contentDiv.getElementsByTagName('input');
+ col.mFilterLabels=contentDiv.getElementsByTagName('label');
+ col.mFilterFocus=col.mFilterInputs.length ? col.mFilterInputs[0] : col.mFilterButton;
+ break;
+
+ case 's':
+ // drop-down select
+ for (var i=0; i<rows.length; i++) {
+ if (rows[i].length>0) {
+ c=rows[i][0];
+ ctrans=c;
+ if (col._getdesc) ctrans = col._getdesc(c);
+ opt=Rico.addSelectOption(col.filterField,c,ctrans || Rico.getPhraseById("filterBlank"));
+ if (col.filterType==Rico.ColumnConst.USERFILTER && c==v) opt.selected=true;
+ }
+ }
+ Rico.eventBind(col.filterField,'change',Rico.eventHandle(col,'filterChange'));
+ break;
+ }
+ return true;\r
+ },
+
+ createMFilterItem: function(table,code,description,id,eventHandle) {
+ var tr=table.insertRow(-1);
+ tr.vAlign='top';
+ if (tr.rowIndex % 2 == 1) tr.className='ricoLG_mFilter_oddrow';
+ var td1=tr.insertCell(-1)
+ var td2=tr.insertCell(-1)
+ var field=Rico.createFormField(td1,'input','checkbox',id);
+ field.value=code;
+ field.checked=true;
+ var label = td2.appendChild(document.createElement("label"));
+ label.htmlFor = id;
+ label.innerHTML=description;
+ Rico.eventBind(field,'click',eventHandle);
+ },
+
+ unplugHighlightEvents: function() {
+ var s=this.options.highlightSection;
+ if (s & 1) this.detachHighlightEvents(this.tbody[0]);
+ if (s & 2) this.detachHighlightEvents(this.tbody[1]);
+ },
+
+/**
+ * place panel names on first row of grid header (used by LiveGridForms)
+ */
+ insertPanelNames: function(r,start,limit,cellClass) {
+ Rico.log('insertPanelNames: start='+start+' limit='+limit);
+ r.className='ricoLG_hdg';
+ var lastIdx=-1, span, newCell=null, spanIdx=0;
+ for( var c=start; c < limit; c++ ) {
+ if (lastIdx == this.options.columnSpecs[c].ColGroupIdx) {
+ span++;
+ } else {
+ if (newCell) newCell.colSpan=span;
+ newCell = r.insertCell(-1);
+ if (cellClass) newCell.className=cellClass;
+ span=1;
+ lastIdx=this.options.columnSpecs[c].ColGroupIdx;
+ newCell.innerHTML=this.options.ColGroups[lastIdx];
+ }
+ }
+ if (newCell) newCell.colSpan=span;
+ },
+
+/**
+ * create grid header for table i (if none was provided)
+ */
+ createHdr: function(i,start,limit) {
+ Rico.log('createHdr: i='+i+' start='+start+' limit='+limit);
+ var mainRow = this.thead[i].insertRow(-1);
+ mainRow.id=this.tableId+'_tab'+i+'h_main';
+ mainRow.className='ricoLG_hdg';
+ for( var c=start; c < limit; c++ ) {
+ var newCell = mainRow.insertCell(-1);
+ newCell.innerHTML=this.options.columnSpecs[c].Hdg;
+ }
+ },
+
+/**
+ * move header cells in original table to grid
+ */
+ loadHdrSrc: function(hdrSrc) {
+ var i,h,c,r,newrow,cells;
+ Rico.log('loadHdrSrc start');
+ for (i=0; i<2; i++) {
+ for (r=0; r<hdrSrc.length; r++) {
+ newrow = this.thead[i].insertRow(-1);
+ newrow.className='ricoLG_hdg '+this.tableId+'_hdg'+r;
+ }
+ }
+ if (hdrSrc.length==1) {
+ cells=hdrSrc[0].cells;
+ for (c=0; cells.length > 0; c++)
+ this.thead[c<this.options.frozenColumns ? 0 : 1].rows[0].appendChild(cells[0]);
+ } else {
+ for (r=0; r<hdrSrc.length; r++) {
+ cells=hdrSrc[r].cells;
+ for (c=0,h=0; cells.length > 0; c++) {
+ if (Rico.hasClass(cells[0],'ricoFrozen')) {
+ if (r==this.headerRowIdx) this.options.frozenColumns=c+1;
+ } else {
+ h=1;
+ }
+ this.thead[h].rows[r].appendChild(cells[0]);
+ }
+ }
+ }
+ Rico.log('loadHdrSrc end');
+ },
+
+/**
+ * Size div elements
+ */
+ sizeDivs: function() {
+ Rico.log('sizeDivs: '+this.tableId);
+ //this.cancelMenu();
+ this.unhighlight();
+ this.baseSizeDivs();
+ var firstVisible=this.firstVisible();
+ if (this.pageSize == 0 || firstVisible < 0) return;
+ var totRowHt=this.columns[firstVisible].dataColDiv.offsetHeight;
+ this.rowHeight = Math.round(totRowHt/this.pageSize);
+ var scrHt=this.dataHt;
+ if (this.scrTabWi0 == this.scrTabWi) {
+ // no scrolling columns - horizontal scroll bar not needed
+ this.innerDiv.style.height=(this.hdrHt+1)+'px';
+ this.scrollDiv.style.overflowX='hidden';
+ } else {
+ this.scrollDiv.style.overflowX='scroll';
+ scrHt+=this.options.scrollBarWidth;
+ }
+ this.scrollDiv.style.height=scrHt+'px';
+ this.innerDiv.style.width=(this.scrWi)+'px';
+ this.scrollTab.style.width=(this.scrWi-this.options.scrollBarWidth)+'px';
+ //this.resizeDiv.style.height=this.frozenTabs.style.height=this.innerDiv.style.height=(this.hdrHt+this.dataHt+1)+'px';
+ this.resizeDiv.style.height=(this.hdrHt+this.dataHt+1)+'px';
+ Rico.log('sizeDivs scrHt='+scrHt+' innerHt='+this.innerDiv.style.height+' rowHt='+this.rowHeight+' pageSize='+this.pageSize);
+ var pad=(this.scrWi-this.scrTabWi < this.options.scrollBarWidth) ? 2 : 0;
+ this.shadowDiv.style.width=(this.scrTabWi+pad)+'px';
+ this.outerDiv.style.height=(this.hdrHt+scrHt)+'px';
+ this.setHorizontalScroll();
+ },
+
+ setHorizontalScroll: function() {
+ var newLeft=(-this.scrollDiv.scrollLeft)+'px';
+ this.tabs[1].style.marginLeft=newLeft;
+ this.tabs[2].style.marginLeft=newLeft;
+ },
+
+ remainingHt: function() {
+ var tabHt=this.outerDiv.offsetHeight;
+ var winHt=Rico.windowHeight();
+ var margin=Rico.isIE ? 15 : 10;
+ // if there is a horizontal scrollbar take it into account
+ if (!Rico.isIE && window.frameElement && window.frameElement.scrolling=='yes' && this.sizeTo!='parent') margin+=this.options.scrollBarWidth;
+ switch (this.sizeTo) {
+ case 'window':
+ var divTop=Rico.cumulativeOffset(this.outerDiv).top;
+ Rico.log("remainingHt/window, winHt="+winHt+' tabHt='+tabHt+' gridY='+divTop);
+ return winHt-divTop-tabHt-margin; // allow for scrollbar and some margin
+ case 'parent':
+ var offset=this.offsetFromParent(this.outerDiv);
+ if (Rico.isIE) Rico.hide(this.outerDiv);
+ var parentHt=this.outerDiv.parentNode.clientHeight;
+ if (Rico.isIE) Rico.show(this.outerDiv);
+ Rico.log("remainingHt/parent, parentHt="+parentHt+' offset='+offset+' tabHt='+tabHt);
+ return parentHt-tabHt-offset-margin;
+ case 'data':
+ case 'body':
+ var bodyHt=Rico.isIE ? document.body.scrollHeight : (document.body.offsetHeight - 50);
+ //alert("remainingHt\n document.height="+document.height+"\n body.offsetHeight="+document.body.offsetHeight+"\n body.scrollHeight="+document.body.scrollHeight+"\n documentElement.scrollHeight="+document.documentElement.scrollHeight);
+ var remHt=winHt-bodyHt-margin;
+ if (!Rico.isWebKit) remHt-=this.options.scrollBarWidth;
+ Rico.log("remainingHt, winHt="+winHt+' pageHt='+bodyHt+' remHt='+remHt);
+ return remHt;
+ default:
+ Rico.log("remainingHt, winHt="+winHt+' tabHt='+tabHt);
+ if (this.sizeTo.slice(-1)=='%') winHt*=parseFloat(this.sizeTo)/100.0;
+ else if (this.sizeTo.slice(-2)=='px') winHt=parseInt(this.sizeTo,10);
+ return winHt-tabHt-margin; // allow for scrollbar and some margin
+ }
+ },
+
+ offsetFromParent: function(element) {
+ var valueT = 0;
+ var elParent=element.parentNode;
+ do {
+ //Rico.log("offsetFromParent: "+element.tagName+' id='+element.id+' otop='+element.offsetTop);
+ valueT += element.offsetTop || 0;
+ element = element.offsetParent;
+ if (!element || element==null) break;
+ var p = Rico.getStyle(element, 'position');
+ if (element.tagName=='BODY' || element.tagName=='HTML' || p=='absolute') return valueT-elParent.offsetTop;
+ } while (element != elParent);
+ return valueT;
+ },
+
+ adjustPageSize: function() {
+ Rico.log('adjustPageSize start');
+ var remHt=this.remainingHt();
+ Rico.log('adjustPageSize remHt='+remHt+' lastRow='+this.lastRowPos);
+ if (remHt > this.rowHeight)
+ this.autoAppendRows(remHt);
+ else if (remHt < 0 || this.sizeTo=='data')
+ this.autoRemoveRows(-remHt);
+ Rico.log('adjustPageSize end');
+ },
+
+ setPageSize: function(newRowCount) {
+ Rico.log('setPageSize '+this.tableId+' newRowCount='+newRowCount);
+ newRowCount=Math.min(newRowCount,this.options.maxPageRows);
+ newRowCount=Math.max(newRowCount,this.options.minPageRows);
+ this.sizeTo='fixed';
+ var oldSize=this.pageSize;
+ while (this.pageSize > newRowCount) {
+ this.removeRow();
+ }
+ while (this.pageSize < newRowCount) {
+ this.appendBlankRow();
+ }
+ this.finishResize(oldSize);
+ },
+
+ pluginWindowResize: function() {
+ Rico.log("pluginWindowResize");
+ this.resizeWindowHandler=Rico.eventHandle(this,'resizeWindow');
+ Rico.eventBind(window, "resize", this.resizeWindowHandler, false);
+ },
+
+ unplugWindowResize: function() {
+ if (!this.resizeWindowHandler) return;
+ Rico.eventUnbind(window,"resize", this.resizeWindowHandler, false);
+ this.resizeWindowHandler=null;
+ },
+
+ resizeWindow: function() {
+ Rico.log('resizeWindow '+this.tableId+' lastRow='+this.lastRowPos+' resizeState='+this.resizeState);
+ if (this.resizeState=='finish') {
+ Rico.log('resizeWindow postponed');
+ this.resizeState='resize';
+ return;
+ }
+ if (!this.sizeTo || this.sizeTo=='fixed') {
+ this.sizeDivs();
+ return;
+ }
+ if (this.sizeTo=='parent' && Rico.getStyle(this.outerDiv.parentNode,'display') == 'none') return;
+ Rico.log('resizeWindow: about to adjustPageSize')
+ var oldSize=this.pageSize;
+ this.adjustPageSize();
+ this.finishResize(oldSize);
+ },
+
+ finishResize: function(oldSize) {
+ Rico.log('finishResize '+this.tableId);
+ if (this.pageSize > oldSize && this.buffer.totalRows>0) {
+ this.isPartialBlank=true;
+ var adjStart=this.adjustRow(this.lastRowPos);
+ this.buffer.fetch(adjStart);
+ } else if (this.pageSize < oldSize) {
+ if (this.options.onRefreshComplete) this.options.onRefreshComplete(this.contentStartPos,this.contentStartPos+this.pageSize-1); // update bookmark
+ }
+ this.resizeState='finish';
+ Rico.runLater(20,this,'finishResize2');
+ Rico.log('Resize '+this.tableId+' complete. old size='+oldSize+' new size='+this.pageSize);
+ },
+
+ finishResize2: function() {
+ Rico.log('finishResize2 '+this.tableId+': resizeState='+this.resizeState);
+ this.sizeDivs();
+ this.updateHeightDiv();
+ if (this.resizeState=='resize') {
+ this.resizeWindow();
+ } else {
+ this.resizeState='';
+ }
+ },
+
+ topOfLastPage: function() {
+ return Math.max(this.buffer.totalRows-this.pageSize,0);
+ },
+
+ updateHeightDiv: function() {
+ var notdisp=this.topOfLastPage();
+ var ht = notdisp ? this.scrollDiv.clientHeight + Math.floor(this.rowHeight * (notdisp + 0.4)) : 1;
+ Rico.log("updateHeightDiv, ht="+ht+' scrollDiv.clientHeight='+this.scrollDiv.clientHeight+' rowsNotDisplayed='+notdisp);
+ this.shadowDiv.style.height=ht+'px';
+ },
+
+ autoRemoveRows: function(overage) {
+ if (!this.rowHeight) return;
+ var removeCnt=Math.ceil(overage / this.rowHeight);
+ if (this.sizeTo=='data')
+ removeCnt=Math.max(removeCnt,this.pageSize-this.buffer.totalRows);
+ Rico.log("autoRemoveRows overage="+overage+" removeCnt="+removeCnt);
+ for (var i=0; i<removeCnt; i++)
+ this.removeRow();
+ },
+
+ removeRow: function() {
+ if (this.pageSize <= this.options.minPageRows) return;
+ this.pageSize--;
+ for( var c=0; c < this.headerColCnt; c++ ) {
+ var cell=this.columns[c].cell(this.pageSize);
+ this.columns[c].dataColDiv.removeChild(cell);
+ }
+ },
+
+ autoAppendRows: function(overage) {
+ if (!this.rowHeight) return;
+ var addCnt=Math.floor(overage / this.rowHeight);
+ Rico.log("autoAppendRows overage="+overage+" cnt="+addCnt+" rowHt="+this.rowHeight);
+ for (var i=0; i<addCnt; i++) {
+ if (this.sizeTo=='data' && this.pageSize>=this.buffer.totalRows) break;
+ this.appendBlankRow();
+ }
+ },
+
+/**
+ * on older systems, this can be fairly slow
+ */
+ appendBlankRow: function() {
+ if (this.pageSize >= this.options.maxPageRows) return;
+ Rico.log("appendBlankRow #"+this.pageSize);
+ var cls=this.defaultRowClass(this.pageSize);
+ for( var c=0; c < this.headerColCnt; c++ ) {
+ var newdiv = document.createElement("div");
+ newdiv.className = 'ricoLG_cell '+cls;
+ newdiv.id=this.tableId+'_'+this.pageSize+'_'+c;
+ this.columns[c].dataColDiv.appendChild(newdiv);
+ if (this.columns[c]._create) {
+ this.columns[c]._create(newdiv,this.pageSize);
+ } else {
+ newdiv.innerHTML=' '; // this seems to be required by IE
+ }
+ if (this.columns[c].format.canDrag && Rico.registerDraggable) {
+ Rico.registerDraggable( new Rico.LiveGridDraggable(this, this.pageSize, c), this.options.dndMgrIdx );
+ }
+ }
+ this.pageSize++;
+ },
+
+ defaultRowClass: function(rownum) {
+ var cls
+ if (rownum % 2==0) {
+ cls='ricoLG_evenRow';
+ //if (Rico.theme.primary) cls+=' '+Rico.theme.primary;
+ } else {
+ cls='ricoLG_oddRow';
+ //if (Rico.theme.secondary) cls+=' '+Rico.theme.secondary;
+ }
+ return cls;
+ },
+
+ handleMenuClick: function(e) {
+ if (!this.menu) return;
+ this.cancelMenu();
+ this.unhighlight(); // in case highlighting was invoked externally
+ var idx;
+ var cell=Rico.eventElement(e);
+ if (cell.className=='ricoLG_highlightDiv') {
+ idx=this.highlightIdx;
+ } else {
+ cell=Rico.getParentByTagName(cell,'div','ricoLG_cell');
+ if (!cell) return;
+ idx=this.winCellIndex(cell);
+ if ((this.options.highlightSection & (idx.tabIdx+1))==0) return;
+ }
+ this.highlight(idx);
+ this.highlightEnabled=false;
+ if (this.hideScroll) this.scrollDiv.style.overflow="hidden";
+ this.menuIdx=idx;
+ if (!this.menu.div) this.menu.createDiv();
+ this.menu.liveGrid=this;
+ if (this.menu.buildGridMenu) {
+ var showMenu=this.menu.buildGridMenu(idx.row, idx.column, idx.tabIdx);
+ if (!showMenu) return;
+ }
+ if (this.options.highlightElem=='selection' && !this.isSelected(idx.cell)) {
+ this.selectCell(idx.cell);
+ }
+ var self=this;
+ this.menu.showmenu(e,function() { self.closeMenu(); });
+ return false;
+ },
+
+ closeMenu: function() {
+ if (!this.menuIdx) return;
+ if (this.hideScroll) this.scrollDiv.style.overflow="";
+ //this.unhighlight();
+ this.highlightEnabled=true;
+ this.menuIdx=null;
+ },
+
+/**
+ * @return index of cell within the window
+ */
+ winCellIndex: function(cell) {
+ var l=cell.id.lastIndexOf('_',cell.id.length);
+ var l2=cell.id.lastIndexOf('_',l-1)+1;
+ var c=parseInt(cell.id.substr(l+1));
+ var r=parseInt(cell.id.substr(l2,l));
+ return {row:r, column:c, tabIdx:this.columns[c].tabIdx, cell:cell};
+ },
+
+/**
+ * @return index of cell within the dataset
+ */
+ datasetIndex: function(cell) {
+ var idx=this.winCellIndex(cell);
+ idx.row+=this.buffer.windowPos;
+ idx.onBlankRow=(idx.row >= this.buffer.endPos());
+ return idx;
+ },
+
+ attachHighlightEvents: function(tBody) {
+ switch (this.options.highlightElem) {
+ case 'selection':
+ Rico.eventBind(tBody,"mousedown", this.options.mouseDownHandler, false);
+ /** @ignore */
+ tBody.ondrag = function () { return false; };
+ /** @ignore */
+ tBody.onselectstart = function () { return false; };
+ break;
+ case 'cursorRow':
+ case 'cursorCell':
+ Rico.eventBind(tBody,"mouseover", this.options.rowOverHandler, false);
+ break;
+ }
+ },
+
+ detachHighlightEvents: function(tBody) {
+ switch (this.options.highlightElem) {
+ case 'selection':
+ Rico.eventUnbind(tBody,"mousedown", this.options.mouseDownHandler, false);
+ tBody.ondrag = null;
+ tBody.onselectstart = null;
+ break;
+ case 'cursorRow':
+ case 'cursorCell':
+ Rico.eventUnbind(tBody,"mouseover", this.options.rowOverHandler, false);
+ break;
+ }
+ },
+
+/**
+ * @return array of objects containing row/col indexes (index values are relative to the start of the window)
+ */
+ getVisibleSelection: function() {
+ var cellList=[];
+ if (this.SelectIdxStart && this.SelectIdxEnd) {
+ var r1=Math.max(Math.min(this.SelectIdxEnd.row,this.SelectIdxStart.row)-this.buffer.startPos,this.buffer.windowStart);
+ var r2=Math.min(Math.max(this.SelectIdxEnd.row,this.SelectIdxStart.row)-this.buffer.startPos,this.buffer.windowEnd-1);
+ var c1=Math.min(this.SelectIdxEnd.column,this.SelectIdxStart.column);
+ var c2=Math.max(this.SelectIdxEnd.column,this.SelectIdxStart.column);
+ //Rico.log("getVisibleSelection "+r1+','+c1+' to '+r2+','+c2+' ('+this.SelectIdxStart.row+',startPos='+this.buffer.startPos+',windowPos='+this.buffer.windowPos+',windowEnd='+this.buffer.windowEnd+')');
+ for (var r=r1; r<=r2; r++) {
+ for (var c=c1; c<=c2; c++)
+ cellList.push({row:r-this.buffer.windowStart,column:c});
+ }
+ }
+ if (this.SelectCtrl) {
+ for (var i=0; i<this.SelectCtrl.length; i++) {
+ if (this.SelectCtrl[i].row>=this.buffer.windowStart && this.SelectCtrl[i].row<this.buffer.windowEnd)
+ cellList.push({row:this.SelectCtrl[i].row-this.buffer.windowStart,column:this.SelectCtrl[i].column});
+ }
+ }
+ return cellList;
+ },
+
+ updateSelectOutline: function() {
+ if (!this.SelectIdxStart || !this.SelectIdxEnd) return;
+ var r1=Math.max(Math.min(this.SelectIdxEnd.row,this.SelectIdxStart.row), this.buffer.windowStart);
+ var r2=Math.min(Math.max(this.SelectIdxEnd.row,this.SelectIdxStart.row), this.buffer.windowEnd-1);
+ if (r1 > r2) {
+ this.HideSelection();
+ return;
+ }
+ var c1=Math.min(this.SelectIdxEnd.column,this.SelectIdxStart.column);
+ var c2=Math.max(this.SelectIdxEnd.column,this.SelectIdxStart.column);
+ var top1=this.columns[c1].cell(r1-this.buffer.windowStart).offsetTop;
+ var cell2=this.columns[c1].cell(r2-this.buffer.windowStart);
+ var bottom2=cell2.offsetTop+cell2.offsetHeight;
+ var left1=this.columns[c1].dataCell.offsetLeft;
+ var left2=this.columns[c2].dataCell.offsetLeft;
+ var right2=left2+this.columns[c2].dataCell.offsetWidth;
+ //window.status='updateSelectOutline: '+r1+' '+r2+' top='+top1+' bot='+bottom2;
+ this.highlightDiv[0].style.top=this.highlightDiv[3].style.top=this.highlightDiv[1].style.top=(this.hdrHt+top1-1) + 'px';
+ this.highlightDiv[2].style.top=(this.hdrHt+bottom2-1)+'px';
+ this.highlightDiv[3].style.left=(left1-2)+'px';
+ this.highlightDiv[0].style.left=this.highlightDiv[2].style.left=(left1-1)+'px';
+ this.highlightDiv[1].style.left=(right2-1)+'px';
+ this.highlightDiv[0].style.width=this.highlightDiv[2].style.width=(right2-left1-1) + 'px';
+ this.highlightDiv[1].style.height=this.highlightDiv[3].style.height=(bottom2-top1) + 'px';
+ //this.highlightDiv[0].style.right=this.highlightDiv[2].style.right=this.highlightDiv[1].style.right=()+'px';
+ //this.highlightDiv[2].style.bottom=this.highlightDiv[3].style.bottom=this.highlightDiv[1].style.bottom=(this.hdrHt+bottom2) + 'px';
+ for (var i=0; i<4; i++)
+ this.highlightDiv[i].style.display='';
+ },
+
+ HideSelection: function() {
+ var i;
+ if (this.options.highlightMethod!='class') {
+ for (i=0; i<this.highlightDiv.length; i++)
+ this.highlightDiv[i].style.display='none';
+ }
+ if (this.options.highlightMethod!='outline') {
+ var cellList=this.getVisibleSelection();
+ Rico.log("HideSelection "+cellList.length);
+ for (i=0; i<cellList.length; i++)
+ this.unhighlightCell(this.columns[cellList[i].column].cell(cellList[i].row));
+ }
+ },
+
+ ShowSelection: function() {
+ if (this.options.highlightMethod!='class')
+ this.updateSelectOutline();
+ if (this.options.highlightMethod!='outline') {
+ var cellList=this.getVisibleSelection();
+ for (var i=0; i<cellList.length; i++)
+ this.highlightCell(this.columns[cellList[i].column].cell(cellList[i].row));
+ }
+ },
+
+ ClearSelection: function() {
+ Rico.log("ClearSelection");
+ this.HideSelection();
+ this.SelectIdxStart=null;
+ this.SelectIdxEnd=null;
+ this.SelectCtrl=[];
+ },
+
+ selectCell: function(cell) {
+ this.ClearSelection();
+ this.SelectIdxStart=this.SelectIdxEnd=this.datasetIndex(cell);
+ this.ShowSelection();
+ },
+
+ AdjustSelection: function(cell) {
+ var newIdx=this.datasetIndex(cell);
+ if (this.SelectIdxStart.tabIdx != newIdx.tabIdx) return;
+ this.HideSelection();
+ this.SelectIdxEnd=newIdx;
+ this.ShowSelection();
+ },
+
+ RefreshSelection: function() {
+ var cellList=this.getVisibleSelection();
+ for (var i=0; i<cellList.length; i++) {
+ this.columns[cellList[i].column].displayValue(cellList[i].row);
+ }
+ },
+
+ FillSelection: function(newVal,newStyle) {
+ if (this.SelectIdxStart && this.SelectIdxEnd) {
+ var r1=Math.min(this.SelectIdxEnd.row,this.SelectIdxStart.row);
+ var r2=Math.max(this.SelectIdxEnd.row,this.SelectIdxStart.row);
+ var c1=Math.min(this.SelectIdxEnd.column,this.SelectIdxStart.column);
+ var c2=Math.max(this.SelectIdxEnd.column,this.SelectIdxStart.column);
+ for (var r=r1; r<=r2; r++) {
+ for (var c=c1; c<=c2; c++) {
+ this.buffer.setValue(r,c,newVal,newStyle);
+ }
+ }
+ }
+ if (this.SelectCtrl) {
+ for (var i=0; i<this.SelectCtrl.length; i++) {
+ this.buffer.setValue(this.SelectCtrl[i].row,this.SelectCtrl[i].column,newVal,newStyle);
+ }
+ }
+ this.RefreshSelection();
+ },
+
+/**
+ * Process mouse down event
+ * @param e event object
+ */
+ selectMouseDown: function(e) {
+ if (this.highlightEnabled==false) return true;
+ this.cancelMenu();
+ var cell=Rico.eventElement(e);
+ if (!Rico.eventLeftClick(e)) return true;
+ cell=Rico.getParentByTagName(cell,'div','ricoLG_cell');
+ if (!cell) return true;
+ Rico.eventStop(e);
+ var newIdx=this.datasetIndex(cell);
+ if (newIdx.onBlankRow) return true;
+ Rico.log("selectMouseDown @"+newIdx.row+','+newIdx.column);
+ if (e.ctrlKey) {
+ if (!this.SelectIdxStart || this.options.highlightMethod!='class') return true;
+ if (!this.isSelected(cell)) {
+ this.highlightCell(cell);
+ this.SelectCtrl.push(this.datasetIndex(cell));
+ } else {
+ for (var i=0; i<this.SelectCtrl.length; i++) {
+ if (this.SelectCtrl[i].row==newIdx.row && this.SelectCtrl[i].column==newIdx.column) {
+ this.unhighlightCell(cell);
+ this.SelectCtrl.splice(i,1);
+ break;
+ }
+ }
+ }
+ } else if (e.shiftKey) {
+ if (!this.SelectIdxStart) return true;
+ this.AdjustSelection(cell);
+ } else {
+ this.selectCell(cell);
+ this.pluginSelect();
+ }
+ return false;
+ },
+
+ pluginSelect: function() {
+ if (this.selectPluggedIn) return;
+ var tBody=this.tbody[this.SelectIdxStart.tabIdx];
+ Rico.eventBind(tBody,"mouseover", this.options.mouseOverHandler, false);
+ Rico.eventBind(this.outerDiv,"mouseup", this.options.mouseUpHandler, false);
+ this.selectPluggedIn=true;
+ },
+
+ unplugSelect: function() {
+ if (!this.selectPluggedIn) return;
+ var tBody=this.tbody[this.SelectIdxStart.tabIdx];
+ Rico.eventUnbind(tBody,"mouseover", this.options.mouseOverHandler , false);
+ Rico.eventUnbind(this.outerDiv,"mouseup", this.options.mouseUpHandler , false);
+ this.selectPluggedIn=false;
+ },
+
+ selectMouseUp: function(e) {
+ this.unplugSelect();
+ var cell=Rico.eventElement(e);
+ cell=Rico.getParentByTagName(cell,'div','ricoLG_cell');
+ if (!cell) return;
+ if (this.SelectIdxStart && this.SelectIdxEnd)
+ this.AdjustSelection(cell);
+ else
+ this.ClearSelection();
+ },
+
+ selectMouseOver: function(e) {
+ var cell=Rico.eventElement(e);
+ cell=Rico.getParentByTagName(cell,'div','ricoLG_cell');
+ if (!cell) return;
+ this.AdjustSelection(cell);
+ Rico.eventStop(e);
+ },
+
+ isSelected: function(cell) {
+ if (this.options.highlightMethod!='outline') return Rico.hasClass(cell,this.options.highlightClass);
+ if (!this.SelectIdxStart || !this.SelectIdxEnd) return false;
+ var r1=Math.max(Math.min(this.SelectIdxEnd.row,this.SelectIdxStart.row), this.buffer.windowStart);
+ var r2=Math.min(Math.max(this.SelectIdxEnd.row,this.SelectIdxStart.row), this.buffer.windowEnd-1);
+ if (r1 > r2) return false;
+ var c1=Math.min(this.SelectIdxEnd.column,this.SelectIdxStart.column);
+ var c2=Math.max(this.SelectIdxEnd.column,this.SelectIdxStart.column);
+ var curIdx=this.datasetIndex(cell);
+ return (r1<=curIdx.row && curIdx.row<=r2 && c1<=curIdx.column && curIdx.column<=c2);
+ },
+
+ highlightCell: function(cell) {
+ Rico.addClass(cell,this.options.highlightClass);
+ },
+
+ unhighlightCell: function(cell) {
+ if (cell) Rico.removeClass(cell,this.options.highlightClass);
+ },
+
+ selectRow: function(r) {
+ for (var c=0; c<this.columns.length; c++)
+ this.highlightCell(this.columns[c].cell(r));
+ },
+
+ unselectRow: function(r) {
+ for (var c=0; c<this.columns.length; c++)
+ this.unhighlightCell(this.columns[c].cell(r));
+ },
+
+ rowMouseOver: function(e) {
+ if (!this.highlightEnabled) return;
+ var cell=Rico.eventElement(e);
+ cell=Rico.getParentByTagName(cell,'div','ricoLG_cell');
+ if (!cell) return;
+ var newIdx=this.winCellIndex(cell);
+ if ((this.options.highlightSection & (newIdx.tabIdx+1))==0) return;
+ this.highlight(newIdx);
+ },
+
+ highlight: function(newIdx) {
+ if (this.options.highlightMethod!='outline') this.cursorSetClass(newIdx);
+ if (this.options.highlightMethod!='class') this.cursorOutline(newIdx);
+ this.highlightIdx=newIdx;
+ },
+
+ cursorSetClass: function(newIdx) {
+ switch (this.options.highlightElem) {
+ case 'menuCell':
+ case 'cursorCell':
+ if (this.highlightIdx) this.unhighlightCell(this.highlightIdx.cell);
+ this.highlightCell(newIdx.cell);
+ break;
+ case 'menuRow':
+ case 'cursorRow':
+ if (this.highlightIdx) this.unselectRow(this.highlightIdx.row);
+ var s1=this.options.highlightSection & 1;
+ var s2=this.options.highlightSection & 2;
+ var c0=s1 ? 0 : this.options.frozenColumns;
+ var c1=s2 ? this.columns.length : this.options.frozenColumns;
+ for (var c=c0; c<c1; c++)
+ this.highlightCell(this.columns[c].cell(newIdx.row));
+ break;
+ default: return;
+ }
+ },
+
+ cursorOutline: function(newIdx) {
+ var div;
+ switch (this.options.highlightElem) {
+ case 'menuCell':
+ case 'cursorCell':
+ div=this.highlightDiv[newIdx.tabIdx];
+ div.style.left=(this.columns[newIdx.column].dataCell.offsetLeft-1)+'px';
+ div.style.width=this.columns[newIdx.column].colWidth;
+ this.highlightDiv[1-newIdx.tabIdx].style.display='none';
+ break;
+ case 'menuRow':
+ case 'cursorRow':
+ div=this.highlightDiv[0];
+ var s1=this.options.highlightSection & 1;
+ var s2=this.options.highlightSection & 2;
+ div.style.left=s1 ? '0px' : this.frozenTabs.style.width;
+ div.style.width=((s1 ? this.frozenTabs.offsetWidth : 0) + (s2 ? this.innerDiv.offsetWidth : 0) - 4)+'px';
+ break;
+ default: return;
+ }
+ div.style.top=(this.hdrHt+newIdx.row*this.rowHeight-1)+'px';
+ div.style.height=(this.rowHeight-1)+'px';
+ div.style.display='';
+ },
+
+ unhighlight: function() {
+ switch (this.options.highlightElem) {
+ case 'menuCell':
+ //this.highlightIdx=this.menuIdx;
+ /*jsl:fallthru*/
+ case 'cursorCell':
+ if (this.highlightIdx) this.unhighlightCell(this.highlightIdx.cell);
+ if (!this.highlightDiv) return;
+ for (var i=0; i<2; i++)
+ this.highlightDiv[i].style.display='none';
+ break;
+ case 'menuRow':
+ //this.highlightIdx=this.menuIdx;
+ /*jsl:fallthru*/
+ case 'cursorRow':
+ if (this.highlightIdx) this.unselectRow(this.highlightIdx.row);
+ if (this.highlightDiv) this.highlightDiv[0].style.display='none';
+ break;
+ }
+ },
+
+ resetContents: function() {
+ Rico.log("resetContents");
+ this.ClearSelection();
+ this.buffer.clear();
+ this.clearRows();
+ this.clearBookmark();
+ },
+
+ setImages: function() {
+ for (var n=0; n<this.columns.length; n++)
+ this.columns[n].setImage();
+ },
+
+/**
+ * @return column index, or -1 if there are no sorted columns
+ */
+ findSortedColumn: function() {
+ for (var n=0; n<this.columns.length; n++) {
+ if (this.columns[n].isSorted()) return n;
+ }
+ return -1;
+ },
+
+/**
+ * Searches options.columnSpecs colAttr for matching colValue
+ * @return array of matching column indexes
+ */
+ findColumnsBySpec: function(colAttr, colValue) {
+ var result=[];
+ for (var n=0; n<this.options.columnSpecs.length; n++) {
+ if (this.options.columnSpecs[n][colAttr] == colValue) result.push(n);
+ }
+ return result;
+ },
+
+/**
+ * Set initial sort
+ */
+ setSortUI: function( columnIdOrNum, sortDirection ) {
+ Rico.log("setSortUI: "+columnIdOrNum+' '+sortDirection);
+ var colnum=this.findSortedColumn();
+ if (colnum >= 0) {
+ sortDirection=this.columns[colnum].getSortDirection();
+ } else {
+ if (typeof sortDirection!='string') {
+ sortDirection=Rico.ColumnConst.SORT_ASC;
+ } else {
+ sortDirection=sortDirection.toUpperCase();
+ if (sortDirection != Rico.ColumnConst.SORT_DESC) sortDirection=Rico.ColumnConst.SORT_ASC;
+ }
+ switch (typeof columnIdOrNum) {
+ case 'string':
+ colnum=this.findColumnsBySpec('id',columnIdOrNum);
+ break;
+ case 'number':
+ colnum=columnIdOrNum;
+ break;
+ }
+ }
+ if (typeof(colnum)!='number' || colnum < 0) return;
+ this.clearSort();
+ this.columns[colnum].setSorted(sortDirection);
+ this.buffer.sortBuffer(colnum);
+ },
+
+/**
+ * clear sort flag on all columns
+ */
+ clearSort: function() {
+ for (var x=0;x<this.columns.length;x++)
+ this.columns[x].setUnsorted();
+ },
+
+/**
+ * clear filters on all columns
+ */
+ clearFilters: function() {
+ for (var x=0;x<this.columns.length;x++) {
+ this.columns[x].setUnfiltered(true);
+ }
+ if (this.options.filterHandler) {
+ this.options.filterHandler();
+ }
+ },
+
+/**
+ * returns number of columns with a user filter set
+ */
+ filterCount: function() {
+ for (var x=0,cnt=0;x<this.columns.length;x++) {
+ if (this.columns[x].isFiltered()) cnt++;
+ }
+ return cnt;
+ },
+
+ sortHandler: function() {
+ this.cancelMenu();
+ this.ClearSelection();
+ this.setImages();
+ var n=this.findSortedColumn();
+ if (n < 0) return;
+ Rico.log("sortHandler: sorting column "+n);
+ this.buffer.sortBuffer(n);
+ this.clearRows();
+ this.scrollDiv.scrollTop = 0;
+ this.buffer.fetch(0);
+ },
+
+ filterHandler: function() {
+ Rico.log("filterHandler");
+ this.cancelMenu();
+ if (this.buffer.processingRequest) {
+ this.queueFilter=true;
+ return;
+ }
+ this.unplugScroll();
+ this.ClearSelection();
+ this.setImages();
+ this.clearBookmark();
+ this.clearRows();
+ this.buffer.fetch(-1);
+ Rico.runLater(10,this,'pluginScroll'); // resetting ht div can cause a scroll event, triggering an extra fetch
+ },
+
+ clearBookmark: function() {
+ if (this.bookmark) this.bookmark.innerHTML=" ";
+ },
+
+ bookmarkHandler: function(firstrow,lastrow) {
+ var newhtml;
+ if (isNaN(firstrow) || !this.bookmark) return;
+ var totrows=this.buffer.totalRows;
+ if (totrows < lastrow) lastrow=totrows;
+ if (totrows<=0) {
+ newhtml = Rico.getPhraseById('bookmarkNoMatch');
+ } else if (lastrow<0) {
+ newhtml = Rico.getPhraseById('bookmarkNoRec');
+ } else if (this.buffer.foundRowCount) {
+ newhtml = Rico.getPhraseById('bookmarkExact',firstrow,lastrow,totrows);
+ } else {
+ newhtml = Rico.getPhraseById('bookmarkAbout',firstrow,lastrow,totrows);
+ }
+ this.bookmark.innerHTML = newhtml;
+ },
+
+ clearRows: function() {
+ if (this.isBlank==true) return;
+ for (var c=0; c < this.columns.length; c++)
+ this.columns[c].clearColumn();
+ this.isBlank = true;
+ },
+
+ refreshContents: function(startPos) {
+ Rico.log("refreshContents1 "+this.tableId+": startPos="+startPos+" lastRow="+this.lastRowPos+" PartBlank="+this.isPartialBlank+" pageSize="+this.pageSize);
+ this.hideMsg();
+ this.cancelMenu();
+ this.unhighlight(); // in case highlighting was manually invoked
+ if (this.queueFilter) {
+ Rico.log("refreshContents: cancelling refresh because filter has changed");
+ this.queueFilter=false;
+ this.filterHandler();
+ return;
+ }
+ this.highlightEnabled=this.options.highlightSection!='none';
+ var viewPrecedesBuffer = this.buffer.startPos > startPos;
+ var contentStartPos = viewPrecedesBuffer ? this.buffer.startPos: startPos;
+ this.contentStartPos = contentStartPos+1;
+ var contentEndPos = Math.min(this.buffer.startPos + this.buffer.size, startPos + this.pageSize);
+ this.buffer.setWindow(contentStartPos, contentEndPos);
+ Rico.log('refreshContents2 '+this.tableId+': cStartPos='+contentStartPos+' cEndPos='+contentEndPos+' vPrecedesBuf='+viewPrecedesBuffer+' b.startPos='+this.buffer.startPos);
+ if (startPos == this.lastRowPos && !this.isPartialBlank && !this.isBlank) return;
+ this.isBlank = false;
+ var onRefreshComplete = this.options.onRefreshComplete;
+
+ if ((startPos + this.pageSize < this.buffer.startPos) ||
+ (this.buffer.startPos + this.buffer.size < startPos) ||
+ (this.buffer.size == 0)) {
+ this.clearRows();
+ if (onRefreshComplete) onRefreshComplete(this.contentStartPos,contentEndPos); // update bookmark
+ return;
+ }
+
+ Rico.log('refreshContents: contentStartPos='+contentStartPos+' contentEndPos='+contentEndPos+' viewPrecedesBuffer='+viewPrecedesBuffer);
+ var rowSize = contentEndPos - contentStartPos;
+ var blankSize = this.pageSize - rowSize;
+ var blankOffset = viewPrecedesBuffer ? 0: rowSize;
+ var contentOffset = viewPrecedesBuffer ? blankSize: 0;
+
+ for (var r=0; r < rowSize; r++) { //initialize what we have
+ for (var c=0; c < this.columns.length; c++)
+ this.columns[c].displayValue(r + contentOffset);
+ }
+ for (var i=0; i < blankSize; i++) // blank out the rest
+ this.blankRow(i + blankOffset);
+ if (this.options.highlightElem=='selection') this.ShowSelection();
+ this.isPartialBlank = blankSize > 0;
+ this.lastRowPos = startPos;
+ Rico.log("refreshContents complete, startPos="+startPos);
+ if (onRefreshComplete) onRefreshComplete(this.contentStartPos,contentEndPos); // update bookmark
+ },
+
+ scrollToRow: function(rowOffset) {
+ var p=this.rowToPixel(rowOffset);
+ Rico.log("scrollToRow, rowOffset="+rowOffset+" pixel="+p);
+ this.scrollDiv.scrollTop = p; // this causes a scroll event
+ if ( this.options.onscroll )
+ this.options.onscroll( this, rowOffset );
+ },
+
+ scrollUp: function() {
+ this.moveRelative(-1);
+ },
+
+ scrollDown: function() {
+ this.moveRelative(1);
+ },
+
+ pageUp: function() {
+ this.moveRelative(-this.pageSize);
+ },
+
+ pageDown: function() {
+ this.moveRelative(this.pageSize);
+ },
+
+ adjustRow: function(rowOffset) {
+ var notdisp=this.topOfLastPage();
+ if (notdisp == 0 || !rowOffset) return 0;
+ return Math.min(notdisp,rowOffset);
+ },
+
+ rowToPixel: function(rowOffset) {
+ return this.adjustRow(rowOffset) * this.rowHeight;
+ },
+
+/**
+ * @returns row to display at top of scroll div
+ */
+ pixeltorow: function(p) {
+ var notdisp=this.topOfLastPage();
+ if (notdisp == 0) return 0;
+ var prow=parseInt(p/this.rowHeight,10);
+ return Math.min(notdisp,prow);
+ },
+
+ moveRelative: function(relOffset) {
+ var newoffset=Math.max(this.scrollDiv.scrollTop+relOffset*this.rowHeight,0);
+ newoffset=Math.min(newoffset,this.scrollDiv.scrollHeight);
+ //Rico.log("moveRelative, newoffset="+newoffset);
+ this.scrollDiv.scrollTop=newoffset;
+ },
+
+ pluginScroll: function() {
+ if (this.scrollPluggedIn) return;
+ Rico.log("pluginScroll: wheelEvent="+this.wheelEvent);
+ Rico.eventBind(this.scrollDiv,"scroll",this.scrollEventFunc, false);
+ for (var t=0; t<3; t++)
+ Rico.eventBind(this.tabs[t],this.wheelEvent,this.wheelEventFunc, false);
+ this.scrollPluggedIn=true;
+ },
+
+ unplugScroll: function() {
+ if (!this.scrollPluggedIn) return;
+ Rico.log("unplugScroll");
+ Rico.eventUnbind(this.scrollDiv,"scroll", this.scrollEventFunc , false);
+ for (var t=0; t<2; t++)
+ Rico.eventUnbind(this.tabs[t],this.wheelEvent,this.wheelEventFunc, false);
+ this.scrollPluggedIn=false;
+ },
+
+ handleWheel: function(e) {
+ var delta = 1;
+ if (e.wheelDelta) {
+ if (Rico.isOpera)
+ delta = e.wheelDelta/120;
+ else if (Rico.isWebKit)
+ delta = -e.wheelDelta/12;
+ else
+ delta = -e.wheelDelta/120;
+ } else if (e.detail) {
+ delta = e.detail/3; /* Mozilla/Gecko */
+ }
+ if (delta) this.moveRelative(delta);
+ Rico.eventStop(e);
+ return false;
+ },
+
+ handleScroll: function(e) {
+ if ( this.scrollTimeout )
+ clearTimeout( this.scrollTimeout );
+ this.setHorizontalScroll();
+ var scrtop=this.scrollDiv.scrollTop;
+ var vscrollDiff = this.lastScrollPos-scrtop;
+ if (vscrollDiff == 0.00) return;
+ var newrow=this.pixeltorow(scrtop);
+ if (newrow == this.lastRowPos && !this.isPartialBlank && !this.isBlank) return;
+ var stamp1 = new Date();
+ Rico.log("handleScroll, newrow="+newrow+" scrtop="+scrtop);
+ if (this.options.highlightElem=='selection') this.HideSelection();
+ this.buffer.fetch(newrow);
+ if (this.options.onscroll) this.options.onscroll(this, newrow);
+ this.scrollTimeout = Rico.runLater(1200,this,'scrollIdle');
+ this.lastScrollPos = this.scrollDiv.scrollTop;
+ var stamp2 = new Date();
+ //Rico.log("handleScroll, time="+(stamp2.getTime()-stamp1.getTime()));
+ },
+
+ scrollIdle: function() {
+ if ( this.options.onscrollidle )
+ this.options.onscrollidle();
+ }
+
+};
+
+
+Rico.LiveGridColumn = function(grid,colIdx,hdrInfo,tabIdx) {
+ this.initialize(grid,colIdx,hdrInfo,tabIdx);
+};
+
+Rico.LiveGridColumn.prototype =
+/** @lends Rico.LiveGridColumn# */
+{
+/**
+ * Implements a LiveGrid column. Also contains static properties used by SimpleGrid columns.
+ * @extends Rico.TableColumnBase
+ * @constructs
+ */
+initialize: function(liveGrid,colIdx,hdrInfo,tabIdx) {
+ Rico.extend(this, new Rico.TableColumnBase());
+ this.baseInit(liveGrid,colIdx,hdrInfo,tabIdx);
+ this.buffer=liveGrid.buffer;
+ if (typeof(this.format.type)!='string' || this.format.EntryType=='tinyMCE') this.format.type='html';
+ if (typeof this.isNullable!='boolean') this.isNullable = /number|date/.test(this.format.type);
+ this.isText = /html|text/.test(this.format.type);
+ Rico.log(" sortable="+this.sortable+" filterable="+this.filterable+" hideable="+this.hideable+" isNullable="+this.isNullable+' isText='+this.isText);
+ this.fixHeaders(this.liveGrid.tableId, this.options.hdrIconsFirst);
+ if (this['format_'+this.format.type]) {
+ this._format=this['format_'+this.format.type];
+ }
+ if (this.format.control) {
+ // copy all properties/methods that start with '_'
+ if (typeof this.format.control=='string') {
+ this.format.control=eval(this.format.control);
+ }
+ for (var property in this.format.control) {
+ if (property.charAt(0)=='_') {
+ Rico.log("Copying control property "+property+ ' to ' + this);
+ this[property] = this.format.control[property];
+ }
+ }
+ }
+},
+
+/**
+ * Sorts the column in ascending order
+ */
+sortAsc: function() {
+ this.setColumnSort(Rico.ColumnConst.SORT_ASC);
+},
+
+/**
+ * Sorts the column in descending order
+ */
+sortDesc: function() {
+ this.setColumnSort(Rico.ColumnConst.SORT_DESC);
+},
+
+/**
+ * Sorts the column in the specified direction
+ * @param direction must be one of Rico.ColumnConst.UNSORTED, .SORT_ASC, or .SORT_DESC
+ */
+setColumnSort: function(direction) {
+ this.liveGrid.clearSort();
+ this.setSorted(direction);
+ if (this.liveGrid.options.saveColumnInfo.sort)
+ this.liveGrid.setCookie();
+ if (this.options.sortHandler)
+ this.options.sortHandler();
+},
+
+/**
+ * @returns true if this column is allowed to be sorted
+ */
+isSortable: function() {
+ return this.sortable;
+},
+
+/**
+ * @returns true if this column is currently sorted
+ */
+isSorted: function() {
+ return this.currentSort != Rico.ColumnConst.UNSORTED;
+},
+
+/**
+ * @returns Rico.ColumnConst.UNSORTED, .SORT_ASC, or .SORT_DESC
+ */
+getSortDirection: function() {
+ return this.currentSort;
+},
+
+/**
+ * toggle the sort sequence for this column
+ */
+toggleSort: function() {
+ if (this.buffer && this.buffer.totalRows==0) return;
+ if (this.currentSort == Rico.ColumnConst.SORT_ASC)
+ this.sortDesc();
+ else
+ this.sortAsc();
+},
+
+/**
+ * Flags that this column is not sorted
+ */
+setUnsorted: function() {
+ this.setSorted(Rico.ColumnConst.UNSORTED);
+},
+
+/**
+ * Flags that this column is sorted, but doesn't actually carry out the sort
+ * @param direction must be one of Rico.ColumnConst.UNSORTED, .SORT_ASC, or .SORT_DESC
+ */
+setSorted: function(direction) {
+ this.currentSort = direction;
+},
+
+/**
+ * @returns true if this column is allowed to be filtered
+ */
+canFilter: function() {
+ return this.filterable;
+},
+
+/**
+ * @returns a textual representation of how this column is filtered
+ */
+getFilterText: function() {
+ var vals=[];
+ for (var i=0; i<this.filterValues.length; i++) {
+ var v=this.filterValues[i];
+ vals.push(v=='' ? Rico.getPhraseById('filterBlank') : v);
+ }
+ switch (this.filterOp) {
+ case 'EQ': return '= '+vals.join(', ');
+ case 'NE': return Rico.getPhraseById('filterNot',vals.join(', '));
+ case 'LT': return '< '+vals[0];
+ case 'GT': return '> '+vals[0];
+ case 'LE': return '<= '+vals[0];
+ case 'GE': return '>= '+vals[0];
+ case 'LIKE': return Rico.getPhraseById('filterLike',vals[0]);
+ case 'NULL': return Rico.getPhraseById('filterEmpty');
+ case 'NOTNULL': return Rico.getPhraseById('filterNotEmpty');
+ }
+ return '?';
+},
+
+/**
+ * @returns returns the query string representation of the filter
+ */
+getFilterQueryParm: function() {
+ if (this.filterType == Rico.ColumnConst.UNFILTERED) return '';
+ var retval='&f['+this.index+'][op]='+this.filterOp;
+ retval+='&f['+this.index+'][len]='+this.filterValues.length;
+ for (var i=0; i<this.filterValues.length; i++) {
+ retval+='&f['+this.index+']['+i+']='+escape(this.filterValues[i]);
+ }
+ return retval;
+},
+
+/**
+ * removes the filter from this column
+ */
+setUnfiltered: function(skipHandler) {
+ this.filterType = Rico.ColumnConst.UNFILTERED;
+ if (this.liveGrid.options.saveColumnInfo.filter)
+ this.liveGrid.setCookie();
+ if (this.removeFilterFunc)
+ this.removeFilterFunc();
+ if (this.options.filterHandler && !skipHandler)
+ this.options.filterHandler();
+},
+
+setFilterEQ: function() {
+ this.setUserFilter('EQ');
+},
+setFilterNE: function() {
+ this.setUserFilter('NE');
+},
+addFilterNE: function() {
+ this.filterValues.push(this.userFilter);
+ if (this.liveGrid.options.saveColumnInfo.filter)
+ this.liveGrid.setCookie();
+ if (this.options.filterHandler)
+ this.options.filterHandler();
+},
+setFilterGE: function() { this.setUserFilter('GE'); },
+setFilterLE: function() { this.setUserFilter('LE'); },
+setFilterKW: function(keyword) {
+ if (keyword!='' && keyword!=null) {
+ this.setFilter('LIKE',keyword,Rico.ColumnConst.USERFILTER);
+ } else {
+ this.setUnfiltered(false);
+ }
+},
+
+setUserFilter: function(relop) {
+ this.setFilter(relop,this.userFilter,Rico.ColumnConst.USERFILTER);
+},
+
+setSystemFilter: function(relop,filter) {
+ this.setFilter(relop,filter,Rico.ColumnConst.SYSTEMFILTER);
+},
+
+setFilter: function(relop,filter,type,removeFilterFunc) {
+ this.filterValues = typeof(filter)=='object' ? filter : [filter];
+ this.filterType = type;
+ this.filterOp = relop;
+ if (type == Rico.ColumnConst.USERFILTER && this.liveGrid.options.saveColumnInfo.filter)
+ this.liveGrid.setCookie();
+ this.removeFilterFunc=removeFilterFunc;
+ if (this.options.filterHandler)
+ this.options.filterHandler();
+},
+
+isFiltered: function() {
+ return this.filterType == Rico.ColumnConst.USERFILTER;
+},
+
+filterChange: function(e) {
+ var selbox=Rico.eventElement(e);
+ if (selbox.value==this.liveGrid.options.FilterAllToken)
+ this.setUnfiltered();
+ else
+ this.setFilter('EQ',selbox.value,Rico.ColumnConst.USERFILTER,function() {selbox.selectedIndex=0;});
+},
+
+nFilterChange: function(e) {
+ var selbox=Rico.eventElement(e);
+ if (selbox.value==this.liveGrid.options.FilterAllToken) {
+ this.setUnfiltered();
+ } else {
+ var op=selbox.value.substr(0,2);
+ var value=selbox.value.substr(2);
+ this.setFilter(op,value,Rico.ColumnConst.USERFILTER,function() {selbox.selectedIndex=0;});
+ }
+},
+
+filterClear: function(e) {\r
+ this.filterField.value='';
+ this.setUnfiltered();\r
+},
+
+filterKeypress: function(e) {\r
+ var txtbox=Rico.eventElement(e);
+ if (typeof this.lastKeyFilter != 'string') this.lastKeyFilter='';\r
+ if (this.lastKeyFilter==txtbox.value) return;\r
+ var v=txtbox.value;\r
+ Rico.log("filterKeypress: "+this.index+' '+v);\r
+ this.lastKeyFilter=v;
+ if (v=='' || v=='*')\r
+ this.setUnfiltered();\r
+ else {
+ this.setFilter('LIKE', v, Rico.ColumnConst.USERFILTER, function() {txtbox.value='';});
+ }\r
+},\r
+
+mFilterSelectClick: function(e) {
+ Rico.eventStop(e);
+ if (this.mFilter.style.display!='none') {
+ this.mFilterFinish(e);
+ if (Rico.isIE && Rico.ieVersion <= 6) {
+ this.filterField.focus();
+ } else {
+ this.filterField.blur();
+ }
+ } else {
+ var offset=Rico.cumulativeOffset(this.filterField);
+ this.mFilter.style.top=(offset.top+this.filterField.offsetHeight)+'px';
+ this.mFilter.style.left=offset.left+'px';
+ this.mFilter.style.width=Math.min(this.filterField.offsetWidth,parseInt(this.colWidth,10))+'px';
+ Rico.show(this.mFilter);
+ this.mFilterFocus.focus();
+ }
+},
+
+mFilterFinish: function(e) {
+ if (!this.mFilterChange) {
+ Rico.hide(this.mFilter);
+ return;
+ }
+ if (this.mFilterInputs[0].checked) {
+ this.mFilterReset();
+ Rico.hide(this.mFilter);
+ this.setUnfiltered();
+ return;
+ }
+ var newValues=[];
+ var newLabels=[];
+ for (var i=1; i<this.mFilterInputs.length; i++) {
+ if (this.mFilterInputs[i].checked) {
+ newValues.push(this.mFilterInputs[i].value)
+ newLabels.push(this.mFilterLabels[i].innerHTML)
+ }
+ }
+ if (newValues.length > 0) {
+ var newText=newLabels.join(', ');
+ this.filterField.options[0].text=newText;
+ this.filterField.title=newText;
+ Rico.hide(this.mFilter);
+ this.mFilterChange=false;
+ var self=this;
+ this.setFilter('EQ',newValues,Rico.ColumnConst.USERFILTER,function() { self.mFilterReset(); });
+ } else {
+ alert('Please select at least one value');
+ }
+},
+
+mFilterReset: function() {
+ var newText=this.mFilterLabels[0].innerHTML; // all
+ this.filterField.options[0].text=newText;
+ this.filterField.title=newText;
+},
+
+mFilterAllClick: function(e) {
+ var allChecked=this.mFilterInputs[0].checked;
+ for (var i=1; i<this.mFilterInputs.length; i++) {
+ this.mFilterInputs[i].checked=allChecked;
+ }
+ this.mFilterChange=true;
+},
+
+mFilterOtherClick: function(e) {
+ this.mFilterInputs[0].checked=false;
+ this.mFilterChange=true;
+},
+
+format_text: function(v) {
+ if (typeof v!='string')
+ return ' ';
+ else
+ return v.replace(/&/g, '&').replace(/</g,'<').replace(/>/g,'>');
+},
+
+format_number: function(v) {
+ if (typeof v=='undefined' || v=='' || v==null)
+ return ' ';
+ else
+ return Rico.formatNumber(v,this.format);
+},
+
+format_datetime: function(v) {
+ if (typeof v=='undefined' || v=='' || v==null)
+ return ' ';
+ else {
+ var d=Rico.setISO8601(v);
+ if (!d) return v;
+ return (this.format.prefix || '')+Rico.formatDate(d,this.format.dateFmt || 'translateDateTime')+(this.format.suffix || '');
+ }
+},
+
+// converts GMT/UTC to local time
+format_utcaslocaltime: function(v) {
+ if (typeof v=='undefined' || v=='' || v==null)
+ return ' ';
+ else {
+ var tz=new Date();
+ var d=Rico.setISO8601(v,-tz.getTimezoneOffset());
+ if (!d) return v;
+ return (this.format.prefix || '')+Rico.formatDate(d,this.format.dateFmt || 'translateDateTime')+(this.format.suffix || '');
+ }
+},
+
+format_date: function(v) {
+ if (typeof v=='undefined' || v==null || v=='')
+ return ' ';
+ else {
+ var d=Rico.setISO8601(v);
+ if (!d) return v;
+ return (this.format.prefix || '')+Rico.formatDate(d,this.format.dateFmt || 'translateDate')+(this.format.suffix || '');
+ }
+},
+
+fixHeaders: function(prefix, iconsfirst) {
+ if (this.sortable) {
+ var handler=Rico.eventHandle(this,'toggleSort');
+ switch (this.options.headingSort) {
+ case 'link':
+ var a=Rico.wrapChildren(this.hdrCellDiv,'ricoSort',undefined,'a');
+ a.href = "javascript:void(0)";
+ Rico.eventBind(a,"click", handler);
+ break;
+ case 'hover':
+ Rico.eventBind(this.hdrCellDiv,"click", handler);
+ break;
+ }
+ }
+ this.imgFilter = document.createElement('span');
+ this.imgFilter.style.display='none';
+ this.imgFilter.className='rico-icon ricoLG_filterCol';
+ this.imgSort = document.createElement('span');
+ this.imgSort.style.display='none';
+ this.imgSort.style.verticalAlign='top';
+ if (iconsfirst) {
+ this.hdrCellDiv.insertBefore(this.imgSort,this.hdrCellDiv.firstChild);
+ this.hdrCellDiv.insertBefore(this.imgFilter,this.hdrCellDiv.firstChild);
+ } else {
+ this.hdrCellDiv.appendChild(this.imgFilter);
+ this.hdrCellDiv.appendChild(this.imgSort);
+ }
+ if (!this.format.filterUI) {
+ Rico.eventBind(this.imgFilter, 'click', Rico.eventHandle(this,'filterClick'), false);
+ }
+},
+
+filterClick: function(e) {
+ if (this.filterType==Rico.ColumnConst.USERFILTER && this.filterOp=='LIKE') {
+ this.liveGrid.openKeyword(this.index);
+ }
+},
+
+getValue: function(windowRow) {
+ return this.buffer.getWindowCell(windowRow,this.index);
+},
+
+getBufferStyle: function(windowRow) {
+ return this.buffer.getWindowStyle(windowRow,this.index);
+},
+
+setValue: function(windowRow,newval) {
+ this.buffer.setWindowValue(windowRow,this.index,newval);
+},
+
+_format: function(v) {
+ return v;
+},
+
+_display: function(v,gridCell) {
+ gridCell.innerHTML=this._format(v);
+},
+
+_export: function(v) {
+ return this._format(v);
+},
+
+exportBuffer: function(bufRow) {
+ return this._export(this.buffer.getValue(bufRow,this.index));
+},
+
+displayValue: function(windowRow) {
+ var bufval=this.getValue(windowRow);
+ if (bufval==null) {
+ this.clearCell(windowRow);
+ return;
+ }
+ var gridCell=this.cell(windowRow);
+ this._display(bufval,gridCell,windowRow);
+ if (this.buffer.options.acceptStyle) {
+ gridCell.style.cssText=this.getBufferStyle(windowRow);
+ }
+}
+
+};
--- /dev/null
+/*
+ * (c) 2005-2011 Richard Cowin (http://openrico.org)
+ * (c) 2005-2011 Matt Brown (http://dowdybrown.com)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this
+ * file except in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the specific language governing permissions
+ * and limitations under the License.
+ */
+
+if(typeof Rico=='undefined') throw("LiveGridAjax requires the Rico JavaScript framework");
+
+if (!Rico.Buffer) Rico.Buffer = {};
+
+Rico.Buffer.AjaxLoadOnce = function(url,options,ajaxOptions) {
+ this.initialize(url,options,ajaxOptions);
+}
+
+Rico.Buffer.AjaxLoadOnce.prototype = {
+/**
+ * @class Implements buffer for LiveGrid. Loads data from server via a single AJAX call.
+ * @extends Rico.Buffer.Base
+ * @constructs
+ */
+ initialize: function(url,options,ajaxOptions) {
+ Rico.extend(this, new Rico.Buffer.Base());
+ Rico.extend(this, Rico.Buffer.AjaxXMLMethods);
+ this.dataSource=url;
+ this.options.bufferTimeout=20000; // time to wait for ajax response (milliseconds)
+ this.options.requestParameters=[];
+ this.options.waitMsg=Rico.getPhraseById("waitForData"); // replace this with an image tag if you prefer
+ this.options.canFilter=true;
+ this.options.fmt='xml';
+ Rico.extend(this.options, options || {});
+ this.ajaxOptions = { parameters: null, method : 'get' };
+ Rico.extend(this.ajaxOptions, ajaxOptions || {});
+ this.requestCount=0;
+ this.processingRequest=false;
+ this.pendingRequest=-2;
+ this.fetchData=true;
+ this.sortParm={};
+ }
+}
+
+Rico.Buffer.AjaxXMLMethods = {
+
+/** @lends Rico.Buffer.AjaxLoadOnce# */
+ fetch: function(offset) {
+ if (this.fetchData) {
+ this.foundRowCount=true;
+ this.fetchData=false;
+ this.processingRequest=true;
+ this.liveGrid.showMsg(this.options.waitMsg);
+ this.timeoutHandler = Rico.runLater(this.options.bufferTimeout,this,'handleTimedOut');
+ this.ajaxOptions.parameters = this.formQueryHashXML(0,-1);
+ Rico.log('sending request');
+ var self=this;
+ if (typeof this.dataSource=='string') {
+ this.ajaxOptions.onComplete = function(xhr) { self.ajaxUpdate(offset,xhr); };
+ new Rico.ajaxRequest(this.dataSource, this.ajaxOptions);
+ } else {
+ this.ajaxOptions.onComplete = function(newRows, newStyle, totalRows, errMsg) { self.jsUpdate(offset, newRows, newStyle, totalRows, errMsg); };
+ this.dataSource(this.ajaxOptions);
+ }
+ } else {
+ if (offset < 0) {
+ this.applyFilters();
+ this.setTotalRows(this.size);
+ offset=0;
+ }
+ this.liveGrid.refreshContents(offset);
+ }
+ },
+
+/**
+ * Server did not respond in time... assume that there could have been
+ * an error, and allow requests to be processed again.
+ */
+ handleTimedOut: function() {
+ Rico.log("Request Timed Out");
+ this.liveGrid.showMsg(Rico.getPhraseById("requestTimedOut"));
+ },
+
+ formQueryHashXML: function(startPos,fetchSize) {
+ var queryHash= {
+ id: this.liveGrid.tableId,
+ page_size: (typeof fetchSize=='number') ? fetchSize : this.totalRows,
+ offset: startPos.toString()
+ };
+ queryHash[this.liveGrid.actionId]="query";
+ if (this.options.requestParameters) {
+ for ( var i=0; i < this.options.requestParameters.length; i++ ) {
+ var anArg = this.options.requestParameters[i];
+ if ( anArg.name != undefined && anArg.value != undefined ) {
+ queryHash[anArg.name]=anArg.value;
+ } else {
+ var ePos = anArg.indexOf('=');
+ var argName = anArg.substring( 0, ePos );
+ var argValue = anArg.substring( ePos + 1 );
+ queryHash[argName]=argValue;
+ }
+ }
+ }
+ return queryHash;
+ },
+
+ clearTimer: function() {
+ if(typeof this.timeoutHandler != "number") return;
+ window.clearTimeout(this.timeoutHandler);
+ delete this.timeoutHandler;
+ },
+
+ // used by both LoadOnce and SQL buffers
+ jsUpdate: function(startPos, newRows, newStyle, totalRows, errMsg) {
+ this.clearTimer();
+ this.processingRequest=false;
+ Rico.log("jsUpdate: "+arguments.length);
+ if (errMsg) {
+ Rico.log("jsUpdate: received error="+errMsg);
+ this.liveGrid.showMsg(Rico.getPhraseById("requestError",errMsg));
+ return;
+ }
+ this.rcvdRows = newRows.length;
+ if (typeof totalRows=='number') {
+ this.rowcntContent = totalRows.toString();
+ this.rcvdRowCount = true;
+ this.foundRowCount = true;
+ Rico.log("jsUpdate: found RowCount="+this.rowcntContent);
+ }
+ this.updateBuffer(startPos, newRows, newStyle);
+ if (this.options.onAjaxUpdate)
+ this.options.onAjaxUpdate();
+ this.updateGrid(startPos);
+ if (this.options.TimeOut && this.timerMsg)
+ this.restartSessionTimer();
+ if (this.pendingRequest>=-1) {
+ var offset=this.pendingRequest;
+ Rico.log("jsUpdate: found pending request for offset="+offset);
+ this.pendingRequest=-2;
+ this.fetch(offset);
+ }
+ },
+
+ // used by both LoadOnce and SQL buffers
+ ajaxUpdate: function(startPos,xhr) {
+ this.clearTimer();
+ this.processingRequest=false;
+ if (xhr.status != 200) {
+ Rico.log("ajaxUpdate: received http error="+xhr.status);
+ this.liveGrid.showMsg(Rico.getPhraseById("httpError",xhr.status));
+ return;
+ }
+ Rico.log("ajaxUpdate: startPos="+startPos);
+ this._responseHandler=this['processResponse'+this.options.fmt.toUpperCase()];
+ if (!this._responseHandler(startPos,xhr)) return;
+ if (this.options.onAjaxUpdate)
+ this.options.onAjaxUpdate();
+ this.updateGrid(startPos);
+ if (this.options.TimeOut && this.timerMsg)
+ this.restartSessionTimer();
+ if (this.pendingRequest>=-1) {
+ var offset=this.pendingRequest;
+ Rico.log("ajaxUpdate: found pending request for offset="+offset);
+ this.pendingRequest=-2;
+ this.fetch(offset);
+ }
+ },
+
+ // used by both LoadOnce and SQL buffers
+ processResponseXML: function(startPos,request) {
+ // The response text may contain META DATA for debugging if client side debugging is enabled in VS\r
+ var xmlDoc = request.responseXML;\r
+ if (request.responseText.substring(0, 4) == "<!--") {\r
+ var nEnd = request.responseText.indexOf("-->");\r
+ if (nEnd == -1) {\r
+ this.liveGrid.showMsg('Web server error - client side debugging may be enabled');\r
+ return false;\r
+ }\r
+ xmlDoc = Rico.createXmlDocument();\r
+ xmlDoc.loadXML(request.responseText.substring(nEnd+3));\r
+ }
+
+ if (!xmlDoc) {
+ alert("Data provider returned an invalid XML response");
+ Rico.log("Data provider returned an invalid XML response");
+ return false;
+ }
+
+ // process children of <ajax-response>
+ var response = xmlDoc.getElementsByTagName("ajax-response");
+ if (response == null || response.length != 1) {
+ alert("Received invalid response from server");
+ return false;
+ }
+ Rico.log("Processing ajax-response");
+ this.rcvdRows = 0;
+ this.rcvdRowCount = false;
+ var ajaxResponse=response[0];
+ var debugtags = ajaxResponse.getElementsByTagName('debug');
+ for (var i=0; i<debugtags.length; i++)
+ Rico.log("ajaxUpdate: debug msg "+i+": "+Rico.getContentAsString(debugtags[i],this.options.isEncoded));
+ var error = ajaxResponse.getElementsByTagName('error');
+ if (error.length > 0) {
+ var msg=Rico.getContentAsString(error[0],this.options.isEncoded);
+ alert("Data provider returned an error:\n"+msg);
+ Rico.log("Data provider returned an error:\n"+msg);
+ return false;
+ }
+ var rowsElement = ajaxResponse.getElementsByTagName('rows')[0];
+ if (!rowsElement) {
+ Rico.log("ajaxUpdate: invalid response");
+ this.liveGrid.showMsg(Rico.getPhraseById("invalidResponse"));
+ return false;
+ }
+ var rowcnttags = ajaxResponse.getElementsByTagName('rowcount');
+ if (rowcnttags && rowcnttags.length==1) {
+ this.rowcntContent = Rico.getContentAsString(rowcnttags[0],this.options.isEncoded);
+ this.rcvdRowCount = true;
+ this.foundRowCount = true;
+ Rico.log("ajaxUpdate: found RowCount="+this.rowcntContent);
+ }
+
+ // process <rows>
+ this.updateUI = rowsElement.getAttribute("update_ui") == "true";
+ this.rcvdOffset = rowsElement.getAttribute("offset");
+ Rico.log("ajaxUpdate: rcvdOffset="+this.rcvdOffset);
+ var newRows = this.dom2jstable(rowsElement);
+ var newStyle = (this.options.acceptStyle) ? this.dom2jstableStyle(rowsElement) : false;
+ this.rcvdRows = newRows.length;
+ this.updateBuffer(startPos, newRows, newStyle);
+ return true;
+ },
+
+ dom2jstableStyle: function(rowsElement,firstRow) {
+ Rico.log("dom2jstableStyle start");
+ var newRows = [];
+ var trs = rowsElement.getElementsByTagName("tr");
+ for ( var i=firstRow || 0; i < trs.length; i++ ) {
+ var row = [];
+ var cells = trs[i].getElementsByTagName("td");
+ for ( var j=0; j < cells.length ; j++ ) {
+ row[j]=cells[j].getAttribute('style') || '';
+ }
+ newRows.push( row );
+ }
+ Rico.log("dom2jstableStyle end");
+ return newRows;
+ },
+
+ processResponseJSON: function(startPos,request) {
+ var json = Rico.getJSON(request);
+ if (!json || json == null) {
+ alert("Data provider returned an invalid JSON response");
+ Rico.log("Data provider returned an invalid JSON response");
+ return false;
+ }
+
+ if (json.debug) {
+ for (var i=0; i<json.debug.length; i++)
+ Rico.writeDebugMsg("debug msg "+i+": "+json.debug[i]);
+ }
+ if (json.error) {
+ alert("Data provider returned an error:\n"+json.error);
+ Rico.writeDebugMsg("Data provider returned an error:\n"+json.error);
+ return false;
+ }
+
+ if (json.rowcount) {
+ this.rowcntContent = json.rowcount;
+ this.rcvdRowCount = true;
+ this.foundRowCount = true;
+ Rico.writeDebugMsg("loadRows, found RowCount="+json.rowcount);
+ }
+
+ this.rcvdRows = json.rows.length;
+ this.updateBuffer(startPos, json.rows, json.styles);
+ return true;
+ },
+
+ // specific to LoadOnce buffer
+ updateBuffer: function(start, newRows, newStyle) {
+ this.baseRows = newRows;
+ this.attr = newStyle;
+ Rico.log("updateBuffer: # of rows="+this.rcvdRows);
+ this.rcvdRowCount=true;
+ this.rowcntContent=this.rcvdRows;
+ if (typeof this.delayedSortCol=='number')
+ this.sortBuffer(this.delayedSortCol);
+ this.applyFilters();
+ this.startPos = 0;
+ },
+
+ // used by both LoadOnce and SQL buffers
+ updateGrid: function(offset) {
+ Rico.log("updateGrid, size="+this.size+' rcv cnt type='+typeof(this.rowcntContent));
+ var newpos;
+ if (this.rcvdRowCount==true) {
+ Rico.log("found row cnt: "+this.rowcntContent);
+ var eofrow=parseInt(this.rowcntContent,10);
+ var lastTotalRows=this.totalRows;
+ if (!isNaN(eofrow) && eofrow!=lastTotalRows) {
+ this.setTotalRows(eofrow);
+ newpos=Math.min(this.liveGrid.topOfLastPage(),offset);
+ Rico.log("updateGrid: new rowcnt="+eofrow+" newpos="+newpos);
+ this.liveGrid.scrollToRow(newpos);
+ if ( this.isInRange(newpos) ) {
+ this.liveGrid.refreshContents(newpos);
+ } else {
+ this.fetch(newpos);
+ }
+ return;
+ }
+ } else {
+ var lastbufrow=offset+this.rcvdRows;
+ if (lastbufrow>this.totalRows) {
+ var newcnt=lastbufrow;
+ Rico.log("extending totrows to "+newcnt);
+ this.setTotalRows(newcnt);
+ }
+ }
+ newpos=this.liveGrid.pixeltorow(this.liveGrid.scrollDiv.scrollTop);
+ Rico.log("updateGrid: newpos="+newpos);
+ this.liveGrid.refreshContents(newpos);
+ }
+
+};
+
+
+
+Rico.Buffer.AjaxSQL = function(url,options,ajaxOptions) {
+ this.initialize(url,options,ajaxOptions);
+}
+
+Rico.Buffer.AjaxSQL.prototype = {
+/**
+ * @class Implements buffer for LiveGrid. Loads data from server in chunks as user scrolls through the grid.
+ * @extends Rico.Buffer.AjaxLoadOnce
+ * @constructs
+ */
+ initialize: function(url,options,ajaxOptions) {
+ Rico.extend(this, new Rico.Buffer.AjaxLoadOnce());
+ Rico.extend(this, Rico.Buffer.AjaxSQLMethods);
+ this.dataSource=url;
+ this.options.canFilter=true;
+ this.options.largeBufferSize = 7.0; // 7 pages
+ this.options.nearLimitFactor = 1.0; // 1 page
+ this.options.canRefresh=true;
+ Rico.extend(this.options, options || {});
+ Rico.extend(this.ajaxOptions, ajaxOptions || {});
+ }
+}
+
+Rico.Buffer.AjaxSQLMethods = {
+/** @lends Rico.Buffer.AjaxSQL# */
+
+ registerGrid: function(liveGrid) {
+ this.liveGrid = liveGrid;
+ this.sessionExpired=false;
+ this.timerMsg=document.getElementById(liveGrid.tableId+'_timer');
+ if (this.options.TimeOut && this.timerMsg) {
+ if (!this.timerMsg.title) this.timerMsg.title=Rico.getPhraseById("sessionExpireMinutes");
+ this.restartSessionTimer();
+ }
+ },
+
+ setBufferSize: function(pageSize) {
+ this.maxFetchSize = Math.max(50,parseInt(this.options.largeBufferSize * pageSize,10));
+ this.nearLimit = parseInt(this.options.nearLimitFactor * pageSize,10);
+ this.maxBufferSize = this.maxFetchSize * 3;
+ },
+
+ restartSessionTimer: function() {
+ if (this.sessionExpired==true) return;
+ this.sessionEndTime = (new Date()).getTime() + this.options.TimeOut*60000;
+ if (this.sessionTimer) clearTimeout(this.sessionTimer);
+ this.updateSessionTimer();
+ },
+
+ updateSessionTimer: function() {
+ var now=(new Date()).getTime();
+ if (now > this.sessionEndTime) {
+ this.displaySessionTimer(Rico.getPhraseById("sessionExpired"));
+ this.timerMsg.style.backgroundColor="red";
+ this.sessionExpired=true;
+ } else {
+ var timeRemaining=Math.ceil((this.sessionEndTime - now) / 60000);
+ this.displaySessionTimer(timeRemaining);
+ this.sessionTimer=Rico.runLater(10000,this,'updateSessionTimer');
+ }
+ },
+
+ displaySessionTimer: function(msg) {
+ this.timerMsg.innerHTML=' '+msg+' ';
+ },
+
+ /**
+ * Update the grid with fresh data from the database, maintaining scroll position.
+ * @param resetRowCount indicates whether the total row count should be refreshed as well
+ */
+ refresh: function(resetRowCount) {
+ var lastGridPos=this.liveGrid.lastRowPos;\r
+ this.clear();
+ if (resetRowCount) {
+ this.setTotalRows(0);
+ this.foundRowCount = false;
+ }
+ this.liveGrid.clearBookmark();
+ this.liveGrid.clearRows();
+ this.fetch(lastGridPos);
+ },
+
+ /**
+ * Fetch data from database.
+ * @param offset position (row) within the dataset (-1=clear existing buffer before issuing request)
+ */
+ fetch: function(offset) {
+ Rico.log("AjaxSQL fetch: offset="+offset+', lastOffset='+this.lastOffset);
+ if (this.processingRequest) {
+ Rico.log("AjaxSQL fetch: queue request");
+ this.pendingRequest=offset;
+ return;
+ }
+ if ((typeof offset == 'undefined') || (offset < 0)) {
+ this.clear();
+ this.setTotalRows(0);
+ this.foundRowCount = false;
+ offset=0;
+ }
+ var lastOffset = this.lastOffset;
+ this.lastOffset = offset;
+ if (this.isInRange(offset)) {
+ Rico.log("AjaxSQL fetch: in buffer");
+ this.liveGrid.refreshContents(offset);
+ if (offset > lastOffset) {
+ if (offset+this.liveGrid.pageSize < this.endPos()-this.nearLimit) return;
+ if (this.endPos()==this.totalRows && this.foundRowCount) return;
+ } else if (offset < lastOffset) {
+ if (offset > this.startPos+this.nearLimit) return;
+ if (this.startPos==0) return;
+ } else return;
+ }
+ if (offset >= this.totalRows && this.foundRowCount) return;
+
+ this.processingRequest=true;
+ Rico.log("AjaxSQL fetch: processing offset="+offset);
+ var bufferStartPos = this.getFetchOffset(offset);
+ var fetchSize = this.getFetchSize(bufferStartPos);
+ var partialLoaded = false;
+
+ this.liveGrid.showMsg(this.options.waitMsg);
+ this.timeoutHandler = Rico.runLater(this.options.bufferTimeout, this, 'handleTimedOut');
+ this.ajaxOptions.parameters = this.formQueryHashSQL(bufferStartPos,fetchSize,this.options.fmt);
+ this.requestCount++;
+ Rico.log('sending req #'+this.requestCount);
+ var self=this;
+ if (typeof this.dataSource=='string') {
+ this.ajaxOptions.onComplete = function(xhr) { self.ajaxUpdate(bufferStartPos, xhr); };
+ new Rico.ajaxRequest(this.dataSource, this.ajaxOptions);
+ } else {
+ this.ajaxOptions.onComplete = function(newRows, newStyle, totalRows, errMsg) { self.jsUpdate(bufferStartPos, newRows, newStyle, totalRows, errMsg); };
+ this.dataSource(this.ajaxOptions);
+ }
+ },
+
+ formQueryHashSQL: function(startPos,fetchSize,fmt) {
+ var queryHash=this.formQueryHashXML(startPos,fetchSize);
+ if (!this.foundRowCount) queryHash['get_total']='true';
+ if (fmt) queryHash._fmt=fmt;
+
+ // sort
+ Rico.extend(queryHash,this.sortParm);
+
+ // filters
+ for (var n=0; n<this.liveGrid.columns.length; n++) {
+ var c=this.liveGrid.columns[n];
+ if (c.filterType == Rico.ColumnConst.UNFILTERED) continue;
+ var colnum=typeof(c.format.filterCol)=='number' ? c.format.filterCol : c.index;
+ queryHash['f['+colnum+'][op]']=c.filterOp;
+ queryHash['f['+colnum+'][len]']=c.filterValues.length;
+ for (var i=0; i<c.filterValues.length; i++) {
+ var fval=c.filterValues[i];
+ if (c.format.type == 'date') {
+ var parts = fval.split('.');
+ if (parts.length > 1) {
+ parts.reverse();
+ for (var j=0; j < parts.length; j++)
+ if (parts[j].length == 1)
+ parts[j] = '0' + parts[j].toString();
+ fval = parts.join('-');
+ }
+ }
+ if (c.filterOp=='LIKE' && fval.indexOf('*')==-1) {
+ if (c.format.filterUI.charAt(1) == '^') fval=fval+'*';
+ else if (c.format.filterUI.charAt(1) == '$') fval='*'+fval;
+ else if (c.format.filterUI.charAt(1) == '=') queryHash['f['+colnum+'][op]']='EQ';
+ else fval='*'+fval+'*';
+ }
+ queryHash['f['+colnum+']['+i+']']=fval;
+ }
+ }
+ return queryHash;
+ },
+
+ getFetchSize: function(adjustedOffset) {
+ var adjustedSize = 0;
+ if (adjustedOffset >= this.startPos) { //appending
+ var endFetchOffset = this.maxFetchSize + adjustedOffset;
+ adjustedSize = endFetchOffset - adjustedOffset;
+ if(adjustedOffset == 0 && adjustedSize < this.maxFetchSize)
+ adjustedSize = this.maxFetchSize;
+ Rico.log("getFetchSize/append, adjustedSize="+adjustedSize+" adjustedOffset="+adjustedOffset+' endFetchOffset='+endFetchOffset);
+ } else { //prepending
+ adjustedSize = Math.min(this.startPos - adjustedOffset,this.maxFetchSize);
+ }
+ return adjustedSize;
+ },
+
+ getFetchOffset: function(offset) {
+ var adjustedOffset = offset;
+ if (offset > this.startPos)
+ adjustedOffset = Math.max(offset, this.endPos()); //appending
+ else if (offset + this.maxFetchSize >= this.startPos)
+ adjustedOffset = Math.max(this.startPos - this.maxFetchSize, 0); //prepending
+ return adjustedOffset;
+ },
+
+ updateBuffer: function(start, newRows, newStyle) {
+ Rico.log("updateBuffer: start="+start+", # of rows="+this.rcvdRows);
+ if (this.rows.length == 0) { // initial load
+ this.rows = newRows;
+ this.attr = newStyle;
+ this.startPos = start;
+ } else if (start > this.startPos) { //appending
+ if (this.startPos + this.rows.length < start) {
+ this.rows = newRows;
+ this.attr = newStyle;
+ this.startPos = start;
+ } else {
+ this.rows = this.rows.concat( newRows.slice(0, newRows.length));
+ if (this.attr && newStyle) this.attr = this.attr.concat( newStyle.slice(0, newStyle.length));
+ if (this.rows.length > this.maxBufferSize) {
+ var fullSize = this.rows.length;
+ this.rows = this.rows.slice(this.rows.length - this.maxBufferSize, this.rows.length);
+ if (this.attr) this.attr = this.attr.slice(this.attr.length - this.maxBufferSize, this.attr.length);
+ this.startPos = this.startPos + (fullSize - this.rows.length);
+ }
+ }
+ } else { //prepending
+ if (start + newRows.length < this.startPos) {
+ this.rows = newRows;
+ this.attr = newStyle;
+ } else {
+ this.rows = newRows.slice(0, this.startPos).concat(this.rows);
+ if (newStyle) this.attr = newStyle.slice(0, this.startPos).concat(this.attr);
+ if (this.maxBufferSize && this.rows.length > this.maxBufferSize) {
+ this.rows = this.rows.slice(0, this.maxBufferSize);
+ if (this.attr) this.attr = this.attr.slice(0, this.maxBufferSize);
+ }
+ }
+ this.startPos = start;
+ }
+ this.size = this.rows.length;
+ },
+
+ sortBuffer: function(colnum) {
+ this.sortParm={};
+ var col=this.liveGrid.columns[colnum];
+ if (this.options.sortParmFmt) {
+ this.sortParm['sort_col']=col[this.options.sortParmFmt];
+ this.sortParm['sort_dir']=col.getSortDirection();
+ } else {
+ this.sortParm['s'+colnum]=col.getSortDirection();
+ }
+ this.clear();
+ },
+
+ printAllSQL: function(exportType) {
+ var parms=this.formQueryHashSQL(0,this.liveGrid.options.maxPrint,exportType);
+ parms.hidden=this.liveGrid.listInvisible('index').join(',');
+ var url=this.dataSource+'?'+Rico.toQueryString(parms);
+ window.open(url,'',this.liveGrid.options.exportWindow);
+ },
+
+ printVisibleSQL: function(exportType) {
+ var parms=this.formQueryHashSQL(this.liveGrid.contentStartPos-1, this.liveGrid.pageSize, exportType);
+ parms.hidden=this.liveGrid.listInvisible('index').join(',');
+ var url=this.dataSource+'?'+Rico.toQueryString(parms);
+ window.open(url,'',this.liveGrid.options.exportWindow);
+ },
+
+ // for datasource that is a javascript function
+ _printAll: function() {
+ this.liveGrid.exportStart();
+ this.ajaxOptions.parameters = this.formQueryHashSQL(0,this.liveGrid.options.maxPrint);
+ var self=this;
+ this.ajaxOptions.onComplete = function() { self._jsExport(); };
+ this.dataSource(this.ajaxOptions);
+ },
+
+ _jsExport: function(newRows, newStyle, totalRows, errMsg) {
+ Rico.log("_jsExport: "+arguments.length);
+ if (errMsg) {
+ Rico.log("_jsExport: received error="+errMsg);
+ this.liveGrid.showMsg(Rico.getPhraseById("requestError",errMsg));
+ return;
+ }
+ this.exportBuffer(newRows,0);
+ this.liveGrid.exportFinish();
+ }
+
+};
--- /dev/null
+/*
+ * (c) 2005-2009 Richard Cowin (http://openrico.org)
+ * (c) 2005-2009 Matt Brown (http://dowdybrown.com)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this
+ * file except in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the specific language governing permissions
+ * and limitations under the License.
+ */
+\r
+// -----------------------------------------------------\r
+//\r
+// Custom formatting for LiveGrid columns\r
+//\r
+// columnSpecs Usage: { type:'control', control:new Rico.TableColumn.CONTROLNAME() }\r
+//\r
+// -----------------------------------------------------\r
+
+Rico.TableColumn = {};
+\r
+Rico.TableColumn.checkboxKey = function(showKey) {
+ this.initialize(showKey);
+}
+
+Rico.TableColumn.checkboxKey.prototype = {
+/**
+ * @class Custom formatting for a LiveGrid column.
+ * Display unique key column as: <checkbox> <key value>
+ * and keep track of which keys the user selects
+ * Key values should not contain <, >, or &
+ * @constructs
+ */
+ initialize: function(showKey) {
+ this._checkboxes=[];
+ this._spans=[];
+ this._KeyHash={};
+ this._showKey=showKey;\r
+ },
+
+ _create: function(gridCell,windowRow) {
+ this._checkboxes[windowRow]=Rico.createFormField(gridCell,'input','checkbox',this.liveGrid.tableId+'_chkbox_'+this.index+'_'+windowRow);
+ this._spans[windowRow]=Rico.createFormField(gridCell,'span',null,this.liveGrid.tableId+'_desc_'+this.index+'_'+windowRow);
+ this._clear(gridCell,windowRow);
+ Rico.eventBind(this._checkboxes[windowRow], 'click', Rico.eventHandle(this,'_onclick'));
+ },
+
+ _onclick: function(e) {
+ var elem=Rico.eventElement(e);
+ var windowRow=parseInt(elem.id.substr((elem.id.lastIndexOf('_',elem.id.length)+1))); //faster than split
+ var v=this.getValue(windowRow);
+ if (elem.checked)
+ this._addChecked(v);
+ else
+ this._remChecked(v);
+ },
+
+ _clear: function(gridCell,windowRow) {
+ var box=this._checkboxes[windowRow];
+ box.checked=false;
+ box.style.display='none';
+ this._spans[windowRow].innerHTML='';
+ },
+
+ _display: function(v,gridCell,windowRow) {
+ var box=this._checkboxes[windowRow];
+ box.style.display='';
+ box.checked=this._KeyHash[v];
+ if (this._showKey) this._spans[windowRow].innerHTML=v;
+ },
+
+ _SelectedKeys: function() {
+ return Rico.keys(this._KeyHash);
+ },
+
+ _addChecked: function(k){\r
+ this._KeyHash[k]=1;\r
+ },\r
+\r
+ _remChecked: function(k){\r
+ delete this._KeyHash[k];\r
+ }\r
+}
+
+
+Rico.TableColumn.checkbox = function(checkedValue, uncheckedValue, defaultValue, readOnly)
+{
+ this.initialize(checkedValue, uncheckedValue, defaultValue, readOnly);
+}
+
+Rico.TableColumn.checkbox.prototype = {
+/**
+ * @class display checkboxes for two-valued column (e.g. yes/no)
+ * @constructs
+ */
+ initialize: function(checkedValue, uncheckedValue, defaultValue, readOnly) {
+ this._checkedValue=checkedValue;
+ this._uncheckedValue=uncheckedValue;
+ this._defaultValue=defaultValue || false;
+ this._readOnly=readOnly || false;
+ this._checkboxes=[];
+ },
+
+ _create: function(gridCell,windowRow) {
+ this._checkboxes[windowRow]=Rico.createFormField(gridCell,'input','checkbox',this.liveGrid.tableId+'_chkbox_'+this.index+'_'+windowRow);
+ this._clear(gridCell,windowRow);
+ if (this._readOnly)
+ this._checkboxes[windowRow].disabled=true;
+ else
+ Rico.eventBind(this._checkboxes[windowRow], 'click', Rico.eventHandle(this,'_onclick'));
+ },
+
+ _onclick: function(e) {
+ var elem=Rico.eventElement(e);
+ var windowRow=parseInt(elem.id.substr((elem.id.lastIndexOf('_',elem.id.length)+1))); //faster than split
+ var newval=elem.checked ? this._checkedValue : this._uncheckedValue;
+ this.setValue(windowRow,newval);
+ },
+
+ _clear: function(gridCell,windowRow) {
+ var box=this._checkboxes[windowRow];
+ box.checked=this._defaultValue;
+ box.style.display='none';
+ },
+
+ _display: function(v,gridCell,windowRow) {
+ var box=this._checkboxes[windowRow];
+ box.style.display='';
+ box.checked=(v==this._checkedValue);
+ }
+
+}
+
+
+Rico.TableColumn.textbox = function(boxSize, boxMaxLen, readOnly) {
+ this.initialize(boxSize, boxMaxLen, readOnly);
+}
+
+Rico.TableColumn.textbox.prototype = {
+/**
+ * @class display value in a text box
+ * @constructs
+ */
+ initialize: function(boxSize, boxMaxLen, readOnly) {
+ this._boxSize=boxSize;
+ this._boxMaxLen=boxMaxLen;
+ this._readOnly=readOnly || false;
+ this._textboxes=[];
+ },
+
+ _create: function(gridCell,windowRow) {
+ var box=Rico.createFormField(gridCell,'input','text',this.liveGrid.tableId+'_txtbox_'+this.index+'_'+windowRow);
+ box.size=this._boxSize;
+ box.maxLength=this._boxMaxLen;
+ this._textboxes[windowRow]=box;
+ this._clear(gridCell,windowRow);
+ if (this._readOnly)
+ box.disabled=true;
+ else
+ Rico.eventBind(box, 'change', Rico.eventHandle(this,'_onchange'));
+ },
+
+ _onchange: function(e) {
+ var elem=Event.element(e);
+ var windowRow=parseInt(elem.id.substr((elem.id.lastIndexOf('_',elem.id.length)+1))); //faster than split
+ this.setValue(windowRow,elem.value);
+ },
+
+ _clear: function(gridCell,windowRow) {
+ var box=this._textboxes[windowRow];
+ box.value='';
+ box.style.display='none';
+ },
+
+ _display: function(v,gridCell,windowRow) {
+ var box=this._textboxes[windowRow];
+ box.style.display='';
+ box.value=v;
+ }
+
+}
+
+
+Rico.TableColumn.bgColor = function() {
+}
+
+Rico.TableColumn.bgColor.prototype = {
+/**
+ * @class database value contains a css color name/value
+ */
+
+ _clear: function(gridCell,windowRow) {
+ gridCell.style.backgroundColor='';
+ },
+
+ _display: function(v,gridCell,windowRow) {
+ gridCell.style.backgroundColor=v;
+ }
+
+}
+
+
+Rico.TableColumn.link = function(href,target,linktext) {
+ this.initialize(href,target,linktext);
+}
+
+Rico.TableColumn.link.prototype = {
+/**
+ * @class database value contains a url to another page
+ * @constructs
+ */
+ initialize: function(href,target,linktext) {
+ this._href=href;
+ this._target=target;
+ this._linktext=linktext;
+ this._anchors=[];
+ },
+
+ _create: function(gridCell,windowRow) {
+ var a = gridCell.appendChild(document.createElement('a'));
+ if (this._target) a.target=this._target;
+ a.href='';
+ a.innerHTML=Rico.isIE ? ' ' : '';
+ this._anchors[windowRow] = a;
+ },
+
+ _clear: function(gridCell,windowRow) {
+ this._anchors[windowRow].style.display='none';
+ },
+
+ _display: function(v,gridCell,windowRow) {
+ var buf=this.liveGrid.buffer;
+ var href=this._href=='self' ? v : this._href.replace(/\{\d+\}/g,
+ function ($1) {
+ var colIdx=parseInt($1.substr(1),10);
+ return encodeURIComponent(buf.getWindowValue(windowRow,colIdx));
+ }
+ );
+ var desc=this._linktext || v;
+ if (href && desc) {
+ this._anchors[windowRow].href=href;
+ this._anchors[windowRow].innerHTML=desc;
+ this._anchors[windowRow].style.display=Rico.isIE ? 'inline-block' : '';
+ } else {
+ this._clear(gridCell,windowRow);
+ }
+ }
+
+};
+
+
+Rico.TableColumn.image = function(prefix,suffix) {
+ this.initialize(prefix,suffix);
+};
+
+Rico.TableColumn.image.prototype = {
+/**
+ * @class database value contains a url to an image
+ * @constructs
+ */
+ initialize: function(prefix,suffix) {
+ this._img=[];
+ this._prefix=prefix || '';
+ this._suffix=suffix || '';
+ },
+
+ _create: function(gridCell,windowRow) {
+ this._img[windowRow]=Rico.createFormField(gridCell,'img',null,this.liveGrid.tableId+'_img_'+this.index+'_'+windowRow);
+ this._clear(gridCell,windowRow);
+ },
+
+ _clear: function(gridCell,windowRow) {
+ var img=this._img[windowRow];
+ img.style.display='none';
+ img.src='';
+ },
+
+ _display: function(v,gridCell,windowRow) {
+ var img=this._img[windowRow];
+ this._img[windowRow].src=this._prefix+v+this._suffix;
+ img.style.display='';
+ }
+
+};
+
+
+Rico.TableColumn.lookup = function(map, defaultCode, defaultDesc) {
+ this.initialize(map, defaultCode, defaultDesc);
+};
+
+Rico.TableColumn.lookup.prototype = {
+/**
+ * @class map a database value to a display value
+ * @constructs
+ */
+ initialize: function(map, defaultCode, defaultDesc) {
+ this._map=map;
+ this._defaultCode=defaultCode || '';
+ this._defaultDesc=defaultDesc || ' ';
+ var self=this;
+ this._sortfunc=function(v) { return self._sortvalue(v); };
+ this._codes=[];
+ this._descriptions=[];
+ },
+
+ _create: function(gridCell,windowRow) {
+ this._descriptions[windowRow]=Rico.createFormField(gridCell,'span',null,this.liveGrid.tableId+'_desc_'+this.index+'_'+windowRow);
+ this._codes[windowRow]=Rico.createFormField(gridCell,'input','hidden',this.liveGrid.tableId+'_code_'+this.index+'_'+windowRow);
+ this._clear(gridCell,windowRow);
+ },
+
+ _clear: function(gridCell,windowRow) {
+ this._codes[windowRow].value=this._defaultCode;
+ this._descriptions[windowRow].innerHTML=' ';
+ },
+
+ _sortvalue: function(v) {
+ return this._getdesc(v).replace(/&/g, '&').replace(/</g,'<').replace(/>/g,'>').replace(/ /g,' ');
+ },
+
+ _getdesc: function(v) {
+ var desc=this._map[v];
+ return (typeof desc=='string') ? desc : this._defaultDesc;
+ },
+
+ _export: function(v) {
+ return this._getdesc(v);
+ },
+
+ _display: function(v,gridCell,windowRow) {
+ this._codes[windowRow].value=v;
+ this._descriptions[windowRow].innerHTML=this._getdesc(v);
+ }
+
+};
+
+
+
+Rico.TableColumn.MultiLine = function() {
+};
+
+Rico.TableColumn.MultiLine.prototype = {
+/**
+ * @class Fix issues with multiline content in IE
+ */
+ _display: function(v,gridCell,windowRow) {\r
+ var newdiv = document.createElement("div");\r
+ newdiv.innerHTML = this._format(v);\r
+ newdiv.style.height='100%';\r
+ if (gridCell.firstChild)\r
+ gridCell.replaceChild(newdiv, gridCell.firstChild);\r
+ else\r
+ gridCell.appendChild(newdiv);\r
+ }\r
+
+};
--- /dev/null
+/*
+ * (c) 2005-2011 Richard Cowin (http://openrico.org)
+ * (c) 2005-2011 Matt Brown (http://dowdybrown.com)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this
+ * file except in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the specific language governing permissions
+ * and limitations under the License.
+ */
+
+if(typeof Rico=='undefined') throw("LiveGridForms requires the Rico JavaScript framework");
+
+
+Rico.TableEdit = function(liveGrid) {
+ this.initialize(liveGrid);
+}
+
+Rico.TableEdit.prototype = {
+/**
+ * @class Supports editing LiveGrid data.
+ * @constructs
+ */
+ initialize: function(liveGrid) {
+ Rico.log('Rico.TableEdit initialize: '+liveGrid.tableId);
+ this.grid=liveGrid;
+ this.options = {
+ maxDisplayLen : 20, // max displayed text field length
+ panelHeight : 200, // size of tabbed panels
+ panelWidth : 500,
+ compact : false, // compact corners
+ RecordName : Rico.getPhraseById("record"),
+ updateURL : window.location.href, // default is that updates post back to the generating page
+ showSaveMsg : 'errors' // disposition of database update responses (full - show full response, errors - show full response for errors and short response otherwise)
+ };
+ Rico.extend(this.options, liveGrid.options);
+ var self=this;
+ this.menu=liveGrid.menu;
+ this.menu.options.dataMenuHandler=function(grid,r,c,onBlankRow) { return self.editMenu(grid,r,c,onBlankRow); };
+ this.menu.ignoreClicks();
+ this.editText=Rico.getPhraseById("editRecord",this.options.RecordName);
+ this.cloneText=Rico.getPhraseById("cloneRecord",this.options.RecordName);
+ this.delText=Rico.getPhraseById("deleteRecord",this.options.RecordName);
+ this.addText=Rico.getPhraseById("addRecord",this.options.RecordName);
+ this.buttonHover=new Rico.HoverSet();
+ this.dateRegExp=/^\s*(\w+)(\W)(\w+)(\W)(\w+)/i;
+ this.createKeyArray();
+ if (typeof(this.options.ConfirmDeleteCol) != 'number')
+ this.options.ConfirmDeleteCol=this.keys.length > 0 ? -2 : -1;
+ this.createEditDiv();
+ this.saveMsg=Rico.$(liveGrid.tableId+'_savemsg');
+ Rico.eventBind(document,"click", Rico.eventHandle(this,'clearSaveMsg'));
+ this.extraMenuItems=[];
+ this.responseHandler=function(xhr) { self.processResponse(xhr); };
+ Rico.log("Rico.TableEdit.initialize complete");
+ },
+
+ createKeyArray: function() {
+ this.keys=[];
+ for (var i=0; i<this.grid.columns.length; i++) {
+ if (this.grid.columns[i].format && this.grid.columns[i].format.isKey)
+ this.keys.push({colidx:i});
+ }
+ },
+
+ createEditDiv: function() {
+
+ // create popup form
+
+ this.requestCount=1;
+ this.formPopup=this.createWindow();
+ Rico.addClass(this.formPopup.content.parentNode,'ricoLG_editDiv');
+ if (this.options.canEdit || this.options.canAdd) {
+ this.startForm();
+ this.createForm(this.form);
+ } else {
+ var buttonClose=this.createButton(Rico.getPhraseById("close"));
+ Rico.eventBind(buttonClose,"click", Rico.eventHandle(this,'cancelEdit'), false);
+ this.createForm(this.formPopup.contentDiv);
+ }
+ this.editDivCreated=true;
+
+ // create responseDialog
+
+ this.responseDialog = this.grid.createDiv('editResponse',document.body);
+ this.responseDialog.style.display='none';
+
+ var buttonOK = document.createElement('button');
+ buttonOK.appendChild(document.createTextNode(Rico.getPhraseById("ok")));
+ Rico.eventBind(buttonOK,"click", Rico.eventHandle(this,'ackResponse'));
+ this.responseDialog.appendChild(buttonOK);
+
+ this.responseDiv = this.grid.createDiv('editResponseText',this.responseDialog);
+
+ if (this.panelGroup) {
+ Rico.log("createEditDiv complete, requestCount="+this.requestCount);
+ Rico.runLater(50,this,'initPanelGroup');
+ }
+ },
+
+ createWindow: function() {
+ var self=this;
+ return new Rico.Window('', {closeFunc: function() { self.makeFormInvisible(); }, overflow: this.options.ColGroups ? 'hidden' : 'auto'});
+ },
+
+ initPanelGroup: function() {
+ this.requestCount--;
+ Rico.log("initPanelGroup: "+this.requestCount);
+ if (this.requestCount>0) return;
+ var wi=parseInt(this.options.panelWidth,10);
+ if (this.form) {
+ //this.form.style.width=(wi+10)+'px';
+ if (Rico.isWebKit) this.formPopup.container.style.display='block'; // this causes display to flash briefly
+ this.options.bgColor = Rico.Color.createColorFromBackground(this.form).toString();
+ }
+ this.formPopup.container.style.display='none';
+ this.formPanels=new Rico.TabbedPanel(this.panelGroup, this.options);
+ },
+
+ notEmpty: function(v) {
+ return typeof(v)!='undefined';
+ },
+
+ startForm: function() {
+ this.form = document.createElement('form');
+ /** @ignore */
+ this.form.onsubmit=function() {return false;};
+ this.form.autocomplete="off"; // seems to fix "Permission denied..." errors in FF
+ this.formPopup.contentDiv.appendChild(this.form);
+
+ var tab = document.createElement('div');
+ tab.className='ButtonBar';
+ var button=tab.appendChild(this.createButton(Rico.getPhraseById("saveRecord",this.options.RecordName)));
+ Rico.eventBind(button,"click", Rico.eventHandle(this,'TESubmit'), false);
+ button=tab.appendChild(this.createButton(Rico.getPhraseById("cancel")));
+ Rico.eventBind(button,"click", Rico.eventHandle(this,'cancelEdit'), false);
+ this.form.appendChild(tab);
+
+ // hidden fields
+ this.hiddenFields = document.createElement('div');
+ this.hiddenFields.style.display='none';
+ this.action = this.appendHiddenField(this.grid.actionId,'');
+ var i,fldSpec;
+ for (i=0; i<this.grid.columns.length; i++) {
+ fldSpec=this.grid.columns[i].format;
+ if (fldSpec && fldSpec.FormView && fldSpec.FormView=="hidden")
+ this.appendHiddenField(fldSpec.FieldName,fldSpec.ColData);
+ }
+ for (var k=0; k<this.keys.length; k++) {
+ this.keys[k].keyField = this.appendHiddenField('_k'+this.keys[k].colidx,'');
+ }
+ this.form.appendChild(this.hiddenFields);
+ },
+
+ createButton: function(buttonLabel) {
+ var button = document.createElement('a');
+ button.href='javascript:void(0)';
+ button.innerHTML=buttonLabel;
+ button.className='RicoButton';
+ if (Rico.theme.button) Rico.addClass(button,Rico.theme.button);
+ this.buttonHover.add(button);
+ return button;
+ },
+
+ createPanel: function(i) {
+ var hasFields=false;
+ for (var j=0; j<this.grid.columns.length; j++) {
+ var fldSpec=this.grid.columns[j].format;
+ if (!fldSpec) continue;
+ if (!fldSpec.EntryType) continue;
+ if (fldSpec.EntryType=='H') continue;
+ if (fldSpec.FormView && fldSpec.FormView=="hidden") continue;
+ var panelIdx=fldSpec.ColGroupIdx || 0;
+ if (panelIdx==i) {
+ hasFields=true;
+ break;
+ }
+ }
+ if (!hasFields) return null;
+ this.panelHdr[i] = document.createElement('li');
+ this.panelHdr[i].innerHTML=this.options.ColGroups[i];
+ this.panelHdrs.appendChild(this.panelHdr[i]);
+ this.panelContent[i] = document.createElement('div');
+ this.panelContents.appendChild(this.panelContent[i]);
+ this.panelActualIdx[i]=this.panelCnt++;
+ return this.createFormTable(this.panelContent[i],'tabContent');
+ },
+
+ createForm: function(parentDiv) {
+ var i,div,fldSpec,panelIdx,tables=[];
+ this.panelCnt=0;
+ this.panelHdr=[];
+ this.panelContent=[];
+ if (this.options.ColGroups) {
+ this.panelGroup = document.createElement('div');
+ this.panelGroup.className='tabPanelGroup';
+ this.panelHdrs = document.createElement('ul');
+ this.panelGroup.appendChild(this.panelHdrs);
+ this.panelContents = document.createElement('div');
+ this.panelContents.className='tabContentContainer';
+ this.panelGroup.appendChild(this.panelContents);
+ this.panelActualIdx=[];
+ parentDiv.appendChild(this.panelGroup);
+ if (this.grid.direction=='rtl') {
+ for (i=this.options.ColGroups.length-1; i>=0; i--) {
+ tables[i]=this.createPanel(i);
+ }
+ } else {
+ for (i=0; i<this.options.ColGroups.length; i++) {
+ tables[i]=this.createPanel(i);
+ }
+ }
+ parentDiv.appendChild(this.panelGroup);
+ } else {
+ div=document.createElement('div');
+ div.className='noTabContent';
+ tables[0]=this.createFormTable(div);
+ parentDiv.appendChild(div);
+ }
+ for (i=0; i<this.grid.columns.length; i++) {
+ fldSpec=this.grid.columns[i].format;
+ if (!fldSpec) continue;
+ panelIdx=fldSpec.ColGroupIdx || 0;
+ if (tables[panelIdx]) this.appendFormField(this.grid.columns[i],tables[panelIdx]);
+ if (typeof fldSpec.pattern=='string') {
+ switch (fldSpec.pattern) {
+ case 'email':
+ fldSpec.regexp=/^[_a-zA-Z0-9-]+(\.[_a-zA-Z0-9-]+)*@[a-zA-Z0-9-]+(\.[a-zA-Z0-9-]+)*\.(([0-9]{1,3})|([a-zA-Z]{2,3})|(aero|coop|info|museum|name))$/;
+ break;
+ case 'float-unsigned':
+ fldSpec.regexp=/^\d+(\.\d+)?$/;
+ break;
+ case 'float-signed':
+ fldSpec.regexp=/^[-+]?\d+(\.\d+)?$/;
+ break;
+ case 'int-unsigned':
+ fldSpec.regexp=/^\d+$/;
+ break;
+ case 'int-signed':
+ fldSpec.regexp=/^[-+]?\d+$/;
+ break;
+ default:
+ fldSpec.regexp=new RegExp(fldSpec.pattern);
+ break;
+ }
+ }
+ }
+ },
+
+ createFormTable: function(div) {
+ var tab=document.createElement('table');
+ tab.border=0;
+ div.appendChild(tab);
+ return tab;
+ },
+
+ appendHiddenField: function(name,value) {
+ var field=Rico.createFormField(this.hiddenFields,'input','hidden',name,name);
+ field.value=value;
+ return field;
+ },
+
+ appendFormField: function(column, table) {
+ var fmt=column.format;
+ if (!fmt.EntryType) return;
+ if (fmt.EntryType=="H") return;
+ if (fmt.FormView) return;
+ Rico.log('appendFormField: '+column.displayName+' - '+fmt.EntryType);
+ var row = fmt.noFormBreak && table.rows.length > 0 ? table.rows[table.rows.length-1] : table.insertRow(-1);
+ var hdr = row.insertCell(-1);
+ column.formLabel=hdr;
+ if (hdr.noWrap) hdr.noWrap=true;
+ var entry = row.insertCell(-1);
+ if (entry.noWrap) entry.noWrap=true;
+ hdr.id='lbl_'+fmt.FieldName;
+ var field, name=fmt.FieldName;
+ switch (fmt.EntryType) {
+ case 'TA':
+ case 'tinyMCE':
+ field=Rico.createFormField(entry,'textarea',null,name);
+ field.cols=fmt.TxtAreaCols;
+ field.rows=fmt.TxtAreaRows;
+ field.innerHTML=fmt.ColData;
+ hdr.style.verticalAlign='top';
+ break;
+ case 'R':
+ case 'RL':
+ field=Rico.createFormField(entry,'div',null,name);
+ if (fmt.DescriptionField) field.RicoUpdate=fmt.DescriptionField;
+ if (fmt.MultiSelect) Rico.addClass(field, 'MultiSelect');
+ if (fmt.isNullable && !fmt.MultiSelect) this.addSelectNone(field);
+ this.selectValuesRequest(field,column);
+ break;
+ case 'N':
+ field=Rico.createFormField(entry,'select',null,name);
+ if (fmt.isNullable) this.addSelectNone(field);
+ Rico.eventBind(field,"change", Rico.eventHandle(this,'checkSelectNew'));
+ this.selectValuesRequest(field,column);
+ field=document.createElement('span');
+ field.className='ricoEditLabel';
+ field.id='labelnew__'+fmt.FieldName;
+ field.innerHTML=' '+Rico.getPhraseById('formNewValue').replace(' ',' ');
+ entry.appendChild(field);
+ name='textnew__'+fmt.FieldName;
+ field=Rico.createFormField(entry,'input','text',name,name);
+ break;
+ case 'S':
+ case 'SL':
+ if (fmt.ReadOnly) {
+ field=Rico.createFormField(entry,'input','text',name,name);
+ this.initField(field,fmt);
+ } else {
+ field=Rico.createFormField(entry,'select',null,name);
+ if (fmt.MultiSelect) field.multiple=true;
+ if (fmt.SelectRows) field.size=parseInt(fmt.SelectRows,10);
+ if (fmt.isNullable && !fmt.MultiSelect) this.addSelectNone(field);
+ if (fmt.DescriptionField) {
+ field.RicoUpdate=fmt.DescriptionField;
+ Rico.eventBind(field,"change", Rico.eventHandle(this,'selectClick'), false);
+ }
+ this.selectValuesRequest(field,column);
+ }
+ break;
+ case 'D':
+ if (!fmt.isNullable) fmt.required=true;
+ if (!fmt.dateFmt) fmt.dateFmt=Rico.dateFmt;
+ if (!fmt.Help) fmt.Help=fmt.dateFmt;
+ if (typeof fmt.min=='string') fmt.min=Rico.setISO8601(fmt.min) || new Date(fmt.min);
+ if (typeof fmt.max=='string') fmt.max=Rico.setISO8601(fmt.max) || new Date(fmt.max);
+ fmt.Length=Math.max(fmt.dateFmt.length,10);
+ if (Rico.inputtypes.date) {
+ // use the WebForms calendar
+ field=Rico.createFormField(entry,'input','date',name,name);
+ field.required=fmt.required;
+ if (fmt.min) field.min=Rico.toISO8601String(fmt.min,3);
+ if (fmt.max) field.max=Rico.toISO8601String(fmt.max,3);
+ field.required=fmt.required;
+ fmt.SelectCtl=null; // no need for Rico calendar control
+ } else {
+ field=Rico.createFormField(entry,'input','text',name,name);
+ }
+ this.initField(field,fmt);
+ break;
+ case 'I':
+ if (!fmt.isNullable) fmt.required=true;
+ if (!fmt.pattern) fmt.pattern='int-signed';
+ if (Rico.inputtypes.number) {
+ field=Rico.createFormField(entry,'input','number',name,name);
+ field.required=fmt.required;
+ field.min=fmt.min;
+ field.max=fmt.max;
+ field.step=1;
+ } else {
+ field=Rico.createFormField(entry,'input','text',name,name);
+ }
+ if (typeof fmt.min=='string') fmt.min=parseInt(fmt.min,10);
+ if (typeof fmt.max=='string') fmt.max=parseInt(fmt.max,10);
+ this.initField(field,fmt);
+ break;
+ case 'F':
+ if (!fmt.isNullable) fmt.required=true;
+ if (!fmt.pattern) fmt.pattern='float-signed';
+ field=Rico.createFormField(entry,'input','text',name,name);
+ this.initField(field,fmt);
+ if (typeof fmt.min=='string') fmt.min=parseFloat(fmt.min);
+ if (typeof fmt.max=='string') fmt.max=parseFloat(fmt.max);
+ break;
+ default:
+ field=Rico.createFormField(entry,'input','text',name,name);
+ if (!fmt.isNullable && fmt.EntryType!='T') fmt.required=true;
+ this.initField(field,fmt);
+ break;
+ }
+ if (field && fmt.SelectCtl) {
+ Rico.EditControls.applyTo(column,field,fmt.EntryType=='D');
+ }
+ var hdrSuffix='';
+ hdr.className='ricoEditLabel';
+ if (fmt.Help) {
+ hdr.title=fmt.Help;
+ hdrSuffix=" <span class='rico-icon rico-info'></span>";
+ }
+ var hdrText=fmt.EntryType.length>1 && fmt.EntryType.charAt(1)=='L' ? column.next.displayName : column.displayName;
+ hdr.innerHTML=hdrText+hdrSuffix;
+ },
+
+ addSelectNone: function(field) {
+ this.addSelectOption(field,this.options.TableSelectNone,Rico.getPhraseById("selectNone"));
+ },
+
+ initField: function(field,fmt) {
+ if (fmt.Length) {
+ field.maxLength=fmt.Length;
+ field.size=Math.min(fmt.Length, this.options.maxDisplayLen);
+ }
+ field.value=fmt.ColData;
+ },
+
+ selectClick: function(e) {
+ var SelObj=Rico.eventElement(e);
+ if (SelObj.readOnly) {
+ Rico.eventStop(e);
+ return false;
+ }
+ if (SelObj.RicoUpdate) {
+ var opt=SelObj.options[SelObj.selectedIndex];
+ Rico.$(SelObj.RicoUpdate).value=opt.innerHTML;
+ }
+ },
+
+ radioClick: function(e) {
+ var ChkBoxObj=Rico.eventElement(e);
+ if (ChkBoxObj.readOnly) {
+ Rico.eventStop(e);
+ return false;
+ }
+ var container=Rico.getParentByTagName(ChkBoxObj,'div');
+ if (container.RicoUpdate) {
+ Rico.$(container.RicoUpdate).value=ChkBoxObj.nextSibling.innerHTML;
+ }
+ },
+
+ checkSelectNew: function(e) {
+ this.updateSelectNew(Rico.eventElement(e));
+ },
+
+ updateSelectNew: function(SelObj) {
+ var vis=(SelObj.value==this.options.TableSelectNew) ? "" : "hidden";
+ Rico.$("labelnew__" + SelObj.id).style.visibility=vis;
+ Rico.$("textnew__" + SelObj.id).style.visibility=vis;
+ },
+
+ selectValuesRequest: function(elem,column) {
+ var fldSpec=column.format;
+ if (fldSpec.SelectValues) {
+ var valueList=fldSpec.SelectValues.split(',');
+ for (var i=0; i<valueList.length; i++)
+ this.addSelectOption(elem,valueList[i],valueList[i],i);
+ } else {
+ this.requestCount++;
+ var options={}, self=this;
+ Rico.extend(options, this.grid.buffer.ajaxOptions);
+ options.parameters = this.grid.buffer.formQueryHashXML(0,-1);
+ options.parameters.edit = column.index;
+ options.onComplete = function(request) { self.selectValuesUpdate(elem,request); };
+ new Rico.ajaxRequest(this.grid.buffer.dataSource, options);
+ Rico.log("selectValuesRequest: "+fldSpec.FieldName);
+ }
+ },
+
+ selectValuesUpdate: function(elem,request) {
+ var response = request.responseXML.getElementsByTagName("ajax-response");
+ Rico.log("selectValuesUpdate: "+request.status);
+ if (response == null || response.length != 1) return;
+ response=response[0];
+ var error = response.getElementsByTagName('error');
+ if (error.length > 0) {
+ var errmsg=Rico.getContentAsString(error[0],this.grid.buffer.isEncoded);
+ Rico.log("Data provider returned an error:\n"+errmsg);
+ alert(Rico.getPhraseById("requestError",errmsg));
+ return;
+ }
+ response=response.getElementsByTagName('response')[0];
+ var rowsElement = response.getElementsByTagName('rows')[0];
+ var rows = this.grid.buffer.dom2jstable(rowsElement);
+ Rico.log("selectValuesUpdate: id="+elem.id+' rows='+rows.length);
+ for (var i=0; i<rows.length; i++) {
+ if (rows[i].length>0) {
+ var c0=rows[i][0];
+ var c1=(rows[i].length>1) ? rows[i][1] : c0;
+ this.addSelectOption(elem,c0,c1,i);
+ }
+ }
+ if (Rico.$('textnew__'+elem.id))
+ this.addSelectOption(elem,this.options.TableSelectNew,Rico.getPhraseById("selectNewVal"));
+ if (this.panelGroup)
+ Rico.runLater(50,this,'initPanelGroup');
+ },
+
+ addSelectOption: function(elem,value,text,idx) {
+ switch (elem.tagName.toLowerCase()) {
+ case 'div':
+ var opt=Rico.createFormField(elem,'input', Rico.hasClass(elem, 'MultiSelect') ? 'checkbox' : 'radio', elem.id+'_'+idx, elem.id);
+ opt.value=value;
+ var lbl=document.createElement('label');
+ lbl.innerHTML=text;
+ lbl.htmlFor=opt.id;
+ elem.appendChild(lbl);
+ Rico.eventBind(opt,"click", Rico.eventHandle(this,'radioClick'), false);
+ break;
+ case 'select':
+ Rico.addSelectOption(elem,value,text);
+ break;
+ }
+ },
+
+ clearSaveMsg: function() {
+ if (this.saveMsg) this.saveMsg.innerHTML="";
+ },
+
+ addMenuItem: function(menuText,menuAction,enabled) {
+ this.extraMenuItems.push({menuText:menuText,menuAction:menuAction,enabled:enabled});
+ },
+
+ editMenu: function(grid,r,c,onBlankRow) {
+ this.clearSaveMsg();
+ if (this.grid.buffer.sessionExpired==true || this.grid.buffer.startPos<0) return false;
+ this.rowIdx=r;
+ var elemTitle=Rico.$('pageTitle');
+ var pageTitle=elemTitle ? elemTitle.innerHTML : document.title;
+ this.menu.addMenuHeading(pageTitle);
+ var self=this;
+ if (onBlankRow==false) {
+ for (var i=0; i<this.extraMenuItems.length; i++) {
+ this.menu.addMenuItem(this.extraMenuItems[i].menuText,this.extraMenuItems[i].menuAction,this.extraMenuItems[i].enabled);
+ }
+ this.menu.addMenuItem(this.editText, function() { self.editRecord(); },this.canEdit(r));
+ this.menu.addMenuItem(this.delText, function() { self.deleteRecord(); },this.canDelete(r));
+ if (this.options.canClone) {
+ this.menu.addMenuItem(this.cloneText, function() { self.cloneRecord(); },this.canAdd(r) && this.canEdit(r));
+ }
+ }
+ this.menu.addMenuItem(this.addText, function() { self.addRecord(); },this.canAdd(r));
+ return true;
+ },
+
+ canAdd: function(r) {
+ return (typeof this.options.canAdd=='function') ? this.options.canAdd(r) : this.options.canAdd;
+ },
+
+ canEdit: function(r) {
+ return (typeof this.options.canEdit=='function') ? this.options.canEdit(r) : this.options.canEdit;
+ },
+
+ canDelete: function(r) {
+ return (typeof this.options.canDelete=='function') ? this.options.canDelete(r) : this.options.canDelete;
+ },
+
+ cancelEdit: function(e) {
+ Rico.eventStop(e);
+ this.makeFormInvisible();
+ this.grid.highlightEnabled=true;
+ this.menu.cancelmenu();
+ return false;
+ },
+
+ setField: function(fldnum,fldvalue) {
+ var fldSpec=this.grid.columns[fldnum].format;
+ var e=Rico.$(fldSpec.FieldName);
+ var a,i,o,elems,opts,txt;
+ if (!e) return;
+ Rico.log('setField: '+fldSpec.FieldName+'='+fldvalue);
+ switch (e.tagName.toUpperCase()) {
+ case 'DIV':
+ elems=e.getElementsByTagName('INPUT');
+ o={}
+ if (fldSpec.MultiSelect && fldvalue) {
+ a=fldvalue.split(',');
+ for (var i=0; i<a.length; i++) o[a[i]]=1;
+ } else {
+ o[fldvalue]=1;
+ }
+ for (i=0; i<elems.length; i++)
+ elems[i].checked=o[elems[i].value]==1;
+ break;
+ case 'INPUT':
+ if (fldSpec.EntryType=='D') {
+ // remove time data if it exists
+ a=fldvalue.split(/\s|T/);
+ fldvalue=a[0];
+ if (this.isTextInput(e)) {
+ var d=fldvalue.toLowerCase() == 'today' ? new Date() : Rico.setISO8601(fldvalue);
+ if (d) fldvalue=Rico.formatDate(d,fldSpec.dateFmt);
+ }
+ }
+ e.value=fldvalue;
+ break;
+ case 'SELECT':
+ opts=e.options;
+ //alert('setField SELECT: id='+e.id+'\nvalue='+fldvalue+'\nopt cnt='+opts.length)
+ o={}
+ if (fldSpec.MultiSelect && fldvalue) {
+ a=fldvalue.split(',');
+ for (var i=0; i<a.length; i++) o[a[i]]=1;
+ for (i=0; i<opts.length; i++)
+ opts[i].selected=o[opts[i].value]==1;
+ } else {
+ for (i=0; i<opts.length; i++) {
+ if (opts[i].value==fldvalue) {
+ e.selectedIndex=i;
+ break;
+ }
+ }
+ }
+ if (fldSpec.EntryType=='N') {
+ txt=Rico.$('textnew__'+e.id);
+ if (!txt) alert('Warning: unable to find id "textnew__'+e.id+'"');
+ txt.value=fldvalue;
+ if (e.selectedIndex!=i) e.selectedIndex=opts.length-1;
+ this.updateSelectNew(e);
+ }
+ return;
+ case 'TEXTAREA':
+ e.value=fldvalue;
+ if (fldSpec.EntryType=='tinyMCE' && typeof(tinyMCE)!='undefined' && this.initialized) {
+ if (tinyMCE.updateContent) {
+ tinyMCE.updateContent(e.id); // version 2.x
+ } else {
+ tinyMCE.execInstanceCommand(e.id, 'mceSetContent', false, fldvalue); // version 3.x
+ }
+ }
+ return;
+ }
+ },
+
+ setReadOnly: function(action) {
+ for (var ro,i=0; i<this.grid.columns.length; i++) {
+ var fldSpec=this.grid.columns[i].format;
+ if (!fldSpec) continue;
+ var e=Rico.$(fldSpec.FieldName);
+ if (!e) continue;
+ switch (action) {
+ case 'ins': ro=!fldSpec.Writeable || fldSpec.ReadOnly || fldSpec.UpdateOnly; break;
+ case 'upd': ro=!fldSpec.Writeable || fldSpec.ReadOnly || fldSpec.InsertOnly; break;
+ default: ro=false; break;
+ }
+ switch (e.tagName.toUpperCase()) {
+ case 'DIV':
+ var elems=e.getElementsByTagName('INPUT');
+ for (var j=0; j<elems.length; j++) {
+ elems[j].disabled=ro;
+ }
+ break;
+ case 'SELECT':
+ if (fldSpec.EntryType=='N') {
+ var txt=Rico.$('textnew__'+e.id);
+ txt.disabled=ro;
+ }
+ e.disabled=ro;
+ break;
+ case 'TEXTAREA':
+ case 'INPUT':
+ e.disabled=ro;
+ if (fldSpec.selectIcon) fldSpec.selectIcon.style.display=ro ? 'none' : '';
+ break;
+ }
+ }
+ },
+
+ hideResponse: function(msg) {
+ this.responseDiv.innerHTML=msg;
+ this.responseDialog.style.display='none';
+ },
+
+ showResponse: function() {
+ var offset=Rico.cumulativeOffset(this.grid.outerDiv);
+ offset.top+=Rico.docScrollTop();
+ this.responseDialog.style.top=offset.top+"px";
+ this.responseDialog.style.left=offset.left+"px";
+ this.responseDialog.style.display='';
+ },
+
+ processResponse: function(xhr) {
+ var responseText,success=true;
+ Rico.log('Processing response from form submittal: '+typeof(xhr));
+ this.responseDiv.innerHTML=xhr.responseText;
+ var respNodes=Rico.select('.ricoFormResponse',this.responseDiv);
+ if (respNodes) {
+ // generate a translated response
+ Rico.log('Found ricoFormResponse');
+ var phraseId=Rico.trim(respNodes[0].className).split(/\s+/)[1];
+ responseText=Rico.getPhraseById(phraseId,this.options.RecordName);
+ } else {
+ // present the response as sent from the server (untranslated)
+ Rico.log('Processing response text');
+ var ch=this.responseDiv.childNodes;
+ for (var i=ch.length-1; i>=0; i--) {
+ if (ch[i].nodeType==1 && ch[i].nodeName!='P' && ch[i].nodeName!='DIV' && ch[i].nodeName!='BR')
+ this.responseDiv.removeChild(ch[i]);
+ }
+ responseText=Rico.stripTags(this.responseDiv.innerHTML);
+ success=(responseText.toLowerCase().indexOf('error')==-1);
+ }
+ if (success && this.options.showSaveMsg!='full') {
+ this.hideResponse('');
+ this.grid.resetContents();
+ this.grid.buffer.foundRowCount = false;
+ this.grid.buffer.fetch(this.grid.lastRowPos || 0);
+ if (this.saveMsg) this.saveMsg.innerHTML=' '+responseText+' ';
+ }
+ this.processCallback(this.options.onSubmitResponse);
+ Rico.log('Processing response completed');
+ },
+
+ processCallback: function(callback) {
+ switch (typeof callback) {
+ case 'string': return eval(callback);
+ case 'function': return callback();
+ }
+ },
+
+ // called when ok pressed on error response message
+ ackResponse: function(e) {
+ this.hideResponse('');
+ this.grid.highlightEnabled=true;
+ },
+
+ cloneRecord: function() {
+ this.formPopup.setTitle(this.cloneText);
+ this.displayEditForm("ins");
+ },
+
+ editRecord: function() {
+ this.formPopup.setTitle(this.editText);
+ this.displayEditForm("upd");
+ },
+
+ displayEditForm: function(action) {
+ this.grid.highlightEnabled=false;
+ this.menu.cancelmenu();
+ this.hideResponse(Rico.getPhraseById('saving'));
+ this.grid.outerDiv.style.cursor = 'auto';
+ this.action.value=action;
+ for (var i=0; i<this.grid.columns.length; i++) {
+ var c=this.grid.columns[i];
+ if (c.format) {
+ var v=c.getValue(this.rowIdx);
+ this.setField(i,v);
+ if (c.format.selectDesc) {
+ if (c.format.EntryType.length>1 && c.format.EntryType.charAt(1)=='L')
+ v=this.grid.columns[i+1].getValue(this.rowIdx);
+ v=c._format(v);
+ if (v==='') v=' ';
+ c.format.selectDesc.innerHTML=v;
+ }
+ if (c.format.SelectCtl)
+ Rico.EditControls.displayClrImg(c, !c.format.InsertOnly);
+ }
+ }
+ this.setReadOnly(action);
+ for (var k=0; k<this.keys.length; k++) {
+ this.keys[k].keyField.value = this.grid.buffer.getWindowValue(this.rowIdx,this.keys[k].colidx);
+ }
+ this.makeFormVisible(this.rowIdx);
+ },
+
+ addPrepare: function() {
+ this.hideResponse(Rico.getPhraseById('saving'));
+ this.form.reset();
+ this.setReadOnly("ins");
+ this.action.value="ins";
+ for (var i=0; i<this.grid.columns.length; i++) {
+ var c=this.grid.columns[i];
+ if (c.format) {
+ this.setField(i,c.format.ColData);
+ if (c.format.SelectCtl) {
+ if (c.format.EntryType != 'D') Rico.EditControls.resetValue(c);
+ Rico.EditControls.displayClrImg(c, !c.format.UpdateOnly);
+ }
+ }
+ }
+ },
+
+ addRecord: function() {
+ this.menu.cancelmenu();
+ this.formPopup.setTitle(this.addText);
+ this.addPrepare();
+ this.makeFormVisible(-1);
+ if (this.formPanels) this.formPanels.select(0);
+ },
+
+ drillDown: function(e,masterColNum,detailColNum) {
+ return this.grid.drillDown.apply(this.grid, arguments);
+ },
+
+ // set filter on a detail grid that is in a master-detail relationship
+ setDetailFilter: function(colNumber,filterValue) {
+ this.grid.setDetailFilter(colNumber,filterValue);
+ },
+
+ makeFormVisible: function(row) {
+ this.formPopup.container.style.display='block';
+
+ // set left position
+ var editWi=this.formPopup.container.offsetWidth;
+ var odOffset=Rico.cumulativeOffset(this.grid.outerDiv);
+ var winWi=Rico.windowWidth();
+ this.formPopup.container.style.left=editWi+odOffset.left > winWi ? (winWi-editWi)+'px' : (odOffset.left+1)+'px';
+
+ // set top position
+ var scrTop=Rico.docScrollTop();
+ var editHt=this.formPopup.container.offsetHeight;
+ var newTop=odOffset.top+this.grid.hdrHt+scrTop;
+ var bottom=Rico.windowHeight()+scrTop;
+ if (row >= 0) {
+ newTop+=(row+1)*this.grid.rowHeight;
+ if (newTop+editHt>bottom) newTop-=(editHt+this.grid.rowHeight);
+ } else {
+ if (newTop+editHt>bottom) newTop=bottom-editHt-2;
+ }
+
+ if (this.processCallback(this.options.formOpen) === false) return;
+ this.formPopup.openPopup(null,Math.max(newTop,scrTop));
+ this.formPopup.container.style.visibility='visible';
+ Rico.EditControls.setZ(Rico.getStyle(this.formPopup.container,'zIndex'));
+ if (this.initialized) return;
+
+ var i, spec;
+ for (i = 0; i < this.grid.columns.length; i++) {
+ spec=this.grid.columns[i].format;
+ if (!spec || !spec.EntryType || !spec.FieldName) continue;
+ switch (spec.EntryType) {
+ case 'tinyMCE':
+ if (typeof tinyMCE!='undefined') tinyMCE.execCommand('mceAddControl', true, spec.FieldName);
+ break;
+ }
+ }
+ this.initialized=true;
+ },
+
+ makeFormInvisible: function() {
+ for (var i=0; i<this.grid.columns.length; i++) {
+ if (this.grid.columns[i].format && this.grid.columns[i].format.SelectCtl)
+ Rico.EditControls.close(this.grid.columns[i].format.SelectCtl);
+ }
+ this.formPopup.container.style.visibility='hidden';
+ this.formPopup.closePopup();
+ this.processCallback(this.options.formClose);
+ },
+
+ getConfirmDesc: function(rowIdx) {
+ return Rico.stripTags(this.grid.cell(rowIdx,this.options.ConfirmDeleteCol).innerHTML).replace(' ',' '); //.unescapeHTML();
+ },
+
+ deleteRecord: function() {
+ this.menu.cancelmenu();
+ var desc;
+ switch(this.options.ConfirmDeleteCol){
+ case -1 :
+ desc=Rico.getPhraseById("thisRecord",this.options.RecordName);
+ break;
+ case -2 : // Use key/column header to identify the row
+ desc='';
+ for (var k=0; k<this.keys.length; k++) {
+ var i=this.keys[k].colidx;
+ var fmt=this.grid.columns[i].format;
+ if (fmt.EntryType.length>1 && fmt.EntryType.charAt(1)=='L') i++;
+ var value=Rico.trim(Rico.stripTags(this.grid.cell(this.rowIdx,i).innerHTML).replace(/ /g,' '));
+ if (desc) desc+=', ';
+ desc+=this.grid.columns[i].displayName + ' \"' + value + '\"';
+ }
+ break;
+ default :
+ desc='\"' + Rico.truncate(this.getConfirmDesc(this.rowIdx),50) + '\"';
+ break;
+ }
+ if (!this.options.ConfirmDelete.valueOf || confirm(Rico.getPhraseById("confirmDelete",desc))) {
+ this.hideResponse(Rico.getPhraseById('deleting'));
+ this.showResponse();
+ var parms={};
+ parms[this.grid.actionId]="del";
+ for (var k=0; k<this.keys.length; k++) {
+ var i=this.keys[k].colidx;
+ var value=this.grid.columns[i].getValue(this.rowIdx);
+ parms['_k'+i]=value; // prototype does the encoding automatically
+ //parms['_k'+i]=encodeURIComponent(value);
+ }
+ new Rico.ajaxRequest(this.options.updateURL, {parameters:parms,method:'post',onComplete:this.responseHandler});
+ }
+ this.menu.cancelmenu();
+ },
+
+ validationMsg: function(elem,colnum,phraseId) {
+ var col=this.grid.columns[colnum];
+ if (this.formPanels) this.formPanels.select(this.panelActualIdx[col.format.ColGroupIdx]);
+ var label=Rico.stripTags(col.formLabel.innerHTML).replace(/ /g,' ');
+ var msg=Rico.getPhraseById(phraseId," \"" + label + "\"");
+ Rico.log(' Validation error: '+msg);
+ if (col.format.Help) msg+="\n\n"+col.format.Help;
+ alert(msg);
+ setTimeout(function() { try { elem.focus(); elem.select(); } catch(e) {}; }, 10);
+ return false;
+ },
+
+ isTextInput: function(elem) {
+ if (!elem) return false;
+ if (elem.tagName.toLowerCase()!='input') return false;
+ if (elem.type.toLowerCase()!='text') return false;
+ if (elem.readOnly) return false;
+ if (!Rico.visible(elem)) return false;
+ return true;
+ },
+
+ parseDate: function(v, dateFmt) {
+ dateParts={};
+ if (!this.dateRegExp.exec(dateFmt)) return NaN;
+ dateParts[RegExp.$1]=0;
+ dateParts[RegExp.$3]=1;
+ dateParts[RegExp.$5]=2;
+ var aDate = v.split(/\D/);
+ var d=new Date();
+ var curyr=d.getFullYear();
+ if (aDate.length==2 && dateParts.yyyy==2) aDate.push(curyr);
+ if (aDate.length!=3) return NaN;
+ var dd=parseInt(aDate[dateParts.dd], 10);
+ if (dd==0 || dd>31) return NaN;
+ var mm=parseInt(aDate[dateParts.mm], 10) - 1;
+ if (mm > 11) return NaN;
+ var yy=parseInt(aDate[dateParts.yyyy], 10);
+ if (yy < 100) {
+ // apply a century to 2-digit years
+ yy+=curyr - (curyr % 100);
+ }
+ return new Date(yy,mm,dd,0,0,0); // ensure time is midnight
+ },
+
+ TESubmit: function(e) {
+ var i,ro,lbl,spec,elem,n,dateValues=[];
+
+ Rico.eventStop(e);
+ Rico.log('Event: TESubmit called to validate input');
+
+ // check fields that are supposed to be non-blank
+
+ for (i = 0; i < this.grid.columns.length; i++) {
+ spec=this.grid.columns[i].format;
+ if (!spec || !spec.EntryType || !spec.FieldName) continue;
+ elem=Rico.$(spec.FieldName);
+ if (!this.isTextInput(elem)) continue;
+ switch (this.action.value) {
+ case 'ins': ro=!spec.Writeable || spec.ReadOnly || spec.UpdateOnly; break;
+ case 'upd': ro=!spec.Writeable || spec.ReadOnly || spec.InsertOnly; break;
+ default: ro=false; break;
+ }
+ if (ro) continue; // readonly, so don't validate
+ Rico.log(' Validating field #'+i+' EntryType='+spec.EntryType+' ('+spec.FieldName+')');
+
+ // check for blanks
+ if (elem.value.length == 0) {
+ if (spec.required)
+ return this.validationMsg(elem,i,"formPleaseEnter");
+ else
+ continue;
+ }
+
+ // check pattern
+ if (elem.value.length > 0 && spec.regexp && !spec.regexp.test(elem.value))
+ return this.validationMsg(elem,i,"formInvalidFmt");
+
+ // check min/max and date values
+ switch (spec.EntryType.charAt(0)) {
+ case 'I': n=parseInt(elem.value,10); break;
+ case 'F': n=parseFloat(elem.value); break;
+ case 'D':
+ n=this.parseDate(elem.value,spec.dateFmt);
+ if (isNaN(n)) return this.validationMsg(elem,i,"formInvalidFmt");
+ dateValues.push({e:elem,v:n});
+ break;
+ default: n=NaN; break;
+ }
+ if (typeof spec.min!='undefined' && !isNaN(n) && n < spec.min)
+ return this.validationMsg(elem,i,"formOutOfRange");
+ if (typeof spec.max!='undefined' && !isNaN(n) && n > spec.max)
+ return this.validationMsg(elem,i,"formOutOfRange");
+ }
+ if (this.processCallback(this.options.formSubmit) === false) return false;
+
+ // update drop-down for any columns with entry type of N
+
+ for (i = 0; i < this.grid.columns.length; i++) {
+ spec=this.grid.columns[i].format;
+ if (!spec || !spec.EntryType || !spec.FieldName) continue;
+ if (spec.EntryType.charAt(0) != 'N') continue;
+ var SelObj=Rico.$(spec.FieldName);
+ if (!SelObj || SelObj.value!=this.options.TableSelectNew) continue;
+ var newtext=Rico.$("textnew__" + SelObj.id).value;
+ this.addSelectOption(SelObj,newtext,newtext);
+ }
+
+ // set date values to ISO format
+ for (i = 0; i < dateValues.length; i++) {
+ dateValues[i].e.value = Rico.formatDate(dateValues[i].v,'yyyy-mm-dd');
+ }
+
+ if (typeof tinyMCE!='undefined') tinyMCE.triggerSave();
+ this.makeFormInvisible();
+ this.sendForm();
+ this.menu.cancelmenu();
+ return false;
+ },
+
+ sendForm: function() {
+ this.setReadOnly("reset"); // reset disabled flag so that all fields are sent to server
+ this.showResponse();
+ Rico.log("sendForm: "+this.grid.tableId);
+ Rico.ajaxSubmit(this.form, this.options.updateURL, {method:'post',onComplete:this.responseHandler});
+ }
+};
+
+
+/**
+ * @namespace Registers custom popup widgets to fill in a text box (e.g. ricoCalendar and ricoTree)
+ * <pre>
+ * Custom widget must implement:
+ * open() method (make control visible)
+ * close() method (hide control)
+ * container property (div element that contains the control)
+ * id property (uniquely identifies the widget class)
+ *
+ * widget calls returnValue method to return a value to the caller
+ *
+ * this object handles clicks on the control's icon and positions the control appropriately.
+ * </pre>
+ */
+Rico.EditControls = {
+ widgetList : {},
+ elemList : {},
+ zIndex : 0,
+
+ register: function(widget, imgsrc) {
+ this.widgetList[widget.id] = {imgsrc:imgsrc, widget:widget, currentEl:''};
+ var self=this;
+ widget.returnValue=function(newVal,newDesc) { self.setValue(widget,newVal,newDesc); };
+ Rico.log("Rico.EditControls.register:"+widget.id);
+ },
+
+ setZ: function(z) {
+ this.zIndex=Math.max(this.zIndex,z+10);
+ },
+
+ applyTo: function(column,inputCtl,showInput) {
+ var wInfo=this.widgetList[column.format.SelectCtl];
+ if (!wInfo) return;
+ Rico.log('Rico.EditControls.applyTo: '+column.displayName+' : '+column.format.SelectCtl);
+ var newimg, descSpan = document.createElement('span');
+ if (wInfo.imgsrc.indexOf('.')==-1 && wInfo.imgsrc.indexOf('/')==-1) {
+ // treat imgsrc as a class name
+ newimg = document.createElement('span');
+ newimg.className=wInfo.imgsrc;
+ } else {
+ // treat imgsrc as an image uri
+ newimg = document.createElement('img');
+ newimg.src=wInfo.imgsrc;
+ }
+ newimg.style.verticalAlign='top';
+ newimg.style.marginLeft='4px';
+ newimg.style.cursor='pointer';
+ newimg.id=this.imgId(column.format.FieldName);
+ Rico.eventBind(newimg,"click", Rico.eventHandle(this,'processClick'));
+ inputCtl.parentNode.appendChild(descSpan);
+ inputCtl.parentNode.appendChild(newimg);
+ if (showInput) {
+ descSpan.style.display='none';
+ } else {
+ inputCtl.style.display='none'; // comment out this line for debugging
+ }
+ var clr;
+ if (column.format.isNullable) {
+ clr=Rico.clearButton(Rico.eventHandle(this,'processClear'));
+ clr.id=newimg.id+'_clear';
+ inputCtl.parentNode.appendChild(clr);
+ }
+ this.elemList[newimg.id] = {descSpan:descSpan, inputCtl:inputCtl, widget:wInfo.widget, listObj:wInfo, column:column, clrimg:clr};
+ column.format.selectIcon=newimg;
+ column.format.selectDesc=descSpan;
+ },
+
+ displayClrImg: function(column,bShow) {
+ var el=this.elemList[this.imgId(column.format.FieldName)];
+ //alert(column.format.FieldName+': '+bShow+' '+el.clrimg.id);
+ if (el && el.clrimg) el.clrimg.style.display=bShow ? 'inline-block' : 'none';
+ },
+
+ processClear: function(e) {
+ var elem=Rico.eventElement(e);
+ var el=this.elemList[elem.id.slice(0,-6)];
+ if (!el) return;
+ el.inputCtl.value='';
+ el.descSpan.innerHTML=el.column._format('');
+ },
+
+ processClick: function(e) {
+ var elem=Rico.eventElement(e);
+ var el=this.elemList[elem.id];
+ if (!el) return;
+ if (el.listObj.currentEl==elem.id && el.widget.container.style.display!='none') {
+ el.widget.close();
+ el.listObj.currentEl='';
+ } else {
+ el.listObj.currentEl=elem.id;
+ Rico.log('Rico.EditControls.processClick: '+el.widget.id+' : '+el.inputCtl.value);
+ el.widget.container.style.zIndex=this.zIndex;
+ el.widget.open(el.inputCtl.value,el.column); // this may change the size of the widget
+ Rico.positionCtlOverIcon(el.widget.container,elem);
+ }
+ },
+
+ imgId: function(fieldname) {
+ return 'icon_'+fieldname;
+ },
+
+ resetValue: function(column) {
+ var el=this.elemList[this.imgId(column.format.FieldName)];
+ if (!el) return;
+ el.inputCtl.value=column.format.ColData;
+ var v=column._format(column.format.ColData);
+ if (v==='') v=' ';
+ el.descSpan.innerHTML=v;
+ },
+
+ setValue: function(widget,newVal,newDesc) {
+ var wInfo=this.widgetList[widget.id];
+ if (!wInfo) return null;
+ var id=wInfo.currentEl;
+ if (!id) return null;
+ var el=this.elemList[id];
+ if (!el) return null;
+ el.inputCtl.value=newVal;
+ if (!newDesc) newDesc=el.column._format(newVal);
+ el.descSpan.innerHTML=newDesc;
+ if (el.column.format.DescriptionField)
+ Rico.$(el.column.format.DescriptionField).value = newDesc;
+ //alert(widget.id+':'+id+':'+el.inputCtl.id+':'+el.inputCtl.value+':'+newDesc);
+ },
+
+ close: function(id) {
+ var wInfo=this.widgetList[id];
+ if (!wInfo) return;
+ if (wInfo.widget.container.style.display!='none')
+ wInfo.widget.close();
+ }
+};
--- /dev/null
+/*
+ * (c) 2005-2011 Richard Cowin (http://openrico.org)
+ * (c) 2005-2011 Matt Brown (http://dowdybrown.com)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this
+ * file except in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the specific language governing permissions
+ * and limitations under the License.
+ */
+
+/**
+ * Standard menu for LiveGrid
+ */
+Rico.GridMenu = function(options) {
+ this.initialize(options);
+};
+
+Rico.GridMenu.prototype = {
+
+initialize: function(options) {
+ this.options = {
+ width : '18em',
+ dataMenuHandler : null // put custom items on the menu
+ };
+ Rico.extend(this.options, options || {});
+ Rico.extend(this, new Rico.Menu(this.options));
+ this.sortmenu = new Rico.Menu({ width: '15em' });
+ this.filtermenu = new Rico.Menu({ width: '22em' });
+ this.exportmenu = new Rico.Menu({ width: '24em' });
+ this.hideshowmenu = new Rico.Menu({ width: '22em' });
+ this.createDiv();
+ this.sortmenu.createDiv();
+ this.filtermenu.createDiv();
+ this.exportmenu.createDiv();
+ this.hideshowmenu.createDiv();
+},
+
+// Build context menu for grid
+buildGridMenu: function(r,c) {
+ this.clearMenu();
+ var livegrid=this.liveGrid;
+ var buffer=livegrid.buffer;
+ var totrows=buffer.totalRows;
+ var maxprint=livegrid.options.maxPrint;
+ var onBlankRow=(r >= totrows);
+ var column=livegrid.columns[c];
+ if (this.options.dataMenuHandler) {
+ var showDefaultMenu=this.options.dataMenuHandler(livegrid,r,c,onBlankRow);
+ if (!showDefaultMenu) return (this.itemCount > 0);
+ }
+
+ // menu items for sorting
+ if (column.sortable && totrows>0) {
+ this.sortmenu.clearMenu();
+ this.addSubMenuItem(Rico.getPhraseById("gridmenuSortBy",column.displayName), this.sortmenu, false);
+ this.sortmenu.addMenuItemId("gridmenuSortAsc", function() { column.sortAsc(); }, true);
+ this.sortmenu.addMenuItemId("gridmenuSortDesc", function() { column.sortDesc(); }, true);
+ }
+
+ // menu items for filtering
+ this.filtermenu.clearMenu();
+ if (column.canFilter()) {
+ this.addSubMenuItem(Rico.getPhraseById("gridmenuFilterBy",column.displayName), this.filtermenu, false);
+ if (!column.format.filterUI && (!onBlankRow || column.filterType == Rico.ColumnConst.USERFILTER)) {
+ column.userFilter=column.getValue(r);
+ if (column.filterType == Rico.ColumnConst.USERFILTER) {
+ this.filtermenu.addMenuItemId("gridmenuRemoveFilter", function() { column.setUnfiltered(false); }, true);
+ if (column.filterOp=='LIKE')
+ this.filtermenu.addMenuItemId("gridmenuChgKeyword", function() { livegrid.openKeyword(c); }, true);
+ if (column.filterOp=='NE' && !onBlankRow)
+ this.filtermenu.addMenuItemId("gridmenuExcludeAlso", function() { column.addFilterNE(); }, true);
+ } else if (!onBlankRow) {
+ this.filtermenu.addMenuItemId("gridmenuInclude", function() { column.setFilterEQ(); }, true);
+ this.filtermenu.addMenuItemId("gridmenuGreaterThan", function() { column.setFilterGE(); }, column.userFilter!='');
+ this.filtermenu.addMenuItemId("gridmenuLessThan", function() { column.setFilterLE(); }, column.userFilter!='');
+ if (column.isText)
+ this.filtermenu.addMenuItemId("gridmenuContains", function() { livegrid.openKeyword(c); }, true);
+ this.filtermenu.addMenuItemId("gridmenuExclude", function() { column.setFilterNE(); }, true);
+ }
+ }
+ if (livegrid.filterCount() > 0) {
+ this.filtermenu.addMenuItemId("gridmenuRemoveAll", function() { livegrid.clearFilters(); }, true);
+ }
+ if (buffer.options.canRefresh) this.filtermenu.addMenuItemId("gridmenuRefresh", function() { livegrid.filterHandler(); }, true);
+ }
+
+ // menu items for Print/Export
+ this.exportmenu.clearMenu();
+ if (maxprint > 0) {
+ this.addSubMenuItem(Rico.getPhraseById('gridmenuExport'),this.exportmenu,false);
+ if (buffer.printVisibleSQL && typeof(buffer.dataSource)=='string') {
+ // SQL buffer
+ this.exportmenu.addMenuItemId("gridmenuExportVis2Web", function() { buffer.printVisibleSQL('html'); });
+ this.exportmenu.addMenuItemId("gridmenuExportAll2Web", function() { buffer.printAllSQL('html'); }, buffer.totalRows <= maxprint);
+ this.exportmenu.addMenuBreak();
+ this.exportmenu.addMenuItemId("gridmenuExportVis2SS", function() { buffer.printVisibleSQL('xl'); });
+ this.exportmenu.addMenuItemId("gridmenuExportAll2SS", function() { buffer.printAllSQL('xl'); }, buffer.totalRows <= maxprint);
+ } else {
+ // any other buffer
+ this.exportmenu.addMenuItemId("gridmenuExportVis2Web", function() { buffer.printVisible(); });
+ this.exportmenu.addMenuItemId("gridmenuExportAll2Web", function() { buffer.printAll(); }, buffer.totalRows <= maxprint);
+ }
+ }
+
+ // menu items for hide/unhide
+ var hiddenCols=livegrid.listInvisible();
+ for (var showableCnt=0,x=0; x<hiddenCols.length; x++) {
+ if (hiddenCols[x].canHideShow()) showableCnt++;
+ }
+ if (showableCnt > 0 || column.canHideShow()) {
+ this.hideshowmenu.clearMenu();
+ this.addSubMenuItem(Rico.getPhraseById('gridmenuHideShow'),this.hideshowmenu,false);
+ this.hideshowmenu.addMenuItemId('gridmenuChooseCols', function() { livegrid.chooseColumns(); },true,false);
+ var visibleCnt=livegrid.columns.length-hiddenCols.length;
+ var enabled=(visibleCnt>1 && column.visible && column.canHideShow());
+ this.hideshowmenu.addMenuItem(Rico.getPhraseById('gridmenuHide',column.displayName), function() { column.hideColumn(); }, enabled);
+ if (hiddenCols.length > 1)
+ this.hideshowmenu.addMenuItemId('gridmenuShowAll', function() { livegrid.showAll(); });
+ }
+ return true;
+}
+
+}
--- /dev/null
+/*****************************************************************
+ ricoLocale_en.js - a component of Rico 3
+ English localization strings
+
+ This file is the basis for all translations
+
+ If you would like to include translations for another language,
+ please post them on http://sourceforge.net/projects/openrico/
+******************************************************************/
+Rico.langCode='en';
+
+// used in ricoLiveGrid.js
+
+Rico.addPhraseId('bookmarkExact',"Listing records $1 - $2 of $3");
+Rico.addPhraseId('bookmarkAbout',"Listing records $1 - $2 of more than $3");
+Rico.addPhraseId('bookmarkNoRec',"No records");
+Rico.addPhraseId('bookmarkNoMatch',"No matching records");
+Rico.addPhraseId('bookmarkLoading',"Loading...");
+Rico.addPhraseId('sorting',"Sorting...");
+Rico.addPhraseId('exportStatus',"Exporting row $1");
+Rico.addPhraseId('filterAll',"(all)");
+Rico.addPhraseId('filterBlank',"(blank)");
+Rico.addPhraseId('filterEmpty',"(empty)");
+Rico.addPhraseId('filterNotEmpty',"(not empty)");
+Rico.addPhraseId('filterLike',"contains: $1");
+Rico.addPhraseId('filterNot',"not: $1");
+Rico.addPhraseId('requestError',"The request for data returned an error:\n$1");
+Rico.addPhraseId('keywordPrompt',"Enter keyword to search for (use * as a wildcard):");
+Rico.addPhraseId('keywordTitle',"Keyword Search");
+Rico.addPhraseId('apply',"Apply");
+
+// used in ricoLiveGridMenu.js
+
+Rico.addPhraseId('gridmenuSortBy',"Sort by: $1");
+Rico.addPhraseId('gridmenuSortAsc',"Ascending");
+Rico.addPhraseId('gridmenuSortDesc',"Descending");
+Rico.addPhraseId('gridmenuFilterBy',"Filter by: $1");
+Rico.addPhraseId('gridmenuRefresh',"Refresh");
+Rico.addPhraseId('gridmenuChgKeyword',"Change keyword...");
+Rico.addPhraseId('gridmenuExcludeAlso',"Exclude this value also");
+Rico.addPhraseId('gridmenuInclude',"Include only this value");
+Rico.addPhraseId('gridmenuGreaterThan',"Greater than or equal to this value");
+Rico.addPhraseId('gridmenuLessThan',"Less than or equal to this value");
+Rico.addPhraseId('gridmenuContains',"Contains keyword...");
+Rico.addPhraseId('gridmenuExclude',"Exclude this value");
+Rico.addPhraseId('gridmenuRemoveFilter',"Remove filter");
+Rico.addPhraseId('gridmenuRemoveAll',"Remove all filters");
+
+Rico.addPhraseId('gridmenuExport',"Print/Export");
+Rico.addPhraseId('gridmenuExportVis2Web',"Visible rows to web page");
+Rico.addPhraseId('gridmenuExportAll2Web',"All rows to web page");
+Rico.addPhraseId('gridmenuExportVis2SS',"Visible rows to spreadsheet");
+Rico.addPhraseId('gridmenuExportAll2SS',"All rows to spreadsheet");
+
+Rico.addPhraseId('gridmenuHideShow',"Hide/Show");
+Rico.addPhraseId('gridmenuChooseCols',"Choose columns...");
+Rico.addPhraseId('gridmenuHide',"Hide: $1");
+Rico.addPhraseId('gridmenuShow',"Show: $1");
+Rico.addPhraseId('gridmenuShowAll',"Show All");
+
+// used in ricoLiveGridAjax.js
+
+Rico.addPhraseId('sessionExpireMinutes',"minutes before your session expires");
+Rico.addPhraseId('sessionExpired',"EXPIRED");
+Rico.addPhraseId('requestTimedOut',"Request for data timed out!");
+Rico.addPhraseId('waitForData',"Waiting for data...");
+Rico.addPhraseId('httpError',"Received HTTP error: $1");
+Rico.addPhraseId('invalidResponse',"Server returned an invalid response");
+
+// used in ricoLiveGridCommon.js
+
+Rico.addPhraseId('gridChooseCols',"Choose columns");
+Rico.addPhraseId('exportComplete',"Exporting complete");
+Rico.addPhraseId('exportInProgress',"Export in progress...");
+Rico.addPhraseId('disableBlocker',"You need to disable your browser's pop-up blocker before exporting.");
+Rico.addPhraseId('showFilterRow',"Show filter row"); // img alt text
+Rico.addPhraseId('hideFilterRow',"Hide filter row"); // img alt text
+
+// used in ricoLiveGridForms.js
+
+Rico.addPhraseId('ok',"OK");
+Rico.addPhraseId('selectNone',"(none)");
+Rico.addPhraseId('selectNewVal',"(new value)");
+Rico.addPhraseId('record',"record");
+Rico.addPhraseId('thisRecord',"this $1");
+Rico.addPhraseId('confirmDelete',"Are you sure you want to delete $1?");
+Rico.addPhraseId('deleting',"Deleting...");
+Rico.addPhraseId('formPleaseEnter',"Please enter a value for $1");
+Rico.addPhraseId('formInvalidFmt',"Invalid format for $1");
+Rico.addPhraseId('formOutOfRange',"Value is out of range for $1");
+Rico.addPhraseId('formNewValue',"new value:");
+Rico.addPhraseId('saving',"Saving...");
+Rico.addPhraseId('clear',"clear");
+Rico.addPhraseId('close',"Close");
+Rico.addPhraseId('saveRecord',"Save $1");
+Rico.addPhraseId('cancel',"Cancel");
+Rico.addPhraseId('editRecord',"Edit $1");
+Rico.addPhraseId('deleteRecord',"Delete this $1");
+Rico.addPhraseId('cloneRecord',"Clone $1");
+Rico.addPhraseId('addRecord',"Add new $1");
+Rico.addPhraseId('addedSuccessfully',"$1 added successfully");
+Rico.addPhraseId('deletedSuccessfully',"$1 deleted successfully");
+Rico.addPhraseId('updatedSuccessfully',"$1 updated successfully");
+
+// used in ricoTree.js
+
+Rico.addPhraseId('treeSave',"Save Selection");
+Rico.addPhraseId('treeClear',"Clear All");
+
+// used in ricoCalendar.js
+
+Rico.addPhraseId('calToday',"Today is $1 $2 $3"); // $1=day, $2=monthabbr, $3=year, $4=month number
+Rico.addPhraseId('calWeekHdg',"Wk");
+Rico.addPhraseId('calYearRange',"Year ($1-$2)");
+Rico.addPhraseId('calInvalidYear',"Invalid year");
+\r
+// Date & number formats\r
+\r
+Rico.thouSep=","\r
+Rico.decPoint="."\r
+Rico.dateFmt="mm/dd/yyyy"\r
+\r
+Rico.monthNames=['January','February','March','April','May','June','July','August','September','October','November','December']\r
+Rico.dayNames=['Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday']\r
--- /dev/null
+/*
+ * (c) 2005-2009 Richard Cowin (http://openrico.org)
+ * (c) 2005-2009 Matt Brown (http://dowdybrown.com)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this
+ * file except in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the specific language governing permissions
+ * and limitations under the License.
+ */
+
+Rico.applyShadow = function(elem,shadowFlag) {
+ if (typeof shadowFlag=='undefined') shadowFlag=true;
+ if (shadowFlag) Rico.addClass(elem,'ricoShadow');
+ return elem;
+};
+
+// ensure popups/windows get closed in the right order when the user hits escape key
+Rico._OpenPopupList = [];
+Rico._RemoveOpenPopup = function(popup) {
+ if (popup.openIndex >= 0 && popup.openIndex < Rico._OpenPopupList.length) Rico._OpenPopupList.splice(popup.openIndex,1);
+ popup.openIndex = -1;
+};
+Rico._AddOpenPopup = function(popup) {
+ popup.openIndex = Rico._OpenPopupList.push(popup) - 1;
+};
+Rico._checkEscKey = function(e) {
+ if (Rico.eventKey(e) != 27) return true;
+ while (Rico._OpenPopupList.length > 0) {
+ var popup = Rico._OpenPopupList.pop();
+ if (popup && popup.visible()) {
+ popup.openIndex = -1;
+ Rico.eventStop(e);
+ popup.closeFunc();
+ return false;
+ }
+ }
+ return true;
+};
+Rico.eventBind(document,"keyup", Rico.eventHandle(Rico,'_checkEscKey'));
+
+
+Rico.Popup = function(containerDiv,options) {
+ this.initialize(containerDiv,options);
+};
+
+Rico.Popup.prototype = {
+/**
+ * @class Class to manage pop-up div windows.
+ * @constructs
+ * @param options object may contain any of the following:<dl>
+ * <dt>hideOnClick </dt><dd> hide popup when mouse button is clicked? default=true</dd>
+ * <dt>ignoreClicks</dt><dd> if true, mouse clicks within the popup are not allowed to bubble up to parent elements</dd>
+ * <dt>position </dt><dd> defaults to absolute, use "auto" to auto-detect</dd>
+ * <dt>shadow </dt><dd> display shadow with popup? default=true</dd>
+ * <dt>zIndex </dt><dd> which layer? default=1</dd>
+ * <dt>canDrag </dt><dd> boolean value (or function that returns a boolean) indicating if it is ok to drag/reposition popup, default=false</dd>
+ * <dt>onClose </dt><dd> function to call when the popup is closed</dd>
+ *</dl>
+ * @param containerDiv if supplied, then setDiv() is called at the end of initialization
+ */
+ initialize: function(containerDiv,options) {
+ this.options = {
+ hideOnClick : false,
+ ignoreClicks : false,
+ position : 'absolute',
+ shadow : true,
+ zIndex : 2,
+ canDrag : false,
+ dragElement : false,
+ closeFunc : false
+ };
+ this.openIndex=-1;
+ if (containerDiv) this.setDiv(containerDiv,options);
+ },
+
+ createContainer: function(options) {
+ this.setDiv(document.createElement('div'), options);
+ if (options && options.parent) {
+ options.parent.appendChild(this.container);
+ } else {
+ document.getElementsByTagName("body")[0].appendChild(this.container);
+ }
+ },
+
+/**
+ * Apply popup behavior to a div that already exists in the DOM
+ * @param containerDiv div element (or element id) in the DOM. If null, then the div is created automatically.
+ */
+ setDiv: function(containerDiv,options) {
+ Rico.extend(this.options, options || {});
+ this.container=Rico.$(containerDiv);
+ if (this.options.position == 'auto') {
+ this.position=Rico.getStyle(this.container,'position').toLowerCase();
+ } else {
+ this.position=this.container.style.position=this.options.position;
+ }
+ this.content=document.createElement('div');
+ while (this.container.firstChild) {
+ this.content.appendChild(this.container.firstChild);
+ }
+ this.container.appendChild(this.content);
+ this.content.className='RicoPopupContent';
+ if (this.position != 'absolute') return;
+
+ if (this.options.closeFunc) {
+ this.closeFunc=this.options.closeFunc;
+ } else {
+ var self=this;
+ this.closeFunc=function() { self.closePopup(); };
+ }
+ this.container.style.top='0px';
+ this.container.style.left='0px';
+ this.container.style.display='none';
+ if (this.options.zIndex >= 0) this.container.style.zIndex=this.options.zIndex;
+
+ if (Rico.isIE && Rico.ieVersion < 7 && this.options.shim!==false) {
+ this.content.style.position='relative';
+ this.content.style.zIndex=2;
+ // create iframe shim
+ this.ifr = document.createElement('iframe');
+ this.ifr.className='RicoShim';
+ this.ifr.frameBorder=0;
+ this.ifr.src="javascript:'';";
+ this.container.appendChild(this.ifr);
+ }
+ Rico.applyShadow(this.container,this.options.shadow);
+
+ if (this.options.hideOnClick)
+ Rico.eventBind(document,"click", Rico.eventHandle(this,'_docClick'));
+ this.dragEnabled=false;
+ this.mousedownHandler = Rico.eventHandle(this,'_startDrag');
+ this.dragHandler = Rico.eventHandle(this,'_drag');
+ this.dropHandler = Rico.eventHandle(this,'_endDrag');
+ if (this.options.canDrag) this.enableDragging();
+ if (this.options.ignoreClicks || this.options.canDrag) this.ignoreClicks();
+ },
+
+ clearContent: function() {
+ this.content.innerHTML="";
+ },
+
+ setContent: function(content) {
+ this.content.innerHTML=content;
+ },
+
+ enableDragging: function() {
+ if (!this.dragEnabled && this.options.dragElement) {
+ Rico.eventBind(this.options.dragElement, "mousedown", this.mousedownHandler);
+ this.dragEnabled=true;
+ }
+ return this.dragEnabled;
+ },
+
+ disableDragging: function() {
+ if (!this.dragEnabled) return;
+ Rico.eventUnbind(this.options.dragElement, "mousedown", this.mousedownHandler);
+ this.dragEnabled=false;
+ },
+
+ setZ: function(zIndex) {
+ this.container.style.zIndex=zIndex;
+ },
+
+/** @private */
+ ignoreClicks: function() {
+ Rico.eventBind(this.container,"click", Rico.eventHandle(this,'_ignoreClick'));
+ },
+
+ _ignoreClick: function(e) {
+ if (e.stopPropagation)
+ e.stopPropagation();
+ else
+ e.cancelBubble = true;
+ return true;
+ },
+
+ _docClick: function(e) {
+ this.closeFunc();
+ return true;
+ },
+
+/**
+ * Move popup to specified position
+ */
+ move: function(left,top) {
+ if (typeof left=='number') this.container.style.left=left+'px';
+ if (typeof top=='number') this.container.style.top=top+'px';
+ },
+
+ _startDrag : function(event){
+ var elem=Rico.eventElement(event);
+ this.container.style.cursor='move';
+ this.lastMouse = Rico.eventClient(event);
+ Rico.eventBind(document, "mousemove", this.dragHandler);
+ Rico.eventBind(document, "mouseup", this.dropHandler);
+ Rico.eventStop(event);
+ },
+
+ _drag : function(event){
+ var newMouse = Rico.eventClient(event);
+ var newLeft = parseInt(this.container.style.left,10) + newMouse.x - this.lastMouse.x;
+ var newTop = parseInt(this.container.style.top,10) + newMouse.y - this.lastMouse.y;
+ this.move(newLeft, newTop);
+ this.lastMouse = newMouse;
+ Rico.eventStop(event);
+ },
+
+ _endDrag : function(){
+ this.container.style.cursor='';
+ Rico.eventUnbind(document, "mousemove", this.dragHandler);
+ Rico.eventUnbind(document, "mouseup", this.dropHandler);
+ },
+
+/**
+ * Display popup at specified position
+ */
+ openPopup: function(left,top) {
+ this.move(left,top);
+ this.container.style.display='';
+ if (this.container.id) Rico.log('openPopup '+this.container.id+' at '+left+','+top);
+ Rico._AddOpenPopup(this);
+ },
+
+ centerPopup: function() {
+ this.openPopup();
+ var msgWidth=this.container.offsetWidth;
+ var msgHeight=this.container.offsetHeight;
+ var divwi=this.container.parentNode.offsetWidth;
+ var divht=this.container.parentNode.offsetHeight;
+ this.move(parseInt(Math.max((divwi-msgWidth)/2,0),10), parseInt(Math.max((divht-msgHeight)/2,0),10));
+ },
+
+ visible: function() {
+ return Rico.visible(this.container);
+ },
+
+/**
+ * Hide popup
+ */
+ closePopup: function() {
+ Rico._RemoveOpenPopup(this);
+ if (!this.visible()) return;
+ if (this.container.id) Rico.log('closePopup '+this.container.id);
+ if (this.dragEnabled) this._endDrag();
+ this.container.style.display="none";
+ if (this.options.onClose) this.options.onClose();
+ }
+
+};
+
+Rico.closeButton = function(handle) {
+ var a = document.createElement('a');
+ a.className='RicoCloseAnchor';
+ if (Rico.theme.closeAnchor) Rico.addClass(a,Rico.theme.closeAnchor);
+ var span = a.appendChild(document.createElement('span'));
+ span.title=Rico.getPhraseById('close');
+ new Rico.HoverSet([a],{hoverClass: Rico.theme.hover || 'ricoCloseHover'});
+ Rico.addClass(span,Rico.theme.close || 'rico-icon RicoClose');
+ Rico.eventBind(a,"click", handle);
+ return a;
+};
+
+Rico.floatButton = function(buttonName, handle, title) {
+ var a=document.createElement("a");
+ a.className='RicoButtonAnchor'
+ Rico.addClass(a,Rico.theme.buttonAnchor || 'RicoButtonAnchorNative');
+ var span=a.appendChild(document.createElement("span"));
+ if (title) span.title=title;
+ span.className=Rico.theme[buttonName.toLowerCase()] || 'rico-icon Rico'+buttonName;
+ Rico.eventBind(a,"click", handle, false);
+ new Rico.HoverSet([a]);
+ return a
+}
+
+Rico.clearButton = function(handle) {
+ var span=document.createElement("span");
+ span.title=Rico.getPhraseById('clear');
+ span.className='ricoClear';
+ Rico.addClass(span, Rico.theme.clear || 'rico-icon ricoClearNative');
+ Rico.eventBind(span,"click", handle);
+ return span;
+}
+
+Rico.Window = function(title, options, contentParam) {
+ this.initialize(title, options, contentParam);
+};
+
+Rico.Window.prototype = {
+
+/**
+ * Create popup div with a title bar.
+ */
+ initialize: function(title, options, contentParam) {
+ options=options || {overflow:'auto'};
+ Rico.extend(this, new Rico.Popup());
+
+ this.titleDiv = document.createElement('div');
+ this.options.canDrag=true;
+ this.options.dragElement=this.titleDiv;
+ this.createContainer(options);
+ this.content.appendChild(this.titleDiv);
+ contentParam=Rico.$(contentParam);
+ if (contentParam) {
+ this.contentDiv=contentParam
+ contentParam.parentNode.insertBefore(this.container,contentParam);
+ } else {
+ this.contentDiv=document.createElement('div');
+ }
+ this.content.appendChild(this.contentDiv);
+
+ // create title area
+ this.titleDiv.className='ricoTitle';
+ if (Rico.theme.dialogTitle) Rico.addClass(this.titleDiv,Rico.theme.dialogTitle);
+ this.titleDiv.style.position='relative';
+ this.titleContent = document.createElement('span');
+ this.titleContent.className='ricoTitleSpan';
+ this.titleDiv.appendChild(this.titleContent);
+ this.titleDiv.appendChild(Rico.closeButton(Rico.eventHandle(this,'closeFunc')));
+ if (!title && contentParam) {
+ title=contentParam.title;
+ contentParam.title='';
+ }
+ this.setTitle(title || ' ');
+
+ // create content area
+ this.contentDiv.className='ricoContent';
+ if (Rico.theme.dialogContent) Rico.addClass(this.contentDiv,Rico.theme.dialogContent);
+ this.contentDiv.style.position='relative';
+ if (options.height) this.contentDiv.style.height=options.height;
+ if (options.width) this.contentDiv.style.width=options.width;
+ if (options.overflow) this.contentDiv.style.overflow=options.overflow;
+ Rico.addClass(this.container,'ricoWindow');
+ if (Rico.theme.dialog) Rico.addClass(this.container,Rico.theme.dialog);
+ /*
+ if (Rico.isIE) {
+ // fix float'ed content in IE
+ this.titleDiv.style.zoom=1;
+ this.contentDiv.style.zoom=1;
+ }
+ */
+ this.content=this.contentDiv;
+ },
+
+ setTitle: function(title) {
+ this.titleContent.innerHTML=title;
+ }
+
+}
+
+
+Rico.Menu = function(options) {
+ this.initialize(options);
+}
+
+Rico.Menu.prototype = {
+/**
+ * @class Implements popup menus and submenus
+ * @extends Rico.Popup
+ * @constructs
+ */
+ initialize: function(options) {
+ Rico.extend(this, new Rico.Popup());
+ Rico.extend(this.options, {
+ width : "15em",
+ arrowColor : "b", // for submenus: b=black, w=white
+ showDisabled : false,
+ hideOnClick : true
+ });
+ if (typeof options=='string')
+ this.options.width=options;
+ else
+ Rico.extend(this.options, options || {});
+ this.hideFunc=null;
+ this.highlightElem=null;
+ },
+
+ createDiv: function(parentNode) {
+ if (this.container) return;
+ var self=this;
+ var options={ closeFunc: function() { self.cancelmenu(); } };
+ if (parentNode) options.parent=parentNode;
+ this.createContainer(options);
+ this.content.className = Rico.isWebKit ? 'ricoMenuSafari' : 'ricoMenu';
+ this.content.style.width=this.options.width;
+ this.direction=Rico.direction(this.container);
+ this.hidemenu();
+ this.itemCount=0;
+ },
+
+ showmenu: function(e,hideFunc){
+ Rico.eventStop(e);
+ this.hideFunc=hideFunc;
+ if (this.content.childNodes.length==0) {
+ this.cancelmenu();
+ return false;
+ }
+ var mousePos = Rico.eventClient(e);
+ this.openmenu(mousePos.x,mousePos.y,0,0);
+ },
+
+ openmenu: function(x,y,clickItemWi,clickItemHt,noOffset) {
+ var newLeft=x + (noOffset ? 0 : Rico.docScrollLeft());
+ this.container.style.visibility="hidden";
+ this.container.style.display="block";
+ var w=this.container.offsetWidth;
+ var cw=this.content.offsetWidth;
+ //window.status='openmenu: newLeft='+newLeft+' width='+w+' clickItemWi='+clickItemWi+' windowWi='+Rico.windowWidth();
+ if (this.direction == 'rtl') {
+ if (newLeft > w+clickItemWi) newLeft-=cw+clickItemWi;
+ } else {
+ if (x+w > Rico.windowWidth()) newLeft-=cw+clickItemWi-2;
+ }
+ var scrTop=Rico.docScrollTop();
+ var newTop=y + (noOffset ? 0 : scrTop);
+ if (y+this.container.offsetHeight-scrTop > Rico.windowHeight())
+ newTop=Math.max(newTop-this.content.offsetHeight+clickItemHt,0);
+ this.openPopup(newLeft,newTop);
+ this.container.style.visibility ="visible";
+ return false;
+ },
+
+ clearMenu: function() {
+ this.clearContent();
+ this.defaultAction=null;
+ this.itemCount=0;
+ },
+
+ addMenuHeading: function(hdg) {
+ var el=document.createElement('div');
+ el.innerHTML=hdg;
+ el.className='ricoMenuHeading';
+ this.content.appendChild(el);
+ },
+
+ addMenuBreak: function() {
+ var brk=document.createElement('div');
+ brk.className="ricoMenuBreak";
+ this.content.appendChild(brk);
+ },
+
+ addSubMenuItem: function(menutext, submenu, translate) {
+ var dir=this.direction=='rtl' ? 'left' : 'right';
+ var a=this.addMenuItem(menutext,null,true,null,translate);
+ a.className='ricoSubMenu';
+ var arrowdiv = a.appendChild(document.createElement('div'));
+ arrowdiv.className='rico-icon rico-'+dir+'-'+this.options.arrowColor;
+ Rico.setStyle(arrowdiv,{position:'absolute',top:'2px'});
+ arrowdiv.style[dir]='0px';
+ a.RicoSubmenu=submenu;
+ Rico.eventBind(a,"mouseover", Rico.eventHandle(this,'showSubMenu'));
+ //Rico.eventBind(a,"mouseout", Rico.eventHandle(this,'subMenuOut'));
+ },
+
+ showSubMenu: function(e) {
+ if (this.openSubMenu) this.hideSubMenu();
+ var a=Rico.eventElement(e);
+ if (!a.RicoSubmenu) a=a.parentNode; // event can happen on arrow div
+ if (!a.RicoSubmenu) return;
+ this.openSubMenu=a.RicoSubmenu;
+ this.openMenuAnchor=a;
+ if (Rico.hasClass(a,'ricoSubMenu')) {
+ Rico.removeClass(a,'ricoSubMenu');
+ Rico.addClass(a,'ricoSubMenuOpen');
+ }
+ a.RicoSubmenu.openmenu(parseInt(this.container.style.left)+a.offsetWidth, parseInt(this.container.style.top)+a.offsetTop, a.offsetWidth-2, a.offsetHeight+2,true);
+ },
+
+ /*
+ subMenuOut: function(e) {
+ if (!this.openSubMenu) return;
+ Rico.eventStop(e);
+ var elem=Rico.eventElement(e);
+ var reltg = Rico.eventRelatedTarget(e) || e.toElement;
+ try {
+ while (reltg != null && reltg != this.openSubMenu.div)
+ reltg=reltg.parentNode;
+ } catch(err) {}
+ if (reltg == this.openSubMenu.div) return;
+ this.hideSubMenu();
+ },
+ */
+
+ hideSubMenu: function() {
+ if (this.openMenuAnchor) {
+ Rico.removeClass(this.openMenuAnchor,'ricoSubMenuOpen');
+ Rico.addClass(this.openMenuAnchor,'ricoSubMenu');
+ this.openMenuAnchor=null;
+ }
+ if (this.openSubMenu) {
+ this.openSubMenu.hidemenu();
+ this.openSubMenu=null;
+ }
+ },
+
+ addMenuItemId: function(phraseId,action,enabled,title,target) {
+ if ( arguments.length < 3 ) enabled=true;
+ this.addMenuItem(Rico.getPhraseById(phraseId),action,enabled,title,target);
+ },
+
+// if action is a string, then it is assumed to be a URL and the target parm can be used indicate which window gets the content
+// action can also be a function
+// action can also be a Rico.eventHandle, but set target='event' in this case
+ addMenuItem: function(menutext,action,enabled,title,target) {
+ if (arguments.length >= 3 && !enabled && !this.options.showDisabled) return null;
+ this.itemCount++;
+ var a = document.createElement(typeof action=='string' ? 'a' : 'div');
+ if ( arguments.length < 3 || enabled ) {
+ if (typeof action=='string') {
+ a.href = action;
+ if (target) a.target = target;
+ } else if (target=='event') {
+ Rico.eventBind(a,"click", action);
+ } else {
+ a.onclick=action;
+ }
+ a.className = 'enabled';
+ if (this.defaultAction==null) this.defaultAction=action;
+ } else {
+ a.disabled = true;
+ a.className = 'disabled';
+ }
+ a.innerHTML = menutext;
+ if (typeof title=='string')
+ a.title = title;
+ a=this.content.appendChild(a);
+ Rico.eventBind(a,"mouseover", Rico.eventHandle(this,'mouseOver'));
+ Rico.eventBind(a,"mouseout", Rico.eventHandle(this,'mouseOut'));
+ return a;
+ },
+
+ mouseOver: function(e) {
+ if (this.highlightElem && this.highlightElem.className=='enabled-hover') {
+ // required for Safari
+ this.highlightElem.className='enabled';
+ this.highlightElem=null;
+ }
+ var elem=Rico.eventElement(e);
+ if (elem.parentNode == this.openMenuAnchor) elem=elem.parentNode;
+ if (this.openMenuAnchor && this.openMenuAnchor!=elem)
+ this.hideSubMenu();
+ if (elem.className=='enabled') {
+ elem.className='enabled-hover';
+ this.highlightElem=elem;
+ }
+ },
+
+ mouseOut: function(e) {
+ var elem=Rico.eventElement(e);
+ if (elem.className=='enabled-hover') elem.className='enabled';
+ if (this.highlightElem==elem) this.highlightElem=null;
+ },
+
+ cancelmenu: function() {
+ if (!this.visible()) return;
+ if (this.hideFunc) this.hideFunc();
+ this.hideFunc=null;
+ this.hidemenu();
+ },
+
+ hidemenu: function() {
+ if (this.openSubMenu) this.openSubMenu.hidemenu();
+ this.closePopup();
+ }
+
+}
+
+
+Rico.SelectionSet = function(selectionSet, options) {
+ this.initialize(selectionSet, options);
+}
+
+Rico.SelectionSet.prototype = {
+/**
+ * @class
+ * @constructs
+ * @param selectionSet collection of DOM elements (or a CSS selection string)
+ * @param options object may contain any of the following:<dl>
+ * <dt>selectedClass</dt><dd>class name to add when element is selected, default is "selected"</dd>
+ * <dt>selectNode </dt><dd>optional function that returns the element to be selected</dd>
+ * <dt>onSelect </dt><dd>optional function that gets called when element is selected</dd>
+ * <dt>onFirstSelect</dt><dd>optional function that gets called the first time element is selected</dd>
+ * <dt>noDefault </dt><dd>when true, no element in the set is initially selected, default is false</dd>
+ * <dt>selectedIndex</dt><dd>index of the element that should be initially selected, default is 0</dd>
+ * <dt>cookieName </dt><dd>optional name of cookie to use to remember selected element. If specified, and the cookie exists, then the cookie value overrides selectedIndex.</dd>
+ * <dt>cookieDays </dt><dd>specifies how long cookie should persist (in days). If unspecified, then the cookie persists for the current session.</dd>
+ * <dt>cookiePath </dt><dd>optional cookie path</dd>
+ * <dt>cookieDomain </dt><dd>optional cookie domain</dd>
+ *</dl>
+ */
+ initialize: function(selectionSet, options){
+ Rico.log('SelectionSet#initialize');
+ this.options = options || {};
+ if (typeof selectionSet == 'string')
+ selectionSet = Rico.select(selectionSet);
+ this.previouslySelected = [];
+ this.selectionSet = [];
+ this.selectedClassName = this.options.selectedClass || Rico.theme.selected || "selected";
+ this.selectNode = this.options.selectNode || function(e){return e;};
+ this.onSelect = this.options.onSelect;
+ this.onFirstSelect = this.options.onFirstSelect;
+ var self=this;
+ this.clickHandler = function(idx) { self.selectIndex(idx); };
+ this.selectedIndex=-1;
+ for (var i=0; i<selectionSet.length; i++)
+ this.add(selectionSet[i]);
+ if (!this.options.noDefault) {
+ var cookieIndex=this.options.cookieName ? this.getCookie() : 0;
+ this.selectIndex(cookieIndex || this.options.selectedIndex || 0);
+ }
+ },
+ getCookie: function() {
+ var cookie = Rico.getCookie(this.options.cookieName);
+ if (!cookie) return 0;
+ var index = parseInt(cookie);
+ return index < this.selectionSet.length ? index : 0;
+ },
+ reset: function(){
+ this.previouslySelected = [];
+ this._notifySelected(this.selectedIndex);
+ },
+ clearSelected: function() {
+ if (this.selected)
+ Rico.removeClass(this.selectNode(this.selected), this.selectedClassName);
+ },
+ getIndex: function(element) {
+ for (var i=0; i<this.selectionSet.length; i++) {
+ if (element == this.selectionSet[i]) return i;
+ }
+ return -1;
+ },
+ select: function(element){
+ if (this.selected == element) return;
+ var i=this.getIndex(element);
+ if (i >= 0) this.selectIndex(i);
+ },
+ _notifySelected: function(index){
+ if (index < 0) return;
+ var element = this.selectionSet[index];
+ if (this.options.cookieName)
+ Rico.setCookie(this.options.cookieName, index, this.options.cookieDays, this.options.cookiePath, this.options.cookieDomain);
+ if (this.onFirstSelect && !this.previouslySelected[index]){
+ this.onFirstSelect(element, index);
+ this.previouslySelected[index] = true;
+ }
+ if (this.onSelect)
+ try{
+ this.onSelect(index);
+ } catch (e) {};
+ },
+ selectIndex: function(index){
+ if (this.selectedIndex == index || index >= this.selectionSet.length) return;
+ this.clearSelected();
+ this._notifySelected(index);
+ this.selectedIndex = index;
+ this.selected=this.selectionSet[index].element;
+ Rico.addClass(this.selectNode(this.selected), this.selectedClassName);
+ },
+ nextSelectIndex: function(){
+ return (this.selectedIndex + 1) % this.selectionSet.length;
+ },
+ nextSelectItem: function(){
+ return this.selectionSet[this.nextSelectIndex()];
+ },
+ selectNext: function(){
+ this.selectIndex(this.nextSelectIndex());
+ },
+ add: function(item){
+ var index=this.selectionSet.length;
+ this.selectionSet[index] = new Rico._SelectionItem(item,index,this.clickHandler);
+ },
+ remove: function(item){
+ if (item==this.selected) this.clearSelected();
+ var i=this.getIndex(item);
+ if (i < 0) return;
+ this.selectionSet[i].remove();
+ this.selectionSet.splice(i,1);
+ },
+ removeAll: function(){
+ this.clearSelected();
+ while (this.selectionSet.length > 0) {
+ this.selectionSet.pop().remove();
+ }
+ }
+};
+
+
+Rico._SelectionItem=function(element,index,callback) {
+ this.add(element,index,callback);
+};
+
+Rico._SelectionItem.prototype = {
+ add: function(element,index,callback) {
+ this.element=element;
+ this.index=index;
+ this.callback=callback;
+ this.handle=Rico.eventHandle(this,'click');
+ Rico.eventBind(element, "click", this.handle);
+ },
+
+ click: function(ev) {
+ this.callback(this.index);
+ },
+
+ remove: function() {
+ Rico.eventUnbind(this.element, "click", this.handle);
+ }
+};
+
+
+Rico.HoverSet = function(hoverSet, options) {
+ this.initialize(hoverSet, options);
+};
+
+Rico.HoverSet.prototype = {
+/**
+ * @class
+ * @constructs
+ * @param hoverSet collection of DOM elements
+ * @param options object may contain any of the following:<dl>
+ * <dt>hoverClass</dt><dd> class name to add when mouse is over element, default is "hover"</dd>
+ * <dt>hoverNodes</dt><dd> optional function to select/filter which nodes are in the set</dd>
+ *</dl>
+ */
+ initialize: function(hoverSet, options){
+ Rico.log('HoverSet#initialize');
+ options = options || {};
+ this.hoverClass = options.hoverClass || Rico.theme.hover || "hover";
+ this.hoverFunc = options.hoverNodes || function(e){return [e];};
+ this.hoverSet=[];
+ if (!hoverSet) return;
+ for (var i=0; i<hoverSet.length; i++)
+ this.add(hoverSet[i]);
+ },
+ add: function(item) {
+ this.hoverSet.push(new Rico._HoverItem(item,this.hoverFunc,this.hoverClass));
+ },
+ removeAll: function(){
+ while (this.hoverSet.length > 0) {
+ this.hoverSet.pop().remove();
+ }
+ }
+};
+
+
+Rico._HoverItem=function(element,selectFunc,hoverClass) {
+ this.add(element,selectFunc,hoverClass);
+};
+
+Rico._HoverItem.prototype = {
+ add: function(element,selectFunc,hoverClass) {
+ this.element=element;
+ this.selectFunc=selectFunc;
+ this.hoverClass=hoverClass;
+ this.movehandle=Rico.eventHandle(this,'move');
+ this.outhandle=Rico.eventHandle(this,'mouseout');
+ Rico.eventBind(element, "mousemove", this.movehandle);
+ Rico.eventBind(element, "mouseout", this.outhandle);
+ },
+
+ move: function(ev) {
+ var elems=this.selectFunc(this.element);
+ for (var i=0; i<elems.length; i++)
+ Rico.addClass(elems[i],this.hoverClass);
+ },
+
+ mouseout: function(ev) {
+ var elems=this.selectFunc(this.element);
+ for (var i=0; i<elems.length; i++)
+ Rico.removeClass(elems[i],this.hoverClass);
+ },
+
+ remove: function() {
+ Rico.eventUnbind(element, "mousemove", this.movehandle);
+ Rico.eventUnbind(element, "mouseout", this.outhandle);
+ }
+};
+
+
+/** @class core methods for transition effects */
+Rico.ContentTransitionBase = function() {};
+Rico.ContentTransitionBase.prototype = {
+ initBase: function(titles, contents, options) {
+ this.options = options || {};
+ this.titles = titles;
+ this.contents = contents;
+ this.hoverSet = new Rico.HoverSet(titles, options);
+ for (var i=0; i<contents.length; i++) {
+ if (contents[i]) Rico.hide(contents[i]);
+ }
+ var self=this;
+ this.selectionSet = new Rico.SelectionSet(titles, Rico.extend(options, { onSelect: function(idx) { self._finishSelect(idx); } }));
+ },
+ reset: function(){
+ this.selectionSet.reset();
+ },
+ select: function(index) {
+ this.selectionSet.selectIndex(index);
+ },
+ _finishSelect: function(index) {
+ Rico.log('ContentTransitionBase#_finishSelect');
+ var panel = this.contents[index];
+ if (!panel) {
+ alert('Internal error: no panel @index='+index);
+ return;
+ }
+ if ( this.selected == panel) return;
+ if (this.transition){
+ if (this.selected){
+ this.transition(panel);
+ } else {
+ panel.style.display='block';
+ }
+ } else {
+ if (this.selected) Rico.hide(this.selected);
+ panel.style.display='block';
+ }
+ this.selected = panel;
+ },
+ addBase: function(title, content){
+ this.titles.push(title);
+ this.contents.push(content);
+ this.hoverSet.add(title);
+ this.selectionSet.add(title);
+ Rico.hide(content);
+ //this.selectionSet.select(title);
+ },
+ removeAll: function(){
+ this.hoverSet.removeAll();
+ this.selectionSet.removeAll();
+ }
+};
+
+
+/**
+ * @class Implements accordion effect
+ * @see Rico.ContentTransitionBase#initialize for construction parameters
+ * @extends Rico.ContentTransitionBase
+ */
+Rico.Accordion = function(element, options) {
+ this.initialize(element, options);
+};
+
+Rico.Accordion.prototype = Rico.extend(new Rico.ContentTransitionBase(),
+/** @lends Rico.Accordion# */
+{
+ initialize: function(element, options) {
+ element=Rico.$(element);
+ element.style.overflow='hidden';
+ element.className=options.accClass || Rico.theme.accordion || "Rico_accordion";
+ if (typeof options.panelWidth=='number') options.panelWidth+="px";
+ if (options.panelWidth) element.style.width = options.panelWidth;
+ var panels=Rico.getDirectChildrenByTag(element,'div');
+ var items,titles=[], contents=[];
+ for (var i=0; i<panels.length; i++) {
+ items=Rico.getDirectChildrenByTag(panels[i],'div');
+ if (items.length>=2) {
+ items[0].className=options.titleClass || Rico.theme.accTitle || "Rico_accTitle";
+ items[1].className=options.contentClass || Rico.theme.accContent || "Rico_accContent";
+ titles.push(items[0]);
+ contents.push(items[1]);
+ var a=Rico.wrapChildren(items[0],'','','a');
+ a.href="javascript:void(0)";
+ }
+ }
+ Rico.log('creating Rico.Accordion for '+element.id+' with '+titles.length+' panels');
+ this.initBase(titles, contents, options);
+ this.selected.style.height = this.options.panelHeight + "px";
+ this.totSteps=(typeof options.duration =='number' ? options.duration : 200)/25;
+ },
+ transition: function(p){
+ if (!this.options.noAnimate) {
+ this.closing=this.selected;
+ this.opening=p;
+ this.curStep=0;
+ var self=this;
+ this.timer=setInterval(function() { self.step(); },25);
+ } else {
+ p.style.height = this.options.panelHeight + "px";
+ if (this.selected) Rico.hide(this.selected);
+ p.style.display='block';
+ }
+ },
+ step: function() {
+ this.curStep++;
+ var oheight=Math.round(this.curStep/this.totSteps*this.options.panelHeight);
+ this.opening.style.height=oheight+'px';
+ this.closing.style.height=(this.options.panelHeight - oheight)+'px';
+ if (this.curStep==1) {
+ this.opening.style.paddingTop=this.opening.style.paddingBottom='0px';
+ this.opening.style.display='block';
+ }
+ if (this.curStep==this.totSteps) {
+ clearInterval(this.timer);
+ this.opening.style.paddingTop=this.opening.style.paddingBottom='';
+ Rico.hide(this.closing);
+ }
+ },
+ setPanelHeight: function(h) {
+ this.options.panelHeight = h;
+ this.selected.style.height = this.options.panelHeight + "px";
+ }
+});
+
+
+/**
+ * @class Implements tabbed panel effect
+ * @see Rico.ContentTransitionBase#initialize for construction parameters
+ * @extends Rico.ContentTransitionBase
+ */
+Rico.TabbedPanel = function(element, options) {
+ this.initialize(element, options);
+};
+
+Rico.TabbedPanel.prototype = Rico.extend(new Rico.ContentTransitionBase(),
+{
+ initialize: function(element, options) {
+ element=Rico.$(element);
+ options=options || {};
+ if (typeof options.panelWidth=='number') options.panelWidth+="px";
+ if (typeof options.panelHeight=='number') options.panelHeight+="px";
+ element.className=options.tabClass || Rico.theme.tabPanel || "Rico_tabPanel";
+ if (options.panelWidth) element.style.width = options.panelWidth;
+ var items = [];
+ var allKids = element.childNodes;
+ for( var i = 0 ; i < allKids.length ; i++ ) {
+ if (allKids[i] && allKids[i].tagName && allKids[i].tagName.match(/^div|ul$/i))
+ items.push(allKids[i]);
+ }
+ if (items.length < 2) return;
+ var childTag=items[0].tagName.toLowerCase()=='ul' ? 'li' : 'div';
+ items[0].className=options.navContainerClass || Rico.theme.tabNavContainer || "Rico_tabNavContainer";
+ items[0].style.listStyle='none';
+ items[1].className=options.contentContainerClass || Rico.theme.tabContentContainer || "Rico_tabContentContainer";
+ var titles=Rico.getDirectChildrenByTag(items[0], childTag);
+ var contents=Rico.getDirectChildrenByTag(items[1],'div');
+ var direction=Rico.direction(element);
+ if (!options.corners) options.corners='top';
+ for (var i=0; i<titles.length; i++) {
+ if (direction == 'rtl') Rico.setStyle(titles[i], {'float':'right'});
+ titles[i].className=options.titleClass || Rico.theme.tabTitle || "Rico_tabTitle";
+ var a=Rico.wrapChildren(titles[i],'','','a');
+ a.href="javascript:void(0)";
+ contents[i].className=options.contentClass || Rico.theme.tabContent || "Rico_tabContent";
+ if (options.panelHeight) contents[i].style.overflow='auto';
+ if (options.corners!='none') {
+ if (options.panelHdrWidth) titles[i].style.width=options.panelHdrWidth;
+ Rico.Corner.round(titles[i], Rico.theme.tabCornerOptions || options);
+ }
+ }
+ options.selectedClass=Rico.theme.tabSelected || 'selected';
+ this.initBase(titles, contents, options);
+ if (this.selected) this.transition(this.selected);
+ },
+ transition: function(p){
+ Rico.log('TabbedPanel#transition '+typeof(p));
+ if (this.selected) Rico.hide(this.selected);
+ Rico.show(p);
+ if (this.options.panelHeight) p.style.height = this.options.panelHeight;
+ }
+});
+
+
+/**
+ * @namespace
+ */
+Rico.Corner = {
+
+ round: function(e, options) {
+ e = Rico.$(e);
+ this.options = {
+ corners : "all",
+ bgColor : "fromParent",
+ compact : false,
+ nativeCorners: false // only use native corners?
+ };
+ Rico.extend(this.options, options || {});
+ if (typeof(Rico.getStyle(e,'border-radius'))=='string')
+ this._roundCornersStdCss(e);
+ else if (typeof(Rico.getStyle(e,'-webkit-border-radius'))=='string')
+ this._roundCornersWebKit(e);
+ else if (typeof(Rico.getStyle(e,'-moz-border-radius'))=='string')
+ this._roundCornersMoz(e);
+ else if (!this.options.nativeCorners)
+ this._roundCornersImpl(e);
+ },
+
+ _roundCornersStdCss: function(e) {
+ var radius=this.options.compact ? '4px' : '8px';
+ if (this._hasString(this.options.corners, "all"))
+ Rico.setStyle(e, {borderRadius:radius});
+ else {
+ if (this._hasString(this.options.corners, "top", "tl")) Rico.setStyle(e, {borderTopLeftRadius:radius});
+ if (this._hasString(this.options.corners, "top", "tr")) Rico.setStyle(e, {borderTopRightRadius:radius});
+ if (this._hasString(this.options.corners, "bottom", "bl")) Rico.setStyle(e, {borderBottomLeftRadius:radius});
+ if (this._hasString(this.options.corners, "bottom", "br")) Rico.setStyle(e, {borderBottomRightRadius:radius});
+ }
+ },
+
+ _roundCornersWebKit: function(e) {
+ var radius=this.options.compact ? '4px' : '8px';
+ if (this._hasString(this.options.corners, "all"))
+ Rico.setStyle(e, {WebkitBorderRadius:radius});
+ else {
+ if (this._hasString(this.options.corners, "top", "tl")) Rico.setStyle(e, {WebkitBorderTopLeftRadius:radius});
+ if (this._hasString(this.options.corners, "top", "tr")) Rico.setStyle(e, {WebkitBorderTopRightRadius:radius});
+ if (this._hasString(this.options.corners, "bottom", "bl")) Rico.setStyle(e, {WebkitBorderBottomLeftRadius:radius});
+ if (this._hasString(this.options.corners, "bottom", "br")) Rico.setStyle(e, {WebkitBorderBottomRightRadius:radius});
+ }
+ },
+
+ _roundCornersMoz: function(e) {
+ var radius=this.options.compact ? '4px' : '8px';
+ if (this._hasString(this.options.corners, "all"))
+ Rico.setStyle(e, {MozBorderRadius:radius});
+ else {
+ if (this._hasString(this.options.corners, "top", "tl")) Rico.setStyle(e, {MozBorderRadiusTopleft:radius});
+ if (this._hasString(this.options.corners, "top", "tr")) Rico.setStyle(e, {MozBorderRadiusTopright:radius});
+ if (this._hasString(this.options.corners, "bottom", "bl")) Rico.setStyle(e, {MozBorderRadiusBottomleft:radius});
+ if (this._hasString(this.options.corners, "bottom", "br")) Rico.setStyle(e, {MozBorderRadiusBottomright:radius});
+ }
+ },
+
+ _roundCornersImpl: function(e) {
+ var bgColor = this.options.bgColor == "fromParent" ? this._background(e.parentNode) : this.options.bgColor;
+ e.style.position='relative';
+ //this.options.numSlices = this.options.compact ? 2 : 4;
+ if (this._hasString(this.options.corners, "all", "top", "tl")) this._createCorner(e,'top','left',bgColor);
+ if (this._hasString(this.options.corners, "all", "top", "tr")) this._createCorner(e,'top','right',bgColor);
+ if (this._hasString(this.options.corners, "all", "bottom", "bl")) this._createCorner(e,'bottom','left',bgColor);
+ if (this._hasString(this.options.corners, "all", "bottom", "br")) this._createCorner(e,'bottom','right',bgColor);
+ },
+
+ _createCorner: function(elem,tb,lr,bgColor) {
+ //alert('Corner: '+tb+' '+lr+' bgColor='+typeof(bgColor));
+ var corner = document.createElement("div");
+ corner.className='ricoCorner';
+ Rico.setStyle(corner,{width:'6px', height:'5px'});
+ var borderStyle = Rico.getStyle(elem,'border-'+tb+'-style');
+ var borderColor = borderStyle=='none' ? bgColor : Rico.getStyle(elem,'border-'+tb+'-color');
+ //alert('Corner: '+tb+' '+borderStyle+borderColor+' '+);
+ var pos=borderStyle=='none' ? '0px' : '-1px';
+ corner.style[tb]=pos;
+ corner.style[lr]=Rico.isIE && Rico.ieVersion<7 && lr=='right' && borderStyle!='none' ? '-2px' : '-1px';
+ //corner.style[lr]='-1px';
+ elem.appendChild(corner);
+ var marginSizes = [ 0, 2, 3, 4, 4 ];
+ if (tb=='bottom') marginSizes.reverse();
+ var borderVal= borderStyle=='none' ? '0px none' : '1px solid '+borderColor;
+ var d= lr=='left' ? 'Right' : 'Left';
+ for (var i=0; i<marginSizes.length; i++) {
+ var slice = document.createElement("div");
+ Rico.setStyle(slice,{backgroundColor:bgColor,height:'1px'});
+ slice.style['margin'+d]=marginSizes[i]+'px';
+ slice.style['border'+d]=borderVal;
+ corner.appendChild(slice);
+ }
+ },
+
+ _background: function(elem) {
+ try {
+ var actualColor = Rico.getStyle(elem, "backgroundColor");
+
+ // if color is tranparent, check parent
+ // Safari returns "rgba(0, 0, 0, 0)", which means transparent
+ if ( actualColor.match(/^(transparent|rgba\(0,\s*0,\s*0,\s*0\))$/i) && elem.parentNode )
+ return this._background(elem.parentNode);
+
+ return actualColor == null ? "#ffffff" : actualColor;
+ } catch(err) {
+ return "#ffffff";
+ }
+ },
+
+ _hasString: function(str) {
+ for(var i=1 ; i<arguments.length ; i++) {
+ if (str.indexOf(arguments[i]) >= 0) return true;
+ }
+ return false;
+ }
+
+};
+
+Rico.toColorPart = function(c) {
+ return Rico.zFill(c, 2, 16);
+};
+
+
+Rico.Color = function(red, green, blue) {
+ this.initialize(red, green, blue);
+};
+
+Rico.Color.prototype = {
+/**
+ * @class Methods to manipulate color values.
+ * @constructs
+ * @param red integer (0-255)
+ * @param green integer (0-255)
+ * @param blue integer (0-255)
+ */
+ initialize: function(red, green, blue) {
+ this.rgb = { r: red, g : green, b : blue };
+ },
+
+ setRed: function(r) {
+ this.rgb.r = r;
+ },
+
+ setGreen: function(g) {
+ this.rgb.g = g;
+ },
+
+ setBlue: function(b) {
+ this.rgb.b = b;
+ },
+
+ setHue: function(h) {
+
+ // get an HSB model, and set the new hue...
+ var hsb = this.asHSB();
+ hsb.h = h;
+
+ // convert back to RGB...
+ this.rgb = Rico.Color.HSBtoRGB(hsb.h, hsb.s, hsb.b);
+ },
+
+ setSaturation: function(s) {
+ // get an HSB model, and set the new hue...
+ var hsb = this.asHSB();
+ hsb.s = s;
+
+ // convert back to RGB and set values...
+ this.rgb = Rico.Color.HSBtoRGB(hsb.h, hsb.s, hsb.b);
+ },
+
+ setBrightness: function(b) {
+ // get an HSB model, and set the new hue...
+ var hsb = this.asHSB();
+ hsb.b = b;
+
+ // convert back to RGB and set values...
+ this.rgb = Rico.Color.HSBtoRGB( hsb.h, hsb.s, hsb.b );
+ },
+
+ darken: function(percent) {
+ var hsb = this.asHSB();
+ this.rgb = Rico.Color.HSBtoRGB(hsb.h, hsb.s, Math.max(hsb.b - percent,0));
+ },
+
+ brighten: function(percent) {
+ var hsb = this.asHSB();
+ this.rgb = Rico.Color.HSBtoRGB(hsb.h, hsb.s, Math.min(hsb.b + percent,1));
+ },
+
+ blend: function(other) {
+ this.rgb.r = Math.floor((this.rgb.r + other.rgb.r)/2);
+ this.rgb.g = Math.floor((this.rgb.g + other.rgb.g)/2);
+ this.rgb.b = Math.floor((this.rgb.b + other.rgb.b)/2);
+ },
+
+ isBright: function() {
+ var hsb = this.asHSB();
+ return this.asHSB().b > 0.5;
+ },
+
+ isDark: function() {
+ return ! this.isBright();
+ },
+
+ asRGB: function() {
+ return "rgb(" + this.rgb.r + "," + this.rgb.g + "," + this.rgb.b + ")";
+ },
+
+ asHex: function() {
+ return "#" + Rico.toColorPart(this.rgb.r) + Rico.toColorPart(this.rgb.g) + Rico.toColorPart(this.rgb.b);
+ },
+
+ asHSB: function() {
+ return Rico.Color.RGBtoHSB(this.rgb.r, this.rgb.g, this.rgb.b);
+ },
+
+ toString: function() {
+ return this.asHex();
+ }
+
+};
+
+/**
+ * Factory method for creating a color from an RGB string
+ * @param hexCode a 3 or 6 digit hex string, optionally preceded by a # symbol
+ * @returns a Rico.Color object
+ */
+Rico.Color.createFromHex = function(hexCode) {
+ if(hexCode.length==4) {
+ var shortHexCode = hexCode;
+ hexCode = '#';
+ for(var i=1;i<4;i++)
+ hexCode += (shortHexCode.charAt(i) + shortHexCode.charAt(i));
+ }
+ if ( hexCode.indexOf('#') == 0 )
+ hexCode = hexCode.substring(1);
+ if (!hexCode.match(/^[0-9A-Fa-f]{6}$/)) return null;
+ var red = hexCode.substring(0,2);
+ var green = hexCode.substring(2,4);
+ var blue = hexCode.substring(4,6);
+ return new Rico.Color( parseInt(red,16), parseInt(green,16), parseInt(blue,16) );
+};
+
+/**
+ * Retrieves the background color of an HTML element
+ * @param elem the DOM element whose background color should be retreived
+ * @returns a Rico.Color object
+ */
+Rico.Color.createColorFromBackground = function(elem) {
+
+ if (!elem.style) return new Rico.Color(255,255,255);
+ var actualColor = Rico.getStyle(elem, "background-color");
+
+ // if color is tranparent, check parent
+ // Safari returns "rgba(0, 0, 0, 0)", which means transparent
+ if ( actualColor.match(/^(transparent|rgba\(0,\s*0,\s*0,\s*0\))$/i) && elem.parentNode )
+ return Rico.Color.createColorFromBackground(elem.parentNode);
+
+ if (actualColor == null) return new Rico.Color(255,255,255);
+
+ if ( actualColor.indexOf("rgb(") == 0 ) {
+ var colors = actualColor.substring(4, actualColor.length - 1 );
+ var colorArray = colors.split(",");
+ return new Rico.Color( parseInt( colorArray[0],10 ),
+ parseInt( colorArray[1],10 ),
+ parseInt( colorArray[2],10 ) );
+
+ }
+ else if ( actualColor.indexOf("#") == 0 ) {
+ return Rico.Color.createFromHex(actualColor);
+ }
+ else
+ return new Rico.Color(255,255,255);
+};
+
+/**
+ * Converts hue/saturation/brightness to RGB
+ * @returns a 3-element object: r=red, g=green, b=blue.
+ */
+Rico.Color.HSBtoRGB = function(hue, saturation, brightness) {
+
+ var red = 0;
+ var green = 0;
+ var blue = 0;
+
+ if (saturation == 0) {
+ red = parseInt(brightness * 255.0 + 0.5,10);
+ green = red;
+ blue = red;
+ }
+ else {
+ var h = (hue - Math.floor(hue)) * 6.0;
+ var f = h - Math.floor(h);
+ var p = brightness * (1.0 - saturation);
+ var q = brightness * (1.0 - saturation * f);
+ var t = brightness * (1.0 - (saturation * (1.0 - f)));
+
+ switch (parseInt(h,10)) {
+ case 0:
+ red = (brightness * 255.0 + 0.5);
+ green = (t * 255.0 + 0.5);
+ blue = (p * 255.0 + 0.5);
+ break;
+ case 1:
+ red = (q * 255.0 + 0.5);
+ green = (brightness * 255.0 + 0.5);
+ blue = (p * 255.0 + 0.5);
+ break;
+ case 2:
+ red = (p * 255.0 + 0.5);
+ green = (brightness * 255.0 + 0.5);
+ blue = (t * 255.0 + 0.5);
+ break;
+ case 3:
+ red = (p * 255.0 + 0.5);
+ green = (q * 255.0 + 0.5);
+ blue = (brightness * 255.0 + 0.5);
+ break;
+ case 4:
+ red = (t * 255.0 + 0.5);
+ green = (p * 255.0 + 0.5);
+ blue = (brightness * 255.0 + 0.5);
+ break;
+ case 5:
+ red = (brightness * 255.0 + 0.5);
+ green = (p * 255.0 + 0.5);
+ blue = (q * 255.0 + 0.5);
+ break;
+ }
+ }
+
+ return { r : parseInt(red,10), g : parseInt(green,10) , b : parseInt(blue,10) };
+};
+
+/**
+ * Converts RGB value to hue/saturation/brightness
+ * @param r integer (0-255)
+ * @param g integer (0-255)
+ * @param b integer (0-255)
+ * @returns a 3-element object: h=hue, s=saturation, b=brightness.
+ * (unlike some HSB documentation which states hue should be a value 0-360, this routine returns hue values from 0 to 1.0)
+ */
+Rico.Color.RGBtoHSB = function(r, g, b) {
+
+ var hue;
+ var saturation;
+ var brightness;
+
+ var cmax = (r > g) ? r : g;
+ if (b > cmax)
+ cmax = b;
+
+ var cmin = (r < g) ? r : g;
+ if (b < cmin)
+ cmin = b;
+
+ brightness = cmax / 255.0;
+ if (cmax != 0)
+ saturation = (cmax - cmin)/cmax;
+ else
+ saturation = 0;
+
+ if (saturation == 0)
+ hue = 0;
+ else {
+ var redc = (cmax - r)/(cmax - cmin);
+ var greenc = (cmax - g)/(cmax - cmin);
+ var bluec = (cmax - b)/(cmax - cmin);
+
+ if (r == cmax)
+ hue = bluec - greenc;
+ else if (g == cmax)
+ hue = 2.0 + redc - bluec;
+ else
+ hue = 4.0 + greenc - redc;
+
+ hue = hue / 6.0;
+ if (hue < 0)
+ hue = hue + 1.0;
+ }
+
+ return { h : hue, s : saturation, b : brightness };
+};
+
+/**
+ * Returns a new XML document object
+ */
+Rico.createXmlDocument = function() {
+ if (document.implementation && document.implementation.createDocument) {
+ var doc = document.implementation.createDocument("", "", null);
+ // some older versions of Moz did not support the readyState property
+ // and the onreadystate event so we patch it!
+ if (doc.readyState == null) {
+ doc.readyState = 1;
+ doc.addEventListener("load", function () {
+ doc.readyState = 4;
+ if (typeof doc.onreadystatechange == "function") {
+ doc.onreadystatechange();
+ }
+ }, false);
+ }
+ return doc;
+ }
+
+ if (window.ActiveXObject)
+ return Rico.tryFunctions(
+ function() { return new ActiveXObject('MSXML2.DomDocument'); },
+ function() { return new ActiveXObject('Microsoft.DomDocument');},
+ function() { return new ActiveXObject('MSXML.DomDocument'); },
+ function() { return new ActiveXObject('MSXML3.DomDocument'); }
+ ) || false;
+ return null;
+}
--- /dev/null
+<?php
+
+// for PHP4
+// copied from http://www.php.net/json_encode
+if (!function_exists('json_encode'))
+{
+ function json_encode($a=false)
+ {
+ if (is_null($a)) return 'null';
+ if ($a === false) return 'false';
+ if ($a === true) return 'true';
+ if (is_scalar($a))
+ {
+ if (is_float($a))
+ {
+ // Always use "." for floats.
+ return floatval(str_replace(",", ".", strval($a)));
+ }
+
+ if (is_string($a))
+ {
+ static $jsonReplaces = array(array("\\", "/", "\n", "\t", "\r", "\b", "\f", '"'), array('\\\\', '\\/', '\\n', '\\t', '\\r', '\\b', '\\f', '\"'));
+ return '"' . str_replace($jsonReplaces[0], $jsonReplaces[1], $a) . '"';
+ }
+ else
+ return $a;
+ }
+ $isList = true;
+ for ($i = 0, reset($a); $i < count($a); $i++, next($a))
+ {
+ if (key($a) !== $i)
+ {
+ $isList = false;
+ break;
+ }
+ }
+ $result = array();
+ if ($isList)
+ {
+ foreach ($a as $v) $result[] = json_encode($v);
+ return '[' . join(',', $result) . ']';
+ }
+ else
+ {
+ foreach ($a as $k => $v) $result[] = json_encode($k).':'.json_encode($v);
+ return '{' . join(',', $result) . '}';
+ }
+ }
+}
+
+class ricoXmlResponse {
+
+ // public properties
+ var $orderByRef;
+ var $sendDebugMsgs;
+ var $readAllRows; // always return the total number of rows? (if true, the user will always see the total number of rows, but there is a small performance hit)
+ var $convertCharSet; // set to true if database is ISO-8859-1 encoded, false if UTF-8
+ var $AllRowsMax; // max # of rows to send if numrows=-1
+ var $fmt; // xml, json, html, xl
+
+ // private properties
+ var $objDB;
+ var $eof;
+ var $oParse;
+ var $sqltext;
+ var $arParams;
+ var $allParams;
+ var $condType;
+ var $RowsStart;
+ var $RowsEnd;
+ var $SendHdg;
+ var $Headings;
+ var $HiddenCols;
+ var $gridDefinition;
+
+ function ricoXmlResponse() {
+ if (isset($GLOBALS['oDB']) && is_object($GLOBALS['oDB'])) {
+ $this->objDB=$GLOBALS['oDB']; // use oDB global as database connection, if it exists
+ }
+ $this->orderByRef=false;
+ $this->sendDebugMsgs=false;
+ $this->readAllRows=true; // has no effect on SQL Server 2005, Oracle, and MySQL because they use Query2xmlRaw_Limit()
+ $this->convertCharSet=false;
+ $this->SendHdg=false;
+ $this->AllRowsMax=1999;
+ $this->Headings=array();
+ $this->HiddenCols=array();
+ }
+
+ function ProcessQuery($id, $sqlselect, $filters=array(), $errmsg='',$sqldistinctselect=false) {
+ $this->fmt=isset($_GET["_fmt"]) ? $_GET["_fmt"] : "xml";
+ $offset=isset($_GET["offset"]) ? $_GET["offset"] : "0";
+ $size=isset($_GET["page_size"]) ? $_GET["page_size"] : "";
+ $total=isset($_GET["get_total"]) ? strtolower($_GET["get_total"]) : "false";
+ $distinct=isset($_GET["distinct"]) ? $_GET["distinct"] : "";
+ $edit=isset($_GET["edit"]) ? $_GET["edit"] : "";
+ if (isset($_GET["hidden"]) && $_GET["hidden"]!="") $this->HiddenCols=explode(",", $_GET["hidden"]);
+
+ ob_clean();
+ if ($this->fmt != "xl") {
+ header("Cache-Control: no-cache");
+ header("Pragma: no-cache");
+ header("Expires: ".gmdate("D, d M Y H:i:s",time()+(-1*60))." GMT");
+ }
+
+ switch ($this->fmt) {
+ case "html":
+ header("Content-type: text/html");
+ echo "<html><head></head><body>\n";
+ $closetags="</body></html>";
+ $this->RowsStart="\n<table border='1'>";
+ $this->RowsEnd="\n</table>";
+ $total="false";
+ $this->sendDebugMsgs=false;
+ $this->SendHdg=true;
+ break;
+ case "xl":
+ $this->convertCharSet=false;
+ header("Content-type: application/vnd.ms-excel");
+ echo "<html><head></head><body>\n";
+ $closetags="</body></html>";
+ $this->RowsStart="\n<table>";
+ $this->RowsEnd="\n</table>";
+ $total="false";
+ $this->sendDebugMsgs=false;
+ $this->SendHdg=true;
+ break;
+ case "json":
+ header("Content-type: application/json");
+ echo "{\n\"id\":\"" . $id . "\"";
+ $this->RowsStart=",\n\"update_ui\":true,\n\"offset\":" . $offset . ",\n\"rows\":[";
+ $this->RowsEnd="\n]";
+ $closetags="}";
+ $this->sendDebugMsgs=false;
+ break;
+ default:
+ // default to xml
+ $this->fmt="xml";
+ header("Content-type: text/xml");
+ echo "<?xml version='1.0' encoding='UTF-8'?".">\n";
+ echo "\n<ajax-response><response type='object' id='" . $id . "'>";
+ $closetags="</response></ajax-response>";
+ $this->RowsStart="\n<rows update_ui='true' offset='" . $offset . "'>";
+ $this->RowsEnd="\n</rows>";
+ break;
+ }
+ if (!empty($errmsg)) {
+ $this->ErrorResponse($errmsg);
+ } elseif (empty($id)) {
+ $this->ErrorResponse("No ID provided!");
+ } elseif ($distinct=="" && !is_numeric($offset)) {
+ $this->ErrorResponse("Invalid offset!");
+ } elseif ($distinct=="" && !is_numeric($size)) {
+ $this->ErrorResponse("Invalid size!");
+ } elseif ($distinct!="" && !is_numeric($distinct)) {
+ $this->ErrorResponse("Invalid distinct parameter!");
+ } else {
+ if ($this->SendHdg && is_array($sqlselect)) {
+ // populate $Headings from $sqlselect[9] taking into account hidden columns
+ for ($i=0,$j=0,$SkipIdx=0; $i<count($sqlselect[9]); $i++) {
+ $skip=false;
+ if ($SkipIdx < count($this->HiddenCols)) {
+ $skip=($this->HiddenCols[$SkipIdx] == $i);
+ if ($skip) $SkipIdx++;
+ }
+ if (!$skip) {
+ $this->Headings[$j++]=$sqlselect[9][$i];
+ }
+ }
+ }
+ $this->objDB->DisplayErrors=false;
+ $this->objDB->ErrMsgFmt="MULTILINE";
+ if ($distinct!="" && is_numeric($distinct)) {
+ $this->Query2xmlDistinct($sqlselect, intval($distinct), -1, $filters, $sqldistinctselect);
+ } elseif ($edit!="" && is_numeric($edit) && is_array($sqlselect)) {
+ $this->Query2xml($sqlselect[8][intval($edit)], intval($offset), intval($size), $total!="false", $filters);
+ } else {
+ $this->Query2xml($sqlselect, intval($offset), intval($size), $total!="false", $filters);
+ }
+ if (!empty($this->objDB->LastErrorMsg)) {
+ $this->ErrorResponse($this->objDB->LastErrorMsg);
+ }
+ }
+ echo "\n".$closetags;
+ }
+
+ function ErrorResponse($msg) {
+ $this->AppendResponse("error",$msg);
+ }
+
+ function AppendResponse($tag, $content) {
+ switch ($this->fmt) {
+ case "html":
+ echo "\n<p>".$tag."<br>".htmlspecialchars($content)."</p>";
+ break;
+ case "xl":
+ echo "\n<p>".$tag."<br>".htmlspecialchars($content)."</p>";
+ break;
+ case "json":
+ echo ",\n\"".$tag."\":".json_encode($content);
+ break;
+ case "xml":
+ echo "\n<".$tag.">".htmlspecialchars($content)."</".$tag.">";
+ break;
+ }
+ }
+
+ // All Oracle and SQL Server 2005 queries *must* have an ORDER BY clause
+ // "as" clauses are now ok
+ // If numrows < 0, then retrieve all rows
+ function Query2xml($sqlselect, $offset, $numrows, $gettotal, $filters=array()) {
+ if ($numrows >= 0) {
+ $Dialect=$this->objDB->Dialect;
+ } else {
+ $numrows=$this->AllRowsMax;
+ $Dialect=""; // don't use limit query
+ }
+ switch ($this->objDB->Dialect) {
+ case "MySQL": $this->orderByRef=true; break;
+ }
+ $this->arParams=array('H'=>array(), 'W'=>array());
+ $this->oParse= new sqlParse();
+ if (is_array($sqlselect)) {
+ $this->oParse->LoadArray($sqlselect);
+ } else {
+ $this->oParse->ParseSelect($sqlselect);
+ }
+ $this->ApplyQStringParms($filters);
+ $this->allParams=array_merge($this->arParams['W'],$this->arParams['H']);
+ echo $this->RowsStart;
+ switch ($Dialect) {
+
+ case "TSQL":
+ $this->objDB->SingleRecordQuery("select @@VERSION", $version);
+ if (is_string($sqlselect) && strtoupper(substr($sqlselect,0,7))!="SELECT ") {
+ $this->allParams=array();
+ $totcnt=$this->Query2xmlRaw($sqlselect, $offset, $numrows);
+ }
+ else if (preg_match("/SQL Server 200(5|8)/i",$version[0])) {
+ $this->sqltext=$this->UnparseWithRowNumber($offset, $numrows + 1, true);
+ $totcnt=$this->Query2xmlRaw_Limit($this->sqltext, $offset, $numrows, 1);
+ }
+ else {
+ $this->sqltext=$this->oParse->UnparseSelectSkip($this->HiddenCols);
+ $totcnt=$this->Query2xmlRaw($this->sqltext, $offset, $numrows);
+ }
+ break;
+
+ case "Oracle":
+ $this->sqltext=$this->UnparseWithRowNumber($offset, $numrows + 1, false);
+ $totcnt=$this->Query2xmlRaw_Limit($this->sqltext, $offset, $numrows, 1);
+ break;
+
+ case "MySQL":
+ $this->sqltext=$this->oParse->UnparseSelectSkip($this->HiddenCols)." LIMIT ".$offset.",".($numrows + 1);
+ $totcnt=$this->Query2xmlRaw_Limit($this->sqltext, $offset, $numrows, 0);
+ break;
+
+ case "PostgreSQL":
+ $this->sqltext=$this->oParse->UnparseSelect()." LIMIT ".($numrows + 1) . " OFFSET ".$offset;
+ $totcnt=$this->Query2xmlRaw_Limit($this->sqltext, $offset, $numrows, 0);
+ break;
+
+ default:
+ $this->sqltext=$this->oParse->UnparseSelectSkip($this->HiddenCols);
+ $totcnt=$this->Query2xmlRaw($this->sqltext, $offset, $numrows);
+ break;
+ }
+ echo $this->RowsEnd;
+ if ($this->sendDebugMsgs) {
+ $this->AppendResponse("debug",$this->objDB->db->lastQuery);
+ }
+ if (!$this->eof && $gettotal) {
+ $totcnt=$this->getTotalRowCount();
+ }
+ if ($this->fmt=="xml" || $this->fmt=="json") {
+ if ($this->eof) $this->AppendResponse("rowcount",$totcnt);
+ }
+ $this->oParse=NULL;
+ return $totcnt;
+ }
+
+
+ function Query2xmlDistinct($sqlselect, $colnum, $numrows, $filters=array(), $sqldistinct=false) {
+ if ($numrows < 0) $numrows=$this->AllRowsMax;
+ $this->arParams=array('H'=>array(), 'W'=>array());
+ $this->oParse= new sqlParse();
+ if (is_array($sqlselect)) {
+ $this->oParse->LoadArray($sqlselect);
+ } else {
+ $this->oParse->ParseSelect($sqlselect);
+ }
+ $this->ApplyQStringParms($filters);
+ $this->allParams=array_merge($this->arParams['W'],$this->arParams['H']);
+ echo $this->RowsStart;
+ if ($sqldistinct) $this->sqltext=$sqldistinct; else
+ $this->sqltext=$this->oParse->UnparseDistinctColumn($colnum);
+ $totcnt=$this->Query2xmlRaw($this->sqltext, 0, $numrows);
+ echo $this->RowsEnd;
+ if ($this->sendDebugMsgs) {
+ $this->AppendResponse("debug",$this->objDB->db->lastQuery);
+ }
+ $this->oParse=NULL;
+ }
+
+
+ // Tested ok with SQL Server 2005, MySQL, and Oracle
+ function getTotalRowCount() {
+ $countSql="SELECT ".$this->oParse->UnparseColumnList()." FROM ".$this->oParse->FromClause;
+ if (!empty($this->oParse->WhereClause)) {
+ $countSql.=" WHERE ".$this->oParse->WhereClause;
+ }
+ if (is_array($this->oParse->arGroupBy)) {
+ if (count($this->oParse->arGroupBy) > 0) {
+ $countSql.=" GROUP BY ".implode(",",$this->oParse->arGroupBy);
+ }
+ }
+ if (!empty($this->oParse->HavingClause)) {
+ $countSql.=" HAVING ".$this->oParse->HavingClause;
+ }
+ $countSql="SELECT COUNT(*) FROM (".$countSql.")";
+ if ($this->objDB->Dialect != "Oracle") {
+ $countSql.=" AS rico_Main";
+ }
+ if (count($this->allParams)>0) {
+ $rsMain=$this->objDB->RunParamQuery($countSql,$this->allParams);
+ } else {
+ $rsMain=$this->objDB->RunQuery($countSql);
+ }
+ if (!$rsMain) {
+ echo "\n<debug>getTotalRowCount: rsMain is null</debug>";
+ return;
+ }
+ if (!$this->objDB->db->FetchArray($rsMain,$a)) return;
+ $this->objDB->rsClose($rsMain);
+ $this->eof=true;
+ return $a[0];
+ }
+
+
+ function UnparseWithRowNumber($offset, $numrows, $includeAS) {
+ if (is_array($this->oParse->arOrderBy)) {
+ if (count($this->oParse->arOrderBy) > 0) {
+ $strOrderBy=implode(",",$this->oParse->arOrderBy);
+ }
+ }
+ if (empty($strOrderBy) && !preg_match("/\bjoin\b/",$this->oParse->FromClause)) {
+ // order by clause should be included in main sql select statement
+ // However, if it isn't, then use primary key as sort - assuming FromClause is a simple table name
+ $strOrderBy=$this->objDB->PrimaryKey($this->oParse->FromClause);
+ }
+ $unparseText="SELECT ROW_NUMBER() OVER (ORDER BY ".$strOrderBy.") AS rico_rownum,";
+ $unparseText.=$this->oParse->UnparseColumnListSkip($this->HiddenCols)." FROM ".$this->oParse->FromClause;
+ if (!empty($this->oParse->WhereClause)) {
+ $unparseText.=" WHERE ".$this->oParse->WhereClause;
+ }
+ if (is_array($this->oParse->arGroupBy)) {
+ if (count($this->oParse->arGroupBy) > 0) {
+ $unparseText.=" GROUP BY ".implode(",",$this->oParse->arGroupBy);
+ }
+ }
+ if (!empty($this->oParse->HavingClause)) {
+ $unparseText.=" HAVING ".$this->oParse->HavingClause;
+ }
+ $unparseText="SELECT * FROM (".$unparseText.")";
+ if ($includeAS) {
+ $unparseText.=" AS rico_Main";
+ }
+ $unparseText.=" WHERE rico_rownum > ".$offset." AND rico_rownum <= ".($offset + $numrows);
+ return $unparseText;
+ }
+
+ function Query2xmlRaw($rawsqltext, $offset, $numrows) {
+ if (count($this->allParams)>0) {
+ $rsMain=$this->objDB->RunParamQuery($rawsqltext,$this->allParams);
+ } else {
+ $rsMain=$this->objDB->RunQuery($rawsqltext);
+ }
+ if (!$rsMain) return;
+
+ $colcnt = $this->objDB->db->NumFields($rsMain);
+ $totcnt = $this->objDB->db->NumRows($rsMain);
+ //echo "<debug>Query2xmlRaw: NumRows=$totcnt</debug>";
+ if ($offset < $totcnt || $totcnt==-1) {
+ $this->objDB->db->Seek($rsMain,$offset);
+ switch ($this->fmt) {
+ case "json": $rowcnt=$this->WriteRowsJSON($rsMain, $numrows, 0); break;
+ default: $rowcnt=$this->WriteRowsXHTML($rsMain, $numrows, 0); break;
+ }
+ if ($totcnt < 0) {
+ $totcnt=$offset+$rowcnt;
+ while($this->objDB->db->FetchRow($rsMain,$row))
+ $totcnt++;
+ }
+ } else {
+ $totcnt=$offset;
+ }
+ $this->objDB->rsClose($rsMain);
+ $this->eof=true;
+ return $totcnt;
+ }
+
+ function Query2xmlRaw_Limit($rawsqltext, $offset, $numrows, $firstcol) {
+ if (count($this->allParams)>0) {
+ $rsMain=$this->objDB->RunParamQuery($rawsqltext,$this->allParams);
+ } else {
+ $rsMain=$this->objDB->RunQuery($rawsqltext);
+ }
+ //if ($this->objDB->db->HasError()) echo "<error>" . $this->objDB->db->ErrorMsg() . "</error>";
+ $totcnt=$offset;
+ $this->eof=true;
+ if (!$rsMain) return;
+ switch ($this->fmt) {
+ case "json": $totcnt+=$this->WriteRowsJSON($rsMain, $numrows, $firstcol); break;
+ default: $totcnt+=$this->WriteRowsXHTML($rsMain, $numrows, $firstcol); break;
+ }
+ $this->objDB->rsClose($rsMain);
+ return $totcnt;
+ }
+
+ function WriteRowsXHTML($rsMain, $numrows, $firstcol) {
+ $colcnt = $this->objDB->db->NumFields($rsMain);
+ $rowcnt=0;
+ if ($this->SendHdg) {
+ echo "\n<tr>";
+ for ($i=$firstcol; $i < $colcnt; $i++) {
+ $n=empty($this->Headings[$i-$firstcol]) ? $this->objDB->db->FieldName($rsMain,$i) : $this->Headings[$i-$firstcol];
+ print $this->XmlStringCell($n);
+ }
+ echo "</tr>";
+ }
+ while(($this->objDB->db->FetchRow($rsMain,$row)) && $rowcnt < $numrows) {
+ $rowcnt++;
+ print "\n<tr>";
+ for ($i=$firstcol; $i < $colcnt; $i++)
+ print $this->XmlStringCell($row[$i]);
+ print "</tr>";
+ }
+ $this->eof=($rowcnt < $numrows);
+ return $rowcnt;
+ }
+
+ function WriteRowsJSON($rsMain, $numrows, $firstcol) {
+ $colcnt = $this->objDB->db->NumFields($rsMain);
+ $rowcnt=0;
+ if ($this->SendHdg) {
+ echo "\n[";
+ for ($i=$firstcol; $i < $colcnt; $i++) {
+ //$n=empty($this->Headings($i-$firstcol)) ? $this->objDB->db->FieldName($rsMain,$i) : $this->Headings($i-$firstcol);
+ print json_encode($n);
+ }
+ echo "]";
+ }
+ while(($this->objDB->db->FetchRow($rsMain,$row)) && $rowcnt < $numrows) {
+ if ($rowcnt>0 || $this->SendHdg) echo ",";
+ $rowcnt++;
+ print "\n[";
+ for ($i=$firstcol; $i < $colcnt; $i++) {
+ if ($i>$firstcol) echo ",";
+ print json_encode($this->convertCharSet ? utf8_encode($row[$i]) : $row[$i]);
+ }
+ print "]";
+ }
+ $this->eof=($rowcnt < $numrows);
+ return $rowcnt;
+ }
+
+ function SetDbConn(&$dbcls) {
+ $this->objDB=&$dbcls;
+ }
+
+ function SetGridDefinition($def) {
+ $this->gridDefinition = $def;
+ }
+
+ function PushParam($newvalue) {
+ $parm=$this->convertCharSet ? utf8_decode($newvalue) : $newvalue;
+ if (get_magic_quotes_gpc()) $parm=stripslashes($parm);
+ array_push($this->arParams[$this->condType], $parm);
+ if ($this->sendDebugMsgs) {
+ echo "\n<debug>".$this->condType." param=".htmlspecialchars($parm)."</debug>";
+ }
+ }
+
+ function setCondType($selectItem) {
+ $this->condType=(preg_match("/\bmin\(|\bmax\(|\bsum\(|\bcount\(/i",$selectItem) && !preg_match("/\bselect\b/i",$selectItem)) ? 'H' : 'W';
+ }
+
+ function addCondition($newfilter) {
+ switch ($this->condType) {
+ case 'H': $this->oParse->AddHavingCondition($newfilter); break;
+ case 'W': $this->oParse->AddWhereCondition($newfilter); break;
+ }
+ }
+
+ function ApplyQStringParms($filters) {
+ foreach($_GET as $qs => $value) {
+ $prefix=substr($qs,0,1);
+ switch ($prefix) {
+
+ // user-invoked condition
+ case "w":
+ case "h":
+ $i=substr($qs,1);
+ if (!is_numeric($i)) break;
+ $i=intval($i);
+ if ($i<0 || $i>=count($filters)) break;
+ $newfilter=$filters[$i];
+ $this->condType=strtoupper($prefix);
+
+ $j=strpos($newfilter," in (?)");
+ if ($j !== false) {
+ $a=explode(",", $value);
+ for ($i=0; $i < count($a); $i++) {
+ $this->PushParam($a[$i]);
+ $a[$i]="?";
+ }
+ $newfilter=substr($newfilter,0,$j+4) . implode(",",$a) . substr($newfilter,$j+5);
+ } elseif (strpos($newfilter,"?") !== false) {
+ $this->PushParam($value);
+ }
+
+ $this->addCondition($newfilter);
+ break;
+
+ // sort
+ case "s":
+ $i=substr($qs,1);
+ if (!is_numeric($i)) break;
+ $i=intval($i);
+ if ($i<0 || $i>=count($this->oParse->arSelList)) break;
+ $value=strtoupper(substr($value,0,4));
+ if (!in_array($value,array('ASC','DESC'))) $value="ASC";
+ if ($this->orderByRef)
+ $this->oParse->AddSort(($i + 1)." ".$value);
+ else
+ $this->oParse->AddSort($this->oParse->arSelList[$i]." ".$value);
+ break;
+
+ // user-supplied filter
+ case "f":
+ //print_r($value);
+ foreach($value as $i => $filter) {
+ if ($i<0 || $i>=count($this->oParse->arSelList)) break;
+ switch ($this->objDB->Dialect) {
+ case "PostgreSQL":
+ if ($filter['op'] == 'LIKE' &&
+ array_key_exists($this->oParse->arSelList[$i], $this->gridDefinition['list']) &&
+ array_key_exists('sqltype', $this->gridDefinition['list'][$this->oParse->arSelList[$i]]) &&
+ in_array($this->gridDefinition['list'][$this->oParse->arSelList[$i]]['sqltype'], array('date','int'))) {
+ $newfilter=sprintf('cast(%s as varchar(100))', $this->oParse->arSelList[$i]);
+ } else
+ $newfilter=$this->oParse->arSelList[$i];
+ break;
+ default:
+ $newfilter=$this->oParse->arSelList[$i];
+ break;
+ }
+
+ $this->setCondType($newfilter);
+ switch ($filter['op']) {
+ case "EQ":
+ if ($this->objDB->Dialect == 'PostgreSQL' &&
+ array_key_exists($this->oParse->arSelList[$i], $this->gridDefinition['list']) &&
+ array_key_exists('sqltype', $this->gridDefinition['list'][$this->oParse->arSelList[$i]]) &&
+ in_array($this->gridDefinition['list'][$this->oParse->arSelList[$i]]['sqltype'], array('int')))
+ $newfilter='('.$this->AddCoalesce($newfilter,'0').' IN '.$this->GetMultiParmFilter($filter).')';
+ else
+ $newfilter='('.$this->AddCoalesce($newfilter).' IN '.$this->GetMultiParmFilter($filter).')';
+ break;
+ case "LE":
+ $newfilter.="<=?";
+ $this->PushParam($filter[0]);
+ break;
+ case "GE":
+ $newfilter.=">=?";
+ $this->PushParam($filter[0]);
+ break;
+ case "NULL": $newfilter.=" is null"; break;
+ case "NOTNULL": $newfilter.=" is not null"; break;
+ case "LIKE":
+ $newfilter.=" LIKE ?";
+ $this->PushParam(str_replace("*",$this->objDB->Wildcard,$filter[0]));
+ break;
+ case "NE":
+ if ($this->objDB->Dialect == 'PostgreSQL' &&
+ array_key_exists($this->oParse->arSelList[$i], $this->gridDefinition['list']) &&
+ array_key_exists('sqltype', $this->gridDefinition['list'][$this->oParse->arSelList[$i]]) &&
+ in_array($this->gridDefinition['list'][$this->oParse->arSelList[$i]]['sqltype'], array('int')))
+ $newfilter='('.$this->AddCoalesce($newfilter,0).' NOT IN '.$this->GetMultiParmFilter($filter).')';
+ else
+ $newfilter='('.$this->AddCoalesce($newfilter).' NOT IN '.$this->GetMultiParmFilter($filter).')';
+ break;
+ }
+ $this->addCondition($newfilter);
+ }
+ break;
+ }
+ }
+ }
+
+ function AddCoalesce($newfilter, $default=false) {
+ if ($this->objDB->Dialect=="Access") {
+ return "iif(IsNull(" . $newfilter . "),''," . $newfilter . ")";
+ } else {
+ return "coalesce(" . $newfilter . "," . ($default !== false ? $default : "''") . ")";
+ }
+ }
+
+
+ function GetMultiParmFilter($filter) {
+ $flen=$filter['len'];
+ if (!is_numeric($flen)) return "";
+ $flen=intval($flen);
+ $newfilter='(';
+ for ($j=0; $j<$flen; $j++) {
+ if ($j > 0) $newfilter.=",";
+ $newfilter.='?';
+ $this->PushParam($filter[$j]);
+ }
+ $newfilter.=')';
+ return $newfilter;
+ }
+
+ function XmlStringCell($value) {
+ if (!isset($value)) {
+ $result="";
+ }
+ else {
+ if ($this->convertCharSet) {
+ $value=utf8_encode($value);
+ $result=htmlspecialchars($value, ENT_COMPAT, 'UTF-8');
+ } else {
+ $result=htmlspecialchars($value);
+ }
+ }
+ if ($this->fmt=="html" && $result=="") $result=" ";
+ return "<td>".$result."</td>";
+ }
+
+ // for the root node, parentID should "" (empty string)
+ // containerORleaf: L/zero (leaf), C/non-zero (container)
+ // selectable: 0->not selectable, 1->selectable
+ function WriteTreeRow($parentID, $ID, $description, $containerORleaf, $selectable) {
+ echo "\n<tr>";
+ echo $this->XmlStringCell($parentID);
+ echo $this->XmlStringCell($ID);
+ echo $this->XmlStringCell($description);
+ echo $this->XmlStringCell($containerORleaf);
+ echo $this->XmlStringCell($selectable);
+ echo "</tr>";
+ }
+
+}
+
+?>
+
--- /dev/null
+/* \r
+ *Rico stylesheet\r
+ */\r
+\r
+/* reset Themeroller font size */ \r
+div.ui-widget {\r
+ font-size: 80%;\r
+}\r
+.ui-dialog {\r
+ width: auto !important;\r
+}\r
+\r
+/* LiveGrid & SimpleGrid */\r
+ \r
+.ricoLG_outerDiv {\r
+ position:relative;\r
+}\r
+\r
+div.ricoLG_innerDiv, div.ricoLG_frozenTabsDiv {\r
+ overflow:hidden;\r
+ margin:0px;\r
+ padding:0px;\r
+ position:relative;\r
+}\r
+\r
+div.ricoLG_scrollDiv {\r
+ overflow:scroll;\r
+ position:relative;\r
+}\r
+\r
+div.ricoLG_scrollContainerDiv {\r
+ position:relative;\r
+}\r
+\r
+div.ricoLG_scrollTabDiv {\r
+ position:absolute;\r
+ top:0px;\r
+ overflow:hidden;\r
+}\r
+\r
+div.ricoLG_resizeDiv {\r
+ position:absolute;\r
+ top:0px;\r
+ width:1px;\r
+ z-index:2;\r
+ background-color:blue;\r
+}\r
+\r
+div.ricoLG_highlightDiv {\r
+ position:absolute;\r
+ border: 2px solid black;\r
+}\r
+\r
+.ricoLG_table, .ricoLG_scrollTab, table.ricoLiveGrid {\r
+ margin: 0px;\r
+ padding: 0px;\r
+ border-right: 1px solid silver;\r
+ border-left-width: 0px; /* for dojo */\r
+}\r
+\r
+.ricoLG_FilterRow div.ricoLG_cell {\r
+ height:1.6em;\r
+ line-height: 1.6em;\r
+ white-space: nowrap;\r
+}\r
+.ricoLG_FilterRow div.ricoLG_cell * {\r
+ vertical-align: top;\r
+}\r
+.ricoLG_FilterRow select {\r
+ width:100%; \r
+}\r
+\r
+.ricoLG_FilterRow input, .ricoLG_FilterRow select, .ricoLG_FilterRow option {\r
+ font-weight: normal;\r
+ font-size: 90% !important;\r
+ padding: 1px;\r
+}\r
+\r
+div.ricoLG_mFilter {\r
+ position:absolute;\r
+ z-index:200;\r
+ border: 1px solid #888;\r
+}\r
+div.ricoLG_mFilter {\r
+ font-size: 67%;\r
+}\r
+div.ricoLG_mFilter_content {\r
+ height: 150px;\r
+ width: 100%;\r
+ overflow: auto;\r
+ background-color: white;\r
+}\r
+div.ricoLG_mFilter_button button{\r
+ font-size: 80%;\r
+}\r
+div.ricoLG_mFilter_button {\r
+ padding: 3px;\r
+ background-color: #DDD;\r
+}\r
+tr.ricoLG_mFilter_oddrow {\r
+ background-color: #EEE;\r
+}\r
+\r
+table.ricoLG_bottom {\r
+ border-top-style: none;\r
+}\r
+\r
+.ricoLG_selection { background-color: #cedebd; }\r
+\r
+div.ricoLG_col {\r
+ overflow:hidden;\r
+ width:100px;\r
+}\r
+\r
+thead.ricoLG_top div.ricoLG_col {\r
+ position:relative;\r
+}\r
+\r
+thead.ricoLG_top div.ricoLG_Resize {\r
+ position:absolute;\r
+ width:5px;\r
+ height:100%;\r
+ top:0px;\r
+ cursor:e-resize;\r
+}\r
+\r
+.ricoLG_bottom div.ricoLG_cell {\r
+ border-style: solid;\r
+ border-color: silver;\r
+ border-width: 0px 0px 1px 0px;\r
+}\r
+\r
+table.ricoLG_table, table.ricoLiveGrid {\r
+ border-top: 1px solid silver;\r
+}\r
+\r
+thead.ricoLG_top th, thead.ricoLG_top td, table.ricoLiveGrid td, table.ricoLiveGrid th {\r
+ border-style: solid;\r
+ border-color: silver;\r
+ border-width: 0px 0px 1px 1px;\r
+ *position: relative; /* IE6-7 only */\r
+}\r
+\r
+.ricoLG_bottom th, .ricoLG_bottom td {\r
+ border-style: solid;\r
+ border-color: silver;\r
+ border-width: 0px 0px 0px 1px;\r
+}\r
+\r
+div.ricoLG_cell, table.ricoLiveGrid td, table.ricoLiveGrid th {\r
+ overflow:hidden;\r
+ height:1.2em;\r
+ padding-left: 3px;\r
+ margin: 0px;\r
+ font-size: 80%;\r
+ padding-top:3px;\r
+ padding-bottom:3px;\r
+}\r
+\r
+.ricoLG_messageDiv {\r
+ font-weight:bold;\r
+ font-size:larger;\r
+ text-align:center;\r
+ padding:1em;\r
+ background-color: #EEE;\r
+ opacity:0.8;\r
+}\r
+\r
+p.ricoBookmark {\r
+ margin-bottom: 3px;\r
+ font-size: 80%;\r
+ white-space: nowrap;\r
+}\r
+\r
+p.ricoBookmark span {\r
+ margin-right: 1em;\r
+}\r
+\r
+span.ricoCaption {\r
+ font-weight: bold;\r
+}\r
+\r
+span.ricoSessionTimer {\r
+ background-color:black;\r
+ color:white;\r
+}\r
+\r
+/* grid column chooser */\r
+\r
+div.ricoLG_chooserDiv {\r
+ z-index:200;\r
+}\r
+div.ricoLG_chooserDiv .ricoContent {\r
+ height: 13em;\r
+ width: 16em;\r
+}\r
+.ricoContent {\r
+ padding: 3px;\r
+ overflow: auto;\r
+}\r
+div.ricoLG_chooserDiv .ricoContent div {\r
+ border-bottom: 1px solid #CCC;\r
+}\r
+div.ricoLG_chooserDiv .ricoContent input {\r
+ margin-right: 0.5em;\r
+}\r
+\r
+/* grid keyword entry */\r
+\r
+div.ricoLG_chooserDiv, div.ricoLG_keywordDiv {\r
+ font-size: smaller;\r
+}\r
+div.ricoLG_keywordDiv {\r
+ position:absolute;\r
+ z-index:200;\r
+ width: 250px;\r
+}\r
+\r
+div.ricoLG_keywordDiv input {\r
+ position: relative;\r
+ font-size: 90%;\r
+ float: left;\r
+}\r
+\r
+\r
+/* LiveGrid Forms */\r
+\r
+span.ricoSaveMsg {\r
+ background-color:yellow;\r
+}\r
+\r
+span.ricoSessionTimer {\r
+ background-color:black;\r
+ color:white;\r
+}\r
+\r
+div.ricoLG_editResponseDiv {\r
+ color:#000; background:#E8ECF3;\r
+ overflow:auto;\r
+ padding:8px;\r
+ border: 1px solid navy;\r
+ position:absolute;\r
+ z-index:300;\r
+ top:0px;\r
+ left:0px;\r
+ font-size: 85%;\r
+}\r
+\r
+form .ricoEditLabel sup {\r
+ font-size: smaller;\r
+}\r
+\r
+form .ricoEditLabel {\r
+ font-weight: bold;\r
+ text-align: left;\r
+ padding-right: 1em;\r
+}\r
+\r
+.ricoLG_editDiv a.RicoButton {\r
+ text-decoration: none;\r
+ padding: 0.3em 1em;\r
+ margin-right: 6px;\r
+}\r
+\r
+.ricoLG_editDiv div.ButtonBar {\r
+ padding: 0.4em 0px;\r
+ margin: 3px;\r
+}\r
+\r
+.ricoLG_editDiv form {\r
+ margin:0px;\r
+}\r
+\r
+.ricoLG_editDiv textarea {\r
+ font-size: 100%;\r
+}\r
+\r
+.ricoLG_editDiv .tabContent, div.ricoLG_editDiv .noTabContent {\r
+ overflow: hidden;\r
+ padding: 4px;\r
+ white-space:nowrap;\r
+}\r
+\r
+\r
+/* shadows */\r
+.ricoShadow {\r
+ -moz-box-shadow: 3px 3px 4px #888;\r
+ -webkit-box-shadow: 3px 3px 4px #888;\r
+ box-shadow: 3px 3px 4px #888;\r
+ /* For IE 8 */\r
+ -ms-filter: "progid:DXImageTransform.Microsoft.Shadow(Strength=5, Direction=135, Color='#aaaaaa')";\r
+ /* For IE 5.5 - 7 */\r
+ filter: progid:DXImageTransform.Microsoft.Shadow(Strength=5, Direction=135, Color='#aaaaaa');\r
+}\r
+\r
+\r
+/* ricoMenu */\r
+\r
+div.ricoMenu, div.ricoMenuSafari {\r
+border:1px solid #666;\r
+padding:2px;\r
+cursor:default;\r
+font-family:tahoma,arial,helvetica,sans-serif;\r
+font-size: 70%;\r
+}\r
+\r
+div.ricoMenu, div.ricoMenu a {\r
+background-color:menu;\r
+color: menutext;\r
+text-decoration: none;\r
+display:block;\r
+}\r
+\r
+div.ricoMenuSafari, div.ricoMenuSafari a {\r
+background-color:#EDEDED;\r
+text-decoration: none;\r
+display:block;\r
+}\r
+\r
+div.ricoMenu div.ricoMenuHeading{\r
+padding: 1px 0px;\r
+font-weight:bold;\r
+}\r
+\r
+div.ricoMenuSafari div.ricoMenuHeading{\r
+padding: 1px 0px;\r
+color: black;\r
+display: block;\r
+font-weight:bold;\r
+}\r
+\r
+div.ricoMenu .enabled {\r
+position: relative;\r
+}\r
+\r
+div.ricoMenuSafari .enabled {\r
+color: black;\r
+}\r
+\r
+div.ricoMenu .enabled, div.ricoMenu .enabled-hover, div.ricoMenuSafari .enabled, div.ricoMenuSafari .enabled-hover, div.ricoMenu .disabled, div.ricoMenuSafari .disabled {\r
+padding-left: 1em;\r
+padding-top:0.1em;\r
+padding-bottom:0.1em;\r
+z-index: 101;\r
+}\r
+\r
+div.ricoMenu .disabled, div.ricoMenuSafari .disabled {\r
+color: #999;\r
+}\r
+\r
+div.ricoMenu hr{\r
+height:1px;\r
+margin:1px;\r
+border:0;\r
+color: menu;\r
+background-color: menu;\r
+}\r
+\r
+div.ricoMenu .enabled-hover, div.ricoMenu .ricoSubMenuOpen {\r
+ background-color: Highlight;\r
+ color: HighlightText;\r
+}\r
+\r
+div.ricoMenuSafari .enabled-hover, div.ricoMenuSafari .ricoSubMenuOpen {\r
+ background-color: #1657B8;\r
+ color: white;\r
+}\r
+\r
+div.ricoMenu .ricoSubMenu, div.ricoMenu .ricoSubMenuOpen, div.ricoMenuSafari .ricoSubMenu, div.ricoMenuSafari .ricoSubMenuOpen {\r
+padding: 1px 0px;\r
+display: block;\r
+font-weight:bold;\r
+z-index: 101;\r
+position: relative;\r
+}\r
+\r
+div.ricoMenu div.ricoMenuBreak, div.ricoMenuSafari div.ricoMenuBreak {\r
+height:1px;\r
+margin:3px 0 3px 0;\r
+padding:0;\r
+background-color: #AAA;\r
+width:100%;\r
+line-height:5px;\r
+overflow:hidden;\r
+}\r
+\r
+a.RicoButton {\r
+ -moz-border-radius: 6px;\r
+ -webkit-border-radius: 6px;\r
+ border-radius: 6px;\r
+}\r
+\r
+\r
+/* Rico.Window */\r
+\r
+\r
+.ricoTitle {\r
+ padding: 3px;\r
+ cursor: move;\r
+}\r
+\r
+.ricoTitleSpan {\r
+ margin-right: 25px;\r
+ white-space: nowrap;\r
+}\r
+\r
+a.RicoButtonAnchorNative {\r
+ background-color: #DDD;\r
+ border: 1px outset;\r
+}\r
+a.RicoButtonAnchorNative span {\r
+ vertical-align: middle;\r
+}\r
+a.RicoButtonAnchor {\r
+ padding: 1px;\r
+ margin: 0px 3px;\r
+ cursor: pointer;\r
+ font-size: 16px;\r
+}\r
+a.RicoButtonAnchor span {\r
+ display: inline-block;\r
+}\r
+\r
+a.RicoButtonAnchorNative:hover {\r
+ border:1px solid #666;\r
+ background-color: #CCC;\r
+}\r
+\r
+* html .ui-dialog-titlebar .ui-dialog-titlebar-close {\r
+ top: 16px; /* required by IE6 */\r
+}\r
+\r
+.ricoLG_cell .ui-icon {\r
+ text-indent: 0px !important;\r
+}\r
+\r
+\r
+\r
+/* ricoKeywordSearch */\r
+.ricoKeywordSearch {\r
+ font-size: 70%;\r
+}\r
+\r
+\r
+/* ricoTree */\r
+\r
+.ricoTreeContainer {\r
+ background-color:#cedebd;\r
+ border:1px solid black;\r
+ padding:4px;\r
+}\r
+\r
+.ricoTree td {\r
+ padding: 0px;\r
+}\r
+\r
+.ricoTree {\r
+ border:thin inset;\r
+ overflow:auto;\r
+ background-color:#FFF;\r
+}\r
+\r
+.ricoTree p, .ricoTree a {\r
+ margin:0px;\r
+ padding-left:0.3em;\r
+ white-space:nowrap;\r
+}\r
+\r
+.ricoTree a {\r
+ cursor:pointer;\r
+ text-decoration:none;\r
+}\r
+\r
+.ricoTree img {\r
+ margin:0px;\r
+ padding:0px;\r
+ display:block;\r
+}\r
+\r
+.ricoTreeContainer {\r
+ font-size:70%;\r
+ white-space:nowrap;\r
+}\r
+\r
+.ricoTreeButtons {\r
+ height:1.1em;\r
+}\r
+\r
+.ricoTreeButtons span:hover {\r
+ background-color:#deeecd;\r
+}\r
+\r
+\r
+/* ricoCalendar */\r
+\r
+.ricoCalContainer {\r
+ font-size:85%;\r
+ background-color:#eee;\r
+}\r
+.ricoCalBody {\r
+ font-size:70%;\r
+}\r
+.ricoCalMonthPrompt {\r
+ font-size:95%;\r
+}\r
+.ricoCalYearPrompt p {\r
+ font-size:70%;\r
+}\r
+\r
+td.RicoCalHeading {\r
+ text-align: left;\r
+ padding: 0px !important;\r
+}\r
+* html td.RicoCalHeading {\r
+ position: static !important; /* override Themeroller */\r
+}\r
+* html td.RicoCalHeading table {\r
+ float: left;\r
+}\r
+* html td.RicoCalHeading .RicoCloseAnchor {\r
+ position: static;\r
+ float: right;\r
+}\r
+\r
+.ui-datepicker td.RicoCalHeading table{\r
+ width: auto;\r
+ margin: 0px 2em !important;\r
+}\r
+.ricoCalContainer td.RicoCalHeading table{\r
+ width: auto;\r
+ margin: 2px 2em 0px 2em;\r
+}\r
+td.RicoCalHeading td {\r
+ padding: 0.2em 0px;\r
+}\r
+td.RicoCalHeading {\r
+ font-size:90%;\r
+}\r
+td.RicoCalHeading table a {\r
+ text-decoration: none;\r
+ font-weight: bold !important;\r
+ margin: 0px !important;\r
+ text-align: center;\r
+ border: 0px none !important;\r
+ font-family: "Lucida Console", Courier, "Courier New", monospace;\r
+}\r
+\r
+.ui-datepicker-header span {\r
+ text-indent: 0px !important;\r
+ padding: 0px !important;\r
+}\r
+\r
+.ricoCalContainer .ricoCalBody td.ricoSelectedDay {\r
+ font-weight:bold;\r
+ background-color: #FFFF66 !important;\r
+}\r
+\r
+.ricoCalContainer tbody td.hover {\r
+ background-color: #FDD;\r
+}\r
+\r
+span.Rico_leftArrow {\r
+ background-position: -10px -1046px;\r
+ display: inline-block;\r
+ width: 10px;\r
+ height: 11px;\r
+}\r
+\r
+.ui-datepicker a.Rico_leftArrow, .ui-datepicker a.Rico_rightArrow {\r
+ display: inline-block;\r
+ width: 16px;\r
+ height: 16px;\r
+}\r
+\r
+.ricoCalContainer a.Rico_leftArrow, .ricoCalContainer a.Rico_rightArrow {\r
+ display: inline-block;\r
+ width: 16px;\r
+ height: 14px;\r
+}\r
+\r
+span.Rico_rightArrow {\r
+ background-position: -10px -1108px;\r
+ display: inline-block;\r
+ width: 10px;\r
+ height: 11px;\r
+}\r
+\r
+.ui-datepicker-header a.ui-dialog-titlebar-close {\r
+ top: 2px;\r
+}\r
+\r
+div.ricoCalYearPrompt {\r
+ margin: 0px;\r
+ padding: 3px;\r
+ border:1px solid #666666;\r
+ background-color: #FEE;\r
+}\r
+\r
+.ricoCalYearPrompt p {\r
+ margin: 0px;\r
+ padding: 3px;\r
+}\r
+\r
+.ricoCalYearPrompt img {\r
+ border: 1px solid black;\r
+ margin-left: 3px;\r
+ vertical-align: middle;\r
+}\r
+\r
+.ricoCalFoot td {\r
+ font-size:75% !important;\r
+ text-align:center;\r
+ padding: 2px;\r
+ text-decoration: underline;\r
+ cursor:pointer;\r
+}\r
+\r
+td.ricoCalFoot {\r
+ color:#FFF;\r
+ background-color: #666666;\r
+}\r
+\r
+tr.ricoCalDayNames td {\r
+ font-weight: bold;\r
+/* padding: 0px 2px 0px 2px;*/\r
+ padding: 0px !important;\r
+ text-align:right;\r
+}\r
+\r
+.ricoCalBody td {\r
+ width:2.7em;\r
+}\r
+\r
+td.ricoCal0, td.ricoCal1, td.ricoCal2, td.ricoCal3, td.ricoCal4, td.ricoCal5, td.ricoCal6, td.ricoCalToday {\r
+ text-align:right;\r
+ text-decoration:none;\r
+}\r
+\r
+td.ricoCal0, td.ricoCal1, td.ricoCal2, td.ricoCal3, td.ricoCal4, td.ricoCal5, td.ricoCal6 {\r
+ cursor:pointer;\r
+/* padding-right: 2px !important;*/\r
+ padding: 0px;\r
+}\r
+\r
+/* Monday-Friday */\r
+.ricoCalContainer td.ricoCal1, .ricoCalContainer td.ricoCal2, .ricoCalContainer td.ricoCal3, .ricoCalContainer td.ricoCal4, .ricoCalContainer td.ricoCal5 {\r
+ color:black;\r
+ background-color:#fff;\r
+}\r
+\r
+/* Sunday, Saturday */\r
+.ricoCalContainer td.ricoCal0, .ricoCalContainer td.ricoCal6 {\r
+ color:#999;\r
+ background-color:#fff;\r
+}\r
+\r
+td.ricoCalToday {\r
+ cursor:pointer;\r
+ color:red;\r
+ font-weight:bold;\r
+}\r
+\r
+.ricoCalContainer .ricoCalBody td.ricoCalToday {\r
+ background-color: #33FFFF;\r
+}\r
+\r
+td.ricoCalWeekNum {\r
+ background-color: #D4D0C8;\r
+ color:black;\r
+ text-align:center;\r
+}\r
+\r
+.ricoCalMenu {\r
+ width:12em;\r
+ background-color: #FEE;\r
+ border-bottom:1px solid #666666;\r
+ border-right:1px solid #666666;\r
+}\r
+\r
+.ricoCalMenu td {\r
+ border-top:1px solid #666666;\r
+ border-left:1px solid #666666;\r
+}\r
+\r
+.ricoCalMenu a {\r
+ display:block;\r
+ text-decoration:none;\r
+ cursor:pointer;\r
+ font-size:70%;\r
+ text-align: center !important;\r
+ color:black;\r
+}\r
+\r
+.ricoCalMenu a:hover {\r
+ background-color: #FCC;\r
+}\r
+\r
+\r
+/* ricoColorPicker */\r
+\r
+div.ricoColorPicker {\r
+ background-color: white;\r
+}\r
+\r
+div.ricoColorPicker td {\r
+ width: 12px;\r
+ height: 12px;\r
+ font-size: 60%;\r
+}\r
+\r
+/* tabbed panels and accordion */\r
+\r
+.Rico_tabNavContainer {\r
+ display:block;\r
+ margin:0px;\r
+ padding: 0px;\r
+}\r
+\r
+.Rico_tabTitle {\r
+ float: left;\r
+ margin-left: 1px;\r
+ margin-right: 1px;\r
+ margin-bottom: 0px;\r
+ display: inline;\r
+}\r
+.Rico_tabContent, .Rico_accContent {\r
+ padding: 1em;\r
+}\r
+.Rico_accContent {\r
+ overflow: auto;\r
+}\r
+.Rico_tabContentContainer {\r
+ clear:both;\r
+}\r
+.Rico_tabNavContainer .hover, .Rico_accTitle {\r
+ cursor: pointer;\r
+}\r
+\r
+div.ricoCorner {\r
+ position: absolute;\r
+}\r
+div.ricoCorner div {\r
+ line-height: 1px;\r
+ font-size:1px;\r
+ overflow: hidden;\r
+}\r
+\r
+* html .Rico_tabPanel {\r
+ height: 1%;\r
+ position: relative;\r
+}\r
+\r
+* html .ui-tabs {\r
+ position: relative;\r
+}\r
+\r
+* html .Rico_tabNavContainer {\r
+ height: 1%;\r
+ position: relative;\r
+}\r
+\r
+.rico-calarrow {\r
+ width: 37px;\r
+ height: 18px;\r
+ display: inline-block;\r
+ background-position: -10px -10px;\r
+}\r
+.rico-calendaricon {\r
+ width: 17px;\r
+ height: 17px;\r
+ display: inline-block;\r
+ background-position: -10px -48px;\r
+}\r
+.rico-close-b {\r
+ background-position: -10px -122px;\r
+}\r
+.rico-close-w {\r
+ background-position: -10px -155px;\r
+}\r
+.rico-delete-b {\r
+ background-position: -10px -188px;\r
+}\r
+.rico-delete-w {\r
+ background-position: -10px -225px;\r
+}\r
+.rico-doc {\r
+ background-position: -10px -262px;\r
+}\r
+.rico-dotbutton {\r
+ width: 17px;\r
+ height: 17px;\r
+ display: inline-block;\r
+ background-position: -10px -304px;\r
+}\r
+.rico-drop {\r
+ background-position: -10px -341px;\r
+}\r
+.rico-folderclosed {\r
+ width: 24px;\r
+ height: 22px;\r
+ display: block;\r
+ background-position: -10px -403px;\r
+}\r
+.rico-folderopen {\r
+ width: 24px;\r
+ height: 22px;\r
+ display: block;\r
+ background-position: -10px -445px;\r
+}\r
+.rico-info {\r
+ width: 15px;\r
+ height: 15px;\r
+ display: inline-block;\r
+ background-position: -10px -487px;\r
+}\r
+.rico-link {\r
+ background-position: -10px -522px;\r
+}\r
+.rico-tree-m {\r
+ width: 16px;\r
+ height: 22px;\r
+ display: block;\r
+ background-position: -10px -564px;\r
+}\r
+.rico-tree-node {\r
+ width: 16px;\r
+ height: 22px;\r
+ display: block;\r
+ background-position: -10px -606px;\r
+}\r
+.rico-tree-nodelast {\r
+ width: 16px;\r
+ height: 22px;\r
+ display: block;\r
+ background-position: -10px -648px;\r
+}\r
+.rico-tree-nodeline {\r
+ width: 16px;\r
+ height: 22px;\r
+ display: block;\r
+ background-position: -10px -690px;\r
+}\r
+.rico-tree-nodem {\r
+ width: 16px;\r
+ height: 22px;\r
+ display: block;\r
+ background-position: -10px -732px;\r
+}\r
+.rico-tree-nodemlast {\r
+ width: 16px;\r
+ height: 22px;\r
+ display: block;\r
+ background-position: -10px -774px;\r
+}\r
+.rico-tree-nodep {\r
+ width: 16px;\r
+ height: 22px;\r
+ display: block;\r
+ background-position: -10px -816px;\r
+}\r
+.rico-tree-nodeplast {\r
+ width: 16px;\r
+ height: 22px;\r
+ display: block;\r
+ background-position: -10px -858px;\r
+}\r
+.rico-tree-p {\r
+ width: 16px;\r
+ height: 22px;\r
+ display: block;\r
+ background-position: -10px -900px;\r
+}\r
+.rico-tree-nodeblank {\r
+ width: 16px;\r
+ height: 22px;\r
+ display: block;\r
+ background: none !important;\r
+}\r
+.rico-removeFilter {\r
+ background-position: -10px -942px;\r
+}\r
+.rico-FilterCollapse {\r
+ background-position: -10px -974px;\r
+}\r
+.rico-FilterExpand {\r
+ background-position: -10px -1010px;\r
+}\r
+.rico-left-b {\r
+ background-position: -10px -1046px;\r
+ width: 10px;\r
+ height: 11px;\r
+}\r
+.rico-left-w {\r
+ background-position: -10px -1077px;\r
+ width: 10px;\r
+ height: 11px;\r
+}\r
+.rico-right-b {\r
+ background-position: -10px -1108px;\r
+ width: 10px;\r
+ height: 11px;\r
+}\r
+.rico-right-w {\r
+ background-position: -10px -1139px;\r
+ width: 10px;\r
+ height: 11px;\r
+}\r
+\r
+.ricoLG_filterCol {\r
+ margin: 0px 2px;\r
+ width: 13px;\r
+ height: 12px;\r
+ background-position: -10px -371px;\r
+}\r
+.ricoLG_sortAsc {\r
+ margin: 0px 2px;\r
+ width: 11px;\r
+ height: 11px;\r
+ background-position: -10px -1168px;\r
+}\r
+.ricoLG_sortDesc {\r
+ margin: 0px 2px;\r
+ width: 11px;\r
+ height: 11px;\r
+ background-position: -10px -1198px;\r
+}\r
+\r
+.ricoClearNative {\r
+ width: 17px;\r
+ height: 17px;\r
+ background-position: -10px -186px;\r
+}\r
+\r
+a span {\r
+ cursor: pointer;\r
+}\r
+\r
+span.ricoClear {\r
+ display:-moz-inline-box;\r
+ display:inline-block;\r
+ cursor: pointer;\r
+}\r
+\r
+span.RicoCheckmark {\r
+ display: inline-block;\r
+ height: 17px;\r
+ width: 17px;\r
+ background-position: -10px -85px;\r
+}\r
+\r
+span.RicoCancel {\r
+ display: inline-block;\r
+ height: 17px;\r
+ width: 17px;\r
+ background-position: -10px -188px;\r
+}\r
+\r
+\r
+.RicoCloseAnchor {\r
+ cursor: pointer;\r
+ position: absolute;\r
+ display: block;\r
+ top: 5px;\r
+ right: 2px;\r
+ border: 0px none !important;\r
+}\r
+span.RicoClose {\r
+ display: block;\r
+ height: 15px;\r
+ width: 16px;\r
+ background-position: -10px -122px;\r
+}\r
+\r
+/* ie6 only */\r
+* html iframe.RicoShim {\r
+ position: absolute;\r
+ display:block;\r
+ top: 0px;\r
+ left: 0px;\r
+ width: expression( this.previousSibling.offsetWidth+'px' );\r
+ height: expression( this.previousSibling.offsetHeight+'px' );\r
+ z-index: 1;\r
+}\r
--- /dev/null
+.ricoLG_Resize {
+ background-repeat: repeat;
+ background-image: url('../../ricoClient/images/resize.gif');
+}
+.rico-icon {
+ background-repeat: no-repeat;
+ background-image: url('../../ricoClient/images/ricoIcons.gif');
+}
--- /dev/null
+div.ricoLG_evenRow { background-color: #ffffff; }\r
+div.ricoLG_oddRow { background-color: #F9FAFB; }\r
+.ricoLG_bottom div.ui-state-hover {\r
+ border-left: none;\r
+ border-top: none;\r
+ border-right: none;\r
+}\r
--- /dev/null
+/**
+ * Copyright (c) 2009-2011 Matt Brown
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this
+ * file except in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the specific language governing permissions
+ * and limitations under the License.
+ **/
+
+if (typeof jQuery=='undefined') throw('This version of Rico requires the jQuery library');
+
+var Rico = {
+ Lib: 'jQuery',
+ LibVersion: jQuery().jquery,
+ extend: jQuery.extend,
+ trim: jQuery.trim,
+ tryFunctions: function() {
+ for (var i=0; i<arguments.length; i++) {
+ try {
+ return arguments[i]();
+ } catch(e){}
+ }
+ return null;
+ },
+
+ _j: function(element) {
+ if (typeof element=='string')
+ element = document.getElementById(element);
+ return jQuery(element);
+ },
+
+ select: function(selector, element) {
+ return element ? this._j(element).find(selector) : jQuery(selector);
+ },
+
+ eventBind: function(element, eventName, handler) {
+ this._j(element).bind(eventName, handler);
+ },
+
+ eventUnbind: function(element, eventName, handler) {
+ this._j(element).unbind(eventName, handler);
+ },
+
+ eventHandle: function(object, method) {
+ return function(e) {
+ return object[method].call(object,e);
+ }
+ },
+
+ eventElement: function(ev) {
+ return ev.target;
+ },
+
+ eventClient: function(ev) {
+ return {x:ev.clientX, y:ev.clientY};
+ },
+
+ eventStop: function(ev) {
+ ev.preventDefault();
+ ev.stopPropagation();
+ },
+
+ addClass: function(element, className) {
+ var j=this._j(element);
+ if (!j.hasClass(className)) j.addClass(className);
+ return j;
+ },
+
+ removeClass: function(element, className) {
+ return this._j(element).removeClass(className);
+ },
+
+ hasClass: function(element, className) {
+ return this._j(element).hasClass(className);
+ },
+
+ getStyle: function(element, property) {
+ return this._j(element).css(property);
+ },
+ setStyle: function(element, properties) {
+ return this._j(element).css(properties);
+ },
+
+ /**
+ * @returns available height, excluding scrollbar & margin
+ */
+ windowHeight: function() {
+ return jQuery(window).height();
+ },
+
+ /**
+ * @returns available width, excluding scrollbar & margin
+ */
+ windowWidth: function() {
+ return jQuery(window).width();
+ },
+
+ positionedOffset: function(element) {
+ return this._j(element).position();
+ },
+
+ cumulativeOffset: function(element) {
+ return this._j(element).offset();
+ },
+
+ docScrollLeft: function() {
+ return jQuery('html').scrollLeft();
+ },
+
+ docScrollTop: function() {
+ return jQuery('html').scrollTop();
+ },
+
+ getDirectChildrenByTag: function(element, tagName) {
+ return this._j(element).children(tagName);
+ },
+
+ toQueryString: jQuery.param,
+
+ // Animation
+
+ fadeIn: function(element,duration,onEnd) {
+ this._j(element).fadeIn(duration,onEnd);
+ },
+
+ fadeOut: function(element,duration,onEnd) {
+ this._j(element).fadeOut(duration,onEnd);
+ },
+
+ animate: function(element,options,properties) {
+ options.complete=options.onEnd;
+ this._j(element).animate(properties,options);
+ },
+
+ getJSON: jQuery.httpData ? function(xhr) { return jQuery.httpData(xhr,'json'); } : function(xhr) { return jQuery.parseJSON(xhr.responseText); },
+
+ ajaxRequest: function(url,options) {
+ this.jSend(url,options);
+ }
+};
+
+Rico.ajaxRequest.prototype = {
+ jSend: function(url,options) {
+ this.onSuccess=options.onSuccess;
+ var self=this;
+ var jOptions = {
+ complete : options.onComplete,
+ error: options.onFailure,
+ success: function() { self.jSuccess(); },
+ type : options.method.toUpperCase(),
+ url : url,
+ data : options.parameters
+ }
+ this.xhr=jQuery.ajax(jOptions);
+ },
+
+ jSuccess: function() {
+ if (this.onSuccess) this.onSuccess(this.xhr);
+ }
+};
+
+Rico.ajaxSubmit=function(form,url,options) {
+ options.parameters=this._j(form).serialize();
+ if (!options.method) options.method='post';
+ url=url || form.action;
+ new Rico.ajaxRequest(url,options);
+};
--- /dev/null
+/*\r
+ * (c) 2005-2009 Richard Cowin (http://openrico.org)\r
+ * (c) 2005-2009 Matt Brown (http://dowdybrown.com)\r
+ *\r
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this\r
+ * file except in compliance with the License. You may obtain a copy of the License at\r
+ *\r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software distributed under the\r
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,\r
+ * either express or implied. See the License for the specific language governing permissions\r
+ * and limitations under the License.\r
+ */\r
+ \r
+// Connects Rico to jQuery Themeroller css classes\r
+\r
+ Rico.theme = {\r
+ gridheader: 'ui-widget-header',\r
+ gridcontent:'ui-widget-content',\r
+ gridMessage:'ui-state-highlight ui-corner-all',\r
+ sortAsc:'ui-icon ui-icon-triangle-1-n',\r
+ sortDesc:'ui-icon ui-icon-triangle-1-s',\r
+ hover:'ui-state-hover',\r
+ selected:'ui-state-active',\r
+ button:'ui-state-default ui-corner-all',\r
+ gridHighlightClass:'ui-state-hover',\r
+ accordion:'ui-accordion ui-widget ui-helper-reset',\r
+ accTitle:'ui-accordion-header ui-helper-reset ui-state-default',\r
+ accContent:'ui-accordion-content ui-helper-reset ui-widget-content',\r
+ tabPanel:'ui-tabs ui-widget ui-widget-content ui-helper-clearfix',\r
+ tabNavContainer:'ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header',\r
+ tabTitle:'ui-state-default',\r
+ tabContent:'ui-tabs-panel ui-widget-content ui-corner-bottom',\r
+ tabCornerOptions: {corners:'top',nativeCorners:true},\r
+ tabSelected:'ui-tabs-selected ui-state-active',\r
+ calendar:'ui-datepicker ui-widget-content',\r
+ calendarHeading:'ui-datepicker-header ui-widget-header',\r
+ calendarSubheading:'ui-datepicker-title',\r
+ calendarTable:'ui-datepicker-calendar',\r
+ calendarDay:'ui-state-default',\r
+ calendarFooter:'ui-widget-footer',\r
+ calendarToday:'ui-state-highlight',\r
+ calendarSelectedDay:'ui-state-active',\r
+ calendarPopdown:'ui-widget-content',\r
+ tree:'ui-widget ui-widget-content',\r
+ treeContent:'ui-widget-content',\r
+ leftArrow:'ui-icon ui-icon-circle-triangle-w',\r
+ rightArrow:'ui-icon ui-icon-circle-triangle-e',\r
+ leftArrowAnchor:'ui-datepicker-prev',\r
+ rightArrowAnchor:'ui-datepicker-next',\r
+ dialog:'ui-dialog ui-widget ui-widget-content ui-draggable',\r
+ dialogTitle:'ui-dialog-titlebar ui-widget-header',\r
+ dialogContent:'ui-widget-content',\r
+ buttonAnchor:'ui-state-default',\r
+ checkmark:'ui-icon ui-icon-check',\r
+ closeAnchor:'ui-dialog-titlebar-close',\r
+ cancel:'ui-icon ui-icon-close',\r
+ clear:'ui-icon ui-icon-close',\r
+ close:'ui-icon ui-icon-closethick'\r
+}\r
--- /dev/null
+/*!
+ * jQuery UI CSS Framework 1.8.24
+ *
+ * Copyright 2012, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Theming/API
+ */
+
+/* Layout helpers
+----------------------------------*/
+.ui-helper-hidden { display: none; }
+.ui-helper-hidden-accessible { position: absolute !important; clip: rect(1px 1px 1px 1px); clip: rect(1px,1px,1px,1px); }
+.ui-helper-reset { margin: 0; padding: 0; border: 0; outline: 0; line-height: 1.3; text-decoration: none; font-size: 100%; list-style: none; }
+.ui-helper-clearfix:before, .ui-helper-clearfix:after { content: ""; display: table; }
+.ui-helper-clearfix:after { clear: both; }
+.ui-helper-clearfix { zoom: 1; }
+.ui-helper-zfix { width: 100%; height: 100%; top: 0; left: 0; position: absolute; opacity: 0; filter:Alpha(Opacity=0); }
+
+
+/* Interaction Cues
+----------------------------------*/
+.ui-state-disabled { cursor: default !important; }
+
+
+/* Icons
+----------------------------------*/
+
+/* states and images */
+.ui-icon { display: block; text-indent: -99999px; overflow: hidden; background-repeat: no-repeat; }
+
+
+/* Misc visuals
+----------------------------------*/
+
+/* Overlays */
+.ui-widget-overlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; }
+
+
+/*!
+ * jQuery UI CSS Framework 1.8.24
+ *
+ * Copyright 2012, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Theming/API
+ *
+ * To view and modify this theme, visit http://jqueryui.com/themeroller/?ffDefault=Lucida%20Grande,%20Lucida%20Sans,%20Arial,%20sans-serif&fwDefault=bold&fsDefault=1.1em&cornerRadius=6px&bgColorHeader=deedf7&bgTextureHeader=03_highlight_soft.png&bgImgOpacityHeader=100&borderColorHeader=aed0ea&fcHeader=222222&iconColorHeader=72a7cf&bgColorContent=f2f5f7&bgTextureContent=04_highlight_hard.png&bgImgOpacityContent=100&borderColorContent=dddddd&fcContent=362b36&iconColorContent=72a7cf&bgColorDefault=d7ebf9&bgTextureDefault=02_glass.png&bgImgOpacityDefault=80&borderColorDefault=aed0ea&fcDefault=2779aa&iconColorDefault=3d80b3&bgColorHover=e4f1fb&bgTextureHover=02_glass.png&bgImgOpacityHover=100&borderColorHover=74b2e2&fcHover=0070a3&iconColorHover=2694e8&bgColorActive=3baae3&bgTextureActive=02_glass.png&bgImgOpacityActive=50&borderColorActive=2694e8&fcActive=ffffff&iconColorActive=ffffff&bgColorHighlight=ffef8f&bgTextureHighlight=03_highlight_soft.png&bgImgOpacityHighlight=25&borderColorHighlight=f9dd34&fcHighlight=363636&iconColorHighlight=2e83ff&bgColorError=cd0a0a&bgTextureError=01_flat.png&bgImgOpacityError=15&borderColorError=cd0a0a&fcError=ffffff&iconColorError=ffffff&bgColorOverlay=eeeeee&bgTextureOverlay=08_diagonals_thick.png&bgImgOpacityOverlay=90&opacityOverlay=80&bgColorShadow=000000&bgTextureShadow=04_highlight_hard.png&bgImgOpacityShadow=70&opacityShadow=30&thicknessShadow=7px&offsetTopShadow=-7px&offsetLeftShadow=-7px&cornerRadiusShadow=8px
+ */
+
+
+/* Component containers
+----------------------------------*/
+.ui-widget { font-family: Lucida Grande, Lucida Sans, Arial, sans-serif; font-size: 1.1em; }
+.ui-widget .ui-widget { font-size: 1em; }
+.ui-widget input, .ui-widget select, .ui-widget textarea, .ui-widget button { font-family: Lucida Grande, Lucida Sans, Arial, sans-serif; font-size: 1em; }
+.ui-widget-content { border: 1px solid #dddddd; background: #f2f5f7 url(images/ui-bg_highlight-hard_100_f2f5f7_1x100.png) 50% top repeat-x; color: #362b36; }
+.ui-widget-content a { color: #362b36; }
+.ui-widget-header { border: 1px solid #aed0ea; background: #deedf7 url(images/ui-bg_highlight-soft_100_deedf7_1x100.png) 50% 50% repeat-x; color: #222222; font-weight: bold; }
+.ui-widget-header a { color: #222222; }
+
+/* Interaction states
+----------------------------------*/
+.ui-state-default, .ui-widget-content .ui-state-default, .ui-widget-header .ui-state-default { border: 1px solid #aed0ea; background: #d7ebf9 url(images/ui-bg_glass_80_d7ebf9_1x400.png) 50% 50% repeat-x; font-weight: bold; color: #2779aa; }
+.ui-state-default a, .ui-state-default a:link, .ui-state-default a:visited { color: #2779aa; text-decoration: none; }
+.ui-state-hover, .ui-widget-content .ui-state-hover, .ui-widget-header .ui-state-hover, .ui-state-focus, .ui-widget-content .ui-state-focus, .ui-widget-header .ui-state-focus { border: 1px solid #74b2e2; background: #e4f1fb url(images/ui-bg_glass_100_e4f1fb_1x400.png) 50% 50% repeat-x; font-weight: bold; color: #0070a3; }
+.ui-state-hover a, .ui-state-hover a:hover { color: #0070a3; text-decoration: none; }
+.ui-state-active, .ui-widget-content .ui-state-active, .ui-widget-header .ui-state-active { border: 1px solid #2694e8; background: #3baae3 url(images/ui-bg_glass_50_3baae3_1x400.png) 50% 50% repeat-x; font-weight: bold; color: #ffffff; }
+.ui-state-active a, .ui-state-active a:link, .ui-state-active a:visited { color: #ffffff; text-decoration: none; }
+.ui-widget :active { outline: none; }
+
+/* Interaction Cues
+----------------------------------*/
+.ui-state-highlight, .ui-widget-content .ui-state-highlight, .ui-widget-header .ui-state-highlight {border: 1px solid #f9dd34; background: #ffef8f url(images/ui-bg_highlight-soft_25_ffef8f_1x100.png) 50% top repeat-x; color: #363636; }
+.ui-state-highlight a, .ui-widget-content .ui-state-highlight a,.ui-widget-header .ui-state-highlight a { color: #363636; }
+.ui-state-error, .ui-widget-content .ui-state-error, .ui-widget-header .ui-state-error {border: 1px solid #cd0a0a; background: #cd0a0a url(images/ui-bg_flat_15_cd0a0a_40x100.png) 50% 50% repeat-x; color: #ffffff; }
+.ui-state-error a, .ui-widget-content .ui-state-error a, .ui-widget-header .ui-state-error a { color: #ffffff; }
+.ui-state-error-text, .ui-widget-content .ui-state-error-text, .ui-widget-header .ui-state-error-text { color: #ffffff; }
+.ui-priority-primary, .ui-widget-content .ui-priority-primary, .ui-widget-header .ui-priority-primary { font-weight: bold; }
+.ui-priority-secondary, .ui-widget-content .ui-priority-secondary, .ui-widget-header .ui-priority-secondary { opacity: .7; filter:Alpha(Opacity=70); font-weight: normal; }
+.ui-state-disabled, .ui-widget-content .ui-state-disabled, .ui-widget-header .ui-state-disabled { opacity: .35; filter:Alpha(Opacity=35); background-image: none; }
+
+/* Icons
+----------------------------------*/
+
+/* states and images */
+.ui-icon { width: 16px; height: 16px; background-image: url(images/ui-icons_72a7cf_256x240.png); }
+.ui-widget-content .ui-icon {background-image: url(images/ui-icons_72a7cf_256x240.png); }
+.ui-widget-header .ui-icon {background-image: url(images/ui-icons_72a7cf_256x240.png); }
+.ui-state-default .ui-icon { background-image: url(images/ui-icons_3d80b3_256x240.png); }
+.ui-state-hover .ui-icon, .ui-state-focus .ui-icon {background-image: url(images/ui-icons_2694e8_256x240.png); }
+.ui-state-active .ui-icon {background-image: url(images/ui-icons_ffffff_256x240.png); }
+.ui-state-highlight .ui-icon {background-image: url(images/ui-icons_2e83ff_256x240.png); }
+.ui-state-error .ui-icon, .ui-state-error-text .ui-icon {background-image: url(images/ui-icons_ffffff_256x240.png); }
+
+/* positioning */
+.ui-icon-carat-1-n { background-position: 0 0; }
+.ui-icon-carat-1-ne { background-position: -16px 0; }
+.ui-icon-carat-1-e { background-position: -32px 0; }
+.ui-icon-carat-1-se { background-position: -48px 0; }
+.ui-icon-carat-1-s { background-position: -64px 0; }
+.ui-icon-carat-1-sw { background-position: -80px 0; }
+.ui-icon-carat-1-w { background-position: -96px 0; }
+.ui-icon-carat-1-nw { background-position: -112px 0; }
+.ui-icon-carat-2-n-s { background-position: -128px 0; }
+.ui-icon-carat-2-e-w { background-position: -144px 0; }
+.ui-icon-triangle-1-n { background-position: 0 -16px; }
+.ui-icon-triangle-1-ne { background-position: -16px -16px; }
+.ui-icon-triangle-1-e { background-position: -32px -16px; }
+.ui-icon-triangle-1-se { background-position: -48px -16px; }
+.ui-icon-triangle-1-s { background-position: -64px -16px; }
+.ui-icon-triangle-1-sw { background-position: -80px -16px; }
+.ui-icon-triangle-1-w { background-position: -96px -16px; }
+.ui-icon-triangle-1-nw { background-position: -112px -16px; }
+.ui-icon-triangle-2-n-s { background-position: -128px -16px; }
+.ui-icon-triangle-2-e-w { background-position: -144px -16px; }
+.ui-icon-arrow-1-n { background-position: 0 -32px; }
+.ui-icon-arrow-1-ne { background-position: -16px -32px; }
+.ui-icon-arrow-1-e { background-position: -32px -32px; }
+.ui-icon-arrow-1-se { background-position: -48px -32px; }
+.ui-icon-arrow-1-s { background-position: -64px -32px; }
+.ui-icon-arrow-1-sw { background-position: -80px -32px; }
+.ui-icon-arrow-1-w { background-position: -96px -32px; }
+.ui-icon-arrow-1-nw { background-position: -112px -32px; }
+.ui-icon-arrow-2-n-s { background-position: -128px -32px; }
+.ui-icon-arrow-2-ne-sw { background-position: -144px -32px; }
+.ui-icon-arrow-2-e-w { background-position: -160px -32px; }
+.ui-icon-arrow-2-se-nw { background-position: -176px -32px; }
+.ui-icon-arrowstop-1-n { background-position: -192px -32px; }
+.ui-icon-arrowstop-1-e { background-position: -208px -32px; }
+.ui-icon-arrowstop-1-s { background-position: -224px -32px; }
+.ui-icon-arrowstop-1-w { background-position: -240px -32px; }
+.ui-icon-arrowthick-1-n { background-position: 0 -48px; }
+.ui-icon-arrowthick-1-ne { background-position: -16px -48px; }
+.ui-icon-arrowthick-1-e { background-position: -32px -48px; }
+.ui-icon-arrowthick-1-se { background-position: -48px -48px; }
+.ui-icon-arrowthick-1-s { background-position: -64px -48px; }
+.ui-icon-arrowthick-1-sw { background-position: -80px -48px; }
+.ui-icon-arrowthick-1-w { background-position: -96px -48px; }
+.ui-icon-arrowthick-1-nw { background-position: -112px -48px; }
+.ui-icon-arrowthick-2-n-s { background-position: -128px -48px; }
+.ui-icon-arrowthick-2-ne-sw { background-position: -144px -48px; }
+.ui-icon-arrowthick-2-e-w { background-position: -160px -48px; }
+.ui-icon-arrowthick-2-se-nw { background-position: -176px -48px; }
+.ui-icon-arrowthickstop-1-n { background-position: -192px -48px; }
+.ui-icon-arrowthickstop-1-e { background-position: -208px -48px; }
+.ui-icon-arrowthickstop-1-s { background-position: -224px -48px; }
+.ui-icon-arrowthickstop-1-w { background-position: -240px -48px; }
+.ui-icon-arrowreturnthick-1-w { background-position: 0 -64px; }
+.ui-icon-arrowreturnthick-1-n { background-position: -16px -64px; }
+.ui-icon-arrowreturnthick-1-e { background-position: -32px -64px; }
+.ui-icon-arrowreturnthick-1-s { background-position: -48px -64px; }
+.ui-icon-arrowreturn-1-w { background-position: -64px -64px; }
+.ui-icon-arrowreturn-1-n { background-position: -80px -64px; }
+.ui-icon-arrowreturn-1-e { background-position: -96px -64px; }
+.ui-icon-arrowreturn-1-s { background-position: -112px -64px; }
+.ui-icon-arrowrefresh-1-w { background-position: -128px -64px; }
+.ui-icon-arrowrefresh-1-n { background-position: -144px -64px; }
+.ui-icon-arrowrefresh-1-e { background-position: -160px -64px; }
+.ui-icon-arrowrefresh-1-s { background-position: -176px -64px; }
+.ui-icon-arrow-4 { background-position: 0 -80px; }
+.ui-icon-arrow-4-diag { background-position: -16px -80px; }
+.ui-icon-extlink { background-position: -32px -80px; }
+.ui-icon-newwin { background-position: -48px -80px; }
+.ui-icon-refresh { background-position: -64px -80px; }
+.ui-icon-shuffle { background-position: -80px -80px; }
+.ui-icon-transfer-e-w { background-position: -96px -80px; }
+.ui-icon-transferthick-e-w { background-position: -112px -80px; }
+.ui-icon-folder-collapsed { background-position: 0 -96px; }
+.ui-icon-folder-open { background-position: -16px -96px; }
+.ui-icon-document { background-position: -32px -96px; }
+.ui-icon-document-b { background-position: -48px -96px; }
+.ui-icon-note { background-position: -64px -96px; }
+.ui-icon-mail-closed { background-position: -80px -96px; }
+.ui-icon-mail-open { background-position: -96px -96px; }
+.ui-icon-suitcase { background-position: -112px -96px; }
+.ui-icon-comment { background-position: -128px -96px; }
+.ui-icon-person { background-position: -144px -96px; }
+.ui-icon-print { background-position: -160px -96px; }
+.ui-icon-trash { background-position: -176px -96px; }
+.ui-icon-locked { background-position: -192px -96px; }
+.ui-icon-unlocked { background-position: -208px -96px; }
+.ui-icon-bookmark { background-position: -224px -96px; }
+.ui-icon-tag { background-position: -240px -96px; }
+.ui-icon-home { background-position: 0 -112px; }
+.ui-icon-flag { background-position: -16px -112px; }
+.ui-icon-calendar { background-position: -32px -112px; }
+.ui-icon-cart { background-position: -48px -112px; }
+.ui-icon-pencil { background-position: -64px -112px; }
+.ui-icon-clock { background-position: -80px -112px; }
+.ui-icon-disk { background-position: -96px -112px; }
+.ui-icon-calculator { background-position: -112px -112px; }
+.ui-icon-zoomin { background-position: -128px -112px; }
+.ui-icon-zoomout { background-position: -144px -112px; }
+.ui-icon-search { background-position: -160px -112px; }
+.ui-icon-wrench { background-position: -176px -112px; }
+.ui-icon-gear { background-position: -192px -112px; }
+.ui-icon-heart { background-position: -208px -112px; }
+.ui-icon-star { background-position: -224px -112px; }
+.ui-icon-link { background-position: -240px -112px; }
+.ui-icon-cancel { background-position: 0 -128px; }
+.ui-icon-plus { background-position: -16px -128px; }
+.ui-icon-plusthick { background-position: -32px -128px; }
+.ui-icon-minus { background-position: -48px -128px; }
+.ui-icon-minusthick { background-position: -64px -128px; }
+.ui-icon-close { background-position: -80px -128px; }
+.ui-icon-closethick { background-position: -96px -128px; }
+.ui-icon-key { background-position: -112px -128px; }
+.ui-icon-lightbulb { background-position: -128px -128px; }
+.ui-icon-scissors { background-position: -144px -128px; }
+.ui-icon-clipboard { background-position: -160px -128px; }
+.ui-icon-copy { background-position: -176px -128px; }
+.ui-icon-contact { background-position: -192px -128px; }
+.ui-icon-image { background-position: -208px -128px; }
+.ui-icon-video { background-position: -224px -128px; }
+.ui-icon-script { background-position: -240px -128px; }
+.ui-icon-alert { background-position: 0 -144px; }
+.ui-icon-info { background-position: -16px -144px; }
+.ui-icon-notice { background-position: -32px -144px; }
+.ui-icon-help { background-position: -48px -144px; }
+.ui-icon-check { background-position: -64px -144px; }
+.ui-icon-bullet { background-position: -80px -144px; }
+.ui-icon-radio-off { background-position: -96px -144px; }
+.ui-icon-radio-on { background-position: -112px -144px; }
+.ui-icon-pin-w { background-position: -128px -144px; }
+.ui-icon-pin-s { background-position: -144px -144px; }
+.ui-icon-play { background-position: 0 -160px; }
+.ui-icon-pause { background-position: -16px -160px; }
+.ui-icon-seek-next { background-position: -32px -160px; }
+.ui-icon-seek-prev { background-position: -48px -160px; }
+.ui-icon-seek-end { background-position: -64px -160px; }
+.ui-icon-seek-start { background-position: -80px -160px; }
+/* ui-icon-seek-first is deprecated, use ui-icon-seek-start instead */
+.ui-icon-seek-first { background-position: -80px -160px; }
+.ui-icon-stop { background-position: -96px -160px; }
+.ui-icon-eject { background-position: -112px -160px; }
+.ui-icon-volume-off { background-position: -128px -160px; }
+.ui-icon-volume-on { background-position: -144px -160px; }
+.ui-icon-power { background-position: 0 -176px; }
+.ui-icon-signal-diag { background-position: -16px -176px; }
+.ui-icon-signal { background-position: -32px -176px; }
+.ui-icon-battery-0 { background-position: -48px -176px; }
+.ui-icon-battery-1 { background-position: -64px -176px; }
+.ui-icon-battery-2 { background-position: -80px -176px; }
+.ui-icon-battery-3 { background-position: -96px -176px; }
+.ui-icon-circle-plus { background-position: 0 -192px; }
+.ui-icon-circle-minus { background-position: -16px -192px; }
+.ui-icon-circle-close { background-position: -32px -192px; }
+.ui-icon-circle-triangle-e { background-position: -48px -192px; }
+.ui-icon-circle-triangle-s { background-position: -64px -192px; }
+.ui-icon-circle-triangle-w { background-position: -80px -192px; }
+.ui-icon-circle-triangle-n { background-position: -96px -192px; }
+.ui-icon-circle-arrow-e { background-position: -112px -192px; }
+.ui-icon-circle-arrow-s { background-position: -128px -192px; }
+.ui-icon-circle-arrow-w { background-position: -144px -192px; }
+.ui-icon-circle-arrow-n { background-position: -160px -192px; }
+.ui-icon-circle-zoomin { background-position: -176px -192px; }
+.ui-icon-circle-zoomout { background-position: -192px -192px; }
+.ui-icon-circle-check { background-position: -208px -192px; }
+.ui-icon-circlesmall-plus { background-position: 0 -208px; }
+.ui-icon-circlesmall-minus { background-position: -16px -208px; }
+.ui-icon-circlesmall-close { background-position: -32px -208px; }
+.ui-icon-squaresmall-plus { background-position: -48px -208px; }
+.ui-icon-squaresmall-minus { background-position: -64px -208px; }
+.ui-icon-squaresmall-close { background-position: -80px -208px; }
+.ui-icon-grip-dotted-vertical { background-position: 0 -224px; }
+.ui-icon-grip-dotted-horizontal { background-position: -16px -224px; }
+.ui-icon-grip-solid-vertical { background-position: -32px -224px; }
+.ui-icon-grip-solid-horizontal { background-position: -48px -224px; }
+.ui-icon-gripsmall-diagonal-se { background-position: -64px -224px; }
+.ui-icon-grip-diagonal-se { background-position: -80px -224px; }
+
+
+/* Misc visuals
+----------------------------------*/
+
+/* Corner radius */
+.ui-corner-all, .ui-corner-top, .ui-corner-left, .ui-corner-tl { -moz-border-radius-topleft: 6px; -webkit-border-top-left-radius: 6px; -khtml-border-top-left-radius: 6px; border-top-left-radius: 6px; }
+.ui-corner-all, .ui-corner-top, .ui-corner-right, .ui-corner-tr { -moz-border-radius-topright: 6px; -webkit-border-top-right-radius: 6px; -khtml-border-top-right-radius: 6px; border-top-right-radius: 6px; }
+.ui-corner-all, .ui-corner-bottom, .ui-corner-left, .ui-corner-bl { -moz-border-radius-bottomleft: 6px; -webkit-border-bottom-left-radius: 6px; -khtml-border-bottom-left-radius: 6px; border-bottom-left-radius: 6px; }
+.ui-corner-all, .ui-corner-bottom, .ui-corner-right, .ui-corner-br { -moz-border-radius-bottomright: 6px; -webkit-border-bottom-right-radius: 6px; -khtml-border-bottom-right-radius: 6px; border-bottom-right-radius: 6px; }
+
+/* Overlays */
+.ui-widget-overlay { background: #eeeeee url(images/ui-bg_diagonals-thick_90_eeeeee_40x40.png) 50% 50% repeat; opacity: .80;filter:Alpha(Opacity=80); }
+.ui-widget-shadow { margin: -7px 0 0 -7px; padding: 7px; background: #000000 url(images/ui-bg_highlight-hard_70_000000_1x100.png) 50% top repeat-x; opacity: .30;filter:Alpha(Opacity=30); -moz-border-radius: 8px; -khtml-border-radius: 8px; -webkit-border-radius: 8px; border-radius: 8px; }/*!
+ * jQuery UI Resizable 1.8.24
+ *
+ * Copyright 2012, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Resizable#theming
+ */
+.ui-resizable { position: relative;}
+.ui-resizable-handle { position: absolute;font-size: 0.1px; display: block; }
+.ui-resizable-disabled .ui-resizable-handle, .ui-resizable-autohide .ui-resizable-handle { display: none; }
+.ui-resizable-n { cursor: n-resize; height: 7px; width: 100%; top: -5px; left: 0; }
+.ui-resizable-s { cursor: s-resize; height: 7px; width: 100%; bottom: -5px; left: 0; }
+.ui-resizable-e { cursor: e-resize; width: 7px; right: -5px; top: 0; height: 100%; }
+.ui-resizable-w { cursor: w-resize; width: 7px; left: -5px; top: 0; height: 100%; }
+.ui-resizable-se { cursor: se-resize; width: 12px; height: 12px; right: 1px; bottom: 1px; }
+.ui-resizable-sw { cursor: sw-resize; width: 9px; height: 9px; left: -5px; bottom: -5px; }
+.ui-resizable-nw { cursor: nw-resize; width: 9px; height: 9px; left: -5px; top: -5px; }
+.ui-resizable-ne { cursor: ne-resize; width: 9px; height: 9px; right: -5px; top: -5px;}/*!
+ * jQuery UI Selectable 1.8.24
+ *
+ * Copyright 2012, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Selectable#theming
+ */
+.ui-selectable-helper { position: absolute; z-index: 100; border:1px dotted black; }
+/*!
+ * jQuery UI Accordion 1.8.24
+ *
+ * Copyright 2012, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Accordion#theming
+ */
+/* IE/Win - Fix animation bug - #4615 */
+.ui-accordion { width: 100%; }
+.ui-accordion .ui-accordion-header { cursor: pointer; position: relative; margin-top: 1px; zoom: 1; }
+.ui-accordion .ui-accordion-li-fix { display: inline; }
+.ui-accordion .ui-accordion-header-active { border-bottom: 0 !important; }
+.ui-accordion .ui-accordion-header a { display: block; font-size: 1em; padding: .5em .5em .5em .7em; }
+.ui-accordion-icons .ui-accordion-header a { padding-left: 2.2em; }
+.ui-accordion .ui-accordion-header .ui-icon { position: absolute; left: .5em; top: 50%; margin-top: -8px; }
+.ui-accordion .ui-accordion-content { padding: 1em 2.2em; border-top: 0; margin-top: -2px; position: relative; top: 1px; margin-bottom: 2px; overflow: auto; display: none; zoom: 1; }
+.ui-accordion .ui-accordion-content-active { display: block; }
+/*!
+ * jQuery UI Autocomplete 1.8.24
+ *
+ * Copyright 2012, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Autocomplete#theming
+ */
+.ui-autocomplete { position: absolute; cursor: default; }
+
+/* workarounds */
+* html .ui-autocomplete { width:1px; } /* without this, the menu expands to 100% in IE6 */
+
+/*
+ * jQuery UI Menu 1.8.24
+ *
+ * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Menu#theming
+ */
+.ui-menu {
+ list-style:none;
+ padding: 2px;
+ margin: 0;
+ display:block;
+ float: left;
+}
+.ui-menu .ui-menu {
+ margin-top: -3px;
+}
+.ui-menu .ui-menu-item {
+ margin:0;
+ padding: 0;
+ zoom: 1;
+ float: left;
+ clear: left;
+ width: 100%;
+}
+.ui-menu .ui-menu-item a {
+ text-decoration:none;
+ display:block;
+ padding:.2em .4em;
+ line-height:1.5;
+ zoom:1;
+}
+.ui-menu .ui-menu-item a.ui-state-hover,
+.ui-menu .ui-menu-item a.ui-state-active {
+ font-weight: normal;
+ margin: -1px;
+}
+/*!
+ * jQuery UI Button 1.8.24
+ *
+ * Copyright 2012, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Button#theming
+ */
+.ui-button { display: inline-block; position: relative; padding: 0; margin-right: .1em; text-decoration: none !important; cursor: pointer; text-align: center; zoom: 1; overflow: visible; } /* the overflow property removes extra width in IE */
+.ui-button-icon-only { width: 2.2em; } /* to make room for the icon, a width needs to be set here */
+button.ui-button-icon-only { width: 2.4em; } /* button elements seem to need a little more width */
+.ui-button-icons-only { width: 3.4em; }
+button.ui-button-icons-only { width: 3.7em; }
+
+/*button text element */
+.ui-button .ui-button-text { display: block; line-height: 1.4; }
+.ui-button-text-only .ui-button-text { padding: .4em 1em; }
+.ui-button-icon-only .ui-button-text, .ui-button-icons-only .ui-button-text { padding: .4em; text-indent: -9999999px; }
+.ui-button-text-icon-primary .ui-button-text, .ui-button-text-icons .ui-button-text { padding: .4em 1em .4em 2.1em; }
+.ui-button-text-icon-secondary .ui-button-text, .ui-button-text-icons .ui-button-text { padding: .4em 2.1em .4em 1em; }
+.ui-button-text-icons .ui-button-text { padding-left: 2.1em; padding-right: 2.1em; }
+/* no icon support for input elements, provide padding by default */
+input.ui-button { padding: .4em 1em; }
+
+/*button icon element(s) */
+.ui-button-icon-only .ui-icon, .ui-button-text-icon-primary .ui-icon, .ui-button-text-icon-secondary .ui-icon, .ui-button-text-icons .ui-icon, .ui-button-icons-only .ui-icon { position: absolute; top: 50%; margin-top: -8px; }
+.ui-button-icon-only .ui-icon { left: 50%; margin-left: -8px; }
+.ui-button-text-icon-primary .ui-button-icon-primary, .ui-button-text-icons .ui-button-icon-primary, .ui-button-icons-only .ui-button-icon-primary { left: .5em; }
+.ui-button-text-icon-secondary .ui-button-icon-secondary, .ui-button-text-icons .ui-button-icon-secondary, .ui-button-icons-only .ui-button-icon-secondary { right: .5em; }
+.ui-button-text-icons .ui-button-icon-secondary, .ui-button-icons-only .ui-button-icon-secondary { right: .5em; }
+
+/*button sets*/
+.ui-buttonset { margin-right: 7px; }
+.ui-buttonset .ui-button { margin-left: 0; margin-right: -.3em; }
+
+/* workarounds */
+button.ui-button::-moz-focus-inner { border: 0; padding: 0; } /* reset extra padding in Firefox */
+/*!
+ * jQuery UI Dialog 1.8.24
+ *
+ * Copyright 2012, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Dialog#theming
+ */
+.ui-dialog { position: absolute; padding: .2em; width: 300px; overflow: hidden; }
+.ui-dialog .ui-dialog-titlebar { padding: .4em 1em; position: relative; }
+.ui-dialog .ui-dialog-title { float: left; margin: .1em 16px .1em 0; }
+.ui-dialog .ui-dialog-titlebar-close { position: absolute; right: .3em; top: 50%; width: 19px; margin: -10px 0 0 0; padding: 1px; height: 18px; }
+.ui-dialog .ui-dialog-titlebar-close span { display: block; margin: 1px; }
+.ui-dialog .ui-dialog-titlebar-close:hover, .ui-dialog .ui-dialog-titlebar-close:focus { padding: 0; }
+.ui-dialog .ui-dialog-content { position: relative; border: 0; padding: .5em 1em; background: none; overflow: auto; zoom: 1; }
+.ui-dialog .ui-dialog-buttonpane { text-align: left; border-width: 1px 0 0 0; background-image: none; margin: .5em 0 0 0; padding: .3em 1em .5em .4em; }
+.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset { float: right; }
+.ui-dialog .ui-dialog-buttonpane button { margin: .5em .4em .5em 0; cursor: pointer; }
+.ui-dialog .ui-resizable-se { width: 14px; height: 14px; right: 3px; bottom: 3px; }
+.ui-draggable .ui-dialog-titlebar { cursor: move; }
+/*!
+ * jQuery UI Slider 1.8.24
+ *
+ * Copyright 2012, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Slider#theming
+ */
+.ui-slider { position: relative; text-align: left; }
+.ui-slider .ui-slider-handle { position: absolute; z-index: 2; width: 1.2em; height: 1.2em; cursor: default; }
+.ui-slider .ui-slider-range { position: absolute; z-index: 1; font-size: .7em; display: block; border: 0; background-position: 0 0; }
+
+.ui-slider-horizontal { height: .8em; }
+.ui-slider-horizontal .ui-slider-handle { top: -.3em; margin-left: -.6em; }
+.ui-slider-horizontal .ui-slider-range { top: 0; height: 100%; }
+.ui-slider-horizontal .ui-slider-range-min { left: 0; }
+.ui-slider-horizontal .ui-slider-range-max { right: 0; }
+
+.ui-slider-vertical { width: .8em; height: 100px; }
+.ui-slider-vertical .ui-slider-handle { left: -.3em; margin-left: 0; margin-bottom: -.6em; }
+.ui-slider-vertical .ui-slider-range { left: 0; width: 100%; }
+.ui-slider-vertical .ui-slider-range-min { bottom: 0; }
+.ui-slider-vertical .ui-slider-range-max { top: 0; }/*!
+ * jQuery UI Tabs 1.8.24
+ *
+ * Copyright 2012, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Tabs#theming
+ */
+.ui-tabs { position: relative; padding: .2em; zoom: 1; } /* position: relative prevents IE scroll bug (element with position: relative inside container with overflow: auto appear as "fixed") */
+.ui-tabs .ui-tabs-nav { margin: 0; padding: .2em .2em 0; }
+.ui-tabs .ui-tabs-nav li { list-style: none; float: left; position: relative; top: 1px; margin: 0 .2em 1px 0; border-bottom: 0 !important; padding: 0; white-space: nowrap; }
+.ui-tabs .ui-tabs-nav li a { float: left; padding: .5em 1em; text-decoration: none; }
+.ui-tabs .ui-tabs-nav li.ui-tabs-selected { margin-bottom: 0; padding-bottom: 1px; }
+.ui-tabs .ui-tabs-nav li.ui-tabs-selected a, .ui-tabs .ui-tabs-nav li.ui-state-disabled a, .ui-tabs .ui-tabs-nav li.ui-state-processing a { cursor: text; }
+.ui-tabs .ui-tabs-nav li a, .ui-tabs.ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-selected a { cursor: pointer; } /* first selector in group seems obsolete, but required to overcome bug in Opera applying cursor: text overall if defined elsewhere... */
+.ui-tabs .ui-tabs-panel { display: block; border-width: 0; padding: 1em 1.4em; background: none; }
+.ui-tabs .ui-tabs-hide { display: none !important; }
+/*!
+ * jQuery UI Datepicker 1.8.24
+ *
+ * Copyright 2012, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Datepicker#theming
+ */
+.ui-datepicker { width: 17em; padding: .2em .2em 0; display: none; }
+.ui-datepicker .ui-datepicker-header { position:relative; padding:.2em 0; }
+.ui-datepicker .ui-datepicker-prev, .ui-datepicker .ui-datepicker-next { position:absolute; top: 2px; width: 1.8em; height: 1.8em; }
+.ui-datepicker .ui-datepicker-prev-hover, .ui-datepicker .ui-datepicker-next-hover { top: 1px; }
+.ui-datepicker .ui-datepicker-prev { left:2px; }
+.ui-datepicker .ui-datepicker-next { right:2px; }
+.ui-datepicker .ui-datepicker-prev-hover { left:1px; }
+.ui-datepicker .ui-datepicker-next-hover { right:1px; }
+.ui-datepicker .ui-datepicker-prev span, .ui-datepicker .ui-datepicker-next span { display: block; position: absolute; left: 50%; margin-left: -8px; top: 50%; margin-top: -8px; }
+.ui-datepicker .ui-datepicker-title { margin: 0 2.3em; line-height: 1.8em; text-align: center; }
+.ui-datepicker .ui-datepicker-title select { font-size:1em; margin:1px 0; }
+.ui-datepicker select.ui-datepicker-month-year {width: 100%;}
+.ui-datepicker select.ui-datepicker-month,
+.ui-datepicker select.ui-datepicker-year { width: 49%;}
+.ui-datepicker table {width: 100%; font-size: .9em; border-collapse: collapse; margin:0 0 .4em; }
+.ui-datepicker th { padding: .7em .3em; text-align: center; font-weight: bold; border: 0; }
+.ui-datepicker td { border: 0; padding: 1px; }
+.ui-datepicker td span, .ui-datepicker td a { display: block; padding: .2em; text-align: right; text-decoration: none; }
+.ui-datepicker .ui-datepicker-buttonpane { background-image: none; margin: .7em 0 0 0; padding:0 .2em; border-left: 0; border-right: 0; border-bottom: 0; }
+.ui-datepicker .ui-datepicker-buttonpane button { float: right; margin: .5em .2em .4em; cursor: pointer; padding: .2em .6em .3em .6em; width:auto; overflow:visible; }
+.ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current { float:left; }
+
+/* with multiple calendars */
+.ui-datepicker.ui-datepicker-multi { width:auto; }
+.ui-datepicker-multi .ui-datepicker-group { float:left; }
+.ui-datepicker-multi .ui-datepicker-group table { width:95%; margin:0 auto .4em; }
+.ui-datepicker-multi-2 .ui-datepicker-group { width:50%; }
+.ui-datepicker-multi-3 .ui-datepicker-group { width:33.3%; }
+.ui-datepicker-multi-4 .ui-datepicker-group { width:25%; }
+.ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header { border-left-width:0; }
+.ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header { border-left-width:0; }
+.ui-datepicker-multi .ui-datepicker-buttonpane { clear:left; }
+.ui-datepicker-row-break { clear:both; width:100%; font-size:0em; }
+
+/* RTL support */
+.ui-datepicker-rtl { direction: rtl; }
+.ui-datepicker-rtl .ui-datepicker-prev { right: 2px; left: auto; }
+.ui-datepicker-rtl .ui-datepicker-next { left: 2px; right: auto; }
+.ui-datepicker-rtl .ui-datepicker-prev:hover { right: 1px; left: auto; }
+.ui-datepicker-rtl .ui-datepicker-next:hover { left: 1px; right: auto; }
+.ui-datepicker-rtl .ui-datepicker-buttonpane { clear:right; }
+.ui-datepicker-rtl .ui-datepicker-buttonpane button { float: left; }
+.ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current { float:right; }
+.ui-datepicker-rtl .ui-datepicker-group { float:right; }
+.ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header { border-right-width:0; border-left-width:1px; }
+.ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header { border-right-width:0; border-left-width:1px; }
+
+/* IE6 IFRAME FIX (taken from datepicker 1.5.3 */
+.ui-datepicker-cover {
+ position: absolute; /*must have*/
+ z-index: -1; /*must have*/
+ filter: mask(); /*must have*/
+ top: -4px; /*must have*/
+ left: -4px; /*must have*/
+ width: 200px; /*must have*/
+ height: 200px; /*must have*/
+}/*!
+ * jQuery UI Progressbar 1.8.24
+ *
+ * Copyright 2012, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Progressbar#theming
+ */
+.ui-progressbar { height:2em; text-align: left; overflow: hidden; }
+.ui-progressbar .ui-progressbar-value {margin: -1px; height:100%; }
\ No newline at end of file
--- /dev/null
+.ui-widget-content { background: none; }
+span.ricoTitleSpan { font-size: 120%; }
+div.ricoShadow.ricoWindow { border: 1px solid #555; padding: 0; }
+.ricoLG_col .ui-state-hover { font-weight: normal; }
+.ricoLG_cell a { color: #0066b3; }
+div.ricoLG_cell, table.ricoLiveGrid td, table.ricoLiveGrid th { font-size: 100%; height: 1.1em; }
+.ricoLG_FilterRow div.ricoLG_cell { height: 1.2em; }
+div.ricoMenu, div.ricoMenuSafari { font-size: 90%; }
+.alignleft { text-align: left; }
+.aligncenter { text-align: center; }
+.alignright { text-align: right; }
+div.ui-datepicker { background: #EEE; }
+.ui-datepicker table { font-size: inherit; }
+.ricoCalFoot td { font-size: 80%; }
+.ricoCalBody { font-size: 80%; }
+.ui-widget-content { border: 1px solid #dddddd; color: #362b36; }
+div.RicoWindow div.info { font-size: 80%; }
if(typeof Rico.TableColumn=='undefined') throw("RicoExtension requires ricoGridCommon.js");
if(typeof Rico.TableColumn.checkbox=='undefined') throw("RicoExtension requires ricoGridControls.js");
-// Checkbox with database connection
-Rico.TableColumn.checkboxDB = Class.create(Rico.TableColumn.checkbox, {
+Rico.TableColumn.checkboxDB = function(refcol, update) {
+ this.initialize(refcol, update);
+};
+
+Rico.TableColumn.checkboxDB.prototype = Rico.extend(new Rico.TableColumn.checkbox(), {
+ initialize: function(refcol, update) {
+ this._checkedValue=1;
+ this._uncheckedValue=0
+ this._defaultValue=0
+ this._readOnly=0
+ this._checkboxes=[];
- initialize: function($super, refcol, update) {
- $super(1, 0, 0, 0);
this._referenceColumn = refcol;
this._updateUrl = update;
},
- _onclick: function($super,e) {
- $super(e);
- var elem=Event.element(e);
- var windowRow=parseInt(elem.id.split(/_/).pop());
+ _onclick: function(e) {
+ var elem=Rico.eventElement(e);
+ var windowRow=parseInt(elem.id.substr((elem.id.lastIndexOf('_',elem.id.length)+1))); //faster than split
+ var newval=elem.checked ? this._checkedValue : this._uncheckedValue;
+ this.setValue(windowRow,newval);
this._update(windowRow);
},
_formbase: function() {
- return 'table='+this.liveGrid.tableId+'&column='+this.index;
+ var formdata = 'table='+this.liveGrid.tableId+'&column='+this.index;
+ if (this.liveGrid.tableId.indexOf('__second') > -1)
+ formdata += '&main_id='+Hallinta.mainId;
+ return formdata;
},
_update: function(row) {
var id = this.liveGrid.columns[this._referenceColumn].getValue(row);
var formdata = this._formbase() + '&reference='+id+'&value='+value;
- new Ajax.Request(this._updateUrl, {method: 'post', parameters: formdata});
+ new Rico.ajaxRequest(this._updateUrl, {method: 'post', parameters: formdata});
},
_updateall: function(value) {
var cols = this.liveGrid.columns.length;
for (var c = 0; c < cols; c++) {
var column = this.liveGrid.columns[c]
- if (column.filterType == Rico.TableColumn.USERFILTER) {
+ if (column.filterType == Rico.ColumnConst.USERFILTER) {
var filter = column.filterOp + '|' + column.filterValues;
formdata += '&filter_'+c+'='+filter;
}
}
}
- new Ajax.Request(this._updateUrl, {method: 'post', parameters: formdata});
+ new Rico.ajaxRequest(this._updateUrl, {method: 'post', parameters: formdata});
var basename = this.liveGrid.tableId + '_chkbox_' + this.index + '_';
var childCnt = this.numRows();
for (var r = 0; r < childCnt; r++)
if (this.getValue(r) != null) {
var name = basename + r;
- $(name).checked = val;
+ $('#'+name).prop('checked', val == 1);
}
var rows = this.liveGrid.buffer.totalRows;
},
_createFilters: function(parent,name) {
- field_p=RicoUtil.createFormField(parent,'img',null,name+'_p');
- field_p.src = Rico.imgDir+'p.gif';
+ field_p=Rico.createFormField(parent,'img',null,name+'_p');
+ field_p.src = Hallinta.baseURL+'lib/rico/images/p.gif';
field_p.tableColumn = this;
field_p.onclick = function() { this.tableColumn._checkall(); };
- field_m=RicoUtil.createFormField(parent,'img',null,name+'_m');
- field_m.src = Rico.imgDir+'m.gif';
+ field_m=Rico.createFormField(parent,'img',null,name+'_m');
+ field_m.src = Hallinta.baseURL+'lib/rico/images/m.gif';
field_m.tableColumn = this;
field_m.onclick = function() { this.tableColumn._uncheckall(); };
}
});
-Rico.includeLoaded('ricoTableColumnDB.js');
+Rico.TableColumn.checkboxFunction = function(callback, callback_all) {
+ this.initialize(callback, callback_all);
+};
+
+Rico.TableColumn.checkboxFunction.prototype = Rico.extend(new Rico.TableColumn.checkbox(), {
+ initialize: function(callback, callback_all) {
+ this._checkedValue=1;
+ this._uncheckedValue=0
+ this._defaultValue=0
+ this._readOnly=0
+ this._checkboxes=[];
+
+ this._callback = callback;
+ this._callback_all = callback_all;
+ },
+
+ _onclick: function(e) {
+ var elem=Rico.eventElement(e);
+ var windowRow=parseInt(elem.id.substr((elem.id.lastIndexOf('_',elem.id.length)+1))); //faster than split
+ var newval=elem.checked ? this._checkedValue : this._uncheckedValue;
+ this.setValue(windowRow,newval);
+
+ this._update(windowRow);
+ },
+
+ _formbase: function() {
+ return 'table='+this.liveGrid.tableId+'&column='+this.index;
+ },
+
+ _update: function(row) {
+ var value = this.getValue(row);
+
+ if (value == undefined)
+ return false;
+
+ this._callback(this, row, value);
+ },
+
+ _updateall: function(value) {
+ var formdata = 'value='+value;
+
+ // Warning: filters not detected in subgrid
+ if (this.liveGrid.filterCount() > 0) {
+ var cols = this.liveGrid.columns.length;
+ for (var c = 0; c < cols; c++) {
+ var column = this.liveGrid.columns[c]
+ if (column.filterType == Rico.ColumnConst.USERFILTER) {
+ var filter = column.filterOp + '|' + column.filterValues;
+ formdata += '&filter_'+c+'='+filter;
+ }
+ }
+ }
+
+ this._callback_all(formdata);
+
+ var basename = this.liveGrid.tableId + '_chkbox_' + this.index + '_';
+ var childCnt = this.numRows();
+ var val = value?true:false;
+ for (var r = 0; r < childCnt; r++)
+ if (this.getValue(r) != null) {
+ var name = basename + r;
+ $('#'+name).prop('checked', val == 1);
+ }
+
+ var rows = this.liveGrid.buffer.totalRows;
+ for (var i = 0; i < rows; i++)
+ this.liveGrid.buffer.setValue(i, this.index, value);
+ },
+
+ _checkall: function() {
+ this._updateall(1);
+ },
+ _uncheckall: function() {
+ this._updateall(0);
+ },
+
+ _createFilters: function(parent,name) {
+ field_p=Rico.createFormField(parent,'img',null,name+'_p');
+ field_p.src = Hallinta.baseURL+'lib/rico/images/p.gif';
+ field_p.tableColumn = this;
+ field_p.onclick = function() { this.tableColumn._checkall(); };
+ field_m=Rico.createFormField(parent,'img',null,name+'_m');
+ field_m.src = Hallinta.baseURL+'lib/rico/images/m.gif';
+ field_m.tableColumn = this;
+ field_m.onclick = function() { this.tableColumn._uncheckall(); };
+ }
+});
join = string
rows = Integer
sort = Integer
+ sortdir = ASC | DESC
maxprint = Integer (-> maxPrint, max exportable rows in table)
prefetch = true / false (default true)
html = string
--- /dev/null
+#! /usr/bin/perl
+
+use DBI;
+use Encode;
+use Getopt::Long;
+use Mail::Sendmail;
+use Date::Calc qw/Day_of_Week/;
+
+my $cfg;
+my $db;
+
+sub basepath
+{
+ my @parts = split('/', $0);
+ pop @parts;pop @parts;pop @parts;
+ return join('/', @parts);
+}
+
+sub config_read
+{
+ my $info;
+ open my $f, basepath.'/config.php' or return;
+ while (<$f>) {
+ chomp;
+ next if /^#/ || /^\s*$/;
+ next unless /^\s*define\(['"](.*?)["']\s*,\s*['"](.*?)["']\)/;
+ $info->{$1} = $2;
+ }
+ close $f;
+ return $info;
+}
+
+sub dbconnect
+{
+ my $dsn = 'dbi:' . ($cfg->{DBDRIVER} eq 'pgsql' ? 'Pg:dbname=' : 'mysql:database=') . $cfg->{DBNAME};
+ $dsn .= ';hostname='.$cfg->{DBHOST} if $cfg->{DBHOST} ne 'localhost';
+ my $dbh = DBI->connect($dsn, $cfg->{DBUSER}, $cfg->{DBPASS},
+ {'PrintError' => 1,
+ 'RaiseError' => 0}) or die "Can't connect to database: $DBI::errstr\n";
+ return $dbh;
+}
+
+sub fetch_dates
+{
+ my $delta = $cfg->{DATES_DELTA};
+ $delta = 1 unless defined $delta;
+
+ my $sql = sprintf("SELECT date_dates.id,date,name FROM date_dates JOIN date_types ON type = date_types.id " .
+ "WHERE notify = 1 AND date = now()::date + interval '%d days' ORDER BY name",
+ $delta);
+ my $sth = $db->prepare($sql);
+ $sth->execute;
+ return $sth->fetchall_hashref('id');
+}
+
+sub send_reminder
+{
+ my $dates = shift;
+ my $body;
+ my @datenames;
+
+ my @wdays = qw/Sonntag Montag Dienstag Mittwoch Donnerstag Freitag Samstag Sonntag/;
+ foreach my $row (values %$dates) {
+ my ($year,$month,$day) = split(/-/, $row->{date});
+ my $dow = $wdays[Day_of_Week($year,$month,$day)];
+ $body .= sprintf("\n%-10s %s %s\n", $dow, $row->{date}, $row->{name});
+ push @datenames, $row->{name};
+ }
+
+ my %mail = ('To' => $cfg->{DATES_REMINDER},
+ 'From' => sprintf('%s <%s>', $cfg->{TITLE}, $cfg->{MAIL_FROM}),
+ 'Subject' => encode("MIME-Header", decode('UTF-8', join(', ', @datenames))),
+ 'Content-type' => 'text/plain; charset=UTF-8',
+ 'Content-Transfer-Encoding' => '8bit',
+ 'Message' => $body,
+ );
+
+ sendmail(%mail) or die $Mail::Sendmail::error;
+}
+
+$cfg = config_read;
+die "Missing define for DATES_REMINDER" unless $cfg->{DATES_REMINDER};
+$db = dbconnect;
+my $dates = fetch_dates;
+send_reminder $dates if keys %$dates;
--- /dev/null
+<?php
+
+define('MODULE', 'documents');
+
+$href = sprintf("new Rico.TableColumn.link('%s%s','_new')",
+ Hallinta::instance()->urlbase(),
+ 'ajax/ajax.php?id={0}&source=documents__files&func=file&name=download');
+
+JavaScript::instance()->file('lib/ricoTableColumnDB.js');
+
+Actions::instance()->addLink(new Link(array('id' => 'btn_clear',
+ 'icon' => Hallinta::instance()->urlbase().'images/icons/clean.png',
+ 'title' => 'Clear selection',
+ 'function' => 'clear_selection')));
+Actions::instance()->addLink(new Link(array('id' => 'btn_archive',
+ 'icon' => Hallinta::instance()->urlbase().'images/icons/download16.png',
+ 'title' => 'Download as ZIP',
+ 'function' => 'name_popup_open')));
+
+$jscode = <<<EOC
+var name_popup = false;
+function name_popup_open()
+{
+ if (!name_popup) {
+ var options = { hideOnClick: false, canDragFunc: true };
+
+ name_popup = new Rico.Window('Archiv-Name', options);
+
+ load_template('popup/filename', {}, function(name, data){
+ name_popup.contentDiv.innerHTML = data;
+ $('#form_name').select();
+ });
+
+ name_popup.centerPopup();
+ } else {
+ name_popup.openPopup();
+ $('#form_name').select();
+ }
+
+ return false;
+}
+
+function build_zip(obj)
+{
+ if (!$('#form_name').val().length) return false;
+
+ name_popup.closePopup();
+ Hallinta.showMsg('Bitte warten, das Archiv wird erstellt...');
+
+ ajax_request('function', 'callback=archive&name='+encodeURIComponent($('#form_name').val()), function(data){
+ Hallinta.hideMsg();
+ info('Archiv erstellt');
+ window.open(Hallinta.baseURL + 'ajax/ajax.php?source='+Hallinta.pageSource+'&func=file&name=archive','_blank');
+ });
+
+ return false;
+}
+
+function clear_selection()
+{
+ ajax_request('function', 'callback=clear', function(data){
+ info('Auswahl geleert');
+ Hallinta.showMsg('Auswahl geleert', {timeout: 3});
+
+ grid_update(Hallinta.grid);
+ });
+
+ return false;
+}
+
+EOC;
+
+JavaScript::instance()->add($jscode);
+
+$sql_download = "
+CASE
+WHEN substring(lower(path),length(path)-3+1) = 'png' THEN '<img src=\"IMGPATH/png.png\" title=\"Download PNG\">'
+WHEN substring(lower(path),length(path)-3+1) = 'pdf' THEN '<img src=\"IMGPATH/pdf.gif\" title=\"Download PDF\">'
+WHEN substring(lower(path),length(path)-3+1) = 'zip' THEN '<img src=\"IMGPATH/zip.gif\" title=\"Download Zip\">'
+WHEN substring(lower(path),length(path)-3+1) = 'csv' THEN '<img src=\"IMGPATH/csv.gif\" title=\"Download CSV \">'
+WHEN substring(lower(path),length(path)-3+1) = 'odt' THEN '<img src=\"IMGPATH/odt.png\" title=\"Download Odt\">'
+WHEN substring(lower(path),length(path)-3+1) = 'doc' THEN '<img src=\"IMGPATH/doc.gif\" title=\"Download Doc\">'
+WHEN substring(lower(path),length(path)-4+1) = 'docx' THEN '<img src=\"IMGPATH/doc.gif\" title=\"Download Doc\">'
+WHEN substring(lower(path),length(path)-3+1) = 'xls' THEN '<img src=\"IMGPATH/xls.png\" title=\"Download spreadsheet\">'
+WHEN substring(lower(path),length(path)-4+1) = 'xlsx' THEN '<img src=\"IMGPATH/xls.png\" title=\"Download spreadsheet\">'
+WHEN substring(lower(path),length(path)-3+1) = 'ods' THEN '<img src=\"IMGPATH/table.png\" title=\"Download spreadsheet\">'
+WHEN substring(lower(path),length(path)-8+1) = 'gnumeric' THEN '<img src=\"IMGPATH/gnumeric.png\" title=\"Download spreadsheet\">'
+WHEN substring(lower(path),length(path)-6+1) = 'tar.gz' THEN '<img src=\"IMGPATH/zip.gif\" title=\"Download Tar\">'
+WHEN substring(lower(path),length(path)-7+1) = 'tar.bz2' THEN '<img src=\"IMGPATH/zip.gif\" title=\"Download Tar\">'
+WHEN substring(lower(path),length(path)-3+1) = 'gif' THEN '<img src=\"IMGPATH/image.gif\" title=\"Download image\">'
+WHEN substring(lower(path),length(path)-3+1) = 'tex' THEN '<img src=\"IMGPATH/tex.png\" title=\"Download TeX file\">'
+WHEN substring(lower(path),length(path)-3+1) = 'sql' THEN '<img src=\"IMGPATH/sql.png\" title=\"Download SQL file\">'
+WHEN substring(lower(path),length(path)-3+1) = 'txt' THEN '<img src=\"IMGPATH/text.png\" title=\"Download text file\">'
+WHEN substring(lower(path),length(path)-3+1) = 'jpg' THEN '<img src=\"IMGPATH/graphic.gif\" title=\"Display image\">'
+WHEN substring(lower(path),length(path)-4+1) = 'epub' THEN '<img src=\"IMGPATH/ebook.gif\" title=\"Download e-book\">'
+WHEN substring(lower(path),length(path)-4+1) = 'html' THEN '<img src=\"IMGPATH/html.png\" title=\"Display HTML\">'
+ELSE '<img src=\"IMGPATH/download.png\" title=\"download\">'
+END
+";
+
+$sql_download = str_replace('IMGPATH', Hallinta::instance()->urlbase().'images/icons', $sql_download);
+
+$mask = array(
+ 'table' => 'doc_files',
+ 'title' => 'Dokumente',
+ 'list' => array(
+ 'id' => array(
+ 'name' => 'ID',
+ 'visible' => false,
+ ),
+ 'owner' => array(
+ 'name' => 'Besitzer',
+ 'sqltype' => 'int',
+ 'width' => 90,
+ 'filter' => 's',
+ 'specs' => array('ClassName' => 'aligncenter'),
+ 'control' => "new Rico.TableColumn.lookup(".grid_lookup_sql('doc_owner','id','name').", 0, '')",
+ 'distinct' => "SELECT DISTINCT owner,name FROM doc_files JOIN doc_owner ON owner = doc_owner.id ORDER BY name",
+ ),
+ 'type' => array(
+ 'name' => 'Typ',
+ 'sqltype' => 'int',
+ 'width' => 90,
+ 'filter' => 's',
+ 'specs' => array('ClassName' => 'aligncenter'),
+ 'control' => "new Rico.TableColumn.lookup(".grid_lookup_sql('doc_types','id','name').", 0, '')",
+ 'distinct' => "SELECT DISTINCT type,name FROM doc_files JOIN doc_types ON type = doc_types.id ORDER BY name",
+ ),
+ 'extract(year from date)' => array(
+ 'name' => 'Jahr',
+ 'sqltype' => 'int',
+ 'specs' => array('ClassName' => 'aligncenter'),
+ 'filter' => 's',
+ 'width' => 50,
+ 'distinct' => "SELECT DISTINCT extract(year from date) AS year FROM doc_files ORDER BY year DESC",
+ ),
+ 'date' => array(
+ 'name' => 'Datum',
+ 'sqltype' => 'date',
+ 'filter' => 't^8',
+ 'width' => 85,
+ ),
+ 'title' => array(
+ 'name' => 'Titel',
+ 'width' => 345,
+ 'filter' => 't',
+ ),
+ 'path' => array(
+ 'name' => 'Pfad',
+ 'width' => 250,
+ 'filter' => 't',
+ 'visible' => false,
+ ),
+ 'download' => array(
+ 'name' => 'DL',
+ 'width' => 25,
+ 'specs' => array('ClassName' => 'aligncenter', 'canSort' => false),
+ 'control' => $href,
+ 'sql' => $sql_download,
+ ),
+ 'selected' => array(
+ 'name' => 'Sel',
+ 'width' => 40,
+ 'sql' => '(SELECT count(*) FROM doc_files_selection WHERE user_ = '
+ . intval($_SESSION['sys']['uid'])
+ . ' AND file = doc_files.id)',
+ 'control' => "new Rico.TableColumn.checkboxDB(0, 'ajax/ricoUpdateConnection.php')",
+ 'filter' => 'c',
+ 'specs' => array('ClassName' => 'aligncenter has-checkbox', 'canSort' => false),
+ 'update' => array('table' => 'doc_files_selection',
+ 'basecol' => 'user_',
+ 'baseval' => $_SESSION['sys']['uid'],
+ 'refcol' => 'file',
+ 'reftable' => 'doc_files',
+ 'refid' => 'doc_files.id',
+ ),
+ ),
+ ),
+ 'files' => array(
+ 'download' => process_download,
+ 'archive' => process_archive,
+ ),
+ 'callbacks' => array(
+ 'clear' => cb_clear,
+ 'archive' => cb_archive,
+ ),
+ );
+
+function mk_tempdir()
+{
+ $tmpdir = sprintf("%sarchive/%s/%s",
+ $_SESSION['sys']['basedir'],
+ MODULE,
+ md5(date('c')));
+ mkdir($tmpdir,0777);
+
+ return $tmpdir;
+}
+
+function rm_tempdir($dir)
+{
+ system(sprintf("rm -rf %s", $dir));
+}
+
+function process_download()
+{
+ global $mask;
+
+ download_file($mask['table'],'path',MODULE,$_GET['id']);
+}
+
+function process_archive()
+{
+ $fname = $_SESSION['files_zipfile'];
+
+ if (!file_exists($fname) || !is_file($fname))
+ return 'File not found';
+
+ send_file($fname);
+ rm_tempdir($_SESSION['files_tmpdir']);
+
+ unset($_SESSION['files_tmpdir']);
+ unset($_SESSION['files_zipfile']);
+}
+
+function cb_clear()
+{
+ global $db;
+
+ return $db->execute(sprintf("DELETE FROM doc_files_selection WHERE user_ = %d", $_SESSION['sys']['uid']));
+}
+
+function cb_archive()
+{
+ global $db;
+
+ $sql = sprintf("SELECT date,title,path FROM doc_files JOIN doc_files_selection ON file = doc_files.id WHERE user_ = %d ORDER BY date, doc_files.id",
+ $_SESSION['sys']['uid']);
+
+ $tmpdir = mk_tempdir();
+
+ chdir($tmpdir.'/..');
+
+ $zipfile = $tmpdir.'/'.$_POST['name'].'.zip';
+ $cmd = sprintf("zip -q -u --names-stdin %s", escapeshellarg($zipfile));
+
+error_log($cmd);
+ $p = popen($cmd, 'w');
+ if (!$p) return array('error' => 'Kann ZIP nicht aufrufen');
+
+ $text = '';
+ foreach ($db->fetchObjectList($sql) as $row) {
+ fwrite($p, $row->path . "\n");
+ $text .= sprintf("%s %-60s %s\n", $row->date, $row->title, $row->path);
+ }
+
+ if (strlen($text))
+ $text = sprintf("%s %-60s %s\n", 'Date', 'Description', 'Path') . $text;
+
+ $f = fopen('content.txt', 'w');
+ if ($f !== false) {
+ fwrite($f, $text);
+ fclose($f);
+ fwrite($p, "content.txt\n");
+ }
+ pclose($p);
+ if (file_exists('content.txt'))
+ unlink('content.txt');
+
+ $_SESSION['files_tmpdir'] = $tmpdir;
+ $_SESSION['files_zipfile'] = $zipfile;
+
+ return true;
+}
<?php
-$href = "new Rico.TableColumn.link('ajax/ajax.php?id={0}&source=documents__files&func=file&name=download','_new')";
+if (file_exists(__DIR__.'/files_config.php'))
+ # scanadf --list-devices
+ require_once(__DIR__.'/files_config.php');
+
+$href = sprintf("new Rico.TableColumn.link('%s%s','_new')",
+ Hallinta::instance()->urlbase(),
+ 'ajax/ajax.php?id={0}&source=documents__files&func=file&name=download');
+
+JavaScript::instance()->add("Hallinta.closeDialogAfterInsert = false;");
+JavaScript::instance()->add("Hallinta.fetchItemAfterInsert = true;");
+JavaScript::instance()->add("Hallinta.preInsert = check_insert_file;");
+JavaScript::instance()->add("Hallinta.postFetch = files_post_fetch;");
+
+if (basename($_SERVER['SCRIPT_NAME']) == 'index.php' && ScannerBase::getScanner()->hasScanner()) {
+ $icon = Hallinta::instance()->urlbase().'masks/'.basename(__DIR__).'/icon/scanner.png';
+ Actions::instance()->addLink(new Link(array('id' => 'btn_scan',
+ 'icon' => $icon,
+ 'title' => 'Open Scanner',
+ 'function' => 'open_scanner')));
+}
+
+$jscode = <<<EOC
+var files_scanner_popup = false;
+var files_scanner_close_popup = false;
+var files_scanner_arrange_popup = false;
+var files_scanner_saving = false;
+function check_insert_file()
+{
+ if (files_scanner_popup && files_scanner_popup.visible() && !\$('#edit_id').val().length)
+ return true;
+
+ if (!\$('#edit_path').val().length) {
+ Hallinta.showMsg('Bitte eine Datei auswählen', {timeout: 5});
+ error('File missing');
+ return false;
+ }
+
+ return true;
+}
+
+function scanner_url(type)
+{
+ if (type == 'download')
+ var url = Hallinta.baseURL + 'ajax/ajax.php?func=file&name=download&source=' + Hallinta.pageSource;
+ else if (type == 'scanner')
+ var url = Hallinta.baseURL + 'ajax/ajax.php?func=file&name=scanner&source=' + Hallinta.pageSource;
+ else
+ var url = Hallinta.baseURL + 'ajax/ajax.php?func=file&name=preview&source=' + Hallinta.pageSource;
+
+ return url;
+}
+
+function close_scanner()
+{
+ if (files_scanner_close_popup) {
+ files_scanner_close_popup.openPopup();
+ } else {
+ files_scanner_close_popup = new Rico.Window('Scanner');
+ ajax_request('template', 'template=popup/close', function(data){
+ \$(files_scanner_close_popup.contentDiv).html(data);
+ files_scanner_close_popup.centerPopup();
+ });
+ }
+}
+
+function open_scanner()
+{
+ Hallinta.editDialog.closePopup();
+
+ if (files_scanner_popup) {
+ files_scanner_popup.openPopup();
+ } else {
+ files_scanner_popup = new Rico.Window('Scanner', {onClose: close_scanner});
+ ajax_callback('scanner', null, function(data){
+ \$(files_scanner_popup.contentDiv).html(data.html);
+ \$('#preview').css('max-width', (window.innerWidth-35) + 'px')
+ \$('#preview').css('max-height', (window.innerHeight-110) + 'px')
+ \$('#preview_img').on('load', function(){
+ files_scanner_popup.centerPopup();
+ });
+ if (data.preview) {
+ \$('#preview_img').attr('src', scanner_url('preview')).show();
+ } else {
+ files_scanner_popup.centerPopup();
+ }
+ });
+ }
+}
+
+function scanner_preview()
+{
+ Hallinta.showMsg("Bitte warten, das Dokument wird gescannt...");
+ ajax_callback('preview', null, function(data){
+ var time = (new Date()).toUTCString();
+ \$('#preview_img').attr('src', scanner_url('preview')+'&'+time).show();
+ files_scanner_popup.centerPopup();
+ Hallinta.hideMsg();
+ });
+}
+
+function scanner_rotate(direction)
+{
+ Hallinta.showMsg("Bitte warten, die Vorschau wird gedreht...");
+ ajax_callback('rotate', 'direction='+direction, function(data){
+ var time = (new Date()).toUTCString();
+ \$('#preview_img').attr('src', scanner_url('preview')+'&'+time).show();
+ files_scanner_popup.centerPopup();
+ Hallinta.hideMsg();
+ });
+}
+
+function scanner_download()
+{
+ Hallinta.showMsg("Bitte warten, die Datei wird vorbereitet...");
+ ajax_callback('download', null, function(data){
+ Hallinta.hideMsg();
+ window.location.href = scanner_url('scanner');
+ });
+}
+
+function files_post_fetch(data)
+{
+ if (files_scanner_saving) {
+ Hallinta.editDialog.closePopup();
+ files_scanner_saving = false;
+
+ set_value('edit_id', '');
+ set_value('edit_path', '');
+ set_value('edit_path_source', '');
+ set_value('edit_real_path', '');
+ }
+}
+
+function scanner_save()
+{
+ files_scanner_saving = true;
+ Hallinta.openEditDialog();
+ button_enable('button_insert');
+ set_value('edit_id', '');
+ set_value('edit_path', '');
+ set_value('edit_path_source', 'scanner');
+ set_value('edit_real_path', 'Dokument vom Scanner');
+}
+
+function scanner_tidy()
+{
+ ajax_callback('tidy', null, function(data){
+ files_scanner_close_popup.closePopup();
+ });
+}
+
+function scanner_store()
+{
+ ajax_callback('store', null, function(data){
+ Hallinta.showMsg("Scan als Seite " + data.page + " gespeichert.", {timeout: 2});
+ ajax_callback('peep', {name: data.name});
+ });
+}
+
+function close_arrange()
+{
+ if (files_scanner_close_popup) {
+ files_scanner_close_popup.openPopup();
+ } else {
+ files_scanner_close_popup = new Rico.Window('Scanner');
+ ajax_request('template', 'template=popup/close', function(data){
+ \$(files_scanner_close_popup.contentDiv).html(data);
+ files_scanner_close_popup.centerPopup();
+ });
+ }
+}
+
+function load_arrange_content()
+{
+ ajax_callback('arrange', null, function(data){
+ \$(files_scanner_arrange_popup.contentDiv).html(data.html);
+ \$('#spreview').css('max-width', (window.innerWidth-35) + 'px')
+ \$('#spreview').css('max-height', (window.innerHeight-110) + 'px')
+ \$('#spreview img.peep').on('load', function(){
+ \$(this).parents('div.page').show();
+ files_scanner_arrange_popup.centerPopup();
+ });
+
+ files_scanner_arrange_popup.centerPopup();
+ });
+}
+
+function open_arrange()
+{
+ if (files_scanner_arrange_popup) {
+ files_scanner_arrange_popup.openPopup();
+ } else {
+ files_scanner_arrange_popup = new Rico.Window('Anordnen', {zIndex: 4});
+ }
+
+ load_arrange_content();
+}
+
+function arrangement_download()
+{
+ Hallinta.showMsg("Bitte warten, die Datei wird vorbereitet...");
+ ajax_callback('series', null, function(data){
+ Hallinta.hideMsg();
+ window.location.href = scanner_url('scanner')+'&series=1';
+ });
+}
+
+function arrangement_up(o)
+{
+ ajax_callback('arrange_up', 'name='+\$(o).parents('div.page').data('name'), function(data){
+ load_arrange_content();
+ });
+
+ return false;
+}
+
+function arrangement_down(o)
+{
+ ajax_callback('arrange_down', 'name='+\$(o).parents('div.page').data('name'), function(data){
+ load_arrange_content();
+ });
+
+ return false;
+}
+
+function arrangement_del(o)
+{
+ ajax_callback('arrange_del', 'name='+\$(o).parents('div.page').data('name'), function(data){
+ load_arrange_content();
+ });
+
+ return false;
+}
+
+function arrangement_save()
+{
+ Hallinta.openEditDialog();
+ button_enable('button_insert');
+ set_value('edit_id', '');
+ set_value('edit_path', '');
+ set_value('edit_path_source', 'series');
+ set_value('edit_real_path', 'Mehrseitiges Dokument vom Scanner');
+}
+
+function arrangement_tidy()
+{
+ ajax_callback('series_tidy', null, function(data){
+ files_scanner_arrange_popup.closePopup();
+ });
+}
+
+EOC;
+
+JavaScript::instance()->add($jscode);
$sql_download = "
CASE
-WHEN substring(lower(path),length(path)-3+1) = 'png' THEN '<img src=\"images/icons/png.png\" title=\"Download PNG\">'
-WHEN substring(lower(path),length(path)-3+1) = 'pdf' THEN '<img src=\"images/icons/pdf.gif\" title=\"Download PDF\">'
-WHEN substring(lower(path),length(path)-3+1) = 'zip' THEN '<img src=\"images/icons/zip.gif\" title=\"Download Zip\">'
-WHEN substring(lower(path),length(path)-3+1) = 'odt' THEN '<img src=\"images/icons/odt.png\" title=\"Download Odt\">'
-WHEN substring(lower(path),length(path)-3+1) = 'doc' THEN '<img src=\"images/icons/doc.gif\" title=\"Download Doc\">'
-WHEN substring(lower(path),length(path)-4+1) = 'docx' THEN '<img src=\"images/icons/doc.gif\" title=\"Download Doc\">'
-WHEN substring(lower(path),length(path)-3+1) = 'xls' THEN '<img src=\"images/icons/xls.png\" title=\"Download spreadsheet\">'
-WHEN substring(lower(path),length(path)-4+1) = 'xlsx' THEN '<img src=\"images/icons/xls.png\" title=\"Download spreadsheet\">'
-WHEN substring(lower(path),length(path)-3+1) = 'ods' THEN '<img src=\"images/icons/table.png\" title=\"Download spreadsheet\">'
-WHEN substring(lower(path),length(path)-6+1) = 'tar.gz' THEN '<img src=\"images/icons/zip.gif\" title=\"Download Tar\">'
-WHEN substring(lower(path),length(path)-7+1) = 'tar.bz2' THEN '<img src=\"images/icons/zip.gif\" title=\"Download Tar\">'
-WHEN substring(lower(path),length(path)-3+1) = 'gif' THEN '<img src=\"images/icons/image.gif\" title=\"Download image\">'
-WHEN substring(lower(path),length(path)-3+1) = 'tex' THEN '<img src=\"images/icons/tex.png\" title=\"Download TeX file\">'
-WHEN substring(lower(path),length(path)-3+1) = 'sql' THEN '<img src=\"images/icons/sql.png\" title=\"Download SQL file\">'
-WHEN substring(lower(path),length(path)-3+1) = 'txt' THEN '<img src=\"images/icons/text.png\" title=\"Download text file\">'
-ELSE '<img src=\"images/icons/download.gif\" title=\"download\">'
+WHEN substring(lower(path),length(path)-3+1) = 'png' THEN '<img src=\"IMGPATH/png.png\" title=\"Download PNG\">'
+WHEN substring(lower(path),length(path)-3+1) = 'pdf' THEN '<img src=\"IMGPATH/pdf.gif\" title=\"Download PDF\">'
+WHEN substring(lower(path),length(path)-3+1) = 'zip' THEN '<img src=\"IMGPATH/zip.gif\" title=\"Download Zip\">'
+WHEN substring(lower(path),length(path)-2+1) = '7z' THEN '<img src=\"IMGPATH/zip.gif\" title=\"Download 7-Zip\">'
+WHEN substring(lower(path),length(path)-3+1) = 'csv' THEN '<img src=\"IMGPATH/csv.gif\" title=\"Download CSV \">'
+WHEN substring(lower(path),length(path)-3+1) = 'odt' THEN '<img src=\"IMGPATH/odt.png\" title=\"Download Odt\">'
+WHEN substring(lower(path),length(path)-3+1) = 'doc' THEN '<img src=\"IMGPATH/doc.gif\" title=\"Download Doc\">'
+WHEN substring(lower(path),length(path)-4+1) = 'docx' THEN '<img src=\"IMGPATH/doc.gif\" title=\"Download Doc\">'
+WHEN substring(lower(path),length(path)-3+1) = 'xls' THEN '<img src=\"IMGPATH/xls.png\" title=\"Download spreadsheet\">'
+WHEN substring(lower(path),length(path)-4+1) = 'xlsx' THEN '<img src=\"IMGPATH/xls.png\" title=\"Download spreadsheet\">'
+WHEN substring(lower(path),length(path)-3+1) = 'ods' THEN '<img src=\"IMGPATH/table.png\" title=\"Download spreadsheet\">'
+WHEN substring(lower(path),length(path)-8+1) = 'gnumeric' THEN '<img src=\"IMGPATH/gnumeric.png\" title=\"Download spreadsheet\">'
+WHEN substring(lower(path),length(path)-6+1) = 'tar.gz' THEN '<img src=\"IMGPATH/zip.gif\" title=\"Download Tar\">'
+WHEN substring(lower(path),length(path)-7+1) = 'tar.bz2' THEN '<img src=\"IMGPATH/zip.gif\" title=\"Download Tar\">'
+WHEN substring(lower(path),length(path)-3+1) = 'gif' THEN '<img src=\"IMGPATH/image.gif\" title=\"Download image\">'
+WHEN substring(lower(path),length(path)-3+1) = 'tex' THEN '<img src=\"IMGPATH/tex.png\" title=\"Download TeX file\">'
+WHEN substring(lower(path),length(path)-3+1) = 'sql' THEN '<img src=\"IMGPATH/sql.png\" title=\"Download SQL file\">'
+WHEN substring(lower(path),length(path)-3+1) = 'txt' THEN '<img src=\"IMGPATH/text.png\" title=\"Download text file\">'
+WHEN substring(lower(path),length(path)-3+1) = 'jpg' THEN '<img src=\"IMGPATH/graphic.gif\" title=\"Display image\">'
+WHEN substring(lower(path),length(path)-4+1) = 'epub' THEN '<img src=\"IMGPATH/ebook.gif\" title=\"Download e-book\">'
+WHEN substring(lower(path),length(path)-4+1) = 'html' THEN '<img src=\"IMGPATH/html.png\" title=\"Display HTML\">'
+ELSE '<img src=\"IMGPATH/download.png\" title=\"download\">'
END
";
+$sql_download = str_replace('IMGPATH', Hallinta::instance()->urlbase().'images/icons', $sql_download);
+
+$monthlist = ['1' => 'Januar',
+ '2' => 'Februar',
+ '3' => 'März',
+ '4' => 'April',
+ '5' => 'Mai',
+ '6' => 'Juni',
+ '7' => 'Juli',
+ '8' => 'August',
+ '9' => 'September',
+ '10' => 'Oktober',
+ '11' => 'November',
+ '12' => 'Dezember'];
+
$mask = array(
'table' => 'doc_files',
'title' => 'Dokumente',
+ 'sort' => 1,
+ 'sortdir' => 'DESC',
'list' => array(
'id' => array(
'name' => 'ID',
'visible' => false,
),
+ 'date||\'-\'||lpad(id::text, 5, \'0\')' => array(
+ 'name' => 'SortCol',
+ 'visible' => false,
+ ),
'owner' => array(
'name' => 'Besitzer',
+ 'sqltype' => 'int',
'width' => 90,
- 'specs' => "ClassName: 'aligncenter', filterUI: 's'",
+ 'filter' => 's',
+ 'specs' => array('ClassName' => 'aligncenter'),
'control' => "new Rico.TableColumn.lookup(".grid_lookup_sql('doc_owner','id','name').", 0, '')",
'distinct' => "SELECT DISTINCT owner,name FROM doc_files JOIN doc_owner ON owner = doc_owner.id ORDER BY name",
),
'type' => array(
'name' => 'Typ',
+ 'sqltype' => 'int',
'width' => 90,
- 'specs' => "ClassName: 'aligncenter', filterUI: 's'",
+ 'filter' => 's',
+ 'specs' => array('ClassName' => 'aligncenter'),
'control' => "new Rico.TableColumn.lookup(".grid_lookup_sql('doc_types','id','name').", 0, '')",
'distinct' => "SELECT DISTINCT type,name FROM doc_files JOIN doc_types ON type = doc_types.id ORDER BY name",
),
+ 'extract(year from date)' => array(
+ 'name' => 'Jahr',
+ 'sqltype' => 'int',
+ 'specs' => array('ClassName' => 'aligncenter'),
+ 'filter' => 's',
+ 'width' => 50,
+ 'distinct' => "SELECT DISTINCT extract(year from date) AS year FROM doc_files ORDER BY year DESC",
+ ),
+ 'extract(month from date)' => array(
+ 'name' => 'Monat',
+ 'sqltype' => 'int',
+ 'specs' => array('ClassName' => 'aligncenter'),
+ 'filter' => 's',
+ 'width' => 50,
+ 'control' => "new Rico.TableColumn.lookup(".json_encode($monthlist).", 0, '')",
+ 'distinct' => "SELECT DISTINCT extract(month from date) AS month FROM doc_files ORDER BY month ASC",
+ ),
'date' => array(
'name' => 'Datum',
- 'width' => 85,
+ 'sqltype' => 'date',
+ 'filter' => 't^5',
+ 'width' => 80,
),
'title' => array(
'name' => 'Titel',
'width' => 345,
- 'specs' => "filterUI: 't'",
+ 'filter' => 't',
+ ),
+ 'filename' => array(
+ 'name' => 'Datei',
+ 'width' => 200,
+ 'filter' => 't',
+ 'visible' => false,
+ 'sql' => "regexp_replace(path, '.+/', '')",
+ ),
+ 'path' => array(
+ 'name' => 'Pfad',
+ 'width' => 300,
+ 'filter' => 't',
+ 'visible' => false,
),
'download' => array(
'name' => 'DL',
'width' => 25,
- 'specs' => "ClassName: 'aligncenter', canSort: false",
+ 'specs' => array('ClassName' => 'aligncenter', 'canSort' => false),
'control' => $href,
'sql' => $sql_download,
),
'name' => 'Dokument',
'type' => 'file',
'path' => 'documents',
+ 'source' => 'use_from_scanner',
+ 'sql' => false,
+ ),
+ 'path_source' => array(
+ 'name' => 'Dokument Source',
+ 'type' => 'hidden',
'sql' => false,
+ 'ignore' => true,
),
'keywords' => array(
'name' => 'Schlagworte',
),
),
'files' => array(
- 'download' => process_download,
+ 'download' => 'process_download',
+ 'preview' => 'process_preview',
+ 'scanner' => 'process_scanner',
),
+ 'delete' => 'delete_file',
);
function process_download()
{
global $mask;
- download_file($mask['table'],'path',$mask['edit']['path']['path'],$_GET['id']);
+ if ($_SESSION['sys']['login'] == 'joey')
+ $inline = true;
+ else
+ $inline = false;
+
+ download_file($mask['table'],'path',$mask['edit']['path']['path'],$_GET['id'],$inline);
+}
+
+function process_preview()
+{
+ if (isset($_GET['id'])) {
+ assert_peep_image($_GET['id']);
+ $path = get_scandir() . $_SESSION['sys']['login'] . '.' . $_GET['id'] . '.png';
+ } else {
+ $path = Hallinta::instance()->basedir() . get_preview_png();
+ }
+ send_file($path, true);
+}
+
+function process_scanner()
+{
+ if (isset($_GET['series']))
+ $preview_pdf = 'archive/documents/scanner/'.$_SESSION['sys']['login'].'.series.pdf';
+ else
+ $preview_pdf = 'archive/documents/scanner/'.$_SESSION['sys']['login'].'.pdf';
+
+ send_file(Hallinta::instance()->basedir() . $preview_pdf, false);
+}
+
+function delete_file()
+{
+ global $db;
+
+ $sql = sprintf("SELECT path FROM doc_files WHERE id = %d", $_POST['id']);
+ $sth = $db->query($sql);
+ $row = $sth->fetch();
+
+ if (unlink($_SESSION['sys']['basedir'] . 'archive/documents/'.$row['path']) === false)
+ return array('error' => 'Cannot delete file');
+
+ $sql = sprintf("DELETE FROM doc_files WHERE id = %d", $_POST['id']);
+ $db->query($sql);
+
+ return array('status' => true);
+}
+
+/*
+ * Convenience functions:
+ * get_scandir()
+ * get_preview_pnm()
+ * get_preview_png()
+ * get_series_file()
+ */
+function get_scandir()
+{
+ return Hallinta::instance()->basedir() . 'archive/documents/scanner/';
+}
+
+function get_preview_pnm()
+{
+ return get_scandir() . $_SESSION['sys']['login'] . '.pnm';
+}
+
+function get_preview_png()
+{
+ return 'archive/documents/scanner/'.$_SESSION['sys']['login'].'.png';
+}
+
+function get_series_file()
+{
+ return get_scandir() . $_SESSION['sys']['login'] . '.series';
+}
+
+function pnm2pdf()
+{
+ $scanner = ScannerBase::getScanner();
+
+ // TODO: Use arranged pages
+ $preview_pnm = get_preview_pnm();
+ $preview_pdf = 'archive/documents/scanner/'.$_SESSION['sys']['login'].'.pdf';
+
+ $scanner->convertPNMtoPDF($preview_pnm, Hallinta::instance()->basedir() . $preview_pdf);
+
+ return $preview_pdf;
+}
+
+/*
+ * Series processing:
+ * series_tidy();
+ * series_load();
+ * series_save(Array $list);
+ * series_append();
+ * assert_peep_image($name);
+ * assert_peep_pdf($name);
+ */
+function series_load()
+{
+ $series = get_series_file();
+
+ if (!file_exists($series))
+ return [];
+
+ $list = [];
+ foreach (explode("\n", file_get_contents($series)) as $name)
+ if (strlen($name))
+ $list[] = $name;
+
+ return $list;
+}
+
+function series_tidy()
+{
+ $dir = get_scandir();
+ $list = series_load();
+
+ foreach ($list as $name) {
+ $path = $dir.$_SESSION['sys']['login'].'.'.$name.'.pnm';
+ if (file_exists($path)) unlink($path);
+ $path = $dir.$_SESSION['sys']['login'].'.'.$name.'.png';
+ if (file_exists($path)) unlink($path);
+ }
+
+ series_save([]);
+}
+
+function series_save(Array $list)
+{
+ $series = get_series_file();
+
+ if (file_exists($series))
+ unlink($series);
+
+ $content = "";
+ foreach ($list as $name)
+ if ($name)
+ $content .= $name . "\n";
+
+ file_put_contents($series, $content);
+}
+
+function series_append()
+{
+ $list = series_load();
+
+ $name = md5(time());
+ $new_pnm = $_SESSION['sys']['login'] . '.' . $name . '.pnm';
+
+ $preview_pnm = get_preview_pnm();
+
+ if (!file_exists($preview_pnm))
+ throw new Exception("No preview available");
+
+ copy($preview_pnm, get_scandir() . $new_pnm);
+ $list[] = $name;
+
+ series_save($list);
+
+ return ['page' => count($list), 'name' => $name];
+}
+
+function series_delete_file($name)
+{
+ $dir = get_scandir();
+
+ $path = $dir . $_SESSION['sys']['login'].'.'.$name.'.pnm';
+ if (file_exists($path)) unlink($path);
+ $path = $dir . $_SESSION['sys']['login'].'.'.$name.'.png';
+ if (file_exists($path)) unlink($path);
+ $path = $dir . $_SESSION['sys']['login'].'.'.$name.'.pdf';
+ if (file_exists($path)) unlink($path);
+}
+
+function assert_peep_image($name)
+{
+ $dir = get_scandir();
+ $new_png = $_SESSION['sys']['login'] . '.' . $name . '.png';
+
+ if (file_exists($dir.$new_png)) return;
+
+ $new_pnm = $_SESSION['sys']['login'] . '.' . $name . '.pnm';
+ $cmd = sprintf("convert -geometry 250 %s %s",
+ escapeshellarg($dir.$new_pnm),
+ escapeshellarg($dir.$new_png));
+
+ system($cmd);
+}
+
+function assert_peep_pdf($name)
+{
+ $scanner = ScannerBase::getScanner();
+
+ $dir = get_scandir();
+ $new_pdf = $_SESSION['sys']['login'] . '.' . $name . '.pdf';
+
+ if (file_exists($dir.$new_pdf)) return;
+
+ $new_pnm = $_SESSION['sys']['login'] . '.' . $name . '.pnm';
+ $scanner->convertPNMtoPDF($dir.$new_pnm, $dir.$new_pdf);
+}
+
+function cb_scanner()
+{
+ if (!is_dir(get_scandir()))
+ mkdir(get_scandir(), 0755, true);
+
+ if (!is_writable(get_scandir()))
+ ajax_error('documents/scanner nicht beschreibbar');
+
+ $preview = file_exists(Hallinta::instance()->basedir() . get_preview_png()) ? true : false;
+
+ return ['html' => Template::render('scanner', []), 'preview' => $preview];
+}
+
+function cb_preview()
+{
+ $scanner = ScannerBase::getScanner();
+
+ $preview_pnm = get_preview_pnm();
+ $preview_png = get_preview_png();
+
+ $scanner->scanIntoPNM($preview_pnm);
+ $scanner->convertPNMtoPNG($preview_pnm, Hallinta::instance()->basedir() . $preview_png);
+
+ return ['preview' => Hallinta::instance()->urlbase() . $preview_png];
}
-?>
+function cb_rotate()
+{
+ $scanner = ScannerBase::getScanner();
+
+ $preview_pnm = get_preview_pnm();
+ $preview_png = get_preview_png();
+
+ $scanner->rotatePNM($preview_pnm, $_POST['direction']);
+ $scanner->convertPNMtoPNG($preview_pnm, Hallinta::instance()->basedir() . $preview_png);
+
+ return ['preview' => Hallinta::instance()->urlbase() . $preview_png];
+}
+
+function cb_download()
+{
+ return ['path' => pnm2pdf()];
+}
+
+function cb_store()
+{
+ return series_append();
+}
+
+function cb_peep()
+{
+ $name = $_POST['name'];
+ assert_peep_image($name);
+ assert_peep_pdf($name);
+}
+
+function cb_tidy()
+{
+ $dir = get_scandir();
+
+ foreach (new DirectoryIterator($dir) as $fileInfo) {
+ if ($fileInfo->isDot()) continue;
+ if ($fileInfo->isDir()) continue;
+
+ if (strpos($fileInfo->getFilename(), $_SESSION['sys']['login'].'.') === 0)
+ unlink($dir.$fileInfo->getFilename());
+ }
+}
+
+function cb_series_tidy()
+{
+ $dir = get_scandir();
+
+ foreach (series_load() as $name)
+ series_delete_file($name);
+
+ $path = $dir . $_SESSION['sys']['login'].'.series.pdf';
+ if (file_exists($path)) unlink($path);
+
+ $path = $dir . $_SESSION['sys']['login'].'.series';
+ if (file_exists($path)) unlink($path);
+}
+
+function cb_arrange()
+{
+ $hallinta = Hallinta::instance();
+
+ if (!is_dir(get_scandir()))
+ mkdir(get_scandir(), 0755, true);
+
+ if (!is_writable(get_scandir()))
+ ajax_error('documents/scanner nicht beschreibbar');
+
+ $page = 0;
+ $list = [];
+ foreach (series_load() as $name)
+ $list[] = ['name' => $name,
+ 'page' => ++$page,
+ 'up' => $hallinta->urlbase().'masks/'.basename(__DIR__).'/icon/up-icon.png',
+ 'down' => $hallinta->urlbase().'masks/'.basename(__DIR__).'/icon/down-icon.png',
+ 'delete' => $hallinta->urlbase().'masks/'.basename(__DIR__).'/icon/trash-icon.png',
+ 'src' => sprintf("%sajax/ajax.php?func=file&name=preview&source=%s__%s&id=%s",
+ $hallinta->urlbase(),
+ $hallinta->module(),
+ $hallinta->page(),
+ $name)];
+ if (count($list)) {
+ $list[0]['up'] = false;
+ $list[count($list)-1]['down'] = false;
+ }
+
+ return ['html' => Template::render('arrange', ['list' => $list])];
+}
+
+function cb_series()
+{
+ $dir = get_scandir();
+ $scanner = ScannerBase::getScanner();
+ $files = [];
+
+ foreach (series_load() as $name) {
+ assert_peep_pdf($name);
+ $files[] = $dir . $_SESSION['sys']['login'] . '.' . $name . '.pdf';
+ }
+
+ $outfile = $dir . $_SESSION['sys']['login'] . '.series.pdf';
+
+ $scanner->mergePDF($files, $outfile);
+}
+
+function cb_arrange_del()
+{
+ $list = series_load();
+
+ for ($i=0; $i < count($list); $i++)
+ if ($list[$i] === $_POST['name']) {
+ series_delete_file($list[$i]);
+ unset($list[$i]);
+ }
+ series_save($list);
+}
+
+function cb_arrange_up()
+{
+ $list = series_load();
+
+ for ($i=1; $i < count($list); $i++)
+ if ($list[$i] === $_POST['name']) {
+ $tmp = $list[$i];
+ $list[$i] = $list[$i-1];
+ $list[$i-1] = $tmp;
+ }
+ series_save($list);
+}
+
+function cb_arrange_down()
+{
+ $list = series_load();
+
+ for ($i=0; $i < count($list)-1; $i++)
+ if ($list[$i] === $_POST['name']) {
+ $tmp = $list[$i];
+ $list[$i] = $list[$i+1];
+ $list[$i+1] = $tmp;
+ }
+ series_save($list);
+}
+
+function use_from_scanner($field, $info)
+{
+ if (isset($_POST['path_source']) && $_POST['path_source'] == 'scanner') {
+ $preview_pdf = pnm2pdf();
+ $title = str_replace(["'", "&", ":", "/", "*", "\\"],
+ ['', '', '', '', '', ''],
+ $_POST['title']);
+ list($base, $fname) = unique_pathname($info['path'], $title.'.pdf');
+
+ if (copy(Hallinta::instance()->basedir() . $preview_pdf, $base.$fname) === false)
+ ajax_error("Datei kann nicht kopiert werden");
+
+ return $fname;
+ } elseif (isset($_POST['path_source']) && $_POST['path_source'] == 'series') {
+ cb_series();
+ $preview_pdf = 'archive/documents/scanner/' . $_SESSION['sys']['login'] . '.series.pdf';
+ $title = str_replace(["'", "&", ":", "/", "*", "\\"],
+ ['', '', '', '', '', ''],
+ $_POST['title']);
+ list($base, $fname) = unique_pathname($info['path'], $title.'.pdf');
+
+ if (copy(Hallinta::instance()->basedir() . $preview_pdf, $base.$fname) === false)
+ ajax_error("Datei kann nicht kopiert werden");
+
+ return $fname;
+ } else {
+ return NULL;
+ }
+
+ ajax_error("Something went wrong");
+}
--- /dev/null
+<div>
+<div id="controls" style="margin-bottom:3px;">
+ <button id="btn_scanner_arrange_download" class="builtin" onclick="arrangement_download()" title="PDF-Datei herunterladen">Download</button>
+ <button id="btn_scanner_arrange_save" class="builtin" onclick="arrangement_save()" title="PDF-Datei archivieren">Archivieren</button>
+ <button id="btn_scanner_arrange_tidy" class="builtin" onclick="arrangement_tidy()" title="Alle Seiten löschen / Neu anfangen">Löschen</button>
+</div>
+<div id="spreview" style="min-width:400px;min-height:300px;overflow:auto;">
+<?php foreach ($list as $item) { ?>
+<div class="page" style="display:none;" data-name="<?php echo $item['name'] ?>">
+ <div style="margin-right:40px;float:left">
+ <img class="peep" src="<?php echo $item['src'] ?>" title="Seite <?php echo $item['page'].$item['name'] ?>" />
+ </div>
+ <div style="width:40px;float:left">
+ <div class="hide-on-mobile" style="padding-top:2ex;padding-bottom:3ex;">Seite <?php echo $item['page'] ?></div>
+ <?php if ($item['up']): ?>
+ <img src="<?php echo $item['up'] ?>" onclick="arrangement_up(this)" title="Nach oben" />
+ <?php endif; ?>
+ <?php if ($item['delete']): ?>
+ <img src="<?php echo $item['delete'] ?>" onclick="arrangement_del(this)" title="Löschen" />
+ <?php endif; ?>
+ <?php if ($item['down']): ?>
+ <img src="<?php echo $item['down'] ?>" onclick="arrangement_down(this)" title="Nach unten" />
+ <?php endif; ?>
+ </div>
+</div>
+<?php } ?>
+</div>
+</div>
--- /dev/null
+<div>
+<div style="margin-top:1ex;margin-bottom:3ex;font-weight:bold;">
+Eingescannte Dateien löschen?
+</div>
+<div style="text-align:center;margin-bottom:1ex;">
+<button id="btn_scanner_close_tidy" class="builtin" onclick="scanner_tidy()" title="Dateien löschen">Löschen</button>
+
+<button id="btn_scanner_close_close" class="builtin" onclick="files_scanner_close_popup.closePopup()" title="Nur Schließen">Behalten</button>
+</div>
+</div>
--- /dev/null
+<div id="popup_form_name">
+<form>
+<label for="form_name">Dateiname (ohne Suffix)</label><br>
+<input id="form_name" name="name" size="20">
+<br>
+<div class="buttons" style="margin-top: 15px;">
+<button class="custom" onclick="return build_zip(this);">Datei erstellen</button>
+</div>
+</form>
+</div>
--- /dev/null
+<div>
+<div id="controls" style="margin-bottom:3px;">
+ <button id="btn_scanner_preview" class="builtin" onclick="scanner_preview()" title="Neues Dokument scannen">Scan</button>
+ <button id="btn_scanner_rotate" class="builtin" onclick="scanner_rotate(<?php echo ScannerBase::RIGHT?>)" title="Dokument um 90° drehen">Drehen</button>
+ <button id="btn_scanner_rotate" class="builtin" onclick="scanner_rotate(<?php echo ScannerBase::FLIP?>)" title="Dokument um 180° drehen">Spiegeln</button>
+ <button id="btn_scanner_download" class="builtin" onclick="scanner_download()" title="PDF-Datei herunterladen">Download</button>
+ <button id="btn_scanner_download" class="builtin" onclick="scanner_store()" title="PDF-Datei zur Serie hinzufügen">Parken</button>
+ <button id="btn_scanner_save" class="builtin" onclick="scanner_save()" title="PDF-Datei archivieren">Archivieren</button>
+ <button id="btn_scanner_arrange" class="builtin" onclick="open_arrange()" title="Seiten arrangieren">Mehrseitig</button>
+</div>
+<div id="preview" style="min-width:400px;min-height:300px;overview:auto;">
+<img id="preview_img" style="display:none;width:90%;height:90%;" />
+</div>
+</div>
\ No newline at end of file
--- /dev/null
+<?php
+
+class HW_Component extends DatabaseTable {
+ public function __construct($id=false)
+ {
+ parent::__construct('hw_component', $id);
+ }
+
+ public function ajaxGetUsage(Array $data)
+ {
+ $sql = <<<EOC
+SELECT hw_organisation.name AS owner,
+ to_char(starttime,'DD.MM.YYYY') AS starttime,
+ to_char(endtime,'DD.MM.YYYY') AS endtime,
+ hw_component.comment,status,hw_status.name AS status
+FROM hw_component
+JOIN hw_organisation ON owner = hw_organisation.id
+JOIN hw_status ON status = hw_status.id
+WHERE hw_component.id = %d
+EOC;
+ $sql = sprintf($sql, $this->id);
+ $info = $this->db->fetchAssoc($sql);
+
+ if (!$info)
+ throw new Exception("Cannot determine usage");
+
+ $sql = <<<EOC
+SELECT hw_compound.name,
+ to_char(hw_screw.starttime,'DD.MM.YYYY') AS starttime,
+ to_char(hw_screw.endtime,'DD.MM.YYYY') AS endtime,
+ usage
+FROM hw_screw
+JOIN hw_compound ON compound = hw_compound.id
+WHERE component = %d ORDER BY hw_screw.starttime
+EOC;
+ $sql = sprintf($sql, $this->id);
+ $screws = $this->db->fetchAssocList($sql);
+
+ $html = Template::render("usage", ['info' => $info, 'screws' => $screws]);
+
+ return ['html' => $html];
+ }
+
+ public function ajaxConnect(Array $data)
+ {
+ if (!$this->id)
+ throw new Exception("No componend selected");
+
+ if (empty($data['compound']) || empty($data['starttime']))
+ throw new Exception("Insufficient data transmitted");
+
+ $starttime = format_date($data['starttime']);
+
+ $sql = sprintf("SELECT id,compound,endtime FROM hw_screw WHERE component = %d AND starttime < '%s'::date ORDER BY starttime DESC LIMIT 1",
+ $this->id, $starttime);
+
+ $row = $this->db->fetchAssoc($sql);
+
+ if (empty($row['endtime'])) {
+ $sql = sprintf("UPDATE hw_screw SET endtime='%s',sys_edit=now(),sys_user=%s WHERE id = %d",
+ $starttime,
+ $this->db->quote($_SESSION['sys']['login']), $row['id']);
+ $this->db->execute($sql);
+ }
+
+ $usage = 'NULL';
+ if (!empty($data['usage']))
+ $usage = $this->db->quote($data['usage']);
+
+ $endtime = 'NULL';
+ if (!empty($data['endtime']))
+ $endtime = "'" . format_date($data['endtime']) . "'";
+
+ $sql = sprintf("INSERT INTO hw_screw (component,compound,usage,starttime,endtime,sys_user,sys_edit) " .
+ "VALUES (%d,%d,%s,'%s',%s,%s,now())",
+ $this->id, $data['compound'],
+ $usage,
+ $starttime, $endtime,
+ $this->db->quote($_SESSION['sys']['login']));
+ return $this->db->execute($sql);
+ }
+
+ public function ajaxDisconnect(Array $data)
+ {
+ if (!$this->id)
+ throw new Exception("No componend selected");
+
+ if (empty($data['termtime']))
+ throw new Exception("Insufficient data transmitted");
+
+ $termtime = format_date($data['termtime']);
+
+ $sql = sprintf("SELECT id,endtime FROM hw_screw WHERE component = %d AND starttime < '%s'::date ORDER BY starttime DESC LIMIT 1",
+ $this->id, $termtime);
+
+ $row = $this->db->fetchAssoc($sql);
+
+ if (empty($row['endtime'])) {
+ $sql = sprintf("UPDATE hw_screw SET endtime='%s',sys_edit=now(),sys_user=%s WHERE id = %d",
+ $termtime,
+ $this->db->quote($_SESSION['sys']['login']), $row['id']);
+ $this->db->execute($sql);
+ }
+
+ if (!empty($data['comment'])) {
+ $sql = sprintf("SELECT comment FROM hw_component WHERE id = %d", $this->id);
+
+ $row = $this->db->fetchAssoc($sql);
+
+ if (!empty($row['comment']))
+ $data['comment'] = $row['comment'] . "\n\n" . $data['comment'];
+
+ $sql = sprintf("UPDATE hw_component SET comment=%s WHERE id = %d",
+ $this->db->quote($data['comment']),
+ $this->id);
+ $this->db->execute($sql);
+ }
+
+ $sql = sprintf("UPDATE hw_component SET endtime='%s',status=%d,sys_edit=now(),sys_user=%s WHERE id = %d",
+ $termtime, STATUS_DEFUNCT,
+ $this->db->quote($_SESSION['sys']['login']),
+ $this->id);
+ return $this->db->execute($sql);
+ }
+}
define('STATUS_DEFUNCT', 3);
-$style[] = <<<EOC
+Styles::instance()->add("
div#form_screw, div#form_decommission {
padding-left: 10px;
padding-right: 10px;
font-size: 90%;
color: #555;
-}
-EOC;
+}");
-$form = '
-<div id="form_screw">
-<form>
-<input id="form_component" name="component" type="hidden" />
-<label for="form_compound">Verbund</label><br>
-<select id="form_compound" name="compound">
-<option value="">...</option>
-</select>
-<br>
-<label for="form_starttime">Von</label><br>
-<input id="form_starttime" name="starttime" size="8"> <img class="calendar" src="images/icons/calendar.gif" onclick="calendar(\\\'form_starttime\\\',event)" />
-<br>
-<label for="form_endtime">Bis</label><br>
-<input id="form_endtime" name="endtime" size="8"> <img class="calendar" src="images/icons/calendar.gif" onclick="calendar(\\\'form_endtime\\\',event)" />
-<br>
-<label for="form_usage">Verwendung</label><br>
-<input id="form_usage" name="usage" size="23">
-<div class="buttons" style="margin-top: 15px;">
-<button onclick="return screw_add(this);">Verbinden</button>
-</div>
-</form>
-</div>
-<div id="form_decommission">
-<form>
-<input id="form_component2" name="component" type="hidden" />
-<label for="form_termtime">Datum</label><br>
-<input id="form_termtime" name="termtime" size="8">
-<img class="calendar" src="images/icons/calendar.gif" onclick="calendar(\\\'form_termtime\\\',event)" />
-<br><label for="form_termcomment">Bemerkung</label><br>
-<textarea id="form_termcomment" name="comment" cols="26" rows="5">
-</textarea>
-<div class="buttons" style="margin-top: 15px;">
-<button onclick="return decommission_component(this);">Stillegen</button>
-</div>
-</form>
-</div>
-';
-
-$javascript = <<<EOC
-var screw_popup = false;
-function screw_popup_open(visibleId, hiddenId)
-{
- if (!screw_popup) {
- var options = { hideOnClick: false, canDragFunc: true };
- var content = 'CONTENT_FORM';
-
- screw_popup = new Rico.Popup(options, false, false);
- screw_popup.createWindow('<strong>Verbinden</strong>',content,'auto','200px');
- }
-
- var name = document.getElementById('edit_name');
- if (name.value.length)
- screw_popup.titleDiv.childNodes[0].innerHTML = name.value;
- else
- screw_popup.titleDiv.childNodes[0].innerHTML = 'Verbinden';
-
- var form_id = document.getElementById('edit_id');
- var component = document.getElementById('form_component');
- var component2 = document.getElementById('form_component2');
- component.value = form_id.value;
- component2.value = form_id.value;
-
- var formDiv = document.getElementById(visibleId);
- formDiv.style.display = '';
- formDiv = document.getElementById(hiddenId);
- formDiv.style.display = 'none';
-
- screw_popup.openPopup(100,300);
-}
-
-function screw_this()
-{
- var eid = document.getElementById('edit_id');
- if (!eid || !eid.value.length) return false;
-
- screw_popup_open('form_screw','form_decommission');
- return false;
-}
-
-function screw_callback(data)
-{
- info('Verbindung gespeichert');
- grid_update(second);
-}
-
-function screw_add(obj)
-{
- screw_popup.closePopup();
-
- var compound = document.getElementById('form_compound');
- if (!compound.options[compound.selectedIndex].value.length) {
- error('Kein Verbund ausgwählt');
- return false;
- }
-
- var starttime = document.getElementById('form_starttime');
- if (!starttime.value.length) {
- error('Keine Anfangszeit angegeben');
- return false;
- }
-
- var source = document.getElementById('source');
- if (!source) return false;
-
- var parms = 'source=' + source.innerHTML + '&callback=screw&';
- ajax_request('function', parms+Form.serialize(obj.form), screw_callback);
-
- starttime.value = '';
-
- return false;
-}
-
-function decommission_callback(data)
-{
- var name = document.getElementById('edit_name');
- if (name.value.length)
- info(name.value + ' stillgelegt');
-
- grid_update(grid);
- grid_update(second);
-}
-
-function decommission_component(obj)
-{
- screw_popup.closePopup();
-
- var termtime = document.getElementById('form_termtime');
- if (!termtime.value.length) {
- error('Keine Endzeit angegeben');
- return false;
- }
-
- var source = document.getElementById('source');
- if (!source) return false;
-
- var parms = 'source=' + source.innerHTML + '&callback=decommission&';
- ajax_request('function', parms+Form.serialize(obj.form), decommission_callback);
-
- termtime.value = '';
-
- return false;
-}
-
-function decommission()
-{
- var eid = document.getElementById('edit_id');
- if (!eid || !eid.value.length) return false;
-
- screw_popup_open('form_decommission','form_screw');
- return false;
-}
-
-EOC;
-
-$options = '<option value="">...</option>';
-if ($_GET['mask'] == 'hardware__component') {
- $compounds = query_db("SELECT id,name FROM hw_compound ORDER BY name");
- foreach ($compounds as $row) {
- $options .= sprintf('<option value="%d">%s</option>', $row['id'], $row['name']);
- }
-}
-
-$jscode[] = str_replace('CONTENT_FORM', str_replace(array('<option value="">...</option>',"\n"),
- array($options,"\\\n"), $form), $javascript);
-
-$buttons = <<<EOC
-<p style="margin-top: 0px; margin-bottom: 4px; text-align: center;">
-<button onclick="return screw_this()">Verbinden</button>
-
-<button onclick="return decommission()">Stillegen</button>
-</p>
-EOC;
+JavaScript::instance()->file('hardware.js');
+JavaScript::instance()->add("Hallinta.pageInit = component_init;");
$mask = array(
'table' => 'hw_component',
),
'hwtype' => array(
'name' => 'Typ',
+ 'sqltype' => 'int',
'width' => 90,
- 'specs' => "ClassName: 'aligncenter', filterUI: 's'",
+ 'filter' => 's',
+ 'specs' => array('ClassName' => 'aligncenter'),
'control' => "new Rico.TableColumn.lookup(".grid_lookup_sql('hw_types','id','name').", 0, '')",
'distinct' => "SELECT DISTINCT hwtype,hw_types.name FROM hw_component JOIN hw_types ON hwtype = hw_types.id ORDER BY name",
),
'name' => array(
'name' => 'Name',
'width' => 230,
- 'specs' => "filterUI: 't'",
+ 'filter' => 't',
),
'serno' => array(
'name' => 'Serial',
'price' => array(
'name' => 'Preis',
'width' => 50,
- 'specs' => "decPlaces: 2, ClassName: 'alignrightpad', canSort: false",
+ 'specs' => array('decPlaces' => 2, 'ClassName' => 'alignrightpad', 'canSort' => false),
),
'owner' => array(
'name' => 'Eigner',
+ 'sqltype' => 'int',
'width' => 55,
- 'specs' => "ClassName: 'aligncenter', filterUI: 's'",
+ 'filter' => 's',
+ 'specs' => array('ClassName' => 'aligncenter'),
'control' => "new Rico.TableColumn.lookup(".grid_lookup_sql('hw_organisation','id','name').", 0, '')",
'distinct' => "SELECT DISTINCT owner,hw_organisation.name FROM hw_component JOIN hw_organisation ON owner = hw_organisation.id ORDER BY name",
),
'starttime' => array(
'name' => 'Start',
'width' => 75,
+ 'type' => 'date',
+ 'specs' => array('dateFmt' => 'yyyy-mm-dd'),
),
'endtime' => array(
'name' => 'End',
'width' => 75,
+ 'type' => 'date',
+ 'specs' => array('dateFmt' => 'yyyy-mm-dd'),
),
'status' => array(
'name' => 'Status',
+ 'sqltype' => 'int',
'width' => 50,
- 'specs' => "filterUI: 's'",
+ 'filter' => 's',
'control' => "new Rico.TableColumn.lookup(".grid_lookup_sql('hw_status','id','name').", 0, '')",
'distinct' => "SELECT DISTINCT status,hw_status.name FROM hw_component JOIN hw_status ON owner = hw_status.id ORDER BY name",
),
'name' => 'Von',
'type' => 'date',
'size' => 8,
+ 'null' => true,
),
'endtime' => array(
'name' => 'Bis',
),
'screw' => array(
'type' => 'html',
- 'code' => $buttons,
+ 'code' => Template::render('screw/buttons', []),
'sql' => false,
),
),
- 'callbacks' => array(
- 'screw' => cb_screw,
- 'decommission' => cb_decommission,
- ),
'second' => array(
+ 'screw' => array(
'title' => 'Verwendung',
'table' => 'hw_screw',
+ 'table_edit' => 'hw_screw',
'rows' => 10,
'join' => array(
'hw_compound ON compound = hw_compound.id',
'id' => array(
'name' => 'ID',
'visible' => false,
+ 'edit' => array('Writeable' => false, 'EntryType' => 'H', 'Length' => 4, 'isKey' => true),
'sql' => 'hw_screw.id',
),
'compound' => array(
'starttime' => array(
'name' => 'Von',
'type' => 'date',
+ 'specs' => array('dateFmt' => 'yyyy-mm-dd'),
'width' => 80,
+ 'edit' => array('EntryType' => 'D', 'isNullable' => true, 'Writeable' => true),
'sql' => 'hw_screw.starttime'
),
'endtime' => array(
'name' => 'Bis',
'type' => 'date',
+ 'specs' => array('dateFmt' => 'yyyy-mm-dd'),
'width' => 80,
+ 'edit' => array('EntryType' => 'D', 'isNullable' => true, 'Writeable' => true),
'sql' => 'hw_screw.endtime'
),
'usage' => array(
'name' => 'Verwendung',
'width' => 270,
+ 'edit' => array('EntryType' => 'T', 'isNullable' => false, 'Writeable' => true),
),
),
),
+ ),
);
-
-function cb_screw()
-{
- global $db;
-
- if (empty($_POST['component']) || empty($_POST['compound']) || empty($_POST['starttime']))
- return array('error' => 'Insufficient data transmitted');
-
- $starttime = format_date($_POST['starttime']);
-
- $sql = sprintf("SELECT id,compound,endtime FROM hw_screw WHERE component = %d AND starttime < '%s'::date ORDER BY starttime DESC LIMIT 1",
- $_POST['component'], $starttime);
-
- $sth = $db->query($sql);
-
- $row = false;
- if ($sth !== false)
- $row = $sth->fetch();
-
- if ($row !== false) {
- if (empty($row['endtime'])) {
- $sql = sprintf("UPDATE hw_screw SET endtime='%s',sys_edit=now(),sys_user=%s WHERE id = %d",
- $starttime,
- $db->quote($_SESSION['sys']['login']), $row['id']);
- $db->query($sql);
- }
- }
-
- $usage = 'NULL';
- if (!empty($_POST['usage']))
- $usage = $db->quote($_POST['usage']);
-
- $endtime = 'NULL';
- if (!empty($_POST['endtime']))
- $endtime = "'" . format_date($_POST['endtime']) . "'";
-
- $sql = sprintf("INSERT INTO hw_screw (component,compound,usage,starttime,endtime,sys_user,sys_edit) " .
- "VALUES (%d,%d,%s,'%s',%s,%s,now())",
- $_POST['component'], $_POST['compound'],
- $usage,
- $starttime, $endtime,
- $db->quote($_SESSION['sys']['login']));
- $db->query($sql);
-
- return true;
-}
-
-function cb_decommission()
-{
- global $db;
-
- if (empty($_POST['component']) || empty($_POST['termtime']))
- return array('error' => 'Insufficient data transmitted');
-
- $termtime = format_date($_POST['termtime']);
-
- $sql = sprintf("SELECT id,endtime FROM hw_screw WHERE component = %d AND starttime < '%s'::date ORDER BY starttime DESC LIMIT 1",
- $_POST['component'], $termtime);
-
- $sth = $db->query($sql);
-
- $row = false;
- if ($sth !== false)
- $row = $sth->fetch();
-
- if ($row !== false && empty($row['endtime'])) {
- $sql = sprintf("UPDATE hw_screw SET endtime='%s',sys_edit=now(),sys_user=%s WHERE id = %d",
- $termtime,
- $db->quote($_SESSION['sys']['login']), $row['id']);
- $db->query($sql);
-
- }
-
- if (!empty($_POST['comment'])) {
- $sql = sprintf("SELECT comment FROM hw_component WHERE id = %d", $_POST['component']);
-
- $sth = $db->query($sql);
-
- if ($sth !== false) {
- $row = $sth->fetch();
- if (!empty($row['comment']))
- $_POST['comment'] = $row['comment'] . "\n\n" . $_POST['comment'];
- }
-
- $sql = sprintf("UPDATE hw_component SET comment=%s WHERE id = %d",
- $db->quote($_POST['comment']),
- $_POST['component']);
- $db->query($sql);
- }
-
-
- $sql = sprintf("UPDATE hw_component SET endtime='%s',status=%d,sys_edit=now(),sys_user=%s WHERE id = %d",
- $termtime, STATUS_DEFUNCT,
- $db->quote($_SESSION['sys']['login']),
- $_POST['component']);
- $db->query($sql);
-
- return true;
-}
-
-?>
<?php
-$jscode[] = <<<EOC
-var component_popup = false;
+JavaScript::instance()->file('hardware.js');
-function component_callback(data)
-{
- component_popup.contentDiv.innerHTML = data['info'] + data['screws'];
-}
-
-function component_popup_open(e, component)
-{
- if (!component_popup) {
- var options = { hideOnClick: false, canDragFunc: true };
-
- component_popup = new Rico.Popup(options, false, false);
- component_popup.createWindow('<strong>Verwendung</strong>','','auto','280px');
- }
-
- var source = document.getElementById('source');
- if (!source) return false;
-
- var parms = 'source=' + source.innerHTML + '&callback=component&component=' + component;
- ajax_request('function', parms, component_callback);
-
- if (component_popup.divPopup.style.display == 'none')
- component_popup.openPopup(e.clientX-50, e.clientY-150);
-}
-
-
-function drill_second(e)
-{
- if (e.originalTarget && e.originalTarget.target && e.originalTarget.target == '_top')
- return;
-
- var id = 0; // Column 0 contains ID
- var row = second.edit.drillDown(e,0,0);
- var cell = second.columns[id].cell(row);
- if (!cell) return;
- var value = cell.innerHTML;
-
- if (!value.length || value == ' ') return;
-
- component_popup_open(e, value);
-};
-EOC;
-
-$style[] = <<<EOC
+Styles::instance()->add("
table.tinfo {
font-size: 10px;
color: #555;
-}
-EOC;
+}");
$mask = array(
'table' => 'hw_compound',
),
'location' => array(
'name' => 'Location',
- 'specs' => "filterUI: 's',ClassName: 'aligncenter'",
+ 'filter' => 's',
+ 'specs' => array('ClassName' => 'aligncenter'),
'control' => "new Rico.TableColumn.lookup(".grid_lookup_sql('hw_organisation','id','name').", 0, '')",
'distinct' => "SELECT DISTINCT location,hw_organisation.name FROM hw_compound JOIN hw_organisation ON location = hw_organisation.id ORDER BY name",
'width' => 100,
'status' => array(
'name' => 'Status',
'width' => 50,
- 'specs' => "filterUI: 's'",
+ 'filter' => 's',
'control' => "new Rico.TableColumn.lookup(".grid_lookup_sql('hw_status','id','name').", 0, '')",
'distinct' => "SELECT DISTINCT status,hw_status.name FROM hw_compound JOIN hw_status ON status = hw_status.id ORDER BY name",
),
),
- 'callbacks' => array(
- 'component' => cb_component,
- ),
'second' => array(
+ 'components' => array(
'title' => 'Komponenten',
'rows' => 8,
'table' => 'hw_screw',
'hw_component ON component = hw_component.id',
),
'where' => 'compound = {id} AND hw_screw.endtime IS NULL ORDER BY name',
- 'onclick' => 'drill_second',
+ 'onclick' => 'component_drilldown',
'list' => array(
'component' => array(
'name' => 'ID',
'starttime' => array(
'name' => 'Seit',
'type' => 'date',
+ 'specs' => array('dateFmt' => 'yyyy-mm-dd'),
'width' => 80,
'sql' => 'hw_screw.starttime'
),
'price' => array(
'name' => 'Preis',
'width' => 50,
- 'specs' => "decPlaces: 2, ClassName: 'alignrightpad', canSort: false",
+ 'specs' => array('decPlaces' => 2, 'ClassName' => 'alignrightpad', 'canSort' => false),
),
'usage' => array(
'name' => 'Verwendung',
),
),
),
+ ),
'edit' => array(
'name' => array(
'name' => 'Name',
),
),
);
-
-function cb_component()
-{
- global $db;
-
- $data = array('info' => '', 'screws' => '');
- $sql = <<<EOC
-SELECT hw_organisation.name AS owner,
- to_char(starttime,'DD.MM.YYYY') AS starttime,
- to_char(endtime,'DD.MM.YYYY') AS endtime,
- hw_component.comment,status,hw_status.name AS status
-FROM hw_component
-JOIN hw_organisation ON owner = hw_organisation.id
-JOIN hw_status ON status = hw_status.id
-WHERE hw_component.id = %d
-EOC;
- $sql = sprintf($sql, $_POST['component']);
- $sth = $db->query($sql);
-
- $row = false;
- if ($sth !== false)
- $row = $sth->fetch();
-
- if ($row !== false) {
- $info = '<table border="0" cellpadding="0" class="tinfo">';
- $info .= sprintf('<tr><td>Eigentümer</td><td>:<td><td>%s</td></tr>', $row['owner']);
- $info .= sprintf('<tr><td>Von</td><td>:<td><td>%s</td></tr>', $row['starttime']);
- if (!empty($row['endtime']))
- $info .= sprintf('<tr><td>Bis</td><td>:<td><td>%s</td></tr>', $row['endtime']);
- if (!empty($row['comment']))
- $info .= sprintf('<tr><td valign="top">Bemerkung</td><td valign="top">:<td><td>%s</td></tr>', $row['comment']);
- $info .= sprintf('<tr><td>Status</td><td>:<td><td>%s</td></tr>', $row['status']);
- $info .= '</table>';
- $data['info'] = $info;
- }
-
- $sql = <<<EOC
-SELECT hw_compound.name,
- to_char(hw_screw.starttime,'DD.MM.YYYY') AS starttime,
- to_char(hw_screw.endtime,'DD.MM.YYYY') AS endtime,
- usage
-FROM hw_screw
-JOIN hw_compound ON compound = hw_compound.id
-WHERE component = %d ORDER BY hw_screw.starttime
-EOC;
- $sql = sprintf($sql, $_POST['component']);
- $sth = $db->query($sql);
-
- $screws = '<table width="99%" border="0" cellspacing="0" class="tinfo">';
- $screws .= '<tr bgcolor="#b3ceff"><th>Name</th><th>Von</th><th>Bis</th><th>Verwendung</th></tr>';
-
- while ($row = $sth->fetch()) {
- $screws .= sprintf('<tr><td>%s</td><td>%s</td><td>%s</td><td>%s</td></tr>',
- $row['name'], $row['starttime'], $row['endtime'], $row['usage']);
-
- }
- $screws .= '</table>';
- $data['screws'] = $screws;
-
- return $data;
-}
-
-?>
--- /dev/null
+var screw_popup = false;
+var screw_form = 'CONTENT_FORM';
+var component_popup = false;
+
+function component_init()
+{
+ ajax_request('Template/Load', 'id=screw/popup', function(data){
+ screw_form = data.data;
+ });
+}
+
+function screw_popup_open(visibleId, hiddenId)
+{
+ if (!screw_popup) {
+ screw_popup = new Rico.Window('Verbinden');
+ $(screw_popup.contentDiv).html(screw_form);
+ }
+
+ var name = document.getElementById('edit_name');
+ if (name.value.length)
+ screw_popup.titleDiv.childNodes[0].innerHTML = name.value;
+ else
+ screw_popup.titleDiv.childNodes[0].innerHTML = 'Verbinden';
+
+ var form_id = document.getElementById('edit_id');
+ var component = document.getElementById('form_component');
+ var component2 = document.getElementById('form_component2');
+ component.value = form_id.value;
+ component2.value = form_id.value;
+
+ var formDiv = document.getElementById(visibleId);
+ formDiv.style.display = '';
+ formDiv = document.getElementById(hiddenId);
+ formDiv.style.display = 'none';
+
+ screw_popup.openPopup(100,300);
+}
+
+function screw_this()
+{
+ var eid = document.getElementById('edit_id');
+ if (!eid || !eid.value.length) return false;
+
+ screw_popup_open('form_screw','form_decommission');
+ return false;
+}
+
+function screw_add(obj)
+{
+ screw_popup.closePopup();
+
+ if (!$('#form_compound').val().length) {
+ error('Kein Verbund ausgwählt');
+ return false;
+ }
+
+ if (!$('#form_starttime').val().length) {
+ error('Keine Anfangszeit angegeben');
+ return false;
+ }
+
+ ajax_request('HW_Component/Connect', $(obj.form).serialize(), function(data){
+ info('Verbindung gespeichert');
+ if (typeof Hallinta.seconds.screw == 'object')
+ grid_update(Hallinta.seconds.screw.grid);
+ });
+
+ starttime.value = '';
+
+ return false;
+}
+
+function decommission_component(obj)
+{
+ screw_popup.closePopup();
+
+ if (!$('#form_termtime').val().length) {
+ error('Keine Endzeit angegeben');
+ return false;
+ }
+
+ ajax_request('HW_Component/Disconnect', $(obj.form).serialize(), function(data){
+ if ($('#edit_name').val().length)
+ info($('#edit_name').val() + ' stillgelegt');
+
+ grid_update(Hallinta.grid);
+ if (typeof Hallinta.seconds.screw == 'object')
+ grid_update(Hallinta.seconds.screw.grid);
+ });
+
+ termtime.value = '';
+
+ return false;
+}
+
+function decommission()
+{
+ if (!$('#edit_id').val().length)
+ return false;
+
+ screw_popup_open('form_decommission','form_screw');
+ return false;
+}
+
+function component_popup_open(e, component)
+{
+ ajax_request('HW_Component/GetUsage', 'id=' + component, function(data){
+ if (!component_popup) {
+ component_popup = new Rico.Window('Verwendung', {zIndex: 100});
+ component_popup.contentDiv.innerHTML = data['html'];
+ component_popup.centerPopup();
+ } else {
+ component_popup.contentDiv.innerHTML = data['html'];
+ component_popup.openPopup();
+ }
+ });
+}
+
+function component_drilldown(e)
+{
+ if (e.originalTarget && e.originalTarget.target && e.originalTarget.target == '_top')
+ return;
+
+ var id = 0; // Column 0 contains ID
+
+ var row = Hallinta.seconds.components.edit.drillDown(e,0,0);
+ var cell = Hallinta.seconds.components.grid.columns[id].cell(row);
+ if (!cell) return;
+ var value = cell.innerHTML;
+
+ if (!value.length || value == ' ') return;
+
+ component_popup_open(e, value);
+};
--- /dev/null
+<p style="margin-top: 0px; margin-bottom: 4px; text-align: center;">
+<button onclick="return screw_this()">Verbinden</button>
+
+<button onclick="return decommission()">Stillegen</button>
+</p>
--- /dev/null
+<div id="form_screw">
+<form>
+<input id="form_component" name="id" type="hidden" />
+<label for="form_compound">Verbund</label><br>
+<select id="form_compound" name="compound">
+<option value="">...</option>
+<?php
+ foreach (Database::get()->fetchObjectList("SELECT id,name AS text FROM hw_compound ORDER BY text") as $row) {
+?>
+ <option value="<?php echo $row->id; ?>"><?php echo $row->text; ?></option>
+<?php } ?>
+</select>
+<br>
+<label for="form_starttime">Von</label><br>
+<input id="form_starttime" name="starttime" size="8"> <img class="calendar" src="<?php echo Hallinta::instance()->urlbase(); ?>images/icons/calendar.gif" onclick="calendar(\'form_starttime\',event)" />
+<br>
+<label for="form_endtime">Bis</label><br>
+<input id="form_endtime" name="endtime" size="8"> <img class="calendar" src="<?php echo Hallinta::instance()->urlbase(); ?>images/icons/calendar.gif" onclick="calendar(\'form_endtime\',event)" />
+<br>
+<label for="form_usage">Verwendung</label><br>
+<input id="form_usage" name="usage" size="23">
+<div class="buttons" style="margin-top: 15px;">
+<button onclick="return screw_add(this);">Verbinden</button>
+</div>
+</form>
+</div>
+<div id="form_decommission">
+<form>
+<input id="form_component2" name="id" type="hidden" />
+<label for="form_termtime">Datum</label><br>
+<input id="form_termtime" name="termtime" size="8">
+<img class="calendar" src="<?php echo Hallinta::instance()->urlbase(); ?>images/icons/calendar.gif" onclick="calendar('form_termtime',event)" />
+<br><label for="form_termcomment">Bemerkung</label><br>
+<textarea id="form_termcomment" name="comment" cols="26" rows="5">
+</textarea>
+<div class="buttons" style="margin-top: 15px;">
+<button onclick="return decommission_component(this);">Stillegen</button>
+</div>
+</form>
+</div>
--- /dev/null
+<div style="min-width: 450px; max-width: 700px;">
+<table border="0" cellpadding="0" class="tinfo">
+<tr><td>Eigentümer</td><td>:<td><td><?php echo $info['owner']; ?></td></tr>
+<tr><td>Von</td><td>:<td><td><?php echo $info['starttime']; ?></td></tr>
+<?php if (!empty($info['endtime'])) { ?>
+ <tr><td>Bis</td><td>:<td><td><?php echo $info['endtime']; ?></td></tr>
+<?php } ?>
+<?php if (!empty($info['comment'])) { ?>
+ <tr><td valign="top">Bemerkung</td><td valign="top">:<td><td><?php echo nl2br($info['comment']); ?></td></tr>
+<?php } ?>
+<tr><td>Status</td><td>:<td><td><?php echo $info['status'];?></td></tr>
+</table>
+
+<table width="99%" border="0" cellspacing="0" class="tinfo">
+<tr bgcolor="#b3ceff"><th>Name</th><th>Von</th><th>Bis</th><th>Verwendung</th></tr>
+<?php foreach ($screws as $screw) { ?>
+ <tr><td><?php echo $screw['name']; ?></td><td><?php echo $screw['starttime']; ?></td><td><?php echo $screw['endtime']; ?></td><td><?php echo $screw['usage']; ?></td></tr>
+<?php } ?>
+</table>
+</div>
--- /dev/null
+<?php
+
+JavaScript::instance()->file('lib/ricoTableColumnDB.js');
+
+$mask = array(
+ 'table' => 'sys_group',
+ 'title' => 'Gruppenverwaltung',
+ 'list' => array(
+ 'id' => array(
+ 'name' => 'ID',
+ 'visible' => false,
+ ),
+ 'gname' => array(
+ 'name' => 'Gruppe',
+ 'width' => 70,
+ ),
+ 'name' => array(
+ 'name' => 'Name',
+ 'width' => 150,
+ ),
+ 'sys_user' => array(
+ 'name' => 'Bearb.',
+ 'width' => 50,
+ ),
+ 'sys_edit' => array(
+ 'name' => 'Geändert',
+ 'width' => 80,
+ 'type' => 'date',
+ 'specs' => array('dateFmt' => 'yyyy-mm-dd'),
+ ),
+ ),
+ 'second' => array(
+ 'user' => array(
+ 'title' => 'Mitglieder',
+ 'table' => 'sys_user',
+ 'rows' => 10,
+ 'width' => 410,
+ 'list' => array(
+ 'id' => array(
+ 'name' => 'ID',
+ 'visible' => false,
+ 'sql' => 'sys_user.id',
+ ),
+ 'login' => array(
+ 'name' => 'Login',
+ 'width' => 70,
+ ),
+ 'name' => array(
+ 'name' => 'Name',
+ 'width' => 120,
+ 'sql' => 'sys_user.name',
+ ),
+ 'email' => array(
+ 'name' => 'E-Mail',
+ 'width' => 150,
+ ),
+ 'checked' => array(
+ 'name' => 'Perm',
+ 'width' => 40,
+ 'sql' => '(SELECT count(*)
+ FROM sys_group_user
+ WHERE sys_user_id = sys_user.id
+ AND sys_group_id = {id})',
+ 'control' => "new Rico.TableColumn.checkboxDB(0," .
+ "Hallinta.baseURL+'ajax/ricoUpdateConnection.php')",
+ 'filter' => 'c',
+ 'specs' => array('ClassName' => 'aligncenter has-checkbox', 'canSort' => true),
+ 'update' => array('table' => 'sys_group_user',
+ 'basecol' => 'sys_group_id',
+ 'refcol' => 'sys_user_id',
+ 'reftable' => 'sys_user',
+ 'refid' => 'sys_user.id',
+ ),
+ ),
+ ),
+ ),
+ 'menuitems' => array(
+ 'title' => 'Menüpunkte',
+ 'table' => 'sys_menuitem',
+ 'rows' => 15,
+ 'width' => 500,
+ 'list' => array(
+ 'id' => array(
+ 'name' => 'ID',
+ 'visible' => false,
+ 'sql' => 'sys_menuitem.id',
+ ),
+ 'parent' => array(
+ 'name' => 'Super',
+ 'sqltype' => 'int',
+ 'filter' => 's',
+ 'width' => 120,
+ 'control' => "new Rico.TableColumn.lookup(".grid_lookup_sql('sys_menuitem','id','title', [0 => 'Root']).", 0, '')",
+ ),
+ 'priority' => array(
+ 'name' => 'Prio',
+ 'width' => 50,
+ 'type' => 'number',
+ 'specs' => array('ClassName' => 'aligncenter'),
+ 'visible' => false,
+ ),
+ 'module' => array(
+ 'filter' => 's',
+ 'name' => 'Modul',
+ 'width' => 90,
+ ),
+ 'page' => array(
+ 'filter' => 't',
+ 'name' => 'Page',
+ 'width' => 100,
+ ),
+ 'title' => array(
+ 'name' => 'Titel',
+ 'filter' => 't',
+ 'width' => 100,
+ ),
+ 'checked' => array(
+ 'name' => 'Perm',
+ 'width' => 40,
+ 'sql' => '(SELECT count(*)
+ FROM sys_group_menuitem
+ WHERE sys_menuitem_id = sys_menuitem.id
+ AND sys_group_id = {id})',
+ 'control' => "new Rico.TableColumn.checkboxDB(0," .
+ "Hallinta.baseURL+'ajax/ricoUpdateConnection.php')",
+ 'filter' => 'c',
+ 'specs' => array('ClassName' => 'aligncenter has-checkbox', 'canSort' => true),
+ 'update' => array('table' => 'sys_group_menuitem',
+ 'basecol' => 'sys_group_id',
+ 'refcol' => 'sys_menuitem_id',
+ 'reftable' => 'sys_menuitem',
+ 'refid' => 'sys_menuitem.id',
+ ),
+ ),
+ ),
+ ),
+ ),
+ 'edit' => array(
+ 'gname' => array(
+ 'name' => 'Gruppe',
+ 'type' => 'text',
+ 'size' => 20,
+ ),
+ 'name' => array(
+ 'name' => 'Name',
+ 'type' => 'text',
+ 'size' => 20,
+ ),
+ ),
+ );
+
--- /dev/null
+function menuitem_init()
+{
+ menuitem_update_parent();
+ menuitem_update_module();
+ $('#edit_module').change(menuitem_update_page);
+}
+
+function menuitem_update_parent()
+{
+ ajax_request('MenuItem/GetParent', '', function(data){
+ select_update('edit_parent', data.list, 1);
+ });
+}
+
+function menuitem_update_module()
+{
+ ajax_request('MenuItem/GetModules', '', function(data){
+ select_update('edit_module', data.list, 1);
+ });
+}
+
+function menuitem_update_page(page)
+{
+ var module = $('#edit_module').val();
+
+ if (!module.length) {
+ select_update('edit_page', [], 1);
+ return;
+ }
+
+ ajax_request('MenuItem/GetPages', 'module='+module, function(data){
+ select_update('edit_page', data.list, 1);
+ if (page)
+ $('#edit_page').val(page);
+ });
+}
+
+function menuitem_post_fetch(data)
+{
+ menuitem_update_page(data.page);
+}
+
+function menuitem_post_insert(data)
+{
+ if (!$('#edit_module').val().length && !$('#edit_page').val().length)
+ menuitem_update_parent();
+}
--- /dev/null
+<?php
+
+JavaScript::instance()->file('lib/ricoTableColumnDB.js');
+JavaScript::instance()->file('menuitem.js');
+JavaScript::instance()->add("Hallinta.postLoadForm = menuitem_init;");
+JavaScript::instance()->add("Hallinta.postFetch = menuitem_post_fetch;");
+JavaScript::instance()->add("Hallinta.postInsert = menuitem_post_insert;");
+
+$mask = array(
+ 'table' => 'sys_menuitem',
+ 'title' => 'Liste der Menüpunkte',
+ 'list' => array(
+ 'id' => array(
+ 'name' => 'ID',
+ 'visible' => false,
+ ),
+ 'parent' => array(
+ 'name' => 'Super',
+ 'sqltype' => 'int',
+ 'filter' => 's',
+ 'width' => 120,
+ 'control' => "new Rico.TableColumn.lookup(".grid_lookup_sql('sys_menuitem','id','title', [0 => 'Root']).", 0, '')",
+# 'distinct' => "SELECT DISTINCT abteilung,metro_abteilung.name FROM metro_artikel JOIN metro_abteilung ON abteilung = metro_abteilung.id ORDER BY name",
+ ),
+ 'priority' => array(
+ 'name' => 'Prio',
+ 'width' => 50,
+ 'type' => 'number',
+ 'specs' => array('ClassName' => 'aligncenter'),
+ ),
+ 'module' => array(
+ 'filter' => 's',
+ 'name' => 'Modul',
+ 'width' => 90,
+ ),
+ 'page' => array(
+ 'filter' => 't',
+ 'name' => 'Page',
+ 'width' => 100,
+ ),
+ 'title' => array(
+ 'name' => 'Titel',
+ 'filter' => 't',
+ 'width' => 100,
+ ),
+ 'edit' => array(
+ 'name' => 'Edit',
+ 'width' => 40,
+ 'specs' => array('ClassName' => 'aligncenter has-checkbox', 'canSort' => false),
+ 'control' => "new Rico.TableColumn.checkbox(1,0,0,1)",
+ ),
+ ),
+ 'edit' => array(
+ 'parent' => array(
+ 'name' => 'Super',
+ 'type' => 'select',
+ 'options' => [['id'=>'0', 'text'=>'Root']],
+ 'options_string' => true,
+ ),
+ 'module' => array(
+ 'name' => 'Modul',
+ 'type' => 'select',
+ 'options' => [['id'=>NULL, 'text'=>'']],
+ 'options_string' => true,
+ 'size' => 24,
+ 'null' => true,
+ ),
+ 'page' => array(
+ 'name' => 'Seite',
+ 'type' => 'select',
+ 'options' => [['id'=>NULL, 'text'=>'']],
+ 'options_string' => true,
+ 'size' => 24,
+ 'null' => true,
+ ),
+ 'priority' => array(
+ 'name' => 'Priorität',
+ 'type' => 'number',
+ 'size' => 10,
+ 'required' => true,
+ ),
+ 'title' => array(
+ 'name' => 'Titel',
+ 'type' => 'text',
+ 'size' => 24,
+ 'required' => true,
+ ),
+ 'tooltip' => array(
+ 'name' => 'Tooltip',
+ 'type' => 'text',
+ 'size' => 24,
+ ),
+ 'edit' => array(
+ 'name' => 'Edit',
+ 'type' => 'boolean',
+ ),
+ 'shadow' => array(
+ 'name' => 'shadow',
+ 'type' => 'boolean',
+ ),
+ ),
+ 'second' => array(
+ 'perms' => array(
+ 'title' => 'Freigaben',
+ 'table' => 'sys_group',
+ 'rows' => 10,
+ 'width' => 320,
+ 'list' => array(
+ 'id' => array(
+ 'name' => 'ID',
+ 'visible' => false,
+ 'sql' => 'sys_group.id',
+ ),
+ 'gname' => array(
+ 'name' => 'Name',
+ 'width' => 80,
+ 'type' => 'text',
+ ),
+ 'name' => array(
+ 'name' => 'Name',
+ 'width' => 150,
+ 'type' => 'text',
+ ),
+ 'checked' => array(
+ 'name' => 'Perm',
+ 'width' => 40,
+ 'sql' => '(SELECT count(*)
+ FROM sys_group_menuitem
+ WHERE sys_group_id = sys_group.id
+ AND sys_menuitem_id = {id})',
+ 'control' => "new Rico.TableColumn.checkboxDB(0," .
+ "Hallinta.baseURL+'ajax/ricoUpdateConnection.php')",
+ 'filter' => 'c',
+ 'specs' => array('ClassName' => 'aligncenter', 'canSort' => true),
+ 'update' => array('table' => 'sys_group_menuitem',
+ 'basecol' => 'sys_menuitem_id',
+ 'refcol' => 'sys_group_id',
+ 'reftable' => 'sys_group',
+ 'refid' => 'sys_group.id',
+ ),
+ ),
+ ),
+ ),
+ ),
+ );
+++ /dev/null
-<?php
-
-$mask = array(
- 'table' => 'sys_group',
- 'title' => 'Liste der Gruppen',
- 'list' => array(
- 'id' => array(
- 'name' => 'ID',
- 'visible' => false,
- ),
- 'gname' => array(
- 'name' => 'Gruppe',
- 'width' => 70,
- ),
- 'name' => array(
- 'name' => 'Name',
- 'width' => 150,
- ),
- 'sys_user' => array(
- 'name' => 'Bearb.',
- 'width' => 50,
- ),
- 'sys_edit' => array(
- 'name' => 'Geändert',
- 'width' => 80,
- 'type' => 'date',
- ),
- ),
- 'edit' => array(
- 'gname' => array(
- 'name' => 'Gruppe',
- 'type' => 'text',
- 'size' => 20,
- ),
- 'name' => array(
- 'name' => 'Name',
- 'type' => 'text',
- 'size' => 20,
- ),
- ),
- );
-
-?>
+++ /dev/null
-<?php
-
-define('VARNAME','system__sys_group_mask.group');
-
-$jscode[] = <<<EOC
-
-Rico.moduleDependencies['checkboxDB'] = ['+LiveGrid', '../ricoTableColumnDB.js'];
-Rico.loadModule('checkboxDB');
-
-function select_group_calback(data)
-{
- grid_update(grid);
-}
-
-function select_group(obj)
-{
- if (!obj.options[obj.selectedIndex].value.length)
- val = -1;
- else
- val = obj.options[obj.selectedIndex].value;
-
- ajax_request('setvar','source=system__sys_group_mask&name=group&value='+val,select_group_calback);
-
- if (obj.options[obj.selectedIndex].value.length)
- info('Gruppe ' + obj.options[obj.selectedIndex].innerHTML + ' ausgewählt');
- else
- info('');
-}
-EOC;
-
-if (empty($_SESSION[VARNAME])) $_SESSION[VARNAME] = 0;
-
-$mask = array(
- 'table' => 'sys_mask',
- 'title' => 'Berechtigungen',
- 'select' => array(
- 'title' => 'Auswahl',
- 'options' => 'SELECT id,name AS text FROM sys_group ORDER BY name',
- 'default' => 'Gruppe wählen',
- 'selected' => $_SESSION[VARNAME],
- 'onchange' => 'select_group(this)',
- ),
- 'join' => array('sys_menu ON sys_mask.menu = sys_menu.id'),
- 'list' => array(
- 'id' => array(
- 'name' => 'ID',
- 'sql' => 'sys_mask.id',
- 'visible' => false,
- ),
- 'menu' => array(
- 'name' => 'Menü',
- 'width' => 80,
- 'sql' => 'sys_menu.name',
- ),
- 'menutitle' => array(
- 'name' => 'Menüpunkt',
- 'width' => 170,
- 'sql' => 'sys_mask.menutitle',
- ),
- 'title' => array(
- 'name' => 'Beschreibung',
- 'width' => 150,
- 'sql' => 'sys_mask.title',
- ),
- 'edit' => array(
- 'name' => 'Edit',
- 'width' => 40,
- 'specs' => "ClassName: 'aligncenter', canSort: false",
- 'sql' => 'sys_mask.edit',
- ),
- 'checked' => array(
- 'name' => 'Menü',
- 'width' => 40,
- 'sql' => '(SELECT count(*) FROM sys_group_mask WHERE gid = '
- . intval($_SESSION[VARNAME])
- . ' AND mask = sys_mask.id)',
- 'control' => "new Rico.TableColumn.checkboxDB(0, 'ajax/ricoUpdateConnection.php')",
- 'specs' => "filterUI: 'c', ClassName: 'aligncenter', canSort: false",
- 'update' => array('table' => 'sys_group_mask',
- 'basecol' => 'gid',
- 'baseval' => $_SESSION[VARNAME],
- 'refcol' => 'mask',
- 'reftable' => 'sys_mask',
- 'refid' => 'sys_mask.id',
- ),
- ),
- ),
- 'variables' => array(
- 'group' => array(),
- ),
- );
-
-?>
+++ /dev/null
-<?php
-
-function discover_cmp($a, $b)
-{
- return strcmp($a['id'],$b['id']);
-}
-
-function discover_masks()
-{
- $info = array();
-
- if (($modules = opendir($_SESSION['sys']['basedir'].'masks')) === false)
- return $info;
-
- while (($module = readdir($modules)) !== false)
- if (is_dir($_SESSION['sys']['basedir'].'masks/'.$module)
- && $module != '.' && $module != '..') {
-
- if (($d = opendir($_SESSION['sys']['basedir'].'masks/'.$module)) === false)
- continue;
-
- while (($file = readdir($d)) !== false)
- if (substr($file,-4) == '.php') {
- $fname = substr($file,0,-4);
- $info[] = array('id' => $module.'|'.$fname, 'text' => $module.'|'.$fname);
- }
- closedir($d);
- }
- closedir($modules);
-
- usort($info,'discover_cmp');
- return $info;
-}
-
-$mask = array(
- 'table' => 'sys_mask',
- 'title' => 'Liste der Menüpunkte',
- 'join' => array('sys_menu ON sys_mask.menu = sys_menu.id'),
- 'list' => array(
- 'id' => array(
- 'name' => 'ID',
- 'visible' => false,
- 'sql' => 'sys_mask.id',
- ),
- 'fname' => array(
- 'name' => 'Dateiname',
- 'width' => 170,
- ),
- 'name' => array(
- 'name' => 'Name',
- 'width' => 150,
- 'sql' => 'sys_mask.name',
- ),
- 'menutitle' => array(
- 'name' => 'Menüpunkt',
- 'width' => 100,
- ),
- 'menu' => array(
- 'name' => 'Menü',
- 'sql' => 'sys_menu.name',
- 'width' => 100,
- ),
- 'edit' => array(
- 'name' => 'Edit',
- 'width' => 40,
- 'specs' => "ClassName: 'aligncenter', canSort: false",
- ),
- 'priority' => array(
- 'name' => 'Priorität',
- 'width' => 60,
- 'type' => 'number',
- 'specs' => "ClassName: 'alignright', canSort: false",
- 'sql' => 'sys_mask.priority',
- ),
- ),
- 'edit' => array(
- 'fname' => array(
- 'name' => 'Dateiname',
- 'type' => 'select',
- 'options' => discover_masks(),
- 'options_string' => true,
- ),
- 'name' => array(
- 'name' => 'Name',
- 'type' => 'text',
- 'size' => 24,
- ),
- 'menutitle' => array(
- 'name' => 'Menüpunkt',
- 'type' => 'text',
- 'size' => 24,
- 'required' => true,
- ),
- 'title' => array(
- 'name' => 'Beschreibung',
- 'type' => 'text',
- 'size' => 24,
- 'null' => true,
- ),
- 'menu' => array(
- 'name' => 'Menü',
- 'type' => 'select',
- 'options' => 'SELECT id,name AS text FROM sys_menu ORDER BY name',
- ),
- 'edit' => array(
- 'name' => 'Edit',
- 'type' => 'boolean',
- ),
- 'shadow' => array(
- 'name' => 'shadow',
- 'type' => 'boolean',
- ),
- 'priority' => array(
- 'name' => 'Priorität',
- 'type' => 'number',
- 'size' => 10,
- ),
- ),
- );
-
-?>
+++ /dev/null
-<?php
-
-$mask = array(
- 'table' => 'sys_menu',
- 'title' => 'Liste der Menüs',
- 'list' => array(
- 'id' => array(
- 'name' => 'ID',
- 'visible' => false,
- ),
- 'name' => array(
- 'name' => 'Name',
- 'width' => 150,
- ),
- 'priority' => array(
- 'name' => 'Priorität',
- 'width' => 80,
- 'type' => 'number',
- 'specs' => "ClassName: 'alignright', canSort: false",
- ),
- ),
- 'edit' => array(
- 'name' => array(
- 'name' => 'Name',
- 'type' => 'text',
- 'size' => 20,
- ),
- 'priority' => array(
- 'name' => 'Priorität',
- 'type' => 'number',
- 'size' => 10,
- ),
- ),
- );
-
-?>
'theme' => array(
'name' => 'Theme',
'width' => 80,
- 'specs' => "ClassName: 'aligncenter', filterUI: 's'",
+ 'filter' => 's',
+ 'specs' => array('ClassName' => 'aligncenter'),
'control' => "new Rico.TableColumn.lookup(".grid_lookup_sql('sys_themes','id','name').", 0, '')",
'distinct' => "SELECT DISTINCT theme,sys_themes.name FROM sys_theme_values JOIN sys_themes ON theme = sys_themes.id ORDER BY name",
),
'item' => array(
'name' => 'Item',
'width' => 170,
- 'specs' => "filterUI: 's'",
+ 'filterUI' => 's',
'control' => "new Rico.TableColumn.lookup(".grid_lookup_sql('sys_theme_items','id','name').", 0, '')",
'distinct' => "SELECT DISTINCT item,sys_theme_items.name FROM sys_theme_values JOIN sys_theme_items ON item = sys_theme_items.id ORDER BY name",
),
+++ /dev/null
-<?php
-
-$mask = array(
- 'table' => 'sys_user',
- 'title' => 'Liste der Anwender',
- 'join' => array('sys_group ON sys_user.gid = sys_group.id'),
- 'list' => array(
- 'id' => array(
- 'name' => 'ID',
- 'visible' => false,
- 'sql' => 'sys_user.id',
- ),
- 'login' => array(
- 'name' => 'Login',
- 'width' => 70,
- ),
- 'name' => array(
- 'name' => 'Name',
- 'width' => 150,
- 'sql' => 'sys_user.name',
- ),
- 'email' => array(
- 'name' => 'E-Mail',
- 'width' => 200,
- ),
- 'gruppe' => array(
- 'name' => 'Gruppe',
- 'width' => 70,
- 'sql' => 'sys_group.name',
- ),
- 'theme' => array(
- 'name' => 'Theme',
- 'width' => 90,
- 'control' => "new Rico.TableColumn.lookup(".grid_lookup_sql('sys_themes','id','name').", 0, '')",
- 'distinct' => "SELECT DISTINCT theme,sys_themes.name FROM sys_user JOIN sys_themes ON theme = sys_themes.id ORDER BY name",
- ),
- ),
- 'edit' => array(
- 'login' => array(
- 'name' => 'Login',
- 'type' => 'text',
- 'size' => 25,
- ),
- 'name' => array(
- 'name' => 'Name',
- 'type' => 'text',
- 'size' => 25,
- ),
- 'email' => array(
- 'name' => 'E-Mail',
- 'type' => 'text',
- 'size' => 25,
- ),
- 'gid' => array(
- 'name' => 'Gruppe',
- 'type' => 'select',
- 'options' => 'SELECT id,name AS text FROM sys_group ORDER BY name',
- ),
- 'theme' => array(
- 'name' => 'Theme',
- 'type' => 'select',
- 'options' => 'SELECT id,name AS text FROM sys_themes ORDER BY name',
- ),
- 'passwd' => array(
- 'name' => 'Passwort',
- 'type' => 'passwd',
- 'size' => 25,
- ),
- ),
- );
-
-?>
--- /dev/null
+<?php
+
+JavaScript::instance()->file('lib/ricoTableColumnDB.js');
+
+$mask = array(
+ 'table' => 'sys_user',
+ 'title' => 'Liste der Anwender',
+ 'join' => array('sys_group ON sys_user.gid = sys_group.id'),
+ 'list' => array(
+ 'id' => array(
+ 'name' => 'ID',
+ 'visible' => false,
+ 'sql' => 'sys_user.id',
+ ),
+ 'login' => array(
+ 'name' => 'Login',
+ 'width' => 70,
+ ),
+ 'name' => array(
+ 'name' => 'Name',
+ 'width' => 150,
+ 'sql' => 'sys_user.name',
+ ),
+ 'email' => array(
+ 'name' => 'E-Mail',
+ 'width' => 200,
+ ),
+ 'gruppe' => array(
+ 'name' => 'Gruppe',
+ 'width' => 70,
+ 'sql' => 'sys_group.name',
+ ),
+ 'theme' => array(
+ 'name' => 'Theme',
+ 'width' => 90,
+ 'control' => "new Rico.TableColumn.lookup(".grid_lookup_sql('sys_themes','id','name').", 0, '')",
+ 'distinct' => "SELECT DISTINCT theme,sys_themes.name FROM sys_user JOIN sys_themes ON theme = sys_themes.id ORDER BY name",
+ ),
+ ),
+ 'second' => array(
+ 'perms' => array(
+ 'title' => 'Freigaben',
+ 'table' => 'sys_group',
+ 'rows' => 10,
+ 'width' => 320,
+ 'list' => array(
+ 'id' => array(
+ 'name' => 'ID',
+ 'visible' => false,
+ 'sql' => 'sys_group.id',
+ ),
+ 'gname' => array(
+ 'name' => 'Name',
+ 'width' => 80,
+ 'type' => 'text',
+ ),
+ 'name' => array(
+ 'name' => 'Name',
+ 'width' => 150,
+ 'type' => 'text',
+ ),
+ 'checked' => array(
+ 'name' => 'Perm',
+ 'width' => 40,
+ 'sql' => '(SELECT count(*)
+ FROM sys_group_user
+ WHERE sys_group_id = sys_group.id
+ AND sys_user_id = {id})',
+ 'control' => "new Rico.TableColumn.checkboxDB(0," .
+ "Hallinta.baseURL+'ajax/ricoUpdateConnection.php')",
+ 'filter' => 'c',
+ 'specs' => array('ClassName' => 'aligncenter has-checkbox', 'canSort' => true),
+ 'update' => array('table' => 'sys_group_user',
+ 'basecol' => 'sys_user_id',
+ 'refcol' => 'sys_group_id',
+ 'reftable' => 'sys_group',
+ 'refid' => 'sys_group.id',
+ ),
+ ),
+ ),
+ ),
+ ),
+ 'edit' => array(
+ 'login' => array(
+ 'name' => 'Login',
+ 'type' => 'text',
+ 'size' => 25,
+ ),
+ 'name' => array(
+ 'name' => 'Name',
+ 'type' => 'text',
+ 'size' => 25,
+ ),
+ 'email' => array(
+ 'name' => 'E-Mail',
+ 'type' => 'text',
+ 'size' => 25,
+ ),
+ 'gid' => array(
+ 'name' => 'Gruppe',
+ 'type' => 'select',
+ 'options' => 'SELECT id,name AS text FROM sys_group ORDER BY name',
+ ),
+ 'theme' => array(
+ 'name' => 'Theme',
+ 'type' => 'select',
+ 'options' => 'SELECT id,name AS text FROM sys_themes ORDER BY name',
+ ),
+ 'passwd' => array(
+ 'name' => 'Passwort',
+ 'type' => 'passwd',
+ 'size' => 25,
+ ),
+ ),
+ );
+
+?>
--- /dev/null
+#! /bin/bash
+
+basedir=$(dirname $0)
+
+if [ -n "$(type -path uglifyjs)" ]
+then
+ find ${basedir} -name '*.js' | grep -v '\.min\.js' | while read infile
+ do
+ outfile=${infile%.js}.min.js
+
+ if [ ! -f "$outfile" -o "$infile" -nt "$outfile" ]
+ then
+ uglifyjs "$infile" > "$outfile"
+ fi
+ done
+fi
+
+if perl -MCSS::Minifier -e '' 2>/dev/null
+then
+ find ${basedir} -name '*.css' | grep -v '\.min\.css' | while read infile
+ do
+ outfile=${infile%.css}.min.css
+
+ if [ ! -f "$outfile" -o "$infile" -nt "$outfile" ]
+ then
+ perl -MCSS::Minifier -e "
+ open(INFILE, '<', '$infile') or die;
+ open(OUTFILE, '>', '$outfile') or die;
+ CSS::Minifier::minify(input => *INFILE, outfile => *OUTFILE);
+ close(INFILE);
+ close(OUTFILE);"
+ fi
+ done
+fi
font: 85%/1.3 Verdana,Arial,sans-serif;
text-align: left;
/* background: #fff; */
- padding-bottom:20px
}
a {
margin-top: 0;
}
+/*
+ * Header
+ */
div#header {
- width:100%;
- background: #BBD9EE;
+ width: 100%;
+ height: 3ex;
+ background: #BBD9EE;
+ background: #48b4f8;
+ background-image: url('images/bg_header.png');
+ background-repeat: repeat-x;
+ padding-bottom: 3px;
}
-div#header h1, div#menu {
- width:770px;
- margin:0 auto;
- text-align:left;
+div#header div#title {
+ padding-left: 5px;
+ font-size: 125%;
+ font-weight: bold;
+ float: left;
}
-div#header h1 {
- padding-top: 10px;
- padding-bottom: 10px;
- color: #555;
+div#header div#titlesep {
+ padding-left: 5px;
+ font-size: 125%;
+ font-weight: bold;
+ float: left;
}
+div#header div#pagetitle {
+ padding-left: 5px;
+ font-size: 125%;
+ font-weight: bold;
+ float: left;
+}
-div.right {
- float: right;
- width: 76%;
- padding: 0;
- padding-top: 0px;
- margin-bottom: 1.2em;
- text-align: justify;
+div#header div#actionbox {
+ padding-top: 1px;
+ padding-right: 5px;
+ float: right;
}
-div.left {
- float: left;
- width: 23%;
- margin: 0;
- padding: 0;
+div#header div#actionbox span.item {
+ margin-left: 0.3rem;
+}
+
+div#header div#actionbox span.item select {
+ font-size: 90%;
+}
+
+/*
+ * Menu
+ */
+
+div.menuDialog ul.menu {
+ list-style: none;
+ padding: 0;
+}
+div.menuDialog ul.menu li {
+ padding: 7px 7px;
+ margin: 1px;
+ border-style: solid;
+ border-width: 1px 1px 1px 0;
+ border-color: #fff #d9d9d9 #d9d9d9;
+ border-color: #fff #aaa #aaa;
+ background-color: #f6f6f6;
+ color: #000;
+}
+div.menuDialog ul.menu li.current {
+ background-color: #ddd;
+ color: #000;
+}
+div.menuDialog ul.menu li:hover {
+ background-color: #eee;
+ color: #000;
}
-div.left .box {
+.box {
padding: 0;
margin: 0 0 1em 0;
border: 1px solid #AAA;
}
div.content {
- font: 95%/1.3 Verdana,Arial,sans-serif;
+ font: 97.5%/1.2 Verdana,Arial,sans-serif;
margin: 0 auto;
- padding: 15px;
+ padding-top: 5px;
+ padding-left: 5px;
+ padding-right: 5px;
background: #e7f1f8;
}
padding-bottom: 2px;
}
+/* Only for WebKit - only for mobile devices */
+@media screen and (-webkit-min-device-pixel-ratio:0)
+{
+ div.ricoLG_scrollContainerDiv {
+ background: lightgrey;
+ }
+
+ div.content {
+ padding-left: 0px !important;
+ }
+
+ div.hide-on-mobile {
+ display: none;
+ }
+ div.show-on-mobile {
+ display: unset;
+ }
+}
+
+/* @tabletViewportWidth: 48em; // 768px */
+@media screen and (max-width: 768px) {
+ div#header div#title,
+ div#header div#titlesep {
+ display: none;
+ }
+}
+@media screen and (min-width: 768px) {
+ div#header div#title,
+ div#header div#titlesep {
+ display: inline !important;
+ }
+}
+
div.ricoLG_cell {
padding-top: 0px;
padding-bottom: 0px;
cursor: default;
}
+.has-checkbox div.ricoLG_cell {
+ padding-top: 0px;
+ padding-bottom: 6px;
+}
+
div.ricoWindow {
border: 1px solid #BBB;
}
+div.ricoWindow .RicoPopupContent .ricoTitle .RicoCloseAnchor.ui-dialog-titlebar-close {
+ padding: 0px;
+}
div.ricoTitle {
background-color: #316994;
color: white;
font-size: 12px;
}
-div.form {
- margin-top: 0px;
- padding: 2px;
+div#column_grid {
+ border: none;
+}
+
+div#column_edit {
border: 1px solid #AAA;
color: #555;
- overflow: hidden;
}
div.second {
margin-bottom: 5px;
}
+label {
+ display: block;
+}
input, select {
+ display; block;
border: 1px solid #CCC;
color: inherit;
background: white;
+ font-size: inherit;
}
textarea {
+ display; block;
border: 1px solid #CCC;
font-size: 90%;
color: inherit;
}
+input.maxwidth, select.maxwidth {
+ width: 98%
+}
+
+input[readonly] {
+ background: #EEEEEE;
+}
+
+textarea.maxwidth {
+ width: 97%
+}
+
button {
border: 1px solid #CCC;
background: #DDD;
background: #DDD;
}
+button.builtin:disabled,
+button.custom:disabled {
+ background-image: none;
+ background-repeat: none;
+}
+
div.buttons {
text-align: center;
padding-top: 0px;
p#form_status {
font-size: 80%;
margin-top: 0px;
+ text-align: right;
}
span.status_ok {
color: #444;
}
-div.alignrightpad {
+.gridPopup .ricoContent {
+ font-size: 125%;
+}
+
+div.alignrightpad > div {
text-align: right;
padding-right: 3px;
}
float: right;
text-align: right;
}
+
+div#column_grid, div#column_edit {
+ background: #e1f3ff;
+}
+
+div#message {
+ background: white;
+ padding-left: 10px;
+ padding-right: 10px;
+ padding-top: 5px;
+ padding-bottom: 5px;
+ border: solid 1px #50a6ff;
+ background: #fff68f;
+ z-index: 200;
+}
$styles['div.form']['background-color'] = $row['value'];
break;
case 'box-title-background':
- $styles['div.ricoTitle']['background-color'] = $row['value'];
+ $styles['div.ricoTitle.ui-widget-header']['background-color'] = $row['value'];
$styles['div.form p.title']['background-color'] = $row['value'];
$styles['.ricoLG_table th']['background-color'] = $row['value'];
break;