Initial import from hg.
This commit is contained in:
Коммит
6ffc3f8279
|
@ -0,0 +1,25 @@
|
|||
[main]
|
||||
testroot = /Users/mozilla/awfy
|
||||
os = mac10.6
|
||||
cpu = x64
|
||||
machine = 4
|
||||
updateURL = http://www.arewefastyet.com/????
|
||||
|
||||
[v8]
|
||||
source = v8
|
||||
|
||||
[jsc]
|
||||
source = WebKit
|
||||
|
||||
[jsci]
|
||||
source = InterpKit
|
||||
|
||||
[tm]
|
||||
source = mozilla-inbound
|
||||
|
||||
[jm]
|
||||
source = mozilla-inbound
|
||||
|
||||
[im]
|
||||
source = ionmonkey
|
||||
|
|
@ -0,0 +1,118 @@
|
|||
# vim: set ts=4 sw=4 tw=99 et:
|
||||
import re
|
||||
import os
|
||||
import sys
|
||||
import urllib2
|
||||
import StringIO
|
||||
import subprocess
|
||||
import ConfigParser
|
||||
import submitter
|
||||
import utils
|
||||
|
||||
def ss_v8(shell, env, args):
|
||||
return run_sunspider('SunSpider', 'v8-v7', 5, shell, env, args)
|
||||
|
||||
def ss_SunSpider(shell, env, args):
|
||||
return run_sunspider('SunSpider', 'sunspider-0.9.1', 20, shell, env, args)
|
||||
|
||||
def ss_Kraken(shell, env, args):
|
||||
return run_sunspider('kraken', 'kraken-1.1', 5, shell, env, args)
|
||||
|
||||
def ss_Assorted(shell, env, args):
|
||||
return run_sunspider('Assorted', 'assorted', 3, shell, env, args)
|
||||
|
||||
def run_sunspider(folder, suite, runs, shell, env, args):
|
||||
with utils.chdir(folder):
|
||||
return _sunspider(suite, runs, shell, env, args)
|
||||
|
||||
def v8_v8(shell, env, args):
|
||||
with utils.chdir('v8-v7'):
|
||||
return _v8(shell, env, args)
|
||||
|
||||
def _v8(shell, env, args):
|
||||
full_args = [shell]
|
||||
if args:
|
||||
full_args.extend(args)
|
||||
full_args.append('run.js')
|
||||
|
||||
p = subprocess.Popen(full_args, stdout=subprocess.PIPE, env=env)
|
||||
output = p.communicate()[0]
|
||||
|
||||
tests = []
|
||||
lines = output.splitlines()
|
||||
|
||||
for x in lines:
|
||||
m = re.search("(.+): (\d+)", x)
|
||||
if m != None:
|
||||
name = m.group(1)
|
||||
score = m.group(2)
|
||||
if name[0:5] == "Score":
|
||||
name = "__total__"
|
||||
tests.append({ 'name': name, 'time': score})
|
||||
print(score + ' - ' + name)
|
||||
|
||||
return tests
|
||||
|
||||
def _sunspider(suite, runs, shell, env, args):
|
||||
if args != None:
|
||||
args = '--args=' + ' '.join(args)
|
||||
else:
|
||||
args = ''
|
||||
|
||||
if suite == "assorted":
|
||||
p = subprocess.Popen(["hg", "pull", "-u"], stdout=subprocess.PIPE)
|
||||
p.communicate()
|
||||
|
||||
p = subprocess.Popen(["./sunspider",
|
||||
"--shell=" + shell,
|
||||
"--runs=" + str(runs),
|
||||
"--suite=" + suite,
|
||||
args],
|
||||
stdout=subprocess.PIPE,
|
||||
env=env)
|
||||
output = p.communicate()[0]
|
||||
|
||||
tests = []
|
||||
|
||||
lines = output.splitlines()
|
||||
found = False
|
||||
for x in lines:
|
||||
if x == "--------------------------------------------" or \
|
||||
x == "-----------------------------------------------":
|
||||
found = True
|
||||
if x[0:5] == "Total":
|
||||
m = re.search(":\s+(\d+\.\d+)ms", x)
|
||||
tests.append({ 'name': '__total__', 'time': m.group(1)})
|
||||
print(m.group(1) + ' - __total__')
|
||||
elif found == True and x[0:4] == " ":
|
||||
m = re.search(" (.+):\s+(\d+\.\d+)ms", x)
|
||||
if m != None:
|
||||
tests.append({ 'name': m.group(1), 'time': m.group(2)})
|
||||
print(m.group(2) + ' - ' + m.group(1))
|
||||
|
||||
if found == False:
|
||||
raise Exception("output marker not found")
|
||||
|
||||
return tests
|
||||
|
||||
Benchmarks = {
|
||||
'v8real': v8_v8,
|
||||
'kraken': ss_Kraken,
|
||||
'ss': ss_SunSpider,
|
||||
#'v8': ss_v8,
|
||||
'misc': ss_Assorted
|
||||
}
|
||||
|
||||
def RunAndSubmitAll(shell, env, args, submitter, mode):
|
||||
for suite in Benchmarks:
|
||||
args_ = args
|
||||
if not args:
|
||||
args_ = []
|
||||
print('Running ' + suite + ' under ' + shell + ' ' + ' '.join(args_))
|
||||
fun = Benchmarks[suite]
|
||||
try:
|
||||
tests = fun(shell, env, args)
|
||||
submitter.AddTests(tests, suite, mode)
|
||||
except:
|
||||
pass
|
||||
|
|
@ -0,0 +1,138 @@
|
|||
# vim: set ts=4 sw=4 tw=99 et:
|
||||
import os
|
||||
import sys
|
||||
import puller
|
||||
import subprocess
|
||||
from utils import Run
|
||||
|
||||
class Engine(object):
|
||||
def __init__(self, conf):
|
||||
self.testroot = conf.get('main', 'testroot')
|
||||
self.cpu = conf.get('main', 'cpu')
|
||||
|
||||
def updateAndBuild(self, update, forceRebuild):
|
||||
pop = os.getcwd()
|
||||
os.chdir(os.path.join(self.testroot, self.source))
|
||||
|
||||
if self.puller == 'svn':
|
||||
scm = puller.SVN
|
||||
elif self.puller == 'hg':
|
||||
scm = puller.HG
|
||||
shell = self.shell()
|
||||
|
||||
if not os.path.isfile(shell):
|
||||
forceRebuild = True
|
||||
|
||||
updated = False
|
||||
if update:
|
||||
updated = scm.Update()
|
||||
|
||||
if forceRebuild or updated:
|
||||
try:
|
||||
os.unlink(shell)
|
||||
except:
|
||||
pass
|
||||
pop2 = os.getcwd()
|
||||
self.build()
|
||||
os.chdir(pop2)
|
||||
updated = True
|
||||
|
||||
version = scm.Identify()
|
||||
|
||||
if not os.path.isfile(shell):
|
||||
print(shell)
|
||||
os.chdir(pop)
|
||||
raise Exception('could not find shell')
|
||||
|
||||
os.chdir(pop)
|
||||
return [version, updated]
|
||||
|
||||
def env(self):
|
||||
return None
|
||||
|
||||
class Nitro(Engine):
|
||||
def __init__(self, conf):
|
||||
super(Nitro, self).__init__(conf)
|
||||
self.puller = 'svn'
|
||||
self.source = conf.get('jsc', 'source')
|
||||
self.args = None
|
||||
self.important = False
|
||||
self.modes = [
|
||||
{
|
||||
'mode': 'jsc',
|
||||
'args': None
|
||||
}
|
||||
]
|
||||
|
||||
def env(self):
|
||||
env = os.environ.copy()
|
||||
env['DYLD_FRAMEWORK_PATH'] = os.path.abspath(os.path.join('WebKitBuild', 'Release'))
|
||||
return env
|
||||
|
||||
def build(self):
|
||||
pop = os.getcwd()
|
||||
os.chdir(os.path.join('Tools', 'Scripts'))
|
||||
if self.cpu == 'x86':
|
||||
Run(['/usr/bin/perl', 'build-jsc', '--32-bit'])
|
||||
else:
|
||||
Run(['/usr/bin/perl', 'build-jsc'])
|
||||
os.chdir(pop)
|
||||
|
||||
def shell(self):
|
||||
return os.path.join('WebKitBuild', 'Release', 'jsc')
|
||||
|
||||
class V8(Engine):
|
||||
def __init__(self, conf):
|
||||
super(V8, self).__init__(conf)
|
||||
self.puller = 'svn'
|
||||
self.source = conf.get('v8', 'source')
|
||||
self.args = ['--expose-gc']
|
||||
self.important = True
|
||||
self.modes = [
|
||||
{
|
||||
'mode': 'v8',
|
||||
'args': None
|
||||
}
|
||||
]
|
||||
|
||||
def build(self):
|
||||
Run(['make', 'dependencies'])
|
||||
if self.cpu == 'x64':
|
||||
Run(['make', 'x64.release'])
|
||||
elif self.cpu == 'arm':
|
||||
Run(['make', 'arm.release'])
|
||||
elif self.cpu == 'x86':
|
||||
Run(['make', 'ia32.release'])
|
||||
|
||||
def shell(self):
|
||||
if self.cpu == 'x64':
|
||||
return os.path.join('out', 'x64.release', 'd8')
|
||||
elif self.cpu == 'arm':
|
||||
return os.path.join('out', 'arm.release', 'd8')
|
||||
elif self.cpu == 'x86':
|
||||
return os.path.join('out', 'ia32.release', 'd8')
|
||||
|
||||
class Mozilla(Engine):
|
||||
def __init__(self, conf):
|
||||
super(Mozilla, self).__init__(conf)
|
||||
self.puller = 'hg'
|
||||
self.source = conf.get('jm', 'source')
|
||||
self.args = None
|
||||
self.important = True
|
||||
self.modes = [
|
||||
{
|
||||
'mode': 'ti',
|
||||
'args': ['-m', '-n', '--no-ion']
|
||||
},
|
||||
{
|
||||
'mode': 'jmim',
|
||||
'args': ['--ion', '-m', '-n']
|
||||
}
|
||||
]
|
||||
|
||||
def build(self):
|
||||
os.system("make -j 3 -C " + os.path.join('js', 'src', 'Opt'))
|
||||
|
||||
def shell(self):
|
||||
return os.path.join('js', 'src', 'Opt', 'js')
|
||||
|
|
@ -0,0 +1,63 @@
|
|||
# vim: set ts=4 sw=4 tw=99 et:
|
||||
import os
|
||||
import ConfigParser
|
||||
import submitter
|
||||
import builders
|
||||
import sys
|
||||
import resource
|
||||
import benchmark
|
||||
import utils
|
||||
|
||||
config = ConfigParser.RawConfigParser()
|
||||
config.read('awfy.config')
|
||||
resource.setrlimit(resource.RLIMIT_AS, (-1, -1))
|
||||
resource.setrlimit(resource.RLIMIT_RSS, (-1, -1))
|
||||
resource.setrlimit(resource.RLIMIT_DATA, (-1, -1))
|
||||
|
||||
# JSC is ilooping...
|
||||
KnownEngines = [
|
||||
builders.V8(config),
|
||||
builders.Mozilla(config),
|
||||
builders.Nitro(config)
|
||||
]
|
||||
Engines = []
|
||||
MozillaUpdated = False
|
||||
NumUpdated = 0
|
||||
for e in KnownEngines:
|
||||
try:
|
||||
cset, updated = e.updateAndBuild(True, False)
|
||||
except:
|
||||
print('Build failed!')
|
||||
continue
|
||||
if cset == None:
|
||||
continue
|
||||
if updated and e.important:
|
||||
NumUpdated += 1
|
||||
Engines.append([e, cset, updated])
|
||||
|
||||
if NumUpdated == 0:
|
||||
sys.exit(0)
|
||||
|
||||
submit = submitter.Submitter(config)
|
||||
submit.Start()
|
||||
for entry in Engines:
|
||||
e = entry[0]
|
||||
cset = entry[1]
|
||||
shell = os.path.join(config.get('main', 'testroot'), e.source, e.shell())
|
||||
env = None
|
||||
with utils.chdir(os.path.join(config.get('main', 'testroot'), e.source)):
|
||||
env = e.env()
|
||||
for m in e.modes:
|
||||
if e.args:
|
||||
args = list(e.args)
|
||||
if m['args']:
|
||||
args.append(*m['args'])
|
||||
elif m['args']:
|
||||
args = list(m['args'])
|
||||
else:
|
||||
args = None
|
||||
submit.AddEngine(m['mode'], cset)
|
||||
benchmark.RunAndSubmitAll(shell, env, args, submit, m['mode'])
|
||||
|
||||
submit.Finish(1)
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
# vim: set ts=4 sw=4 tw=99 et:
|
||||
import re
|
||||
import os
|
||||
import sys
|
||||
import subprocess
|
||||
from utils import Run
|
||||
|
||||
class HG:
|
||||
@staticmethod
|
||||
def Update():
|
||||
output = Run(['hg', 'pull', '-u'])
|
||||
return re.search("no changes found", output) == None
|
||||
|
||||
@staticmethod
|
||||
def Identify():
|
||||
output = Run(['hg', 'id', '-i'])
|
||||
m = re.match("([0-9a-z]+)\s*", output)
|
||||
if m == None:
|
||||
raise Exception('unknown output from hg: ' + output)
|
||||
return m.group(1)
|
||||
|
||||
class SVN:
|
||||
@staticmethod
|
||||
def Update():
|
||||
output = Run(['svn', 'update'])
|
||||
return re.search("At revision", output) == None
|
||||
|
||||
@staticmethod
|
||||
def Identify():
|
||||
output = Run(['svn', 'info'])
|
||||
m = re.search("Revision: ([0-9]+)", output)
|
||||
if m == None:
|
||||
raise Exception('unknown output from svn: ' + output)
|
||||
return m.group(1)
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
# vim: set ts=4 sw=4 tw=99 et:
|
||||
import re
|
||||
import urllib2
|
||||
|
||||
class Submitter:
|
||||
def __init__(self, conf):
|
||||
self.url = conf.get('main', 'updateURL')
|
||||
self.cpu = conf.get('main', 'cpu')
|
||||
self.os = conf.get('main', 'os')
|
||||
self.machine = conf.get('main', 'machine')
|
||||
|
||||
def Start(self):
|
||||
url = self.url
|
||||
url += '?run=yes'
|
||||
url += '&CPU=' + self.cpu
|
||||
url += '&OS=' + self.os
|
||||
url += '&MACHINE=' + str(self.machine)
|
||||
url = urllib2.urlopen(url)
|
||||
contents = url.read()
|
||||
m = re.search('id=(\d+)', contents)
|
||||
if m == None:
|
||||
raise Exception('Remote error: ' + contents)
|
||||
self.runID = int(m.group(1))
|
||||
|
||||
def AddEngine(self, name, cset):
|
||||
url = self.url
|
||||
url += '?run=addEngine'
|
||||
url += '&runid=' + str(self.runID)
|
||||
url += '&name=' + name
|
||||
url += '&cset=' + str(cset)
|
||||
urllib2.urlopen(url)
|
||||
|
||||
def AddTests(self, tests, suite, mode):
|
||||
for test in tests:
|
||||
self.SubmitTest(test['name'], suite, mode, test['time'])
|
||||
|
||||
def SubmitTest(self, name, suite, mode, time):
|
||||
url = self.url
|
||||
url += '?name=' + name
|
||||
url += '&run=' + str(self.runID)
|
||||
url += '&suite=' + suite
|
||||
url += '&mode=' + mode
|
||||
url += '&time=' + str(time)
|
||||
urllib2.urlopen(url)
|
||||
|
||||
def Finish(self, status):
|
||||
url = self.url
|
||||
url += '?run=finish'
|
||||
url += '&status=' + str(status)
|
||||
url += '&runid=' + str(self.runID)
|
||||
urllib2.urlopen(url)
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
# vim: set ts=4 sw=4 tw=99 et:
|
||||
import os
|
||||
import subprocess
|
||||
|
||||
class FolderChanger:
|
||||
def __init__(self, folder):
|
||||
self.old = os.getcwd()
|
||||
self.new = folder
|
||||
|
||||
def __enter__(self):
|
||||
os.chdir(self.new)
|
||||
|
||||
def __exit__(self, type, value, traceback):
|
||||
os.chdir(self.old)
|
||||
|
||||
def chdir(folder):
|
||||
return FolderChanger(folder)
|
||||
|
||||
def Run(vec):
|
||||
print(">> Executing in " + os.getcwd())
|
||||
print(' '.join(vec))
|
||||
o = subprocess.check_output(vec, stderr=subprocess.STDOUT)
|
||||
o = o.decode("utf-8")
|
||||
print(o)
|
||||
return o
|
||||
|
|
@ -0,0 +1,59 @@
|
|||
<?php
|
||||
|
||||
require_once("internals.php");
|
||||
|
||||
init_database();
|
||||
|
||||
if (isset($_GET['run']) && $_GET['run'] == 'yes') {
|
||||
$CPU = mysql_real_escape_string(GET_string('CPU'));
|
||||
$OS = mysql_real_escape_string(GET_string('OS'));
|
||||
$MACHINE = GET_int('MACHINE');
|
||||
$CSET = mysql_real_escape_string(GET_string('CSET'));
|
||||
mysql_query("INSERT INTO fast_run (cpu, os, machine, stamp, cset)
|
||||
VALUES
|
||||
('$CPU', '$OS', $MACHINE, UNIX_TIMESTAMP(), '$CSET')")
|
||||
or die("ERROR: " . mysql_error());
|
||||
print("id=" . mysql_insert_id());
|
||||
} else if (isset($_GET['run']) && $_GET['run'] == 'finish') {
|
||||
$runid = GET_int('runid');
|
||||
$status = GET_int('status');
|
||||
if (isset($_GET['error']))
|
||||
$error = '\'' . mysql_real_escape_string(GET_string('error')) . '\'';
|
||||
else
|
||||
$error = 'NULL';
|
||||
mysql_query("UPDATE fast_run
|
||||
SET status = $status,
|
||||
error = $error
|
||||
WHERE id = $runid")
|
||||
or die("ERROR: " . mysql_error());
|
||||
} else if (isset($_GET['run']) && $_GET['run'] == 'addEngine') {
|
||||
$runid = GET_int('runid');
|
||||
$mode_id = find_mode(GET_string('name'));
|
||||
$cset = mysql_real_escape_string(GET_string('cset'));
|
||||
mysql_query("INSERT INTO awfy_build
|
||||
(run_id, mode_id, cset)
|
||||
VALUES
|
||||
($runid, $mode_id, '$cset')")
|
||||
or die("ERROR: " . mysql_error());
|
||||
} else {
|
||||
$name = mysql_real_escape_string(GET_string('name'));
|
||||
$time = mysql_real_escape_string(GET_string('time'));
|
||||
$suite_id = find_suite(GET_string('suite'));
|
||||
$mode_id = find_mode(GET_string('mode'));
|
||||
$run = GET_int('run');
|
||||
if ($name == '__total__') {
|
||||
mysql_query("INSERT INTO awfy_score
|
||||
(run_id, suite_id, mode_id, score)
|
||||
VALUES
|
||||
($run, $suite_id, $mode_id, $time)")
|
||||
or die("ERROR: " . mysql_error());
|
||||
} else {
|
||||
mysql_query("INSERT INTO awfy_breakdown
|
||||
(run_id, suite_id, mode_id, test, score)
|
||||
VALUES
|
||||
($run, $suite_id, $mode_id, '$name', $time)")
|
||||
or die("ERROR: " . mysql_error());
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
|
@ -0,0 +1,62 @@
|
|||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
|
||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<title>AWFY - Frequently Asked Questions</title>
|
||||
<link rel="stylesheet" type="text/css" href="style.css" />
|
||||
</head>
|
||||
<body>
|
||||
<h1>Frequently Asked Questions</h1>
|
||||
<ol id="faq">
|
||||
<li>
|
||||
<p>What's this site?</p>
|
||||
<p>This site tracks the performance of popular JavaScript engines.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>What versions are you testing with?</p>
|
||||
<p>Each test run checks out a copy of the latest source code for each vendor it's testing. This means we're testing the latest, greatest, unstable, bleeding-edge versions of browsers' JS engines. The scores here may not represent what you see in stable releases.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Who's behind it? Is Mozilla?</p>
|
||||
<p>This site is maintained by Mozilla's JavaScript team.</p>
|
||||
Special thanks to wx24 for the new layout, and Michael Clackler for the UI improvements such as hover-tip deltas. Awesome!
|
||||
</li>
|
||||
<li>
|
||||
<p>Why does the v8 benchmark go down, instead of up?</p>
|
||||
<p>The v8 benchmark produces a score, not raw time. We inverted the graph so they all look like "lower is better".</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Why do some changesets appear multiple times?</p>
|
||||
<p>The graphs update on every v8 or tracemonkey check-in, roughly, so if one updates but not the other, the same changeset can be tested twice.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Why isn't Opera/IE/something here?</p>
|
||||
<p>Right now, the performance tests are run on a Mac, which means no IE. Also the tests rely on a "shell" JS engine that runs in a command line. It doesn't test browsers. We'll change that, eventually.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>What are the axes?</p>
|
||||
<p>The Y axis is time to benchmark completion. Lower is better. The X axis represents test runs, chronologically. The left-most run is the oldest, the right-most run is the latest.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>What are the graphs?</p>
|
||||
<p>The top left-hand graph is Mozilla's Kraken benchmark. The top right-hand graph is Apple's SunSpider benchmark. The bottom graph is Google's V8 benchmark suite.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>What do the hover tips mean?</p>
|
||||
<p>"Time" is...time. "Source" is where we got the engine from. "Tested" is when we downloaded the engine, compiled, and tested it. "Rev" is the unique point in the engine's revision history we tested. These numbers/strings are for developers to see which changes happened in between points in the graph.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>What runs the tests?</p>
|
||||
<p>A mac-mini.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>What's ARM?</p>
|
||||
<p>ARM is the CPU present in many embedded devices, like smartphones. We're interested in this for mobile Firefox.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Is this open source?</p>
|
||||
<p>It's not very interesting (or good), but yes: <a href="http://hg.mozilla.org/users/danderson_mozilla.com/awfy">click here</a></p>
|
||||
</li>
|
||||
</ol>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,230 @@
|
|||
<?php
|
||||
date_default_timezone_set('UTC');
|
||||
/* vim: set ts=4 sw=4 tw=99 et: */
|
||||
|
||||
require_once("internals.php");
|
||||
|
||||
init_database();
|
||||
|
||||
global $MACHINE;
|
||||
|
||||
$MACHINE = 5;
|
||||
if (isset($_GET['machine']))
|
||||
$MACHINE = intval($_GET['machine']);
|
||||
|
||||
$smarty = new_smarty();
|
||||
$smarty->assign('arewefastyet', 'NO.');
|
||||
$smarty->assign('MACHINE', $MACHINE);
|
||||
|
||||
Everything($smarty);
|
||||
|
||||
$smarty->display('arewefastyet.tpl');
|
||||
|
||||
function GetStat($suite, $mode)
|
||||
{
|
||||
global $MACHINE;
|
||||
|
||||
$query = "SELECT id FROM `fast_run`
|
||||
WHERE status = 1 AND
|
||||
machine = $MACHINE
|
||||
ORDER BY stamp DESC LIMIT 1";
|
||||
$res = mysql_query($query) or die("ERROR: " . mysql_error() . "\n");
|
||||
if (!mysql_num_rows($res))
|
||||
die("no data\n");
|
||||
$top = mysql_fetch_array($res);
|
||||
$top = $top[0];
|
||||
|
||||
$query = "SELECT SUM(time_ms) FROM fast_test
|
||||
WHERE suite = '$suite' AND
|
||||
mode = '$mode' AND
|
||||
machine = $MACHINE
|
||||
run = $top";
|
||||
$res = mysql_query($query);
|
||||
$data = mysql_fetch_array($res);
|
||||
return number_format($data[0], 0);
|
||||
}
|
||||
|
||||
function &BuildLines(&$stats, $modes, &$runIds, $suite)
|
||||
{
|
||||
$MODE_NAMES = array('j' => 'tracer',
|
||||
'm' => 'jmnotrc',
|
||||
'v8' => 'v8',
|
||||
'jsc' => 'nitro',
|
||||
'mooi' => 'mooi',
|
||||
'moom' => 'moom',
|
||||
'mooj' => 'mooj');
|
||||
|
||||
$lines = array();
|
||||
for ($i = 0; $i < count($modes); $i++) {
|
||||
$mode = $modes[$i];
|
||||
$lines[$mode] = '[';
|
||||
$counter = 0;
|
||||
for ($j = count($runIds) - 1; $j >= 0; $j--) {
|
||||
$runId = $runIds[$j];
|
||||
if (isset($stats[$runId][$suite][$mode]))
|
||||
$amount = $stats[$runId][$suite][$mode];
|
||||
else
|
||||
$amount = 'null';
|
||||
$lines[$mode] .= '[' . $counter . ',' .
|
||||
$amount .
|
||||
']';
|
||||
if ($j != 0)
|
||||
$lines[$mode] .= ',';
|
||||
$counter++;
|
||||
}
|
||||
$lines[$mode] .= ']';
|
||||
}
|
||||
|
||||
$nlines = array();
|
||||
for ($i = 0; $i < count($modes); $i++) {
|
||||
$mode = $modes[$i];
|
||||
$nlines[] = array('name' => $MODE_NAMES[$mode],
|
||||
'data' => $lines[$mode]);
|
||||
}
|
||||
|
||||
return $nlines;
|
||||
}
|
||||
|
||||
function Everything(&$smarty)
|
||||
{
|
||||
global $MACHINE;
|
||||
|
||||
$runs = FindRuns(32);
|
||||
|
||||
/* Find runs that failed. */
|
||||
for ($i = 0; $i < count($runs); $i++) {
|
||||
$run = $runs[$i];
|
||||
if ($run['status'] != 1) {
|
||||
$smarty->assign('runError', $run);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$runIds = array();
|
||||
$runTimes = array();
|
||||
for ($i = 0; $i < count($runs); $i++) {
|
||||
if ($runs[$i]['status'] != 1)
|
||||
continue;
|
||||
$runIds[] = $runs[$i]['id'];
|
||||
$runTimes[] = date("M j, Y", $runs[$i]['stamp']);
|
||||
}
|
||||
$runTimes = array_reverse($runTimes);
|
||||
if (count($runIds) == 0) {
|
||||
die("oh no what are you doing");
|
||||
}
|
||||
$idstr = implode(",", $runIds);
|
||||
|
||||
$query = "SELECT run, name, time_ms, suite, mode
|
||||
FROM fast_test
|
||||
WHERE run IN ($idstr)";
|
||||
$result = mysql_query($query) or die("error: " . mysql_error());
|
||||
$suite_stats = array();
|
||||
while (($row = mysql_fetch_array($result)) !== FALSE) {
|
||||
$runId = $row['run'];
|
||||
$name = $row['name'];
|
||||
$time = $row['time_ms'];
|
||||
$suite = $row['suite'];
|
||||
$mode = $row['mode'];
|
||||
if ($mode == '')
|
||||
$mode = 'i';
|
||||
if (!isset($suite_stats[$runId][$suite][$mode]))
|
||||
$suite_stats[$runId][$suite][$mode] = floatval($time);
|
||||
else
|
||||
$suite_stats[$runId][$suite][$mode] += floatval($time);
|
||||
}
|
||||
|
||||
$query = "SELECT run, name, cset FROM fast_engine
|
||||
WHERE run IN ($idstr)";
|
||||
$result = mysql_query($query) or die("error: " . mysql_error());
|
||||
$builds = array();
|
||||
while (($row = mysql_fetch_array($result)) !== FALSE) {
|
||||
$runId = $row['run'];
|
||||
$builds[$runId] = array('engine' => $row['name'], 'cset' => $row['cset']);
|
||||
}
|
||||
|
||||
$MIDS = array(3 => array('j', 'v8'),
|
||||
4 => array('v8', 'jsc', 'mooj', 'j'),
|
||||
5 => array('v8', 'jsc', 'mooj', 'j'),
|
||||
6 => array('j', 'moom', 'mooj', 'v8'),
|
||||
7 => array('j', 'moom', 'mooj', 'v8')
|
||||
);
|
||||
|
||||
/* Build the line graph data sets. */
|
||||
$self_ss = BuildLines($suite_stats, $MIDS[$MACHINE], $runIds, 'ss');
|
||||
$self_v8 = BuildLines($suite_stats, $MIDS[$MACHINE], $runIds, 'v8');
|
||||
|
||||
$smarty->assign('self_ss', $self_ss);
|
||||
$smarty->assign('self_v8', $self_v8);
|
||||
|
||||
/* Now, in the same order, we want build information about each engine. */
|
||||
$query = "SELECT fr.id, fe.name, fe.cset
|
||||
FROM fast_engine fe
|
||||
JOIN fast_run fr
|
||||
ON fe.run = fr.id
|
||||
WHERE fr.id IN ($idstr)
|
||||
ORDER BY fr.id ASC";
|
||||
$query = mysql_query($query);
|
||||
if (!$query)
|
||||
die('error: ' . mysql_error());
|
||||
|
||||
/* Prep the mapping of engine names and runs to builds. */
|
||||
$engines = array('jm', 'tm', 'v8', 'jsc', 'jsci', 'moo');
|
||||
$engineStrings = array();
|
||||
for ($i = 0; $i < count($engines); $i++)
|
||||
$engineStrings[$engines[$i]] = array();
|
||||
|
||||
/* Map engine names and run IDs to builds. */
|
||||
while (($data = mysql_fetch_array($query)) !== FALSE)
|
||||
$engineStrings[$data[1]][$data[0]] = "'" . $data[2] . "'";
|
||||
|
||||
/* Please agree with me that this is hideous. Why aren't I using Python. */
|
||||
$engineBuilds = array();
|
||||
for ($i = 0; $i < count($engines); $i++) {
|
||||
$engine = $engines[$i];
|
||||
$newvec = array();
|
||||
for ($j = count($runIds) - 1; $j >= 0; $j--) {
|
||||
$run = $runIds[$j];
|
||||
if (isset($engineStrings[$engine][$run])) {
|
||||
$newvec[] = $engineStrings[$engine][$run];
|
||||
} else {
|
||||
$newvec[] = "null";
|
||||
}
|
||||
}
|
||||
$engineBuilds[$engine] = implode(',', $newvec);
|
||||
}
|
||||
|
||||
$smarty->assign('engineBuilds', $engineBuilds);
|
||||
$smarty->assign('runTimes', $runTimes);
|
||||
|
||||
$EMAP = array('j' => 'tm',
|
||||
'mj' => 'tm',
|
||||
'v8' => 'v8',
|
||||
'jsc' => 'jsc',
|
||||
'moom' => 'tm',
|
||||
'mooj' => 'tm');
|
||||
|
||||
/* Give a mapping from seriesIndex to engine name. */
|
||||
$engineMapping = array();
|
||||
for ($i = 0; $i < count($MIDS[$MACHINE]); $i++) {
|
||||
$engineMapping[] = "'" . $EMAP[$MIDS[$MACHINE][$i]] . "'";
|
||||
}
|
||||
$engineMapping = '[' . implode(',', $engineMapping) . ']';
|
||||
$smarty->assign('engineMapping', $engineMapping);
|
||||
}
|
||||
|
||||
function FindRuns($num)
|
||||
{
|
||||
global $MACHINE;
|
||||
$query = "SELECT id, stamp, cset, status, error
|
||||
FROM fast_run
|
||||
WHERE machine = $MACHINE
|
||||
ORDER BY stamp DESC
|
||||
LIMIT $num";
|
||||
$result = mysql_query($query) or die("error");
|
||||
$runs = array();
|
||||
while (($row = mysql_fetch_array($result)) !== FALSE)
|
||||
$runs[] = $row;
|
||||
return $runs;
|
||||
}
|
||||
|
||||
?>
|
|
@ -0,0 +1,254 @@
|
|||
<?php
|
||||
/* vim: set ts=4 sw=4 tw=99 et: */
|
||||
|
||||
require_once("internals.php");
|
||||
|
||||
init_database();
|
||||
|
||||
global $MACHINE;
|
||||
|
||||
$MACHINE = 5;
|
||||
if (isset($_GET['machine']))
|
||||
$MACHINE = intval($_GET['machine']);
|
||||
|
||||
global $STOP_DATE;
|
||||
$STOP_DATE = FALSE;
|
||||
if (isset($_GET['stopDate']))
|
||||
$STOP_DATE = intval($_GET['stopDate']);
|
||||
|
||||
$smarty = new_smarty();
|
||||
$smarty->assign('arewefastyet', 'NO.');
|
||||
$smarty->assign('MACHINE', $MACHINE);
|
||||
|
||||
$TEST_LIST = array('ss-3bit-bits-in-byte',
|
||||
'ss-aes',
|
||||
'ss-base64',
|
||||
'ss-binary-trees',
|
||||
'ss-bits-in-byte',
|
||||
'ss-bitwise-and',
|
||||
'ss-cordic',
|
||||
'v8-crypto',
|
||||
'ss-cube',
|
||||
'v8-deltablue',
|
||||
'ss-dna',
|
||||
'v8-earley-boyer',
|
||||
'ss-fannkuch',
|
||||
'ss-fasta',
|
||||
'ss-format-tofte',
|
||||
'ss-format-xparb',
|
||||
'ss-md5',
|
||||
'ss-morph',
|
||||
'ss-nbody',
|
||||
'ss-nsieve',
|
||||
'ss-nsieve-bits',
|
||||
'ss-partial-sums',
|
||||
'ss-raytrace',
|
||||
'v8-raytrace',
|
||||
'ss-recursive',
|
||||
'v8-regexp',
|
||||
'v8-richards',
|
||||
'ss-sha1',
|
||||
'ss-spectral-norm',
|
||||
'v8-splay',
|
||||
'ss-tagcloud',
|
||||
'ss-unpack-code',
|
||||
'ss-validate-input');
|
||||
|
||||
Everything($smarty);
|
||||
|
||||
$smarty->display('individual.tpl');
|
||||
|
||||
function &BuildLines(&$stats, $modes, &$runIds, $test)
|
||||
{
|
||||
$MODE_NAMES = array('j' => 'tracer',
|
||||
'm' => 'jmnotrc',
|
||||
'v8' => 'v8',
|
||||
'jsc' => 'nitro',
|
||||
'moom' => 'moom',
|
||||
'mooj' => 'mooj');
|
||||
|
||||
$lines = array();
|
||||
for ($i = 0; $i < count($modes); $i++) {
|
||||
$mode = $modes[$i];
|
||||
$lines[$mode] = '[';
|
||||
$counter = 0;
|
||||
for ($j = count($runIds) - 1; $j >= 0; $j--) {
|
||||
$runId = $runIds[$j];
|
||||
if (isset($stats[$runId][$test][$mode]))
|
||||
$amount = $stats[$runId][$test][$mode];
|
||||
else
|
||||
$amount = 'null';
|
||||
$lines[$mode] .= '[' . $counter . ',' .
|
||||
$amount .
|
||||
']';
|
||||
if ($j != 0)
|
||||
$lines[$mode] .= ',';
|
||||
$counter++;
|
||||
}
|
||||
$lines[$mode] .= ']';
|
||||
}
|
||||
|
||||
$nlines = array();
|
||||
for ($i = 0; $i < count($modes); $i++) {
|
||||
$mode = $modes[$i];
|
||||
$nlines[] = array('name' => $MODE_NAMES[$mode],
|
||||
'data' => $lines[$mode]);
|
||||
}
|
||||
|
||||
return $nlines;
|
||||
}
|
||||
|
||||
function Everything(&$smarty)
|
||||
{
|
||||
global $MACHINE;
|
||||
|
||||
$runs = FindRuns(70);
|
||||
|
||||
/* Find runs that failed. */
|
||||
for ($i = 0; $i < count($runs); $i++) {
|
||||
$run = $runs[$i];
|
||||
if ($run['status'] != 1) {
|
||||
$smarty->assign('runError', $run);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$runIds = array();
|
||||
$runTimes = array();
|
||||
for ($i = 0; $i < count($runs); $i++) {
|
||||
if ($runs[$i]['status'] != 1)
|
||||
continue;
|
||||
$runIds[] = $runs[$i]['id'];
|
||||
$runTimes[] = date("M j, Y", $runs[$i]['stamp']);
|
||||
}
|
||||
$runTimes = array_reverse($runTimes);
|
||||
if (count($runIds) == 0) {
|
||||
die("oh no what are you doing");
|
||||
}
|
||||
$idstr = implode(",", $runIds);
|
||||
|
||||
$query = "SELECT run, name, time_ms, mode, suite
|
||||
FROM fast_test
|
||||
WHERE run IN ($idstr)";
|
||||
$result = mysql_query($query) or die("error: " . mysql_error());
|
||||
$suite_stats = array();
|
||||
while (($row = mysql_fetch_array($result)) !== FALSE) {
|
||||
$runId = $row['run'];
|
||||
$name = $row['suite'] . '-' . $row['name'];
|
||||
$time = $row['time_ms'];
|
||||
$mode = $row['mode'];
|
||||
if ($mode == '')
|
||||
$mode = 'i';
|
||||
if (!isset($suite_stats[$runId][$name][$mode]))
|
||||
$suite_stats[$runId][$name][$mode] = floatval($time);
|
||||
else
|
||||
$suite_stats[$runId][$name][$mode] += floatval($time);
|
||||
}
|
||||
|
||||
$query = "SELECT run, name, cset FROM fast_engine
|
||||
WHERE run IN ($idstr)";
|
||||
$result = mysql_query($query) or die("error: " . mysql_error());
|
||||
$builds = array();
|
||||
while (($row = mysql_fetch_array($result)) !== FALSE) {
|
||||
$runId = $row['run'];
|
||||
$builds[$runId] = array('engine' => $row['name'], 'cset' => $row['cset']);
|
||||
}
|
||||
|
||||
$MIDS = array(3 => array('j', 'v8'),
|
||||
4 => array('j', 'v8', 'jsc', 'moom', 'mooj'),
|
||||
5 => array('j', 'v8', 'jsc', 'moom', 'mooj'),
|
||||
6 => array('j', 'moom', 'mooj', 'v8'),
|
||||
7 => array('j', 'moom', 'mooj', 'v8')
|
||||
);
|
||||
|
||||
/* Build the line graph data sets. */
|
||||
global $TEST_LIST;
|
||||
$tests = array();
|
||||
for ($i = 0; $i < count($TEST_LIST); $i++) {
|
||||
$lines = BuildLines($suite_stats, $MIDS[$MACHINE], $runIds, $TEST_LIST[$i]);
|
||||
$tests[] = array('lines' => $lines, 'name' => $TEST_LIST[$i]);
|
||||
}
|
||||
$smarty->assign('tests', $tests);
|
||||
|
||||
/* Now, in the same order, we want build information about each engine. */
|
||||
$query = "SELECT fr.id, fe.name, fe.cset
|
||||
FROM fast_engine fe
|
||||
JOIN fast_run fr
|
||||
ON fe.run = fr.id
|
||||
WHERE fr.id IN ($idstr)
|
||||
ORDER BY fr.id ASC";
|
||||
$query = mysql_query($query);
|
||||
if (!$query)
|
||||
die('error: ' . mysql_error());
|
||||
|
||||
/* Prep the mapping of engine names and runs to builds. */
|
||||
$engines = array('jm', 'tm', 'v8', 'jsc', 'moo');
|
||||
$engineStrings = array();
|
||||
for ($i = 0; $i < count($engines); $i++)
|
||||
$engineStrings[$engines[$i]] = array();
|
||||
|
||||
/* Map engine names and run IDs to builds. */
|
||||
while (($data = mysql_fetch_array($query)) !== FALSE)
|
||||
$engineStrings[$data[1]][$data[0]] = "'" . $data[2] . "'";
|
||||
|
||||
/* Please agree with me that this is hideous. Why aren't I using Python. */
|
||||
$engineBuilds = array();
|
||||
for ($i = 0; $i < count($engines); $i++) {
|
||||
$engine = $engines[$i];
|
||||
$newvec = array();
|
||||
for ($j = count($runIds) - 1; $j >= 0; $j--) {
|
||||
$run = $runIds[$j];
|
||||
if (isset($engineStrings[$engine][$run])) {
|
||||
$newvec[] = $engineStrings[$engine][$run];
|
||||
} else {
|
||||
$newvec[] = "null";
|
||||
}
|
||||
}
|
||||
$engineBuilds[$engine] = implode(',', $newvec);
|
||||
}
|
||||
|
||||
$smarty->assign('engineBuilds', $engineBuilds);
|
||||
$smarty->assign('runTimes', $runTimes);
|
||||
|
||||
$EMAP = array('j' => 'tm',
|
||||
'mj' => 'tm',
|
||||
'v8' => 'v8',
|
||||
'jsc' => 'jsc',
|
||||
'moom' => 'tm',
|
||||
'mooj' => 'tm');
|
||||
|
||||
/* Give a mapping from seriesIndex to engine name. */
|
||||
$engineMapping = array();
|
||||
for ($i = 0; $i < count($MIDS[$MACHINE]); $i++) {
|
||||
$engineMapping[] = "'" . $EMAP[$MIDS[$MACHINE][$i]] . "'";
|
||||
}
|
||||
$engineMapping = '[' . implode(',', $engineMapping) . ']';
|
||||
$smarty->assign('engineMapping', $engineMapping);
|
||||
}
|
||||
|
||||
function FindRuns($num)
|
||||
{
|
||||
global $MACHINE;
|
||||
global $STOP_DATE;
|
||||
if ($STOP_DATE) {
|
||||
$query = "SELECT id, stamp, cset, status, error
|
||||
FROM fast_run
|
||||
WHERE machine = $MACHINE
|
||||
AND stamp <= $STOP_DATE
|
||||
ORDER BY stamp DESC
|
||||
LIMIT $num";
|
||||
} else {
|
||||
$query = "SELECT id, stamp, cset, status, error
|
||||
FROM fast_run
|
||||
WHERE machine = $MACHINE
|
||||
ORDER BY stamp DESC
|
||||
LIMIT $num";
|
||||
}
|
||||
$result = mysql_query($query) or die("error");
|
||||
$runs = array();
|
||||
while (($row = mysql_fetch_array($result)) !== FALSE)
|
||||
$runs[] = $row;
|
||||
return $runs;
|
||||
}
|
||||
|
||||
?>
|
|
@ -0,0 +1,75 @@
|
|||
<?php
|
||||
// vim: set ts=4 sw=4 tw=99 et:
|
||||
|
||||
require_once("smarty/libs/Smarty.class.php");
|
||||
|
||||
function init_database()
|
||||
{
|
||||
mysql_connect("localhost", "***", "***") or die("ERROR: " . mysql_error());
|
||||
mysql_select_db("dvander") or die("ERROR: " . mysql_error());
|
||||
}
|
||||
|
||||
function GET_int($name)
|
||||
{
|
||||
if (isset($_GET[$name]))
|
||||
return intval($_GET[$name]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
function GET_string($name)
|
||||
{
|
||||
if (isset($_GET[$name]))
|
||||
return $_GET[$name];
|
||||
return "";
|
||||
}
|
||||
|
||||
function new_smarty()
|
||||
{
|
||||
$smarty = new Smarty;
|
||||
$base = '/usr/apache/htdocs';
|
||||
$smarty->template_dir = $base . '/templates';
|
||||
$smarty->compile_dir = $base . '/cache_templates';
|
||||
$smarty->cache_dir = $base . '/cache_stuff';
|
||||
return $smarty;
|
||||
}
|
||||
|
||||
function find_vendor_of_mode_id($mode_id)
|
||||
{
|
||||
$query = "SELECT vendor_id FROM awfy_mode
|
||||
WHERE id = $mode_id";
|
||||
$results = mysql_query($query);
|
||||
if (!$results || mysql_num_rows($results) < 1)
|
||||
return 01;
|
||||
$row = mysql_fetch_array($results);
|
||||
return intval($row[0]);
|
||||
}
|
||||
|
||||
function find_mode($mode)
|
||||
{
|
||||
$query = "SELECT id FROM awfy_mode
|
||||
WHERE mode = '" . mysql_real_escape_string($mode) . "'";
|
||||
$results = mysql_query($query);
|
||||
if (!$results || mysql_num_rows($results) < 1)
|
||||
return -1;
|
||||
$row = mysql_fetch_array($results);
|
||||
return intval($row[0]);
|
||||
}
|
||||
|
||||
function find_suite($suite)
|
||||
{
|
||||
$query = "SELECT id FROM awfy_suite
|
||||
WHERE name = '" . mysql_real_escape_string($suite) . "'";
|
||||
$results = mysql_query($query);
|
||||
if (!$results || mysql_num_rows($results) < 1)
|
||||
return -1;
|
||||
$row = mysql_fetch_array($results);
|
||||
return intval($row[0]);
|
||||
}
|
||||
|
||||
function awfy_query($query)
|
||||
{
|
||||
$result = mysql_query($query) or die(mysql_error());
|
||||
return $result;
|
||||
}
|
||||
|
||||
?>
|
|
@ -0,0 +1,4 @@
|
|||
internals.php has settings redacted - fill 'em in, under mysql_connect and /usr/apache/htdocs
|
||||
UPDATED.PHP should be renamed to something random, not very secure i know but this is a hack job.
|
||||
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
<?php
|
||||
/* vim: set ts=4 sw=4 tw=99 et: */
|
||||
|
||||
require_once("internals.php");
|
||||
|
||||
init_database();
|
||||
|
||||
global $MACHINE;
|
||||
|
||||
$smarty = new_smarty();
|
||||
|
||||
Everything($smarty);
|
||||
|
||||
$smarty->display('rss.tpl');
|
||||
|
||||
function Everything(&$smarty)
|
||||
{
|
||||
$runs = FindRuns(20);
|
||||
|
||||
for ($i = 0; $i < count($runs); $i++) {
|
||||
$runs[$i]['date'] = date("M j, Y H:i", $runs[$i]['stamp']);
|
||||
}
|
||||
|
||||
$smarty->assign('runs', $runs);
|
||||
}
|
||||
|
||||
function FindRuns($num)
|
||||
{
|
||||
global $MACHINE;
|
||||
$query = "SELECT id, stamp, cset, status, error, machine, cpu, os
|
||||
FROM fast_run
|
||||
ORDER BY stamp DESC
|
||||
LIMIT $num";
|
||||
$result = mysql_query($query) or die("error");
|
||||
$runs = array();
|
||||
while (($row = mysql_fetch_array($result)) !== FALSE)
|
||||
$runs[] = $row;
|
||||
return $runs;
|
||||
}
|
||||
|
||||
?>
|
|
@ -0,0 +1,63 @@
|
|||
-- phpMyAdmin SQL Dump
|
||||
-- version 3.1.3
|
||||
-- http://www.phpmyadmin.net
|
||||
--
|
||||
-- Host: localhost
|
||||
-- Generation Time: Apr 23, 2010 at 03:53 AM
|
||||
-- Server version: 5.1.41
|
||||
-- PHP Version: 5.2.9
|
||||
|
||||
SET SQL_MODE="NO_AUTO_VALUE_ON_ZERO";
|
||||
|
||||
--
|
||||
-- Database: `dvander`
|
||||
--
|
||||
|
||||
-- --------------------------------------------------------
|
||||
|
||||
--
|
||||
-- Table structure for table `fast_engine`
|
||||
--
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `fast_engine` (
|
||||
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`run` int(10) unsigned NOT NULL,
|
||||
`name` varchar(32) NOT NULL,
|
||||
`cset` varchar(256) NOT NULL,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;
|
||||
|
||||
-- --------------------------------------------------------
|
||||
|
||||
--
|
||||
-- Table structure for table `fast_run`
|
||||
--
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `fast_run` (
|
||||
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`cpu` varchar(20) NOT NULL,
|
||||
`os` varchar(20) NOT NULL,
|
||||
`machine` int(10) unsigned NOT NULL,
|
||||
`stamp` int(10) unsigned NOT NULL,
|
||||
`cset` varchar(160) NOT NULL,
|
||||
`status` int(11) NOT NULL,
|
||||
`error` mediumtext NOT NULL,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=1;
|
||||
|
||||
-- --------------------------------------------------------
|
||||
|
||||
--
|
||||
-- Table structure for table `fast_test`
|
||||
--
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `fast_test` (
|
||||
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`run` int(10) unsigned NOT NULL,
|
||||
`name` varchar(50) NOT NULL,
|
||||
`time_ms` float NOT NULL,
|
||||
`suite` varchar(50) NOT NULL,
|
||||
`mode` varchar(12) NOT NULL,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=1;
|
||||
|
|
@ -0,0 +1,123 @@
|
|||
body {
|
||||
background-color:#FFF;
|
||||
font:.6875em Verdana, Arial, Helvetica, sans-serif;
|
||||
color:#000;
|
||||
}
|
||||
a {
|
||||
color:#000;
|
||||
text-decoration:underline;
|
||||
}
|
||||
a:hover {
|
||||
text-decoration:none;
|
||||
}
|
||||
h1 {
|
||||
font-size:2.265em;
|
||||
font-weight:700;
|
||||
}
|
||||
#graph-container {
|
||||
margin: 0 auto;
|
||||
width:1040px;
|
||||
}
|
||||
.graph, .label {
|
||||
width:900px;
|
||||
}
|
||||
.graph {
|
||||
height: 350px;
|
||||
}
|
||||
.label {
|
||||
position:relative;
|
||||
text-align:center;
|
||||
padding-bottom:5px;
|
||||
}
|
||||
#tooltip {
|
||||
-moz-border-radius:.35em;
|
||||
-webkit-border-radius:.35em;
|
||||
background-color:#000;
|
||||
color:#FFF;
|
||||
display:none;
|
||||
opacity:0.8;
|
||||
padding:.25em;
|
||||
position:absolute;
|
||||
}
|
||||
#tooltip a:link, #tooltip a:active, #tooltip a:visited {
|
||||
color:#FFF;
|
||||
text-decoration: underline;
|
||||
}
|
||||
#tooltip a:hover {
|
||||
color:#FFF;
|
||||
text-decoration: none;
|
||||
}
|
||||
.engine-legend {
|
||||
padding-top:2em;
|
||||
clear:both;
|
||||
}
|
||||
.engine-legend {
|
||||
text-align:center;
|
||||
}
|
||||
|
||||
#legend1 {
|
||||
margin-bottom:-1em;
|
||||
}
|
||||
|
||||
#legend2, #links, h1 {
|
||||
text-align:center;
|
||||
margin-bottom:1em;
|
||||
}
|
||||
.engine-legend li, #links li {
|
||||
display:inline;
|
||||
}
|
||||
.engine-legend li {
|
||||
border-left:1.2em solid #FFF;
|
||||
padding-left:.5em;
|
||||
margin-right:2em;
|
||||
}
|
||||
.engine-legend #tracing {
|
||||
border-color:#FFA451;
|
||||
}
|
||||
.engine-legend #jaeger {
|
||||
border-color:#3E99D7;
|
||||
}
|
||||
.engine-legend #jaeger-and-tracing {
|
||||
border-color:#6f0a93;
|
||||
}
|
||||
.engine-legend #google-v8 {
|
||||
border-color:#4DA74D;
|
||||
}
|
||||
.engine-legend #apple-nitro {
|
||||
border-color:#CF4B4B;
|
||||
}
|
||||
.engine-legend #interpreter {
|
||||
border-color:#737373;
|
||||
}
|
||||
.engine-legend #apple-jsci {
|
||||
border-color:#EF8B8B;
|
||||
}
|
||||
.engine-legend #moz-mooi {
|
||||
border-color:#027364;
|
||||
}
|
||||
.engine-legend #moz-moom {
|
||||
border-color:#000000;
|
||||
}
|
||||
#links li {
|
||||
border-right:1px solid #000;
|
||||
padding:0 1.265em 0 1em;
|
||||
}
|
||||
#links li:last-child {
|
||||
border:none;
|
||||
}
|
||||
#lastUpdate {
|
||||
float:right;
|
||||
margin-bottom:1em;
|
||||
color: gray;
|
||||
font-size: x-small;
|
||||
}
|
||||
#faq {
|
||||
margin:2em auto;
|
||||
width:80%;
|
||||
}
|
||||
#faq li {
|
||||
font-weight:700
|
||||
}
|
||||
#faq li p:last-child {
|
||||
font-weight:normal;
|
||||
}
|
|
@ -0,0 +1,127 @@
|
|||
body {
|
||||
background-color:#FFF;
|
||||
font:.6875em Verdana, Arial, Helvetica, sans-serif;
|
||||
color:#000;
|
||||
}
|
||||
a {
|
||||
color:#000;
|
||||
text-decoration:underline;
|
||||
}
|
||||
a:hover {
|
||||
text-decoration:none;
|
||||
}
|
||||
h1 {
|
||||
font-size:2.265em;
|
||||
font-weight:700;
|
||||
}
|
||||
#graph-container {
|
||||
margin: 0 auto;
|
||||
width:1140px;
|
||||
}
|
||||
#sunspider-graph, #v8-graph, #sunspider-label, #v8-label {
|
||||
width:555px;
|
||||
float:left;
|
||||
}
|
||||
#sunspider-graph, #v8-graph {
|
||||
height:350px;
|
||||
}
|
||||
#v8-graph, #v8-label {
|
||||
Left:50px;
|
||||
}
|
||||
#sunspider-label, #v8-label {
|
||||
position:relative;
|
||||
text-align:center;
|
||||
padding-bottom:5px;
|
||||
}
|
||||
#tooltip {
|
||||
-moz-border-radius:.35em;
|
||||
-webkit-border-radius:.35em;
|
||||
background-color:#000;
|
||||
color:#FFF;
|
||||
display:none;
|
||||
opacity:0.8;
|
||||
padding:.25em;
|
||||
position:absolute;
|
||||
}
|
||||
#tooltip a:link, #tooltip a:active, #tooltip a:visited {
|
||||
color:#FFF;
|
||||
text-decoration: underline;
|
||||
}
|
||||
#tooltip a:hover {
|
||||
color:#FFF;
|
||||
text-decoration: none;
|
||||
}
|
||||
.engine-legend {
|
||||
padding-top:2em;
|
||||
clear:both;
|
||||
}
|
||||
.engine-legend {
|
||||
text-align:center;
|
||||
}
|
||||
|
||||
#legend1 {
|
||||
margin-bottom:-1em;
|
||||
}
|
||||
|
||||
#legend2, #links, h1, #footer {
|
||||
text-align:center;
|
||||
margin-bottom:1em;
|
||||
}
|
||||
.engine-legend li, #links li, #footer li {
|
||||
display:inline;
|
||||
}
|
||||
.engine-legend li {
|
||||
border-left:1.2em solid #FFF;
|
||||
padding-left:.5em;
|
||||
margin-right:2em;
|
||||
}
|
||||
.engine-legend #tracing {
|
||||
border-color:#FFA451;
|
||||
}
|
||||
.engine-legend #jaeger {
|
||||
border-color:#3E99D7;
|
||||
}
|
||||
.engine-legend #moz-mooj {
|
||||
border-color:#6f0a93;
|
||||
}
|
||||
.engine-legend #google-v8 {
|
||||
border-color:#4DA74D;
|
||||
}
|
||||
.engine-legend #apple-nitro {
|
||||
border-color:#CF4B4B;
|
||||
}
|
||||
.engine-legend #interpreter {
|
||||
border-color:#737373;
|
||||
}
|
||||
.engine-legend #apple-jsci {
|
||||
border-color:#EF8B8B;
|
||||
}
|
||||
.engine-legend #moz-mooi {
|
||||
border-color:#027364;
|
||||
}
|
||||
.engine-legend #moz-moom {
|
||||
border-color:#000000;
|
||||
}
|
||||
#links li, #footer li {
|
||||
border-right:1px solid #000;
|
||||
padding:0 1.265em 0 1em;
|
||||
}
|
||||
#links li:last-child, #footer li:last-child {
|
||||
border:none;
|
||||
}
|
||||
#lastUpdate {
|
||||
float:right;
|
||||
margin-bottom:1em;
|
||||
color: gray;
|
||||
font-size: x-small;
|
||||
}
|
||||
#faq {
|
||||
margin:2em auto;
|
||||
width:80%;
|
||||
}
|
||||
#faq li {
|
||||
font-weight:700
|
||||
}
|
||||
#faq li p:last-child {
|
||||
font-weight:normal;
|
||||
}
|
|
@ -0,0 +1,295 @@
|
|||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
|
||||
<meta http-equiv="content-language" content="en">
|
||||
<meta http-equiv="refresh" content="300">
|
||||
<title>ARE WE FAST YET?</title>
|
||||
<link rel="stylesheet" title="Default Stylesheet" type="text/css" href="style.css">
|
||||
<link rel="alternate" type="application/rss+xml" title="RSS feeds" href="rss.php">
|
||||
<link rel="shortcut icon" href="http://www.arewefastyet.com/awfy_favicon.png">
|
||||
<script type="text/javascript" src="flot/jquery.js"></script>
|
||||
<script type="text/javascript" src="flot/jquery.flot.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="graph-container">
|
||||
<div id="sunspider-label">sunspider<span id="sunspider-speed"></span></div>
|
||||
<div id="v8-label">v8bench<span id="v8-speed"></span></div>
|
||||
<div id="sunspider-graph"></div>
|
||||
<div id="v8-graph"></div>
|
||||
</div>
|
||||
<ul class="engine-legend" id="legend1">
|
||||
<li id="moz-mooj">mozilla firefox 4 (TM+JM)</li>
|
||||
<li id="google-v8">google chrome (v8)</li>
|
||||
</ul>
|
||||
<ul class="engine-legend" id="legend2">
|
||||
{if $MACHINE == 5 or $MACHINE == 4}
|
||||
<li id="apple-nitro">apple safari (nitro)</li>
|
||||
{else}
|
||||
<li id="moz-moom">mozilla firefox (JM only)</li>
|
||||
<li id="tracing">mozilla firefox (TM only)</li>
|
||||
{/if}
|
||||
</ul>
|
||||
<script type="text/javascript">
|
||||
{literal}
|
||||
var fullNames = {
|
||||
jm: 'tracemonkey',
|
||||
tm: 'tracemonkey',
|
||||
v8: 'v8',
|
||||
jsc: 'WebKit',
|
||||
jsci: 'WebKit',
|
||||
moo: 'tracemonkey',
|
||||
};
|
||||
function calcPercentDiff(currentValue, previousValue) {
|
||||
return -Math.round(((currentValue - previousValue) / previousValue) * 1000) / 10;
|
||||
}
|
||||
function getLowestNitroV8SetNumber(dsets) {
|
||||
var nitroSetNumber = -1;
|
||||
var v8SetNumber = -1;
|
||||
for (var i = 0; i < dsets.length; i++) {
|
||||
if (dsets[i].name == "nitro") {
|
||||
nitroSetNumber = i;
|
||||
} else if (dsets[i].name == "v8") {
|
||||
v8SetNumber = i;
|
||||
}
|
||||
}
|
||||
if ((nitroSetNumber > -1) && (dsets[nitroSetNumber].data[dsets[nitroSetNumber,1].data.length - 1][1] < dsets[v8SetNumber].data[dsets[v8SetNumber,1].data.length - 1][1])) {
|
||||
return nitroSetNumber;
|
||||
} else {
|
||||
return v8SetNumber;
|
||||
}
|
||||
}
|
||||
function getTitlePercentDiff(dsets) {
|
||||
var dataLength = dsets[3].data.length -1; //ID for last Jaeger dataset
|
||||
var lastJaeger = dsets[3].data[dataLength][1]; //last speed data point for Jaeger
|
||||
var target = dsets[getLowestNitroV8SetNumber(dsets)].data[dataLength][1]; //set Target to the lowest last value of V8 and Nitro
|
||||
var percentDiff = calcPercentDiff(lastJaeger,target); //get the percent diff between Jaeger and the Target
|
||||
if (percentDiff > 10) percentDiff = Math.round(percentDiff);//if the percent diff is above 10, round to eliminate 10ths
|
||||
var direction = "slower"; //set speed direction Slower/Faster from Jaeger value compared to Target
|
||||
if (lastJaeger < target) direction = "FASTER!";
|
||||
var titlePercent = ' is ' + percentDiff +'% ' + direction;
|
||||
return titlePercent;
|
||||
}
|
||||
function colorForName(name) {
|
||||
return ({ nitro: "#cf4b4b",
|
||||
interp: "#bbbbbb",
|
||||
v8: "#4da74d",
|
||||
jaeger: "#6f0a93",
|
||||
{/literal}
|
||||
{if $MACHINE == 4 || $MACHINE == 5}
|
||||
tracer: "#6f0a93",
|
||||
{else}
|
||||
tracer: "#ffa451",
|
||||
{/if}
|
||||
{literal}
|
||||
jsci: "#EF8B8B",
|
||||
mooi: "#027364",
|
||||
moom: "#000000",
|
||||
mooj: "#6f0a93",
|
||||
jmnotrc: "#3e99d7"})[name];
|
||||
}
|
||||
function fillColorForName(name) {
|
||||
return "#ffffff";
|
||||
}
|
||||
function drawGraph(sel, dsets) {
|
||||
var sets = [];
|
||||
var jaegerSetNumber = 3;
|
||||
for (var i = 0; i < dsets.length; i++) {
|
||||
var dataRadius = 2.0;
|
||||
if (dsets[i].name == "jaeger") {
|
||||
jaegerSetNumber = i;
|
||||
}
|
||||
sets[i] = {
|
||||
lines: { show: true },
|
||||
points: { show: true,
|
||||
fillColor: fillColorForName(dsets[i].name),
|
||||
},
|
||||
borderWidth: 1.5,
|
||||
borderColor: "#BEBEBE",
|
||||
markingsLineWidth: .75,
|
||||
hoverable: true,
|
||||
clickable: true,
|
||||
label: dsets[i].name,
|
||||
data: dsets[i].data,
|
||||
color: colorForName(dsets[i].name),
|
||||
shadowSize: 0
|
||||
};
|
||||
}
|
||||
var options = { yaxis: {
|
||||
min: 0,
|
||||
tickFormatter:
|
||||
function (v, axis) { return v + "ms"; }
|
||||
},
|
||||
xaxis: {
|
||||
tickFormatter:
|
||||
function (v, axis) {
|
||||
v = Math.round(v);
|
||||
if (!(v in runTimes))
|
||||
return '';
|
||||
return runTimes[v].substr(0, runTimes[v].indexOf(','));
|
||||
}
|
||||
},
|
||||
legend:
|
||||
{
|
||||
show: false
|
||||
},
|
||||
grid:
|
||||
{
|
||||
hoverable: true,
|
||||
clickable: true
|
||||
}
|
||||
};
|
||||
function showToolTip(x, y, contents) {
|
||||
var tipWidth = 165;
|
||||
var tipHeight = 75;
|
||||
var xOffset = 5;
|
||||
var yOffset = 5;
|
||||
var ie = document.all && !window.opera;
|
||||
var iebody = (document.compatMode == "CSS1Compat")
|
||||
? document.documentElement
|
||||
: document.body;
|
||||
var scrollLeft = ie ? iebody.scrollLeft : window.pageXOffset;
|
||||
var scrollTop = ie ? iebody.scrollTop : window.pageYOffset;
|
||||
var docWidth = ie ? iebody.clientWidth - 15 : window.innerWidth - 15;
|
||||
var docHeight = ie ? iebody.clientHeight - 15 : window.innerHeight - 18;
|
||||
y = (y + tipHeight - scrollTop > docHeight)
|
||||
? y - tipHeight - 5 - (yOffset * 2)
|
||||
: y; // account for bottom edge
|
||||
|
||||
// account for right edge
|
||||
if (x + tipWidth - scrollLeft > docWidth) {
|
||||
$('<div id="tooltip">' + contents + '<\/div>').css( {
|
||||
top: y + yOffset,
|
||||
right: docWidth - x + xOffset,
|
||||
}).appendTo("body").fadeIn(200);
|
||||
} else {
|
||||
$('<div id="tooltip">' + contents + '<\/div>').css( {
|
||||
top: y + yOffset,
|
||||
left: x + xOffset,
|
||||
}).appendTo("body").fadeIn(200);
|
||||
}
|
||||
}
|
||||
var previousPoint = null;
|
||||
$.plot(sel, sets, options);
|
||||
sel.bind("plothover", function (event, pos, item) {
|
||||
if (item) {
|
||||
if (!previousPoint ||
|
||||
(previousPoint[0] != item.datapoint[0]) ||
|
||||
(previousPoint[1] != item.datapoint[1])) {
|
||||
previousPoint = item.datapoint;
|
||||
$("#tooltip").remove();
|
||||
var x = item.datapoint[0];
|
||||
var y = item.datapoint[1];
|
||||
var e = engineNames[item.seriesIndex];
|
||||
var text = 'speed: ' + y + "ms" + "<br>";
|
||||
if (x > 0) {
|
||||
var thisValue = parseFloat(y);
|
||||
var prevValue = parseFloat(item.series.data[x-1,x-1][1]);
|
||||
var speedDiff = Math.round((thisValue - prevValue)*10)/10;
|
||||
var pdiff = calcPercentDiff(thisValue, prevValue);
|
||||
var fbofw;
|
||||
if (pdiff < 0) {
|
||||
fbofw = "worse";
|
||||
pdiff = -pdiff;
|
||||
} else {
|
||||
fbofw = "better";
|
||||
}
|
||||
if (speedDiff === speedDiff) {
|
||||
text += String.fromCharCode(916) + ": " + speedDiff + 'ms (' +
|
||||
pdiff + "% " + fbofw + ")<br>";
|
||||
}
|
||||
}
|
||||
var fullName = fullNames[e];
|
||||
text += "source: " + fullName + "<br>";
|
||||
text += "rev: ";
|
||||
var cset = engineBuilds[e][x];
|
||||
if (cset) {
|
||||
if (fullName == "tracemonkey") {
|
||||
text += "<a href=\"http://hg.mozilla.org/tracemonkey/rev/" + cset +
|
||||
"\">" + cset + "</a>";
|
||||
} else if (fullName == "v8") {
|
||||
text += "<a href=\"http://code.google.com/p/v8/source/detail?r=" + cset +
|
||||
"\">" + cset + "</a>";
|
||||
} else if (fullName == "WebKit") {
|
||||
text += "<a href=\"http://trac.webkit.org/changeset/" + cset +
|
||||
"\">" + cset + "</a>";
|
||||
} else {
|
||||
text += cset;
|
||||
}
|
||||
} else {
|
||||
text += 'unknown';
|
||||
}
|
||||
text += "<br>";
|
||||
var buildTime = runTimes[x];
|
||||
text += "tested: " + buildTime;
|
||||
showToolTip(item.pageX, item.pageY, text);
|
||||
}
|
||||
} else {
|
||||
$("#tooltip").remove();
|
||||
previousPoint = null;
|
||||
}
|
||||
});
|
||||
}
|
||||
var runTimes = [
|
||||
{/literal}
|
||||
{foreach from=$runTimes item=v name=runtimes}
|
||||
'{$v}'{if !$smarty.foreach.runtimes.last},{/if}
|
||||
{/foreach}
|
||||
{literal}
|
||||
];
|
||||
var engineBuilds = {
|
||||
{/literal}
|
||||
{foreach from=$engineBuilds key=k item=v name=emap}
|
||||
{$k}: [ {$v} ]{if !$smarty.foreach.emap.last},{/if}
|
||||
|
||||
{/foreach}
|
||||
{literal}
|
||||
};
|
||||
var engineNames = {/literal}{$engineMapping}{literal};
|
||||
function drawSelfSS() {
|
||||
var dsets = [
|
||||
{/literal}
|
||||
{foreach from=$self_ss item=set}
|
||||
{literal}{{/literal}
|
||||
name: "{$set.name}",
|
||||
data: {$set.data}
|
||||
{literal}}{/literal},
|
||||
{/foreach}
|
||||
{literal}
|
||||
];
|
||||
drawGraph($("#sunspider-graph"), dsets);
|
||||
//document.getElementById('sunspider-speed').innerHTML = getTitlePercentDiff(dsets);
|
||||
}
|
||||
function drawSelfV8() {
|
||||
var dsets = [
|
||||
{/literal}
|
||||
{foreach from=$self_v8 item=set}
|
||||
{literal}{{/literal}
|
||||
name: "{$set.name}",
|
||||
data: {$set.data}
|
||||
{literal}}{/literal},
|
||||
{/foreach}
|
||||
{literal}
|
||||
];
|
||||
drawGraph($("#v8-graph"), dsets);
|
||||
//document.getElementById('v8-speed').innerHTML = getTitlePercentDiff(dsets);
|
||||
}
|
||||
$(document).ready(function () {
|
||||
drawSelfSS();
|
||||
drawSelfV8();
|
||||
});
|
||||
{/literal}
|
||||
</script>
|
||||
<ul id="links">
|
||||
<li><a href="?machine=5">x86</a></li>
|
||||
<li><a href="?machine=4">x64</a></li>
|
||||
<!-- <li><a href="?machine=3">ARM</a></li> -->
|
||||
<li><a href="?machine=6">regress-x86</a></li>
|
||||
<li><a href="?machine=7">regress-x64</a></li>
|
||||
<li><a href="faq.html">FAQ</a></li>
|
||||
<li><a href="awfy2.php?machine=9">beta awfy2</a></li>
|
||||
<li><a href="mailto:danderson@mozilla.com">suggestions</a></li>
|
||||
</ul>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,251 @@
|
|||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
|
||||
<meta http-equiv="content-language" content="en">
|
||||
<title>ARE WE FAST YET?</title>
|
||||
<link rel="stylesheet" title="Default Stylesheet" type="text/css" href="style-indiv.css">
|
||||
<link rel="alternate" type="application/rss+xml" title="RSS feeds" href="rss.php">
|
||||
<link rel="shortcut icon" href="http://www.arewefastyet.com/awfy_favicon.png">
|
||||
<script type="text/javascript" src="MochiKit/MochiKit.js"></script>
|
||||
<script type="text/javascript" src="flot/jquery.js"></script>
|
||||
<script type="text/javascript" src="flot/jquery.flot.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<ul class="engine-legend" id="legend1">
|
||||
<li id="tracing">moz tracing JIT</li>
|
||||
{if $MACHINE >= 6}
|
||||
<li id="jaeger-and-tracing">moz method+tracing</li>
|
||||
{else}
|
||||
<li id="google-v8">google v8</li>
|
||||
{if $MACHINE != 3}
|
||||
<li id="apple-nitro">apple nitro</li>
|
||||
{/if}
|
||||
{/if}
|
||||
</ul>
|
||||
{if $MACHINE >= 4}
|
||||
<ul class="engine-legend" id="legend2">
|
||||
<li id="moz-moom">moz method JIT</li>
|
||||
{if $MACHINE >= 6}
|
||||
<li id="google-v8">google v8</li>
|
||||
{/if}
|
||||
</ul>
|
||||
{/if}
|
||||
{foreach from=$tests item=test}
|
||||
<div class="graph-label">{$test.name}</div>
|
||||
<div class="graph" id="graph-{$test.name}"></div>
|
||||
<p> </p>
|
||||
{/foreach}
|
||||
<script type="text/javascript">
|
||||
{literal}
|
||||
var fullNames = {
|
||||
jm: 'jaegermonkey',
|
||||
tm: 'tracemonkey',
|
||||
v8: 'v8',
|
||||
jsc: 'WebKit',
|
||||
jsci: 'WebKit',
|
||||
moo: 'jm-fatvals'
|
||||
};
|
||||
function calcPercentDiff(currentValue, previousValue) {
|
||||
return -Math.round(((currentValue - previousValue) / previousValue) * 1000) / 10;
|
||||
}
|
||||
function getLowestNitroV8SetNumber(dsets) {
|
||||
var nitroSetNumber = -1;
|
||||
var v8SetNumber = -1;
|
||||
for (var i = 0; i < dsets.length; i++) {
|
||||
if (dsets[i].name == "nitro") {
|
||||
nitroSetNumber = i;
|
||||
} else if (dsets[i].name == "v8") {
|
||||
v8SetNumber = i;
|
||||
}
|
||||
}
|
||||
if ((nitroSetNumber > -1) && (dsets[nitroSetNumber].data[dsets[nitroSetNumber,1].data.length - 1][1] < dsets[v8SetNumber].data[dsets[v8SetNumber,1].data.length - 1][1])) {
|
||||
return nitroSetNumber;
|
||||
} else {
|
||||
return v8SetNumber;
|
||||
}
|
||||
}
|
||||
function getTitlePercentDiff(dsets) {
|
||||
var dataLength = dsets[3].data.length -1; //ID for last Jaeger dataset
|
||||
var lastJaeger = dsets[3].data[dataLength][1]; //last speed data point for Jaeger
|
||||
var target = dsets[getLowestNitroV8SetNumber(dsets)].data[dataLength][1]; //set Target to the lowest last value of V8 and Nitro
|
||||
var percentDiff = calcPercentDiff(lastJaeger,target); //get the percent diff between Jaeger and the Target
|
||||
if (percentDiff > 10) percentDiff = Math.round(percentDiff);//if the percent diff is above 10, round to eliminate 10ths
|
||||
var direction = "slower"; //set speed direction Slower/Faster from Jaeger value compared to Target
|
||||
if (lastJaeger < target) direction = "FASTER!";
|
||||
var titlePercent = ' is ' + percentDiff +'% ' + direction;
|
||||
return titlePercent;
|
||||
}
|
||||
function colorForName(name) {
|
||||
return ({ nitro: "#cf4b4b",
|
||||
interp: "#bbbbbb",
|
||||
v8: "#4da74d",
|
||||
jaeger: "#6f0a93",
|
||||
tracer: "#ffa451",
|
||||
jsci: "#EF8B8B",
|
||||
mooi: "#027364",
|
||||
mooj: "#6f0a93",
|
||||
moom: "#000000",
|
||||
jmnotrc: "#3e99d7"})[name];
|
||||
}
|
||||
function fillColorForName(name) {
|
||||
return "#ffffff";
|
||||
}
|
||||
function drawGraph(sel, dsets) {
|
||||
var sets = [];
|
||||
var jaegerSetNumber = 3;
|
||||
for (var i = 0; i < dsets.length; i++) {
|
||||
var dataRadius = 1.8;
|
||||
if (dsets[i].name == "jaeger") {
|
||||
jaegerSetNumber = i;
|
||||
}
|
||||
sets[i] = {
|
||||
lines: { show: true },
|
||||
points: { show: true,
|
||||
fillColor: fillColorForName(dsets[i].name),
|
||||
radius: dataRadius
|
||||
},
|
||||
borderWidth: 1.5,
|
||||
borderColor: "#BEBEBE",
|
||||
markingsLineWidth: .75,
|
||||
hoverable: true,
|
||||
clickable: true,
|
||||
label: dsets[i].name,
|
||||
data: dsets[i].data,
|
||||
color: colorForName(dsets[i].name),
|
||||
shadowSize: 0
|
||||
};
|
||||
}
|
||||
var options = { yaxis: {
|
||||
min: 0,
|
||||
tickFormatter:
|
||||
function (v, axis) { return v + "ms"; }
|
||||
},
|
||||
xaxis: {
|
||||
tickFormatter:
|
||||
function (v, axis) {
|
||||
v = Math.round(v);
|
||||
if (!(v in runTimes))
|
||||
return '';
|
||||
return runTimes[v].substr(0, runTimes[v].indexOf(','));
|
||||
}
|
||||
},
|
||||
legend: {
|
||||
show: false
|
||||
},
|
||||
grid: {
|
||||
hoverable: true,
|
||||
clickable: true
|
||||
}
|
||||
};
|
||||
function showToolTip(x, y, contents) {
|
||||
$('<div id="tooltip">' + contents + '<\/div>').css( {
|
||||
top: y + 5,
|
||||
left: x + 5,
|
||||
}).appendTo("body").fadeIn(200);
|
||||
}
|
||||
var previousPoint = null;
|
||||
$.plot(sel, sets, options);
|
||||
sel.bind("plothover", function (event, pos, item) {
|
||||
if (item) {
|
||||
if (!previousPoint ||
|
||||
(previousPoint[0] != item.datapoint[0]) ||
|
||||
(previousPoint[1] != item.datapoint[1])) {
|
||||
previousPoint = item.datapoint;
|
||||
$("#tooltip").remove();
|
||||
var x = item.datapoint[0];
|
||||
var y = item.datapoint[1];
|
||||
var e = engineNames[item.seriesIndex];
|
||||
var text = 'speed: ' + y + "ms" + "<br>";
|
||||
if (x > 0) {
|
||||
var thisValue = parseFloat(y);
|
||||
var prevValue = parseFloat(item.series.data[x-1,x-1][1]);
|
||||
var speedDiff = Math.round((thisValue - prevValue)*10)/10;
|
||||
var pdiff = calcPercentDiff(thisValue, prevValue);
|
||||
var fbofw;
|
||||
if (pdiff < 0) {
|
||||
fbofw = "worse";
|
||||
pdiff = -pdiff;
|
||||
} else {
|
||||
fbofw = "better";
|
||||
}
|
||||
text += String.fromCharCode(916) + ": " + speedDiff + 'ms (' +
|
||||
pdiff + "% " + fbofw + ")<br>";
|
||||
}
|
||||
var fullName = fullNames[e];
|
||||
text += "source: " + fullName + "<br>";
|
||||
text += "rev: ";
|
||||
var cset = engineBuilds[e][x];
|
||||
if (cset) {
|
||||
if (fullName == "tracemonkey") {
|
||||
text += "<a href=\"http://hg.mozilla.org/tracemonkey/rev/" + cset +
|
||||
"\">" + cset + "</a>";
|
||||
} else if (fullName == "v8") {
|
||||
text += "<a href=\"http://code.google.com/p/v8/source/detail?r=" + cset +
|
||||
"\">" + cset + "</a>";
|
||||
} else if (fullName == "WebKit") {
|
||||
text += "<a href=\"http://trac.webkit.org/changeset/" + cset +
|
||||
"\">" + cset + "</a>";
|
||||
} else {
|
||||
text += cset;
|
||||
}
|
||||
} else {
|
||||
text += 'unknown';
|
||||
}
|
||||
text += "<br>";
|
||||
var buildTime = runTimes[x];
|
||||
text += "tested: " + buildTime;
|
||||
showToolTip(item.pageX, item.pageY, text);
|
||||
}
|
||||
} else {
|
||||
$("#tooltip").remove();
|
||||
previousPoint = null;
|
||||
}
|
||||
});
|
||||
}
|
||||
var runTimes = [
|
||||
{/literal}
|
||||
{foreach from=$runTimes item=v name=runtimes}
|
||||
'{$v}'{if !$smarty.foreach.runtimes.last},{/if}
|
||||
{/foreach}
|
||||
{literal}
|
||||
];
|
||||
var engineBuilds = {
|
||||
{/literal}
|
||||
{foreach from=$engineBuilds key=k item=v name=emap}
|
||||
{$k}: [ {$v} ]{if !$smarty.foreach.emap.last},{/if}
|
||||
|
||||
{/foreach}
|
||||
{literal}
|
||||
};
|
||||
var engineNames = {/literal}{ $engineMapping }{literal};
|
||||
function drawAllGraphs() {
|
||||
var dsets;
|
||||
|
||||
{/literal}
|
||||
{foreach from=$tests item=test}
|
||||
dsets = [
|
||||
{foreach from=$test.lines item=line}
|
||||
{literal}{{/literal}
|
||||
name: "{$line.name}",
|
||||
data: {$line.data}
|
||||
{literal}}{/literal},
|
||||
{/foreach}
|
||||
];
|
||||
drawGraph($("#graph-{$test.name}"), dsets);
|
||||
{/foreach}
|
||||
{literal}
|
||||
}
|
||||
MochiKit.DOM.addLoadEvent(drawAllGraphs);
|
||||
{/literal}
|
||||
</script>
|
||||
<ul id="links">
|
||||
<li><a href="?machine=5">x86 graphs</a></li>
|
||||
<li><a href="?machine=4">x64 graphs</a></li>
|
||||
<li><a href="?machine=3">ARM graphs</a></li>
|
||||
<li><a href="faq.html">FAQ</a></li>
|
||||
<li><a href="mailto:danderson@mozilla.com">suggestions</a></li>
|
||||
</ul>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<rss version="2.0">
|
||||
<channel>
|
||||
<title>Are We Fast Yet?</title>
|
||||
<link>http://www.arewefastyet.com/</link>
|
||||
<description>Tracks JavaScript performance</description>
|
||||
<language>en-us</language>
|
||||
<pubDate>{$runs[0].date}</pubDate>
|
||||
<lastBuildDate>{$runs[0].date}</lastBuildDate>
|
||||
{foreach from=$runs item=run}
|
||||
<item>
|
||||
<title>{$run.cpu}-{$run.os} cset {$run.cset}</title>
|
||||
<link>http://www.arewefastyet.com/?machine={$run.machine}</link>
|
||||
<pubDate>{$run.date}</pubDate>
|
||||
</item>
|
||||
{/foreach}
|
||||
</channel>
|
||||
</rss>
|
||||
|
|
@ -0,0 +1,59 @@
|
|||
<?php
|
||||
|
||||
require_once("internals.php");
|
||||
|
||||
init_database();
|
||||
|
||||
if (isset($_GET['run']) && $_GET['run'] == 'yes') {
|
||||
$CPU = mysql_real_escape_string(GET_string('CPU'));
|
||||
$OS = mysql_real_escape_string(GET_string('OS'));
|
||||
$MACHINE = GET_int('MACHINE');
|
||||
$CSET = mysql_real_escape_string(GET_string('CSET'));
|
||||
mysql_query("INSERT INTO fast_run (cpu, os, machine, stamp, cset)
|
||||
VALUES
|
||||
('$CPU', '$OS', $MACHINE, UNIX_TIMESTAMP(), '$CSET')")
|
||||
or die("ERROR: " . mysql_error());
|
||||
print("id=" . mysql_insert_id());
|
||||
} else if (isset($_GET['run']) && $_GET['run'] == 'finish') {
|
||||
$runid = GET_int('runid');
|
||||
$status = GET_int('status');
|
||||
if (isset($_GET['error']))
|
||||
$error = '\'' . mysql_real_escape_string(GET_string('error')) . '\'';
|
||||
else
|
||||
$error = 'NULL';
|
||||
mysql_query("UPDATE fast_run
|
||||
SET status = $status,
|
||||
error = $error
|
||||
WHERE id = $runid")
|
||||
or die("ERROR: " . mysql_error());
|
||||
} else if (isset($_GET['run']) && $_GET['run'] == 'addEngine') {
|
||||
$runid = GET_int('runid');
|
||||
$mode_id = find_mode(GET_string('name'));
|
||||
$cset = mysql_real_escape_string(GET_string('cset'));
|
||||
mysql_query("INSERT INTO awfy_build
|
||||
(run_id, mode_id, cset)
|
||||
VALUES
|
||||
($runid, $mode_id, '$cset')")
|
||||
or die("ERROR: " . mysql_error());
|
||||
} else {
|
||||
$name = mysql_real_escape_string(GET_string('name'));
|
||||
$time = mysql_real_escape_string(GET_string('time'));
|
||||
$suite_id = find_suite(GET_string('suite'));
|
||||
$mode_id = find_mode(GET_string('mode'));
|
||||
$run = GET_int('run');
|
||||
if ($name == '__total__') {
|
||||
mysql_query("INSERT INTO awfy_score
|
||||
(run_id, suite_id, mode_id, score)
|
||||
VALUES
|
||||
($run, $suite_id, $mode_id, $time)")
|
||||
or die("ERROR: " . mysql_error());
|
||||
} else {
|
||||
mysql_query("INSERT INTO awfy_breakdown
|
||||
(run_id, suite_id, mode_id, test, score)
|
||||
VALUES
|
||||
($run, $suite_id, $mode_id, '$name', $time)")
|
||||
or die("ERROR: " . mysql_error());
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
Двоичный файл не отображается.
После Ширина: | Высота: | Размер: 1.8 KiB |
|
@ -0,0 +1,228 @@
|
|||
<?php
|
||||
// vim: set ts=4 sw=4 tw=99 et:
|
||||
|
||||
class Context
|
||||
{
|
||||
var $vendors;
|
||||
var $vendorMap_;
|
||||
var $modes;
|
||||
var $modeMap_;
|
||||
var $machine_id;
|
||||
var $run_count;
|
||||
var $view;
|
||||
var $vars;
|
||||
|
||||
function Context() {
|
||||
$this->vendors = array();
|
||||
$this->vendorMap_ = array();
|
||||
|
||||
// Create an array of vendors, and a reverse mapping from DB ids.
|
||||
$query = "SELECT id, name, vendor, csetURL, browser FROM awfy_vendor";
|
||||
$result = awfy_query($query);
|
||||
while (($row = mysql_fetch_assoc($result)) !== FALSE) {
|
||||
$this->vendorMap_[$row['id']] = count($this->vendors);
|
||||
$this->vendors[] = $row;
|
||||
}
|
||||
|
||||
// Create an array of modes, and a reverse mapping from DB ids.
|
||||
$query = "SELECT id, vendor_id, mode, name, color FROM awfy_mode";
|
||||
$result = awfy_query($query);
|
||||
while (($row = mysql_fetch_assoc($result)) !== FALSE) {
|
||||
$this->modeMap_[$row['id']] = count($this->modes);
|
||||
$row['vendor'] = $this->vendorMap_[$row['vendor_id']];
|
||||
$row['used'] = false;
|
||||
$this->modes[] = $row;
|
||||
}
|
||||
|
||||
$this->vars = array();
|
||||
|
||||
$this->machine_id = 9;
|
||||
if (isset($_GET['machine'])) {
|
||||
$this->machine_id = intval($_GET['machine']);
|
||||
$this->vars['machine'] = $this->machine_id;
|
||||
}
|
||||
|
||||
$this->run_count = 32;
|
||||
if (isset($_GET['runs'])) {
|
||||
if (intval($_GET['runs']) > 1) {
|
||||
$this->run_count = intval($_GET['runs']);
|
||||
$this->vars['runs'] = $this->run_count;
|
||||
}
|
||||
}
|
||||
|
||||
$this->view = 'overall';
|
||||
if (isset($_GET['view'])) {
|
||||
$view = $_GET['view'];
|
||||
if ($view == 'breakdown' || $view == 'regress') {
|
||||
$this->view = $view;
|
||||
$this->vars['view'] = $this->view;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function markModeUsed($mode_id) {
|
||||
$mode = $this->modeFromDB($mode_id);
|
||||
$this->modes[$mode]['used'] = true;
|
||||
}
|
||||
|
||||
function url($new_vars) {
|
||||
$r = $this->vars;
|
||||
foreach ($new_vars as $key => $value) {
|
||||
if (!$value)
|
||||
unset($r[$key]);
|
||||
else
|
||||
$r[$key] = $value;
|
||||
}
|
||||
$query = http_build_query($r);
|
||||
if ($query == "")
|
||||
return "?a=b";
|
||||
return '?' . $query;
|
||||
}
|
||||
|
||||
function modeFromDB($mode_id) {
|
||||
return $this->modeMap_[$mode_id];
|
||||
}
|
||||
}
|
||||
|
||||
class RunFilter
|
||||
{
|
||||
var $machine_id;
|
||||
var $run_count;
|
||||
var $suite_id;
|
||||
var $runs;
|
||||
var $runmap;
|
||||
var $idstr;
|
||||
var $modemap;
|
||||
var $series;
|
||||
var $level;
|
||||
|
||||
function RunFilter($cx, $machine_id, $run_count, $suite_id) {
|
||||
$this->machine_id = $machine_id;
|
||||
$this->run_count = $run_count;
|
||||
$this->suite_id = $suite_id;
|
||||
$this->runs = $this->findRuns();
|
||||
$this->level = ($cx->view == 'overall') ? 1 : 10;
|
||||
|
||||
// Get the list of run IDs for this graph.
|
||||
$ids = array();
|
||||
$this->runmap = array();
|
||||
for ($i = 0; $i < count($this->runs); $i++) {
|
||||
$ids[] = $this->runs[$i]['id'];
|
||||
$this->runmap[$this->runs[$i]['id']] = $i;
|
||||
}
|
||||
$this->idstr = implode(',', $ids);
|
||||
|
||||
if (count($ids) == 0)
|
||||
die("unknown machine ID");
|
||||
|
||||
// Find the list of modes that apply to this filter. Note that the
|
||||
// driver guarantees filling awfy_score only iff awfy_breakdown was
|
||||
// filled correctly, so it suffices to only check awfy_score even if
|
||||
// the filter includes a particular test case.
|
||||
$query = "SELECT s.mode_id
|
||||
FROM awfy_score s
|
||||
JOIN awfy_mode m ON s.mode_id = m.id
|
||||
WHERE s.run_id IN (" . $this->idstr . ")
|
||||
AND m.level <= " . $this->level . "
|
||||
AND s.suite_id = " . $this->suite_id . "
|
||||
GROUP BY s.mode_id";
|
||||
$result = awfy_query($query);
|
||||
$this->modemap = array();
|
||||
$this->series = array();
|
||||
while (($row = mysql_fetch_assoc($result)) !== FALSE) {
|
||||
$mode_id = $row['mode_id'];
|
||||
$this->modemap[$mode_id] = count($this->series);
|
||||
$this->series[] = array('mode' => $cx->modeFromDB($mode_id));
|
||||
$cx->markModeUsed($mode_id);
|
||||
}
|
||||
|
||||
// To each series, add a vector that maps run indexes to changeset
|
||||
// information about that series.
|
||||
$query = "SELECT ab.run_id, ab.mode_id, ab.cset
|
||||
FROM awfy_build ab
|
||||
JOIN awfy_mode m ON ab.mode_id = m.id
|
||||
WHERE ab.run_id IN (" . $this->idstr . ")
|
||||
AND m.level <= " . $this->level;
|
||||
$result = awfy_query($query);
|
||||
while (($row = mysql_fetch_assoc($result)) !== FALSE) {
|
||||
$mode_id = $row['mode_id'];
|
||||
$run_id = $row['run_id'];
|
||||
$mode = $this->findSeriesOfMode($mode_id);
|
||||
$run = $this->findRun($run_id);
|
||||
if (!isset($this->modemap[$mode_id]))
|
||||
continue;
|
||||
$this->series[$mode]['csets'][$run] = $row['cset'];
|
||||
}
|
||||
}
|
||||
|
||||
function findSeriesOfMode($mode_id) {
|
||||
return $this->modemap[$mode_id];
|
||||
}
|
||||
|
||||
function findRuns() {
|
||||
$query = "SELECT fr.id, fr.stamp
|
||||
FROM fast_run fr
|
||||
JOIN awfy_score a
|
||||
ON fr.id = a.run_id
|
||||
WHERE fr.machine = " . $this->machine_id . "
|
||||
AND fr.status <> 0
|
||||
GROUP BY fr.id
|
||||
ORDER BY fr.stamp DESC
|
||||
LIMIT " . $this->run_count;
|
||||
$result = awfy_query($query);
|
||||
$rows = array();
|
||||
while (($row = mysql_fetch_assoc($result)) !== FALSE)
|
||||
$rows[] = $row;
|
||||
return array_reverse($rows);
|
||||
}
|
||||
|
||||
function findRun($run_id) {
|
||||
return $this->runmap[$run_id];
|
||||
}
|
||||
|
||||
function FromGET($cx, $suite_id) {
|
||||
$machine_id = $cx->machine_id;
|
||||
$run_count = $cx->run_count;
|
||||
return new RunFilter($cx, $machine_id, $run_count, $suite_id);
|
||||
}
|
||||
}
|
||||
|
||||
class GraphBuilder
|
||||
{
|
||||
var $idstr;
|
||||
var $series;
|
||||
var $runs;
|
||||
|
||||
function GraphBuilder(&$cx, &$filter, $test_name = FALSE) {
|
||||
$this->runs = $filter->runs;
|
||||
|
||||
// PHP arrays are by value, so this is safe.
|
||||
$this->series = $filter->series;
|
||||
|
||||
// Finally, get statistics for this graph.
|
||||
if (!$test_name) {
|
||||
$query = "SELECT s.run_id, s.mode_id, s.score
|
||||
FROM awfy_score s
|
||||
JOIN awfy_mode m ON m.id = s.mode_id
|
||||
WHERE s.suite_id = " . $filter->suite_id . "
|
||||
AND m.level <= " . $filter->level . "
|
||||
AND s.run_id IN (" . $filter->idstr . ")";
|
||||
} else {
|
||||
$query = "SELECT b.run_id, b.mode_id, b.score
|
||||
FROM awfy_breakdown b
|
||||
WHERE b.suite_id = " . $filter->suite_id . "
|
||||
AND b.run_id IN (" . $filter->idstr . ")
|
||||
AND b.test = '" . mysql_real_escape_string($test_name) . "'";
|
||||
}
|
||||
$result = awfy_query($query);
|
||||
while (($row = mysql_fetch_assoc($result)) !== FALSE) {
|
||||
$run_id = $row['run_id'];
|
||||
$mode_id = $row['mode_id'];
|
||||
$mode = $filter->findSeriesOfMode($mode_id);
|
||||
$run = $filter->findRun($run_id);
|
||||
$this->series[$mode]['scores'][$run] = $row['score'];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
|
@ -0,0 +1,62 @@
|
|||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
|
||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<title>AWFY - Frequently Asked Questions</title>
|
||||
<link rel="stylesheet" type="text/css" href="style.css" />
|
||||
</head>
|
||||
<body>
|
||||
<h1>Frequently Asked Questions</h1>
|
||||
<ol id="faq">
|
||||
<li>
|
||||
<p>What's this site?</p>
|
||||
<p>This site tracks the performance of popular JavaScript engines.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>What versions are you testing with?</p>
|
||||
<p>Each test run checks out a copy of the latest source code for each vendor it's testing. This means we're testing the latest, greatest, unstable, bleeding-edge versions of browsers' JS engines. The scores here may not represent what you see in stable releases.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Who's behind it? Is Mozilla?</p>
|
||||
<p>This site is maintained by Mozilla's JavaScript team.</p>
|
||||
Special thanks to wx24 for the new layout, and Michael Clackler for the UI improvements such as hover-tip deltas. Awesome!
|
||||
</li>
|
||||
<li>
|
||||
<p>Why does the v8 benchmark go down, instead of up?</p>
|
||||
<p>The v8 benchmark produces a score, not raw time. We inverted the graph so they all look like "lower is better".</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Why do some changesets appear multiple times?</p>
|
||||
<p>The graphs update on every v8 or tracemonkey check-in, roughly, so if one updates but not the other, the same changeset can be tested twice.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Why isn't Opera/IE/something here?</p>
|
||||
<p>Right now, the performance tests are run on a Mac, which means no IE. Also the tests rely on a "shell" JS engine that runs in a command line. It doesn't test browsers. We'll change that, eventually.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>What are the axes?</p>
|
||||
<p>The Y axis is time to benchmark completion. Lower is better. The X axis represents test runs, chronologically. The left-most run is the oldest, the right-most run is the latest.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>What are the graphs?</p>
|
||||
<p>The top left-hand graph is Mozilla's Kraken benchmark. The top right-hand graph is Apple's SunSpider benchmark. The bottom graph is Google's V8 benchmark suite.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>What do the hover tips mean?</p>
|
||||
<p>"Time" is...time. "Source" is where we got the engine from. "Tested" is when we downloaded the engine, compiled, and tested it. "Rev" is the unique point in the engine's revision history we tested. These numbers/strings are for developers to see which changes happened in between points in the graph.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>What runs the tests?</p>
|
||||
<p>A mac-mini.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>What's ARM?</p>
|
||||
<p>ARM is the CPU present in many embedded devices, like smartphones. We're interested in this for mobile Firefox.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Is this open source?</p>
|
||||
<p>It's not very interesting (or good), but yes: <a href="http://hg.mozilla.org/users/danderson_mozilla.com/awfy">click here</a></p>
|
||||
</li>
|
||||
</ol>
|
||||
</body>
|
||||
</html>
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,71 @@
|
|||
Frequently asked questions
|
||||
--------------------------
|
||||
|
||||
Q: How much data can Flot cope with?
|
||||
|
||||
A: Flot will happily draw everything you send to it so the answer
|
||||
depends on the browser. The excanvas emulation used for IE (built with
|
||||
VML) makes IE by far the slowest browser so be sure to test with that
|
||||
if IE users are in your target group.
|
||||
|
||||
1000 points is not a problem, but as soon as you start having more
|
||||
points than the pixel width, you should probably start thinking about
|
||||
downsampling/aggregation as this is near the resolution limit of the
|
||||
chart anyway. If you downsample server-side, you also save bandwidth.
|
||||
|
||||
|
||||
Q: Flot isn't working when I'm using JSON data as source!
|
||||
|
||||
A: Actually, Flot loves JSON data, you just got the format wrong.
|
||||
Double check that you're not inputting strings instead of numbers,
|
||||
like [["0", "-2.13"], ["5", "4.3"]]. This is most common mistake, and
|
||||
the error might not show up immediately because Javascript can do some
|
||||
conversion automatically.
|
||||
|
||||
|
||||
Q: Can I export the graph?
|
||||
|
||||
A: This is a limitation of the canvas technology. There's a hook in
|
||||
the canvas object for getting an image out, but you won't get the tick
|
||||
labels. And it's not likely to be supported by IE. At this point, your
|
||||
best bet is probably taking a screenshot, e.g. with PrtScn.
|
||||
|
||||
|
||||
Q: The bars are all tiny in time mode?
|
||||
|
||||
A: It's not really possible to determine the bar width automatically.
|
||||
So you have to set the width with the barWidth option which is NOT in
|
||||
pixels, but in the units of the x axis (or the y axis for horizontal
|
||||
bars). For time mode that's milliseconds so the default value of 1
|
||||
makes the bars 1 millisecond wide.
|
||||
|
||||
|
||||
Q: Can I use Flot with libraries like Mootools or Prototype?
|
||||
|
||||
A: Yes, Flot supports it out of the box and it's easy! Just use jQuery
|
||||
instead of $, e.g. call jQuery.plot instead of $.plot and use
|
||||
jQuery(something) instead of $(something). As a convenience, you can
|
||||
put in a DOM element for the graph placeholder where the examples and
|
||||
the API documentation are using jQuery objects.
|
||||
|
||||
Depending on how you include jQuery, you may have to add one line of
|
||||
code to prevent jQuery from overwriting functions from the other
|
||||
libraries, see the documentation in jQuery ("Using jQuery with other
|
||||
libraries") for details.
|
||||
|
||||
|
||||
Q: Flot doesn't work with [widget framework xyz]!
|
||||
|
||||
A: The problem is most likely within the framework, or your use of the
|
||||
framework.
|
||||
|
||||
The only non-standard thing used by Flot is the canvas tag; otherwise
|
||||
it is simply a series of absolute positioned divs within the
|
||||
placeholder tag you put in. If this is not working, it's probably
|
||||
because the framework you're using is doing something weird with the
|
||||
DOM. As a last resort, you might try replotting and see if it helps.
|
||||
|
||||
If you find there's a specific thing we can do to Flot to help, feel
|
||||
free to submit a bug report. Otherwise, you're welcome to ask for help
|
||||
on the mailing list, but please don't submit a bug report to Flot -
|
||||
try the framework instead.
|
|
@ -0,0 +1,22 @@
|
|||
Copyright (c) 2007-2009 IOLA and Ole Laursen
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation
|
||||
files (the "Software"), to deal in the Software without
|
||||
restriction, including without limitation the rights to use,
|
||||
copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following
|
||||
conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
OTHER DEALINGS IN THE SOFTWARE.
|
|
@ -0,0 +1,15 @@
|
|||
# Makefile for generating minified files
|
||||
|
||||
YUICOMPRESSOR_PATH=../yuicompressor-2.3.5.jar
|
||||
|
||||
# if you need another compressor path, just copy the above line to a
|
||||
# file called Makefile.local, customize it and you're good to go
|
||||
-include Makefile.local
|
||||
|
||||
.PHONY: all
|
||||
|
||||
# we cheat and process all .js files instead of listing them
|
||||
all: $(patsubst %.js,%.min.js,$(filter-out %.min.js,$(wildcard *.js)))
|
||||
|
||||
%.min.js: %.js
|
||||
java -jar $(YUICOMPRESSOR_PATH) $< -o $@
|
|
@ -0,0 +1,340 @@
|
|||
Flot 0.6
|
||||
--------
|
||||
|
||||
API changes:
|
||||
|
||||
1. Selection support has been moved to a plugin. Thus if you're
|
||||
passing selection: { mode: something }, you MUST include the file
|
||||
jquery.flot.selection.js after jquery.flot.js. This reduces the size
|
||||
of base Flot and makes it easier to customize the selection as well as
|
||||
improving code clarity. The change is based on patch from andershol.
|
||||
|
||||
2. In the global options specified in the $.plot command,
|
||||
"lines", "points", "bars" and "shadowSize" have been moved to a
|
||||
sub-object called "series", i.e.
|
||||
|
||||
$.plot(placeholder, data, { lines: { show: true }})
|
||||
|
||||
should be changed to
|
||||
|
||||
$.plot(placeholder, data, { series: { lines: { show: true }}})
|
||||
|
||||
All future series-specific options will go into this sub-object to
|
||||
simplify plugin writing. Backward-compatibility code is in place, so
|
||||
old code should not break.
|
||||
|
||||
3. "plothover" no longer provides the original data point, but instead
|
||||
a normalized one, since there may be no corresponding original point.
|
||||
|
||||
4. Due to a bug in previous versions of jQuery, you now need at least
|
||||
jQuery 1.2.6. But if you can, try jQuery 1.3.2 as it got some
|
||||
improvements in event handling speed.
|
||||
|
||||
|
||||
Changes:
|
||||
|
||||
- Added support for disabling interactivity for specific data series
|
||||
(request from Ronald Schouten and Steve Upton).
|
||||
|
||||
- Flot now calls $() on the placeholder and optional legend container
|
||||
passed in so you can specify DOM elements or CSS expressions to make
|
||||
it easier to use Flot with libraries like Prototype or Mootools or
|
||||
through raw JSON from Ajax responses.
|
||||
|
||||
- A new "plotselecting" event is now emitted while the user is making
|
||||
a selection.
|
||||
|
||||
- The "plothover" event is now emitted immediately instead of at most
|
||||
10 times per second, you'll have to put in a setTimeout yourself if
|
||||
you're doing something really expensive on this event.
|
||||
|
||||
- The built-in date formatter can now be accessed as
|
||||
$.plot.formatDate(...) (suggestion by Matt Manela) and even
|
||||
replaced.
|
||||
|
||||
- Added "borderColor" option to the grid (patch from Amaury Chamayou
|
||||
and patch from Mike R. Williamson).
|
||||
|
||||
- Added support for gradient backgrounds for the grid, take a look at
|
||||
the "setting options" example (based on patch from Amaury Chamayou,
|
||||
issue 90).
|
||||
|
||||
- Gradient bars (suggestion by stefpet).
|
||||
|
||||
- Added a "plotunselected" event which is triggered when the selection
|
||||
is removed, see "selection" example (suggestion by Meda Ugo);
|
||||
|
||||
- The option legend.margin can now specify horizontal and vertical
|
||||
margins independently (suggestion by someone who's annoyed).
|
||||
|
||||
- Data passed into Flot is now copied to a new canonical format to
|
||||
enable further processing before it hits the drawing routines. As a
|
||||
side-effect, this should make Flot more robust in the face of bad
|
||||
data (and fixes issue 112).
|
||||
|
||||
- Step-wise charting: line charts have a new option "steps" that when
|
||||
set to true connects the points with horizontal/vertical steps
|
||||
instead of diagonal lines.
|
||||
|
||||
- The legend labelFormatter now passes the series in addition to just
|
||||
the label (suggestion by Vincent Lemeltier).
|
||||
|
||||
- Horizontal bars (based on patch by Jason LeBrun).
|
||||
|
||||
- Support for partial bars by specifying a third coordinate, i.e. they
|
||||
don't have to start from the axis. This can be used to make stacked
|
||||
bars.
|
||||
|
||||
- New option to disable the (grid.show).
|
||||
|
||||
- Added pointOffset method for converting a point in data space to an
|
||||
offset within the placeholder.
|
||||
|
||||
- Plugin system: register an init method in the $.flot.plugins array
|
||||
to get started, see PLUGINS.txt for details on how to write plugins
|
||||
(it's easy). There are also some extra methods to enable access to
|
||||
internal state.
|
||||
|
||||
- Hooks: you can register functions that are called while Flot is
|
||||
crunching the data and doing the plot. This can be used to modify
|
||||
Flot without changing the source, useful for writing plugins. Some
|
||||
hooks are defined, more are likely to come.
|
||||
|
||||
- Threshold plugin: you can set a threshold and a color, and the data
|
||||
points below that threshold will then get the color. Useful for
|
||||
marking data below 0, for instance.
|
||||
|
||||
- Stack plugin: you can specify a stack key for each series to have
|
||||
them summed. This is useful for drawing additive/cumulative graphs
|
||||
with bars and (currently unfilled) lines.
|
||||
|
||||
- Crosshairs plugin: trace the mouse position on the axes, enable with
|
||||
crosshair: { mode: "x"} (see the new tracking example for a use).
|
||||
|
||||
- Image plugin: plot prerendered images.
|
||||
|
||||
- Navigation plugin for panning and zooming a plot.
|
||||
|
||||
- More configurable grid.
|
||||
|
||||
- Axis transformation support, useful for non-linear plots, e.g. log
|
||||
axes and compressed time axes (like omitting weekends).
|
||||
|
||||
- Support for twelve-hour date formatting (patch by Forrest Aldridge).
|
||||
|
||||
- The color parsing code in Flot has been cleaned up and split out so
|
||||
it's now available as a separate jQuery plugin. It's included inline
|
||||
in the Flot source to make dependency managing easier. This also
|
||||
makes it really easy to use the color helpers in Flot plugins.
|
||||
|
||||
Bug fixes:
|
||||
|
||||
- Fixed two corner-case bugs when drawing filled curves (report and
|
||||
analysis by Joshua Varner).
|
||||
- Fix auto-adjustment code when setting min to 0 for an axis where the
|
||||
dataset is completely flat on that axis (report by chovy).
|
||||
- Fixed a bug with passing in data from getData to setData when the
|
||||
secondary axes are used (issue 65, reported by nperelman).
|
||||
- Fixed so that it is possible to turn lines off when no other chart
|
||||
type is shown (based on problem reported by Glenn Vanderburg), and
|
||||
fixed so that setting lineWidth to 0 also hides the shadow (based on
|
||||
problem reported by Sergio Nunes).
|
||||
- Updated mousemove position expression to the latest from jQuery (bug
|
||||
reported by meyuchas).
|
||||
- Use CSS borders instead of background in legend (fix printing issue 25
|
||||
and 45).
|
||||
- Explicitly convert axis min/max to numbers.
|
||||
- Fixed a bug with drawing marking lines with different colors
|
||||
(reported by Khurram).
|
||||
- Fixed a bug with returning y2 values in the selection event (fix
|
||||
by exists, issue 75).
|
||||
- Only set position relative on placeholder if it hasn't already a
|
||||
position different from static (reported by kyberneticist, issue 95).
|
||||
- Don't round markings to prevent sub-pixel problems (reported by Dan
|
||||
Lipsitt).
|
||||
- Make the grid border act similarly to a regular CSS border, i.e.
|
||||
prevent it from overlapping the plot itself. This also fixes a
|
||||
problem with anti-aliasing when the width is 1 pixel (reported by
|
||||
Anthony Ettinger).
|
||||
- Imported version 3 of excanvas and fixed two issues with the newer
|
||||
version. Hopefully, this will make Flot work with IE8 (nudge by
|
||||
Fabien Menager, further analysis by Booink, issue 133).
|
||||
- Changed the shadow code for lines to hopefully look a bit better
|
||||
with vertical lines.
|
||||
- Round tick positions to avoid possible problems with fractions
|
||||
(suggestion by Fred, issue 130).
|
||||
- Made the heuristic for determining how many ticks to aim for a bit
|
||||
smarter.
|
||||
- Fix for uneven axis margins (report and patch by Paul Kienzle) and
|
||||
snapping to ticks (concurrent report and patch by lifthrasiir).
|
||||
- Fixed bug with slicing in findNearbyItems (patch by zollman).
|
||||
- Make heuristic for x axis label widths more dynamic (patch by
|
||||
rickinhethuis).
|
||||
- Make sure points on top take precedence when finding nearby points
|
||||
when hovering (reported by didroe, issue 224).
|
||||
|
||||
Flot 0.5
|
||||
--------
|
||||
|
||||
Backwards API change summary: Timestamps are now in UTC. Also
|
||||
"selected" event -> becomes "plotselected" with new data, the
|
||||
parameters for setSelection are now different (but backwards
|
||||
compatibility hooks are in place), coloredAreas becomes markings with
|
||||
a new interface (but backwards compatibility hooks are in place).
|
||||
|
||||
|
||||
Interactivity: added a new "plothover" event and this and the
|
||||
"plotclick" event now returns the closest data item (based on patch by
|
||||
/david, patch by Mark Byers for bar support). See the revamped
|
||||
"interacting with the data" example for some hints on what you can do.
|
||||
|
||||
Highlighting: you can now highlight points and datapoints are
|
||||
autohighlighted when you hover over them (if hovering is turned on).
|
||||
|
||||
Support for dual axis has been added (based on patch by someone who's
|
||||
annoyed and /david). For each data series you can specify which axes
|
||||
it belongs to, and there are two more axes, x2axis and y2axis, to
|
||||
customize. This affects the "selected" event which has been renamed to
|
||||
"plotselected" and spews out { xaxis: { from: -10, to: 20 } ... },
|
||||
setSelection in which the parameters are on a new form (backwards
|
||||
compatible hooks are in place so old code shouldn't break) and
|
||||
markings (formerly coloredAreas).
|
||||
|
||||
Timestamps in time mode are now displayed according to
|
||||
UTC instead of the time zone of the visitor. This affects the way the
|
||||
timestamps should be input; you'll probably have to offset the
|
||||
timestamps according to your local time zone. It also affects any
|
||||
custom date handling code (which basically now should use the
|
||||
equivalent UTC date mehods, e.g. .setUTCMonth() instead of
|
||||
.setMonth().
|
||||
|
||||
Added support for specifying the size of tick labels (axis.labelWidth,
|
||||
axis.labelHeight). Useful for specifying a max label size to keep
|
||||
multiple plots aligned.
|
||||
|
||||
Markings, previously coloredAreas, are now specified as ranges on the
|
||||
axes, like { xaxis: { from: 0, to: 10 }}. Furthermore with markings
|
||||
you can now draw horizontal/vertical lines by setting from and to to
|
||||
the same coordinate (idea from line support patch by by Ryan Funduk).
|
||||
|
||||
The "fill" option can now be a number that specifies the opacity of
|
||||
the fill.
|
||||
|
||||
You can now specify a coordinate as null (like [2, null]) and Flot
|
||||
will take the other coordinate into account when scaling the axes
|
||||
(based on patch by joebno).
|
||||
|
||||
New option for bars "align". Set it to "center" to center the bars on
|
||||
the value they represent.
|
||||
|
||||
setSelection now takes a second parameter which you can use to prevent
|
||||
the method from firing the "plotselected" handler.
|
||||
|
||||
Using the "container" option in legend now overwrites the container
|
||||
element instead of just appending to it (fixes infinite legend bug,
|
||||
reported by several people, fix by Brad Dewey).
|
||||
|
||||
Fixed a bug in calculating spacing around the plot (reported by
|
||||
timothytoe). Fixed a bug in finding max values for all-negative data
|
||||
sets. Prevent the possibility of eternal looping in tick calculations.
|
||||
Fixed a bug when borderWidth is set to 0 (reported by
|
||||
Rob/sanchothefat). Fixed a bug with drawing bars extending below 0
|
||||
(reported by James Hewitt, patch by Ryan Funduk). Fixed a
|
||||
bug with line widths of bars (reported by MikeM). Fixed a bug with
|
||||
'nw' and 'sw' legend positions. Improved the handling of axis
|
||||
auto-scaling with bars. Fixed a bug with multi-line x-axis tick
|
||||
labels (reported by Luca Ciano). IE-fix help by Savage Zhang.
|
||||
|
||||
|
||||
Flot 0.4
|
||||
--------
|
||||
|
||||
API changes: deprecated axis.noTicks in favor of just specifying the
|
||||
number as axis.ticks. So "xaxis: { noTicks: 10 }" becomes
|
||||
"xaxis: { ticks: 10 }"
|
||||
|
||||
Time series support. Specify axis.mode: "time", put in Javascript
|
||||
timestamps as data, and Flot will automatically spit out sensible
|
||||
ticks. Take a look at the two new examples. The format can be
|
||||
customized with axis.timeformat and axis.monthNames, or if that fails
|
||||
with axis.tickFormatter.
|
||||
|
||||
Support for colored background areas via grid.coloredAreas. Specify an
|
||||
array of { x1, y1, x2, y2 } objects or a function that returns these
|
||||
given { xmin, xmax, ymin, ymax }.
|
||||
|
||||
More members on the plot object (report by Chris Davies and others).
|
||||
"getData" for inspecting the assigned settings on data series (e.g.
|
||||
color) and "setData", "setupGrid" and "draw" for updating the contents
|
||||
without a total replot.
|
||||
|
||||
The default number of ticks to aim for is now dependent on the size of
|
||||
the plot in pixels. Support for customizing tick interval sizes
|
||||
directly with axis.minTickSize and axis.tickSize.
|
||||
|
||||
Cleaned up the automatic axis scaling algorithm and fixed how it
|
||||
interacts with ticks. Also fixed a couple of tick-related corner case
|
||||
bugs (one reported by mainstreetmark, another reported by timothytoe).
|
||||
|
||||
The option axis.tickFormatter now takes a function with two
|
||||
parameters, the second parameter is an optional object with
|
||||
information about the axis. It has min, max, tickDecimals, tickSize.
|
||||
|
||||
Added support for segmented lines (based on patch from Michael
|
||||
MacDonald) and for ignoring null and bad values (suggestion from Nick
|
||||
Konidaris and joshwaihi).
|
||||
|
||||
Added support for changing the border width (joebno and safoo).
|
||||
Label colors can be changed via CSS by selecting the tickLabel class.
|
||||
|
||||
Fixed a bug in handling single-item bar series (reported by Emil
|
||||
Filipov). Fixed erratic behaviour when interacting with the plot
|
||||
with IE 7 (reported by Lau Bech Lauritzen). Prevent IE/Safari text
|
||||
selection when selecting stuff on the canvas.
|
||||
|
||||
|
||||
|
||||
Flot 0.3
|
||||
--------
|
||||
|
||||
This is mostly a quick-fix release because jquery.js wasn't included
|
||||
in the previous zip/tarball.
|
||||
|
||||
Support clicking on the plot. Turn it on with grid: { clickable: true },
|
||||
then you get a "plotclick" event on the graph placeholder with the
|
||||
position in units of the plot.
|
||||
|
||||
Fixed a bug in dealing with data where min = max, thanks to Michael
|
||||
Messinides.
|
||||
|
||||
Include jquery.js in the zip/tarball.
|
||||
|
||||
|
||||
Flot 0.2
|
||||
--------
|
||||
|
||||
Added support for putting a background behind the default legend. The
|
||||
default is the partly transparent background color. Added
|
||||
backgroundColor and backgroundOpacity to the legend options to control
|
||||
this.
|
||||
|
||||
The ticks options can now be a callback function that takes one
|
||||
parameter, an object with the attributes min and max. The function
|
||||
should return a ticks array.
|
||||
|
||||
Added labelFormatter option in legend, useful for turning the legend
|
||||
labels into links.
|
||||
|
||||
Fixed a couple of bugs.
|
||||
|
||||
The API should now be fully documented.
|
||||
|
||||
Patch from Guy Fraser to make parts of the code smaller.
|
||||
|
||||
API changes: Moved labelMargin option to grid from x/yaxis.
|
||||
|
||||
|
||||
Flot 0.1
|
||||
--------
|
||||
|
||||
First public release.
|
|
@ -0,0 +1,105 @@
|
|||
Writing plugins
|
||||
---------------
|
||||
|
||||
To make a new plugin, create an init function and a set of options (if
|
||||
needed), stuff it into an object and put it in the $.plot.plugins
|
||||
array. For example:
|
||||
|
||||
function myCoolPluginInit(plot) { plot.coolstring = "Hello!" };
|
||||
var myCoolOptions = { coolstuff: { show: true } }
|
||||
$.plot.plugins.push({ init: myCoolPluginInit, options: myCoolOptions });
|
||||
|
||||
// now when $.plot is called, the returned object will have the
|
||||
// attribute "coolstring"
|
||||
|
||||
Now, given that the plugin might run in many different places, it's
|
||||
a good idea to avoid leaking names. We can avoid this by wrapping the
|
||||
above lines in an anonymous function which we call immediately, like
|
||||
this: (function () { inner code ... })(). To make it even more robust
|
||||
in case $ is not bound to jQuery but some other Javascript library, we
|
||||
can write it as
|
||||
|
||||
(function ($) {
|
||||
// plugin definition
|
||||
// ...
|
||||
})(jQuery);
|
||||
|
||||
Here is a simple debug plugin which alerts each of the series in the
|
||||
plot. It has a single option that control whether it is enabled and
|
||||
how much info to output:
|
||||
|
||||
(function ($) {
|
||||
function init(plot) {
|
||||
var debugLevel = 1;
|
||||
|
||||
function checkDebugEnabled(plot, options) {
|
||||
if (options.debug) {
|
||||
debugLevel = options.debug;
|
||||
|
||||
plot.hooks.processDatapoints.push(alertSeries);
|
||||
}
|
||||
}
|
||||
|
||||
function alertSeries(plot, series, datapoints) {
|
||||
var msg = "series " + series.label;
|
||||
if (debugLevel > 1)
|
||||
msg += " with " + series.data.length + " points";
|
||||
alert(msg);
|
||||
}
|
||||
|
||||
plot.hooks.processOptions.push(checkDebugEnabled);
|
||||
}
|
||||
|
||||
var options = { debug: 0 };
|
||||
|
||||
$.plot.plugins.push({
|
||||
init: init,
|
||||
options: options,
|
||||
name: "simpledebug",
|
||||
version: "0.1"
|
||||
});
|
||||
})(jQuery);
|
||||
|
||||
We also define "name" and "version". It's not used by Flot, but might
|
||||
be helpful for other plugins in resolving dependencies.
|
||||
|
||||
Put the above in a file named "jquery.flot.debug.js", include it in an
|
||||
HTML page and then it can be used with:
|
||||
|
||||
$.plot($("#placeholder"), [...], { debug: 2 });
|
||||
|
||||
This simple plugin illustrates a couple of points:
|
||||
|
||||
- It uses the anonymous function trick to avoid name pollution.
|
||||
- It can be enabled/disabled through an option.
|
||||
- Variables in the init function can be used to store plot-specific
|
||||
state between the hooks.
|
||||
|
||||
|
||||
Options guidelines
|
||||
==================
|
||||
|
||||
Plugins should always support appropriate options to enable/disable
|
||||
them because the plugin user may have several plots on the same page
|
||||
where only one should use the plugin.
|
||||
|
||||
If the plugin needs series-specific options, you can put them in
|
||||
"series" in the options object, e.g.
|
||||
|
||||
var options = {
|
||||
series: {
|
||||
downsample: {
|
||||
algorithm: null,
|
||||
maxpoints: 1000
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Then they will be copied by Flot into each series, providing the
|
||||
defaults in case the plugin user doesn't specify any. Again, in most
|
||||
cases it's probably a good idea if the plugin is turned off rather
|
||||
than on per default, just like most of the powerful features in Flot.
|
||||
|
||||
Think hard and long about naming the options. These names are going to
|
||||
be public API, and code is going to depend on them if the plugin is
|
||||
successful.
|
|
@ -0,0 +1,81 @@
|
|||
About
|
||||
-----
|
||||
|
||||
Flot is a Javascript plotting library for jQuery. Read more at the
|
||||
website:
|
||||
|
||||
http://code.google.com/p/flot/
|
||||
|
||||
Take a look at the examples linked from above, they should give a good
|
||||
impression of what Flot can do and the source code of the examples is
|
||||
probably the fastest way to learn how to use Flot.
|
||||
|
||||
|
||||
Installation
|
||||
------------
|
||||
|
||||
Just include the Javascript file after you've included jQuery.
|
||||
|
||||
Note that you need to get a version of Excanvas (e.g. the one bundled
|
||||
with Flot) which is canvas emulation on Internet Explorer. You can
|
||||
include the excanvas script like this:
|
||||
|
||||
<!--[if IE]><script language="javascript" type="text/javascript" src="excanvas.pack.js"></script><![endif]-->
|
||||
|
||||
If it's not working on your development IE 6.0, check that it has
|
||||
support for VML which excanvas is relying on. It appears that some
|
||||
stripped down versions used for test environments on virtual machines
|
||||
lack the VML support.
|
||||
|
||||
Also note that you need at least jQuery 1.2.6 (but at least jQuery
|
||||
1.3.2 is recommended for interactive charts because of performance
|
||||
improvements in event handling).
|
||||
|
||||
|
||||
Basic usage
|
||||
-----------
|
||||
|
||||
Create a placeholder div to put the graph in:
|
||||
|
||||
<div id="placeholder"></div>
|
||||
|
||||
You need to set the width and height of this div, otherwise the plot
|
||||
library doesn't know how to scale the graph. You can do it inline like
|
||||
this:
|
||||
|
||||
<div id="placeholder" style="width:600px;height:300px"></div>
|
||||
|
||||
You can also do it with an external stylesheet. Make sure that the
|
||||
placeholder isn't within something with a display:none CSS property -
|
||||
in that case, Flot has trouble measuring label dimensions which
|
||||
results in garbled looks and might have trouble measuring the
|
||||
placeholder dimensions which is fatal (it'll throw an exception).
|
||||
|
||||
Then when the div is ready in the DOM, which is usually on document
|
||||
ready, run the plot function:
|
||||
|
||||
$.plot($("#placeholder"), data, options);
|
||||
|
||||
Here, data is an array of data series and options is an object with
|
||||
settings if you want to customize the plot. Take a look at the
|
||||
examples for some ideas of what to put in or look at the reference
|
||||
in the file "API.txt". Here's a quick example that'll draw a line from
|
||||
(0, 0) to (1, 1):
|
||||
|
||||
$.plot($("#placeholder"), [ [[0, 0], [1, 1]] ], { yaxis: { max: 1 } });
|
||||
|
||||
The plot function immediately draws the chart and then returns a plot
|
||||
object with a couple of methods.
|
||||
|
||||
|
||||
What's with the name?
|
||||
---------------------
|
||||
|
||||
First: it's pronounced with a short o, like "plot". Not like "flawed".
|
||||
|
||||
So "Flot" rhymes with "plot".
|
||||
|
||||
And if you look up "flot" in a Danish-to-English dictionary, some up
|
||||
the words that come up are "good-looking", "attractive", "stylish",
|
||||
"smart", "impressive", "extravagant". One of the main goals with Flot
|
||||
is pretty looks.
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
|
@ -0,0 +1,174 @@
|
|||
/* Plugin for jQuery for working with colors.
|
||||
*
|
||||
* Version 1.0.
|
||||
*
|
||||
* Inspiration from jQuery color animation plugin by John Resig.
|
||||
*
|
||||
* Released under the MIT license by Ole Laursen, October 2009.
|
||||
*
|
||||
* Examples:
|
||||
*
|
||||
* $.color.parse("#fff").scale('rgb', 0.25).add('a', -0.5).toString()
|
||||
* var c = $.color.extract($("#mydiv"), 'background-color');
|
||||
* console.log(c.r, c.g, c.b, c.a);
|
||||
* $.color.make(100, 50, 25, 0.4).toString() // returns "rgba(100,50,25,0.4)"
|
||||
*
|
||||
* Note that .scale() and .add() work in-place instead of returning
|
||||
* new objects.
|
||||
*/
|
||||
|
||||
(function() {
|
||||
jQuery.color = {};
|
||||
|
||||
// construct color object with some convenient chainable helpers
|
||||
jQuery.color.make = function (r, g, b, a) {
|
||||
var o = {};
|
||||
o.r = r || 0;
|
||||
o.g = g || 0;
|
||||
o.b = b || 0;
|
||||
o.a = a != null ? a : 1;
|
||||
|
||||
o.add = function (c, d) {
|
||||
for (var i = 0; i < c.length; ++i)
|
||||
o[c.charAt(i)] += d;
|
||||
return o.normalize();
|
||||
};
|
||||
|
||||
o.scale = function (c, f) {
|
||||
for (var i = 0; i < c.length; ++i)
|
||||
o[c.charAt(i)] *= f;
|
||||
return o.normalize();
|
||||
};
|
||||
|
||||
o.toString = function () {
|
||||
if (o.a >= 1.0) {
|
||||
return "rgb("+[o.r, o.g, o.b].join(",")+")";
|
||||
} else {
|
||||
return "rgba("+[o.r, o.g, o.b, o.a].join(",")+")";
|
||||
}
|
||||
};
|
||||
|
||||
o.normalize = function () {
|
||||
function clamp(min, value, max) {
|
||||
return value < min ? min: (value > max ? max: value);
|
||||
}
|
||||
|
||||
o.r = clamp(0, parseInt(o.r), 255);
|
||||
o.g = clamp(0, parseInt(o.g), 255);
|
||||
o.b = clamp(0, parseInt(o.b), 255);
|
||||
o.a = clamp(0, o.a, 1);
|
||||
return o;
|
||||
};
|
||||
|
||||
o.clone = function () {
|
||||
return jQuery.color.make(o.r, o.b, o.g, o.a);
|
||||
};
|
||||
|
||||
return o.normalize();
|
||||
}
|
||||
|
||||
// extract CSS color property from element, going up in the DOM
|
||||
// if it's "transparent"
|
||||
jQuery.color.extract = function (elem, css) {
|
||||
var c;
|
||||
do {
|
||||
c = elem.css(css).toLowerCase();
|
||||
// keep going until we find an element that has color, or
|
||||
// we hit the body
|
||||
if (c != '' && c != 'transparent')
|
||||
break;
|
||||
elem = elem.parent();
|
||||
} while (!jQuery.nodeName(elem.get(0), "body"));
|
||||
|
||||
// catch Safari's way of signalling transparent
|
||||
if (c == "rgba(0, 0, 0, 0)")
|
||||
c = "transparent";
|
||||
|
||||
return jQuery.color.parse(c);
|
||||
}
|
||||
|
||||
// parse CSS color string (like "rgb(10, 32, 43)" or "#fff"),
|
||||
// returns color object
|
||||
jQuery.color.parse = function (str) {
|
||||
var res, m = jQuery.color.make;
|
||||
|
||||
// Look for rgb(num,num,num)
|
||||
if (res = /rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/.exec(str))
|
||||
return m(parseInt(res[1], 10), parseInt(res[2], 10), parseInt(res[3], 10));
|
||||
|
||||
// Look for rgba(num,num,num,num)
|
||||
if (res = /rgba\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]+(?:\.[0-9]+)?)\s*\)/.exec(str))
|
||||
return m(parseInt(res[1], 10), parseInt(res[2], 10), parseInt(res[3], 10), parseFloat(res[4]));
|
||||
|
||||
// Look for rgb(num%,num%,num%)
|
||||
if (res = /rgb\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*\)/.exec(str))
|
||||
return m(parseFloat(res[1])*2.55, parseFloat(res[2])*2.55, parseFloat(res[3])*2.55);
|
||||
|
||||
// Look for rgba(num%,num%,num%,num)
|
||||
if (res = /rgba\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\s*\)/.exec(str))
|
||||
return m(parseFloat(res[1])*2.55, parseFloat(res[2])*2.55, parseFloat(res[3])*2.55, parseFloat(res[4]));
|
||||
|
||||
// Look for #a0b1c2
|
||||
if (res = /#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(str))
|
||||
return m(parseInt(res[1], 16), parseInt(res[2], 16), parseInt(res[3], 16));
|
||||
|
||||
// Look for #fff
|
||||
if (res = /#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(str))
|
||||
return m(parseInt(res[1]+res[1], 16), parseInt(res[2]+res[2], 16), parseInt(res[3]+res[3], 16));
|
||||
|
||||
// Otherwise, we're most likely dealing with a named color
|
||||
var name = jQuery.trim(str).toLowerCase();
|
||||
if (name == "transparent")
|
||||
return m(255, 255, 255, 0);
|
||||
else {
|
||||
res = lookupColors[name];
|
||||
return m(res[0], res[1], res[2]);
|
||||
}
|
||||
}
|
||||
|
||||
var lookupColors = {
|
||||
aqua:[0,255,255],
|
||||
azure:[240,255,255],
|
||||
beige:[245,245,220],
|
||||
black:[0,0,0],
|
||||
blue:[0,0,255],
|
||||
brown:[165,42,42],
|
||||
cyan:[0,255,255],
|
||||
darkblue:[0,0,139],
|
||||
darkcyan:[0,139,139],
|
||||
darkgrey:[169,169,169],
|
||||
darkgreen:[0,100,0],
|
||||
darkkhaki:[189,183,107],
|
||||
darkmagenta:[139,0,139],
|
||||
darkolivegreen:[85,107,47],
|
||||
darkorange:[255,140,0],
|
||||
darkorchid:[153,50,204],
|
||||
darkred:[139,0,0],
|
||||
darksalmon:[233,150,122],
|
||||
darkviolet:[148,0,211],
|
||||
fuchsia:[255,0,255],
|
||||
gold:[255,215,0],
|
||||
green:[0,128,0],
|
||||
indigo:[75,0,130],
|
||||
khaki:[240,230,140],
|
||||
lightblue:[173,216,230],
|
||||
lightcyan:[224,255,255],
|
||||
lightgreen:[144,238,144],
|
||||
lightgrey:[211,211,211],
|
||||
lightpink:[255,182,193],
|
||||
lightyellow:[255,255,224],
|
||||
lime:[0,255,0],
|
||||
magenta:[255,0,255],
|
||||
maroon:[128,0,0],
|
||||
navy:[0,0,128],
|
||||
olive:[128,128,0],
|
||||
orange:[255,165,0],
|
||||
pink:[255,192,203],
|
||||
purple:[128,0,128],
|
||||
violet:[128,0,128],
|
||||
red:[255,0,0],
|
||||
silver:[192,192,192],
|
||||
white:[255,255,255],
|
||||
yellow:[255,255,0]
|
||||
};
|
||||
})();
|
|
@ -0,0 +1 @@
|
|||
(function(){jQuery.color={};jQuery.color.make=function(E,D,B,C){var F={};F.r=E||0;F.g=D||0;F.b=B||0;F.a=C!=null?C:1;F.add=function(I,H){for(var G=0;G<I.length;++G){F[I.charAt(G)]+=H}return F.normalize()};F.scale=function(I,H){for(var G=0;G<I.length;++G){F[I.charAt(G)]*=H}return F.normalize()};F.toString=function(){if(F.a>=1){return"rgb("+[F.r,F.g,F.b].join(",")+")"}else{return"rgba("+[F.r,F.g,F.b,F.a].join(",")+")"}};F.normalize=function(){function G(I,J,H){return J<I?I:(J>H?H:J)}F.r=G(0,parseInt(F.r),255);F.g=G(0,parseInt(F.g),255);F.b=G(0,parseInt(F.b),255);F.a=G(0,F.a,1);return F};F.clone=function(){return jQuery.color.make(F.r,F.b,F.g,F.a)};return F.normalize()};jQuery.color.extract=function(C,B){var D;do{D=C.css(B).toLowerCase();if(D!=""&&D!="transparent"){break}C=C.parent()}while(!jQuery.nodeName(C.get(0),"body"));if(D=="rgba(0, 0, 0, 0)"){D="transparent"}return jQuery.color.parse(D)};jQuery.color.parse=function(E){var D,B=jQuery.color.make;if(D=/rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/.exec(E)){return B(parseInt(D[1],10),parseInt(D[2],10),parseInt(D[3],10))}if(D=/rgba\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]+(?:\.[0-9]+)?)\s*\)/.exec(E)){return B(parseInt(D[1],10),parseInt(D[2],10),parseInt(D[3],10),parseFloat(D[4]))}if(D=/rgb\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*\)/.exec(E)){return B(parseFloat(D[1])*2.55,parseFloat(D[2])*2.55,parseFloat(D[3])*2.55)}if(D=/rgba\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\s*\)/.exec(E)){return B(parseFloat(D[1])*2.55,parseFloat(D[2])*2.55,parseFloat(D[3])*2.55,parseFloat(D[4]))}if(D=/#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(E)){return B(parseInt(D[1],16),parseInt(D[2],16),parseInt(D[3],16))}if(D=/#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(E)){return B(parseInt(D[1]+D[1],16),parseInt(D[2]+D[2],16),parseInt(D[3]+D[3],16))}var C=jQuery.trim(E).toLowerCase();if(C=="transparent"){return B(255,255,255,0)}else{D=A[C];return B(D[0],D[1],D[2])}};var A={aqua:[0,255,255],azure:[240,255,255],beige:[245,245,220],black:[0,0,0],blue:[0,0,255],brown:[165,42,42],cyan:[0,255,255],darkblue:[0,0,139],darkcyan:[0,139,139],darkgrey:[169,169,169],darkgreen:[0,100,0],darkkhaki:[189,183,107],darkmagenta:[139,0,139],darkolivegreen:[85,107,47],darkorange:[255,140,0],darkorchid:[153,50,204],darkred:[139,0,0],darksalmon:[233,150,122],darkviolet:[148,0,211],fuchsia:[255,0,255],gold:[255,215,0],green:[0,128,0],indigo:[75,0,130],khaki:[240,230,140],lightblue:[173,216,230],lightcyan:[224,255,255],lightgreen:[144,238,144],lightgrey:[211,211,211],lightpink:[255,182,193],lightyellow:[255,255,224],lime:[0,255,0],magenta:[255,0,255],maroon:[128,0,0],navy:[0,0,128],olive:[128,128,0],orange:[255,165,0],pink:[255,192,203],purple:[128,0,128],violet:[128,0,128],red:[255,0,0],silver:[192,192,192],white:[255,255,255],yellow:[255,255,0]}})();
|
|
@ -0,0 +1,156 @@
|
|||
/*
|
||||
Flot plugin for showing a crosshair, thin lines, when the mouse hovers
|
||||
over the plot.
|
||||
|
||||
crosshair: {
|
||||
mode: null or "x" or "y" or "xy"
|
||||
color: color
|
||||
lineWidth: number
|
||||
}
|
||||
|
||||
Set the mode to one of "x", "y" or "xy". The "x" mode enables a
|
||||
vertical crosshair that lets you trace the values on the x axis, "y"
|
||||
enables a horizontal crosshair and "xy" enables them both. "color" is
|
||||
the color of the crosshair (default is "rgba(170, 0, 0, 0.80)"),
|
||||
"lineWidth" is the width of the drawn lines (default is 1).
|
||||
|
||||
The plugin also adds four public methods:
|
||||
|
||||
- setCrosshair(pos)
|
||||
|
||||
Set the position of the crosshair. Note that this is cleared if
|
||||
the user moves the mouse. "pos" should be on the form { x: xpos,
|
||||
y: ypos } (or x2 and y2 if you're using the secondary axes), which
|
||||
is coincidentally the same format as what you get from a "plothover"
|
||||
event. If "pos" is null, the crosshair is cleared.
|
||||
|
||||
- clearCrosshair()
|
||||
|
||||
Clear the crosshair.
|
||||
|
||||
- lockCrosshair(pos)
|
||||
|
||||
Cause the crosshair to lock to the current location, no longer
|
||||
updating if the user moves the mouse. Optionally supply a position
|
||||
(passed on to setCrosshair()) to move it to.
|
||||
|
||||
Example usage:
|
||||
var myFlot = $.plot( $("#graph"), ..., { crosshair: { mode: "x" } } };
|
||||
$("#graph").bind("plothover", function (evt, position, item) {
|
||||
if (item) {
|
||||
// Lock the crosshair to the data point being hovered
|
||||
myFlot.lockCrosshair({ x: item.datapoint[0], y: item.datapoint[1] });
|
||||
}
|
||||
else {
|
||||
// Return normal crosshair operation
|
||||
myFlot.unlockCrosshair();
|
||||
}
|
||||
});
|
||||
|
||||
- unlockCrosshair()
|
||||
|
||||
Free the crosshair to move again after locking it.
|
||||
*/
|
||||
|
||||
(function ($) {
|
||||
var options = {
|
||||
crosshair: {
|
||||
mode: null, // one of null, "x", "y" or "xy",
|
||||
color: "rgba(170, 0, 0, 0.80)",
|
||||
lineWidth: 1
|
||||
}
|
||||
};
|
||||
|
||||
function init(plot) {
|
||||
// position of crosshair in pixels
|
||||
var crosshair = { x: -1, y: -1, locked: false };
|
||||
|
||||
plot.setCrosshair = function setCrosshair(pos) {
|
||||
if (!pos)
|
||||
crosshair.x = -1;
|
||||
else {
|
||||
var axes = plot.getAxes();
|
||||
|
||||
crosshair.x = Math.max(0, Math.min(pos.x != null ? axes.xaxis.p2c(pos.x) : axes.x2axis.p2c(pos.x2), plot.width()));
|
||||
crosshair.y = Math.max(0, Math.min(pos.y != null ? axes.yaxis.p2c(pos.y) : axes.y2axis.p2c(pos.y2), plot.height()));
|
||||
}
|
||||
|
||||
plot.triggerRedrawOverlay();
|
||||
};
|
||||
|
||||
plot.clearCrosshair = plot.setCrosshair; // passes null for pos
|
||||
|
||||
plot.lockCrosshair = function lockCrosshair(pos) {
|
||||
if (pos)
|
||||
plot.setCrosshair(pos);
|
||||
crosshair.locked = true;
|
||||
}
|
||||
|
||||
plot.unlockCrosshair = function unlockCrosshair() {
|
||||
crosshair.locked = false;
|
||||
}
|
||||
|
||||
plot.hooks.bindEvents.push(function (plot, eventHolder) {
|
||||
if (!plot.getOptions().crosshair.mode)
|
||||
return;
|
||||
|
||||
eventHolder.mouseout(function () {
|
||||
if (crosshair.x != -1) {
|
||||
crosshair.x = -1;
|
||||
plot.triggerRedrawOverlay();
|
||||
}
|
||||
});
|
||||
|
||||
eventHolder.mousemove(function (e) {
|
||||
if (plot.getSelection && plot.getSelection()) {
|
||||
crosshair.x = -1; // hide the crosshair while selecting
|
||||
return;
|
||||
}
|
||||
|
||||
if (crosshair.locked)
|
||||
return;
|
||||
|
||||
var offset = plot.offset();
|
||||
crosshair.x = Math.max(0, Math.min(e.pageX - offset.left, plot.width()));
|
||||
crosshair.y = Math.max(0, Math.min(e.pageY - offset.top, plot.height()));
|
||||
plot.triggerRedrawOverlay();
|
||||
});
|
||||
});
|
||||
|
||||
plot.hooks.drawOverlay.push(function (plot, ctx) {
|
||||
var c = plot.getOptions().crosshair;
|
||||
if (!c.mode)
|
||||
return;
|
||||
|
||||
var plotOffset = plot.getPlotOffset();
|
||||
|
||||
ctx.save();
|
||||
ctx.translate(plotOffset.left, plotOffset.top);
|
||||
|
||||
if (crosshair.x != -1) {
|
||||
ctx.strokeStyle = c.color;
|
||||
ctx.lineWidth = c.lineWidth;
|
||||
ctx.lineJoin = "round";
|
||||
|
||||
ctx.beginPath();
|
||||
if (c.mode.indexOf("x") != -1) {
|
||||
ctx.moveTo(crosshair.x, 0);
|
||||
ctx.lineTo(crosshair.x, plot.height());
|
||||
}
|
||||
if (c.mode.indexOf("y") != -1) {
|
||||
ctx.moveTo(0, crosshair.y);
|
||||
ctx.lineTo(plot.width(), crosshair.y);
|
||||
}
|
||||
ctx.stroke();
|
||||
}
|
||||
ctx.restore();
|
||||
});
|
||||
}
|
||||
|
||||
$.plot.plugins.push({
|
||||
init: init,
|
||||
options: options,
|
||||
name: 'crosshair',
|
||||
version: '1.0'
|
||||
});
|
||||
})(jQuery);
|
|
@ -0,0 +1 @@
|
|||
(function(B){var A={crosshair:{mode:null,color:"rgba(170, 0, 0, 0.80)",lineWidth:1}};function C(G){var H={x:-1,y:-1,locked:false};G.setCrosshair=function D(J){if(!J){H.x=-1}else{var I=G.getAxes();H.x=Math.max(0,Math.min(J.x!=null?I.xaxis.p2c(J.x):I.x2axis.p2c(J.x2),G.width()));H.y=Math.max(0,Math.min(J.y!=null?I.yaxis.p2c(J.y):I.y2axis.p2c(J.y2),G.height()))}G.triggerRedrawOverlay()};G.clearCrosshair=G.setCrosshair;G.lockCrosshair=function E(I){if(I){G.setCrosshair(I)}H.locked=true};G.unlockCrosshair=function F(){H.locked=false};G.hooks.bindEvents.push(function(J,I){if(!J.getOptions().crosshair.mode){return }I.mouseout(function(){if(H.x!=-1){H.x=-1;J.triggerRedrawOverlay()}});I.mousemove(function(K){if(J.getSelection&&J.getSelection()){H.x=-1;return }if(H.locked){return }var L=J.offset();H.x=Math.max(0,Math.min(K.pageX-L.left,J.width()));H.y=Math.max(0,Math.min(K.pageY-L.top,J.height()));J.triggerRedrawOverlay()})});G.hooks.drawOverlay.push(function(K,I){var L=K.getOptions().crosshair;if(!L.mode){return }var J=K.getPlotOffset();I.save();I.translate(J.left,J.top);if(H.x!=-1){I.strokeStyle=L.color;I.lineWidth=L.lineWidth;I.lineJoin="round";I.beginPath();if(L.mode.indexOf("x")!=-1){I.moveTo(H.x,0);I.lineTo(H.x,K.height())}if(L.mode.indexOf("y")!=-1){I.moveTo(0,H.y);I.lineTo(K.width(),H.y)}I.stroke()}I.restore()})}B.plot.plugins.push({init:C,options:A,name:"crosshair",version:"1.0"})})(jQuery);
|
|
@ -0,0 +1,237 @@
|
|||
/*
|
||||
Flot plugin for plotting images, e.g. useful for putting ticks on a
|
||||
prerendered complex visualization.
|
||||
|
||||
The data syntax is [[image, x1, y1, x2, y2], ...] where (x1, y1) and
|
||||
(x2, y2) are where you intend the two opposite corners of the image to
|
||||
end up in the plot. Image must be a fully loaded Javascript image (you
|
||||
can make one with new Image()). If the image is not complete, it's
|
||||
skipped when plotting.
|
||||
|
||||
There are two helpers included for retrieving images. The easiest work
|
||||
the way that you put in URLs instead of images in the data (like
|
||||
["myimage.png", 0, 0, 10, 10]), then call $.plot.image.loadData(data,
|
||||
options, callback) where data and options are the same as you pass in
|
||||
to $.plot. This loads the images, replaces the URLs in the data with
|
||||
the corresponding images and calls "callback" when all images are
|
||||
loaded (or failed loading). In the callback, you can then call $.plot
|
||||
with the data set. See the included example.
|
||||
|
||||
A more low-level helper, $.plot.image.load(urls, callback) is also
|
||||
included. Given a list of URLs, it calls callback with an object
|
||||
mapping from URL to Image object when all images are loaded or have
|
||||
failed loading.
|
||||
|
||||
Options for the plugin are
|
||||
|
||||
series: {
|
||||
images: {
|
||||
show: boolean
|
||||
anchor: "corner" or "center"
|
||||
alpha: [0,1]
|
||||
}
|
||||
}
|
||||
|
||||
which can be specified for a specific series
|
||||
|
||||
$.plot($("#placeholder"), [{ data: [ ... ], images: { ... } ])
|
||||
|
||||
Note that because the data format is different from usual data points,
|
||||
you can't use images with anything else in a specific data series.
|
||||
|
||||
Setting "anchor" to "center" causes the pixels in the image to be
|
||||
anchored at the corner pixel centers inside of at the pixel corners,
|
||||
effectively letting half a pixel stick out to each side in the plot.
|
||||
|
||||
|
||||
A possible future direction could be support for tiling for large
|
||||
images (like Google Maps).
|
||||
|
||||
*/
|
||||
|
||||
(function ($) {
|
||||
var options = {
|
||||
series: {
|
||||
images: {
|
||||
show: false,
|
||||
alpha: 1,
|
||||
anchor: "corner" // or "center"
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
$.plot.image = {};
|
||||
|
||||
$.plot.image.loadDataImages = function (series, options, callback) {
|
||||
var urls = [], points = [];
|
||||
|
||||
var defaultShow = options.series.images.show;
|
||||
|
||||
$.each(series, function (i, s) {
|
||||
if (!(defaultShow || s.images.show))
|
||||
return;
|
||||
|
||||
if (s.data)
|
||||
s = s.data;
|
||||
|
||||
$.each(s, function (i, p) {
|
||||
if (typeof p[0] == "string") {
|
||||
urls.push(p[0]);
|
||||
points.push(p);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
$.plot.image.load(urls, function (loadedImages) {
|
||||
$.each(points, function (i, p) {
|
||||
var url = p[0];
|
||||
if (loadedImages[url])
|
||||
p[0] = loadedImages[url];
|
||||
});
|
||||
|
||||
callback();
|
||||
});
|
||||
}
|
||||
|
||||
$.plot.image.load = function (urls, callback) {
|
||||
var missing = urls.length, loaded = {};
|
||||
if (missing == 0)
|
||||
callback({});
|
||||
|
||||
$.each(urls, function (i, url) {
|
||||
var handler = function () {
|
||||
--missing;
|
||||
|
||||
loaded[url] = this;
|
||||
|
||||
if (missing == 0)
|
||||
callback(loaded);
|
||||
};
|
||||
|
||||
$('<img />').load(handler).error(handler).attr('src', url);
|
||||
});
|
||||
}
|
||||
|
||||
function draw(plot, ctx) {
|
||||
var plotOffset = plot.getPlotOffset();
|
||||
|
||||
$.each(plot.getData(), function (i, series) {
|
||||
var points = series.datapoints.points,
|
||||
ps = series.datapoints.pointsize;
|
||||
|
||||
for (var i = 0; i < points.length; i += ps) {
|
||||
var img = points[i],
|
||||
x1 = points[i + 1], y1 = points[i + 2],
|
||||
x2 = points[i + 3], y2 = points[i + 4],
|
||||
xaxis = series.xaxis, yaxis = series.yaxis,
|
||||
tmp;
|
||||
|
||||
// actually we should check img.complete, but it
|
||||
// appears to be a somewhat unreliable indicator in
|
||||
// IE6 (false even after load event)
|
||||
if (!img || img.width <= 0 || img.height <= 0)
|
||||
continue;
|
||||
|
||||
if (x1 > x2) {
|
||||
tmp = x2;
|
||||
x2 = x1;
|
||||
x1 = tmp;
|
||||
}
|
||||
if (y1 > y2) {
|
||||
tmp = y2;
|
||||
y2 = y1;
|
||||
y1 = tmp;
|
||||
}
|
||||
|
||||
// if the anchor is at the center of the pixel, expand the
|
||||
// image by 1/2 pixel in each direction
|
||||
if (series.images.anchor == "center") {
|
||||
tmp = 0.5 * (x2-x1) / (img.width - 1);
|
||||
x1 -= tmp;
|
||||
x2 += tmp;
|
||||
tmp = 0.5 * (y2-y1) / (img.height - 1);
|
||||
y1 -= tmp;
|
||||
y2 += tmp;
|
||||
}
|
||||
|
||||
// clip
|
||||
if (x1 == x2 || y1 == y2 ||
|
||||
x1 >= xaxis.max || x2 <= xaxis.min ||
|
||||
y1 >= yaxis.max || y2 <= yaxis.min)
|
||||
continue;
|
||||
|
||||
var sx1 = 0, sy1 = 0, sx2 = img.width, sy2 = img.height;
|
||||
if (x1 < xaxis.min) {
|
||||
sx1 += (sx2 - sx1) * (xaxis.min - x1) / (x2 - x1);
|
||||
x1 = xaxis.min;
|
||||
}
|
||||
|
||||
if (x2 > xaxis.max) {
|
||||
sx2 += (sx2 - sx1) * (xaxis.max - x2) / (x2 - x1);
|
||||
x2 = xaxis.max;
|
||||
}
|
||||
|
||||
if (y1 < yaxis.min) {
|
||||
sy2 += (sy1 - sy2) * (yaxis.min - y1) / (y2 - y1);
|
||||
y1 = yaxis.min;
|
||||
}
|
||||
|
||||
if (y2 > yaxis.max) {
|
||||
sy1 += (sy1 - sy2) * (yaxis.max - y2) / (y2 - y1);
|
||||
y2 = yaxis.max;
|
||||
}
|
||||
|
||||
x1 = xaxis.p2c(x1);
|
||||
x2 = xaxis.p2c(x2);
|
||||
y1 = yaxis.p2c(y1);
|
||||
y2 = yaxis.p2c(y2);
|
||||
|
||||
// the transformation may have swapped us
|
||||
if (x1 > x2) {
|
||||
tmp = x2;
|
||||
x2 = x1;
|
||||
x1 = tmp;
|
||||
}
|
||||
if (y1 > y2) {
|
||||
tmp = y2;
|
||||
y2 = y1;
|
||||
y1 = tmp;
|
||||
}
|
||||
|
||||
tmp = ctx.globalAlpha;
|
||||
ctx.globalAlpha *= series.images.alpha;
|
||||
ctx.drawImage(img,
|
||||
sx1, sy1, sx2 - sx1, sy2 - sy1,
|
||||
x1 + plotOffset.left, y1 + plotOffset.top,
|
||||
x2 - x1, y2 - y1);
|
||||
ctx.globalAlpha = tmp;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function processRawData(plot, series, data, datapoints) {
|
||||
if (!series.images.show)
|
||||
return;
|
||||
|
||||
// format is Image, x1, y1, x2, y2 (opposite corners)
|
||||
datapoints.format = [
|
||||
{ required: true },
|
||||
{ x: true, number: true, required: true },
|
||||
{ y: true, number: true, required: true },
|
||||
{ x: true, number: true, required: true },
|
||||
{ y: true, number: true, required: true }
|
||||
];
|
||||
}
|
||||
|
||||
function init(plot) {
|
||||
plot.hooks.processRawData.push(processRawData);
|
||||
plot.hooks.draw.push(draw);
|
||||
}
|
||||
|
||||
$.plot.plugins.push({
|
||||
init: init,
|
||||
options: options,
|
||||
name: 'image',
|
||||
version: '1.1'
|
||||
});
|
||||
})(jQuery);
|
|
@ -0,0 +1 @@
|
|||
(function(D){var B={series:{images:{show:false,alpha:1,anchor:"corner"}}};D.plot.image={};D.plot.image.loadDataImages=function(G,F,K){var J=[],H=[];var I=F.series.images.show;D.each(G,function(L,M){if(!(I||M.images.show)){return }if(M.data){M=M.data}D.each(M,function(N,O){if(typeof O[0]=="string"){J.push(O[0]);H.push(O)}})});D.plot.image.load(J,function(L){D.each(H,function(N,O){var M=O[0];if(L[M]){O[0]=L[M]}});K()})};D.plot.image.load=function(H,I){var G=H.length,F={};if(G==0){I({})}D.each(H,function(K,J){var L=function(){--G;F[J]=this;if(G==0){I(F)}};D("<img />").load(L).error(L).attr("src",J)})};function A(H,F){var G=H.getPlotOffset();D.each(H.getData(),function(O,P){var X=P.datapoints.points,I=P.datapoints.pointsize;for(var O=0;O<X.length;O+=I){var Q=X[O],M=X[O+1],V=X[O+2],K=X[O+3],T=X[O+4],W=P.xaxis,S=P.yaxis,N;if(!Q||Q.width<=0||Q.height<=0){continue}if(M>K){N=K;K=M;M=N}if(V>T){N=T;T=V;V=N}if(P.images.anchor=="center"){N=0.5*(K-M)/(Q.width-1);M-=N;K+=N;N=0.5*(T-V)/(Q.height-1);V-=N;T+=N}if(M==K||V==T||M>=W.max||K<=W.min||V>=S.max||T<=S.min){continue}var L=0,U=0,J=Q.width,R=Q.height;if(M<W.min){L+=(J-L)*(W.min-M)/(K-M);M=W.min}if(K>W.max){J+=(J-L)*(W.max-K)/(K-M);K=W.max}if(V<S.min){R+=(U-R)*(S.min-V)/(T-V);V=S.min}if(T>S.max){U+=(U-R)*(S.max-T)/(T-V);T=S.max}M=W.p2c(M);K=W.p2c(K);V=S.p2c(V);T=S.p2c(T);if(M>K){N=K;K=M;M=N}if(V>T){N=T;T=V;V=N}N=F.globalAlpha;F.globalAlpha*=P.images.alpha;F.drawImage(Q,L,U,J-L,R-U,M+G.left,V+G.top,K-M,T-V);F.globalAlpha=N}})}function C(I,F,G,H){if(!F.images.show){return }H.format=[{required:true},{x:true,number:true,required:true},{y:true,number:true,required:true},{x:true,number:true,required:true},{y:true,number:true,required:true}]}function E(F){F.hooks.processRawData.push(C);F.hooks.draw.push(A)}D.plot.plugins.push({init:E,options:B,name:"image",version:"1.1"})})(jQuery);
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
|
@ -0,0 +1,272 @@
|
|||
/*
|
||||
Flot plugin for adding panning and zooming capabilities to a plot.
|
||||
|
||||
The default behaviour is double click and scrollwheel up/down to zoom
|
||||
in, drag to pan. The plugin defines plot.zoom({ center }),
|
||||
plot.zoomOut() and plot.pan(offset) so you easily can add custom
|
||||
controls. It also fires a "plotpan" and "plotzoom" event when
|
||||
something happens, useful for synchronizing plots.
|
||||
|
||||
Example usage:
|
||||
|
||||
plot = $.plot(...);
|
||||
|
||||
// zoom default amount in on the pixel (100, 200)
|
||||
plot.zoom({ center: { left: 10, top: 20 } });
|
||||
|
||||
// zoom out again
|
||||
plot.zoomOut({ center: { left: 10, top: 20 } });
|
||||
|
||||
// pan 100 pixels to the left and 20 down
|
||||
plot.pan({ left: -100, top: 20 })
|
||||
|
||||
|
||||
Options:
|
||||
|
||||
zoom: {
|
||||
interactive: false
|
||||
trigger: "dblclick" // or "click" for single click
|
||||
amount: 1.5 // 2 = 200% (zoom in), 0.5 = 50% (zoom out)
|
||||
}
|
||||
|
||||
pan: {
|
||||
interactive: false
|
||||
}
|
||||
|
||||
xaxis, yaxis, x2axis, y2axis: {
|
||||
zoomRange: null // or [number, number] (min range, max range)
|
||||
panRange: null // or [number, number] (min, max)
|
||||
}
|
||||
|
||||
"interactive" enables the built-in drag/click behaviour. "amount" is
|
||||
the amount to zoom the viewport relative to the current range, so 1 is
|
||||
100% (i.e. no change), 1.5 is 150% (zoom in), 0.7 is 70% (zoom out).
|
||||
|
||||
"zoomRange" is the interval in which zooming can happen, e.g. with
|
||||
zoomRange: [1, 100] the zoom will never scale the axis so that the
|
||||
difference between min and max is smaller than 1 or larger than 100.
|
||||
You can set either of them to null to ignore.
|
||||
|
||||
"panRange" confines the panning to stay within a range, e.g. with
|
||||
panRange: [-10, 20] panning stops at -10 in one end and at 20 in the
|
||||
other. Either can be null.
|
||||
*/
|
||||
|
||||
|
||||
// First two dependencies, jquery.event.drag.js and
|
||||
// jquery.mousewheel.js, we put them inline here to save people the
|
||||
// effort of downloading them.
|
||||
|
||||
/*
|
||||
jquery.event.drag.js ~ v1.5 ~ Copyright (c) 2008, Three Dub Media (http://threedubmedia.com)
|
||||
Licensed under the MIT License ~ http://threedubmedia.googlecode.com/files/MIT-LICENSE.txt
|
||||
*/
|
||||
(function(E){E.fn.drag=function(L,K,J){if(K){this.bind("dragstart",L)}if(J){this.bind("dragend",J)}return !L?this.trigger("drag"):this.bind("drag",K?K:L)};var A=E.event,B=A.special,F=B.drag={not:":input",distance:0,which:1,dragging:false,setup:function(J){J=E.extend({distance:F.distance,which:F.which,not:F.not},J||{});J.distance=I(J.distance);A.add(this,"mousedown",H,J);if(this.attachEvent){this.attachEvent("ondragstart",D)}},teardown:function(){A.remove(this,"mousedown",H);if(this===F.dragging){F.dragging=F.proxy=false}G(this,true);if(this.detachEvent){this.detachEvent("ondragstart",D)}}};B.dragstart=B.dragend={setup:function(){},teardown:function(){}};function H(L){var K=this,J,M=L.data||{};if(M.elem){K=L.dragTarget=M.elem;L.dragProxy=F.proxy||K;L.cursorOffsetX=M.pageX-M.left;L.cursorOffsetY=M.pageY-M.top;L.offsetX=L.pageX-L.cursorOffsetX;L.offsetY=L.pageY-L.cursorOffsetY}else{if(F.dragging||(M.which>0&&L.which!=M.which)||E(L.target).is(M.not)){return }}switch(L.type){case"mousedown":E.extend(M,E(K).offset(),{elem:K,target:L.target,pageX:L.pageX,pageY:L.pageY});A.add(document,"mousemove mouseup",H,M);G(K,false);F.dragging=null;return false;case !F.dragging&&"mousemove":if(I(L.pageX-M.pageX)+I(L.pageY-M.pageY)<M.distance){break}L.target=M.target;J=C(L,"dragstart",K);if(J!==false){F.dragging=K;F.proxy=L.dragProxy=E(J||K)[0]}case"mousemove":if(F.dragging){J=C(L,"drag",K);if(B.drop){B.drop.allowed=(J!==false);B.drop.handler(L)}if(J!==false){break}L.type="mouseup"}case"mouseup":A.remove(document,"mousemove mouseup",H);if(F.dragging){if(B.drop){B.drop.handler(L)}C(L,"dragend",K)}G(K,true);F.dragging=F.proxy=M.elem=false;break}return true}function C(M,K,L){M.type=K;var J=E.event.handle.call(L,M);return J===false?false:J||M.result}function I(J){return Math.pow(J,2)}function D(){return(F.dragging===false)}function G(K,J){if(!K){return }K.unselectable=J?"off":"on";K.onselectstart=function(){return J};if(K.style){K.style.MozUserSelect=J?"":"none"}}})(jQuery);
|
||||
|
||||
|
||||
/* jquery.mousewheel.min.js
|
||||
* Copyright (c) 2009 Brandon Aaron (http://brandonaaron.net)
|
||||
* Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php)
|
||||
* and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses.
|
||||
* Thanks to: http://adomas.org/javascript-mouse-wheel/ for some pointers.
|
||||
* Thanks to: Mathias Bank(http://www.mathias-bank.de) for a scope bug fix.
|
||||
*
|
||||
* Version: 3.0.2
|
||||
*
|
||||
* Requires: 1.2.2+
|
||||
*/
|
||||
(function(c){var a=["DOMMouseScroll","mousewheel"];c.event.special.mousewheel={setup:function(){if(this.addEventListener){for(var d=a.length;d;){this.addEventListener(a[--d],b,false)}}else{this.onmousewheel=b}},teardown:function(){if(this.removeEventListener){for(var d=a.length;d;){this.removeEventListener(a[--d],b,false)}}else{this.onmousewheel=null}}};c.fn.extend({mousewheel:function(d){return d?this.bind("mousewheel",d):this.trigger("mousewheel")},unmousewheel:function(d){return this.unbind("mousewheel",d)}});function b(f){var d=[].slice.call(arguments,1),g=0,e=true;f=c.event.fix(f||window.event);f.type="mousewheel";if(f.wheelDelta){g=f.wheelDelta/120}if(f.detail){g=-f.detail/3}d.unshift(f,g);return c.event.handle.apply(this,d)}})(jQuery);
|
||||
|
||||
|
||||
|
||||
|
||||
(function ($) {
|
||||
var options = {
|
||||
xaxis: {
|
||||
zoomRange: null, // or [number, number] (min range, max range)
|
||||
panRange: null // or [number, number] (min, max)
|
||||
},
|
||||
zoom: {
|
||||
interactive: false,
|
||||
trigger: "dblclick", // or "click" for single click
|
||||
amount: 1.5 // how much to zoom relative to current position, 2 = 200% (zoom in), 0.5 = 50% (zoom out)
|
||||
},
|
||||
pan: {
|
||||
interactive: false
|
||||
}
|
||||
};
|
||||
|
||||
function init(plot) {
|
||||
function bindEvents(plot, eventHolder) {
|
||||
var o = plot.getOptions();
|
||||
if (o.zoom.interactive) {
|
||||
function clickHandler(e, zoomOut) {
|
||||
var c = plot.offset();
|
||||
c.left = e.pageX - c.left;
|
||||
c.top = e.pageY - c.top;
|
||||
if (zoomOut)
|
||||
plot.zoomOut({ center: c });
|
||||
else
|
||||
plot.zoom({ center: c });
|
||||
}
|
||||
|
||||
eventHolder[o.zoom.trigger](clickHandler);
|
||||
|
||||
eventHolder.mousewheel(function (e, delta) {
|
||||
clickHandler(e, delta < 0);
|
||||
return false;
|
||||
});
|
||||
}
|
||||
if (o.pan.interactive) {
|
||||
var prevCursor = 'default', pageX = 0, pageY = 0;
|
||||
|
||||
eventHolder.bind("dragstart", { distance: 10 }, function (e) {
|
||||
if (e.which != 1) // only accept left-click
|
||||
return false;
|
||||
eventHolderCursor = eventHolder.css('cursor');
|
||||
eventHolder.css('cursor', 'move');
|
||||
pageX = e.pageX;
|
||||
pageY = e.pageY;
|
||||
});
|
||||
eventHolder.bind("drag", function (e) {
|
||||
// unused at the moment, but we need it here to
|
||||
// trigger the dragstart/dragend events
|
||||
});
|
||||
eventHolder.bind("dragend", function (e) {
|
||||
eventHolder.css('cursor', prevCursor);
|
||||
plot.pan({ left: pageX - e.pageX,
|
||||
top: pageY - e.pageY });
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
plot.zoomOut = function (args) {
|
||||
if (!args)
|
||||
args = {};
|
||||
|
||||
if (!args.amount)
|
||||
args.amount = plot.getOptions().zoom.amount
|
||||
|
||||
args.amount = 1 / args.amount;
|
||||
plot.zoom(args);
|
||||
}
|
||||
|
||||
plot.zoom = function (args) {
|
||||
if (!args)
|
||||
args = {};
|
||||
|
||||
var axes = plot.getAxes(),
|
||||
options = plot.getOptions(),
|
||||
c = args.center,
|
||||
amount = args.amount ? args.amount : options.zoom.amount,
|
||||
w = plot.width(), h = plot.height();
|
||||
|
||||
if (!c)
|
||||
c = { left: w / 2, top: h / 2 };
|
||||
|
||||
var xf = c.left / w,
|
||||
x1 = c.left - xf * w / amount,
|
||||
x2 = c.left + (1 - xf) * w / amount,
|
||||
yf = c.top / h,
|
||||
y1 = c.top - yf * h / amount,
|
||||
y2 = c.top + (1 - yf) * h / amount;
|
||||
|
||||
function scaleAxis(min, max, name) {
|
||||
var axis = axes[name],
|
||||
axisOptions = options[name];
|
||||
|
||||
if (!axis.used)
|
||||
return;
|
||||
|
||||
min = axis.c2p(min);
|
||||
max = axis.c2p(max);
|
||||
if (max < min) { // make sure min < max
|
||||
var tmp = min
|
||||
min = max;
|
||||
max = tmp;
|
||||
}
|
||||
|
||||
var range = max - min, zr = axisOptions.zoomRange;
|
||||
if (zr &&
|
||||
((zr[0] != null && range < zr[0]) ||
|
||||
(zr[1] != null && range > zr[1])))
|
||||
return;
|
||||
|
||||
axisOptions.min = min;
|
||||
axisOptions.max = max;
|
||||
}
|
||||
|
||||
scaleAxis(x1, x2, 'xaxis');
|
||||
scaleAxis(x1, x2, 'x2axis');
|
||||
scaleAxis(y1, y2, 'yaxis');
|
||||
scaleAxis(y1, y2, 'y2axis');
|
||||
|
||||
plot.setupGrid();
|
||||
plot.draw();
|
||||
|
||||
if (!args.preventEvent)
|
||||
plot.getPlaceholder().trigger("plotzoom", [ plot ]);
|
||||
}
|
||||
|
||||
plot.pan = function (args) {
|
||||
var l = +args.left, t = +args.top,
|
||||
axes = plot.getAxes(), options = plot.getOptions();
|
||||
|
||||
if (isNaN(l))
|
||||
l = 0;
|
||||
if (isNaN(t))
|
||||
t = 0;
|
||||
|
||||
function panAxis(delta, name) {
|
||||
var axis = axes[name],
|
||||
axisOptions = options[name],
|
||||
min, max;
|
||||
|
||||
if (!axis.used)
|
||||
return;
|
||||
|
||||
min = axis.c2p(axis.p2c(axis.min) + delta),
|
||||
max = axis.c2p(axis.p2c(axis.max) + delta);
|
||||
|
||||
var pr = axisOptions.panRange;
|
||||
if (pr) {
|
||||
// check whether we hit the wall
|
||||
if (pr[0] != null && pr[0] > min) {
|
||||
delta = pr[0] - min;
|
||||
min += delta;
|
||||
max += delta;
|
||||
}
|
||||
|
||||
if (pr[1] != null && pr[1] < max) {
|
||||
delta = pr[1] - max;
|
||||
min += delta;
|
||||
max += delta;
|
||||
}
|
||||
}
|
||||
|
||||
axisOptions.min = min;
|
||||
axisOptions.max = max;
|
||||
}
|
||||
|
||||
panAxis(l, 'xaxis');
|
||||
panAxis(l, 'x2axis');
|
||||
panAxis(t, 'yaxis');
|
||||
panAxis(t, 'y2axis');
|
||||
|
||||
plot.setupGrid();
|
||||
plot.draw();
|
||||
|
||||
if (!args.preventEvent)
|
||||
plot.getPlaceholder().trigger("plotpan", [ plot ]);
|
||||
}
|
||||
|
||||
plot.hooks.bindEvents.push(bindEvents);
|
||||
}
|
||||
|
||||
$.plot.plugins.push({
|
||||
init: init,
|
||||
options: options,
|
||||
name: 'navigate',
|
||||
version: '1.1'
|
||||
});
|
||||
})(jQuery);
|
|
@ -0,0 +1 @@
|
|||
(function(R){R.fn.drag=function(A,B,C){if(B){this.bind("dragstart",A)}if(C){this.bind("dragend",C)}return !A?this.trigger("drag"):this.bind("drag",B?B:A)};var M=R.event,L=M.special,Q=L.drag={not:":input",distance:0,which:1,dragging:false,setup:function(A){A=R.extend({distance:Q.distance,which:Q.which,not:Q.not},A||{});A.distance=N(A.distance);M.add(this,"mousedown",O,A);if(this.attachEvent){this.attachEvent("ondragstart",J)}},teardown:function(){M.remove(this,"mousedown",O);if(this===Q.dragging){Q.dragging=Q.proxy=false}P(this,true);if(this.detachEvent){this.detachEvent("ondragstart",J)}}};L.dragstart=L.dragend={setup:function(){},teardown:function(){}};function O(A){var B=this,C,D=A.data||{};if(D.elem){B=A.dragTarget=D.elem;A.dragProxy=Q.proxy||B;A.cursorOffsetX=D.pageX-D.left;A.cursorOffsetY=D.pageY-D.top;A.offsetX=A.pageX-A.cursorOffsetX;A.offsetY=A.pageY-A.cursorOffsetY}else{if(Q.dragging||(D.which>0&&A.which!=D.which)||R(A.target).is(D.not)){return }}switch(A.type){case"mousedown":R.extend(D,R(B).offset(),{elem:B,target:A.target,pageX:A.pageX,pageY:A.pageY});M.add(document,"mousemove mouseup",O,D);P(B,false);Q.dragging=null;return false;case !Q.dragging&&"mousemove":if(N(A.pageX-D.pageX)+N(A.pageY-D.pageY)<D.distance){break}A.target=D.target;C=K(A,"dragstart",B);if(C!==false){Q.dragging=B;Q.proxy=A.dragProxy=R(C||B)[0]}case"mousemove":if(Q.dragging){C=K(A,"drag",B);if(L.drop){L.drop.allowed=(C!==false);L.drop.handler(A)}if(C!==false){break}A.type="mouseup"}case"mouseup":M.remove(document,"mousemove mouseup",O);if(Q.dragging){if(L.drop){L.drop.handler(A)}K(A,"dragend",B)}P(B,true);Q.dragging=Q.proxy=D.elem=false;break}return true}function K(D,B,A){D.type=B;var C=R.event.handle.call(A,D);return C===false?false:C||D.result}function N(A){return Math.pow(A,2)}function J(){return(Q.dragging===false)}function P(A,B){if(!A){return }A.unselectable=B?"off":"on";A.onselectstart=function(){return B};if(A.style){A.style.MozUserSelect=B?"":"none"}}})(jQuery);(function(C){var B=["DOMMouseScroll","mousewheel"];C.event.special.mousewheel={setup:function(){if(this.addEventListener){for(var D=B.length;D;){this.addEventListener(B[--D],A,false)}}else{this.onmousewheel=A}},teardown:function(){if(this.removeEventListener){for(var D=B.length;D;){this.removeEventListener(B[--D],A,false)}}else{this.onmousewheel=null}}};C.fn.extend({mousewheel:function(D){return D?this.bind("mousewheel",D):this.trigger("mousewheel")},unmousewheel:function(D){return this.unbind("mousewheel",D)}});function A(E){var G=[].slice.call(arguments,1),D=0,F=true;E=C.event.fix(E||window.event);E.type="mousewheel";if(E.wheelDelta){D=E.wheelDelta/120}if(E.detail){D=-E.detail/3}G.unshift(E,D);return C.event.handle.apply(this,G)}})(jQuery);(function(B){var A={xaxis:{zoomRange:null,panRange:null},zoom:{interactive:false,trigger:"dblclick",amount:1.5},pan:{interactive:false}};function C(D){function E(J,F){var K=J.getOptions();if(K.zoom.interactive){function L(N,M){var O=J.offset();O.left=N.pageX-O.left;O.top=N.pageY-O.top;if(M){J.zoomOut({center:O})}else{J.zoom({center:O})}}F[K.zoom.trigger](L);F.mousewheel(function(M,N){L(M,N<0);return false})}if(K.pan.interactive){var I="default",H=0,G=0;F.bind("dragstart",{distance:10},function(M){if(M.which!=1){return false}eventHolderCursor=F.css("cursor");F.css("cursor","move");H=M.pageX;G=M.pageY});F.bind("drag",function(M){});F.bind("dragend",function(M){F.css("cursor",I);J.pan({left:H-M.pageX,top:G-M.pageY})})}}D.zoomOut=function(F){if(!F){F={}}if(!F.amount){F.amount=D.getOptions().zoom.amount}F.amount=1/F.amount;D.zoom(F)};D.zoom=function(M){if(!M){M={}}var L=D.getAxes(),S=D.getOptions(),N=M.center,J=M.amount?M.amount:S.zoom.amount,R=D.width(),I=D.height();if(!N){N={left:R/2,top:I/2}}var Q=N.left/R,G=N.left-Q*R/J,F=N.left+(1-Q)*R/J,H=N.top/I,P=N.top-H*I/J,O=N.top+(1-H)*I/J;function K(X,T,V){var Y=L[V],a=S[V];if(!Y.used){return }X=Y.c2p(X);T=Y.c2p(T);if(T<X){var W=X;X=T;T=W}var U=T-X,Z=a.zoomRange;if(Z&&((Z[0]!=null&&U<Z[0])||(Z[1]!=null&&U>Z[1]))){return }a.min=X;a.max=T}K(G,F,"xaxis");K(G,F,"x2axis");K(P,O,"yaxis");K(P,O,"y2axis");D.setupGrid();D.draw();if(!M.preventEvent){D.getPlaceholder().trigger("plotzoom",[D])}};D.pan=function(I){var F=+I.left,J=+I.top,K=D.getAxes(),H=D.getOptions();if(isNaN(F)){F=0}if(isNaN(J)){J=0}function G(R,M){var O=K[M],Q=H[M],N,L;if(!O.used){return }N=O.c2p(O.p2c(O.min)+R),L=O.c2p(O.p2c(O.max)+R);var P=Q.panRange;if(P){if(P[0]!=null&&P[0]>N){R=P[0]-N;N+=R;L+=R}if(P[1]!=null&&P[1]<L){R=P[1]-L;N+=R;L+=R}}Q.min=N;Q.max=L}G(F,"xaxis");G(F,"x2axis");G(J,"yaxis");G(J,"y2axis");D.setupGrid();D.draw();if(!I.preventEvent){D.getPlaceholder().trigger("plotpan",[D])}};D.hooks.bindEvents.push(E)}B.plot.plugins.push({init:C,options:A,name:"navigate",version:"1.1"})})(jQuery);
|
|
@ -0,0 +1,299 @@
|
|||
/*
|
||||
Flot plugin for selecting regions.
|
||||
|
||||
The plugin defines the following options:
|
||||
|
||||
selection: {
|
||||
mode: null or "x" or "y" or "xy",
|
||||
color: color
|
||||
}
|
||||
|
||||
You enable selection support by setting the mode to one of "x", "y" or
|
||||
"xy". In "x" mode, the user will only be able to specify the x range,
|
||||
similarly for "y" mode. For "xy", the selection becomes a rectangle
|
||||
where both ranges can be specified. "color" is color of the selection.
|
||||
|
||||
When selection support is enabled, a "plotselected" event will be emitted
|
||||
on the DOM element you passed into the plot function. The event
|
||||
handler gets one extra parameter with the ranges selected on the axes,
|
||||
like this:
|
||||
|
||||
placeholder.bind("plotselected", function(event, ranges) {
|
||||
alert("You selected " + ranges.xaxis.from + " to " + ranges.xaxis.to)
|
||||
// similar for yaxis, secondary axes are in x2axis
|
||||
// and y2axis if present
|
||||
});
|
||||
|
||||
The "plotselected" event is only fired when the user has finished
|
||||
making the selection. A "plotselecting" event is fired during the
|
||||
process with the same parameters as the "plotselected" event, in case
|
||||
you want to know what's happening while it's happening,
|
||||
|
||||
A "plotunselected" event with no arguments is emitted when the user
|
||||
clicks the mouse to remove the selection.
|
||||
|
||||
The plugin allso adds the following methods to the plot object:
|
||||
|
||||
- setSelection(ranges, preventEvent)
|
||||
|
||||
Set the selection rectangle. The passed in ranges is on the same
|
||||
form as returned in the "plotselected" event. If the selection
|
||||
mode is "x", you should put in either an xaxis (or x2axis) object,
|
||||
if the mode is "y" you need to put in an yaxis (or y2axis) object
|
||||
and both xaxis/x2axis and yaxis/y2axis if the selection mode is
|
||||
"xy", like this:
|
||||
|
||||
setSelection({ xaxis: { from: 0, to: 10 }, yaxis: { from: 40, to: 60 } });
|
||||
|
||||
setSelection will trigger the "plotselected" event when called. If
|
||||
you don't want that to happen, e.g. if you're inside a
|
||||
"plotselected" handler, pass true as the second parameter.
|
||||
|
||||
- clearSelection(preventEvent)
|
||||
|
||||
Clear the selection rectangle. Pass in true to avoid getting a
|
||||
"plotunselected" event.
|
||||
|
||||
- getSelection()
|
||||
|
||||
Returns the current selection in the same format as the
|
||||
"plotselected" event. If there's currently no selection, the
|
||||
function returns null.
|
||||
|
||||
*/
|
||||
|
||||
(function ($) {
|
||||
function init(plot) {
|
||||
var selection = {
|
||||
first: { x: -1, y: -1}, second: { x: -1, y: -1},
|
||||
show: false,
|
||||
active: false
|
||||
};
|
||||
|
||||
// FIXME: The drag handling implemented here should be
|
||||
// abstracted out, there's some similar code from a library in
|
||||
// the navigation plugin, this should be massaged a bit to fit
|
||||
// the Flot cases here better and reused. Doing this would
|
||||
// make this plugin much slimmer.
|
||||
var savedhandlers = {};
|
||||
|
||||
function onMouseMove(e) {
|
||||
if (selection.active) {
|
||||
plot.getPlaceholder().trigger("plotselecting", [ getSelection() ]);
|
||||
|
||||
updateSelection(e);
|
||||
}
|
||||
}
|
||||
|
||||
function onMouseDown(e) {
|
||||
if (e.which != 1) // only accept left-click
|
||||
return;
|
||||
|
||||
// cancel out any text selections
|
||||
document.body.focus();
|
||||
|
||||
// prevent text selection and drag in old-school browsers
|
||||
if (document.onselectstart !== undefined && savedhandlers.onselectstart == null) {
|
||||
savedhandlers.onselectstart = document.onselectstart;
|
||||
document.onselectstart = function () { return false; };
|
||||
}
|
||||
if (document.ondrag !== undefined && savedhandlers.ondrag == null) {
|
||||
savedhandlers.ondrag = document.ondrag;
|
||||
document.ondrag = function () { return false; };
|
||||
}
|
||||
|
||||
setSelectionPos(selection.first, e);
|
||||
|
||||
selection.active = true;
|
||||
|
||||
$(document).one("mouseup", onMouseUp);
|
||||
}
|
||||
|
||||
function onMouseUp(e) {
|
||||
// revert drag stuff for old-school browsers
|
||||
if (document.onselectstart !== undefined)
|
||||
document.onselectstart = savedhandlers.onselectstart;
|
||||
if (document.ondrag !== undefined)
|
||||
document.ondrag = savedhandlers.ondrag;
|
||||
|
||||
// no more draggy-dee-drag
|
||||
selection.active = false;
|
||||
updateSelection(e);
|
||||
|
||||
if (selectionIsSane())
|
||||
triggerSelectedEvent();
|
||||
else {
|
||||
// this counts as a clear
|
||||
plot.getPlaceholder().trigger("plotunselected", [ ]);
|
||||
plot.getPlaceholder().trigger("plotselecting", [ null ]);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function getSelection() {
|
||||
if (!selectionIsSane())
|
||||
return null;
|
||||
|
||||
var x1 = Math.min(selection.first.x, selection.second.x),
|
||||
x2 = Math.max(selection.first.x, selection.second.x),
|
||||
y1 = Math.max(selection.first.y, selection.second.y),
|
||||
y2 = Math.min(selection.first.y, selection.second.y);
|
||||
|
||||
var r = {};
|
||||
var axes = plot.getAxes();
|
||||
if (axes.xaxis.used)
|
||||
r.xaxis = { from: axes.xaxis.c2p(x1), to: axes.xaxis.c2p(x2) };
|
||||
if (axes.x2axis.used)
|
||||
r.x2axis = { from: axes.x2axis.c2p(x1), to: axes.x2axis.c2p(x2) };
|
||||
if (axes.yaxis.used)
|
||||
r.yaxis = { from: axes.yaxis.c2p(y1), to: axes.yaxis.c2p(y2) };
|
||||
if (axes.y2axis.used)
|
||||
r.y2axis = { from: axes.y2axis.c2p(y1), to: axes.y2axis.c2p(y2) };
|
||||
return r;
|
||||
}
|
||||
|
||||
function triggerSelectedEvent() {
|
||||
var r = getSelection();
|
||||
|
||||
plot.getPlaceholder().trigger("plotselected", [ r ]);
|
||||
|
||||
// backwards-compat stuff, to be removed in future
|
||||
var axes = plot.getAxes();
|
||||
if (axes.xaxis.used && axes.yaxis.used)
|
||||
plot.getPlaceholder().trigger("selected", [ { x1: r.xaxis.from, y1: r.yaxis.from, x2: r.xaxis.to, y2: r.yaxis.to } ]);
|
||||
}
|
||||
|
||||
function clamp(min, value, max) {
|
||||
return value < min? min: (value > max? max: value);
|
||||
}
|
||||
|
||||
function setSelectionPos(pos, e) {
|
||||
var o = plot.getOptions();
|
||||
var offset = plot.getPlaceholder().offset();
|
||||
var plotOffset = plot.getPlotOffset();
|
||||
pos.x = clamp(0, e.pageX - offset.left - plotOffset.left, plot.width());
|
||||
pos.y = clamp(0, e.pageY - offset.top - plotOffset.top, plot.height());
|
||||
|
||||
if (o.selection.mode == "y")
|
||||
pos.x = pos == selection.first? 0: plot.width();
|
||||
|
||||
if (o.selection.mode == "x")
|
||||
pos.y = pos == selection.first? 0: plot.height();
|
||||
}
|
||||
|
||||
function updateSelection(pos) {
|
||||
if (pos.pageX == null)
|
||||
return;
|
||||
|
||||
setSelectionPos(selection.second, pos);
|
||||
if (selectionIsSane()) {
|
||||
selection.show = true;
|
||||
plot.triggerRedrawOverlay();
|
||||
}
|
||||
else
|
||||
clearSelection(true);
|
||||
}
|
||||
|
||||
function clearSelection(preventEvent) {
|
||||
if (selection.show) {
|
||||
selection.show = false;
|
||||
plot.triggerRedrawOverlay();
|
||||
if (!preventEvent)
|
||||
plot.getPlaceholder().trigger("plotunselected", [ ]);
|
||||
}
|
||||
}
|
||||
|
||||
function setSelection(ranges, preventEvent) {
|
||||
var axis, range, axes = plot.getAxes();
|
||||
var o = plot.getOptions();
|
||||
|
||||
if (o.selection.mode == "y") {
|
||||
selection.first.x = 0;
|
||||
selection.second.x = plot.width();
|
||||
}
|
||||
else {
|
||||
axis = ranges["xaxis"]? axes["xaxis"]: (ranges["x2axis"]? axes["x2axis"]: axes["xaxis"]);
|
||||
range = ranges["xaxis"] || ranges["x2axis"] || { from:ranges["x1"], to:ranges["x2"] }
|
||||
selection.first.x = axis.p2c(Math.min(range.from, range.to));
|
||||
selection.second.x = axis.p2c(Math.max(range.from, range.to));
|
||||
}
|
||||
|
||||
if (o.selection.mode == "x") {
|
||||
selection.first.y = 0;
|
||||
selection.second.y = plot.height();
|
||||
}
|
||||
else {
|
||||
axis = ranges["yaxis"]? axes["yaxis"]: (ranges["y2axis"]? axes["y2axis"]: axes["yaxis"]);
|
||||
range = ranges["yaxis"] || ranges["y2axis"] || { from:ranges["y1"], to:ranges["y2"] }
|
||||
selection.first.y = axis.p2c(Math.min(range.from, range.to));
|
||||
selection.second.y = axis.p2c(Math.max(range.from, range.to));
|
||||
}
|
||||
|
||||
selection.show = true;
|
||||
plot.triggerRedrawOverlay();
|
||||
if (!preventEvent)
|
||||
triggerSelectedEvent();
|
||||
}
|
||||
|
||||
function selectionIsSane() {
|
||||
var minSize = 5;
|
||||
return Math.abs(selection.second.x - selection.first.x) >= minSize &&
|
||||
Math.abs(selection.second.y - selection.first.y) >= minSize;
|
||||
}
|
||||
|
||||
plot.clearSelection = clearSelection;
|
||||
plot.setSelection = setSelection;
|
||||
plot.getSelection = getSelection;
|
||||
|
||||
plot.hooks.bindEvents.push(function(plot, eventHolder) {
|
||||
var o = plot.getOptions();
|
||||
if (o.selection.mode != null)
|
||||
eventHolder.mousemove(onMouseMove);
|
||||
|
||||
if (o.selection.mode != null)
|
||||
eventHolder.mousedown(onMouseDown);
|
||||
});
|
||||
|
||||
|
||||
plot.hooks.drawOverlay.push(function (plot, ctx) {
|
||||
// draw selection
|
||||
if (selection.show && selectionIsSane()) {
|
||||
var plotOffset = plot.getPlotOffset();
|
||||
var o = plot.getOptions();
|
||||
|
||||
ctx.save();
|
||||
ctx.translate(plotOffset.left, plotOffset.top);
|
||||
|
||||
var c = $.color.parse(o.selection.color);
|
||||
|
||||
ctx.strokeStyle = c.scale('a', 0.8).toString();
|
||||
ctx.lineWidth = 1;
|
||||
ctx.lineJoin = "round";
|
||||
ctx.fillStyle = c.scale('a', 0.4).toString();
|
||||
|
||||
var x = Math.min(selection.first.x, selection.second.x),
|
||||
y = Math.min(selection.first.y, selection.second.y),
|
||||
w = Math.abs(selection.second.x - selection.first.x),
|
||||
h = Math.abs(selection.second.y - selection.first.y);
|
||||
|
||||
ctx.fillRect(x, y, w, h);
|
||||
ctx.strokeRect(x, y, w, h);
|
||||
|
||||
ctx.restore();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
$.plot.plugins.push({
|
||||
init: init,
|
||||
options: {
|
||||
selection: {
|
||||
mode: null, // one of null, "x", "y" or "xy"
|
||||
color: "#e8cfac"
|
||||
}
|
||||
},
|
||||
name: 'selection',
|
||||
version: '1.0'
|
||||
});
|
||||
})(jQuery);
|
|
@ -0,0 +1 @@
|
|||
(function(A){function B(J){var O={first:{x:-1,y:-1},second:{x:-1,y:-1},show:false,active:false};var L={};function D(Q){if(O.active){J.getPlaceholder().trigger("plotselecting",[F()]);K(Q)}}function M(Q){if(Q.which!=1){return }document.body.focus();if(document.onselectstart!==undefined&&L.onselectstart==null){L.onselectstart=document.onselectstart;document.onselectstart=function(){return false}}if(document.ondrag!==undefined&&L.ondrag==null){L.ondrag=document.ondrag;document.ondrag=function(){return false}}C(O.first,Q);O.active=true;A(document).one("mouseup",I)}function I(Q){if(document.onselectstart!==undefined){document.onselectstart=L.onselectstart}if(document.ondrag!==undefined){document.ondrag=L.ondrag}O.active=false;K(Q);if(E()){H()}else{J.getPlaceholder().trigger("plotunselected",[]);J.getPlaceholder().trigger("plotselecting",[null])}return false}function F(){if(!E()){return null}var R=Math.min(O.first.x,O.second.x),Q=Math.max(O.first.x,O.second.x),T=Math.max(O.first.y,O.second.y),S=Math.min(O.first.y,O.second.y);var U={};var V=J.getAxes();if(V.xaxis.used){U.xaxis={from:V.xaxis.c2p(R),to:V.xaxis.c2p(Q)}}if(V.x2axis.used){U.x2axis={from:V.x2axis.c2p(R),to:V.x2axis.c2p(Q)}}if(V.yaxis.used){U.yaxis={from:V.yaxis.c2p(T),to:V.yaxis.c2p(S)}}if(V.y2axis.used){U.y2axis={from:V.y2axis.c2p(T),to:V.y2axis.c2p(S)}}return U}function H(){var Q=F();J.getPlaceholder().trigger("plotselected",[Q]);var R=J.getAxes();if(R.xaxis.used&&R.yaxis.used){J.getPlaceholder().trigger("selected",[{x1:Q.xaxis.from,y1:Q.yaxis.from,x2:Q.xaxis.to,y2:Q.yaxis.to}])}}function G(R,S,Q){return S<R?R:(S>Q?Q:S)}function C(U,R){var T=J.getOptions();var S=J.getPlaceholder().offset();var Q=J.getPlotOffset();U.x=G(0,R.pageX-S.left-Q.left,J.width());U.y=G(0,R.pageY-S.top-Q.top,J.height());if(T.selection.mode=="y"){U.x=U==O.first?0:J.width()}if(T.selection.mode=="x"){U.y=U==O.first?0:J.height()}}function K(Q){if(Q.pageX==null){return }C(O.second,Q);if(E()){O.show=true;J.triggerRedrawOverlay()}else{P(true)}}function P(Q){if(O.show){O.show=false;J.triggerRedrawOverlay();if(!Q){J.getPlaceholder().trigger("plotunselected",[])}}}function N(R,Q){var T,S,U=J.getAxes();var V=J.getOptions();if(V.selection.mode=="y"){O.first.x=0;O.second.x=J.width()}else{T=R.xaxis?U.xaxis:(R.x2axis?U.x2axis:U.xaxis);S=R.xaxis||R.x2axis||{from:R.x1,to:R.x2};O.first.x=T.p2c(Math.min(S.from,S.to));O.second.x=T.p2c(Math.max(S.from,S.to))}if(V.selection.mode=="x"){O.first.y=0;O.second.y=J.height()}else{T=R.yaxis?U.yaxis:(R.y2axis?U.y2axis:U.yaxis);S=R.yaxis||R.y2axis||{from:R.y1,to:R.y2};O.first.y=T.p2c(Math.min(S.from,S.to));O.second.y=T.p2c(Math.max(S.from,S.to))}O.show=true;J.triggerRedrawOverlay();if(!Q){H()}}function E(){var Q=5;return Math.abs(O.second.x-O.first.x)>=Q&&Math.abs(O.second.y-O.first.y)>=Q}J.clearSelection=P;J.setSelection=N;J.getSelection=F;J.hooks.bindEvents.push(function(R,Q){var S=R.getOptions();if(S.selection.mode!=null){Q.mousemove(D)}if(S.selection.mode!=null){Q.mousedown(M)}});J.hooks.drawOverlay.push(function(T,Y){if(O.show&&E()){var R=T.getPlotOffset();var Q=T.getOptions();Y.save();Y.translate(R.left,R.top);var U=A.color.parse(Q.selection.color);Y.strokeStyle=U.scale("a",0.8).toString();Y.lineWidth=1;Y.lineJoin="round";Y.fillStyle=U.scale("a",0.4).toString();var W=Math.min(O.first.x,O.second.x),V=Math.min(O.first.y,O.second.y),X=Math.abs(O.second.x-O.first.x),S=Math.abs(O.second.y-O.first.y);Y.fillRect(W,V,X,S);Y.strokeRect(W,V,X,S);Y.restore()}})}A.plot.plugins.push({init:B,options:{selection:{mode:null,color:"#e8cfac"}},name:"selection",version:"1.0"})})(jQuery);
|
|
@ -0,0 +1,152 @@
|
|||
/*
|
||||
Flot plugin for stacking data sets, i.e. putting them on top of each
|
||||
other, for accumulative graphs. Note that the plugin assumes the data
|
||||
is sorted on x. Also note that stacking a mix of positive and negative
|
||||
values in most instances doesn't make sense (so it looks weird).
|
||||
|
||||
Two or more series are stacked when their "stack" attribute is set to
|
||||
the same key (which can be any number or string or just "true"). To
|
||||
specify the default stack, you can set
|
||||
|
||||
series: {
|
||||
stack: null or true or key (number/string)
|
||||
}
|
||||
|
||||
or specify it for a specific series
|
||||
|
||||
$.plot($("#placeholder"), [{ data: [ ... ], stack: true ])
|
||||
|
||||
The stacking order is determined by the order of the data series in
|
||||
the array (later series end up on top of the previous).
|
||||
|
||||
Internally, the plugin modifies the datapoints in each series, adding
|
||||
an offset to the y value. For line series, extra data points are
|
||||
inserted through interpolation. For bar charts, the second y value is
|
||||
also adjusted.
|
||||
*/
|
||||
|
||||
(function ($) {
|
||||
var options = {
|
||||
series: { stack: null } // or number/string
|
||||
};
|
||||
|
||||
function init(plot) {
|
||||
function findMatchingSeries(s, allseries) {
|
||||
var res = null
|
||||
for (var i = 0; i < allseries.length; ++i) {
|
||||
if (s == allseries[i])
|
||||
break;
|
||||
|
||||
if (allseries[i].stack == s.stack)
|
||||
res = allseries[i];
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
function stackData(plot, s, datapoints) {
|
||||
if (s.stack == null)
|
||||
return;
|
||||
|
||||
var other = findMatchingSeries(s, plot.getData());
|
||||
if (!other)
|
||||
return;
|
||||
|
||||
var ps = datapoints.pointsize,
|
||||
points = datapoints.points,
|
||||
otherps = other.datapoints.pointsize,
|
||||
otherpoints = other.datapoints.points,
|
||||
newpoints = [],
|
||||
px, py, intery, qx, qy, bottom,
|
||||
withlines = s.lines.show, withbars = s.bars.show,
|
||||
withsteps = withlines && s.lines.steps,
|
||||
i = 0, j = 0, l;
|
||||
|
||||
while (true) {
|
||||
if (i >= points.length)
|
||||
break;
|
||||
|
||||
l = newpoints.length;
|
||||
|
||||
if (j >= otherpoints.length
|
||||
|| otherpoints[j] == null
|
||||
|| points[i] == null) {
|
||||
// degenerate cases
|
||||
for (m = 0; m < ps; ++m)
|
||||
newpoints.push(points[i + m]);
|
||||
i += ps;
|
||||
}
|
||||
else {
|
||||
// cases where we actually got two points
|
||||
px = points[i];
|
||||
py = points[i + 1];
|
||||
qx = otherpoints[j];
|
||||
qy = otherpoints[j + 1];
|
||||
bottom = 0;
|
||||
|
||||
if (px == qx) {
|
||||
for (m = 0; m < ps; ++m)
|
||||
newpoints.push(points[i + m]);
|
||||
|
||||
newpoints[l + 1] += qy;
|
||||
bottom = qy;
|
||||
|
||||
i += ps;
|
||||
j += otherps;
|
||||
}
|
||||
else if (px > qx) {
|
||||
// we got past point below, might need to
|
||||
// insert interpolated extra point
|
||||
if (withlines && i > 0 && points[i - ps] != null) {
|
||||
intery = py + (points[i - ps + 1] - py) * (qx - px) / (points[i - ps] - px);
|
||||
newpoints.push(qx);
|
||||
newpoints.push(intery + qy)
|
||||
for (m = 2; m < ps; ++m)
|
||||
newpoints.push(points[i + m]);
|
||||
bottom = qy;
|
||||
}
|
||||
|
||||
j += otherps;
|
||||
}
|
||||
else {
|
||||
for (m = 0; m < ps; ++m)
|
||||
newpoints.push(points[i + m]);
|
||||
|
||||
// we might be able to interpolate a point below,
|
||||
// this can give us a better y
|
||||
if (withlines && j > 0 && otherpoints[j - ps] != null)
|
||||
bottom = qy + (otherpoints[j - ps + 1] - qy) * (px - qx) / (otherpoints[j - ps] - qx);
|
||||
|
||||
newpoints[l + 1] += bottom;
|
||||
|
||||
i += ps;
|
||||
}
|
||||
|
||||
if (l != newpoints.length && withbars)
|
||||
newpoints[l + 2] += bottom;
|
||||
}
|
||||
|
||||
// maintain the line steps invariant
|
||||
if (withsteps && l != newpoints.length && l > 0
|
||||
&& newpoints[l] != null
|
||||
&& newpoints[l] != newpoints[l - ps]
|
||||
&& newpoints[l + 1] != newpoints[l - ps + 1]) {
|
||||
for (m = 0; m < ps; ++m)
|
||||
newpoints[l + ps + m] = newpoints[l + m];
|
||||
newpoints[l + 1] = newpoints[l - ps + 1];
|
||||
}
|
||||
}
|
||||
|
||||
datapoints.points = newpoints;
|
||||
}
|
||||
|
||||
plot.hooks.processDatapoints.push(stackData);
|
||||
}
|
||||
|
||||
$.plot.plugins.push({
|
||||
init: init,
|
||||
options: options,
|
||||
name: 'stack',
|
||||
version: '1.0'
|
||||
});
|
||||
})(jQuery);
|
|
@ -0,0 +1 @@
|
|||
(function(B){var A={series:{stack:null}};function C(F){function D(J,I){var H=null;for(var G=0;G<I.length;++G){if(J==I[G]){break}if(I[G].stack==J.stack){H=I[G]}}return H}function E(W,P,G){if(P.stack==null){return }var L=D(P,W.getData());if(!L){return }var T=G.pointsize,Y=G.points,H=L.datapoints.pointsize,S=L.datapoints.points,N=[],R,Q,I,a,Z,M,O=P.lines.show,K=P.bars.show,J=O&&P.lines.steps,X=0,V=0,U;while(true){if(X>=Y.length){break}U=N.length;if(V>=S.length||S[V]==null||Y[X]==null){for(m=0;m<T;++m){N.push(Y[X+m])}X+=T}else{R=Y[X];Q=Y[X+1];a=S[V];Z=S[V+1];M=0;if(R==a){for(m=0;m<T;++m){N.push(Y[X+m])}N[U+1]+=Z;M=Z;X+=T;V+=H}else{if(R>a){if(O&&X>0&&Y[X-T]!=null){I=Q+(Y[X-T+1]-Q)*(a-R)/(Y[X-T]-R);N.push(a);N.push(I+Z);for(m=2;m<T;++m){N.push(Y[X+m])}M=Z}V+=H}else{for(m=0;m<T;++m){N.push(Y[X+m])}if(O&&V>0&&S[V-T]!=null){M=Z+(S[V-T+1]-Z)*(R-a)/(S[V-T]-a)}N[U+1]+=M;X+=T}}if(U!=N.length&&K){N[U+2]+=M}}if(J&&U!=N.length&&U>0&&N[U]!=null&&N[U]!=N[U-T]&&N[U+1]!=N[U-T+1]){for(m=0;m<T;++m){N[U+T+m]=N[U+m]}N[U+1]=N[U-T+1]}}G.points=N}F.hooks.processDatapoints.push(E)}B.plot.plugins.push({init:C,options:A,name:"stack",version:"1.0"})})(jQuery);
|
|
@ -0,0 +1,103 @@
|
|||
/*
|
||||
Flot plugin for thresholding data. Controlled through the option
|
||||
"threshold" in either the global series options
|
||||
|
||||
series: {
|
||||
threshold: {
|
||||
below: number
|
||||
color: colorspec
|
||||
}
|
||||
}
|
||||
|
||||
or in a specific series
|
||||
|
||||
$.plot($("#placeholder"), [{ data: [ ... ], threshold: { ... }}])
|
||||
|
||||
The data points below "below" are drawn with the specified color. This
|
||||
makes it easy to mark points below 0, e.g. for budget data.
|
||||
|
||||
Internally, the plugin works by splitting the data into two series,
|
||||
above and below the threshold. The extra series below the threshold
|
||||
will have its label cleared and the special "originSeries" attribute
|
||||
set to the original series. You may need to check for this in hover
|
||||
events.
|
||||
*/
|
||||
|
||||
(function ($) {
|
||||
var options = {
|
||||
series: { threshold: null } // or { below: number, color: color spec}
|
||||
};
|
||||
|
||||
function init(plot) {
|
||||
function thresholdData(plot, s, datapoints) {
|
||||
if (!s.threshold)
|
||||
return;
|
||||
|
||||
var ps = datapoints.pointsize, i, x, y, p, prevp,
|
||||
thresholded = $.extend({}, s); // note: shallow copy
|
||||
|
||||
thresholded.datapoints = { points: [], pointsize: ps };
|
||||
thresholded.label = null;
|
||||
thresholded.color = s.threshold.color;
|
||||
thresholded.threshold = null;
|
||||
thresholded.originSeries = s;
|
||||
thresholded.data = [];
|
||||
|
||||
var below = s.threshold.below,
|
||||
origpoints = datapoints.points,
|
||||
addCrossingPoints = s.lines.show;
|
||||
|
||||
threspoints = [];
|
||||
newpoints = [];
|
||||
|
||||
for (i = 0; i < origpoints.length; i += ps) {
|
||||
x = origpoints[i]
|
||||
y = origpoints[i + 1];
|
||||
|
||||
prevp = p;
|
||||
if (y < below)
|
||||
p = threspoints;
|
||||
else
|
||||
p = newpoints;
|
||||
|
||||
if (addCrossingPoints && prevp != p && x != null
|
||||
&& i > 0 && origpoints[i - ps] != null) {
|
||||
var interx = (x - origpoints[i - ps]) / (y - origpoints[i - ps + 1]) * (below - y) + x;
|
||||
prevp.push(interx);
|
||||
prevp.push(below);
|
||||
for (m = 2; m < ps; ++m)
|
||||
prevp.push(origpoints[i + m]);
|
||||
|
||||
p.push(null); // start new segment
|
||||
p.push(null);
|
||||
for (m = 2; m < ps; ++m)
|
||||
p.push(origpoints[i + m]);
|
||||
p.push(interx);
|
||||
p.push(below);
|
||||
for (m = 2; m < ps; ++m)
|
||||
p.push(origpoints[i + m]);
|
||||
}
|
||||
|
||||
p.push(x);
|
||||
p.push(y);
|
||||
}
|
||||
|
||||
datapoints.points = newpoints;
|
||||
thresholded.datapoints.points = threspoints;
|
||||
|
||||
if (thresholded.datapoints.points.length > 0)
|
||||
plot.getData().push(thresholded);
|
||||
|
||||
// FIXME: there are probably some edge cases left in bars
|
||||
}
|
||||
|
||||
plot.hooks.processDatapoints.push(thresholdData);
|
||||
}
|
||||
|
||||
$.plot.plugins.push({
|
||||
init: init,
|
||||
options: options,
|
||||
name: 'threshold',
|
||||
version: '1.0'
|
||||
});
|
||||
})(jQuery);
|
|
@ -0,0 +1 @@
|
|||
(function(B){var A={series:{threshold:null}};function C(D){function E(L,S,M){if(!S.threshold){return }var F=M.pointsize,I,O,N,G,K,H=B.extend({},S);H.datapoints={points:[],pointsize:F};H.label=null;H.color=S.threshold.color;H.threshold=null;H.originSeries=S;H.data=[];var P=S.threshold.below,Q=M.points,R=S.lines.show;threspoints=[];newpoints=[];for(I=0;I<Q.length;I+=F){O=Q[I];N=Q[I+1];K=G;if(N<P){G=threspoints}else{G=newpoints}if(R&&K!=G&&O!=null&&I>0&&Q[I-F]!=null){var J=(O-Q[I-F])/(N-Q[I-F+1])*(P-N)+O;K.push(J);K.push(P);for(m=2;m<F;++m){K.push(Q[I+m])}G.push(null);G.push(null);for(m=2;m<F;++m){G.push(Q[I+m])}G.push(J);G.push(P);for(m=2;m<F;++m){G.push(Q[I+m])}}G.push(O);G.push(N)}M.points=newpoints;H.datapoints.points=threspoints;if(H.datapoints.points.length>0){L.getData().push(H)}}D.hooks.processDatapoints.push(E)}B.plot.plugins.push({init:C,options:A,name:"threshold",version:"1.0"})})(jQuery);
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
|
@ -0,0 +1,110 @@
|
|||
<?php
|
||||
date_default_timezone_set("UTC");
|
||||
// vim: set ts=4 sw=4 tw=99 et:
|
||||
|
||||
require_once("internals.php");
|
||||
require_once("context.php");
|
||||
|
||||
init_database();
|
||||
|
||||
$smarty = new_smarty();
|
||||
$cx = new Context();
|
||||
$view = isset($_GET['view']) ? $_GET['view'] : 'normal';
|
||||
|
||||
if ($cx->view == 'breakdown') {
|
||||
$graphs = makeIndividualGraphs($cx, array(1, 3, 4));
|
||||
$tpl = "takethree-individual";
|
||||
} else {
|
||||
$graphs = makeTotalGraphs($cx, array(1, 3, 4));
|
||||
$tpl = "takethree";
|
||||
}
|
||||
|
||||
$machines = array(array('id' => 9,
|
||||
'info' => 'Mac OS X, 32-bit (Mac Mini)'),
|
||||
array('id' => 8,
|
||||
'info' => 'Mac OS X, 64-bit (Mac Mini)'),
|
||||
array('id' => 10,
|
||||
'info' => 'Linux ARMv7 (nVidia Tegra 250)'));
|
||||
$smarty->assign('machines', $machines);
|
||||
$smarty->assign('machine_id', $cx->machine_id);
|
||||
$smarty->assign('url_machine', $cx->url(array('machine' => false)));
|
||||
|
||||
$views = array(array('id' => 'overall',
|
||||
'name' => 'Overall'),
|
||||
array('id' => 'regress',
|
||||
'name' => 'Regression Testing'),
|
||||
array('id' => 'breakdown',
|
||||
'name' => 'Test Breakdown'));
|
||||
$smarty->assign('views', $views);
|
||||
$smarty->assign('view', $cx->view);
|
||||
$smarty->assign('url_view', $cx->url(array('view' => false)));
|
||||
|
||||
$smarty->assign('cx', $cx);
|
||||
$smarty->assign('graphs', $graphs);
|
||||
|
||||
$smarty->display("$tpl.tpl");
|
||||
|
||||
function makeIndividualGraphs(&$cx, $list)
|
||||
{
|
||||
$graphs = array();
|
||||
|
||||
for ($i = 0; $i < count($list); $i++) {
|
||||
$suite_id = $list[$i];
|
||||
$query = "SELECT name, description, better_direction
|
||||
FROM awfy_suite
|
||||
WHERE id = $suite_id";
|
||||
$result = awfy_query($query);
|
||||
if (!mysql_num_rows($result))
|
||||
continue;
|
||||
$row = mysql_fetch_assoc($result);
|
||||
$suite_name = $row['name'];
|
||||
$suite_desc = $row['description'];
|
||||
$suite_direction = $row['better_direction'];
|
||||
|
||||
$filter = RunFilter::FromGET($cx, $suite_id);
|
||||
|
||||
$query = "SELECT test
|
||||
FROM awfy_breakdown b
|
||||
WHERE run_id IN (" . $filter->idstr . ")
|
||||
AND suite_id = $suite_id
|
||||
GROUP BY test";
|
||||
$result = awfy_query($query);
|
||||
while (($row = mysql_fetch_assoc($result)) !== FALSE) {
|
||||
$test_name = $row['test'];
|
||||
$gb = new GraphBuilder($cx, $filter, $test_name);
|
||||
$graphs[$suite_name . "-" . $test_name] = array(
|
||||
'description' => $suite_name . "-" . $test_name,
|
||||
'direction' => $suite_direction,
|
||||
'graph' => $gb
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return $graphs;
|
||||
}
|
||||
|
||||
function makeTotalGraphs(&$cx, $list)
|
||||
{
|
||||
$graphs = array();
|
||||
|
||||
for ($i = 0; $i < count($list); $i++) {
|
||||
$id = $list[$i];
|
||||
$query = "SELECT name, description, better_direction
|
||||
FROM awfy_suite
|
||||
WHERE id = $id";
|
||||
$result = awfy_query($query);
|
||||
if (!mysql_num_rows($result))
|
||||
continue;
|
||||
$row = mysql_fetch_assoc($result);
|
||||
$filter = RunFilter::FromGET($cx, $id);
|
||||
$gb = new GraphBuilder($cx, $filter);
|
||||
$graphs[$row['name']] = array(
|
||||
'description' => $row['description'],
|
||||
'direction' => $row['better_direction'],
|
||||
'graph' => $gb
|
||||
);
|
||||
}
|
||||
|
||||
return $graphs;
|
||||
}
|
||||
|
|
@ -0,0 +1,75 @@
|
|||
<?php
|
||||
// vim: set ts=4 sw=4 tw=99 et:
|
||||
|
||||
require_once("smarty/libs/Smarty.class.php");
|
||||
|
||||
function init_database()
|
||||
{
|
||||
mysql_connect("localhost", "***", "***") or die("ERROR: " . mysql_error());
|
||||
mysql_select_db("dvander") or die("ERROR: " . mysql_error());
|
||||
}
|
||||
|
||||
function GET_int($name)
|
||||
{
|
||||
if (isset($_GET[$name]))
|
||||
return intval($_GET[$name]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
function GET_string($name)
|
||||
{
|
||||
if (isset($_GET[$name]))
|
||||
return $_GET[$name];
|
||||
return "";
|
||||
}
|
||||
|
||||
function new_smarty()
|
||||
{
|
||||
$smarty = new Smarty;
|
||||
$base = '/usr/apache/htdocs';
|
||||
$smarty->template_dir = $base . '/templates';
|
||||
$smarty->compile_dir = $base . '/cache_templates';
|
||||
$smarty->cache_dir = $base . '/cache_stuff';
|
||||
return $smarty;
|
||||
}
|
||||
|
||||
function find_vendor_of_mode_id($mode_id)
|
||||
{
|
||||
$query = "SELECT vendor_id FROM awfy_mode
|
||||
WHERE id = $mode_id";
|
||||
$results = mysql_query($query);
|
||||
if (!$results || mysql_num_rows($results) < 1)
|
||||
return 01;
|
||||
$row = mysql_fetch_array($results);
|
||||
return intval($row[0]);
|
||||
}
|
||||
|
||||
function find_mode($mode)
|
||||
{
|
||||
$query = "SELECT id FROM awfy_mode
|
||||
WHERE mode = '" . mysql_real_escape_string($mode) . "'";
|
||||
$results = mysql_query($query);
|
||||
if (!$results || mysql_num_rows($results) < 1)
|
||||
return -1;
|
||||
$row = mysql_fetch_array($results);
|
||||
return intval($row[0]);
|
||||
}
|
||||
|
||||
function find_suite($suite)
|
||||
{
|
||||
$query = "SELECT id FROM awfy_suite
|
||||
WHERE name = '" . mysql_real_escape_string($suite) . "'";
|
||||
$results = mysql_query($query);
|
||||
if (!$results || mysql_num_rows($results) < 1)
|
||||
return -1;
|
||||
$row = mysql_fetch_array($results);
|
||||
return intval($row[0]);
|
||||
}
|
||||
|
||||
function awfy_query($query)
|
||||
{
|
||||
$result = mysql_query($query) or die(mysql_error());
|
||||
return $result;
|
||||
}
|
||||
|
||||
?>
|
|
@ -0,0 +1,77 @@
|
|||
/* vim: set ts=4 sw=4 tw=99 et: */
|
||||
|
||||
#navbar
|
||||
{
|
||||
margin: 0;
|
||||
display: inline;
|
||||
}
|
||||
|
||||
#navbar li
|
||||
{
|
||||
line-height: 20px;
|
||||
}
|
||||
|
||||
#navbar > li
|
||||
{
|
||||
/* float: left; */
|
||||
list-style: none;
|
||||
margin-bottom: 1em;
|
||||
border: 1px solid transparent;
|
||||
text-align: right;
|
||||
width: 70px;
|
||||
padding-right: 5px;
|
||||
}
|
||||
|
||||
#navbar li a
|
||||
{
|
||||
display: block;
|
||||
margin: 0 10px;
|
||||
text-decoration: none;
|
||||
width: 70px;
|
||||
color: #000000;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
#navbar li.active
|
||||
{
|
||||
background: #F2F2F2;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#navbar li.active ul
|
||||
{
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
#navbar li ul
|
||||
{
|
||||
border-right: 1px outset black;
|
||||
border-bottom: 1px outset black;
|
||||
margin-top: -21px; // == line-height + border height
|
||||
margin-left: 75px; // == parent width + parent padding
|
||||
padding: 0;
|
||||
position: absolute;
|
||||
visibility: hidden;
|
||||
background: #F2F2F2;
|
||||
z-index: 0;
|
||||
}
|
||||
|
||||
#navbar li ul li
|
||||
{
|
||||
float: none;
|
||||
display: inline;
|
||||
text-align: left;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#navbar li ul li a
|
||||
{
|
||||
width: auto;
|
||||
}
|
||||
|
||||
#navbar li ul li a:hover
|
||||
{
|
||||
text-decoration:underline;
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
/* vim: set ts=4 sw=4 tw=99 et: */
|
||||
|
||||
function NavBar(name)
|
||||
{
|
||||
var timeout = 200;
|
||||
var closeTimer = null;
|
||||
|
||||
function open() {
|
||||
cancel();
|
||||
close();
|
||||
$(this).addClass('active');
|
||||
}
|
||||
|
||||
function close() {
|
||||
$('#' + name + ' > li').removeClass('active'); // make sure all others are closed
|
||||
}
|
||||
|
||||
function timer() {
|
||||
closeTimer = window.setTimeout(close, timeout);
|
||||
}
|
||||
|
||||
function cancel() {
|
||||
if (closeTimer) {
|
||||
window.clearTimeout(closeTimer);
|
||||
closeTimer = null;
|
||||
}
|
||||
}
|
||||
|
||||
$('#' + name + ' > li').bind('mouseover', open);
|
||||
$('#' + name + ' > li').bind('mouseout', timer);
|
||||
$('#' + name + ' > li').bind('onclick', open);
|
||||
document.onclick = close;
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
internals.php has settings redacted - fill 'em in, under mysql_connect and /usr/apache/htdocs
|
||||
UPDATED.PHP should be renamed to something random, not very secure i know but this is a hack job.
|
||||
flot is modified, see http://code.google.com/p/flot/issues/detail?id=23 comment #25's patch
|
||||
|
||||
|
|
@ -0,0 +1,182 @@
|
|||
-- phpMyAdmin SQL Dump
|
||||
-- version 3.3.9
|
||||
-- http://www.phpmyadmin.net
|
||||
--
|
||||
-- Host: localhost
|
||||
-- Generation Time: Feb 03, 2011 at 12:53 AM
|
||||
-- Server version: 5.1.41
|
||||
-- PHP Version: 5.3.5
|
||||
|
||||
SET SQL_MODE="NO_AUTO_VALUE_ON_ZERO";
|
||||
|
||||
--
|
||||
-- Database: `dvander`
|
||||
--
|
||||
|
||||
-- --------------------------------------------------------
|
||||
|
||||
--
|
||||
-- Table structure for table `awfy_breakdown`
|
||||
--
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `awfy_breakdown` (
|
||||
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`run_id` int(11) DEFAULT NULL,
|
||||
`suite_id` int(11) DEFAULT NULL,
|
||||
`mode_id` int(11) DEFAULT NULL,
|
||||
`test` varchar(45) DEFAULT NULL,
|
||||
`score` varchar(45) DEFAULT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `run_id` (`run_id`),
|
||||
KEY `suite_id` (`suite_id`),
|
||||
KEY `mode_id` (`mode_id`)
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=329903 ;
|
||||
|
||||
-- --------------------------------------------------------
|
||||
|
||||
--
|
||||
-- Table structure for table `awfy_build`
|
||||
--
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `awfy_build` (
|
||||
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`run_id` int(10) unsigned NOT NULL,
|
||||
`mode_id` int(10) unsigned NOT NULL,
|
||||
`cset` varchar(256) NOT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `index2` (`run_id`,`mode_id`)
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=12680 ;
|
||||
|
||||
-- --------------------------------------------------------
|
||||
|
||||
--
|
||||
-- Table structure for table `awfy_score`
|
||||
--
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `awfy_score` (
|
||||
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`run_id` int(11) DEFAULT NULL,
|
||||
`suite_id` int(11) DEFAULT NULL,
|
||||
`mode_id` int(11) DEFAULT NULL,
|
||||
`score` double DEFAULT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `run_id` (`run_id`),
|
||||
KEY `mode_id` (`mode_id`)
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=24486 ;
|
||||
|
||||
-- --------------------------------------------------------
|
||||
|
||||
--
|
||||
-- Table structure for table `fast_run`
|
||||
--
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `fast_run` (
|
||||
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`cpu` varchar(20) NOT NULL,
|
||||
`os` varchar(20) NOT NULL,
|
||||
`machine` int(10) unsigned NOT NULL,
|
||||
`stamp` int(10) unsigned NOT NULL,
|
||||
`cset` varchar(160) NOT NULL,
|
||||
`status` int(11) NOT NULL,
|
||||
`error` mediumtext NOT NULL,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=3502 ;
|
||||
|
||||
-- phpMyAdmin SQL Dump
|
||||
-- version 3.3.9
|
||||
-- http://www.phpmyadmin.net
|
||||
--
|
||||
-- Host: localhost
|
||||
-- Generation Time: Feb 03, 2011 at 12:53 AM
|
||||
-- Server version: 5.1.41
|
||||
-- PHP Version: 5.3.5
|
||||
|
||||
SET SQL_MODE="NO_AUTO_VALUE_ON_ZERO";
|
||||
|
||||
--
|
||||
-- Database: `dvander`
|
||||
--
|
||||
|
||||
-- --------------------------------------------------------
|
||||
|
||||
--
|
||||
-- Table structure for table `awfy_mode`
|
||||
--
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `awfy_mode` (
|
||||
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`vendor_id` int(10) unsigned NOT NULL,
|
||||
`mode` varchar(12) NOT NULL,
|
||||
`name` varchar(255) NOT NULL,
|
||||
`color` varchar(45) DEFAULT NULL,
|
||||
`level` int(10) unsigned NOT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `mode` (`mode`),
|
||||
UNIQUE KEY `index3` (`vendor_id`,`mode`)
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=12 ;
|
||||
|
||||
--
|
||||
-- Dumping data for table `awfy_mode`
|
||||
--
|
||||
|
||||
INSERT INTO `awfy_mode` (`id`, `vendor_id`, `mode`, `name`, `color`, `level`) VALUES
|
||||
(1, 2, 'moom', 'JM', '#000000', 10),
|
||||
(2, 2, 'mooj', 'TM+JM', '#6f0a93', 1),
|
||||
(3, 1, 'v8', 'v8', '#4DA74D', 1),
|
||||
(4, 3, 'jsc', 'jsc', '#cf4b4b', 1),
|
||||
(5, 3, 'jsci', 'no JIT', '#ef8b8b', 10),
|
||||
(6, 2, 'j', 'TM', '#ffa451', 10),
|
||||
(7, 2, 'm', 'JM', '#000000', 10),
|
||||
(8, 2, 'i', 'no JIT', '#bbbbbb', 10),
|
||||
(9, 2, 'mj', 'TM+JM', '#6f0a93', 10),
|
||||
(11, 2, 'tm', '', '', 10);
|
||||
|
||||
-- --------------------------------------------------------
|
||||
|
||||
--
|
||||
-- Table structure for table `awfy_suite`
|
||||
--
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `awfy_suite` (
|
||||
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`name` varchar(45) DEFAULT NULL,
|
||||
`description` varchar(45) DEFAULT NULL,
|
||||
`better_direction` int(11) DEFAULT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `name_UNIQUE` (`name`)
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=5 ;
|
||||
|
||||
--
|
||||
-- Dumping data for table `awfy_suite`
|
||||
--
|
||||
|
||||
INSERT INTO `awfy_suite` (`id`, `name`, `description`, `better_direction`) VALUES
|
||||
(1, 'ss', 'SunSpider', -1),
|
||||
(2, 'v8', 'V8 (SS harness)', -1),
|
||||
(3, 'v8real', 'V8 Benchmark', 1),
|
||||
(4, 'kraken', 'Kraken', -1);
|
||||
|
||||
-- --------------------------------------------------------
|
||||
|
||||
--
|
||||
-- Table structure for table `awfy_vendor`
|
||||
--
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `awfy_vendor` (
|
||||
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`name` varchar(20) NOT NULL,
|
||||
`vendor` varchar(30) NOT NULL,
|
||||
`csetURL` varchar(255) NOT NULL,
|
||||
`browser` varchar(30) NOT NULL,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=4 ;
|
||||
|
||||
--
|
||||
-- Dumping data for table `awfy_vendor`
|
||||
--
|
||||
|
||||
INSERT INTO `awfy_vendor` (`id`, `name`, `vendor`, `csetURL`, `browser`) VALUES
|
||||
(1, 'V8', 'Google', 'http://code.google.com/p/v8/source/detail?r=', 'Chrome'),
|
||||
(2, 'SpiderMonkey', 'Mozilla', 'http://hg.mozilla.org/tracemonkey/rev/', 'Firefox'),
|
||||
(3, 'Nitro', 'Apple', 'http://trac.webkit.org/changeset/', 'Safari');
|
||||
|
|
@ -0,0 +1,165 @@
|
|||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
|
||||
This version of the GNU Lesser General Public License incorporates
|
||||
the terms and conditions of version 3 of the GNU General Public
|
||||
License, supplemented by the additional permissions listed below.
|
||||
|
||||
0. Additional Definitions.
|
||||
|
||||
As used herein, "this License" refers to version 3 of the GNU Lesser
|
||||
General Public License, and the "GNU GPL" refers to version 3 of the GNU
|
||||
General Public License.
|
||||
|
||||
"The Library" refers to a covered work governed by this License,
|
||||
other than an Application or a Combined Work as defined below.
|
||||
|
||||
An "Application" is any work that makes use of an interface provided
|
||||
by the Library, but which is not otherwise based on the Library.
|
||||
Defining a subclass of a class defined by the Library is deemed a mode
|
||||
of using an interface provided by the Library.
|
||||
|
||||
A "Combined Work" is a work produced by combining or linking an
|
||||
Application with the Library. The particular version of the Library
|
||||
with which the Combined Work was made is also called the "Linked
|
||||
Version".
|
||||
|
||||
The "Minimal Corresponding Source" for a Combined Work means the
|
||||
Corresponding Source for the Combined Work, excluding any source code
|
||||
for portions of the Combined Work that, considered in isolation, are
|
||||
based on the Application, and not on the Linked Version.
|
||||
|
||||
The "Corresponding Application Code" for a Combined Work means the
|
||||
object code and/or source code for the Application, including any data
|
||||
and utility programs needed for reproducing the Combined Work from the
|
||||
Application, but excluding the System Libraries of the Combined Work.
|
||||
|
||||
1. Exception to Section 3 of the GNU GPL.
|
||||
|
||||
You may convey a covered work under sections 3 and 4 of this License
|
||||
without being bound by section 3 of the GNU GPL.
|
||||
|
||||
2. Conveying Modified Versions.
|
||||
|
||||
If you modify a copy of the Library, and, in your modifications, a
|
||||
facility refers to a function or data to be supplied by an Application
|
||||
that uses the facility (other than as an argument passed when the
|
||||
facility is invoked), then you may convey a copy of the modified
|
||||
version:
|
||||
|
||||
a) under this License, provided that you make a good faith effort to
|
||||
ensure that, in the event an Application does not supply the
|
||||
function or data, the facility still operates, and performs
|
||||
whatever part of its purpose remains meaningful, or
|
||||
|
||||
b) under the GNU GPL, with none of the additional permissions of
|
||||
this License applicable to that copy.
|
||||
|
||||
3. Object Code Incorporating Material from Library Header Files.
|
||||
|
||||
The object code form of an Application may incorporate material from
|
||||
a header file that is part of the Library. You may convey such object
|
||||
code under terms of your choice, provided that, if the incorporated
|
||||
material is not limited to numerical parameters, data structure
|
||||
layouts and accessors, or small macros, inline functions and templates
|
||||
(ten or fewer lines in length), you do both of the following:
|
||||
|
||||
a) Give prominent notice with each copy of the object code that the
|
||||
Library is used in it and that the Library and its use are
|
||||
covered by this License.
|
||||
|
||||
b) Accompany the object code with a copy of the GNU GPL and this license
|
||||
document.
|
||||
|
||||
4. Combined Works.
|
||||
|
||||
You may convey a Combined Work under terms of your choice that,
|
||||
taken together, effectively do not restrict modification of the
|
||||
portions of the Library contained in the Combined Work and reverse
|
||||
engineering for debugging such modifications, if you also do each of
|
||||
the following:
|
||||
|
||||
a) Give prominent notice with each copy of the Combined Work that
|
||||
the Library is used in it and that the Library and its use are
|
||||
covered by this License.
|
||||
|
||||
b) Accompany the Combined Work with a copy of the GNU GPL and this license
|
||||
document.
|
||||
|
||||
c) For a Combined Work that displays copyright notices during
|
||||
execution, include the copyright notice for the Library among
|
||||
these notices, as well as a reference directing the user to the
|
||||
copies of the GNU GPL and this license document.
|
||||
|
||||
d) Do one of the following:
|
||||
|
||||
0) Convey the Minimal Corresponding Source under the terms of this
|
||||
License, and the Corresponding Application Code in a form
|
||||
suitable for, and under terms that permit, the user to
|
||||
recombine or relink the Application with a modified version of
|
||||
the Linked Version to produce a modified Combined Work, in the
|
||||
manner specified by section 6 of the GNU GPL for conveying
|
||||
Corresponding Source.
|
||||
|
||||
1) Use a suitable shared library mechanism for linking with the
|
||||
Library. A suitable mechanism is one that (a) uses at run time
|
||||
a copy of the Library already present on the user's computer
|
||||
system, and (b) will operate properly with a modified version
|
||||
of the Library that is interface-compatible with the Linked
|
||||
Version.
|
||||
|
||||
e) Provide Installation Information, but only if you would otherwise
|
||||
be required to provide such information under section 6 of the
|
||||
GNU GPL, and only to the extent that such information is
|
||||
necessary to install and execute a modified version of the
|
||||
Combined Work produced by recombining or relinking the
|
||||
Application with a modified version of the Linked Version. (If
|
||||
you use option 4d0, the Installation Information must accompany
|
||||
the Minimal Corresponding Source and Corresponding Application
|
||||
Code. If you use option 4d1, you must provide the Installation
|
||||
Information in the manner specified by section 6 of the GNU GPL
|
||||
for conveying Corresponding Source.)
|
||||
|
||||
5. Combined Libraries.
|
||||
|
||||
You may place library facilities that are a work based on the
|
||||
Library side by side in a single library together with other library
|
||||
facilities that are not Applications and are not covered by this
|
||||
License, and convey such a combined library under terms of your
|
||||
choice, if you do both of the following:
|
||||
|
||||
a) Accompany the combined library with a copy of the same work based
|
||||
on the Library, uncombined with any other library facilities,
|
||||
conveyed under the terms of this License.
|
||||
|
||||
b) Give prominent notice with the combined library that part of it
|
||||
is a work based on the Library, and explaining where to find the
|
||||
accompanying uncombined form of the same work.
|
||||
|
||||
6. Revised Versions of the GNU Lesser General Public License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions
|
||||
of the GNU Lesser General Public License from time to time. Such new
|
||||
versions will be similar in spirit to the present version, but may
|
||||
differ in detail to address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Library as you received it specifies that a certain numbered version
|
||||
of the GNU Lesser General Public License "or any later version"
|
||||
applies to it, you have the option of following the terms and
|
||||
conditions either of that published version or of any later version
|
||||
published by the Free Software Foundation. If the Library as you
|
||||
received it does not specify a version number of the GNU Lesser
|
||||
General Public License, you may choose any version of the GNU Lesser
|
||||
General Public License ever published by the Free Software Foundation.
|
||||
|
||||
If the Library as you received it specifies that a proxy can decide
|
||||
whether future versions of the GNU Lesser General Public License shall
|
||||
apply, that proxy's public statement of acceptance of any version is
|
||||
permanent authorization for you to choose that version for the
|
||||
Library.
|
|
@ -0,0 +1,570 @@
|
|||
Smarty 3.0.5
|
||||
|
||||
Author: Monte Ohrt <monte at ohrt dot com >
|
||||
Author: Uwe Tews
|
||||
|
||||
AN INTRODUCTION TO SMARTY 3
|
||||
|
||||
NOTICE for 3.0.5 release:
|
||||
|
||||
Smarty now follows the PHP error_reporting level by default. If PHP does not mask E_NOTICE and you try to access an unset template variable, you will now get an E_NOTICE warning. To revert to the old behavior:
|
||||
|
||||
$smarty->error_reporting = E_ALL & ~E_NOTICE;
|
||||
|
||||
NOTICE for 3.0 release:
|
||||
|
||||
IMPORTANT: Some API adjustments have been made between the RC4 and 3.0 release.
|
||||
We felt it is better to make these now instead of after a 3.0 release, then have to
|
||||
immediately deprecate APIs in 3.1. Online documentation has been updated
|
||||
to reflect these changes. Specifically:
|
||||
|
||||
---- API CHANGES RC4 -> 3.0 ----
|
||||
|
||||
$smarty->register->*
|
||||
$smarty->unregister->*
|
||||
$smarty->utility->*
|
||||
$samrty->cache->*
|
||||
|
||||
Have all been changed to local method calls such as:
|
||||
|
||||
$smarty->clearAllCache()
|
||||
$smarty->registerFoo()
|
||||
$smarty->unregisterFoo()
|
||||
$smarty->testInstall()
|
||||
etc.
|
||||
|
||||
Registration of function, block, compiler, and modifier plugins have been
|
||||
consolidated under two API calls:
|
||||
|
||||
$smarty->registerPlugin(...)
|
||||
$smarty->unregisterPlugin(...)
|
||||
|
||||
Registration of pre, post, output and variable filters have been
|
||||
consolidated under two API calls:
|
||||
|
||||
$smarty->registerFilter(...)
|
||||
$smarty->unregisterFilter(...)
|
||||
|
||||
Please refer to the online documentation for all specific changes:
|
||||
|
||||
http://www.smarty.net/documentation
|
||||
|
||||
----
|
||||
|
||||
The Smarty 3 API has been refactored to a syntax geared
|
||||
for consistency and modularity. The Smarty 2 API syntax is still supported, but
|
||||
will throw a deprecation notice. You can disable the notices, but it is highly
|
||||
recommended to adjust your syntax to Smarty 3, as the Smarty 2 syntax must run
|
||||
through an extra rerouting wrapper.
|
||||
|
||||
Basically, all Smarty methods now follow the "fooBarBaz" camel case syntax. Also,
|
||||
all Smarty properties now have getters and setters. So for example, the property
|
||||
$smarty->cache_dir can be set with $smarty->setCacheDir('foo/') and can be
|
||||
retrieved with $smarty->getCacheDir().
|
||||
|
||||
Some of the Smarty 3 APIs have been revoked such as the "is*" methods that were
|
||||
just duplicate functions of the now available "get*" methods.
|
||||
|
||||
Here is a rundown of the Smarty 3 API:
|
||||
|
||||
$smarty->fetch($template, $cache_id = null, $compile_id = null, $parent = null)
|
||||
$smarty->display($template, $cache_id = null, $compile_id = null, $parent = null)
|
||||
$smarty->isCached($template, $cache_id = null, $compile_id = null)
|
||||
$smarty->createData($parent = null)
|
||||
$smarty->createTemplate($template, $cache_id = null, $compile_id = null, $parent = null)
|
||||
$smarty->enableSecurity()
|
||||
$smarty->disableSecurity()
|
||||
$smarty->setTemplateDir($template_dir)
|
||||
$smarty->addTemplateDir($template_dir)
|
||||
$smarty->templateExists($resource_name)
|
||||
$smarty->loadPlugin($plugin_name, $check = true)
|
||||
$smarty->loadFilter($type, $name)
|
||||
$smarty->setExceptionHandler($handler)
|
||||
$smarty->addPluginsDir($plugins_dir)
|
||||
$smarty->getGlobal($varname = null)
|
||||
$smarty->getRegisteredObject($name)
|
||||
$smarty->getDebugTemplate()
|
||||
$smarty->setDebugTemplate($tpl_name)
|
||||
$smarty->assign($tpl_var, $value = null, $nocache = false)
|
||||
$smarty->assignGlobal($varname, $value = null, $nocache = false)
|
||||
$smarty->assignByRef($tpl_var, &$value, $nocache = false)
|
||||
$smarty->append($tpl_var, $value = null, $merge = false, $nocache = false)
|
||||
$smarty->appendByRef($tpl_var, &$value, $merge = false)
|
||||
$smarty->clearAssign($tpl_var)
|
||||
$smarty->clearAllAssign()
|
||||
$smarty->configLoad($config_file, $sections = null)
|
||||
$smarty->getVariable($variable, $_ptr = null, $search_parents = true, $error_enable = true)
|
||||
$smarty->getConfigVariable($variable)
|
||||
$smarty->getStreamVariable($variable)
|
||||
$smarty->getConfigVars($varname = null)
|
||||
$smarty->clearConfig($varname = null)
|
||||
$smarty->getTemplateVars($varname = null, $_ptr = null, $search_parents = true)
|
||||
$smarty->clearAllCache($exp_time = null, $type = null)
|
||||
$smarty->clearCache($template_name, $cache_id = null, $compile_id = null, $exp_time = null, $type = null)
|
||||
|
||||
$smarty->registerPlugin($type, $tag, $callback, $cacheable = true, $cache_attr = array())
|
||||
|
||||
$smarty->registerObject($object_name, $object_impl, $allowed = array(), $smarty_args = true, $block_methods = array())
|
||||
|
||||
$smarty->registerFilter($type, $function_name)
|
||||
$smarty->registerResource($resource_type, $function_names)
|
||||
$smarty->registerDefaultPluginHandler($function_name)
|
||||
$smarty->registerDefaultTemplateHandler($function_name)
|
||||
|
||||
$smarty->unregisterPlugin($type, $tag)
|
||||
$smarty->unregisterObject($object_name)
|
||||
$smarty->unregisterFilter($type, $function_name)
|
||||
$smarty->unregisterResource($resource_type)
|
||||
|
||||
$smarty->compileAllTemplates($extention = '.tpl', $force_compile = false, $time_limit = 0, $max_errors = null)
|
||||
$smarty->clearCompiledTemplate($resource_name = null, $compile_id = null, $exp_time = null)
|
||||
$smarty->testInstall()
|
||||
|
||||
// then all the getters/setters, available for all properties. Here are a few:
|
||||
|
||||
$caching = $smarty->getCaching(); // get $smarty->caching
|
||||
$smarty->setCaching(true); // set $smarty->caching
|
||||
$smarty->setDeprecationNotices(false); // set $smarty->deprecation_notices
|
||||
$smarty->setCacheId($id); // set $smarty->cache_id
|
||||
$debugging = $smarty->getDebugging(); // get $smarty->debugging
|
||||
|
||||
|
||||
FILE STRUCTURE
|
||||
|
||||
The Smarty 3 file structure is similar to Smarty 2:
|
||||
|
||||
/libs/
|
||||
Smarty.class.php
|
||||
/libs/sysplugins/
|
||||
internal.*
|
||||
/libs/plugins/
|
||||
function.mailto.php
|
||||
modifier.escape.php
|
||||
...
|
||||
|
||||
A lot of Smarty 3 core functionality lies in the sysplugins directory; you do
|
||||
not need to change any files here. The /libs/plugins/ folder is where Smarty
|
||||
plugins are located. You can add your own here, or create a separate plugin
|
||||
directory, just the same as Smarty 2. You will still need to create your own
|
||||
/cache/, /templates/, /templates_c/, /configs/ folders. Be sure /cache/ and
|
||||
/templates_c/ are writable.
|
||||
|
||||
The typical way to use Smarty 3 should also look familiar:
|
||||
|
||||
require('Smarty.class.php');
|
||||
$smarty = new Smarty;
|
||||
$smarty->assign('foo','bar');
|
||||
$smarty->display('index.tpl');
|
||||
|
||||
|
||||
However, Smarty 3 works completely different on the inside. Smarty 3 is mostly
|
||||
backward compatible with Smarty 2, except for the following items:
|
||||
|
||||
*) Smarty 3 is PHP 5 only. It will not work with PHP 4.
|
||||
*) The {php} tag is disabled by default. Enable with $smarty->allow_php_tag=true.
|
||||
*) Delimiters surrounded by whitespace are no longer treated as Smarty tags.
|
||||
Therefore, { foo } will not compile as a tag, you must use {foo}. This change
|
||||
Makes Javascript/CSS easier to work with, eliminating the need for {literal}.
|
||||
This can be disabled by setting $smarty->auto_literal = false;
|
||||
*) The Smarty 3 API is a bit different. Many Smarty 2 API calls are deprecated
|
||||
but still work. You will want to update your calls to Smarty 3 for maximum
|
||||
efficiency.
|
||||
|
||||
|
||||
There are many things that are new to Smarty 3. Here are the notable items:
|
||||
|
||||
LEXER/PARSER
|
||||
============
|
||||
|
||||
Smarty 3 now uses a lexing tokenizer for its parser/compiler. Basically, this
|
||||
means Smarty has some syntax additions that make life easier such as in-template
|
||||
math, shorter/intuitive function parameter options, infinite function recursion,
|
||||
more accurate error handling, etc.
|
||||
|
||||
|
||||
WHAT IS NEW IN SMARTY TEMPLATE SYNTAX
|
||||
=====================================
|
||||
|
||||
Smarty 3 allows expressions almost anywhere. Expressions can include PHP
|
||||
functions as long as they are not disabled by the security policy, object
|
||||
methods and properties, etc. The {math} plugin is no longer necessary but
|
||||
is still supported for BC.
|
||||
|
||||
Examples:
|
||||
{$x+$y} will output the sum of x and y.
|
||||
{$foo = strlen($bar)} function in assignment
|
||||
{assign var=foo value= $x+$y} in attributes
|
||||
{$foo = myfunct( ($x+$y)*3 )} as function parameter
|
||||
{$foo[$x+3]} as array index
|
||||
|
||||
Smarty tags can be used as values within other tags.
|
||||
Example: {$foo={counter}+3}
|
||||
|
||||
Smarty tags can also be used inside double quoted strings.
|
||||
Example: {$foo="this is message {counter}"}
|
||||
|
||||
You can define arrays within templates.
|
||||
Examples:
|
||||
{assign var=foo value=[1,2,3]}
|
||||
{assign var=foo value=['y'=>'yellow','b'=>'blue']}
|
||||
Arrays can be nested.
|
||||
{assign var=foo value=[1,[9,8],3]}
|
||||
|
||||
There is a new short syntax supported for assigning variables.
|
||||
Example: {$foo=$bar+2}
|
||||
|
||||
You can assign a value to a specific array element. If the variable exists but
|
||||
is not an array, it is converted to an array before the new values are assigned.
|
||||
Examples:
|
||||
{$foo['bar']=1}
|
||||
{$foo['bar']['blar']=1}
|
||||
|
||||
You can append values to an array. If the variable exists but is not an array,
|
||||
it is converted to an array before the new values are assigned.
|
||||
Example: {$foo[]=1}
|
||||
|
||||
You can use a PHP-like syntax for accessing array elements, as well as the
|
||||
original "dot" notation.
|
||||
Examples:
|
||||
{$foo[1]} normal access
|
||||
{$foo['bar']}
|
||||
{$foo['bar'][1]}
|
||||
{$foo[$x+$x]} index may contain any expression
|
||||
{$foo[$bar[1]]} nested index
|
||||
{$foo[section_name]} smarty section access, not array access!
|
||||
|
||||
The original "dot" notation stays, and with improvements.
|
||||
Examples:
|
||||
{$foo.a.b.c} => $foo['a']['b']['c']
|
||||
{$foo.a.$b.c} => $foo['a'][$b]['c'] with variable index
|
||||
{$foo.a.{$b+4}.c} => $foo['a'][$b+4]['c'] with expression as index
|
||||
{$foo.a.{$b.c}} => $foo['a'][$b['c']] with nested index
|
||||
|
||||
note that { and } are used to address ambiguties when nesting the dot syntax.
|
||||
|
||||
Variable names themselves can be variable and contain expressions.
|
||||
Examples:
|
||||
$foo normal variable
|
||||
$foo_{$bar} variable name containing other variable
|
||||
$foo_{$x+$y} variable name containing expressions
|
||||
$foo_{$bar}_buh_{$blar} variable name with multiple segments
|
||||
{$foo_{$x}} will output the variable $foo_1 if $x has a value of 1.
|
||||
|
||||
Object method chaining is implemented.
|
||||
Example: {$object->method1($x)->method2($y)}
|
||||
|
||||
{for} tag added for looping (replacement for {section} tag):
|
||||
{for $x=0, $y=count($foo); $x<$y; $x++} .... {/for}
|
||||
Any number of statements can be used separated by comma as the first
|
||||
inital expression at {for}.
|
||||
|
||||
{for $x = $start to $end step $step} ... {/for}is in the SVN now .
|
||||
You can use also
|
||||
{for $x = $start to $end} ... {/for}
|
||||
In this case the step value will be automaticall 1 or -1 depending on the start and end values.
|
||||
Instead of $start and $end you can use any valid expression.
|
||||
Inside the loop the following special vars can be accessed:
|
||||
$x@iteration = number of iteration
|
||||
$x@total = total number of iterations
|
||||
$x@first = true on first iteration
|
||||
$x@last = true on last iteration
|
||||
|
||||
|
||||
The Smarty 2 {section} syntax is still supported.
|
||||
|
||||
New shorter {foreach} syntax to loop over an array.
|
||||
Example: {foreach $myarray as $var}...{/foreach}
|
||||
|
||||
Within the foreach loop, properties are access via:
|
||||
|
||||
$var@key foreach $var array key
|
||||
$var@iteration foreach current iteration count (1,2,3...)
|
||||
$var@index foreach current index count (0,1,2...)
|
||||
$var@total foreach $var array total
|
||||
$var@first true on first iteration
|
||||
$var@last true on last iteration
|
||||
|
||||
The Smarty 2 {foreach} tag syntax is still supported.
|
||||
|
||||
NOTE: {$bar[foo]} still indicates a variable inside of a {section} named foo.
|
||||
If you want to access an array element with index foo, you must use quotes
|
||||
such as {$bar['foo']}, or use the dot syntax {$bar.foo}.
|
||||
|
||||
while block tag is now implemented:
|
||||
{while $foo}...{/while}
|
||||
{while $x lt 10}...{/while}
|
||||
|
||||
Direct access to PHP functions:
|
||||
Just as you can use PHP functions as modifiers directly, you can now access
|
||||
PHP functions directly, provided they are permitted by security settings:
|
||||
{time()}
|
||||
|
||||
There is a new {function}...{/function} block tag to implement a template function.
|
||||
This enables reuse of code sequences like a plugin function. It can call itself recursively.
|
||||
Template function must be called with the new {call name=foo...} tag.
|
||||
|
||||
Example:
|
||||
|
||||
Template file:
|
||||
{function name=menu level=0}
|
||||
<ul class="level{$level}">
|
||||
{foreach $data as $entry}
|
||||
{if is_array($entry)}
|
||||
<li>{$entry@key}</li>
|
||||
{call name=menu data=$entry level=$level+1}
|
||||
{else}
|
||||
<li>{$entry}</li>
|
||||
{/if}
|
||||
{/foreach}
|
||||
</ul>
|
||||
{/function}
|
||||
|
||||
{$menu = ['item1','item2','item3' => ['item3-1','item3-2','item3-3' =>
|
||||
['item3-3-1','item3-3-2']],'item4']}
|
||||
|
||||
{call name=menu data=$menu}
|
||||
|
||||
|
||||
Generated output:
|
||||
* item1
|
||||
* item2
|
||||
* item3
|
||||
o item3-1
|
||||
o item3-2
|
||||
o item3-3
|
||||
+ item3-3-1
|
||||
+ item3-3-2
|
||||
* item4
|
||||
|
||||
The function tag itself must have the "name" attribute. This name is the tag
|
||||
name when calling the function. The function tag may have any number of
|
||||
additional attributes. These will be default settings for local variables.
|
||||
|
||||
New {nocache} block function:
|
||||
{nocache}...{/nocache} will declare a section of the template to be non-cached
|
||||
when template caching is enabled.
|
||||
|
||||
New nocache attribute:
|
||||
You can declare variable/function output as non-cached with the nocache attribute.
|
||||
Examples:
|
||||
|
||||
{$foo nocache=true}
|
||||
{$foo nocache} /* same */
|
||||
|
||||
{foo bar="baz" nocache=true}
|
||||
{foo bar="baz" nocache} /* same */
|
||||
|
||||
{time() nocache=true}
|
||||
{time() nocache} /* same */
|
||||
|
||||
Or you can also assign the variable in your script as nocache:
|
||||
$smarty->assign('foo',$something,true); // third param is nocache setting
|
||||
{$foo} /* non-cached */
|
||||
|
||||
$smarty.current_dir returns the directory name of the current template.
|
||||
|
||||
You can use strings directly as templates with the "string" resource type.
|
||||
Examples:
|
||||
$smarty->display('string:This is my template, {$foo}!'); // php
|
||||
{include file="string:This is my template, {$foo}!"} // template
|
||||
|
||||
|
||||
|
||||
VARIABLE SCOPE / VARIABLE STORAGE
|
||||
=================================
|
||||
|
||||
In Smarty 2, all assigned variables were stored within the Smarty object.
|
||||
Therefore, all variables assigned in PHP were accessible by all subsequent
|
||||
fetch and display template calls.
|
||||
|
||||
In Smarty 3, we have the choice to assign variables to the main Smarty object,
|
||||
to user-created data objects, and to user-created template objects.
|
||||
These objects can be chained. The object at the end of a chain can access all
|
||||
variables belonging to that template and all variables within the parent objects.
|
||||
The Smarty object can only be the root of a chain, but a chain can be isolated
|
||||
from the Smarty object.
|
||||
|
||||
All known Smarty assignment interfaces will work on the data and template objects.
|
||||
|
||||
Besides the above mentioned objects, there is also a special storage area for
|
||||
global variables.
|
||||
|
||||
A Smarty data object can be created as follows:
|
||||
$data = $smarty->createData(); // create root data object
|
||||
$data->assign('foo','bar'); // assign variables as usual
|
||||
$data->config_load('my.conf'); // load config file
|
||||
|
||||
$data= $smarty->createData($smarty); // create data object having a parent link to
|
||||
the Smarty object
|
||||
|
||||
$data2= $smarty->createData($data); // create data object having a parent link to
|
||||
the $data data object
|
||||
|
||||
A template object can be created by using the createTemplate method. It has the
|
||||
same parameter assignments as the fetch() or display() method.
|
||||
Function definition:
|
||||
function createTemplate($template, $cache_id = null, $compile_id = null, $parent = null)
|
||||
|
||||
The first parameter can be a template name, a smarty object or a data object.
|
||||
|
||||
Examples:
|
||||
$tpl = $smarty->createTemplate('mytpl.tpl'); // create template object not linked to any parent
|
||||
$tpl->assign('foo','bar'); // directly assign variables
|
||||
$tpl->config_load('my.conf'); // load config file
|
||||
|
||||
$tpl = $smarty->createTemplate('mytpl.tpl',$smarty); // create template having a parent link to the Smarty object
|
||||
$tpl = $smarty->createTemplate('mytpl.tpl',$data); // create template having a parent link to the $data object
|
||||
|
||||
The standard fetch() and display() methods will implicitly create a template object.
|
||||
If the $parent parameter is not specified in these method calls, the template object
|
||||
is will link back to the Smarty object as it's parent.
|
||||
|
||||
If a template is called by an {include...} tag from another template, the
|
||||
subtemplate links back to the calling template as it's parent.
|
||||
|
||||
All variables assigned locally or from a parent template are accessible. If the
|
||||
template creates or modifies a variable by using the {assign var=foo...} or
|
||||
{$foo=...} tags, these new values are only known locally (local scope). When the
|
||||
template exits, none of the new variables or modifications can be seen in the
|
||||
parent template(s). This is same behavior as in Smarty 2.
|
||||
|
||||
With Smarty 3, we can assign variables with a scope attribute which allows the
|
||||
availablility of these new variables or modifications globally (ie in the parent
|
||||
templates.)
|
||||
|
||||
Possible scopes are local, parent, root and global.
|
||||
Examples:
|
||||
{assign var=foo value='bar'} // no scope is specified, the default 'local'
|
||||
{$foo='bar'} // same, local scope
|
||||
{assign var=foo value='bar' scope='local'} // same, local scope
|
||||
|
||||
{assign var=foo value='bar' scope='parent'} // Values will be available to the parent object
|
||||
{$foo='bar' scope='parent'} // (normally the calling template)
|
||||
|
||||
{assign var=foo value='bar' scope='root'} // Values will be exported up to the root object, so they can
|
||||
{$foo='bar' scope='root'} // be seen from all templates using the same root.
|
||||
|
||||
{assign var=foo value='bar' scope='global'} // Values will be exported to global variable storage,
|
||||
{$foo='bar' scope='global'} // they are available to any and all templates.
|
||||
|
||||
|
||||
The scope attribute can also be attached to the {include...} tag. In this case,
|
||||
the specified scope will be the default scope for all assignments within the
|
||||
included template.
|
||||
|
||||
|
||||
PLUGINS
|
||||
=======
|
||||
|
||||
Smarty3 are following the same coding rules as in Smarty2.
|
||||
The only difference is that the template object is passed as additional third parameter.
|
||||
|
||||
smarty_plugintype_name (array $params, object $smarty, object $template)
|
||||
|
||||
The Smarty 2 plugins are still compatible as long as they do not make use of specific Smarty2 internals.
|
||||
|
||||
|
||||
TEMPLATE INHERITANCE:
|
||||
=====================
|
||||
|
||||
With template inheritance you can define blocks, which are areas that can be
|
||||
overriden by child templates, so your templates could look like this:
|
||||
|
||||
parent.tpl:
|
||||
<html>
|
||||
<head>
|
||||
<title>{block name='title'}My site name{/block}</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>{block name='page-title'}Default page title{/block}</h1>
|
||||
<div id="content">
|
||||
{block name='content'}
|
||||
Default content
|
||||
{/block}
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
child.tpl:
|
||||
{extends file='parent.tpl'}
|
||||
{block name='title'}
|
||||
Child title
|
||||
{/block}
|
||||
|
||||
grandchild.tpl:
|
||||
{extends file='child.tpl'}
|
||||
{block name='title'}Home - {$smarty.block.parent}{/block}
|
||||
{block name='page-title'}My home{/block}
|
||||
{block name='content'}
|
||||
{foreach $images as $img}
|
||||
<img src="{$img.url}" alt="{$img.description}" />
|
||||
{/foreach}
|
||||
{/block}
|
||||
|
||||
We redefined all the blocks here, however in the title block we used {$smarty.block.parent},
|
||||
which tells Smarty to insert the default content from the parent template in its place.
|
||||
The content block was overriden to display the image files, and page-title has also be
|
||||
overriden to display a completely different title.
|
||||
|
||||
If we render grandchild.tpl we will get this:
|
||||
<html>
|
||||
<head>
|
||||
<title>Home - Child title</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>My home</h1>
|
||||
<div id="content">
|
||||
<img src="/example.jpg" alt="image" />
|
||||
<img src="/example2.jpg" alt="image" />
|
||||
<img src="/example3.jpg" alt="image" />
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
NOTE: In the child templates everything outside the {extends} or {block} tag sections
|
||||
is ignored.
|
||||
|
||||
The inheritance tree can be as big as you want (meaning you can extend a file that
|
||||
extends another one that extends another one and so on..), but be aware that all files
|
||||
have to be checked for modifications at runtime so the more inheritance the more overhead you add.
|
||||
|
||||
Instead of defining the parent/child relationships with the {extends} tag in the child template you
|
||||
can use the resource as follow:
|
||||
|
||||
$smarty->display('extends:parent.tpl|child.tpl|grandchild.tpl');
|
||||
|
||||
Child {block} tags may optionally have a append or prepend attribute. In this case the parent block content
|
||||
is appended or prepended to the child block content.
|
||||
|
||||
{block name='title' append} My title {/block}
|
||||
|
||||
|
||||
PHP STREAMS:
|
||||
============
|
||||
|
||||
(see online documentation)
|
||||
|
||||
VARIBLE FILTERS:
|
||||
================
|
||||
|
||||
(see online documentation)
|
||||
|
||||
|
||||
STATIC CLASS ACCESS AND NAMESPACE SUPPORT
|
||||
=========================================
|
||||
|
||||
You can register a class with optional namespace for the use in the template like:
|
||||
|
||||
$smarty->register->templateClass('foo','name\name2\myclass');
|
||||
|
||||
In the template you can use it like this:
|
||||
{foo::method()} etc.
|
||||
|
||||
|
||||
=======================
|
||||
|
||||
Please look through it and send any questions/suggestions/etc to the forums.
|
||||
|
||||
http://www.phpinsider.com/smarty-forum/viewtopic.php?t=14168
|
||||
|
||||
Monte and Uwe
|
|
@ -0,0 +1,109 @@
|
|||
= Known incompatibilities with Smarty 2 =
|
||||
|
||||
== Syntax ==
|
||||
|
||||
Smarty 3 API has a new syntax. Much of the Smarty 2 syntax is supported
|
||||
by a wrapper but deprecated. See the README that comes with Smarty 3 for more
|
||||
information.
|
||||
|
||||
The {$array|@mod} syntax has always been a bit confusing, where an "@" is required
|
||||
to apply a modifier to an array instead of the individual elements. Normally you
|
||||
always want the modifier to apply to the variable regardless of its type. In Smarty 3,
|
||||
{$array|mod} and {$array|@mod} behave identical. It is safe to drop the "@" and the
|
||||
modifier will still apply to the array. If you really want the modifier to apply to
|
||||
each array element, you must loop the array in-template, or use a custom modifier that
|
||||
supports array iteration. Most smarty functions already escape values where necessary
|
||||
such as {html_options}
|
||||
|
||||
== PHP Version ==
|
||||
Smarty 3 is PHP 5 only. It will not work with PHP 4.
|
||||
|
||||
== {php} Tag ==
|
||||
The {php} tag is disabled by default. The use of {php} tags is
|
||||
deprecated. It can be enabled with $smarty->allow_php_tag=true.
|
||||
|
||||
But if you scatter PHP code which belongs together into several
|
||||
{php} tags it may not work any longer.
|
||||
|
||||
== Delimiters and whitespace ==
|
||||
Delimiters surrounded by whitespace are no longer treated as Smarty tags.
|
||||
Therefore, { foo } will not compile as a tag, you must use {foo}. This change
|
||||
Makes Javascript/CSS easier to work with, eliminating the need for {literal}.
|
||||
This can be disabled by setting $smarty->auto_literal = false;
|
||||
|
||||
== Unquoted Strings ==
|
||||
Smarty 2 was a bit more forgiving (and ambiguous) when it comes to unquoted strings
|
||||
in parameters. Smarty3 is more restrictive. You can still pass strings without quotes
|
||||
so long as they contain no special characters. (anything outside of A-Za-z0-9_)
|
||||
|
||||
For example filename strings must be quoted
|
||||
<source lang="smarty">
|
||||
{include file='path/foo.tpl'}
|
||||
</source>
|
||||
|
||||
== Extending the Smarty class ==
|
||||
Smarty 3 makes use of the __construct method for initialization. If you are extending
|
||||
the Smarty class, its constructor is not called implicitly if the your child class defines
|
||||
its own constructor. In order to run Smarty's constructor, a call to parent::__construct()
|
||||
within your child constructor is required.
|
||||
|
||||
<source lang="php">
|
||||
class MySmarty extends Smarty {
|
||||
function __construct() {
|
||||
parent::__construct();
|
||||
|
||||
// your initialization code goes here
|
||||
|
||||
}
|
||||
}
|
||||
</source>
|
||||
|
||||
== Autoloader ==
|
||||
Smarty 3 does register its own autoloader with spl_autoload_register. If your code has
|
||||
an existing __autoload function then this function must be explicitly registered on
|
||||
the __autoload stack. See http://us3.php.net/manual/en/function.spl-autoload-register.php
|
||||
for further details.
|
||||
|
||||
== Plugin Filenames ==
|
||||
Smarty 3 optionally supports the PHP spl_autoloader. The autoloader requires filenames
|
||||
to be lower case. Because of this, Smarty plugin file names must also be lowercase.
|
||||
In Smarty 2, mixed case file names did work.
|
||||
|
||||
== Scope of Special Smarty Variables ==
|
||||
In Smarty 2 the special Smarty variables $smarty.section... and $smarty.foreach...
|
||||
had global scope. If you had loops with the same name in subtemplates you could accidentally
|
||||
overwrite values of parent template.
|
||||
|
||||
In Smarty 3 these special Smarty variable have only local scope in the template which
|
||||
is defining the loop. If you need their value in a subtemplate you have to pass them
|
||||
as parameter.
|
||||
<source lang="smarty">
|
||||
{include file='path/foo.tpl' index=$smarty.section.foo.index}
|
||||
</source>
|
||||
|
||||
== SMARTY_RESOURCE_CHAR_SET ==
|
||||
Smarty 3 sets the constant SMARTY_RESOURCE_CHAR_SET to utf-8 as default template charset.
|
||||
This is now used also on modifiers like escape as default charset. If your templates use
|
||||
other charsets make sure that you define the constant accordingly. Otherwise you may not
|
||||
get any output.
|
||||
|
||||
== newline at {if} tags ==
|
||||
A \n was added to the compiled code of the {if},{else},{elseif},{/if} tags to get output of newlines as expected by the template source.
|
||||
If one of the {if} tags is at the line end you will now get a newline in the HTML output.
|
||||
|
||||
== trigger_error() ==
|
||||
The API function trigger_error() has been removed because it did just map to PHP trigger_error.
|
||||
However it's still included in the Smarty2 API wrapper.
|
||||
|
||||
== Smarty constants ==
|
||||
The constants
|
||||
SMARTY_PHP_PASSTHRU
|
||||
SMARTY_PHP_QUOTE
|
||||
SMARTY_PHP_REMOVE
|
||||
SMARTY_PHP_ALLOW
|
||||
have been replaced with class constants
|
||||
Smarty::PHP_PASSTHRU
|
||||
Smarty::PHP_QUOTE
|
||||
Smarty::PHP_REMOVE
|
||||
Smarty::PHP_ALLOW
|
||||
|
|
@ -0,0 +1,807 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Project: Smarty: the PHP compiling template engine
|
||||
* File: Smarty.class.php
|
||||
* SVN: $Id: Smarty.class.php 3794 2010-11-15 22:54:59Z uwe.tews@googlemail.com $
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* For questions, help, comments, discussion, etc., please join the
|
||||
* Smarty mailing list. Send a blank e-mail to
|
||||
* smarty-discussion-subscribe@googlegroups.com
|
||||
*
|
||||
* @link http://www.smarty.net/
|
||||
* @copyright 2008 New Digital Group, Inc.
|
||||
* @author Monte Ohrt <monte at ohrt dot com>
|
||||
* @author Uwe Tews
|
||||
* @package Smarty
|
||||
* @version 3.0.5
|
||||
*/
|
||||
|
||||
/**
|
||||
* define shorthand directory separator constant
|
||||
*/
|
||||
if (!defined('DS')) {
|
||||
define('DS', DIRECTORY_SEPARATOR);
|
||||
}
|
||||
|
||||
/**
|
||||
* set SMARTY_DIR to absolute path to Smarty library files.
|
||||
* Sets SMARTY_DIR only if user application has not already defined it.
|
||||
*/
|
||||
if (!defined('SMARTY_DIR')) {
|
||||
define('SMARTY_DIR', dirname(__FILE__) . DS);
|
||||
}
|
||||
|
||||
/**
|
||||
* set SMARTY_SYSPLUGINS_DIR to absolute path to Smarty internal plugins.
|
||||
* Sets SMARTY_SYSPLUGINS_DIR only if user application has not already defined it.
|
||||
*/
|
||||
if (!defined('SMARTY_SYSPLUGINS_DIR')) {
|
||||
define('SMARTY_SYSPLUGINS_DIR', SMARTY_DIR . 'sysplugins' . DS);
|
||||
}
|
||||
if (!defined('SMARTY_PLUGINS_DIR')) {
|
||||
define('SMARTY_PLUGINS_DIR', SMARTY_DIR . 'plugins' . DS);
|
||||
}
|
||||
if (!defined('SMARTY_RESOURCE_CHAR_SET')) {
|
||||
define('SMARTY_RESOURCE_CHAR_SET', 'UTF-8');
|
||||
}
|
||||
if (!defined('SMARTY_RESOURCE_DATE_FORMAT')) {
|
||||
define('SMARTY_RESOURCE_DATE_FORMAT', '%b %e, %Y');
|
||||
}
|
||||
|
||||
/**
|
||||
* register the class autoloader
|
||||
*/
|
||||
if (!defined('SMARTY_SPL_AUTOLOAD')) {
|
||||
define('SMARTY_SPL_AUTOLOAD', 0);
|
||||
}
|
||||
|
||||
if (SMARTY_SPL_AUTOLOAD && set_include_path(get_include_path() . PATH_SEPARATOR . SMARTY_SYSPLUGINS_DIR) !== false) {
|
||||
$registeredAutoLoadFunctions = spl_autoload_functions();
|
||||
if (!isset($registeredAutoLoadFunctions['spl_autoload'])) {
|
||||
spl_autoload_register();
|
||||
}
|
||||
} else {
|
||||
spl_autoload_register('smartyAutoload');
|
||||
}
|
||||
|
||||
/**
|
||||
* This is the main Smarty class
|
||||
*/
|
||||
class Smarty extends Smarty_Internal_Data {
|
||||
/**
|
||||
* constant definitions
|
||||
*/
|
||||
// smarty version
|
||||
const SMARTY_VERSION = 'Smarty-3.0.5';
|
||||
//define variable scopes
|
||||
const SCOPE_LOCAL = 0;
|
||||
const SCOPE_PARENT = 1;
|
||||
const SCOPE_ROOT = 2;
|
||||
const SCOPE_GLOBAL = 3;
|
||||
// define caching modes
|
||||
const CACHING_OFF = 0;
|
||||
const CACHING_LIFETIME_CURRENT = 1;
|
||||
const CACHING_LIFETIME_SAVED = 2;
|
||||
/** modes for handling of "<?php ... ?>" tags in templates. **/
|
||||
const PHP_PASSTHRU = 0; //-> print tags as plain text
|
||||
const PHP_QUOTE = 1; //-> escape tags as entities
|
||||
const PHP_REMOVE = 2; //-> escape tags as entities
|
||||
const PHP_ALLOW = 3; //-> escape tags as entities
|
||||
// filter types
|
||||
const FILTER_POST = 'post';
|
||||
const FILTER_PRE = 'pre';
|
||||
const FILTER_OUTPUT = 'output';
|
||||
const FILTER_VARIABLE = 'variable';
|
||||
// plugin types
|
||||
const PLUGIN_FUNCTION = 'function';
|
||||
const PLUGIN_BLOCK = 'block';
|
||||
const PLUGIN_COMPILER = 'compiler';
|
||||
const PLUGIN_MODIFIER = 'modifier';
|
||||
|
||||
/**
|
||||
* static variables
|
||||
*/
|
||||
// assigned global tpl vars
|
||||
static $global_tpl_vars = array();
|
||||
|
||||
/**
|
||||
* variables
|
||||
*/
|
||||
// auto literal on delimiters with whitspace
|
||||
public $auto_literal = true;
|
||||
// display error on not assigned variables
|
||||
public $error_unassigned = false;
|
||||
// template directory
|
||||
public $template_dir = null;
|
||||
// default template handler
|
||||
public $default_template_handler_func = null;
|
||||
// compile directory
|
||||
public $compile_dir = null;
|
||||
// plugins directory
|
||||
public $plugins_dir = null;
|
||||
// cache directory
|
||||
public $cache_dir = null;
|
||||
// config directory
|
||||
public $config_dir = null;
|
||||
// force template compiling?
|
||||
public $force_compile = false;
|
||||
// check template for modifications?
|
||||
public $compile_check = true;
|
||||
// locking concurrent compiles
|
||||
public $compile_locking = true;
|
||||
// use sub dirs for compiled/cached files?
|
||||
public $use_sub_dirs = false;
|
||||
// compile_error?
|
||||
public $compile_error = false;
|
||||
// caching enabled
|
||||
public $caching = false;
|
||||
// merge compiled includes
|
||||
public $merge_compiled_includes = false;
|
||||
// cache lifetime
|
||||
public $cache_lifetime = 3600;
|
||||
// force cache file creation
|
||||
public $force_cache = false;
|
||||
// cache_id
|
||||
public $cache_id = null;
|
||||
// compile_id
|
||||
public $compile_id = null;
|
||||
// template delimiters
|
||||
public $left_delimiter = "{";
|
||||
public $right_delimiter = "}";
|
||||
// security
|
||||
public $security_class = 'Smarty_Security';
|
||||
public $security_policy = null;
|
||||
public $php_handling = self::PHP_PASSTHRU;
|
||||
public $allow_php_tag = false;
|
||||
public $allow_php_templates = false;
|
||||
public $direct_access_security = true;
|
||||
public $trusted_dir = array();
|
||||
// debug mode
|
||||
public $debugging = false;
|
||||
public $debugging_ctrl = 'NONE';
|
||||
public $smarty_debug_id = 'SMARTY_DEBUG';
|
||||
public $debug_tpl = null;
|
||||
// When set, smarty does uses this value as error_reporting-level.
|
||||
public $error_reporting = null;
|
||||
// config var settings
|
||||
public $config_overwrite = true; //Controls whether variables with the same name overwrite each other.
|
||||
public $config_booleanize = true; //Controls whether config values of on/true/yes and off/false/no get converted to boolean
|
||||
public $config_read_hidden = true; //Controls whether hidden config sections/vars are read from the file.
|
||||
// config vars
|
||||
public $config_vars = array();
|
||||
// assigned tpl vars
|
||||
public $tpl_vars = array();
|
||||
// dummy parent object
|
||||
public $parent = null;
|
||||
// global template functions
|
||||
public $template_functions = array();
|
||||
// resource type used if none given
|
||||
public $default_resource_type = 'file';
|
||||
// caching type
|
||||
public $caching_type = 'file';
|
||||
// internal cache resource types
|
||||
public $cache_resource_types = array('file');
|
||||
// internal config properties
|
||||
public $properties = array();
|
||||
// config type
|
||||
public $default_config_type = 'file';
|
||||
// cached template objects
|
||||
public $template_objects = null;
|
||||
// check If-Modified-Since headers
|
||||
public $cache_modified_check = false;
|
||||
// registered plugins
|
||||
public $registered_plugins = array();
|
||||
// plugin search order
|
||||
public $plugin_search_order = array('function', 'block', 'compiler', 'class');
|
||||
// registered objects
|
||||
public $registered_objects = array();
|
||||
// registered classes
|
||||
public $registered_classes = array();
|
||||
// registered filters
|
||||
public $registered_filters = array();
|
||||
// registered resources
|
||||
public $registered_resources = array();
|
||||
// autoload filter
|
||||
public $autoload_filters = array();
|
||||
// status of filter on variable output
|
||||
public $variable_filter = true;
|
||||
// default modifier
|
||||
public $default_modifiers = array();
|
||||
// global internal smarty vars
|
||||
static $_smarty_vars = array();
|
||||
// start time for execution time calculation
|
||||
public $start_time = 0;
|
||||
// default file permissions
|
||||
public $_file_perms = 0644;
|
||||
// default dir permissions
|
||||
public $_dir_perms = 0771;
|
||||
// block tag hierarchy
|
||||
public $_tag_stack = array();
|
||||
// flag if {block} tag is compiled for template inheritance
|
||||
public $inheritance = false;
|
||||
// generate deprecated function call notices?
|
||||
public $deprecation_notices = true;
|
||||
// Smarty 2 BC
|
||||
public $_version = self::SMARTY_VERSION;
|
||||
|
||||
/**
|
||||
* Class constructor, initializes basic smarty properties
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
// selfpointer need by some other class methods
|
||||
$this->smarty = $this;
|
||||
if (is_callable('mb_internal_encoding')) {
|
||||
mb_internal_encoding(SMARTY_RESOURCE_CHAR_SET);
|
||||
}
|
||||
$this->start_time = microtime(true);
|
||||
// set default dirs
|
||||
$this->template_dir = array('.' . DS . 'templates' . DS);
|
||||
$this->compile_dir = '.' . DS . 'templates_c' . DS;
|
||||
$this->plugins_dir = array(SMARTY_PLUGINS_DIR);
|
||||
$this->cache_dir = '.' . DS . 'cache' . DS;
|
||||
$this->config_dir = '.' . DS . 'configs' . DS;
|
||||
$this->debug_tpl = SMARTY_DIR . 'debug.tpl';
|
||||
if (!$this->debugging && $this->debugging_ctrl == 'URL') {
|
||||
if (isset($_SERVER['QUERY_STRING'])) {
|
||||
$_query_string = $_SERVER['QUERY_STRING'];
|
||||
} else {
|
||||
$_query_string = '';
|
||||
}
|
||||
if (false !== strpos($_query_string, $this->smarty_debug_id)) {
|
||||
if (false !== strpos($_query_string, $this->smarty_debug_id . '=on')) {
|
||||
// enable debugging for this browser session
|
||||
setcookie('SMARTY_DEBUG', true);
|
||||
$this->debugging = true;
|
||||
} elseif (false !== strpos($_query_string, $this->smarty_debug_id . '=off')) {
|
||||
// disable debugging for this browser session
|
||||
setcookie('SMARTY_DEBUG', false);
|
||||
$this->debugging = false;
|
||||
} else {
|
||||
// enable debugging for this page
|
||||
$this->debugging = true;
|
||||
}
|
||||
} else {
|
||||
if (isset($_COOKIE['SMARTY_DEBUG'])) {
|
||||
$this->debugging = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (isset($_SERVER['SCRIPT_NAME'])) {
|
||||
$this->assignGlobal('SCRIPT_NAME', $_SERVER['SCRIPT_NAME']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Class destructor
|
||||
*/
|
||||
public function __destruct()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* fetches a rendered Smarty template
|
||||
*
|
||||
* @param string $template the resource handle of the template file or template object
|
||||
* @param mixed $cache_id cache id to be used with this template
|
||||
* @param mixed $compile_id compile id to be used with this template
|
||||
* @param object $ |null $parent next higher level of Smarty variables
|
||||
* @return string rendered template output
|
||||
*/
|
||||
public function fetch($template, $cache_id = null, $compile_id = null, $parent = null, $display = false)
|
||||
{
|
||||
if (!empty($cache_id) && is_object($cache_id)) {
|
||||
$parent = $cache_id;
|
||||
$cache_id = null;
|
||||
}
|
||||
if ($parent === null) {
|
||||
// get default Smarty data object
|
||||
$parent = $this;
|
||||
}
|
||||
// create template object if necessary
|
||||
($template instanceof $this->template_class)? $_template = $template :
|
||||
$_template = $this->createTemplate ($template, $cache_id, $compile_id, $parent);
|
||||
if (isset($this->error_reporting)) {
|
||||
$_smarty_old_error_level = error_reporting($this->error_reporting);
|
||||
}
|
||||
// obtain data for cache modified check
|
||||
if ($this->cache_modified_check && $this->caching && $display) {
|
||||
$_isCached = $_template->isCached() && !$_template->has_nocache_code;
|
||||
if ($_isCached) {
|
||||
$_gmt_mtime = gmdate('D, d M Y H:i:s', $_template->getCachedTimestamp()) . ' GMT';
|
||||
} else {
|
||||
$_gmt_mtime = '';
|
||||
}
|
||||
}
|
||||
// return redered template
|
||||
if (isset($this->autoload_filters['output']) || isset($this->registered_filters['output'])) {
|
||||
$_output = Smarty_Internal_Filter_Handler::runFilter('output', $_template->getRenderedTemplate(), $_template);
|
||||
} else {
|
||||
$_output = $_template->getRenderedTemplate();
|
||||
}
|
||||
$_template->rendered_content = null;
|
||||
if (isset($this->error_reporting)) {
|
||||
error_reporting($_smarty_old_error_level);
|
||||
}
|
||||
// display or fetch
|
||||
if ($display) {
|
||||
if ($this->caching && $this->cache_modified_check) {
|
||||
$_last_modified_date = @substr($_SERVER['HTTP_IF_MODIFIED_SINCE'], 0, strpos($_SERVER['HTTP_IF_MODIFIED_SINCE'], 'GMT') + 3);
|
||||
if ($_isCached && $_gmt_mtime == $_last_modified_date) {
|
||||
if (php_sapi_name() == 'cgi')
|
||||
header('Status: 304 Not Modified');
|
||||
else
|
||||
header('HTTP/1.1 304 Not Modified');
|
||||
} else {
|
||||
header('Last-Modified: ' . gmdate('D, d M Y H:i:s', $_template->getCachedTimestamp()) . ' GMT');
|
||||
echo $_output;
|
||||
}
|
||||
} else {
|
||||
echo $_output;
|
||||
}
|
||||
// debug output
|
||||
if ($this->debugging) {
|
||||
Smarty_Internal_Debug::display_debug($this);
|
||||
}
|
||||
return;
|
||||
} else {
|
||||
// return fetched content
|
||||
return $_output;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* displays a Smarty template
|
||||
*
|
||||
* @param string $ |object $template the resource handle of the template file or template object
|
||||
* @param mixed $cache_id cache id to be used with this template
|
||||
* @param mixed $compile_id compile id to be used with this template
|
||||
* @param object $parent next higher level of Smarty variables
|
||||
*/
|
||||
public function display($template, $cache_id = null, $compile_id = null, $parent = null)
|
||||
{
|
||||
// display template
|
||||
$this->fetch ($template, $cache_id, $compile_id, $parent, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* test if cache i valid
|
||||
*
|
||||
* @param string $ |object $template the resource handle of the template file or template object
|
||||
* @param mixed $cache_id cache id to be used with this template
|
||||
* @param mixed $compile_id compile id to be used with this template
|
||||
* @param object $parent next higher level of Smarty variables
|
||||
* @return boolean cache status
|
||||
*/
|
||||
public function isCached($template, $cache_id = null, $compile_id = null, $parent = null)
|
||||
{
|
||||
if ($parent === null) {
|
||||
$parent = $this;
|
||||
}
|
||||
if (!($template instanceof $this->template_class)) {
|
||||
$template = $this->createTemplate ($template, $cache_id, $compile_id, $parent);
|
||||
}
|
||||
// return cache status of template
|
||||
return $template->isCached();
|
||||
}
|
||||
|
||||
/**
|
||||
* creates a data object
|
||||
*
|
||||
* @param object $parent next higher level of Smarty variables
|
||||
* @returns object data object
|
||||
*/
|
||||
public function createData($parent = null)
|
||||
{
|
||||
return new Smarty_Data($parent, $this);
|
||||
}
|
||||
|
||||
/**
|
||||
* creates a template object
|
||||
*
|
||||
* @param string $template the resource handle of the template file
|
||||
* @param object $parent next higher level of Smarty variables
|
||||
* @param mixed $cache_id cache id to be used with this template
|
||||
* @param mixed $compile_id compile id to be used with this template
|
||||
* @returns object template object
|
||||
*/
|
||||
public function createTemplate($template, $cache_id = null, $compile_id = null, $parent = null)
|
||||
{
|
||||
if (!empty($cache_id) && (is_object($cache_id) || is_array($cache_id))) {
|
||||
$parent = $cache_id;
|
||||
$cache_id = null;
|
||||
}
|
||||
if (!empty($parent) && is_array($parent)) {
|
||||
$data = $parent;
|
||||
$parent = null;
|
||||
} else {
|
||||
$data = null;
|
||||
}
|
||||
if (!is_object($template)) {
|
||||
// we got a template resource
|
||||
// already in template cache?
|
||||
$_templateId = sha1($template . $cache_id . $compile_id);
|
||||
if (isset($this->template_objects[$_templateId]) && $this->caching) {
|
||||
// return cached template object
|
||||
$tpl = $this->template_objects[$_templateId];
|
||||
} else {
|
||||
// create new template object
|
||||
$tpl = new $this->template_class($template, clone $this, $parent, $cache_id, $compile_id);
|
||||
}
|
||||
} else {
|
||||
// just return a copy of template class
|
||||
$tpl = $template;
|
||||
}
|
||||
// fill data if present
|
||||
if (!empty($data) && is_array($data)) {
|
||||
// set up variable values
|
||||
foreach ($data as $_key => $_val) {
|
||||
$tpl->tpl_vars[$_key] = new Smarty_variable($_val);
|
||||
}
|
||||
}
|
||||
return $tpl;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Check if a template resource exists
|
||||
*
|
||||
* @param string $resource_name template name
|
||||
* @return boolean status
|
||||
*/
|
||||
function templateExists($resource_name)
|
||||
{
|
||||
// create template object
|
||||
$save = $this->template_objects;
|
||||
$tpl = new $this->template_class($resource_name, $this);
|
||||
// check if it does exists
|
||||
$result = $tpl->isExisting();
|
||||
$this->template_objects = $save;
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a single or all global variables
|
||||
*
|
||||
* @param object $smarty
|
||||
* @param string $varname variable name or null
|
||||
* @return string variable value or or array of variables
|
||||
*/
|
||||
function getGlobal($varname = null)
|
||||
{
|
||||
if (isset($varname)) {
|
||||
if (isset(self::$global_tpl_vars[$varname])) {
|
||||
return self::$global_tpl_vars[$varname]->value;
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
} else {
|
||||
$_result = array();
|
||||
foreach (self::$global_tpl_vars AS $key => $var) {
|
||||
$_result[$key] = $var->value;
|
||||
}
|
||||
return $_result;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Empty cache folder
|
||||
*
|
||||
* @param integer $exp_time expiration time
|
||||
* @param string $type resource type
|
||||
* @return integer number of cache files deleted
|
||||
*/
|
||||
function clearAllCache($exp_time = null, $type = null)
|
||||
{
|
||||
// load cache resource and call clearAll
|
||||
return $this->loadCacheResource($type)->clearAll($exp_time);
|
||||
}
|
||||
|
||||
/**
|
||||
* Empty cache for a specific template
|
||||
*
|
||||
* @param string $template_name template name
|
||||
* @param string $cache_id cache id
|
||||
* @param string $compile_id compile id
|
||||
* @param integer $exp_time expiration time
|
||||
* @param string $type resource type
|
||||
* @return integer number of cache files deleted
|
||||
*/
|
||||
function clearCache($template_name, $cache_id = null, $compile_id = null, $exp_time = null, $type = null)
|
||||
{
|
||||
// load cache resource and call clear
|
||||
return $this->loadCacheResource($type)->clear($template_name, $cache_id, $compile_id, $exp_time);
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads security class and enables security
|
||||
*/
|
||||
public function enableSecurity($security_class = null)
|
||||
{
|
||||
if ($security_class instanceof Smarty_Security) {
|
||||
$this->security_policy = $security_class;
|
||||
return;
|
||||
}
|
||||
if ($security_class == null) {
|
||||
$security_class = $this->security_class;
|
||||
}
|
||||
if (class_exists($security_class)) {
|
||||
$this->security_policy = new $security_class($this);
|
||||
} else {
|
||||
throw new SmartyException("Security class '$security_class' is not defined");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable security
|
||||
*/
|
||||
public function disableSecurity()
|
||||
{
|
||||
$this->security_policy = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads cache resource.
|
||||
*
|
||||
* @param string $type cache resource type
|
||||
* @return object of cache resource
|
||||
*/
|
||||
public function loadCacheResource($type = null) {
|
||||
if (!isset($type)) {
|
||||
$type = $this->caching_type;
|
||||
}
|
||||
if (in_array($type, $this->cache_resource_types)) {
|
||||
$cache_resource_class = 'Smarty_Internal_CacheResource_' . ucfirst($type);
|
||||
return new $cache_resource_class($this);
|
||||
}
|
||||
else {
|
||||
// try plugins dir
|
||||
$cache_resource_class = 'Smarty_CacheResource_' . ucfirst($type);
|
||||
if ($this->loadPlugin($cache_resource_class)) {
|
||||
return new $cache_resource_class($this);
|
||||
}
|
||||
else {
|
||||
throw new SmartyException("Unable to load cache resource '{$type}'");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set template directory
|
||||
*
|
||||
* @param string $ |array $template_dir folder(s) of template sorces
|
||||
*/
|
||||
public function setTemplateDir($template_dir)
|
||||
{
|
||||
$this->template_dir = (array)$template_dir;
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds template directory(s) to existing ones
|
||||
*
|
||||
* @param string $ |array $template_dir folder(s) of template sources
|
||||
*/
|
||||
public function addTemplateDir($template_dir)
|
||||
{
|
||||
$this->template_dir = array_unique(array_merge((array)$this->template_dir, (array)$template_dir));
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds directory of plugin files
|
||||
*
|
||||
* @param object $smarty
|
||||
* @param string $ |array $ plugins folder
|
||||
* @return
|
||||
*/
|
||||
function addPluginsDir($plugins_dir)
|
||||
{
|
||||
$this->plugins_dir = array_unique(array_merge((array)$this->plugins_dir, (array)$plugins_dir));
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* return a reference to a registered object
|
||||
*
|
||||
* @param string $name object name
|
||||
* @return object
|
||||
*/
|
||||
function getRegisteredObject($name)
|
||||
{
|
||||
if (!isset($this->registered_objects[$name]))
|
||||
throw new SmartyException("'$name' is not a registered object");
|
||||
|
||||
if (!is_object($this->registered_objects[$name][0]))
|
||||
throw new SmartyException("registered '$name' is not an object");
|
||||
|
||||
return $this->registered_objects[$name][0];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* return name of debugging template
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
function getDebugTemplate()
|
||||
{
|
||||
return $this->debug_tpl;
|
||||
}
|
||||
|
||||
/**
|
||||
* set the debug template
|
||||
*
|
||||
* @param string $tpl_name
|
||||
* @return bool
|
||||
*/
|
||||
function setDebugTemplate($tpl_name)
|
||||
{
|
||||
return $this->debug_tpl = $tpl_name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes unknown classes and loads plugin files for them
|
||||
* class name format: Smarty_PluginType_PluginName
|
||||
* plugin filename format: plugintype.pluginname.php
|
||||
*
|
||||
* @param string $plugin_name class plugin name to load
|
||||
* @return string |boolean filepath of loaded file or false
|
||||
*/
|
||||
public function loadPlugin($plugin_name, $check = true)
|
||||
{
|
||||
// if function or class exists, exit silently (already loaded)
|
||||
if ($check && (is_callable($plugin_name) || class_exists($plugin_name, false)))
|
||||
return true;
|
||||
// Plugin name is expected to be: Smarty_[Type]_[Name]
|
||||
$_plugin_name = strtolower($plugin_name);
|
||||
$_name_parts = explode('_', $_plugin_name, 3);
|
||||
// class name must have three parts to be valid plugin
|
||||
if (count($_name_parts) < 3 || $_name_parts[0] !== 'smarty') {
|
||||
throw new SmartyException("plugin {$plugin_name} is not a valid name format");
|
||||
return false;
|
||||
}
|
||||
// if type is "internal", get plugin from sysplugins
|
||||
if ($_name_parts[1] == 'internal') {
|
||||
$file = SMARTY_SYSPLUGINS_DIR . $_plugin_name . '.php';
|
||||
if (file_exists($file)) {
|
||||
require_once($file);
|
||||
return $file;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// plugin filename is expected to be: [type].[name].php
|
||||
$_plugin_filename = "{$_name_parts[1]}.{$_name_parts[2]}.php";
|
||||
// loop through plugin dirs and find the plugin
|
||||
foreach((array)$this->plugins_dir as $_plugin_dir) {
|
||||
if (strpos('/\\', substr($_plugin_dir, -1)) === false) {
|
||||
$_plugin_dir .= DS;
|
||||
}
|
||||
$file = $_plugin_dir . $_plugin_filename;
|
||||
if (file_exists($file)) {
|
||||
require_once($file);
|
||||
return $file;
|
||||
}
|
||||
}
|
||||
// no plugin loaded
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* clean up properties on cloned object
|
||||
*/
|
||||
public function __clone()
|
||||
{
|
||||
// clear config vars
|
||||
$this->config_vars = array();
|
||||
// clear assigned tpl vars
|
||||
$this->tpl_vars = array();
|
||||
// clear objects for external methods
|
||||
unset($this->register);
|
||||
unset($this->filter);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Handle unknown class methods
|
||||
*
|
||||
* @param string $name unknown methode name
|
||||
* @param array $args aurgument array
|
||||
*/
|
||||
public function __call($name, $args)
|
||||
{
|
||||
static $camel_func;
|
||||
if (!isset($camel_func))
|
||||
$camel_func = create_function('$c', 'return "_" . strtolower($c[1]);');
|
||||
// see if this is a set/get for a property
|
||||
$first3 = strtolower(substr($name, 0, 3));
|
||||
if (in_array($first3, array('set', 'get')) && substr($name, 3, 1) !== '_') {
|
||||
// try to keep case correct for future PHP 6.0 case-sensitive class methods
|
||||
// lcfirst() not available < PHP 5.3.0, so improvise
|
||||
$property_name = strtolower(substr($name, 3, 1)) . substr($name, 4);
|
||||
// convert camel case to underscored name
|
||||
$property_name = preg_replace_callback('/([A-Z])/', $camel_func, $property_name);
|
||||
if (!property_exists($this, $property_name)) {
|
||||
throw new SmartyException("property '$property_name' does not exist.");
|
||||
return false;
|
||||
}
|
||||
if ($first3 == 'get')
|
||||
return $this->$property_name;
|
||||
else
|
||||
return $this->$property_name = $args[0];
|
||||
}
|
||||
// Smarty Backward Compatible wrapper
|
||||
if (strpos($name,'_') !== false) {
|
||||
if (!isset($this->wrapper)) {
|
||||
$this->wrapper = new Smarty_Internal_Wrapper($this);
|
||||
}
|
||||
return $this->wrapper->convert($name, $args);
|
||||
}
|
||||
// external Smarty methods ?
|
||||
foreach(array('filter','register') as $external) {
|
||||
if (method_exists("Smarty_Internal_{$external}",$name)) {
|
||||
if (!isset($this->$external)) {
|
||||
$class = "Smarty_Internal_{$external}";
|
||||
$this->$external = new $class($this);
|
||||
}
|
||||
return call_user_func_array(array($this->$external,$name), $args);
|
||||
}
|
||||
}
|
||||
if (in_array($name,array('clearCompiledTemplate','compileAllTemplates','compileAllConfig','testInstall','getTags'))) {
|
||||
if (!isset($this->utility)) {
|
||||
$this->utility = new Smarty_Internal_Utility($this);
|
||||
}
|
||||
return call_user_func_array(array($this->utility,$name), $args);
|
||||
}
|
||||
// PHP4 call to constructor?
|
||||
if (strtolower($name) == 'smarty') {
|
||||
throw new SmartyException('Please use parent::__construct() to call parent constuctor');
|
||||
return false;
|
||||
}
|
||||
throw new SmartyException("Call of unknown function '$name'.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Autoloader
|
||||
*/
|
||||
function smartyAutoload($class)
|
||||
{
|
||||
$_class = strtolower($class);
|
||||
if (substr($_class, 0, 16) === 'smarty_internal_' || $_class == 'smarty_security') {
|
||||
include SMARTY_SYSPLUGINS_DIR . $_class . '.php';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Smarty exception class
|
||||
*/
|
||||
Class SmartyException extends Exception {
|
||||
}
|
||||
|
||||
/**
|
||||
* Smarty compiler exception class
|
||||
*/
|
||||
Class SmartyCompilerException extends SmartyException {
|
||||
}
|
||||
|
||||
?>
|
|
@ -0,0 +1,136 @@
|
|||
{capture name='_smarty_debug' assign=debug_output}
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
|
||||
<head>
|
||||
<title>Smarty Debug Console</title>
|
||||
<style type="text/css">
|
||||
{literal}
|
||||
body, h1, h2, td, th, p {
|
||||
font-family: sans-serif;
|
||||
font-weight: normal;
|
||||
font-size: 0.9em;
|
||||
margin: 1px;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
h1 {
|
||||
margin: 0;
|
||||
text-align: left;
|
||||
padding: 2px;
|
||||
background-color: #f0c040;
|
||||
color: black;
|
||||
font-weight: bold;
|
||||
font-size: 1.2em;
|
||||
}
|
||||
|
||||
h2 {
|
||||
background-color: #9B410E;
|
||||
color: white;
|
||||
text-align: left;
|
||||
font-weight: bold;
|
||||
padding: 2px;
|
||||
border-top: 1px solid black;
|
||||
}
|
||||
|
||||
body {
|
||||
background: black;
|
||||
}
|
||||
|
||||
p, table, div {
|
||||
background: #f0ead8;
|
||||
}
|
||||
|
||||
p {
|
||||
margin: 0;
|
||||
font-style: italic;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
table {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
th, td {
|
||||
font-family: monospace;
|
||||
vertical-align: top;
|
||||
text-align: left;
|
||||
width: 50%;
|
||||
}
|
||||
|
||||
td {
|
||||
color: green;
|
||||
}
|
||||
|
||||
.odd {
|
||||
background-color: #eeeeee;
|
||||
}
|
||||
|
||||
.even {
|
||||
background-color: #fafafa;
|
||||
}
|
||||
|
||||
.exectime {
|
||||
font-size: 0.8em;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
#table_assigned_vars th {
|
||||
color: blue;
|
||||
}
|
||||
|
||||
#table_config_vars th {
|
||||
color: maroon;
|
||||
}
|
||||
{/literal}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<h1>Smarty Debug Console - Total Time {$execution_time|string_format:"%.5f"}</h1>
|
||||
|
||||
<h2>included templates & config files (load time in seconds)</h2>
|
||||
|
||||
<div>
|
||||
{foreach $template_data as $template}
|
||||
<font color=brown>{$template.name}</font>
|
||||
<span class="exectime">
|
||||
(compile {$template['compile_time']|string_format:"%.5f"}) (render {$template['render_time']|string_format:"%.5f"}) (cache {$template['cache_time']|string_format:"%.5f"})
|
||||
</span>
|
||||
<br>
|
||||
{/foreach}
|
||||
</div>
|
||||
|
||||
<h2>assigned template variables</h2>
|
||||
|
||||
<table id="table_assigned_vars">
|
||||
{foreach $assigned_vars as $vars}
|
||||
<tr class="{if $vars@iteration % 2 eq 0}odd{else}even{/if}">
|
||||
<th>${$vars@key|escape:'html'}</th>
|
||||
<td>{$vars|debug_print_var}</td></tr>
|
||||
{/foreach}
|
||||
</table>
|
||||
|
||||
<h2>assigned config file variables (outer template scope)</h2>
|
||||
|
||||
<table id="table_config_vars">
|
||||
{foreach $config_vars as $vars}
|
||||
<tr class="{if $vars@iteration % 2 eq 0}odd{else}even{/if}">
|
||||
<th>{$vars@key|escape:'html'}</th>
|
||||
<td>{$vars|debug_print_var}</td></tr>
|
||||
{/foreach}
|
||||
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
||||
{/capture}
|
||||
<script type="text/javascript">
|
||||
{literal} if ( self.name == '' ) {
|
||||
var title = 'Console';
|
||||
}
|
||||
else {
|
||||
var title = 'Console_' + self.name;
|
||||
}{/literal}
|
||||
_smarty_console = window.open("",title.value,"width=680,height=600,resizable,scrollbars=yes");
|
||||
_smarty_console.document.write("{$debug_output|escape:'javascript'}");
|
||||
_smarty_console.document.close();
|
||||
</script>
|
|
@ -0,0 +1,27 @@
|
|||
<?php
|
||||
/**
|
||||
* Smarty plugin to execute PHP code
|
||||
*
|
||||
* @package Smarty
|
||||
* @subpackage PluginsBlock
|
||||
* @author Uwe Tews
|
||||
*/
|
||||
|
||||
/**
|
||||
* Smarty {php}{/php} block plugin
|
||||
*
|
||||
* @param string $content contents of the block
|
||||
* @param object $template template object
|
||||
* @param boolean $ &$repeat repeat flag
|
||||
* @return string content re-formatted
|
||||
*/
|
||||
function smarty_block_php($params, $content, $template, &$repeat)
|
||||
{
|
||||
if (!$template->allow_php_tag) {
|
||||
throw new SmartyException("{php} is deprecated, set allow_php_tag = true to enable");
|
||||
}
|
||||
eval($content);
|
||||
return '';
|
||||
}
|
||||
|
||||
?>
|
|
@ -0,0 +1,102 @@
|
|||
<?php
|
||||
/**
|
||||
* Smarty plugin to format text blocks
|
||||
*
|
||||
* @package Smarty
|
||||
* @subpackage PluginsBlock
|
||||
*/
|
||||
|
||||
/**
|
||||
* Smarty {textformat}{/textformat} block plugin
|
||||
*
|
||||
* Type: block function<br>
|
||||
* Name: textformat<br>
|
||||
* Purpose: format text a certain way with preset styles
|
||||
* or custom wrap/indent settings<br>
|
||||
*
|
||||
* @link http://smarty.php.net/manual/en/language.function.textformat.php {textformat}
|
||||
* (Smarty online manual)
|
||||
* @param array $params parameters
|
||||
* <pre>
|
||||
* Params: style: string (email)
|
||||
* indent: integer (0)
|
||||
* wrap: integer (80)
|
||||
* wrap_char string ("\n")
|
||||
* indent_char: string (" ")
|
||||
* wrap_boundary: boolean (true)
|
||||
* </pre>
|
||||
* @author Monte Ohrt <monte at ohrt dot com>
|
||||
* @param string $content contents of the block
|
||||
* @param object $template template object
|
||||
* @param boolean &$repeat repeat flag
|
||||
* @return string content re-formatted
|
||||
*/
|
||||
function smarty_block_textformat($params, $content, $template, &$repeat)
|
||||
{
|
||||
if (is_null($content)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$style = null;
|
||||
$indent = 0;
|
||||
$indent_first = 0;
|
||||
$indent_char = ' ';
|
||||
$wrap = 80;
|
||||
$wrap_char = "\n";
|
||||
$wrap_cut = false;
|
||||
$assign = null;
|
||||
|
||||
foreach ($params as $_key => $_val) {
|
||||
switch ($_key) {
|
||||
case 'style':
|
||||
case 'indent_char':
|
||||
case 'wrap_char':
|
||||
case 'assign':
|
||||
$$_key = (string)$_val;
|
||||
break;
|
||||
|
||||
case 'indent':
|
||||
case 'indent_first':
|
||||
case 'wrap':
|
||||
$$_key = (int)$_val;
|
||||
break;
|
||||
|
||||
case 'wrap_cut':
|
||||
$$_key = (bool)$_val;
|
||||
break;
|
||||
|
||||
default:
|
||||
trigger_error("textformat: unknown attribute '$_key'");
|
||||
}
|
||||
}
|
||||
|
||||
if ($style == 'email') {
|
||||
$wrap = 72;
|
||||
}
|
||||
// split into paragraphs
|
||||
$_paragraphs = preg_split('![\r\n][\r\n]!', $content);
|
||||
$_output = '';
|
||||
|
||||
for($_x = 0, $_y = count($_paragraphs); $_x < $_y; $_x++) {
|
||||
if ($_paragraphs[$_x] == '') {
|
||||
continue;
|
||||
}
|
||||
// convert mult. spaces & special chars to single space
|
||||
$_paragraphs[$_x] = preg_replace(array('!\s+!', '!(^\s+)|(\s+$)!'), array(' ', ''), $_paragraphs[$_x]);
|
||||
// indent first line
|
||||
if ($indent_first > 0) {
|
||||
$_paragraphs[$_x] = str_repeat($indent_char, $indent_first) . $_paragraphs[$_x];
|
||||
}
|
||||
// wordwrap sentences
|
||||
$_paragraphs[$_x] = wordwrap($_paragraphs[$_x], $wrap - $indent, $wrap_char, $wrap_cut);
|
||||
// indent lines
|
||||
if ($indent > 0) {
|
||||
$_paragraphs[$_x] = preg_replace('!^!m', str_repeat($indent_char, $indent), $_paragraphs[$_x]);
|
||||
}
|
||||
}
|
||||
$_output = implode($wrap_char . $wrap_char, $_paragraphs);
|
||||
|
||||
return $assign ? $template->assign($assign, $_output) : $_output;
|
||||
}
|
||||
|
||||
?>
|
|
@ -0,0 +1,78 @@
|
|||
<?php
|
||||
/**
|
||||
* Smarty plugin
|
||||
* @package Smarty
|
||||
* @subpackage PluginsFunction
|
||||
*/
|
||||
|
||||
/**
|
||||
* Smarty {counter} function plugin
|
||||
*
|
||||
* Type: function<br>
|
||||
* Name: counter<br>
|
||||
* Purpose: print out a counter value
|
||||
* @author Monte Ohrt <monte at ohrt dot com>
|
||||
* @link http://smarty.php.net/manual/en/language.function.counter.php {counter}
|
||||
* (Smarty online manual)
|
||||
* @param array parameters
|
||||
* @param Smarty
|
||||
* @param object $template template object
|
||||
* @return string|null
|
||||
*/
|
||||
function smarty_function_counter($params, $template)
|
||||
{
|
||||
static $counters = array();
|
||||
|
||||
$name = (isset($params['name'])) ? $params['name'] : 'default';
|
||||
if (!isset($counters[$name])) {
|
||||
$counters[$name] = array(
|
||||
'start'=>1,
|
||||
'skip'=>1,
|
||||
'direction'=>'up',
|
||||
'count'=>1
|
||||
);
|
||||
}
|
||||
$counter =& $counters[$name];
|
||||
|
||||
if (isset($params['start'])) {
|
||||
$counter['start'] = $counter['count'] = (int)$params['start'];
|
||||
}
|
||||
|
||||
if (!empty($params['assign'])) {
|
||||
$counter['assign'] = $params['assign'];
|
||||
}
|
||||
|
||||
if (isset($counter['assign'])) {
|
||||
$template->assign($counter['assign'], $counter['count']);
|
||||
}
|
||||
|
||||
if (isset($params['print'])) {
|
||||
$print = (bool)$params['print'];
|
||||
} else {
|
||||
$print = empty($counter['assign']);
|
||||
}
|
||||
|
||||
if ($print) {
|
||||
$retval = $counter['count'];
|
||||
} else {
|
||||
$retval = null;
|
||||
}
|
||||
|
||||
if (isset($params['skip'])) {
|
||||
$counter['skip'] = $params['skip'];
|
||||
}
|
||||
|
||||
if (isset($params['direction'])) {
|
||||
$counter['direction'] = $params['direction'];
|
||||
}
|
||||
|
||||
if ($counter['direction'] == "down")
|
||||
$counter['count'] -= $counter['skip'];
|
||||
else
|
||||
$counter['count'] += $counter['skip'];
|
||||
|
||||
return $retval;
|
||||
|
||||
}
|
||||
|
||||
?>
|
|
@ -0,0 +1,106 @@
|
|||
<?php
|
||||
/**
|
||||
* Smarty plugin
|
||||
*
|
||||
* @package Smarty
|
||||
* @subpackage PluginsFunction
|
||||
*/
|
||||
|
||||
/**
|
||||
* Smarty {cycle} function plugin
|
||||
*
|
||||
* Type: function<br>
|
||||
* Name: cycle<br>
|
||||
* Date: May 3, 2002<br>
|
||||
* Purpose: cycle through given values<br>
|
||||
* Input:
|
||||
* - name = name of cycle (optional)
|
||||
* - values = comma separated list of values to cycle,
|
||||
* or an array of values to cycle
|
||||
* (this can be left out for subsequent calls)
|
||||
* - reset = boolean - resets given var to true
|
||||
* - print = boolean - print var or not. default is true
|
||||
* - advance = boolean - whether or not to advance the cycle
|
||||
* - delimiter = the value delimiter, default is ","
|
||||
* - assign = boolean, assigns to template var instead of
|
||||
* printed.
|
||||
*
|
||||
* Examples:<br>
|
||||
* <pre>
|
||||
* {cycle values="#eeeeee,#d0d0d0d"}
|
||||
* {cycle name=row values="one,two,three" reset=true}
|
||||
* {cycle name=row}
|
||||
* </pre>
|
||||
* @link http://smarty.php.net/manual/en/language.function.cycle.php {cycle}
|
||||
* (Smarty online manual)
|
||||
* @author Monte Ohrt <monte at ohrt dot com>
|
||||
* @author credit to Mark Priatel <mpriatel@rogers.com>
|
||||
* @author credit to Gerard <gerard@interfold.com>
|
||||
* @author credit to Jason Sweat <jsweat_php@yahoo.com>
|
||||
* @version 1.3
|
||||
* @param array
|
||||
* @param object $template template object
|
||||
* @return string|null
|
||||
*/
|
||||
|
||||
function smarty_function_cycle($params, $template)
|
||||
{
|
||||
static $cycle_vars;
|
||||
|
||||
$name = (empty($params['name'])) ? 'default' : $params['name'];
|
||||
$print = (isset($params['print'])) ? (bool)$params['print'] : true;
|
||||
$advance = (isset($params['advance'])) ? (bool)$params['advance'] : true;
|
||||
$reset = (isset($params['reset'])) ? (bool)$params['reset'] : false;
|
||||
|
||||
if (!in_array('values', array_keys($params))) {
|
||||
if(!isset($cycle_vars[$name]['values'])) {
|
||||
trigger_error("cycle: missing 'values' parameter");
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
if(isset($cycle_vars[$name]['values'])
|
||||
&& $cycle_vars[$name]['values'] != $params['values'] ) {
|
||||
$cycle_vars[$name]['index'] = 0;
|
||||
}
|
||||
$cycle_vars[$name]['values'] = $params['values'];
|
||||
}
|
||||
|
||||
if (isset($params['delimiter'])) {
|
||||
$cycle_vars[$name]['delimiter'] = $params['delimiter'];
|
||||
} elseif (!isset($cycle_vars[$name]['delimiter'])) {
|
||||
$cycle_vars[$name]['delimiter'] = ',';
|
||||
}
|
||||
|
||||
if(is_array($cycle_vars[$name]['values'])) {
|
||||
$cycle_array = $cycle_vars[$name]['values'];
|
||||
} else {
|
||||
$cycle_array = explode($cycle_vars[$name]['delimiter'],$cycle_vars[$name]['values']);
|
||||
}
|
||||
|
||||
if(!isset($cycle_vars[$name]['index']) || $reset ) {
|
||||
$cycle_vars[$name]['index'] = 0;
|
||||
}
|
||||
|
||||
if (isset($params['assign'])) {
|
||||
$print = false;
|
||||
$template->assign($params['assign'], $cycle_array[$cycle_vars[$name]['index']]);
|
||||
}
|
||||
|
||||
if($print) {
|
||||
$retval = $cycle_array[$cycle_vars[$name]['index']];
|
||||
} else {
|
||||
$retval = null;
|
||||
}
|
||||
|
||||
if($advance) {
|
||||
if ( $cycle_vars[$name]['index'] >= count($cycle_array) -1 ) {
|
||||
$cycle_vars[$name]['index'] = 0;
|
||||
} else {
|
||||
$cycle_vars[$name]['index']++;
|
||||
}
|
||||
}
|
||||
|
||||
return $retval;
|
||||
}
|
||||
|
||||
?>
|
|
@ -0,0 +1,216 @@
|
|||
<?php
|
||||
/**
|
||||
* Smarty plugin
|
||||
*
|
||||
* @package Smarty
|
||||
* @subpackage PluginsFunction
|
||||
*/
|
||||
|
||||
/**
|
||||
* Smarty {fetch} plugin
|
||||
*
|
||||
* Type: function<br>
|
||||
* Name: fetch<br>
|
||||
* Purpose: fetch file, web or ftp data and display results
|
||||
* @link http://smarty.php.net/manual/en/language.function.fetch.php {fetch}
|
||||
* (Smarty online manual)
|
||||
* @author Monte Ohrt <monte at ohrt dot com>
|
||||
* @param array $params parameters
|
||||
* @param object $template template object
|
||||
* @return string|null if the assign parameter is passed, Smarty assigns the
|
||||
* result to a template variable
|
||||
*/
|
||||
function smarty_function_fetch($params, $template)
|
||||
{
|
||||
if (empty($params['file'])) {
|
||||
trigger_error("[plugin] fetch parameter 'file' cannot be empty",E_USER_NOTICE);
|
||||
return;
|
||||
}
|
||||
|
||||
$content = '';
|
||||
if (isset($template->security_policy) && !preg_match('!^(http|ftp)://!i', $params['file'])) {
|
||||
if(!$template->security_policy->isTrustedResourceDir($params['file'])) {
|
||||
return;
|
||||
}
|
||||
|
||||
// fetch the file
|
||||
if($fp = @fopen($params['file'],'r')) {
|
||||
while(!feof($fp)) {
|
||||
$content .= fgets ($fp,4096);
|
||||
}
|
||||
fclose($fp);
|
||||
} else {
|
||||
trigger_error('[plugin] fetch cannot read file \'' . $params['file'] . '\'',E_USER_NOTICE);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
// not a local file
|
||||
if(preg_match('!^http://!i',$params['file'])) {
|
||||
// http fetch
|
||||
if($uri_parts = parse_url($params['file'])) {
|
||||
// set defaults
|
||||
$host = $server_name = $uri_parts['host'];
|
||||
$timeout = 30;
|
||||
$accept = "image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, */*";
|
||||
$agent = "Smarty Template Engine ".$template->_version;
|
||||
$referer = "";
|
||||
$uri = !empty($uri_parts['path']) ? $uri_parts['path'] : '/';
|
||||
$uri .= !empty($uri_parts['query']) ? '?' . $uri_parts['query'] : '';
|
||||
$_is_proxy = false;
|
||||
if(empty($uri_parts['port'])) {
|
||||
$port = 80;
|
||||
} else {
|
||||
$port = $uri_parts['port'];
|
||||
}
|
||||
if(!empty($uri_parts['user'])) {
|
||||
$user = $uri_parts['user'];
|
||||
}
|
||||
if(!empty($uri_parts['pass'])) {
|
||||
$pass = $uri_parts['pass'];
|
||||
}
|
||||
// loop through parameters, setup headers
|
||||
foreach($params as $param_key => $param_value) {
|
||||
switch($param_key) {
|
||||
case "file":
|
||||
case "assign":
|
||||
case "assign_headers":
|
||||
break;
|
||||
case "user":
|
||||
if(!empty($param_value)) {
|
||||
$user = $param_value;
|
||||
}
|
||||
break;
|
||||
case "pass":
|
||||
if(!empty($param_value)) {
|
||||
$pass = $param_value;
|
||||
}
|
||||
break;
|
||||
case "accept":
|
||||
if(!empty($param_value)) {
|
||||
$accept = $param_value;
|
||||
}
|
||||
break;
|
||||
case "header":
|
||||
if(!empty($param_value)) {
|
||||
if(!preg_match('![\w\d-]+: .+!',$param_value)) {
|
||||
trigger_error("[plugin] invalid header format '".$param_value."'",E_USER_NOTICE);
|
||||
return;
|
||||
} else {
|
||||
$extra_headers[] = $param_value;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case "proxy_host":
|
||||
if(!empty($param_value)) {
|
||||
$proxy_host = $param_value;
|
||||
}
|
||||
break;
|
||||
case "proxy_port":
|
||||
if(!preg_match('!\D!', $param_value)) {
|
||||
$proxy_port = (int) $param_value;
|
||||
} else {
|
||||
trigger_error("[plugin] invalid value for attribute '".$param_key."'",E_USER_NOTICE);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case "agent":
|
||||
if(!empty($param_value)) {
|
||||
$agent = $param_value;
|
||||
}
|
||||
break;
|
||||
case "referer":
|
||||
if(!empty($param_value)) {
|
||||
$referer = $param_value;
|
||||
}
|
||||
break;
|
||||
case "timeout":
|
||||
if(!preg_match('!\D!', $param_value)) {
|
||||
$timeout = (int) $param_value;
|
||||
} else {
|
||||
trigger_error("[plugin] invalid value for attribute '".$param_key."'",E_USER_NOTICE);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
trigger_error("[plugin] unrecognized attribute '".$param_key."'",E_USER_NOTICE);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if(!empty($proxy_host) && !empty($proxy_port)) {
|
||||
$_is_proxy = true;
|
||||
$fp = fsockopen($proxy_host,$proxy_port,$errno,$errstr,$timeout);
|
||||
} else {
|
||||
$fp = fsockopen($server_name,$port,$errno,$errstr,$timeout);
|
||||
}
|
||||
|
||||
if(!$fp) {
|
||||
trigger_error("[plugin] unable to fetch: $errstr ($errno)",E_USER_NOTICE);
|
||||
return;
|
||||
} else {
|
||||
if($_is_proxy) {
|
||||
fputs($fp, 'GET ' . $params['file'] . " HTTP/1.0\r\n");
|
||||
} else {
|
||||
fputs($fp, "GET $uri HTTP/1.0\r\n");
|
||||
}
|
||||
if(!empty($host)) {
|
||||
fputs($fp, "Host: $host\r\n");
|
||||
}
|
||||
if(!empty($accept)) {
|
||||
fputs($fp, "Accept: $accept\r\n");
|
||||
}
|
||||
if(!empty($agent)) {
|
||||
fputs($fp, "User-Agent: $agent\r\n");
|
||||
}
|
||||
if(!empty($referer)) {
|
||||
fputs($fp, "Referer: $referer\r\n");
|
||||
}
|
||||
if(isset($extra_headers) && is_array($extra_headers)) {
|
||||
foreach($extra_headers as $curr_header) {
|
||||
fputs($fp, $curr_header."\r\n");
|
||||
}
|
||||
}
|
||||
if(!empty($user) && !empty($pass)) {
|
||||
fputs($fp, "Authorization: BASIC ".base64_encode("$user:$pass")."\r\n");
|
||||
}
|
||||
|
||||
fputs($fp, "\r\n");
|
||||
while(!feof($fp)) {
|
||||
$content .= fgets($fp,4096);
|
||||
}
|
||||
fclose($fp);
|
||||
$csplit = preg_split("!\r\n\r\n!",$content,2);
|
||||
|
||||
$content = $csplit[1];
|
||||
|
||||
if(!empty($params['assign_headers'])) {
|
||||
$template->assign($params['assign_headers'],preg_split("!\r\n!",$csplit[0]));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
trigger_error("[plugin fetch] unable to parse URL, check syntax",E_USER_NOTICE);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
// ftp fetch
|
||||
if($fp = @fopen($params['file'],'r')) {
|
||||
while(!feof($fp)) {
|
||||
$content .= fgets ($fp,4096);
|
||||
}
|
||||
fclose($fp);
|
||||
} else {
|
||||
trigger_error('[plugin] fetch cannot read file \'' . $params['file'] .'\'',E_USER_NOTICE);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
if (!empty($params['assign'])) {
|
||||
$template->assign($params['assign'],$content);
|
||||
} else {
|
||||
return $content;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
|
@ -0,0 +1,143 @@
|
|||
<?php
|
||||
/**
|
||||
* Smarty plugin
|
||||
*
|
||||
* @package Smarty
|
||||
* @subpackage PluginsFunction
|
||||
*/
|
||||
|
||||
/**
|
||||
* Smarty {html_checkboxes} function plugin
|
||||
*
|
||||
* File: function.html_checkboxes.php<br>
|
||||
* Type: function<br>
|
||||
* Name: html_checkboxes<br>
|
||||
* Date: 24.Feb.2003<br>
|
||||
* Purpose: Prints out a list of checkbox input types<br>
|
||||
* Examples:
|
||||
* <pre>
|
||||
* {html_checkboxes values=$ids output=$names}
|
||||
* {html_checkboxes values=$ids name='box' separator='<br>' output=$names}
|
||||
* {html_checkboxes values=$ids checked=$checked separator='<br>' output=$names}
|
||||
* </pre>
|
||||
* @link http://smarty.php.net/manual/en/language.function.html.checkboxes.php {html_checkboxes}
|
||||
* (Smarty online manual)
|
||||
* @author Christopher Kvarme <christopher.kvarme@flashjab.com>
|
||||
* @author credits to Monte Ohrt <monte at ohrt dot com>
|
||||
* @version 1.0
|
||||
* @param array $params parameters
|
||||
* Input:<br>
|
||||
* - name (optional) - string default "checkbox"
|
||||
* - values (required) - array
|
||||
* - options (optional) - associative array
|
||||
* - checked (optional) - array default not set
|
||||
* - separator (optional) - ie <br> or
|
||||
* - output (optional) - the output next to each checkbox
|
||||
* - assign (optional) - assign the output as an array to this variable
|
||||
* @param object $template template object
|
||||
* @return string
|
||||
* @uses smarty_function_escape_special_chars()
|
||||
*/
|
||||
function smarty_function_html_checkboxes($params, $template)
|
||||
{
|
||||
require_once(SMARTY_PLUGINS_DIR . 'shared.escape_special_chars.php');
|
||||
|
||||
$name = 'checkbox';
|
||||
$values = null;
|
||||
$options = null;
|
||||
$selected = null;
|
||||
$separator = '';
|
||||
$labels = true;
|
||||
$output = null;
|
||||
|
||||
$extra = '';
|
||||
|
||||
foreach($params as $_key => $_val) {
|
||||
switch($_key) {
|
||||
case 'name':
|
||||
case 'separator':
|
||||
$$_key = $_val;
|
||||
break;
|
||||
|
||||
case 'labels':
|
||||
$$_key = (bool)$_val;
|
||||
break;
|
||||
|
||||
case 'options':
|
||||
$$_key = (array)$_val;
|
||||
break;
|
||||
|
||||
case 'values':
|
||||
case 'output':
|
||||
$$_key = array_values((array)$_val);
|
||||
break;
|
||||
|
||||
case 'checked':
|
||||
case 'selected':
|
||||
$selected = array_map('strval', array_values((array)$_val));
|
||||
break;
|
||||
|
||||
case 'checkboxes':
|
||||
trigger_error('html_checkboxes: the use of the "checkboxes" attribute is deprecated, use "options" instead', E_USER_WARNING);
|
||||
$options = (array)$_val;
|
||||
break;
|
||||
|
||||
case 'assign':
|
||||
break;
|
||||
|
||||
default:
|
||||
if(!is_array($_val)) {
|
||||
$extra .= ' '.$_key.'="'.smarty_function_escape_special_chars($_val).'"';
|
||||
} else {
|
||||
trigger_error("html_checkboxes: extra attribute '$_key' cannot be an array", E_USER_NOTICE);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!isset($options) && !isset($values))
|
||||
return ''; /* raise error here? */
|
||||
|
||||
settype($selected, 'array');
|
||||
$_html_result = array();
|
||||
|
||||
if (isset($options)) {
|
||||
|
||||
foreach ($options as $_key=>$_val)
|
||||
$_html_result[] = smarty_function_html_checkboxes_output($name, $_key, $_val, $selected, $extra, $separator, $labels);
|
||||
|
||||
|
||||
} else {
|
||||
foreach ($values as $_i=>$_key) {
|
||||
$_val = isset($output[$_i]) ? $output[$_i] : '';
|
||||
$_html_result[] = smarty_function_html_checkboxes_output($name, $_key, $_val, $selected, $extra, $separator, $labels);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if(!empty($params['assign'])) {
|
||||
$template->assign($params['assign'], $_html_result);
|
||||
} else {
|
||||
return implode("\n",$_html_result);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function smarty_function_html_checkboxes_output($name, $value, $output, $selected, $extra, $separator, $labels) {
|
||||
$_output = '';
|
||||
if ($labels) $_output .= '<label>';
|
||||
$_output .= '<input type="checkbox" name="'
|
||||
. smarty_function_escape_special_chars($name) . '[]" value="'
|
||||
. smarty_function_escape_special_chars($value) . '"';
|
||||
|
||||
if (in_array((string)$value, $selected)) {
|
||||
$_output .= ' checked="checked"';
|
||||
}
|
||||
$_output .= $extra . ' />' . $output;
|
||||
if ($labels) $_output .= '</label>';
|
||||
$_output .= $separator;
|
||||
|
||||
return $_output;
|
||||
}
|
||||
|
||||
?>
|
|
@ -0,0 +1,137 @@
|
|||
<?php
|
||||
/**
|
||||
* Smarty plugin
|
||||
*
|
||||
* @package Smarty
|
||||
* @subpackage PluginsFunction
|
||||
*/
|
||||
|
||||
/**
|
||||
* Smarty {html_image} function plugin
|
||||
*
|
||||
* Type: function<br>
|
||||
* Name: html_image<br>
|
||||
* Date: Feb 24, 2003<br>
|
||||
* Purpose: format HTML tags for the image<br>
|
||||
* Examples: {html_image file="/images/masthead.gif"}
|
||||
* Output: <img src="/images/masthead.gif" width=400 height=23>
|
||||
*
|
||||
* @link http://smarty.php.net/manual/en/language.function.html.image.php {html_image}
|
||||
* (Smarty online manual)
|
||||
* @author Monte Ohrt <monte at ohrt dot com>
|
||||
* @author credits to Duda <duda@big.hu>
|
||||
* @version 1.0
|
||||
* @param array $params parameters
|
||||
* Input:<br>
|
||||
* - file = file (and path) of image (required)
|
||||
* - height = image height (optional, default actual height)
|
||||
* - width = image width (optional, default actual width)
|
||||
* - basedir = base directory for absolute paths, default
|
||||
* is environment variable DOCUMENT_ROOT
|
||||
* - path_prefix = prefix for path output (optional, default empty)
|
||||
* @param object $template template object
|
||||
* @return string
|
||||
* @uses smarty_function_escape_special_chars()
|
||||
*/
|
||||
function smarty_function_html_image($params, $template)
|
||||
{
|
||||
require_once(SMARTY_PLUGINS_DIR . 'shared.escape_special_chars.php');
|
||||
|
||||
$alt = '';
|
||||
$file = '';
|
||||
$height = '';
|
||||
$width = '';
|
||||
$extra = '';
|
||||
$prefix = '';
|
||||
$suffix = '';
|
||||
$path_prefix = '';
|
||||
$server_vars = $_SERVER;
|
||||
$basedir = isset($server_vars['DOCUMENT_ROOT']) ? $server_vars['DOCUMENT_ROOT'] : '';
|
||||
foreach($params as $_key => $_val) {
|
||||
switch ($_key) {
|
||||
case 'file':
|
||||
case 'height':
|
||||
case 'width':
|
||||
case 'dpi':
|
||||
case 'path_prefix':
|
||||
case 'basedir':
|
||||
$$_key = $_val;
|
||||
break;
|
||||
|
||||
case 'alt':
|
||||
if (!is_array($_val)) {
|
||||
$$_key = smarty_function_escape_special_chars($_val);
|
||||
} else {
|
||||
throw new SmartyException ("html_image: extra attribute '$_key' cannot be an array", E_USER_NOTICE);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'link':
|
||||
case 'href':
|
||||
$prefix = '<a href="' . $_val . '">';
|
||||
$suffix = '</a>';
|
||||
break;
|
||||
|
||||
default:
|
||||
if (!is_array($_val)) {
|
||||
$extra .= ' ' . $_key . '="' . smarty_function_escape_special_chars($_val) . '"';
|
||||
} else {
|
||||
throw new SmartyException ("html_image: extra attribute '$_key' cannot be an array", E_USER_NOTICE);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($file)) {
|
||||
trigger_error("html_image: missing 'file' parameter", E_USER_NOTICE);
|
||||
return;
|
||||
}
|
||||
|
||||
if (substr($file, 0, 1) == '/') {
|
||||
$_image_path = $basedir . $file;
|
||||
} else {
|
||||
$_image_path = $file;
|
||||
}
|
||||
|
||||
if (!isset($params['width']) || !isset($params['height'])) {
|
||||
if (!$_image_data = @getimagesize($_image_path)) {
|
||||
if (!file_exists($_image_path)) {
|
||||
trigger_error("html_image: unable to find '$_image_path'", E_USER_NOTICE);
|
||||
return;
|
||||
} else if (!is_readable($_image_path)) {
|
||||
trigger_error("html_image: unable to read '$_image_path'", E_USER_NOTICE);
|
||||
return;
|
||||
} else {
|
||||
trigger_error("html_image: '$_image_path' is not a valid image file", E_USER_NOTICE);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (isset($template->security_policy)) {
|
||||
if (!$template->security_policy->isTrustedResourceDir($_image_path)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!isset($params['width'])) {
|
||||
$width = $_image_data[0];
|
||||
}
|
||||
if (!isset($params['height'])) {
|
||||
$height = $_image_data[1];
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($params['dpi'])) {
|
||||
if (strstr($server_vars['HTTP_USER_AGENT'], 'Mac')) {
|
||||
$dpi_default = 72;
|
||||
} else {
|
||||
$dpi_default = 96;
|
||||
}
|
||||
$_resize = $dpi_default / $params['dpi'];
|
||||
$width = round($width * $_resize);
|
||||
$height = round($height * $_resize);
|
||||
}
|
||||
|
||||
return $prefix . '<img src="' . $path_prefix . $file . '" alt="' . $alt . '" width="' . $width . '" height="' . $height . '"' . $extra . ' />' . $suffix;
|
||||
}
|
||||
|
||||
?>
|
|
@ -0,0 +1,119 @@
|
|||
<?php
|
||||
/**
|
||||
* Smarty plugin
|
||||
*
|
||||
* @package Smarty
|
||||
* @subpackage PluginsFunction
|
||||
*/
|
||||
|
||||
/**
|
||||
* Smarty {html_options} function plugin
|
||||
*
|
||||
* Type: function<br>
|
||||
* Name: html_options<br>
|
||||
* Purpose: Prints the list of <option> tags generated from
|
||||
* the passed parameters
|
||||
*
|
||||
* @link http://smarty.php.net/manual/en/language.function.html.options.php {html_image}
|
||||
* (Smarty online manual)
|
||||
* @author Monte Ohrt <monte at ohrt dot com>
|
||||
* @param array $params parameters
|
||||
* Input:<br>
|
||||
* - name (optional) - string default "select"
|
||||
* - values (required if no options supplied) - array
|
||||
* - options (required if no values supplied) - associative array
|
||||
* - selected (optional) - string default not set
|
||||
* - output (required if not options supplied) - array
|
||||
* @param object $template template object
|
||||
* @return string
|
||||
* @uses smarty_function_escape_special_chars()
|
||||
*/
|
||||
function smarty_function_html_options($params, $template)
|
||||
{
|
||||
require_once(SMARTY_PLUGINS_DIR . 'shared.escape_special_chars.php');
|
||||
|
||||
$name = null;
|
||||
$values = null;
|
||||
$options = null;
|
||||
$selected = array();
|
||||
$output = null;
|
||||
|
||||
$extra = '';
|
||||
|
||||
foreach($params as $_key => $_val) {
|
||||
switch ($_key) {
|
||||
case 'name':
|
||||
$$_key = (string)$_val;
|
||||
break;
|
||||
|
||||
case 'options':
|
||||
$$_key = (array)$_val;
|
||||
break;
|
||||
|
||||
case 'values':
|
||||
case 'output':
|
||||
$$_key = array_values((array)$_val);
|
||||
break;
|
||||
|
||||
case 'selected':
|
||||
$$_key = array_map('strval', array_values((array)$_val));
|
||||
break;
|
||||
|
||||
default:
|
||||
if (!is_array($_val)) {
|
||||
$extra .= ' ' . $_key . '="' . smarty_function_escape_special_chars($_val) . '"';
|
||||
} else {
|
||||
trigger_error("html_options: extra attribute '$_key' cannot be an array", E_USER_NOTICE);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!isset($options) && !isset($values))
|
||||
return '';
|
||||
/* raise error here? */
|
||||
|
||||
$_html_result = '';
|
||||
|
||||
if (isset($options)) {
|
||||
foreach ($options as $_key => $_val)
|
||||
$_html_result .= smarty_function_html_options_optoutput($_key, $_val, $selected);
|
||||
} else {
|
||||
foreach ($values as $_i => $_key) {
|
||||
$_val = isset($output[$_i]) ? $output[$_i] : '';
|
||||
$_html_result .= smarty_function_html_options_optoutput($_key, $_val, $selected);
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($name)) {
|
||||
$_html_result = '<select name="' . $name . '"' . $extra . '>' . "\n" . $_html_result . '</select>' . "\n";
|
||||
}
|
||||
|
||||
return $_html_result;
|
||||
}
|
||||
|
||||
function smarty_function_html_options_optoutput($key, $value, $selected)
|
||||
{
|
||||
if (!is_array($value)) {
|
||||
$_html_result = '<option value="' .
|
||||
smarty_function_escape_special_chars($key) . '"';
|
||||
if (in_array((string)$key, $selected))
|
||||
$_html_result .= ' selected="selected"';
|
||||
$_html_result .= '>' . smarty_function_escape_special_chars($value) . '</option>' . "\n";
|
||||
} else {
|
||||
$_html_result = smarty_function_html_options_optgroup($key, $value, $selected);
|
||||
}
|
||||
return $_html_result;
|
||||
}
|
||||
|
||||
function smarty_function_html_options_optgroup($key, $values, $selected)
|
||||
{
|
||||
$optgroup_html = '<optgroup label="' . smarty_function_escape_special_chars($key) . '">' . "\n";
|
||||
foreach ($values as $key => $value) {
|
||||
$optgroup_html .= smarty_function_html_options_optoutput($key, $value, $selected);
|
||||
}
|
||||
$optgroup_html .= "</optgroup>\n";
|
||||
return $optgroup_html;
|
||||
}
|
||||
|
||||
?>
|
|
@ -0,0 +1,154 @@
|
|||
<?php
|
||||
/**
|
||||
* Smarty plugin
|
||||
*
|
||||
* @package Smarty
|
||||
* @subpackage PluginsFunction
|
||||
*/
|
||||
|
||||
/**
|
||||
* Smarty {html_radios} function plugin
|
||||
*
|
||||
* File: function.html_radios.php<br>
|
||||
* Type: function<br>
|
||||
* Name: html_radios<br>
|
||||
* Date: 24.Feb.2003<br>
|
||||
* Purpose: Prints out a list of radio input types<br>
|
||||
* Examples:
|
||||
* <pre>
|
||||
* {html_radios values=$ids output=$names}
|
||||
* {html_radios values=$ids name='box' separator='<br>' output=$names}
|
||||
* {html_radios values=$ids checked=$checked separator='<br>' output=$names}
|
||||
* </pre>
|
||||
*
|
||||
* @link http://smarty.php.net/manual/en/language.function.html.radios.php {html_radios}
|
||||
* (Smarty online manual)
|
||||
* @author Christopher Kvarme <christopher.kvarme@flashjab.com>
|
||||
* @author credits to Monte Ohrt <monte at ohrt dot com>
|
||||
* @version 1.0
|
||||
* @param array $params parameters
|
||||
* Input:<br>
|
||||
* - name (optional) - string default "radio"
|
||||
* - values (required) - array
|
||||
* - options (optional) - associative array
|
||||
* - checked (optional) - array default not set
|
||||
* - separator (optional) - ie <br> or
|
||||
* - output (optional) - the output next to each radio button
|
||||
* - assign (optional) - assign the output as an array to this variable
|
||||
* @param object $template template object
|
||||
* @return string
|
||||
* @uses smarty_function_escape_special_chars()
|
||||
*/
|
||||
function smarty_function_html_radios($params, $template)
|
||||
{
|
||||
require_once(SMARTY_PLUGINS_DIR . 'shared.escape_special_chars.php');
|
||||
|
||||
$name = 'radio';
|
||||
$values = null;
|
||||
$options = null;
|
||||
$selected = null;
|
||||
$separator = '';
|
||||
$labels = true;
|
||||
$label_ids = false;
|
||||
$output = null;
|
||||
$extra = '';
|
||||
|
||||
foreach($params as $_key => $_val) {
|
||||
switch ($_key) {
|
||||
case 'name':
|
||||
case 'separator':
|
||||
$$_key = (string)$_val;
|
||||
break;
|
||||
|
||||
case 'checked':
|
||||
case 'selected':
|
||||
if (is_array($_val)) {
|
||||
trigger_error('html_radios: the "' . $_key . '" attribute cannot be an array', E_USER_WARNING);
|
||||
} else {
|
||||
$selected = (string)$_val;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'labels':
|
||||
case 'label_ids':
|
||||
$$_key = (bool)$_val;
|
||||
break;
|
||||
|
||||
case 'options':
|
||||
$$_key = (array)$_val;
|
||||
break;
|
||||
|
||||
case 'values':
|
||||
case 'output':
|
||||
$$_key = array_values((array)$_val);
|
||||
break;
|
||||
|
||||
case 'radios':
|
||||
trigger_error('html_radios: the use of the "radios" attribute is deprecated, use "options" instead', E_USER_WARNING);
|
||||
$options = (array)$_val;
|
||||
break;
|
||||
|
||||
case 'assign':
|
||||
break;
|
||||
|
||||
default:
|
||||
if (!is_array($_val)) {
|
||||
$extra .= ' ' . $_key . '="' . smarty_function_escape_special_chars($_val) . '"';
|
||||
} else {
|
||||
trigger_error("html_radios: extra attribute '$_key' cannot be an array", E_USER_NOTICE);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!isset($options) && !isset($values))
|
||||
return '';
|
||||
/* raise error here? */
|
||||
|
||||
$_html_result = array();
|
||||
|
||||
if (isset($options)) {
|
||||
foreach ($options as $_key => $_val)
|
||||
$_html_result[] = smarty_function_html_radios_output($name, $_key, $_val, $selected, $extra, $separator, $labels, $label_ids);
|
||||
} else {
|
||||
foreach ($values as $_i => $_key) {
|
||||
$_val = isset($output[$_i]) ? $output[$_i] : '';
|
||||
$_html_result[] = smarty_function_html_radios_output($name, $_key, $_val, $selected, $extra, $separator, $labels, $label_ids);
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($params['assign'])) {
|
||||
$template->assign($params['assign'], $_html_result);
|
||||
} else {
|
||||
return implode("\n", $_html_result);
|
||||
}
|
||||
}
|
||||
|
||||
function smarty_function_html_radios_output($name, $value, $output, $selected, $extra, $separator, $labels, $label_ids)
|
||||
{
|
||||
$_output = '';
|
||||
if ($labels) {
|
||||
if ($label_ids) {
|
||||
$_id = smarty_function_escape_special_chars(preg_replace('![^\w\-\.]!', '_', $name . '_' . $value));
|
||||
$_output .= '<label for="' . $_id . '">';
|
||||
} else {
|
||||
$_output .= '<label>';
|
||||
}
|
||||
}
|
||||
$_output .= '<input type="radio" name="'
|
||||
. smarty_function_escape_special_chars($name) . '" value="'
|
||||
. smarty_function_escape_special_chars($value) . '"';
|
||||
|
||||
if ($labels && $label_ids) $_output .= ' id="' . $_id . '"';
|
||||
|
||||
if ((string)$value == $selected) {
|
||||
$_output .= ' checked="checked"';
|
||||
}
|
||||
$_output .= $extra . ' />' . $output;
|
||||
if ($labels) $_output .= '</label>';
|
||||
$_output .= $separator;
|
||||
|
||||
return $_output;
|
||||
}
|
||||
|
||||
?>
|
|
@ -0,0 +1,330 @@
|
|||
<?php
|
||||
/**
|
||||
* Smarty plugin
|
||||
*
|
||||
* @package Smarty
|
||||
* @subpackage PluginsFunction
|
||||
*/
|
||||
|
||||
/**
|
||||
* Smarty {html_select_date} plugin
|
||||
*
|
||||
* Type: function<br>
|
||||
* Name: html_select_date<br>
|
||||
* Purpose: Prints the dropdowns for date selection.
|
||||
*
|
||||
* ChangeLog:<br>
|
||||
* - 1.0 initial release
|
||||
* - 1.1 added support for +/- N syntax for begin
|
||||
* and end year values. (Monte)
|
||||
* - 1.2 added support for yyyy-mm-dd syntax for
|
||||
* time value. (Jan Rosier)
|
||||
* - 1.3 added support for choosing format for
|
||||
* month values (Gary Loescher)
|
||||
* - 1.3.1 added support for choosing format for
|
||||
* day values (Marcus Bointon)
|
||||
* - 1.3.2 support negative timestamps, force year
|
||||
* dropdown to include given date unless explicitly set (Monte)
|
||||
* - 1.3.4 fix behaviour of 0000-00-00 00:00:00 dates to match that
|
||||
* of 0000-00-00 dates (cybot, boots)
|
||||
*
|
||||
* @link http://smarty.php.net/manual/en/language.function.html.select.date.php {html_select_date}
|
||||
* (Smarty online manual)
|
||||
* @version 1.3.4
|
||||
* @author Andrei Zmievski
|
||||
* @author Monte Ohrt <monte at ohrt dot com>
|
||||
* @param array $params parameters
|
||||
* @param object $template template object
|
||||
* @return string
|
||||
*/
|
||||
function smarty_function_html_select_date($params, $template)
|
||||
{
|
||||
require_once(SMARTY_PLUGINS_DIR . 'shared.escape_special_chars.php');
|
||||
require_once(SMARTY_PLUGINS_DIR . 'shared.make_timestamp.php');
|
||||
require_once(SMARTY_PLUGINS_DIR . 'function.html_options.php');
|
||||
|
||||
/* Default values. */
|
||||
$prefix = "Date_";
|
||||
$start_year = strftime("%Y");
|
||||
$end_year = $start_year;
|
||||
$display_days = true;
|
||||
$display_months = true;
|
||||
$display_years = true;
|
||||
$month_format = "%B";
|
||||
/* Write months as numbers by default GL */
|
||||
$month_value_format = "%m";
|
||||
$day_format = "%02d";
|
||||
/* Write day values using this format MB */
|
||||
$day_value_format = "%d";
|
||||
$year_as_text = false;
|
||||
/* Display years in reverse order? Ie. 2000,1999,.... */
|
||||
$reverse_years = false;
|
||||
/* Should the select boxes be part of an array when returned from PHP?
|
||||
e.g. setting it to "birthday", would create "birthday[Day]",
|
||||
"birthday[Month]" & "birthday[Year]". Can be combined with prefix */
|
||||
$field_array = null;
|
||||
/* <select size>'s of the different <select> tags.
|
||||
If not set, uses default dropdown. */
|
||||
$day_size = null;
|
||||
$month_size = null;
|
||||
$year_size = null;
|
||||
/* Unparsed attributes common to *ALL* the <select>/<input> tags.
|
||||
An example might be in the template: all_extra ='class ="foo"'. */
|
||||
$all_extra = null;
|
||||
/* Separate attributes for the tags. */
|
||||
$day_extra = null;
|
||||
$month_extra = null;
|
||||
$year_extra = null;
|
||||
/* Order in which to display the fields.
|
||||
"D" -> day, "M" -> month, "Y" -> year. */
|
||||
$field_order = 'MDY';
|
||||
/* String printed between the different fields. */
|
||||
$field_separator = "\n";
|
||||
$time = time();
|
||||
$all_empty = null;
|
||||
$day_empty = null;
|
||||
$month_empty = null;
|
||||
$year_empty = null;
|
||||
$extra_attrs = '';
|
||||
|
||||
foreach ($params as $_key => $_value) {
|
||||
switch ($_key) {
|
||||
case 'prefix':
|
||||
case 'time':
|
||||
case 'start_year':
|
||||
case 'end_year':
|
||||
case 'month_format':
|
||||
case 'day_format':
|
||||
case 'day_value_format':
|
||||
case 'field_array':
|
||||
case 'day_size':
|
||||
case 'month_size':
|
||||
case 'year_size':
|
||||
case 'all_extra':
|
||||
case 'day_extra':
|
||||
case 'month_extra':
|
||||
case 'year_extra':
|
||||
case 'field_order':
|
||||
case 'field_separator':
|
||||
case 'month_value_format':
|
||||
case 'month_empty':
|
||||
case 'day_empty':
|
||||
case 'year_empty':
|
||||
$$_key = (string)$_value;
|
||||
break;
|
||||
|
||||
case 'all_empty':
|
||||
$$_key = (string)$_value;
|
||||
$day_empty = $month_empty = $year_empty = $all_empty;
|
||||
break;
|
||||
|
||||
case 'display_days':
|
||||
case 'display_months':
|
||||
case 'display_years':
|
||||
case 'year_as_text':
|
||||
case 'reverse_years':
|
||||
$$_key = (bool)$_value;
|
||||
break;
|
||||
|
||||
default:
|
||||
if (!is_array($_value)) {
|
||||
$extra_attrs .= ' ' . $_key . '="' . smarty_function_escape_special_chars($_value) . '"';
|
||||
} else {
|
||||
trigger_error("html_select_date: extra attribute '$_key' cannot be an array", E_USER_NOTICE);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (preg_match('!^-\d+$!', $time)) {
|
||||
// negative timestamp, use date()
|
||||
$time = date('Y-m-d', $time);
|
||||
}
|
||||
// If $time is not in format yyyy-mm-dd
|
||||
if (preg_match('/^(\d{0,4}-\d{0,2}-\d{0,2})/', $time, $found)) {
|
||||
$time = $found[1];
|
||||
} else {
|
||||
// use smarty_make_timestamp to get an unix timestamp and
|
||||
// strftime to make yyyy-mm-dd
|
||||
$time = strftime('%Y-%m-%d', smarty_make_timestamp($time));
|
||||
}
|
||||
// Now split this in pieces, which later can be used to set the select
|
||||
$time = explode("-", $time);
|
||||
// make syntax "+N" or "-N" work with start_year and end_year
|
||||
if (preg_match('!^(\+|\-)\s*(\d+)$!', $end_year, $match)) {
|
||||
if ($match[1] == '+') {
|
||||
$end_year = strftime('%Y') + $match[2];
|
||||
} else {
|
||||
$end_year = strftime('%Y') - $match[2];
|
||||
}
|
||||
}
|
||||
if (preg_match('!^(\+|\-)\s*(\d+)$!', $start_year, $match)) {
|
||||
if ($match[1] == '+') {
|
||||
$start_year = strftime('%Y') + $match[2];
|
||||
} else {
|
||||
$start_year = strftime('%Y') - $match[2];
|
||||
}
|
||||
}
|
||||
if (strlen($time[0]) > 0) {
|
||||
if ($start_year > $time[0] && !isset($params['start_year'])) {
|
||||
// force start year to include given date if not explicitly set
|
||||
$start_year = $time[0];
|
||||
}
|
||||
if ($end_year < $time[0] && !isset($params['end_year'])) {
|
||||
// force end year to include given date if not explicitly set
|
||||
$end_year = $time[0];
|
||||
}
|
||||
}
|
||||
|
||||
$field_order = strtoupper($field_order);
|
||||
|
||||
$html_result = $month_result = $day_result = $year_result = "";
|
||||
|
||||
$field_separator_count = -1;
|
||||
if ($display_months) {
|
||||
$field_separator_count++;
|
||||
$month_names = array();
|
||||
$month_values = array();
|
||||
if (isset($month_empty)) {
|
||||
$month_names[''] = $month_empty;
|
||||
$month_values[''] = '';
|
||||
}
|
||||
for ($i = 1; $i <= 12; $i++) {
|
||||
$month_names[$i] = strftime($month_format, mktime(0, 0, 0, $i, 1, 2000));
|
||||
$month_values[$i] = strftime($month_value_format, mktime(0, 0, 0, $i, 1, 2000));
|
||||
}
|
||||
|
||||
$month_result .= '<select name=';
|
||||
if (null !== $field_array) {
|
||||
$month_result .= '"' . $field_array . '[' . $prefix . 'Month]"';
|
||||
} else {
|
||||
$month_result .= '"' . $prefix . 'Month"';
|
||||
}
|
||||
if (null !== $month_size) {
|
||||
$month_result .= ' size="' . $month_size . '"';
|
||||
}
|
||||
if (null !== $month_extra) {
|
||||
$month_result .= ' ' . $month_extra;
|
||||
}
|
||||
if (null !== $all_extra) {
|
||||
$month_result .= ' ' . $all_extra;
|
||||
}
|
||||
$month_result .= $extra_attrs . '>' . "\n";
|
||||
|
||||
$month_result .= smarty_function_html_options(array('output' => $month_names,
|
||||
'values' => $month_values,
|
||||
'selected' => (int)$time[1] ? strftime($month_value_format, mktime(0, 0, 0, (int)$time[1], 1, 2000)) : '',
|
||||
'print_result' => false),
|
||||
$template);
|
||||
$month_result .= '</select>';
|
||||
}
|
||||
|
||||
if ($display_days) {
|
||||
$field_separator_count++;
|
||||
$days = array();
|
||||
if (isset($day_empty)) {
|
||||
$days[''] = $day_empty;
|
||||
$day_values[''] = '';
|
||||
}
|
||||
for ($i = 1; $i <= 31; $i++) {
|
||||
$days[] = sprintf($day_format, $i);
|
||||
$day_values[] = sprintf($day_value_format, $i);
|
||||
}
|
||||
|
||||
$day_result .= '<select name=';
|
||||
if (null !== $field_array) {
|
||||
$day_result .= '"' . $field_array . '[' . $prefix . 'Day]"';
|
||||
} else {
|
||||
$day_result .= '"' . $prefix . 'Day"';
|
||||
}
|
||||
if (null !== $day_size) {
|
||||
$day_result .= ' size="' . $day_size . '"';
|
||||
}
|
||||
if (null !== $all_extra) {
|
||||
$day_result .= ' ' . $all_extra;
|
||||
}
|
||||
if (null !== $day_extra) {
|
||||
$day_result .= ' ' . $day_extra;
|
||||
}
|
||||
$day_result .= $extra_attrs . '>' . "\n";
|
||||
$day_result .= smarty_function_html_options(array('output' => $days,
|
||||
'values' => $day_values,
|
||||
'selected' => $time[2],
|
||||
'print_result' => false),
|
||||
$template);
|
||||
$day_result .= '</select>';
|
||||
}
|
||||
|
||||
if ($display_years) {
|
||||
$field_separator_count++;
|
||||
if (null !== $field_array) {
|
||||
$year_name = $field_array . '[' . $prefix . 'Year]';
|
||||
} else {
|
||||
$year_name = $prefix . 'Year';
|
||||
}
|
||||
if ($year_as_text) {
|
||||
$year_result .= '<input type="text" name="' . $year_name . '" value="' . $time[0] . '" size="4" maxlength="4"';
|
||||
if (null !== $all_extra) {
|
||||
$year_result .= ' ' . $all_extra;
|
||||
}
|
||||
if (null !== $year_extra) {
|
||||
$year_result .= ' ' . $year_extra;
|
||||
}
|
||||
$year_result .= ' />';
|
||||
} else {
|
||||
$years = range((int)$start_year, (int)$end_year);
|
||||
if ($reverse_years) {
|
||||
rsort($years, SORT_NUMERIC);
|
||||
} else {
|
||||
sort($years, SORT_NUMERIC);
|
||||
}
|
||||
$yearvals = $years;
|
||||
if (isset($year_empty)) {
|
||||
array_unshift($years, $year_empty);
|
||||
array_unshift($yearvals, '');
|
||||
}
|
||||
$year_result .= '<select name="' . $year_name . '"';
|
||||
if (null !== $year_size) {
|
||||
$year_result .= ' size="' . $year_size . '"';
|
||||
}
|
||||
if (null !== $all_extra) {
|
||||
$year_result .= ' ' . $all_extra;
|
||||
}
|
||||
if (null !== $year_extra) {
|
||||
$year_result .= ' ' . $year_extra;
|
||||
}
|
||||
$year_result .= $extra_attrs . '>' . "\n";
|
||||
$year_result .= smarty_function_html_options(array('output' => $years,
|
||||
'values' => $yearvals,
|
||||
'selected' => $time[0],
|
||||
'print_result' => false),
|
||||
$template);
|
||||
$year_result .= '</select>';
|
||||
}
|
||||
}
|
||||
// Loop thru the field_order field
|
||||
for ($i = 0; $i <= 2; $i++) {
|
||||
$c = substr($field_order, $i, 1);
|
||||
switch ($c) {
|
||||
case 'D':
|
||||
$html_result .= $day_result;
|
||||
break;
|
||||
|
||||
case 'M':
|
||||
$html_result .= $month_result;
|
||||
break;
|
||||
|
||||
case 'Y':
|
||||
$html_result .= $year_result;
|
||||
break;
|
||||
}
|
||||
// Add the field seperator
|
||||
if ($i < $field_separator_count) {
|
||||
$html_result .= $field_separator;
|
||||
}
|
||||
}
|
||||
|
||||
return $html_result;
|
||||
}
|
||||
|
||||
?>
|
|
@ -0,0 +1,194 @@
|
|||
<?php
|
||||
/**
|
||||
* Smarty plugin
|
||||
*
|
||||
* @package Smarty
|
||||
* @subpackage PluginsFunction
|
||||
*/
|
||||
|
||||
/**
|
||||
* Smarty {html_select_time} function plugin
|
||||
*
|
||||
* Type: function<br>
|
||||
* Name: html_select_time<br>
|
||||
* Purpose: Prints the dropdowns for time selection
|
||||
*
|
||||
* @link http://smarty.php.net/manual/en/language.function.html.select.time.php {html_select_time}
|
||||
* (Smarty online manual)
|
||||
* @author Roberto Berto <roberto@berto.net>
|
||||
* @credits Monte Ohrt <monte AT ohrt DOT com>
|
||||
* @param array $params parameters
|
||||
* @param object $template template object
|
||||
* @return string
|
||||
* @uses smarty_make_timestamp()
|
||||
*/
|
||||
function smarty_function_html_select_time($params, $template)
|
||||
{
|
||||
require_once(SMARTY_PLUGINS_DIR . 'shared.make_timestamp.php');
|
||||
require_once(SMARTY_PLUGINS_DIR . 'function.html_options.php');
|
||||
|
||||
/* Default values. */
|
||||
$prefix = "Time_";
|
||||
$time = time();
|
||||
$display_hours = true;
|
||||
$display_minutes = true;
|
||||
$display_seconds = true;
|
||||
$display_meridian = true;
|
||||
$use_24_hours = true;
|
||||
$minute_interval = 1;
|
||||
$second_interval = 1;
|
||||
/* Should the select boxes be part of an array when returned from PHP?
|
||||
e.g. setting it to "birthday", would create "birthday[Hour]",
|
||||
"birthday[Minute]", "birthday[Seconds]" & "birthday[Meridian]".
|
||||
Can be combined with prefix. */
|
||||
$field_array = null;
|
||||
$all_extra = null;
|
||||
$hour_extra = null;
|
||||
$minute_extra = null;
|
||||
$second_extra = null;
|
||||
$meridian_extra = null;
|
||||
|
||||
foreach ($params as $_key => $_value) {
|
||||
switch ($_key) {
|
||||
case 'prefix':
|
||||
case 'time':
|
||||
case 'field_array':
|
||||
case 'all_extra':
|
||||
case 'hour_extra':
|
||||
case 'minute_extra':
|
||||
case 'second_extra':
|
||||
case 'meridian_extra':
|
||||
$$_key = (string)$_value;
|
||||
break;
|
||||
|
||||
case 'display_hours':
|
||||
case 'display_minutes':
|
||||
case 'display_seconds':
|
||||
case 'display_meridian':
|
||||
case 'use_24_hours':
|
||||
$$_key = (bool)$_value;
|
||||
break;
|
||||
|
||||
case 'minute_interval':
|
||||
case 'second_interval':
|
||||
$$_key = (int)$_value;
|
||||
break;
|
||||
|
||||
default:
|
||||
trigger_error("[html_select_time] unknown parameter $_key", E_USER_WARNING);
|
||||
}
|
||||
}
|
||||
|
||||
$time = smarty_make_timestamp($time);
|
||||
|
||||
$html_result = '';
|
||||
|
||||
if ($display_hours) {
|
||||
$hours = $use_24_hours ? range(0, 23) : range(1, 12);
|
||||
$hour_fmt = $use_24_hours ? '%H' : '%I';
|
||||
for ($i = 0, $for_max = count($hours); $i < $for_max; $i++)
|
||||
$hours[$i] = sprintf('%02d', $hours[$i]);
|
||||
$html_result .= '<select name=';
|
||||
if (null !== $field_array) {
|
||||
$html_result .= '"' . $field_array . '[' . $prefix . 'Hour]"';
|
||||
} else {
|
||||
$html_result .= '"' . $prefix . 'Hour"';
|
||||
}
|
||||
if (null !== $hour_extra) {
|
||||
$html_result .= ' ' . $hour_extra;
|
||||
}
|
||||
if (null !== $all_extra) {
|
||||
$html_result .= ' ' . $all_extra;
|
||||
}
|
||||
$html_result .= '>' . "\n";
|
||||
$html_result .= smarty_function_html_options(array('output' => $hours,
|
||||
'values' => $hours,
|
||||
'selected' => strftime($hour_fmt, $time),
|
||||
'print_result' => false),
|
||||
$template);
|
||||
$html_result .= "</select>\n";
|
||||
}
|
||||
|
||||
if ($display_minutes) {
|
||||
$all_minutes = range(0, 59);
|
||||
for ($i = 0, $for_max = count($all_minutes); $i < $for_max; $i += $minute_interval)
|
||||
$minutes[] = sprintf('%02d', $all_minutes[$i]);
|
||||
$selected = intval(floor(strftime('%M', $time) / $minute_interval) * $minute_interval);
|
||||
$html_result .= '<select name=';
|
||||
if (null !== $field_array) {
|
||||
$html_result .= '"' . $field_array . '[' . $prefix . 'Minute]"';
|
||||
} else {
|
||||
$html_result .= '"' . $prefix . 'Minute"';
|
||||
}
|
||||
if (null !== $minute_extra) {
|
||||
$html_result .= ' ' . $minute_extra;
|
||||
}
|
||||
if (null !== $all_extra) {
|
||||
$html_result .= ' ' . $all_extra;
|
||||
}
|
||||
$html_result .= '>' . "\n";
|
||||
|
||||
$html_result .= smarty_function_html_options(array('output' => $minutes,
|
||||
'values' => $minutes,
|
||||
'selected' => $selected,
|
||||
'print_result' => false),
|
||||
$template);
|
||||
$html_result .= "</select>\n";
|
||||
}
|
||||
|
||||
if ($display_seconds) {
|
||||
$all_seconds = range(0, 59);
|
||||
for ($i = 0, $for_max = count($all_seconds); $i < $for_max; $i += $second_interval)
|
||||
$seconds[] = sprintf('%02d', $all_seconds[$i]);
|
||||
$selected = intval(floor(strftime('%S', $time) / $second_interval) * $second_interval);
|
||||
$html_result .= '<select name=';
|
||||
if (null !== $field_array) {
|
||||
$html_result .= '"' . $field_array . '[' . $prefix . 'Second]"';
|
||||
} else {
|
||||
$html_result .= '"' . $prefix . 'Second"';
|
||||
}
|
||||
|
||||
if (null !== $second_extra) {
|
||||
$html_result .= ' ' . $second_extra;
|
||||
}
|
||||
if (null !== $all_extra) {
|
||||
$html_result .= ' ' . $all_extra;
|
||||
}
|
||||
$html_result .= '>' . "\n";
|
||||
|
||||
$html_result .= smarty_function_html_options(array('output' => $seconds,
|
||||
'values' => $seconds,
|
||||
'selected' => $selected,
|
||||
'print_result' => false),
|
||||
$template);
|
||||
$html_result .= "</select>\n";
|
||||
}
|
||||
|
||||
if ($display_meridian && !$use_24_hours) {
|
||||
$html_result .= '<select name=';
|
||||
if (null !== $field_array) {
|
||||
$html_result .= '"' . $field_array . '[' . $prefix . 'Meridian]"';
|
||||
} else {
|
||||
$html_result .= '"' . $prefix . 'Meridian"';
|
||||
}
|
||||
|
||||
if (null !== $meridian_extra) {
|
||||
$html_result .= ' ' . $meridian_extra;
|
||||
}
|
||||
if (null !== $all_extra) {
|
||||
$html_result .= ' ' . $all_extra;
|
||||
}
|
||||
$html_result .= '>' . "\n";
|
||||
|
||||
$html_result .= smarty_function_html_options(array('output' => array('AM', 'PM'),
|
||||
'values' => array('am', 'pm'),
|
||||
'selected' => strtolower(strftime('%p', $time)),
|
||||
'print_result' => false),
|
||||
$template);
|
||||
$html_result .= "</select>\n";
|
||||
}
|
||||
|
||||
return $html_result;
|
||||
}
|
||||
|
||||
?>
|
|
@ -0,0 +1,177 @@
|
|||
<?php
|
||||
/**
|
||||
* Smarty plugin
|
||||
*
|
||||
* @package Smarty
|
||||
* @subpackage PluginsFunction
|
||||
*/
|
||||
|
||||
/**
|
||||
* Smarty {html_table} function plugin
|
||||
*
|
||||
* Type: function<br>
|
||||
* Name: html_table<br>
|
||||
* Date: Feb 17, 2003<br>
|
||||
* Purpose: make an html table from an array of data<br>
|
||||
*
|
||||
*
|
||||
* Examples:
|
||||
* <pre>
|
||||
* {table loop=$data}
|
||||
* {table loop=$data cols=4 tr_attr='"bgcolor=red"'}
|
||||
* {table loop=$data cols="first,second,third" tr_attr=$colors}
|
||||
* </pre>
|
||||
*
|
||||
* @author Monte Ohrt <monte at ohrt dot com>
|
||||
* @author credit to Messju Mohr <messju at lammfellpuschen dot de>
|
||||
* @author credit to boots <boots dot smarty at yahoo dot com>
|
||||
* @version 1.1
|
||||
* @link http://smarty.php.net/manual/en/language.function.html.table.php {html_table}
|
||||
* (Smarty online manual)
|
||||
* @param array $params parameters
|
||||
* Input:<br>
|
||||
* - loop = array to loop through
|
||||
* - cols = number of columns, comma separated list of column names
|
||||
* or array of column names
|
||||
* - rows = number of rows
|
||||
* - table_attr = table attributes
|
||||
* - th_attr = table heading attributes (arrays are cycled)
|
||||
* - tr_attr = table row attributes (arrays are cycled)
|
||||
* - td_attr = table cell attributes (arrays are cycled)
|
||||
* - trailpad = value to pad trailing cells with
|
||||
* - caption = text for caption element
|
||||
* - vdir = vertical direction (default: "down", means top-to-bottom)
|
||||
* - hdir = horizontal direction (default: "right", means left-to-right)
|
||||
* - inner = inner loop (default "cols": print $loop line by line,
|
||||
* $loop will be printed column by column otherwise)
|
||||
* @param object $template template object
|
||||
* @return string
|
||||
*/
|
||||
function smarty_function_html_table($params, $template)
|
||||
{
|
||||
$table_attr = 'border="1"';
|
||||
$tr_attr = '';
|
||||
$th_attr = '';
|
||||
$td_attr = '';
|
||||
$cols = $cols_count = 3;
|
||||
$rows = 3;
|
||||
$trailpad = ' ';
|
||||
$vdir = 'down';
|
||||
$hdir = 'right';
|
||||
$inner = 'cols';
|
||||
$caption = '';
|
||||
$loop = null;
|
||||
|
||||
if (!isset($params['loop'])) {
|
||||
trigger_error("html_table: missing 'loop' parameter",E_USER_WARNING);
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ($params as $_key => $_value) {
|
||||
switch ($_key) {
|
||||
case 'loop':
|
||||
$$_key = (array)$_value;
|
||||
break;
|
||||
|
||||
case 'cols':
|
||||
if (is_array($_value) && !empty($_value)) {
|
||||
$cols = $_value;
|
||||
$cols_count = count($_value);
|
||||
} elseif (!is_numeric($_value) && is_string($_value) && !empty($_value)) {
|
||||
$cols = explode(',', $_value);
|
||||
$cols_count = count($cols);
|
||||
} elseif (!empty($_value)) {
|
||||
$cols_count = (int)$_value;
|
||||
} else {
|
||||
$cols_count = $cols;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'rows':
|
||||
$$_key = (int)$_value;
|
||||
break;
|
||||
|
||||
case 'table_attr':
|
||||
case 'trailpad':
|
||||
case 'hdir':
|
||||
case 'vdir':
|
||||
case 'inner':
|
||||
case 'caption':
|
||||
$$_key = (string)$_value;
|
||||
break;
|
||||
|
||||
case 'tr_attr':
|
||||
case 'td_attr':
|
||||
case 'th_attr':
|
||||
$$_key = $_value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$loop_count = count($loop);
|
||||
if (empty($params['rows'])) {
|
||||
/* no rows specified */
|
||||
$rows = ceil($loop_count / $cols_count);
|
||||
} elseif (empty($params['cols'])) {
|
||||
if (!empty($params['rows'])) {
|
||||
/* no cols specified, but rows */
|
||||
$cols_count = ceil($loop_count / $rows);
|
||||
}
|
||||
}
|
||||
|
||||
$output = "<table $table_attr>\n";
|
||||
|
||||
if (!empty($caption)) {
|
||||
$output .= '<caption>' . $caption . "</caption>\n";
|
||||
}
|
||||
|
||||
if (is_array($cols)) {
|
||||
$cols = ($hdir == 'right') ? $cols : array_reverse($cols);
|
||||
$output .= "<thead><tr>\n";
|
||||
|
||||
for ($r = 0; $r < $cols_count; $r++) {
|
||||
$output .= '<th' . smarty_function_html_table_cycle('th', $th_attr, $r) . '>';
|
||||
$output .= $cols[$r];
|
||||
$output .= "</th>\n";
|
||||
}
|
||||
$output .= "</tr></thead>\n";
|
||||
}
|
||||
|
||||
$output .= "<tbody>\n";
|
||||
for ($r = 0; $r < $rows; $r++) {
|
||||
$output .= "<tr" . smarty_function_html_table_cycle('tr', $tr_attr, $r) . ">\n";
|
||||
$rx = ($vdir == 'down') ? $r * $cols_count : ($rows-1 - $r) * $cols_count;
|
||||
|
||||
for ($c = 0; $c < $cols_count; $c++) {
|
||||
$x = ($hdir == 'right') ? $rx + $c : $rx + $cols_count-1 - $c;
|
||||
if ($inner != 'cols') {
|
||||
/* shuffle x to loop over rows*/
|
||||
$x = floor($x / $cols_count) + ($x % $cols_count) * $rows;
|
||||
}
|
||||
|
||||
if ($x < $loop_count) {
|
||||
$output .= "<td" . smarty_function_html_table_cycle('td', $td_attr, $c) . ">" . $loop[$x] . "</td>\n";
|
||||
} else {
|
||||
$output .= "<td" . smarty_function_html_table_cycle('td', $td_attr, $c) . ">$trailpad</td>\n";
|
||||
}
|
||||
}
|
||||
$output .= "</tr>\n";
|
||||
}
|
||||
$output .= "</tbody>\n";
|
||||
$output .= "</table>\n";
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
function smarty_function_html_table_cycle($name, $var, $no)
|
||||
{
|
||||
if (!is_array($var)) {
|
||||
$ret = $var;
|
||||
} else {
|
||||
$ret = $var[$no % count($var)];
|
||||
}
|
||||
|
||||
return ($ret) ? ' ' . $ret : '';
|
||||
}
|
||||
|
||||
?>
|
|
@ -0,0 +1,156 @@
|
|||
<?php
|
||||
/**
|
||||
* Smarty plugin
|
||||
*
|
||||
* @package Smarty
|
||||
* @subpackage PluginsFunction
|
||||
*/
|
||||
|
||||
/**
|
||||
* Smarty {mailto} function plugin
|
||||
*
|
||||
* Type: function<br>
|
||||
* Name: mailto<br>
|
||||
* Date: May 21, 2002
|
||||
* Purpose: automate mailto address link creation, and optionally
|
||||
* encode them.<br>
|
||||
*
|
||||
* Examples:
|
||||
* <pre>
|
||||
* {mailto address="me@domain.com"}
|
||||
* {mailto address="me@domain.com" encode="javascript"}
|
||||
* {mailto address="me@domain.com" encode="hex"}
|
||||
* {mailto address="me@domain.com" subject="Hello to you!"}
|
||||
* {mailto address="me@domain.com" cc="you@domain.com,they@domain.com"}
|
||||
* {mailto address="me@domain.com" extra='class="mailto"'}
|
||||
* </pre>
|
||||
*
|
||||
* @link http://smarty.php.net/manual/en/language.function.mailto.php {mailto}
|
||||
* (Smarty online manual)
|
||||
* @version 1.2
|
||||
* @author Monte Ohrt <monte at ohrt dot com>
|
||||
* @author credits to Jason Sweat (added cc, bcc and subject functionality)
|
||||
* @param array $params parameters
|
||||
* Input:<br>
|
||||
* - address = e-mail address
|
||||
* - text = (optional) text to display, default is address
|
||||
* - encode = (optional) can be one of:
|
||||
* * none : no encoding (default)
|
||||
* * javascript : encode with javascript
|
||||
* * javascript_charcode : encode with javascript charcode
|
||||
* * hex : encode with hexidecimal (no javascript)
|
||||
* - cc = (optional) address(es) to carbon copy
|
||||
* - bcc = (optional) address(es) to blind carbon copy
|
||||
* - subject = (optional) e-mail subject
|
||||
* - newsgroups = (optional) newsgroup(s) to post to
|
||||
* - followupto = (optional) address(es) to follow up to
|
||||
* - extra = (optional) extra tags for the href link
|
||||
* @param object $template template object
|
||||
* @return string
|
||||
*/
|
||||
function smarty_function_mailto($params, $template)
|
||||
{
|
||||
$extra = '';
|
||||
|
||||
if (empty($params['address'])) {
|
||||
trigger_error("mailto: missing 'address' parameter",E_USER_WARNING);
|
||||
return;
|
||||
} else {
|
||||
$address = $params['address'];
|
||||
}
|
||||
|
||||
$text = $address;
|
||||
// netscape and mozilla do not decode %40 (@) in BCC field (bug?)
|
||||
// so, don't encode it.
|
||||
$search = array('%40', '%2C');
|
||||
$replace = array('@', ',');
|
||||
$mail_parms = array();
|
||||
foreach ($params as $var => $value) {
|
||||
switch ($var) {
|
||||
case 'cc':
|
||||
case 'bcc':
|
||||
case 'followupto':
|
||||
if (!empty($value))
|
||||
$mail_parms[] = $var . '=' . str_replace($search, $replace, rawurlencode($value));
|
||||
break;
|
||||
|
||||
case 'subject':
|
||||
case 'newsgroups':
|
||||
$mail_parms[] = $var . '=' . rawurlencode($value);
|
||||
break;
|
||||
|
||||
case 'extra':
|
||||
case 'text':
|
||||
$$var = $value;
|
||||
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
$mail_parm_vals = '';
|
||||
for ($i = 0; $i < count($mail_parms); $i++) {
|
||||
$mail_parm_vals .= (0 == $i) ? '?' : '&';
|
||||
$mail_parm_vals .= $mail_parms[$i];
|
||||
}
|
||||
$address .= $mail_parm_vals;
|
||||
|
||||
$encode = (empty($params['encode'])) ? 'none' : $params['encode'];
|
||||
if (!in_array($encode, array('javascript', 'javascript_charcode', 'hex', 'none'))) {
|
||||
trigger_error("mailto: 'encode' parameter must be none, javascript or hex",E_USER_WARNING);
|
||||
return;
|
||||
}
|
||||
|
||||
if ($encode == 'javascript') {
|
||||
$string = 'document.write(\'<a href="mailto:' . $address . '" ' . $extra . '>' . $text . '</a>\');';
|
||||
|
||||
$js_encode = '';
|
||||
for ($x = 0; $x < strlen($string); $x++) {
|
||||
$js_encode .= '%' . bin2hex($string[$x]);
|
||||
}
|
||||
|
||||
return '<script type="text/javascript">eval(unescape(\'' . $js_encode . '\'))</script>';
|
||||
} elseif ($encode == 'javascript_charcode') {
|
||||
$string = '<a href="mailto:' . $address . '" ' . $extra . '>' . $text . '</a>';
|
||||
|
||||
for($x = 0, $y = strlen($string); $x < $y; $x++) {
|
||||
$ord[] = ord($string[$x]);
|
||||
}
|
||||
|
||||
$_ret = "<script type=\"text/javascript\" language=\"javascript\">\n";
|
||||
$_ret .= "<!--\n";
|
||||
$_ret .= "{document.write(String.fromCharCode(";
|
||||
$_ret .= implode(',', $ord);
|
||||
$_ret .= "))";
|
||||
$_ret .= "}\n";
|
||||
$_ret .= "//-->\n";
|
||||
$_ret .= "</script>\n";
|
||||
|
||||
return $_ret;
|
||||
} elseif ($encode == 'hex') {
|
||||
preg_match('!^(.*)(\?.*)$!', $address, $match);
|
||||
if (!empty($match[2])) {
|
||||
trigger_error("mailto: hex encoding does not work with extra attributes. Try javascript.",E_USER_WARNING);
|
||||
return;
|
||||
}
|
||||
$address_encode = '';
|
||||
for ($x = 0; $x < strlen($address); $x++) {
|
||||
if (preg_match('!\w!', $address[$x])) {
|
||||
$address_encode .= '%' . bin2hex($address[$x]);
|
||||
} else {
|
||||
$address_encode .= $address[$x];
|
||||
}
|
||||
}
|
||||
$text_encode = '';
|
||||
for ($x = 0; $x < strlen($text); $x++) {
|
||||
$text_encode .= '&#x' . bin2hex($text[$x]) . ';';
|
||||
}
|
||||
|
||||
$mailto = "mailto:";
|
||||
return '<a href="' . $mailto . $address_encode . '" ' . $extra . '>' . $text_encode . '</a>';
|
||||
} else {
|
||||
// no encoding
|
||||
return '<a href="mailto:' . $address . '" ' . $extra . '>' . $text . '</a>';
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
|
@ -0,0 +1,83 @@
|
|||
<?php
|
||||
/**
|
||||
* Smarty plugin
|
||||
*
|
||||
* This plugin is only for Smarty2 BC
|
||||
* @package Smarty
|
||||
* @subpackage PluginsFunction
|
||||
*/
|
||||
|
||||
/**
|
||||
* Smarty {math} function plugin
|
||||
*
|
||||
* Type: function<br>
|
||||
* Name: math<br>
|
||||
* Purpose: handle math computations in template<br>
|
||||
* @link http://smarty.php.net/manual/en/language.function.math.php {math}
|
||||
* (Smarty online manual)
|
||||
* @author Monte Ohrt <monte at ohrt dot com>
|
||||
* @param array $params parameters
|
||||
* @param object $template template object
|
||||
* @return string|null
|
||||
*/
|
||||
function smarty_function_math($params, $template)
|
||||
{
|
||||
// be sure equation parameter is present
|
||||
if (empty($params['equation'])) {
|
||||
trigger_error("math: missing equation parameter",E_USER_WARNING);
|
||||
return;
|
||||
}
|
||||
|
||||
$equation = $params['equation'];
|
||||
|
||||
// make sure parenthesis are balanced
|
||||
if (substr_count($equation,"(") != substr_count($equation,")")) {
|
||||
trigger_error("math: unbalanced parenthesis",E_USER_WARNING);
|
||||
return;
|
||||
}
|
||||
|
||||
// match all vars in equation, make sure all are passed
|
||||
preg_match_all("!(?:0x[a-fA-F0-9]+)|([a-zA-Z][a-zA-Z0-9_]*)!",$equation, $match);
|
||||
$allowed_funcs = array('int','abs','ceil','cos','exp','floor','log','log10',
|
||||
'max','min','pi','pow','rand','round','sin','sqrt','srand','tan');
|
||||
|
||||
foreach($match[1] as $curr_var) {
|
||||
if ($curr_var && !in_array($curr_var, array_keys($params)) && !in_array($curr_var, $allowed_funcs)) {
|
||||
trigger_error("math: function call $curr_var not allowed",E_USER_WARNING);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
foreach($params as $key => $val) {
|
||||
if ($key != "equation" && $key != "format" && $key != "assign") {
|
||||
// make sure value is not empty
|
||||
if (strlen($val)==0) {
|
||||
trigger_error("math: parameter $key is empty",E_USER_WARNING);
|
||||
return;
|
||||
}
|
||||
if (!is_numeric($val)) {
|
||||
trigger_error("math: parameter $key: is not numeric",E_USER_WARNING);
|
||||
return;
|
||||
}
|
||||
$equation = preg_replace("/\b$key\b/", " \$params['$key'] ", $equation);
|
||||
}
|
||||
}
|
||||
$smarty_math_result = null;
|
||||
eval("\$smarty_math_result = ".$equation.";");
|
||||
|
||||
if (empty($params['format'])) {
|
||||
if (empty($params['assign'])) {
|
||||
return $smarty_math_result;
|
||||
} else {
|
||||
$template->assign($params['assign'],$smarty_math_result);
|
||||
}
|
||||
} else {
|
||||
if (empty($params['assign'])){
|
||||
printf($params['format'],$smarty_math_result);
|
||||
} else {
|
||||
$template->assign($params['assign'],sprintf($params['format'],$smarty_math_result));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
|
@ -0,0 +1,118 @@
|
|||
<?php
|
||||
/**
|
||||
* Smarty plugin
|
||||
*
|
||||
* @package Smarty
|
||||
* @subpackage PluginsFunction
|
||||
*/
|
||||
|
||||
/**
|
||||
* Smarty {popup} function plugin
|
||||
*
|
||||
* Type: function<br>
|
||||
* Name: popup<br>
|
||||
* Purpose: make text pop up in windows via overlib
|
||||
* @link http://smarty.php.net/manual/en/language.function.popup.php {popup}
|
||||
* (Smarty online manual)
|
||||
* @author Monte Ohrt <monte at ohrt dot com>
|
||||
* @param array $params parameters
|
||||
* @param object $template template object
|
||||
* @return string
|
||||
*/
|
||||
function smarty_function_popup($params, $template)
|
||||
{
|
||||
$append = '';
|
||||
foreach ($params as $_key=>$_value) {
|
||||
switch ($_key) {
|
||||
case 'text':
|
||||
case 'trigger':
|
||||
case 'function':
|
||||
case 'inarray':
|
||||
$$_key = (string)$_value;
|
||||
if ($_key == 'function' || $_key == 'inarray')
|
||||
$append .= ',' . strtoupper($_key) . ",'$_value'";
|
||||
break;
|
||||
|
||||
case 'caption':
|
||||
case 'closetext':
|
||||
case 'status':
|
||||
$append .= ',' . strtoupper($_key) . ",'" . str_replace("'","\'",$_value) . "'";
|
||||
break;
|
||||
|
||||
case 'fgcolor':
|
||||
case 'bgcolor':
|
||||
case 'textcolor':
|
||||
case 'capcolor':
|
||||
case 'closecolor':
|
||||
case 'textfont':
|
||||
case 'captionfont':
|
||||
case 'closefont':
|
||||
case 'fgbackground':
|
||||
case 'bgbackground':
|
||||
case 'caparray':
|
||||
case 'capicon':
|
||||
case 'background':
|
||||
case 'frame':
|
||||
$append .= ',' . strtoupper($_key) . ",'$_value'";
|
||||
break;
|
||||
|
||||
case 'textsize':
|
||||
case 'captionsize':
|
||||
case 'closesize':
|
||||
case 'width':
|
||||
case 'height':
|
||||
case 'border':
|
||||
case 'offsetx':
|
||||
case 'offsety':
|
||||
case 'snapx':
|
||||
case 'snapy':
|
||||
case 'fixx':
|
||||
case 'fixy':
|
||||
case 'padx':
|
||||
case 'pady':
|
||||
case 'timeout':
|
||||
case 'delay':
|
||||
$append .= ',' . strtoupper($_key) . ",$_value";
|
||||
break;
|
||||
|
||||
case 'sticky':
|
||||
case 'left':
|
||||
case 'right':
|
||||
case 'center':
|
||||
case 'above':
|
||||
case 'below':
|
||||
case 'noclose':
|
||||
case 'autostatus':
|
||||
case 'autostatuscap':
|
||||
case 'fullhtml':
|
||||
case 'hauto':
|
||||
case 'vauto':
|
||||
case 'mouseoff':
|
||||
case 'followmouse':
|
||||
case 'closeclick':
|
||||
case 'wrap':
|
||||
if ($_value) $append .= ',' . strtoupper($_key);
|
||||
break;
|
||||
|
||||
default:
|
||||
trigger_error("[popup] unknown parameter $_key", E_USER_WARNING);
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($text) && !isset($inarray) && empty($function)) {
|
||||
trigger_error("overlib: attribute 'text' or 'inarray' or 'function' required",E_USER_WARNING);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (empty($trigger)) { $trigger = "onmouseover"; }
|
||||
|
||||
$retval = $trigger . '="return overlib(\''.preg_replace(array("!'!",'!"!',"![\r\n]!"),array("\'","\'",'\r'),$text).'\'';
|
||||
$retval .= $append . ');"';
|
||||
if ($trigger == 'onmouseover')
|
||||
$retval .= ' onmouseout="nd();"';
|
||||
|
||||
|
||||
return $retval;
|
||||
}
|
||||
|
||||
?>
|
|
@ -0,0 +1,39 @@
|
|||
<?php
|
||||
/**
|
||||
* Smarty plugin
|
||||
*
|
||||
* @package Smarty
|
||||
* @subpackage PluginsFunction
|
||||
*/
|
||||
|
||||
/**
|
||||
* Smarty {popup_init} function plugin
|
||||
*
|
||||
* Type: function<br>
|
||||
* Name: popup_init<br>
|
||||
* Purpose: initialize overlib
|
||||
* @link http://smarty.php.net/manual/en/language.function.popup.init.php {popup_init}
|
||||
* (Smarty online manual)
|
||||
* @author Monte Ohrt <monte at ohrt dot com>
|
||||
* @param array $params parameters
|
||||
* @param object $template template object
|
||||
* @return string
|
||||
*/
|
||||
|
||||
function smarty_function_popup_init($params, $template)
|
||||
{
|
||||
$zindex = 1000;
|
||||
|
||||
if (!empty($params['zindex'])) {
|
||||
$zindex = $params['zindex'];
|
||||
}
|
||||
|
||||
if (!empty($params['src'])) {
|
||||
return '<div id="overDiv" style="position:absolute; visibility:hidden; z-index:'.$zindex.';"></div>' . "\n"
|
||||
. '<script type="text/javascript" language="JavaScript" src="'.$params['src'].'"></script>' . "\n";
|
||||
} else {
|
||||
trigger_error("popup_init: missing src parameter",E_USER_WARNING);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
|
@ -0,0 +1,37 @@
|
|||
<?php
|
||||
/**
|
||||
* Smarty plugin
|
||||
*
|
||||
* @package Smarty
|
||||
* @subpackage PluginsModifier
|
||||
*/
|
||||
|
||||
/**
|
||||
* Smarty capitalize modifier plugin
|
||||
*
|
||||
* Type: modifier<br>
|
||||
* Name: capitalize<br>
|
||||
* Purpose: capitalize words in the string
|
||||
*
|
||||
* @link
|
||||
* @author Monte Ohrt <monte at ohrt dot com>
|
||||
* @param string $
|
||||
* @return string
|
||||
*/
|
||||
function smarty_modifier_capitalize($string, $uc_digits = false)
|
||||
{
|
||||
// uppercase with php function ucwords
|
||||
$upper_string = ucwords($string);
|
||||
// check for any missed hyphenated words
|
||||
$upper_string = preg_replace("!(^|[^\p{L}'])([\p{Ll}])!ue", "'\\1'.ucfirst('\\2')", $upper_string);
|
||||
// check uc_digits case
|
||||
if (!$uc_digits) {
|
||||
if (preg_match_all("!\b([\p{L}]*[\p{N}]+[\p{L}]*)\b!u", $string, $matches, PREG_OFFSET_CAPTURE)) {
|
||||
foreach($matches[1] as $match)
|
||||
$upper_string = substr_replace($upper_string, $match[0], $match[1], strlen($match[0]));
|
||||
}
|
||||
}
|
||||
return $upper_string;
|
||||
}
|
||||
|
||||
?>
|
|
@ -0,0 +1,61 @@
|
|||
<?php
|
||||
/**
|
||||
* Smarty plugin
|
||||
*
|
||||
* @package Smarty
|
||||
* @subpackage PluginsModifier
|
||||
*/
|
||||
|
||||
/**
|
||||
* Smarty date_format modifier plugin
|
||||
*
|
||||
* Type: modifier<br>
|
||||
* Name: date_format<br>
|
||||
* Purpose: format datestamps via strftime<br>
|
||||
* Input:<br>
|
||||
* - string: input date string
|
||||
* - format: strftime format for output
|
||||
* - default_date: default date if $string is empty
|
||||
*
|
||||
* @link http://smarty.php.net/manual/en/language.modifier.date.format.php date_format (Smarty online manual)
|
||||
* @author Monte Ohrt <monte at ohrt dot com>
|
||||
* @param string $
|
||||
* @param string $
|
||||
* @param string $
|
||||
* @return string |void
|
||||
* @uses smarty_make_timestamp()
|
||||
*/
|
||||
function smarty_modifier_date_format($string, $format = SMARTY_RESOURCE_DATE_FORMAT, $default_date = '',$formatter='auto')
|
||||
{
|
||||
/**
|
||||
* Include the {@link shared.make_timestamp.php} plugin
|
||||
*/
|
||||
require_once(SMARTY_PLUGINS_DIR . 'shared.make_timestamp.php');
|
||||
if ($string != '') {
|
||||
$timestamp = smarty_make_timestamp($string);
|
||||
} elseif ($default_date != '') {
|
||||
$timestamp = smarty_make_timestamp($default_date);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
if($formatter=='strftime'||($formatter=='auto'&&strpos($format,'%')!==false)) {
|
||||
if (DS == '\\') {
|
||||
$_win_from = array('%D', '%h', '%n', '%r', '%R', '%t', '%T');
|
||||
$_win_to = array('%m/%d/%y', '%b', "\n", '%I:%M:%S %p', '%H:%M', "\t", '%H:%M:%S');
|
||||
if (strpos($format, '%e') !== false) {
|
||||
$_win_from[] = '%e';
|
||||
$_win_to[] = sprintf('%\' 2d', date('j', $timestamp));
|
||||
}
|
||||
if (strpos($format, '%l') !== false) {
|
||||
$_win_from[] = '%l';
|
||||
$_win_to[] = sprintf('%\' 2d', date('h', $timestamp));
|
||||
}
|
||||
$format = str_replace($_win_from, $_win_to, $format);
|
||||
}
|
||||
return strftime($format, $timestamp);
|
||||
} else {
|
||||
return date($format, $timestamp);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
|
@ -0,0 +1,87 @@
|
|||
<?php
|
||||
/**
|
||||
* Smarty plugin
|
||||
*
|
||||
* @package Smarty
|
||||
* @subpackage Debug
|
||||
*/
|
||||
|
||||
/**
|
||||
* Smarty debug_print_var modifier plugin
|
||||
*
|
||||
* Type: modifier<br>
|
||||
* Name: debug_print_var<br>
|
||||
* Purpose: formats variable contents for display in the console
|
||||
*
|
||||
* @link http://smarty.php.net/manual/en/language.modifier.debug.print.var.php debug_print_var (Smarty online manual)
|
||||
* @author Monte Ohrt <monte at ohrt dot com>
|
||||
* @param array $ |object
|
||||
* @param integer $
|
||||
* @param integer $
|
||||
* @return string
|
||||
*/
|
||||
function smarty_modifier_debug_print_var ($var, $depth = 0, $length = 40)
|
||||
{
|
||||
$_replace = array("\n" => '<i>\n</i>',
|
||||
"\r" => '<i>\r</i>',
|
||||
"\t" => '<i>\t</i>'
|
||||
);
|
||||
|
||||
switch (gettype($var)) {
|
||||
case 'array' :
|
||||
$results = '<b>Array (' . count($var) . ')</b>';
|
||||
foreach ($var as $curr_key => $curr_val) {
|
||||
$results .= '<br>' . str_repeat(' ', $depth * 2)
|
||||
. '<b>' . strtr($curr_key, $_replace) . '</b> => '
|
||||
. smarty_modifier_debug_print_var($curr_val, ++$depth, $length);
|
||||
$depth--;
|
||||
}
|
||||
break;
|
||||
case 'object' :
|
||||
$object_vars = get_object_vars($var);
|
||||
$results = '<b>' . get_class($var) . ' Object (' . count($object_vars) . ')</b>';
|
||||
foreach ($object_vars as $curr_key => $curr_val) {
|
||||
$results .= '<br>' . str_repeat(' ', $depth * 2)
|
||||
. '<b> ->' . strtr($curr_key, $_replace) . '</b> = '
|
||||
. smarty_modifier_debug_print_var($curr_val, ++$depth, $length);
|
||||
$depth--;
|
||||
}
|
||||
break;
|
||||
case 'boolean' :
|
||||
case 'NULL' :
|
||||
case 'resource' :
|
||||
if (true === $var) {
|
||||
$results = 'true';
|
||||
} elseif (false === $var) {
|
||||
$results = 'false';
|
||||
} elseif (null === $var) {
|
||||
$results = 'null';
|
||||
} else {
|
||||
$results = htmlspecialchars((string) $var);
|
||||
}
|
||||
$results = '<i>' . $results . '</i>';
|
||||
break;
|
||||
case 'integer' :
|
||||
case 'float' :
|
||||
$results = htmlspecialchars((string) $var);
|
||||
break;
|
||||
case 'string' :
|
||||
$results = strtr($var, $_replace);
|
||||
if (strlen($var) > $length) {
|
||||
$results = substr($var, 0, $length - 3) . '...';
|
||||
}
|
||||
$results = htmlspecialchars('"' . $results . '"');
|
||||
break;
|
||||
case 'unknown type' :
|
||||
default :
|
||||
$results = strtr((string) $var, $_replace);
|
||||
if (strlen($results) > $length) {
|
||||
$results = substr($results, 0, $length - 3) . '...';
|
||||
}
|
||||
$results = htmlspecialchars($results);
|
||||
}
|
||||
|
||||
return $results;
|
||||
}
|
||||
|
||||
?>
|
|
@ -0,0 +1,114 @@
|
|||
<?php
|
||||
/**
|
||||
* Smarty plugin
|
||||
*
|
||||
* @package Smarty
|
||||
* @subpackage PluginsModifier
|
||||
*/
|
||||
|
||||
/**
|
||||
* Smarty escape modifier plugin
|
||||
*
|
||||
* Type: modifier<br>
|
||||
* Name: escape<br>
|
||||
* Purpose: escape string for output
|
||||
*
|
||||
* @link http://smarty.php.net/manual/en/language.modifier.count.characters.php count_characters (Smarty online manual)
|
||||
* @author Monte Ohrt <monte at ohrt dot com>
|
||||
* @param string $string input string
|
||||
* @param string $esc_type escape type
|
||||
* @param string $char_set character set
|
||||
* @return string escaped input string
|
||||
*/
|
||||
function smarty_modifier_escape($string, $esc_type = 'html', $char_set = SMARTY_RESOURCE_CHAR_SET)
|
||||
{
|
||||
if (!function_exists('mb_str_replace')) {
|
||||
// simulate the missing PHP mb_str_replace function
|
||||
function mb_str_replace($needles, $replacements, $haystack)
|
||||
{
|
||||
$rep = (array)$replacements;
|
||||
foreach ((array)$needles as $key => $needle) {
|
||||
$replacement = $rep[$key];
|
||||
$needle_len = mb_strlen($needle);
|
||||
$replacement_len = mb_strlen($replacement);
|
||||
$pos = mb_strpos($haystack, $needle, 0);
|
||||
while ($pos !== false) {
|
||||
$haystack = mb_substr($haystack, 0, $pos) . $replacement
|
||||
. mb_substr($haystack, $pos + $needle_len);
|
||||
$pos = mb_strpos($haystack, $needle, $pos + $replacement_len);
|
||||
}
|
||||
}
|
||||
return $haystack;
|
||||
}
|
||||
}
|
||||
switch ($esc_type) {
|
||||
case 'html':
|
||||
return htmlspecialchars($string, ENT_QUOTES, $char_set);
|
||||
|
||||
case 'htmlall':
|
||||
return htmlentities($string, ENT_QUOTES, $char_set);
|
||||
|
||||
case 'url':
|
||||
return rawurlencode($string);
|
||||
|
||||
case 'urlpathinfo':
|
||||
return str_replace('%2F', '/', rawurlencode($string));
|
||||
|
||||
case 'quotes':
|
||||
// escape unescaped single quotes
|
||||
return preg_replace("%(?<!\\\\)'%", "\\'", $string);
|
||||
|
||||
case 'hex':
|
||||
// escape every character into hex
|
||||
$return = '';
|
||||
for ($x = 0; $x < strlen($string); $x++) {
|
||||
$return .= '%' . bin2hex($string[$x]);
|
||||
}
|
||||
return $return;
|
||||
|
||||
case 'hexentity':
|
||||
$return = '';
|
||||
for ($x = 0; $x < strlen($string); $x++) {
|
||||
$return .= '&#x' . bin2hex($string[$x]) . ';';
|
||||
}
|
||||
return $return;
|
||||
|
||||
case 'decentity':
|
||||
$return = '';
|
||||
for ($x = 0; $x < strlen($string); $x++) {
|
||||
$return .= '&#' . ord($string[$x]) . ';';
|
||||
}
|
||||
return $return;
|
||||
|
||||
case 'javascript':
|
||||
// escape quotes and backslashes, newlines, etc.
|
||||
return strtr($string, array('\\' => '\\\\', "'" => "\\'", '"' => '\\"', "\r" => '\\r', "\n" => '\\n', '</' => '<\/'));
|
||||
|
||||
case 'mail':
|
||||
// safe way to display e-mail address on a web page
|
||||
if (function_exists('mb_substr')) {
|
||||
return mb_str_replace(array('@', '.'), array(' [AT] ', ' [DOT] '), $string);
|
||||
} else {
|
||||
return str_replace(array('@', '.'), array(' [AT] ', ' [DOT] '), $string);
|
||||
}
|
||||
|
||||
case 'nonstd':
|
||||
// escape non-standard chars, such as ms document quotes
|
||||
$_res = '';
|
||||
for($_i = 0, $_len = strlen($string); $_i < $_len; $_i++) {
|
||||
$_ord = ord(substr($string, $_i, 1));
|
||||
// non-standard char, escape it
|
||||
if ($_ord >= 126) {
|
||||
$_res .= '&#' . $_ord . ';';
|
||||
} else {
|
||||
$_res .= substr($string, $_i, 1);
|
||||
}
|
||||
}
|
||||
return $_res;
|
||||
|
||||
default:
|
||||
return $string;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
|
@ -0,0 +1,46 @@
|
|||
<?php
|
||||
/**
|
||||
* Smarty plugin
|
||||
*
|
||||
* @package Smarty
|
||||
* @subpackage PluginsModifier
|
||||
*/
|
||||
|
||||
/**
|
||||
* Smarty regex_replace modifier plugin
|
||||
*
|
||||
* Type: modifier<br>
|
||||
* Name: regex_replace<br>
|
||||
* Purpose: regular expression search/replace
|
||||
* @link http://smarty.php.net/manual/en/language.modifier.regex.replace.php
|
||||
* regex_replace (Smarty online manual)
|
||||
* @author Monte Ohrt <monte at ohrt dot com>
|
||||
* @param string
|
||||
* @param string|array
|
||||
* @param string|array
|
||||
* @return string
|
||||
*/
|
||||
function smarty_modifier_regex_replace($string, $search, $replace)
|
||||
{
|
||||
if(is_array($search)) {
|
||||
foreach($search as $idx => $s)
|
||||
$search[$idx] = _smarty_regex_replace_check($s);
|
||||
} else {
|
||||
$search = _smarty_regex_replace_check($search);
|
||||
}
|
||||
|
||||
return preg_replace($search, $replace, $string);
|
||||
}
|
||||
|
||||
function _smarty_regex_replace_check($search)
|
||||
{
|
||||
if (($pos = strpos($search,"\0")) !== false)
|
||||
$search = substr($search,0,$pos);
|
||||
if (preg_match('!([a-zA-Z\s]+)$!s', $search, $match) && (strpos($match[1], 'e') !== false)) {
|
||||
/* remove eval-modifier from $search */
|
||||
$search = substr($search, 0, -strlen($match[1])) . preg_replace('![e\s]+!', '', $match[1]);
|
||||
}
|
||||
return $search;
|
||||
}
|
||||
|
||||
?>
|
|
@ -0,0 +1,51 @@
|
|||
<?php
|
||||
/**
|
||||
* Smarty plugin
|
||||
* @package Smarty
|
||||
* @subpackage PluginsModifier
|
||||
*/
|
||||
|
||||
/**
|
||||
* Smarty replace modifier plugin
|
||||
*
|
||||
* Type: modifier<br>
|
||||
* Name: replace<br>
|
||||
* Purpose: simple search/replace
|
||||
*
|
||||
* @link http://smarty.php.net/manual/en/language.modifier.replace.php replace (Smarty online manual)
|
||||
* @author Monte Ohrt <monte at ohrt dot com>
|
||||
* @author Uwe Tews
|
||||
* @param string $
|
||||
* @param string $
|
||||
* @param string $
|
||||
* @return string
|
||||
*/
|
||||
function smarty_modifier_replace($string, $search, $replace)
|
||||
{
|
||||
if (!function_exists('mb_str_replace')) {
|
||||
// simulate the missing PHP mb_str_replace function
|
||||
function mb_str_replace($needles, $replacements, $haystack)
|
||||
{
|
||||
$rep = (array)$replacements;
|
||||
foreach ((array)$needles as $key => $needle) {
|
||||
$replacement = $rep[$key];
|
||||
$needle_len = mb_strlen($needle);
|
||||
$replacement_len = mb_strlen($replacement);
|
||||
$pos = mb_strpos($haystack, $needle, 0);
|
||||
while ($pos !== false) {
|
||||
$haystack = mb_substr($haystack, 0, $pos) . $replacement
|
||||
. mb_substr($haystack, $pos + $needle_len);
|
||||
$pos = mb_strpos($haystack, $needle, $pos + $replacement_len);
|
||||
}
|
||||
}
|
||||
return $haystack;
|
||||
}
|
||||
}
|
||||
if (function_exists('mb_substr')) {
|
||||
return mb_str_replace($search, $replace, $string);
|
||||
} else {
|
||||
return str_replace($search, $replace, $string);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
|
@ -0,0 +1,37 @@
|
|||
<?php
|
||||
/**
|
||||
* Smarty plugin
|
||||
* @package Smarty
|
||||
* @subpackage PluginsModifier
|
||||
*/
|
||||
|
||||
/**
|
||||
* Smarty spacify modifier plugin
|
||||
*
|
||||
* Type: modifier<br>
|
||||
* Name: spacify<br>
|
||||
* Purpose: add spaces between characters in a string
|
||||
*
|
||||
* @link http://smarty.php.net/manual/en/language.modifier.spacify.php spacify (Smarty online manual)
|
||||
* @author Monte Ohrt <monte at ohrt dot com>
|
||||
* @param string $
|
||||
* @param string $
|
||||
* @return string
|
||||
*/
|
||||
function smarty_modifier_spacify($string, $spacify_char = ' ')
|
||||
{
|
||||
// mb_ functions available?
|
||||
if (function_exists('mb_strlen') && mb_detect_encoding($string, 'UTF-8, ISO-8859-1') === 'UTF-8') {
|
||||
$strlen = mb_strlen($string);
|
||||
while ($strlen) {
|
||||
$array[] = mb_substr($string, 0, 1, "UTF-8");
|
||||
$string = mb_substr($string, 1, $strlen, "UTF-8");
|
||||
$strlen = mb_strlen($string);
|
||||
}
|
||||
return implode($spacify_char, $array);
|
||||
} else {
|
||||
return implode($spacify_char, preg_split('//', $string, -1));
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
|
@ -0,0 +1,67 @@
|
|||
<?php
|
||||
/**
|
||||
* Smarty plugin
|
||||
*
|
||||
* @package Smarty
|
||||
* @subpackage PluginsModifier
|
||||
*/
|
||||
|
||||
/**
|
||||
* Smarty truncate modifier plugin
|
||||
*
|
||||
* Type: modifier<br>
|
||||
* Name: truncate<br>
|
||||
* Purpose: Truncate a string to a certain length if necessary,
|
||||
* optionally splitting in the middle of a word, and
|
||||
* appending the $etc string or inserting $etc into the middle.
|
||||
*
|
||||
* @link http://smarty.php.net/manual/en/language.modifier.truncate.php truncate (Smarty online manual)
|
||||
* @author Monte Ohrt <monte at ohrt dot com>
|
||||
* @param string $string input string
|
||||
* @param integer $length lenght of truncated text
|
||||
* @param string $etc end string
|
||||
* @param boolean $break_words truncate at word boundary
|
||||
* @param boolean $middle truncate in the middle of text
|
||||
* @return string truncated string
|
||||
*/
|
||||
function smarty_modifier_truncate($string, $length = 80, $etc = '...',
|
||||
$break_words = false, $middle = false)
|
||||
{
|
||||
if ($length == 0)
|
||||
return '';
|
||||
|
||||
if (is_callable('mb_strlen')) {
|
||||
if (mb_detect_encoding($string, 'UTF-8, ISO-8859-1') === 'UTF-8') {
|
||||
// $string has utf-8 encoding
|
||||
if (mb_strlen($string) > $length) {
|
||||
$length -= min($length, mb_strlen($etc));
|
||||
if (!$break_words && !$middle) {
|
||||
$string = preg_replace('/\s+?(\S+)?$/u', '', mb_substr($string, 0, $length + 1));
|
||||
}
|
||||
if (!$middle) {
|
||||
return mb_substr($string, 0, $length) . $etc;
|
||||
} else {
|
||||
return mb_substr($string, 0, $length / 2) . $etc . mb_substr($string, - $length / 2);
|
||||
}
|
||||
} else {
|
||||
return $string;
|
||||
}
|
||||
}
|
||||
}
|
||||
// $string has no utf-8 encoding
|
||||
if (strlen($string) > $length) {
|
||||
$length -= min($length, strlen($etc));
|
||||
if (!$break_words && !$middle) {
|
||||
$string = preg_replace('/\s+?(\S+)?$/', '', substr($string, 0, $length + 1));
|
||||
}
|
||||
if (!$middle) {
|
||||
return substr($string, 0, $length) . $etc;
|
||||
} else {
|
||||
return substr($string, 0, $length / 2) . $etc . substr($string, - $length / 2);
|
||||
}
|
||||
} else {
|
||||
return $string;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
|
@ -0,0 +1,29 @@
|
|||
<?php
|
||||
/**
|
||||
* Smarty plugin
|
||||
*
|
||||
* @package Smarty
|
||||
* @subpackage PluginsModifierCompiler
|
||||
*/
|
||||
|
||||
/**
|
||||
* Smarty cat modifier plugin
|
||||
*
|
||||
* Type: modifier<br>
|
||||
* Name: cat<br>
|
||||
* Date: Feb 24, 2003
|
||||
* Purpose: catenate a value to a variable
|
||||
* Input: string to catenate
|
||||
* Example: {$var|cat:"foo"}
|
||||
* @link http://smarty.php.net/manual/en/language.modifier.cat.php cat
|
||||
* (Smarty online manual)
|
||||
* @author Uwe Tews
|
||||
* @param array $params parameters
|
||||
* @return string with compiled code
|
||||
*/
|
||||
function smarty_modifiercompiler_cat($params, $compiler)
|
||||
{
|
||||
return '('.implode(').(', $params).')';
|
||||
}
|
||||
|
||||
?>
|
|
@ -0,0 +1,39 @@
|
|||
<?php
|
||||
/**
|
||||
* Smarty plugin
|
||||
*
|
||||
* @package Smarty
|
||||
* @subpackage PluginsModifierCompiler
|
||||
*/
|
||||
|
||||
/**
|
||||
* Smarty count_characters modifier plugin
|
||||
*
|
||||
* Type: modifier<br>
|
||||
* Name: count_characteres<br>
|
||||
* Purpose: count the number of characters in a text
|
||||
*
|
||||
* @link http://smarty.php.net/manual/en/language.modifier.count.characters.php count_characters (Smarty online manual)
|
||||
* @author Uwe Tews
|
||||
* @param array $params parameters
|
||||
* @return string with compiled code
|
||||
*/
|
||||
function smarty_modifiercompiler_count_characters($params, $compiler)
|
||||
{
|
||||
// mb_ functions available?
|
||||
if (function_exists('mb_strlen')) {
|
||||
// count also spaces?
|
||||
if (isset($params[1]) && $params[1] == 'true') {
|
||||
return '((mb_detect_encoding(' . $params[0] . ', \'UTF-8, ISO-8859-1\') === \'UTF-8\') ? mb_strlen(' . $params[0] . ', SMARTY_RESOURCE_CHAR_SET) : strlen(' . $params[0] . '))';
|
||||
}
|
||||
return '((mb_detect_encoding(' . $params[0] . ', \'UTF-8, ISO-8859-1\') === \'UTF-8\') ? preg_match_all(\'#[^\s\pZ]#u\', ' . $params[0] . ', $tmp) : preg_match_all(\'/[^\s]/\',' . $params[0] . ', $tmp))';
|
||||
} else {
|
||||
// count also spaces?
|
||||
if (isset($params[1]) && $params[1] == 'true') {
|
||||
return 'strlen(' . $params[0] . ')';
|
||||
}
|
||||
return 'preg_match_all(\'/[^\s]/\',' . $params[0] . ', $tmp)';
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
|
@ -0,0 +1,27 @@
|
|||
<?php
|
||||
/**
|
||||
* Smarty plugin
|
||||
*
|
||||
* @package Smarty
|
||||
* @subpackage PluginsModifierCompiler
|
||||
*/
|
||||
|
||||
/**
|
||||
* Smarty count_paragraphs modifier plugin
|
||||
*
|
||||
* Type: modifier<br>
|
||||
* Name: count_paragraphs<br>
|
||||
* Purpose: count the number of paragraphs in a text
|
||||
* @link http://smarty.php.net/manual/en/language.modifier.count.paragraphs.php
|
||||
* count_paragraphs (Smarty online manual)
|
||||
* @author Uwe Tews
|
||||
* @param array $params parameters
|
||||
* @return string with compiled code
|
||||
*/
|
||||
function smarty_modifiercompiler_count_paragraphs($params, $compiler)
|
||||
{
|
||||
// count \r or \n characters
|
||||
return '(preg_match_all(\'#[\r\n]+#\', ' . $params[0] . ', $tmp)+1)';
|
||||
}
|
||||
|
||||
?>
|
|
@ -0,0 +1,27 @@
|
|||
<?php
|
||||
/**
|
||||
* Smarty plugin
|
||||
*
|
||||
* @package Smarty
|
||||
* @subpackage PluginsModifierCompiler
|
||||
*/
|
||||
|
||||
/**
|
||||
* Smarty count_sentences modifier plugin
|
||||
*
|
||||
* Type: modifier<br>
|
||||
* Name: count_sentences
|
||||
* Purpose: count the number of sentences in a text
|
||||
* @link http://smarty.php.net/manual/en/language.modifier.count.paragraphs.php
|
||||
* count_sentences (Smarty online manual)
|
||||
* @author Uwe Tews
|
||||
* @param array $params parameters
|
||||
* @return string with compiled code
|
||||
*/
|
||||
function smarty_modifiercompiler_count_sentences($params, $compiler)
|
||||
{
|
||||
// find periods with a word before but not after.
|
||||
return 'preg_match_all(\'/[^\s]\.(?!\w)/\', ' . $params[0] . ', $tmp)';
|
||||
}
|
||||
|
||||
?>
|
|
@ -0,0 +1,31 @@
|
|||
<?php
|
||||
/**
|
||||
* Smarty plugin
|
||||
*
|
||||
* @package Smarty
|
||||
* @subpackage PluginsModifierCompiler
|
||||
*/
|
||||
|
||||
/**
|
||||
* Smarty count_words modifier plugin
|
||||
*
|
||||
* Type: modifier<br>
|
||||
* Name: count_words<br>
|
||||
* Purpose: count the number of words in a text
|
||||
*
|
||||
* @link http://smarty.php.net/manual/en/language.modifier.count.words.php count_words (Smarty online manual)
|
||||
* @author Uwe Tews
|
||||
* @param array $params parameters
|
||||
* @return string with compiled code
|
||||
*/
|
||||
function smarty_modifiercompiler_count_words($params, $compiler)
|
||||
{
|
||||
// mb_ functions available?
|
||||
if (function_exists('mb_strlen')) {
|
||||
return '((mb_detect_encoding(' . $params[0] . ', \'UTF-8, ISO-8859-1\') === \'UTF-8\') ? preg_match_all(\'#[\w\pL]+#u\', ' . $params[0] . ', $tmp) : preg_match_all(\'#\w+#\',' . $params[0] . ', $tmp))';
|
||||
} else {
|
||||
return 'str_word_count(' . $params[0] . ')';
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
|
@ -0,0 +1,33 @@
|
|||
<?php
|
||||
/**
|
||||
* Smarty plugin
|
||||
*
|
||||
* @package Smarty
|
||||
* @subpackage PluginsModifierCompiler
|
||||
*/
|
||||
|
||||
/**
|
||||
* Smarty default modifier plugin
|
||||
*
|
||||
* Type: modifier<br>
|
||||
* Name: default<br>
|
||||
* Purpose: designate default value for empty variables
|
||||
*
|
||||
* @link http://smarty.php.net/manual/en/language.modifier.default.php default (Smarty online manual)
|
||||
* @author Uwe Tews
|
||||
* @param array $params parameters
|
||||
* @return string with compiled code
|
||||
*/
|
||||
function smarty_modifiercompiler_default ($params, $compiler)
|
||||
{
|
||||
$output = $params[0];
|
||||
if (!isset($params[1])) {
|
||||
$params[1] = "''";
|
||||
}
|
||||
for ($i = 1, $cnt = count($params); $i < $cnt; $i++) {
|
||||
$output = '(($tmp = @' . $output . ')===null||$tmp===\'\' ? ' . $params[$i] . ' : $tmp)';
|
||||
}
|
||||
return $output;
|
||||
}
|
||||
|
||||
?>
|
|
@ -0,0 +1,32 @@
|
|||
<?php
|
||||
/**
|
||||
* Smarty plugin
|
||||
* @package Smarty
|
||||
* @subpackage PluginsModifierCompiler
|
||||
*/
|
||||
|
||||
/**
|
||||
* Smarty indent modifier plugin
|
||||
*
|
||||
* Type: modifier<br>
|
||||
* Name: indent<br>
|
||||
* Purpose: indent lines of text
|
||||
* @link http://smarty.php.net/manual/en/language.modifier.indent.php
|
||||
* indent (Smarty online manual)
|
||||
* @author Uwe Tews
|
||||
* @param array $params parameters
|
||||
* @return string with compiled code
|
||||
*/
|
||||
|
||||
function smarty_modifiercompiler_indent($params, $compiler)
|
||||
{
|
||||
if (!isset($params[1])) {
|
||||
$params[1] = 4;
|
||||
}
|
||||
if (!isset($params[2])) {
|
||||
$params[2] = "' '";
|
||||
}
|
||||
return 'preg_replace(\'!^!m\',str_repeat(' . $params[2] . ',' . $params[1] . '),' . $params[0] . ')';
|
||||
}
|
||||
|
||||
?>
|
|
@ -0,0 +1,31 @@
|
|||
<?php
|
||||
/**
|
||||
* Smarty plugin
|
||||
* @package Smarty
|
||||
* @subpackage PluginsModifierCompiler
|
||||
*/
|
||||
|
||||
/**
|
||||
* Smarty lower modifier plugin
|
||||
*
|
||||
* Type: modifier<br>
|
||||
* Name: lower<br>
|
||||
* Purpose: convert string to lowercase
|
||||
*
|
||||
* @link http://smarty.php.net/manual/en/language.modifier.lower.php lower (Smarty online manual)
|
||||
* @author Monte Ohrt <monte at ohrt dot com>
|
||||
* @author Uwe Tews
|
||||
* @param array $params parameters
|
||||
* @return string with compiled code
|
||||
*/
|
||||
|
||||
function smarty_modifiercompiler_lower($params, $compiler)
|
||||
{
|
||||
if (function_exists('mb_strtolower')) {
|
||||
return '((mb_detect_encoding(' . $params[0] . ', \'UTF-8, ISO-8859-1\') === \'UTF-8\') ? mb_strtolower(' . $params[0] . ',SMARTY_RESOURCE_CHAR_SET) : strtolower(' . $params[0] . '))' ;
|
||||
} else {
|
||||
return 'strtolower(' . $params[0] . ')';
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
|
@ -0,0 +1,24 @@
|
|||
<?php
|
||||
/**
|
||||
* Smarty plugin
|
||||
*
|
||||
* @package Smarty
|
||||
* @subpackage PluginsModifierCompiler
|
||||
*/
|
||||
|
||||
/**
|
||||
* Smarty noprint modifier plugin
|
||||
*
|
||||
* Type: modifier<br>
|
||||
* Name: noprint<br>
|
||||
* Purpose: return an empty string
|
||||
* @author Uwe Tews
|
||||
* @param array $params parameters
|
||||
* @return string with compiled code
|
||||
*/
|
||||
function smarty_modifiercompiler_noprint($params, $compiler)
|
||||
{
|
||||
return "''";
|
||||
}
|
||||
|
||||
?>
|
|
@ -0,0 +1,26 @@
|
|||
<?php
|
||||
/**
|
||||
* Smarty plugin
|
||||
*
|
||||
* @package Smarty
|
||||
* @subpackage PluginsModifierCompiler
|
||||
*/
|
||||
|
||||
/**
|
||||
* Smarty string_format modifier plugin
|
||||
*
|
||||
* Type: modifier<br>
|
||||
* Name: string_format<br>
|
||||
* Purpose: format strings via sprintf
|
||||
*
|
||||
* @link http://smarty.php.net/manual/en/language.modifier.string.format.php string_format (Smarty online manual)
|
||||
* @author Uwe Tews
|
||||
* @param array $params parameters
|
||||
* @return string with compiled code
|
||||
*/
|
||||
function smarty_modifiercompiler_string_format($params, $compiler)
|
||||
{
|
||||
return 'sprintf(' . $params[1] . ',' . $params[0] . ')';
|
||||
}
|
||||
|
||||
?>
|
|
@ -0,0 +1,33 @@
|
|||
<?php
|
||||
/**
|
||||
* Smarty plugin
|
||||
*
|
||||
* @package Smarty
|
||||
* @subpackage PluginsModifierCompiler
|
||||
*/
|
||||
|
||||
/**
|
||||
* Smarty strip modifier plugin
|
||||
*
|
||||
* Type: modifier<br>
|
||||
* Name: strip<br>
|
||||
* Purpose: Replace all repeated spaces, newlines, tabs
|
||||
* with a single space or supplied replacement string.<br>
|
||||
* Example: {$var|strip} {$var|strip:" "}
|
||||
* Date: September 25th, 2002
|
||||
*
|
||||
* @link http://smarty.php.net/manual/en/language.modifier.strip.php strip (Smarty online manual)
|
||||
* @author Uwe Tews
|
||||
* @param array $params parameters
|
||||
* @return string with compiled code
|
||||
*/
|
||||
|
||||
function smarty_modifiercompiler_strip($params, $compiler)
|
||||
{
|
||||
if (!isset($params[1])) {
|
||||
$params[1] = "' '";
|
||||
}
|
||||
return "preg_replace('!\s+!', {$params[1]},{$params[0]})";
|
||||
}
|
||||
|
||||
?>
|
|
@ -0,0 +1,34 @@
|
|||
<?php
|
||||
/**
|
||||
* Smarty plugin
|
||||
*
|
||||
* @package Smarty
|
||||
* @subpackage PluginsModifierCompiler
|
||||
*/
|
||||
|
||||
/**
|
||||
* Smarty strip_tags modifier plugin
|
||||
*
|
||||
* Type: modifier<br>
|
||||
* Name: strip_tags<br>
|
||||
* Purpose: strip html tags from text
|
||||
*
|
||||
* @link http://smarty.php.net/manual/en/language.modifier.strip.tags.php strip_tags (Smarty online manual)
|
||||
* @author Uwe Tews
|
||||
* @param array $params parameters
|
||||
* @return string with compiled code
|
||||
*/
|
||||
|
||||
function smarty_modifiercompiler_strip_tags($params, $compiler)
|
||||
{
|
||||
if (!isset($params[1])) {
|
||||
$params[1] = true;
|
||||
}
|
||||
if ($params[1] === true) {
|
||||
return "preg_replace('!<[^>]*?>!', ' ', {$params[0]})";
|
||||
} else {
|
||||
return 'strip_tags(' . $params[0] . ')';
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
|
@ -0,0 +1,30 @@
|
|||
<?php
|
||||
/**
|
||||
* Smarty plugin
|
||||
*
|
||||
* @package Smarty
|
||||
* @subpackage PluginsModifierCompiler
|
||||
*/
|
||||
|
||||
/**
|
||||
* Smarty upper modifier plugin
|
||||
*
|
||||
* Type: modifier<br>
|
||||
* Name: lower<br>
|
||||
* Purpose: convert string to uppercase
|
||||
*
|
||||
* @link http://smarty.php.net/manual/en/language.modifier.upper.php lower (Smarty online manual)
|
||||
* @author Uwe Tews
|
||||
* @param array $params parameters
|
||||
* @return string with compiled code
|
||||
*/
|
||||
function smarty_modifiercompiler_upper($params, $compiler)
|
||||
{
|
||||
if (function_exists('mb_strtoupper')) {
|
||||
return '((mb_detect_encoding(' . $params[0] . ', \'UTF-8, ISO-8859-1\') === \'UTF-8\') ? mb_strtoupper(' . $params[0] . ',SMARTY_RESOURCE_CHAR_SET) : strtoupper(' . $params[0] . '))' ;
|
||||
} else {
|
||||
return 'strtoupper(' . $params[0] . ')';
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
|
@ -0,0 +1,35 @@
|
|||
<?php
|
||||
/**
|
||||
* Smarty plugin
|
||||
*
|
||||
* @package Smarty
|
||||
* @subpackage PluginsModifierCompiler
|
||||
*/
|
||||
|
||||
/**
|
||||
* Smarty wordwrap modifier plugin
|
||||
*
|
||||
* Type: modifier<br>
|
||||
* Name: wordwrap<br>
|
||||
* Purpose: wrap a string of text at a given length
|
||||
*
|
||||
* @link http://smarty.php.net/manual/en/language.modifier.wordwrap.php wordwrap (Smarty online manual)
|
||||
* @author Uwe Tews
|
||||
* @param array $params parameters
|
||||
* @return string with compiled code
|
||||
*/
|
||||
function smarty_modifiercompiler_wordwrap($params, $compiler)
|
||||
{
|
||||
if (!isset($params[1])) {
|
||||
$params[1] = 80;
|
||||
}
|
||||
if (!isset($params[2])) {
|
||||
$params[2] = '"\n"';
|
||||
}
|
||||
if (!isset($params[3])) {
|
||||
$params[3] = 'false';
|
||||
}
|
||||
return 'wordwrap(' . $params[0] . ',' . $params[1] . ',' . $params[2] . ',' . $params[3] . ')';
|
||||
}
|
||||
|
||||
?>
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче