mirror of
https://github.com/opensourcepos/opensourcepos.git
synced 2026-05-25 00:44:03 -04:00
Compare commits
451 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7180e7e9ed | ||
|
|
40ddfdc2ab | ||
|
|
345d2d95d8 | ||
|
|
24b4c98d94 | ||
|
|
ea6fffc525 | ||
|
|
a0b422be34 | ||
|
|
6599ea6678 | ||
|
|
9d056b2765 | ||
|
|
acd9beae73 | ||
|
|
48a16d65e1 | ||
|
|
89f126ab04 | ||
|
|
8f9d80a809 | ||
|
|
85c6da4346 | ||
|
|
574548f360 | ||
|
|
847c4a67c9 | ||
|
|
8aab154a9f | ||
|
|
a3119d1993 | ||
|
|
0a159c803f | ||
|
|
22a7231d8f | ||
|
|
c36f6b603d | ||
|
|
f063aa16a8 | ||
|
|
2520970698 | ||
|
|
a21a825aac | ||
|
|
8f72756737 | ||
|
|
463af45e73 | ||
|
|
4ccab6b8b5 | ||
|
|
1849ee807c | ||
|
|
1148ef1595 | ||
|
|
bcbdee3a50 | ||
|
|
cfbb700f0c | ||
|
|
a3d3cfad61 | ||
|
|
192955b33d | ||
|
|
9048d68baf | ||
|
|
2b70762b7a | ||
|
|
b5cc1542b6 | ||
|
|
1a77960daa | ||
|
|
301fbf4427 | ||
|
|
2f0666325f | ||
|
|
d0c765ce20 | ||
|
|
a1ad99cc0d | ||
|
|
2d0b20499e | ||
|
|
26ff81ab71 | ||
|
|
da3349765a | ||
|
|
4ddde65b41 | ||
|
|
c408afad67 | ||
|
|
b1ba7d0afe | ||
|
|
31a223cece | ||
|
|
3bd778737f | ||
|
|
648251978e | ||
|
|
240c96a185 | ||
|
|
810000e37c | ||
|
|
6aa5126bf0 | ||
|
|
90591382ce | ||
|
|
9e2d89c528 | ||
|
|
1601d679fd | ||
|
|
aa0409af48 | ||
|
|
ad194bd4c0 | ||
|
|
1779685d31 | ||
|
|
51df82f35e | ||
|
|
bf0622d7fa | ||
|
|
da25281df9 | ||
|
|
2f52d083e8 | ||
|
|
eb63f49db7 | ||
|
|
c007513fc8 | ||
|
|
9f5782e0ba | ||
|
|
2f14a0f868 | ||
|
|
fb924daa81 | ||
|
|
1bb9acdc37 | ||
|
|
16d5dfce77 | ||
|
|
afa203e73c | ||
|
|
bc85391734 | ||
|
|
7c2cc9646d | ||
|
|
c0303cc873 | ||
|
|
0ddd80dc2c | ||
|
|
af582056d7 | ||
|
|
56859a77ab | ||
|
|
ec5846e1eb | ||
|
|
6d5c192447 | ||
|
|
1b90ac14d2 | ||
|
|
9c775ca44b | ||
|
|
0d87fc51d9 | ||
|
|
c4c7d9d792 | ||
|
|
455a5f59d1 | ||
|
|
9cf5d5734f | ||
|
|
43b8d32efc | ||
|
|
0c25b01666 | ||
|
|
1fd7fda645 | ||
|
|
3eb798917d | ||
|
|
64023f6eec | ||
|
|
d8a369f39d | ||
|
|
98b0df9e80 | ||
|
|
763a9e73fa | ||
|
|
df5a0448aa | ||
|
|
76365afbd2 | ||
|
|
6e27b4c9ec | ||
|
|
a7e2ea5fa7 | ||
|
|
986bbc9b36 | ||
|
|
03f6d234bc | ||
|
|
79361c976c | ||
|
|
1296f393d7 | ||
|
|
e49dd4e0b9 | ||
|
|
319545b989 | ||
|
|
4a3e9ef79d | ||
|
|
e566223db9 | ||
|
|
22406d0c3a | ||
|
|
8bb108503c | ||
|
|
1eb43d2a74 | ||
|
|
56f7be21ae | ||
|
|
ba6ecf0319 | ||
|
|
47c8d6c0bd | ||
|
|
d9c49c1a72 | ||
|
|
5af7473769 | ||
|
|
aa9cd1fe6a | ||
|
|
58899ca4cf | ||
|
|
404bc47e96 | ||
|
|
7dfcec394f | ||
|
|
0646200f6c | ||
|
|
2bc7b688ff | ||
|
|
9309d7f15b | ||
|
|
87153fc70e | ||
|
|
ff12531b42 | ||
|
|
f18b54a758 | ||
|
|
9a47b448ac | ||
|
|
569bf4db69 | ||
|
|
f97e02c3d4 | ||
|
|
893345d334 | ||
|
|
80fcede1ca | ||
|
|
461de2f048 | ||
|
|
4106378a6c | ||
|
|
dfb556b27b | ||
|
|
41607c23bd | ||
|
|
a29b8c2a62 | ||
|
|
dc45b77573 | ||
|
|
ad948ac81e | ||
|
|
eee7f137ef | ||
|
|
2237c332b9 | ||
|
|
d5cf608bac | ||
|
|
96973da280 | ||
|
|
bca4386aed | ||
|
|
27f89a63be | ||
|
|
3f5d0b781b | ||
|
|
0984cdbfc4 | ||
|
|
c48106f2f5 | ||
|
|
e1ddcbbb5b | ||
|
|
2b7ceb4228 | ||
|
|
3c89416b83 | ||
|
|
290aee4671 | ||
|
|
10ea821b2a | ||
|
|
cf0276c772 | ||
|
|
8f2740d349 | ||
|
|
eb71dbc300 | ||
|
|
68915dd28c | ||
|
|
93d8775ac5 | ||
|
|
807d48ac7b | ||
|
|
79fd666bff | ||
|
|
393ac9bb97 | ||
|
|
ac95e1f7d8 | ||
|
|
c843c174ed | ||
|
|
d6f052f082 | ||
|
|
a78ef2fb08 | ||
|
|
4cbbd3a6f7 | ||
|
|
4a8c3a83b3 | ||
|
|
308be8079f | ||
|
|
335ced948e | ||
|
|
b41a006a79 | ||
|
|
506aced23e | ||
|
|
e9ea2ba792 | ||
|
|
2c5f3ee759 | ||
|
|
b680cdff36 | ||
|
|
80f7966d1c | ||
|
|
e62df579f1 | ||
|
|
2b6b3914a7 | ||
|
|
756b675e2b | ||
|
|
1d65ceaccf | ||
|
|
0c92cc661f | ||
|
|
c87a936e22 | ||
|
|
c041a18624 | ||
|
|
ac3aab51fa | ||
|
|
9281995029 | ||
|
|
f36c700129 | ||
|
|
d35ef071bb | ||
|
|
852f83a8f6 | ||
|
|
7bbd651779 | ||
|
|
a624d21fcd | ||
|
|
9a2cafc1b1 | ||
|
|
b226a40efc | ||
|
|
0b8a263443 | ||
|
|
75fa706299 | ||
|
|
c88f37f8e7 | ||
|
|
3e24b9caff | ||
|
|
517363b485 | ||
|
|
011caf375f | ||
|
|
9f1485cfe5 | ||
|
|
0336fe6298 | ||
|
|
4ab2ec1b5b | ||
|
|
eb3657e76f | ||
|
|
61206547cb | ||
|
|
9ae6e3242b | ||
|
|
7f5fe9efde | ||
|
|
9e189a503e | ||
|
|
da41aec0d1 | ||
|
|
03b9924d57 | ||
|
|
87222611e6 | ||
|
|
cc06d93d30 | ||
|
|
7926a05948 | ||
|
|
d7ff4a371c | ||
|
|
aa144b43eb | ||
|
|
f806ea84b3 | ||
|
|
17ac5b1837 | ||
|
|
8bcd2a69dc | ||
|
|
e0f80528f4 | ||
|
|
491d8d0b72 | ||
|
|
80dcc2f63f | ||
|
|
92da2749ad | ||
|
|
83a297cf15 | ||
|
|
70b7a03c63 | ||
|
|
b1f1feda48 | ||
|
|
48fe4aa4cf | ||
|
|
0788f4eef9 | ||
|
|
fc5f097820 | ||
|
|
df7907fb8f | ||
|
|
46b5c18aca | ||
|
|
5c1ecf4618 | ||
|
|
ccc2af2a26 | ||
|
|
872d6857cd | ||
|
|
658792c1fc | ||
|
|
4a324fbf4c | ||
|
|
97d268e323 | ||
|
|
ca05583ec3 | ||
|
|
7d0a6dc7ae | ||
|
|
3ba3a3dea0 | ||
|
|
1ad08c014f | ||
|
|
3936f2dcf3 | ||
|
|
fcc71a5f74 | ||
|
|
46f6824199 | ||
|
|
7c0f884872 | ||
|
|
15493ae58e | ||
|
|
ac7c0241e5 | ||
|
|
fd933e3ed6 | ||
|
|
6a2a5278b8 | ||
|
|
687d4c06c6 | ||
|
|
19f7c6aa57 | ||
|
|
ccf1a6209f | ||
|
|
4db6f28c76 | ||
|
|
3e08ec99a5 | ||
|
|
4142f0fc71 | ||
|
|
1d9a0bc8b6 | ||
|
|
a58510c541 | ||
|
|
b2a37b7ded | ||
|
|
69528baa21 | ||
|
|
c5defaab35 | ||
|
|
af7910a6a8 | ||
|
|
86eb397866 | ||
|
|
9b1785df01 | ||
|
|
8f09a32ef5 | ||
|
|
c6d9a8a994 | ||
|
|
54855849b3 | ||
|
|
7a9590359e | ||
|
|
11eed40718 | ||
|
|
bc7eeb5d30 | ||
|
|
4916f98bcb | ||
|
|
c85dd1660e | ||
|
|
08c0c2c63f | ||
|
|
81c24d7151 | ||
|
|
3d62a73c8c | ||
|
|
b8fba91244 | ||
|
|
80dbe6efa7 | ||
|
|
3f46f1aca9 | ||
|
|
26fddcf8d4 | ||
|
|
7a4df2a050 | ||
|
|
de3d7ce726 | ||
|
|
4ffc5351af | ||
|
|
3f14c51c97 | ||
|
|
e9b4e57c06 | ||
|
|
70bb02c753 | ||
|
|
6f7090d7ba | ||
|
|
43ecda44e0 | ||
|
|
04abb716fa | ||
|
|
95ae2766cd | ||
|
|
f45f75e458 | ||
|
|
b85b9d37a1 | ||
|
|
ebd473ea11 | ||
|
|
7d7ee83ef4 | ||
|
|
27c6f275d1 | ||
|
|
39edf5ccdb | ||
|
|
90c4df7f2a | ||
|
|
ae99555fec | ||
|
|
8ff742085a | ||
|
|
86bf8866f0 | ||
|
|
a8f353de9c | ||
|
|
9b98f15f69 | ||
|
|
138d1cbeef | ||
|
|
9ead6fcca9 | ||
|
|
ced5ca4e2e | ||
|
|
ca2c9a6ae4 | ||
|
|
cae9d3b67e | ||
|
|
aa65593ce3 | ||
|
|
c10860a005 | ||
|
|
a39e12e76d | ||
|
|
b29cb85b9b | ||
|
|
6faaec53d6 | ||
|
|
b29ec8ef31 | ||
|
|
4ac1a943eb | ||
|
|
0e357f14f6 | ||
|
|
e0fd35220e | ||
|
|
ffb8501276 | ||
|
|
8981efbd2a | ||
|
|
b2f76f3fe6 | ||
|
|
98cae8928b | ||
|
|
b02b16b63e | ||
|
|
81cb46bb8b | ||
|
|
b11bf919af | ||
|
|
9ee63294a4 | ||
|
|
dbddb34ed4 | ||
|
|
71c9294978 | ||
|
|
1226d217a6 | ||
|
|
3204391521 | ||
|
|
40ebba4252 | ||
|
|
9351a263ee | ||
|
|
cb1075e6c0 | ||
|
|
33cf0422a7 | ||
|
|
bd54a180d5 | ||
|
|
b752ec9952 | ||
|
|
e688a24326 | ||
|
|
468b3e3580 | ||
|
|
e96dd7883e | ||
|
|
8e221033bf | ||
|
|
17594f95f1 | ||
|
|
9e427485f3 | ||
|
|
c389e6030c | ||
|
|
0f77300131 | ||
|
|
9856f0bc65 | ||
|
|
378d45691b | ||
|
|
e7f9f29cd3 | ||
|
|
babddd524c | ||
|
|
6ff19cb3f3 | ||
|
|
42c30bf30b | ||
|
|
50006aeb6a | ||
|
|
8edff136d0 | ||
|
|
f6fb275dff | ||
|
|
4025883765 | ||
|
|
b9b8e2b4e5 | ||
|
|
13f6640576 | ||
|
|
aa969273db | ||
|
|
a809807288 | ||
|
|
2a07bbaef9 | ||
|
|
4bc1d87782 | ||
|
|
6710112f3d | ||
|
|
7ec4c21587 | ||
|
|
9b61e0ad67 | ||
|
|
40eef74aa0 | ||
|
|
c7c4ac15d6 | ||
|
|
cf2ca1e6c7 | ||
|
|
9d0fb43fb1 | ||
|
|
99c37ad9a7 | ||
|
|
a8e15f7db0 | ||
|
|
b5c33b4fcb | ||
|
|
9e9a9a80a9 | ||
|
|
fe081779c5 | ||
|
|
1267e92117 | ||
|
|
d6f27141af | ||
|
|
4b48a97166 | ||
|
|
ed70fdc40b | ||
|
|
ade913f0e4 | ||
|
|
cd92f85691 | ||
|
|
081bf77782 | ||
|
|
4e6a6d6434 | ||
|
|
57cbbdab56 | ||
|
|
4a6a69bdef | ||
|
|
88a9193d3a | ||
|
|
4b99252a83 | ||
|
|
8b1186c4f9 | ||
|
|
2e36b7e03b | ||
|
|
b7751bde1a | ||
|
|
f021215cbb | ||
|
|
9191eb4535 | ||
|
|
0fdb760d6f | ||
|
|
a46221ad04 | ||
|
|
da5c65e42e | ||
|
|
3594c348ee | ||
|
|
c40ad31ed0 | ||
|
|
4579f16518 | ||
|
|
49a0a4e127 | ||
|
|
d208e6dccb | ||
|
|
8b2a2f8074 | ||
|
|
84ffe5d4eb | ||
|
|
39301e7091 | ||
|
|
0a29809f7a | ||
|
|
4332bce401 | ||
|
|
42f4eb9c7b | ||
|
|
bd5e5b0b94 | ||
|
|
c763e8831f | ||
|
|
0616560e3e | ||
|
|
c7a898a89d | ||
|
|
377284f491 | ||
|
|
93968814db | ||
|
|
941ff4cd4a | ||
|
|
4d2de519a1 | ||
|
|
8fd315e389 | ||
|
|
fe786b5888 | ||
|
|
28711df45a | ||
|
|
f77f2e6e29 | ||
|
|
707114805d | ||
|
|
aebed9347b | ||
|
|
aa1c46738b | ||
|
|
080ae5df3a | ||
|
|
c04fa362b1 | ||
|
|
c7280e6018 | ||
|
|
374f9556d1 | ||
|
|
ec6455647f | ||
|
|
7081fe0338 | ||
|
|
8b6182dded | ||
|
|
f2fd360d23 | ||
|
|
8ccba57d98 | ||
|
|
7efb1428f5 | ||
|
|
46cfe0b18a | ||
|
|
2f74c400bd | ||
|
|
7c24682584 | ||
|
|
215a2104a1 | ||
|
|
aae02b7420 | ||
|
|
48867d44be | ||
|
|
d3b9bc08c9 | ||
|
|
1bf839601a | ||
|
|
bd763596b9 | ||
|
|
dc12c7bdd2 | ||
|
|
4ddec66d7b | ||
|
|
839849bf8d | ||
|
|
b4ac74aa55 | ||
|
|
8ac58a4612 | ||
|
|
08325c8cf7 | ||
|
|
43f4e9e790 | ||
|
|
f497ac54f1 | ||
|
|
f323bec9ca | ||
|
|
24a6c9c34f | ||
|
|
4f456c75f7 | ||
|
|
8705b91bd3 | ||
|
|
16814f2d12 | ||
|
|
b9ee7b6b01 | ||
|
|
344cb5c749 | ||
|
|
4556938154 | ||
|
|
a2b7ff688d | ||
|
|
df71cb9cf8 | ||
|
|
927dbbabb6 | ||
|
|
7544aae394 | ||
|
|
868721c6f5 | ||
|
|
1d9661d0b0 | ||
|
|
e7fd57afdf | ||
|
|
ad51278ba5 | ||
|
|
606eb01a67 | ||
|
|
94287ddec4 | ||
|
|
3d6d473145 |
3
.gitattributes
vendored
Normal file
3
.gitattributes
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
dist/ merge=ours
|
||||
application/language/**/*.php merge=ours
|
||||
text=auto
|
||||
9
.gitignore
vendored
9
.gitignore
vendored
@@ -1,10 +1,13 @@
|
||||
node_modules
|
||||
bower_components
|
||||
application/config/email.php
|
||||
application/config/database.php
|
||||
*.patch
|
||||
patches/
|
||||
.idea/
|
||||
git-svn-diff.py
|
||||
*.bash
|
||||
*.sh
|
||||
*.swp
|
||||
.swp
|
||||
.buildpath
|
||||
.project
|
||||
.settings/*
|
||||
@@ -12,3 +15,5 @@ git-svn-diff.py
|
||||
*.rej
|
||||
*.orig
|
||||
*~
|
||||
*.~
|
||||
*.log
|
||||
|
||||
16
.travis.yml
Normal file
16
.travis.yml
Normal file
@@ -0,0 +1,16 @@
|
||||
sudo: false
|
||||
|
||||
language: node_js
|
||||
|
||||
node_js:
|
||||
- "4.1"
|
||||
|
||||
services:
|
||||
- docker
|
||||
|
||||
before_install:
|
||||
- docker build -t jekkos/opensourcepos .
|
||||
- docker run -d jekkos/opensourcepos
|
||||
|
||||
script:
|
||||
- docker exec -t -i $(docker ps | tail -n 1 | cut -d' ' -f1) /bin/sh -c "while ! curl http://localhost/index.php | grep username; do sleep 1; done; cd app && grunt mochaWebdriver:test"
|
||||
@@ -1,6 +1,13 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2014 pappastech
|
||||
Copyright (c) 2012-2014 pappastech
|
||||
Copyright (c) 2012 Alain
|
||||
Copyright (c) 2013 Rob Garrison
|
||||
Copyright (c) 2013 Parq
|
||||
Copyright (c) 2013 Ramel
|
||||
Copyright (c) 2014-2015 jekkos
|
||||
Copyright (c) 2015 FrancescoUK (aka daN4cat)
|
||||
Copyright (c) 2015 Aamir Shahzad (aka asakpke), RoshanTech.com
|
||||
|
||||
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
|
||||
@@ -17,4 +24,4 @@ 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.
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
28
Dockerfile
Normal file
28
Dockerfile
Normal file
@@ -0,0 +1,28 @@
|
||||
FROM ubuntu:utopic
|
||||
MAINTAINER jekkos
|
||||
RUN sed -i -e 's/archive.ubuntu.com\|security.ubuntu.com/old-releases.ubuntu.com/g' /etc/apt/sources.list
|
||||
RUN apt-get update
|
||||
RUN apt-get -y upgrade
|
||||
RUN DEBIAN_FRONTEND=noninteractive apt-get -y install mysql-client mysql-server apache2 libapache2-mod-php5 pwgen python-setuptools vim-tiny php5-mysql php5-gd nodejs npm curl
|
||||
RUN easy_install supervisor
|
||||
ADD ./docker/foreground.sh /etc/apache2/foreground.sh
|
||||
ADD ./docker/supervisord.conf /etc/supervisord.conf
|
||||
RUN chmod 755 /etc/apache2/foreground.sh
|
||||
# Install dependencies
|
||||
RUN apt-get install -y --no-install-recommends software-properties-common
|
||||
RUN apt-get install -y python git
|
||||
|
||||
# Get latest Ospos source from Git
|
||||
RUN git clone https://github.com/jekkos/opensourcepos.git /app
|
||||
# RUN cd app && git checkout develop/2.4
|
||||
RUN ln -s /usr/bin/nodejs /usr/bin/node
|
||||
RUN cd app && npm install
|
||||
RUN npm install -g grunt-cli
|
||||
RUn ln -s /usr/local/bin/grunt /usr/bin/grunt
|
||||
|
||||
RUN ln -fs /app/* /var/www/html
|
||||
RUN rm /var/www/html/index.html
|
||||
ADD ./docker/start_container.sh /start_container.sh
|
||||
RUN chmod 755 /start_container.sh
|
||||
EXPOSE 80 3306
|
||||
CMD ["/bin/bash", "/start_container.sh"]
|
||||
116
Gruntfile.js
Normal file
116
Gruntfile.js
Normal file
@@ -0,0 +1,116 @@
|
||||
module.exports = function(grunt) {
|
||||
|
||||
grunt.initConfig({
|
||||
pkg: grunt.file.readJSON('package.json'),
|
||||
concat: {
|
||||
js: {
|
||||
options: {
|
||||
separator: ';'
|
||||
},
|
||||
dist: {
|
||||
src: ['js/jquery*', 'js/*.js'],
|
||||
dest: 'dist/<%= pkg.name %>.js'
|
||||
}
|
||||
},
|
||||
sql: {
|
||||
options: {
|
||||
banner: '-- >> This file is autogenerated from tables.sql and constraints.sql. Do not modify directly << --'
|
||||
},
|
||||
files: {
|
||||
'database/database.sql': ['database/tables.sql', 'database/constraints.sql'],
|
||||
'database/migrate_phppos_dist.sql': ['database/tables.sql', 'database/phppos_migrate.sql', 'database/constraints.sql']
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
uglify: {
|
||||
options: {
|
||||
banner: '/*! <%= pkg.name %> <%= grunt.template.today("dd-mm-yyyy") %> */\n'
|
||||
},
|
||||
dist: {
|
||||
files: {
|
||||
'dist/<%= pkg.name %>.min.js': ['<%= concat.js.dist.dest %>']
|
||||
}
|
||||
}
|
||||
},
|
||||
jshint: {
|
||||
files: ['Gruntfile.js', 'js/*.js'],
|
||||
options: {
|
||||
// options here to override JSHint defaults
|
||||
globals: {
|
||||
jQuery: true,
|
||||
console: true,
|
||||
module: true,
|
||||
document: true
|
||||
}
|
||||
}
|
||||
},
|
||||
tags: {
|
||||
js : {
|
||||
options: {
|
||||
scriptTemplate: '<script type="text/javascript" src="{{ path }}" language="javascript"></script>',
|
||||
openTag: '<!-- start js template tags -->',
|
||||
closeTag: '<!-- end js template tags -->',
|
||||
absolutePath: true
|
||||
},
|
||||
src: [
|
||||
'js/jquery*.js', 'js/*.js',
|
||||
],
|
||||
dest: 'application/views/partial/header.php'
|
||||
},
|
||||
minjs : {
|
||||
options: {
|
||||
scriptTemplate: '<script type="text/javascript" src="{{ path }}" language="javascript"></script>',
|
||||
openTag: '<!-- start minjs template tags -->',
|
||||
closeTag: '<!-- end minjs template tags -->',
|
||||
absolutePath: true
|
||||
},
|
||||
src: [
|
||||
'dist/*min.js',
|
||||
],
|
||||
dest: 'application/views/partial/header.php'
|
||||
}
|
||||
},
|
||||
mochaWebdriver: {
|
||||
options: {
|
||||
timeout: 1000 * 60 * 3
|
||||
},
|
||||
test : {
|
||||
options: {
|
||||
usePhantom: true,
|
||||
usePromises: true
|
||||
},
|
||||
src: ['test/**/*.js']
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
files: ['<%= jshint.files %>'],
|
||||
tasks: ['jshint']
|
||||
},
|
||||
cachebreaker: {
|
||||
dev: {
|
||||
options: {
|
||||
match: ['opensourcepos.min.js'],
|
||||
src: {
|
||||
path: 'dist/opensourcepos.min.js'
|
||||
},
|
||||
replacement: 'md5'
|
||||
},
|
||||
files: {
|
||||
src: ['application/views/partial/header.php']
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
grunt.loadNpmTasks('grunt-contrib-uglify');
|
||||
grunt.loadNpmTasks('grunt-contrib-jshint');
|
||||
grunt.loadNpmTasks('grunt-contrib-watch');
|
||||
grunt.loadNpmTasks('grunt-contrib-concat');
|
||||
grunt.loadNpmTasks('grunt-script-link-tags');
|
||||
grunt.loadNpmTasks('grunt-mocha-webdriver');
|
||||
grunt.loadNpmTasks('grunt-cache-breaker');
|
||||
|
||||
grunt.registerTask('default', ['tags:js', 'concat', 'uglify', 'tags:minjs', 'cachebreaker']);
|
||||
|
||||
};
|
||||
27
README.md
27
README.md
@@ -1,5 +1,7 @@
|
||||
Open Source Point of Sale is a web based point of sale system written in the PHP language. It uses MySQL as the data storage back-end and has a simple user interface.
|
||||
|
||||
[](https://travis-ci.org/jekkos/opensourcepos)
|
||||
|
||||
How to Install
|
||||
--------------
|
||||
1. Create/locate a new mysql database to install open source point of sale into
|
||||
@@ -14,4 +16,27 @@ username: admin
|
||||
password:pointofsale
|
||||
9. Enjoy
|
||||
|
||||
A more extensive setup guide can be found at [this site](http://www.opensourceposguide.com/guide/gettingstarted/installation)
|
||||
13/01/2016: Intall using Docker
|
||||
-------------------------------
|
||||
From now on ospos can be deployed using Docker on Linux, Mac or Windows. This setup dramatically reduces the number of possible issues as all setup is now done in a Dockerfile. Docker runs natively on mac and linux, but will require more overhead on windows. Please refer to the docker documentation for instructions on how to set it up on your platform.
|
||||
|
||||
To build and run the image, issue following commands in a terminal with docker installed
|
||||
|
||||
docker build -t me/ospos https://github.com/jekkos/opensourcepos.git
|
||||
docker run -d -p 80:80 me/ospos
|
||||
|
||||
Docker will clone the latest master into the image and start a LAMP stack with the application configured. If you like to persist your changes in this install, then you can use two docker data containers to store database and filesystem changes. In this case you will need following command (first time only)
|
||||
|
||||
docker run -d -v /app --name="ospos" -v /var/lib/mysql --name="ospos-sql" -p 127.0.0.1:80:80 me/ospos
|
||||
|
||||
After stopping the created container for the first time, this command will be replaced with
|
||||
|
||||
docker run -d -v /app --volumes-from="ospos" -v /var/lib/mysql --volumes-from="ospos-sql" -p 127.0.0.1:80:80 me/ospos
|
||||
|
||||
Both the data and mysql directories will be persisted in a separate docker container and can be mounted within any other container using the last command. A more extensive setup guide can be found at [this site](http://www.opensourceposguide.com/guide/gettingstarted/installation)
|
||||
|
||||
If you like the project, and you are making money out of it on a daily basis, then consider to buy me a coffee so I can keep adding features.
|
||||
|
||||
|
||||
[](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=MUN6AEG7NY6H8)
|
||||
|
||||
|
||||
@@ -1,3 +1,58 @@
|
||||
Version 2.3.4
|
||||
-------------
|
||||
+ Migration script fixes
|
||||
+ Improved continuous integration setup
|
||||
+ More integration tests
|
||||
+ Virtualized container setup (docker install)
|
||||
+ Live clock functionality + favicon
|
||||
+ Improved PHP 7 compatbility
|
||||
+ Added de_CH (German) as language
|
||||
+ Minor code cleanup
|
||||
+ Removal of annoying backup prompt on logout
|
||||
|
||||
Version 2.3.3
|
||||
-------------
|
||||
+ Item kit fixes (search, list, ..)
|
||||
+ Add datepicker widgets in sale/receiving edit forms
|
||||
+ Add date filter in items module
|
||||
+ Add barcode generation logic for EAN8, EAN13
|
||||
+ Add barcode validation + fallback logic for EAN8, EAN13
|
||||
+ New config option to generate barcodes if item_number empty
|
||||
+ Add cost + count to inventory reports
|
||||
+ Giftcard fixes
|
||||
+ Refactor sales overview (added date filtering + search options)
|
||||
+ Better locale config support
|
||||
+ Improve php compatibility
|
||||
+ Fix invoice numbering bug on suspend
|
||||
+ Add configurable locale-dependent dateformat
|
||||
+ Add grunt-cache-breaker plugin
|
||||
+ Suspend button appeaers before adding a payment
|
||||
+ Searching of deleted items, filtering part is removed
|
||||
+ Remove infamous "0" after leaving sale or receiving comments empty
|
||||
+ Add SQL script to clean zeroes in sales/receivings comments
|
||||
+ Numerous other bug fixes
|
||||
|
||||
Version 2.3.2
|
||||
-------------
|
||||
+ Nominatim (OpenStreetMap) customer address autocompletion
|
||||
+ Sale invoice templating
|
||||
+ Configurable barcode generation for items
|
||||
+ Stock location filtering in detailed sales and receivings reports
|
||||
+ Giftcards bugfixes
|
||||
+ Proper pagination support for most modules
|
||||
+ Language updates
|
||||
+ Bugfix for decimal taxrates
|
||||
+ Add gender + company name attributes to customer
|
||||
+ Stock location config screen refactor
|
||||
+ Basic travis-ci + phantomJs setup
|
||||
+ Database backup on admin logout
|
||||
+ Modifiable item thumbnails
|
||||
+ Email invoice PDF generation using DomPDF
|
||||
+ Modifiable company logo
|
||||
+ jQuery upgrade (1.2 -> 1.8.3)
|
||||
+ Javascript minification (using grunt)
|
||||
+ Numerous bugfixes
|
||||
|
||||
Version 2.3.1
|
||||
-------------
|
||||
|
||||
|
||||
@@ -64,7 +64,7 @@ $autoload['libraries'] = array('database','form_validation','session','user_agen
|
||||
| $autoload['helper'] = array('url', 'file');
|
||||
*/
|
||||
|
||||
$autoload['helper'] = array('form','url','table','text','currency', 'html', 'download', 'directory');
|
||||
$autoload['helper'] = array('form','url','table','text','currency', 'html', 'download', 'directory', 'dateformat_helper');
|
||||
|
||||
|
||||
/*
|
||||
@@ -109,7 +109,7 @@ $autoload['language'] = array();
|
||||
|
|
||||
*/
|
||||
|
||||
$autoload['model'] = array('Appconfig','Person','Customer','Employee','Module','Item', 'Item_taxes', 'Sale', 'Sale_suspended', 'Supplier','Inventory','Receiving','Giftcard', 'Item_kit', 'Item_kit_items','Stock_locations','Item_quantities');
|
||||
$autoload['model'] = array('Appconfig','Person','Customer','Employee','Module','Item', 'Item_taxes', 'Sale', 'Sale_suspended', 'Supplier','Inventory','Receiving','Giftcard', 'Item_kit', 'Item_kit_items','Stock_location','Item_quantity');
|
||||
|
||||
|
||||
/* End of file autoload.php */
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
|
||||
|
|
||||
*/
|
||||
$config['application_version'] = '2.3.1';
|
||||
$config['application_version'] = '2.3.4';
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
@@ -264,8 +264,8 @@ $config['sess_encrypt_cookie'] = FALSE;
|
||||
$config['sess_use_database'] = TRUE;
|
||||
$config['sess_table_name'] = 'sessions';
|
||||
$config['sess_match_ip'] = FALSE;
|
||||
$config['sess_match_useragent'] = FAlSE;
|
||||
$config['sess_time_to_update'] = 0;
|
||||
$config['sess_match_useragent'] = FALSE;
|
||||
$config['sess_time_to_update'] = 120;
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
|
||||
@@ -39,7 +39,7 @@ define('FOPEN_READ_WRITE_CREATE_STRICT', 'x+b');
|
||||
/*
|
||||
| Precision for calculations performed on decimals
|
||||
*/
|
||||
define("PRECISION", 3);
|
||||
define("PRECISION", 5);
|
||||
|
||||
/* End of file constants.php */
|
||||
/* Location: ./application/config/constants.php */
|
||||
@@ -49,10 +49,10 @@ $active_group = 'default';
|
||||
$active_record = TRUE;
|
||||
|
||||
$db['default']['hostname'] = 'localhost';
|
||||
$db['default']['username'] = '';
|
||||
$db['default']['username'] = 'root';
|
||||
$db['default']['password'] = '';
|
||||
$db['default']['database'] = '';
|
||||
$db['default']['dbdriver'] = 'mysql';
|
||||
$db['default']['database'] = 'ospos';
|
||||
$db['default']['dbdriver'] = 'mysqli';
|
||||
$db['default']['dbprefix'] = 'ospos_';
|
||||
$db['default']['pconnect'] = FALSE;
|
||||
$db['default']['db_debug'] = TRUE;
|
||||
@@ -66,4 +66,4 @@ $db['default']['stricton'] = FALSE;
|
||||
|
||||
|
||||
/* End of file database.php */
|
||||
/* Location: ./application/config/database.php */
|
||||
/* Location: ./application/config/database.php */
|
||||
|
||||
@@ -15,7 +15,5 @@ $hook['post_controller_constructor'] = array(
|
||||
'filename' => 'load_config.php',
|
||||
'filepath' => 'hooks'
|
||||
);
|
||||
|
||||
|
||||
/* End of file hooks.php */
|
||||
/* Location: ./application/config/hooks.php */
|
||||
@@ -39,17 +39,23 @@
|
||||
*/
|
||||
|
||||
$route['default_controller'] = "login";
|
||||
$route['no_access/(:any)'] = "no_access/index/$1";
|
||||
$route['no_access/(:any)/(:any)'] = "no_access/index/$1/$2";
|
||||
$route['sales/index/(:any)'] = "sales/manage/$1";
|
||||
$route['sales/index/(:any)/(:any)'] = "sales/manage/$1/$2";
|
||||
$route['sales/index/(:any)/(:any)/(:any)'] = "sales/manage/$1/$2/$3";
|
||||
$route['reports/(summary_:any)/(:any)/(:any)'] = "reports/$1/$2/$3";
|
||||
$route['reports/summary_:any'] = "reports/date_input_excel_export";
|
||||
$route['reports/(graphical_:any)/(:any)/(:any)'] = "reports/$1/$2/$3";
|
||||
$route['reports/graphical_:any'] = "reports/date_input";
|
||||
$route['reports/(inventory_:any)/(:any)'] = "reports/$1/$2";
|
||||
$route['reports/inventory_:any'] = "reports/excel_export";
|
||||
$route['reports/inventory_summary'] = "reports/inventory_summary_input";
|
||||
$route['reports/(inventory_summary)/(:any)/(:any)/(:any)'] = "reports/$1/$2/$3/$4";
|
||||
|
||||
$route['reports/(detailed_sales)/(:any)/(:any)'] = "reports/$1/$2/$3";
|
||||
$route['reports/detailed_sales'] = "reports/date_input";
|
||||
$route['reports/(detailed_receivings)/(:any)/(:any)'] = "reports/$1/$2/$3";
|
||||
$route['reports/(detailed_sales)/(:any)/(:any)/(:any)'] = "reports/$1/$2/$3$/$4";
|
||||
$route['reports/detailed_sales'] = "reports/date_input_sales";
|
||||
$route['reports/(detailed_receivings)/(:any)/(:any)/(:any)'] = "reports/$1/$2/$3/$4";
|
||||
$route['reports/detailed_receivings'] = "reports/date_input_recv";
|
||||
$route['reports/(specific_:any)/(:any)/(:any)/(:any)'] = "reports/$1/$2/$3/$4";
|
||||
$route['reports/specific_customer'] = "reports/specific_customer_input";
|
||||
@@ -58,7 +64,7 @@ $route['reports/specific_discount'] = "reports/specific_discount_input";
|
||||
|
||||
$route['scaffolding_trigger'] = "";
|
||||
|
||||
$route['404_override'] = 'errors/page_missing';
|
||||
$route['404_override'] = "";
|
||||
|
||||
/* End of file routes.php */
|
||||
/* Location: ./application/config/routes.php */
|
||||
@@ -1,5 +1,6 @@
|
||||
<?php
|
||||
class Barcode extends CI_Controller
|
||||
require_once ("secure_area.php");
|
||||
class Barcode extends Secure_area
|
||||
{
|
||||
function __construct()
|
||||
{
|
||||
@@ -10,5 +11,6 @@ class Barcode extends CI_Controller
|
||||
{
|
||||
$this->load->view('barcode');
|
||||
}
|
||||
|
||||
}
|
||||
?>
|
||||
@@ -5,76 +5,216 @@ class Config extends Secure_area
|
||||
function __construct()
|
||||
{
|
||||
parent::__construct('config');
|
||||
$this->load->library('barcode_lib');
|
||||
}
|
||||
|
||||
function index()
|
||||
{
|
||||
$location_names = array();
|
||||
$locations = $this->Stock_locations->get_location_names();
|
||||
foreach($locations->result_array() as $array)
|
||||
{
|
||||
array_push($location_names, $array['location_name']);
|
||||
}
|
||||
$data['location_names'] = implode(',', $location_names);
|
||||
$this->load->view("config", $data);
|
||||
$data['stock_locations'] = $this->Stock_location->get_all()->result_array();
|
||||
$data['support_barcode'] = $this->barcode_lib->get_list_barcodes();
|
||||
$this->load->view("configs/manage", $data);
|
||||
$this->_remove_duplicate_cookies();
|
||||
}
|
||||
|
||||
function save()
|
||||
{
|
||||
$upload_success = $this->_handle_logo_upload();
|
||||
$upload_data = $this->upload->data();
|
||||
|
||||
$batch_save_data=array(
|
||||
'company'=>$this->input->post('company'),
|
||||
'address'=>$this->input->post('address'),
|
||||
'phone'=>$this->input->post('phone'),
|
||||
'email'=>$this->input->post('email'),
|
||||
'fax'=>$this->input->post('fax'),
|
||||
'website'=>$this->input->post('website'),
|
||||
'default_tax_1_rate'=>$this->input->post('default_tax_1_rate'),
|
||||
'default_tax_1_name'=>$this->input->post('default_tax_1_name'),
|
||||
'default_tax_2_rate'=>$this->input->post('default_tax_2_rate'),
|
||||
'default_tax_2_name'=>$this->input->post('default_tax_2_name'),
|
||||
'currency_symbol'=>$this->input->post('currency_symbol'),
|
||||
'currency_side'=>$this->input->post('currency_side'),/**GARRISON ADDED 4/20/2013**/
|
||||
'return_policy'=>$this->input->post('return_policy'),
|
||||
'language'=>$this->input->post('language'),
|
||||
'timezone'=>$this->input->post('timezone'),
|
||||
'print_after_sale'=>$this->input->post('print_after_sale'),
|
||||
'tax_included'=>$this->input->post('tax_included'),
|
||||
'recv_invoice_format'=>$this->input->post('recv_invoice_format'),
|
||||
'sales_invoice_format'=>$this->input->post('sales_invoice_format'),
|
||||
'custom1_name'=>$this->input->post('custom1_name'),/**GARRISON ADDED 4/20/2013**/
|
||||
'custom2_name'=>$this->input->post('custom2_name'),/**GARRISON ADDED 4/20/2013**/
|
||||
'custom3_name'=>$this->input->post('custom3_name'),/**GARRISON ADDED 4/20/2013**/
|
||||
'custom4_name'=>$this->input->post('custom4_name'),/**GARRISON ADDED 4/20/2013**/
|
||||
'custom5_name'=>$this->input->post('custom5_name'),/**GARRISON ADDED 4/20/2013**/
|
||||
'custom6_name'=>$this->input->post('custom6_name'),/**GARRISON ADDED 4/20/2013**/
|
||||
'custom7_name'=>$this->input->post('custom7_name'),/**GARRISON ADDED 4/20/2013**/
|
||||
'custom8_name'=>$this->input->post('custom8_name'),/**GARRISON ADDED 4/20/2013**/
|
||||
'custom9_name'=>$this->input->post('custom9_name'),/**GARRISON ADDED 4/20/2013**/
|
||||
'custom10_name'=>$this->input->post('custom10_name')/**GARRISON ADDED 4/20/2013**/
|
||||
'address'=>$this->input->post('address'),
|
||||
'phone'=>$this->input->post('phone'),
|
||||
'email'=>$this->input->post('email'),
|
||||
'fax'=>$this->input->post('fax'),
|
||||
'website'=>$this->input->post('website'),
|
||||
'default_tax_1_rate'=>$this->input->post('default_tax_1_rate'),
|
||||
'default_tax_1_name'=>$this->input->post('default_tax_1_name'),
|
||||
'default_tax_2_rate'=>$this->input->post('default_tax_2_rate'),
|
||||
'default_tax_2_name'=>$this->input->post('default_tax_2_name'),
|
||||
'return_policy'=>$this->input->post('return_policy'),
|
||||
'tax_included'=>$this->input->post('tax_included'),
|
||||
'recv_invoice_format'=>$this->input->post('recv_invoice_format'),
|
||||
'sales_invoice_format'=>$this->input->post('sales_invoice_format'),
|
||||
'receiving_calculate_average_price'=>$this->input->post('receiving_calculate_average_price'),
|
||||
'lines_per_page'=>$this->input->post('lines_per_page'),
|
||||
'default_sales_discount'=>$this->input->post('default_sales_discount'),
|
||||
'custom1_name'=>$this->input->post('custom1_name'),
|
||||
'custom2_name'=>$this->input->post('custom2_name'),
|
||||
'custom3_name'=>$this->input->post('custom3_name'),
|
||||
'custom4_name'=>$this->input->post('custom4_name'),
|
||||
'custom5_name'=>$this->input->post('custom5_name'),
|
||||
'custom6_name'=>$this->input->post('custom6_name'),
|
||||
'custom7_name'=>$this->input->post('custom7_name'),
|
||||
'custom8_name'=>$this->input->post('custom8_name'),
|
||||
'custom9_name'=>$this->input->post('custom9_name'),
|
||||
'custom10_name'=>$this->input->post('custom10_name')
|
||||
);
|
||||
|
||||
$stock_locations = explode( ',', $this->input->post('stock_location'));
|
||||
$stock_locations_trimmed=array();
|
||||
foreach($stock_locations as $location)
|
||||
{
|
||||
array_push($stock_locations_trimmed, trim($location, ' '));
|
||||
}
|
||||
$current_locations = $this->Stock_locations->concat_location_names()->location_names;
|
||||
if ($this->input->post('stock_locations') != $current_locations)
|
||||
{
|
||||
$this->load->library('sale_lib');
|
||||
$this->sale_lib->clear_sale_location();
|
||||
$this->sale_lib->clear_all();
|
||||
$this->load->library('receiving_lib');
|
||||
$this->receiving_lib->clear_stock_source();
|
||||
$this->receiving_lib->clear_stock_destination();
|
||||
$this->receiving_lib->clear_all();
|
||||
}
|
||||
|
||||
if( $this->Appconfig->batch_save( $batch_save_data ) && $this->Stock_locations->array_save($stock_locations_trimmed))
|
||||
if (!empty($upload_data['orig_name']))
|
||||
{
|
||||
echo json_encode(array('success'=>true,'message'=>$this->lang->line('config_saved_successfully')));
|
||||
$batch_save_data['company_logo'] = $upload_data['raw_name'] . $upload_data['file_ext'];
|
||||
}
|
||||
|
||||
$result = $this->Appconfig->batch_save( $batch_save_data );
|
||||
$success = $upload_success && $result ? true : false;
|
||||
$message = $this->lang->line('config_saved_' . ($success ? '' : 'un') . 'successfully');
|
||||
$message = $upload_success ? $message : $this->upload->display_errors();
|
||||
echo json_encode(array('success'=>$success,'message'=>$message));
|
||||
$this->_remove_duplicate_cookies();
|
||||
}
|
||||
|
||||
function save_locale()
|
||||
{
|
||||
$batch_save_data=array(
|
||||
'currency_symbol'=>$this->input->post('currency_symbol'),
|
||||
'currency_side'=>$this->input->post('currency_side'),
|
||||
'language'=>$this->input->post('language'),
|
||||
'timezone'=>$this->input->post('timezone'),
|
||||
'dateformat'=>$this->input->post('dateformat'),
|
||||
'timeformat'=>$this->input->post('timeformat'),
|
||||
'thousands_separator'=>$this->input->post('thousands_separator'),
|
||||
'decimal_point'=>$this->input->post('decimal_point')
|
||||
);
|
||||
|
||||
$result = $this->Appconfig->batch_save( $batch_save_data );
|
||||
$success = $result ? true : false;
|
||||
echo json_encode(array('success'=>$success, 'message'=>$this->lang->line('config_saved_' . ($success ? '' : 'un') . 'successfully')));
|
||||
$this->_remove_duplicate_cookies();
|
||||
}
|
||||
|
||||
function stock_locations()
|
||||
{
|
||||
$stock_locations = $this->Stock_location->get_all()->result_array();
|
||||
$this->load->view('partial/stock_locations', array('stock_locations' => $stock_locations));
|
||||
}
|
||||
|
||||
function _clear_session_state()
|
||||
{
|
||||
$this->load->library('sale_lib');
|
||||
$this->sale_lib->clear_sale_location();
|
||||
$this->sale_lib->clear_all();
|
||||
$this->load->library('receiving_lib');
|
||||
$this->receiving_lib->clear_stock_source();
|
||||
$this->receiving_lib->clear_stock_destination();
|
||||
$this->receiving_lib->clear_all();
|
||||
}
|
||||
|
||||
function save_locations()
|
||||
{
|
||||
$this->db->trans_start();
|
||||
|
||||
$deleted_locations = $this->Stock_location->get_allowed_locations();
|
||||
foreach($this->input->post() as $key => $value)
|
||||
{
|
||||
if (strstr($key, 'stock_location'))
|
||||
{
|
||||
$location_id = preg_replace("/.*?_(\d+)$/", "$1", $key);
|
||||
unset($deleted_locations[$location_id]);
|
||||
// save or update
|
||||
$location_data = array('location_name' => $value);
|
||||
if ($this->Stock_location->save($location_data, $location_id))
|
||||
{
|
||||
$this->_clear_session_state();
|
||||
}
|
||||
}
|
||||
}
|
||||
// all locations not available in post will be deleted now
|
||||
foreach ($deleted_locations as $location_id => $location_name)
|
||||
{
|
||||
$this->Stock_location->delete($location_id);
|
||||
}
|
||||
$success = $this->db->trans_complete();
|
||||
echo json_encode(array('success'=>$success,'message'=>$this->lang->line('config_saved_' . ($success ? '' : 'un') . 'successfully')));
|
||||
$this->_remove_duplicate_cookies();
|
||||
}
|
||||
|
||||
function save_barcode()
|
||||
{
|
||||
$batch_save_data=array(
|
||||
'barcode_type'=>$this->input->post('barcode_type'),
|
||||
'barcode_quality'=>$this->input->post('barcode_quality'),
|
||||
'barcode_width'=>$this->input->post('barcode_width'),
|
||||
'barcode_height'=>$this->input->post('barcode_height'),
|
||||
'barcode_font'=>$this->input->post('barcode_font'),
|
||||
'barcode_font_size'=>$this->input->post('barcode_font_size'),
|
||||
'barcode_first_row'=>$this->input->post('barcode_first_row'),
|
||||
'barcode_second_row'=>$this->input->post('barcode_second_row'),
|
||||
'barcode_third_row'=>$this->input->post('barcode_third_row'),
|
||||
'barcode_num_in_row'=>$this->input->post('barcode_num_in_row'),
|
||||
'barcode_page_width'=>$this->input->post('barcode_page_width'),
|
||||
'barcode_page_cellspacing'=>$this->input->post('barcode_page_cellspacing'),
|
||||
'barcode_generate_if_empty'=>$this->input->post('barcode_generate_if_empty'),
|
||||
'barcode_content'=>$this->input->post('barcode_content')
|
||||
);
|
||||
|
||||
$result = $this->Appconfig->batch_save( $batch_save_data );
|
||||
$success = $result ? true : false;
|
||||
echo json_encode(array('success'=>$success, 'message'=>$this->lang->line('config_saved_' . ($success ? '' : 'un') . 'successfully')));
|
||||
}
|
||||
|
||||
function save_receipt()
|
||||
{
|
||||
$batch_save_data = array (
|
||||
'use_invoice_template' => $this->input->post ( 'use_invoice_template' ),
|
||||
'invoice_default_comments' => $this->input->post ( 'invoice_default_comments' ),
|
||||
'invoice_email_message' => $this->input->post ( 'invoice_email_message' ),
|
||||
'receipt_show_taxes' => $this->input->post ( 'receipt_show_taxes' ),
|
||||
'print_silently' => $this->input->post ( 'print_silently' ),
|
||||
'print_header' => $this->input->post ( 'print_header' ),
|
||||
'print_footer' => $this->input->post ( 'print_footer' ),
|
||||
'print_top_margin' => $this->input->post ( 'print_top_margin' ),
|
||||
'print_left_margin' => $this->input->post ( 'print_left_margin' ),
|
||||
'print_bottom_margin' => $this->input->post ( 'print_bottom_margin' ),
|
||||
'print_right_margin' => $this->input->post ( 'print_right_margin' ),
|
||||
'show_total_discount' => $this->input->post( 'show_total_discount' )
|
||||
);
|
||||
$result = $this->Appconfig->batch_save( $batch_save_data );
|
||||
$success = $result ? true : false;
|
||||
echo json_encode(array('success'=>$success, 'message'=>$this->lang->line('config_saved_' . ($success ? '' : 'un') . 'successfully')));
|
||||
}
|
||||
|
||||
function _handle_logo_upload()
|
||||
{
|
||||
$this->load->helper('directory');
|
||||
// load upload library
|
||||
$config = array('upload_path' => './uploads/',
|
||||
'allowed_types' => 'gif|jpg|png',
|
||||
'max_size' => '1024',
|
||||
'max_width' => '800',
|
||||
'max_height' => '680',
|
||||
'file_name' => 'company_logo');
|
||||
$this->load->library('upload', $config);
|
||||
$this->upload->do_upload('company_logo');
|
||||
return strlen($this->upload->display_errors()) == 0 || !strcmp($this->upload->display_errors(), '<p>'.$this->lang->line('upload_no_file_selected').'</p>');
|
||||
}
|
||||
|
||||
function backup_db()
|
||||
{
|
||||
$employee_id=$this->Employee->get_logged_in_employee_info()->person_id;
|
||||
if($this->Employee->has_module_grant('config',$employee_id))
|
||||
{
|
||||
$this->load->dbutil();
|
||||
$prefs = array(
|
||||
'format' => 'zip',
|
||||
'filename' => 'ospos.sql'
|
||||
);
|
||||
|
||||
$backup =& $this->dbutil->backup($prefs);
|
||||
|
||||
$file_name = 'ospos-' . date("Y-m-d-H-i-s") .'.zip';
|
||||
$save = 'uploads/'.$file_name;
|
||||
$this->load->helper('download');
|
||||
while (ob_get_level()) {
|
||||
ob_end_clean();
|
||||
}
|
||||
force_download($file_name, $backup);
|
||||
}
|
||||
else
|
||||
{
|
||||
redirect('no_access/config');
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
||||
?>
|
||||
|
||||
@@ -7,28 +7,30 @@ class Customers extends Person_controller
|
||||
parent::__construct('customers');
|
||||
}
|
||||
|
||||
function index()
|
||||
function index($limit_from=0)
|
||||
{
|
||||
$config['base_url'] = site_url('/customers/index');
|
||||
$config['total_rows'] = $this->Customer->count_all();
|
||||
$config['per_page'] = '20';
|
||||
$config['uri_segment'] = 3;
|
||||
$this->pagination->initialize($config);
|
||||
|
||||
$data['controller_name']=strtolower(get_class());
|
||||
$data['controller_name']=$this->get_controller_name();
|
||||
$data['form_width']=$this->get_form_width();
|
||||
$data['manage_table']=get_people_manage_table( $this->Customer->get_all( $config['per_page'], $this->uri->segment( $config['uri_segment'] ) ), $this );
|
||||
$lines_per_page = $this->Appconfig->get('lines_per_page');
|
||||
$customers = $this->Customer->get_all($lines_per_page,$limit_from);
|
||||
$data['links'] = $this->_initialize_pagination($this->Customer,$lines_per_page,$limit_from);
|
||||
$data['manage_table']=get_people_manage_table($customers,$this);
|
||||
$this->load->view('people/manage',$data);
|
||||
}
|
||||
|
||||
/*
|
||||
Returns customer table data rows. This will be called with AJAX.
|
||||
Returns customer table data rows. This will be called with AJAX.
|
||||
*/
|
||||
function search()
|
||||
{
|
||||
$search=$this->input->post('search');
|
||||
$data_rows=get_people_manage_table_data_rows($this->Customer->search($search),$this);
|
||||
echo $data_rows;
|
||||
$search = $this->input->post('search');
|
||||
$limit_from = $this->input->post('limit_from');
|
||||
$lines_per_page = $this->Appconfig->get('lines_per_page');
|
||||
$customers = $this->Customer->search($search, $lines_per_page, $limit_from);
|
||||
$total_rows = $this->Customer->get_found_rows($search);
|
||||
$links = $this->_initialize_pagination($this->Customer,$lines_per_page, $limit_from, $total_rows);
|
||||
$data_rows=get_people_manage_table_data_rows($customers,$this);
|
||||
echo json_encode(array('total_rows' => $total_rows, 'rows' => $data_rows, 'pagination' => $links));
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -57,6 +59,7 @@ class Customers extends Person_controller
|
||||
$person_data = array(
|
||||
'first_name'=>$this->input->post('first_name'),
|
||||
'last_name'=>$this->input->post('last_name'),
|
||||
'gender'=>$this->input->post('gender'),
|
||||
'email'=>$this->input->post('email'),
|
||||
'phone_number'=>$this->input->post('phone_number'),
|
||||
'address_1'=>$this->input->post('address_1'),
|
||||
@@ -69,6 +72,7 @@ class Customers extends Person_controller
|
||||
);
|
||||
$customer_data=array(
|
||||
'account_number'=>$this->input->post('account_number')=='' ? null:$this->input->post('account_number'),
|
||||
'company_name'=>$this->input->post('company_name')=='' ? null:$this->input->post('company_name'),
|
||||
'taxable'=>$this->input->post('taxable')=='' ? 0:1,
|
||||
);
|
||||
if($this->Customer->save($person_data,$customer_data,$customer_id))
|
||||
@@ -92,6 +96,12 @@ class Customers extends Person_controller
|
||||
}
|
||||
}
|
||||
|
||||
function check_account_number()
|
||||
{
|
||||
$exists = $this->Customer->account_number_exists($this->input->post('account_number'),$this->input->post('person_id'));
|
||||
echo json_encode(array('success'=>!$exists,'message'=>$this->lang->line('customers_account_number_duplicate')));
|
||||
}
|
||||
|
||||
/*
|
||||
This deletes customers from the customers table
|
||||
*/
|
||||
@@ -145,23 +155,31 @@ class Customers extends Person_controller
|
||||
$person_data = array(
|
||||
'first_name'=>$data[0],
|
||||
'last_name'=>$data[1],
|
||||
'email'=>$data[2],
|
||||
'phone_number'=>$data[3],
|
||||
'address_1'=>$data[4],
|
||||
'address_2'=>$data[5],
|
||||
'city'=>$data[6],
|
||||
'state'=>$data[7],
|
||||
'zip'=>$data[8],
|
||||
'country'=>$data[9],
|
||||
'comments'=>$data[10]
|
||||
'gender'=>$data[2],
|
||||
'email'=>$data[3],
|
||||
'phone_number'=>$data[4],
|
||||
'address_1'=>$data[5],
|
||||
'address_2'=>$data[6],
|
||||
'city'=>$data[7],
|
||||
'state'=>$data[8],
|
||||
'zip'=>$data[9],
|
||||
'country'=>$data[10],
|
||||
'comments'=>$data[11]
|
||||
);
|
||||
|
||||
$customer_data=array(
|
||||
'account_number'=>$data[11]=='' ? null:$data[11],
|
||||
'taxable'=>$data[12]=='' ? 0:1,
|
||||
'taxable'=>$data[13]=='' ? 0:1
|
||||
);
|
||||
|
||||
if(!$this->Customer->save($person_data,$customer_data))
|
||||
$account_number = $data[12];
|
||||
$invalidated = false;
|
||||
if ($account_number != "")
|
||||
{
|
||||
$customer_data['account_number'] = $account_number;
|
||||
$invalidated = $this->Customer->account_number_exists($account_number);
|
||||
}
|
||||
|
||||
if($invalidated || !$this->Customer->save($person_data,$customer_data))
|
||||
{
|
||||
$failCodes[] = $i;
|
||||
}
|
||||
@@ -177,7 +195,7 @@ class Customers extends Person_controller
|
||||
}
|
||||
|
||||
$success = true;
|
||||
if(count($failCodes) > 1)
|
||||
if(count($failCodes) > 0)
|
||||
{
|
||||
$msg = "Most customers imported. But some were not, here is list of their CODE (" .count($failCodes) ."): ".implode(", ", $failCodes);
|
||||
$success = false;
|
||||
@@ -195,7 +213,7 @@ class Customers extends Person_controller
|
||||
*/
|
||||
function get_form_width()
|
||||
{
|
||||
return 350;
|
||||
return 400;
|
||||
}
|
||||
}
|
||||
?>
|
||||
@@ -7,18 +7,15 @@ class Employees extends Person_controller
|
||||
parent::__construct('employees');
|
||||
}
|
||||
|
||||
function index()
|
||||
function index($limit_from=0)
|
||||
{
|
||||
$config['base_url'] = site_url('/employees/index');
|
||||
$config['total_rows'] = $this->Employee->count_all();
|
||||
$config['per_page'] = '20';
|
||||
$config['uri_segment'] = 3;
|
||||
$this->pagination->initialize($config);
|
||||
|
||||
$data['controller_name']=strtolower(get_class());
|
||||
$data['controller_name']=$this->get_controller_name();
|
||||
$data['form_width']=$this->get_form_width();
|
||||
$data['manage_table']=get_people_manage_table( $this->Employee->get_all( $config['per_page'], $this->uri->segment( $config['uri_segment'] ) ), $this );
|
||||
$this->load->view('people/manage',$data);
|
||||
$lines_per_page = $this->Appconfig->get('lines_per_page');
|
||||
$suppliers = $this->Employee->get_all($lines_per_page,$limit_from);
|
||||
$data['links'] = $this->_initialize_pagination($this->Employee,$lines_per_page,$limit_from);
|
||||
$data['manage_table']=get_people_manage_table($suppliers,$this);
|
||||
$this->load->view('suppliers/manage',$data);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -26,9 +23,14 @@ class Employees extends Person_controller
|
||||
*/
|
||||
function search()
|
||||
{
|
||||
$search=$this->input->post('search');
|
||||
$data_rows=get_people_manage_table_data_rows($this->Employee->search($search),$this);
|
||||
echo $data_rows;
|
||||
$search = $this->input->post('search');
|
||||
$limit_from = $this->input->post('limit_from');
|
||||
$lines_per_page = $this->Appconfig->get('lines_per_page');
|
||||
$employees = $this->Employee->search($search, $limit_from, $lines_per_page);
|
||||
$total_rows = $this->Employee->get_found_rows($search);
|
||||
$links = $this->_initialize_pagination($this->Employee, $lines_per_page, $limit_from, $total_rows);
|
||||
$data_rows=get_people_manage_table_data_rows($employees,$this);
|
||||
echo json_encode(array('rows' => $data_rows, 'pagination' => $links));
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -59,6 +61,7 @@ class Employees extends Person_controller
|
||||
$person_data = array(
|
||||
'first_name'=>$this->input->post('first_name'),
|
||||
'last_name'=>$this->input->post('last_name'),
|
||||
'gender'=>$this->input->post('gender'),
|
||||
'email'=>$this->input->post('email'),
|
||||
'phone_number'=>$this->input->post('phone_number'),
|
||||
'address_1'=>$this->input->post('address_1'),
|
||||
@@ -69,7 +72,7 @@ class Employees extends Person_controller
|
||||
'country'=>$this->input->post('country'),
|
||||
'comments'=>$this->input->post('comments')
|
||||
);
|
||||
$grants_data = $this->input->post("grants")!=false ? $this->input->post("grants"):array();
|
||||
$grants_data = $this->input->post("grants")!=FALSE ? $this->input->post("grants"):array();
|
||||
|
||||
//Password has been changed OR first time password set
|
||||
if($this->input->post('password')!='')
|
||||
@@ -127,7 +130,7 @@ class Employees extends Person_controller
|
||||
*/
|
||||
function get_form_width()
|
||||
{
|
||||
return 650;
|
||||
return 750;
|
||||
}
|
||||
}
|
||||
?>
|
||||
@@ -1,6 +1,7 @@
|
||||
<?php
|
||||
require_once ("secure_area.php");
|
||||
require_once ("interfaces/idata_controller.php");
|
||||
|
||||
class Giftcards extends Secure_area implements iData_controller
|
||||
{
|
||||
function __construct()
|
||||
@@ -8,25 +9,27 @@ class Giftcards extends Secure_area implements iData_controller
|
||||
parent::__construct('giftcards');
|
||||
}
|
||||
|
||||
function index()
|
||||
function index($limit_from=0)
|
||||
{
|
||||
$config['base_url'] = site_url('/giftcards/index');
|
||||
$config['total_rows'] = $this->Giftcard->count_all();
|
||||
$config['per_page'] = '20';
|
||||
$config['uri_segment'] = 3;
|
||||
$this->pagination->initialize($config);
|
||||
|
||||
$data['controller_name']=strtolower(get_class());
|
||||
$data['form_width']=$this->get_form_width();
|
||||
$data['manage_table']=get_giftcards_manage_table( $this->Giftcard->get_all( $config['per_page'], $this->uri->segment( $config['uri_segment'] ) ), $this );
|
||||
$this->load->view('giftcards/manage',$data);
|
||||
$data['controller_name'] = $this->get_controller_name();
|
||||
$data['form_width'] = $this->get_form_width();
|
||||
$lines_per_page = $this->Appconfig->get('lines_per_page');
|
||||
$giftcards = $this->Giftcard->get_all($lines_per_page, $limit_from);
|
||||
$data['links'] = $this->_initialize_pagination($this->Giftcard, $lines_per_page, $limit_from);
|
||||
$data['manage_table'] = get_giftcards_manage_table($giftcards, $this);
|
||||
$this->load->view('giftcards/manage', $data);
|
||||
}
|
||||
|
||||
function search()
|
||||
{
|
||||
$search=$this->input->post('search');
|
||||
$data_rows=get_giftcards_manage_table_data_rows($this->Giftcard->search($search),$this);
|
||||
echo $data_rows;
|
||||
$search = $this->input->post('search');
|
||||
$limit_from = $this->input->post('limit_from');
|
||||
$lines_per_page = $this->Appconfig->get('lines_per_page');
|
||||
$giftcards = $this->Giftcard->search($search, $lines_per_page, $limit_from);
|
||||
$total_rows = $this->Giftcard->get_found_rows($search);
|
||||
$links = $this->_initialize_pagination($this->Giftcard, $lines_per_page, $limit_from, $total_rows);
|
||||
$data_rows = get_giftcards_manage_table_data_rows($giftcards, $this);
|
||||
echo json_encode(array('total_rows' => $total_rows, 'rows' => $data_rows, 'pagination' => $links));
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -34,23 +37,23 @@ class Giftcards extends Secure_area implements iData_controller
|
||||
*/
|
||||
function suggest()
|
||||
{
|
||||
$suggestions = $this->Giftcard->get_search_suggestions($this->input->post('q'),$this->input->post('limit'));
|
||||
$suggestions = $this->Giftcard->get_search_suggestions($this->input->post('q'), $this->input->post('limit'));
|
||||
echo implode("\n",$suggestions);
|
||||
}
|
||||
/** GARRISON ADDED 5/3/2013 **/
|
||||
|
||||
/*
|
||||
Gives search suggestions for person_id based on what is being searched for
|
||||
*/
|
||||
function person_search()
|
||||
{
|
||||
$suggestions = $this->Customer->get_customer_search_suggestions($this->input->post('q'),$this->input->post('limit'));
|
||||
$suggestions = $this->Customer->get_customer_search_suggestions($this->input->post('q'), $this->input->post('limit'));
|
||||
echo implode("\n",$suggestions);
|
||||
}
|
||||
/** END GARRISON ADDED **/
|
||||
|
||||
function get_row()
|
||||
{
|
||||
$giftcard_id = $this->input->post('row_id');
|
||||
$data_row=get_giftcard_data_row($this->Giftcard->get_info($giftcard_id),$this);
|
||||
$data_row = get_giftcard_data_row($this->Giftcard->get_info($giftcard_id), $this);
|
||||
echo $data_row;
|
||||
}
|
||||
|
||||
@@ -58,8 +61,8 @@ class Giftcards extends Secure_area implements iData_controller
|
||||
{
|
||||
$giftcard_info = $this->Giftcard->get_info($giftcard_id);
|
||||
$person_name=$giftcard_id > 0? $giftcard_info->first_name . ' ' . $giftcard_info->last_name : '';
|
||||
$data['selected_person'] = $giftcard_id > 0 ? $giftcard_info->person_id . "|" . $person_name : "";
|
||||
$data['giftcard_number']= $giftcard_id > 0 ? $giftcard_info->giftcard_id : $this->Giftcard->get_max_number()->giftcard_number + 1;
|
||||
$data['selected_person'] = $giftcard_id > 0 && isset($giftcard_info->person_id) ? $giftcard_info->person_id . "|" . $person_name : "";
|
||||
$data['giftcard_number'] = $giftcard_id > 0 ? $giftcard_info->giftcard_number : $this->Giftcard->get_max_number()->giftcard_number + 1;
|
||||
$data['giftcard_info'] = $giftcard_info;
|
||||
$this->load->view("giftcards/form",$data);
|
||||
}
|
||||
@@ -68,9 +71,9 @@ class Giftcards extends Secure_area implements iData_controller
|
||||
{
|
||||
$giftcard_data = array(
|
||||
'record_time' => date('Y-m-d H:i:s'),
|
||||
'giftcard_number'=>$this->input->post('giftcard_number'),
|
||||
'value'=>$this->input->post('value'),
|
||||
'person_id'=>$this->input->post('person_id')/**GARRISON ADDED 4/22/2013**/
|
||||
'giftcard_number'=>$this->input->post('giftcard_number', TRUE),
|
||||
'value'=>$this->input->post('value', TRUE),
|
||||
'person_id'=>$this->input->post('person_id', TRUE) ? $this->input->post('person_id') : NULL
|
||||
);
|
||||
|
||||
if( $this->Giftcard->save( $giftcard_data, $giftcard_id ) )
|
||||
@@ -78,20 +81,20 @@ class Giftcards extends Secure_area implements iData_controller
|
||||
//New giftcard
|
||||
if($giftcard_id==-1)
|
||||
{
|
||||
echo json_encode(array('success'=>true,'message'=>$this->lang->line('giftcards_successful_adding').' '.
|
||||
$giftcard_data['giftcard_number'],'giftcard_id'=>$giftcard_data['giftcard_id']));
|
||||
echo json_encode(array('success'=>true, 'message'=>$this->lang->line('giftcards_successful_adding').' '.
|
||||
$giftcard_data['giftcard_number'], 'giftcard_id'=>$giftcard_data['giftcard_id']));
|
||||
$giftcard_id = $giftcard_data['giftcard_id'];
|
||||
}
|
||||
else //previous giftcard
|
||||
{
|
||||
echo json_encode(array('success'=>true,'message'=>$this->lang->line('giftcards_successful_updating').' '.
|
||||
$giftcard_data['giftcard_number'],'giftcard_id'=>$giftcard_id));
|
||||
echo json_encode(array('success'=>true, 'message'=>$this->lang->line('giftcards_successful_updating').' '.
|
||||
$giftcard_data['giftcard_number'], 'giftcard_id'=>$giftcard_id));
|
||||
}
|
||||
}
|
||||
else//failure
|
||||
{
|
||||
echo json_encode(array('success'=>false,'message'=>$this->lang->line('giftcards_error_adding_updating').' '.
|
||||
$giftcard_data['giftcard_number'],'giftcard_id'=>-1));
|
||||
$giftcard_data['giftcard_number'], 'giftcard_id'=>-1));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -101,12 +104,12 @@ class Giftcards extends Secure_area implements iData_controller
|
||||
|
||||
if($this->Giftcard->delete_list($giftcards_to_delete))
|
||||
{
|
||||
echo json_encode(array('success'=>true,'message'=>$this->lang->line('giftcards_successful_deleted').' '.
|
||||
count($giftcards_to_delete).' '.$this->lang->line('giftcards_one_or_multiple')));
|
||||
echo json_encode(array('success'=>true, 'message'=>$this->lang->line('giftcards_successful_deleted').' '.
|
||||
count($giftcards_to_delete).' '.$this->lang->line('giftcards_one_or_multiple')));
|
||||
}
|
||||
else
|
||||
{
|
||||
echo json_encode(array('success'=>false,'message'=>$this->lang->line('giftcards_cannot_be_deleted')));
|
||||
echo json_encode(array('success'=>false, 'message'=>$this->lang->line('giftcards_cannot_be_deleted')));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -7,26 +7,63 @@ class Item_kits extends Secure_area implements iData_controller
|
||||
{
|
||||
parent::__construct('item_kits');
|
||||
}
|
||||
|
||||
function index()
|
||||
|
||||
// add the total cost and retail price to a passed items kit retrieving the data from each singolar item part of the kit
|
||||
private function add_totals_to_item_kit($item_kit)
|
||||
{
|
||||
$config['base_url'] = site_url('/item_kits/index');
|
||||
$config['total_rows'] = $this->Item_kit->count_all();
|
||||
$config['per_page'] = '20';
|
||||
$config['uri_segment'] = 3;
|
||||
$this->pagination->initialize($config);
|
||||
$item_kit->total_cost_price = 0;
|
||||
$item_kit->total_unit_price = 0;
|
||||
|
||||
$data['controller_name']=strtolower(get_class());
|
||||
$data['form_width']=$this->get_form_width();
|
||||
$data['manage_table']=get_item_kits_manage_table( $this->Item_kit->get_all( $config['per_page'], $this->uri->segment( $config['uri_segment'] ) ), $this );
|
||||
$this->load->view('item_kits/manage',$data);
|
||||
}
|
||||
foreach ($this->Item_kit_items->get_info($item_kit->item_kit_id) as $item_kit_item)
|
||||
{
|
||||
$item_info = $this->Item->get_info($item_kit_item['item_id']);
|
||||
|
||||
$item_kit->total_cost_price += $item_info->cost_price * $item_kit_item['quantity'];
|
||||
$item_kit->total_unit_price += $item_info->unit_price * $item_kit_item['quantity'];
|
||||
}
|
||||
|
||||
return $item_kit;
|
||||
}
|
||||
|
||||
function index($limit_from=0)
|
||||
{
|
||||
$data['controller_name'] = $this->get_controller_name();
|
||||
$data['form_width'] = $this->get_form_width();
|
||||
$lines_per_page = $this->Appconfig->get('lines_per_page');
|
||||
$item_kits = $this->Item_kit->get_all($lines_per_page, $limit_from);
|
||||
|
||||
foreach($item_kits->result() as $item_kit)
|
||||
{
|
||||
// calculate the total cost and retail price of the Kit so it can be printed out in the manage table
|
||||
$item_kit = $this->add_totals_to_item_kit($item_kit);
|
||||
}
|
||||
|
||||
$data['links'] = $this->_initialize_pagination($this->Item_kit, $lines_per_page, $limit_from);
|
||||
$data['manage_table'] = get_item_kits_manage_table($item_kits, $this);
|
||||
|
||||
$this->load->view('item_kits/manage', $data);
|
||||
$this->_remove_duplicate_cookies();
|
||||
}
|
||||
|
||||
function search()
|
||||
{
|
||||
$search=$this->input->post('search');
|
||||
$data_rows=get_item_kits_manage_table_data_rows($this->Item_kit->search($search),$this);
|
||||
echo $data_rows;
|
||||
$search = $this->input->post('search');
|
||||
$limit_from = $this->input->post('limit_from');
|
||||
$lines_per_page = $this->Appconfig->get('lines_per_page');
|
||||
$item_kits = $this->Item_kit->search($search, $lines_per_page, $limit_from);
|
||||
$total_rows = $this->Item_kit->get_found_rows($search);
|
||||
$links = $this->_initialize_pagination($this->Item_kit, $lines_per_page, $limit_from, $total_rows, 'search');
|
||||
|
||||
foreach($item_kits->result() as $item_kit)
|
||||
{
|
||||
// calculate the total cost and retail price of the Kit so it can be printed out in the manage table
|
||||
$item_kit = $this->add_totals_to_item_kit($item_kit);
|
||||
}
|
||||
|
||||
$data_rows = get_item_kits_manage_table_data_rows($item_kits, $this);
|
||||
$this->_remove_duplicate_cookies();
|
||||
|
||||
echo json_encode(array('total_rows' => $total_rows, 'rows' => $data_rows, 'pagination' => $links));
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -34,43 +71,51 @@ class Item_kits extends Secure_area implements iData_controller
|
||||
*/
|
||||
function suggest()
|
||||
{
|
||||
$suggestions = $this->Item_kit->get_search_suggestions($this->input->post('q'),$this->input->post('limit'));
|
||||
echo implode("\n",$suggestions);
|
||||
$suggestions = $this->Item_kit->get_search_suggestions($this->input->post('q'), $this->input->post('limit'));
|
||||
|
||||
echo implode("\n", $suggestions);
|
||||
}
|
||||
|
||||
function get_row()
|
||||
{
|
||||
$item_kit_id = $this->input->post('row_id');
|
||||
$data_row=get_item_kit_data_row($this->Item_kit->get_info($item_kit_id),$this);
|
||||
echo $data_row;
|
||||
|
||||
// calculate the total cost and retail price of the Kit so it can be added to the table refresh
|
||||
$item_kit = $this->add_totals_to_item_kit($this->Item_kit->get_info($item_kit_id));
|
||||
|
||||
echo (get_item_kit_data_row($item_kit, $this));
|
||||
$this->_remove_duplicate_cookies();
|
||||
}
|
||||
|
||||
function view($item_kit_id=-1)
|
||||
{
|
||||
$data['item_kit_info']=$this->Item_kit->get_info($item_kit_id);
|
||||
$this->load->view("item_kits/form",$data);
|
||||
$data['item_kit_info'] = $this->Item_kit->get_info($item_kit_id);
|
||||
$this->load->view("item_kits/form", $data);
|
||||
}
|
||||
|
||||
function save($item_kit_id=-1)
|
||||
{
|
||||
$item_kit_data = array(
|
||||
'name'=>$this->input->post('name'),
|
||||
'description'=>$this->input->post('description')
|
||||
'name' => $this->input->post('name'),
|
||||
'description' => $this->input->post('description')
|
||||
);
|
||||
|
||||
if($this->Item_kit->save($item_kit_data,$item_kit_id))
|
||||
if ($this->Item_kit->save($item_kit_data, $item_kit_id))
|
||||
{
|
||||
//New item kit
|
||||
if($item_kit_id==-1)
|
||||
if ($item_kit_id==-1)
|
||||
{
|
||||
echo json_encode(array('success'=>true,'message'=>$this->lang->line('item_kits_successful_adding').' '.
|
||||
$item_kit_data['name'],'item_kit_id'=>$item_kit_data['item_kit_id']));
|
||||
$item_kit_id = $item_kit_data['item_kit_id'];
|
||||
|
||||
echo json_encode(array('success'=>true,
|
||||
'message'=>$this->lang->line('item_kits_successful_adding').' '.$item_kit_data['name'],
|
||||
'item_kit_id'=>$item_kit_id));
|
||||
}
|
||||
else //previous item
|
||||
{
|
||||
echo json_encode(array('success'=>true,'message'=>$this->lang->line('item_kits_successful_updating').' '.
|
||||
$item_kit_data['name'],'item_kit_id'=>$item_kit_id));
|
||||
echo json_encode(array('success'=>true,
|
||||
'message'=>$this->lang->line('item_kits_successful_updating').' '.$item_kit_data['name'],
|
||||
'item_kit_id'=>$item_kit_id));
|
||||
}
|
||||
|
||||
if ($this->input->post('item_kit_item'))
|
||||
@@ -81,7 +126,7 @@ class Item_kits extends Secure_area implements iData_controller
|
||||
$item_kit_items[] = array(
|
||||
'item_id' => $item_id,
|
||||
'quantity' => $quantity
|
||||
);
|
||||
);
|
||||
}
|
||||
|
||||
$this->Item_kit_items->save($item_kit_items, $item_kit_id);
|
||||
@@ -89,50 +134,60 @@ class Item_kits extends Secure_area implements iData_controller
|
||||
}
|
||||
else//failure
|
||||
{
|
||||
echo json_encode(array('success'=>false,'message'=>$this->lang->line('item_kits_error_adding_updating').' '.
|
||||
$item_kit_data['name'],'item_kit_id'=>-1));
|
||||
echo json_encode(array('success'=>false,
|
||||
'message'=>$this->lang->line('item_kits_error_adding_updating').' '.$item_kit_data['name'],
|
||||
'item_kit_id'=>-1));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function delete()
|
||||
{
|
||||
$item_kits_to_delete=$this->input->post('ids');
|
||||
$item_kits_to_delete = $this->input->post('ids');
|
||||
|
||||
if($this->Item_kit->delete_list($item_kits_to_delete))
|
||||
if ($this->Item_kit->delete_list($item_kits_to_delete))
|
||||
{
|
||||
echo json_encode(array('success'=>true,'message'=>$this->lang->line('item_kits_successful_deleted').' '.
|
||||
count($item_kits_to_delete).' '.$this->lang->line('item_kits_one_or_multiple')));
|
||||
echo json_encode(array('success'=>true,
|
||||
'message'=>$this->lang->line('item_kits_successful_deleted').' '.count($item_kits_to_delete).' '.$this->lang->line('item_kits_one_or_multiple')));
|
||||
}
|
||||
else
|
||||
{
|
||||
echo json_encode(array('success'=>false,'message'=>$this->lang->line('item_kits_cannot_be_deleted')));
|
||||
echo json_encode(array('success'=>false,
|
||||
'message'=>$this->lang->line('item_kits_cannot_be_deleted')));
|
||||
}
|
||||
}
|
||||
|
||||
function generate_barcodes($item_kit_ids)
|
||||
{
|
||||
$this->load->library('barcode_lib');
|
||||
$result = array();
|
||||
|
||||
$item_kit_ids = explode(':', $item_kit_ids);
|
||||
foreach ($item_kit_ids as $item_kid_id)
|
||||
{
|
||||
$item_kit_info = $this->Item_kit->get_info($item_kid_id);
|
||||
{
|
||||
// calculate the total cost and retail price of the Kit so it can be added to the barcode text at the bottom
|
||||
$item_kit = $this->add_totals_to_item_kit($this->Item_kit->get_info($item_kid_id));
|
||||
|
||||
$result[] = array('name' =>$item_kit_info->name, 'id'=> 'KIT '.$item_kid_id);
|
||||
$result[] = array('name'=>$item_kit->name, 'item_id'=>'KIT '.$item_kid_id, 'item_number'=>'KIT '.$item_kid_id, 'cost_price'=>$item_kit->total_cost_price, 'unit_price'=>$item_kit->total_unit_price);
|
||||
}
|
||||
|
||||
$data['items'] = $result;
|
||||
$barcode_config = $this->barcode_lib->get_barcode_config();
|
||||
// in case the selected barcode type is not Code39 or Code128 we set by default Code128
|
||||
// the rationale for this is that EAN codes cannot have strings as seed, so 'KIT ' is not allowed
|
||||
if($barcode_config['barcode_type'] != 'Code39' && $barcode_config['barcode_type'] != 'Code128')
|
||||
{
|
||||
$barcode_config['barcode_type'] = 'Code128';
|
||||
}
|
||||
$data['barcode_config'] = $barcode_config;
|
||||
$this->load->view("barcode_sheet", $data);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
get the width for the add/edit form
|
||||
*/
|
||||
function get_form_width()
|
||||
{
|
||||
return 360;
|
||||
return 400;
|
||||
}
|
||||
}
|
||||
?>
|
||||
@@ -1,6 +1,7 @@
|
||||
<?php
|
||||
require_once ("secure_area.php");
|
||||
require_once ("interfaces/idata_controller.php");
|
||||
|
||||
class Items extends Secure_area implements iData_controller
|
||||
{
|
||||
function __construct()
|
||||
@@ -8,47 +9,37 @@ class Items extends Secure_area implements iData_controller
|
||||
parent::__construct('items');
|
||||
$this->load->library('item_lib');
|
||||
}
|
||||
|
||||
function index()
|
||||
|
||||
function index($limit_from=0)
|
||||
{
|
||||
$config['base_url'] = site_url('/items/index');
|
||||
$config['total_rows'] = $this->Item->count_all();
|
||||
$config['per_page'] = '20';
|
||||
$config['uri_segment'] = 3;
|
||||
$this->pagination->initialize($config);
|
||||
$stock_location = $this->item_lib->get_item_location();
|
||||
$stock_locations = $this->Stock_location->get_allowed_locations();
|
||||
|
||||
$stock_location=$this->item_lib->get_item_location();
|
||||
$stock_locations=$this->Stock_locations->get_allowed_locations();
|
||||
$data['stock_location']=$stock_location;
|
||||
$data['stock_locations']=$stock_locations;
|
||||
$data['controller_name']=strtolower(get_class());
|
||||
$data['form_width']=$this->get_form_width();
|
||||
$data['manage_table']=get_items_manage_table( $this->Item->get_all( $stock_location, $config['per_page'], $this->uri->segment( $config['uri_segment'] ) ), $this );
|
||||
$this->load->view('items/manage',$data);
|
||||
}
|
||||
$data['controller_name'] = $this->get_controller_name();
|
||||
$data['form_width'] = $this->get_form_width();
|
||||
$lines_per_page = $this->Appconfig->get('lines_per_page');
|
||||
$items = $this->Item->get_all($stock_location, $lines_per_page, $limit_from);
|
||||
$data['links'] = $this->_initialize_pagination($this->Item, $lines_per_page, $limit_from);
|
||||
|
||||
// assume year 2010 as starting date for OSPOS
|
||||
$start_of_time = date($this->config->item('dateformat'), mktime(0,0,0,1,1,2010));
|
||||
$today = date($this->config->item('dateformat'));
|
||||
|
||||
function refresh()
|
||||
{
|
||||
$is_serialized=$this->input->post('is_serialized');
|
||||
$no_description=$this->input->post('no_description');
|
||||
$search_custom=$this->input->post('search_custom');//GARRISON ADDED 4/13/2013
|
||||
$is_deleted=$this->input->post('is_deleted'); // Parq 131215
|
||||
$this->item_lib->set_item_location($this->input->post('stock_location'));
|
||||
|
||||
$stock_location=$this->input->post('stock_location');
|
||||
$stock_locations=$this->Stock_locations->get_allowed_locations();
|
||||
$data['stock_location']=$this->item_lib->get_item_location();
|
||||
$data['stock_locations']=$stock_locations;
|
||||
|
||||
$data['search_section_state']=$this->input->post('search_section_state');
|
||||
$data['is_serialized']=$this->input->post('is_serialized');
|
||||
$data['no_description']=$this->input->post('no_description');
|
||||
$data['search_custom']=$this->input->post('search_custom');//GARRISON ADDED 4/13/2013
|
||||
$data['is_deleted']=$this->input->post('is_deleted'); // Parq 131215
|
||||
$data['controller_name']=strtolower(get_class());
|
||||
$data['form_width']=$this->get_form_width();
|
||||
$data['manage_table']=get_items_manage_table($this->Item->get_all_filtered($stock_location,$is_serialized,$no_description,$search_custom,$is_deleted),$this);//GARRISON MODIFIED 4/13/2013, Parq 131215
|
||||
$this->load->view('items/manage',$data);
|
||||
$start_date = $this->input->post('start_date') != NULL ? $this->input->post('start_date', TRUE) : $start_of_time;
|
||||
$start_date_formatter = date_create_from_format($this->config->item('dateformat'), $start_date);
|
||||
$end_date = $this->input->post('end_date') != NULL ? $this->input->post('end_date', TRUE) : $today;
|
||||
$end_date_formatter = date_create_from_format($this->config->item('dateformat'), $end_date);
|
||||
|
||||
$data['start_date'] = $start_date_formatter->format($this->config->item('dateformat'));
|
||||
$data['end_date'] = $end_date_formatter->format($this->config->item('dateformat'));
|
||||
|
||||
$data['stock_location'] = $stock_location;
|
||||
$data['stock_locations'] = $stock_locations;
|
||||
$data['manage_table'] = get_items_manage_table( $this->Item->get_all($stock_location, $lines_per_page, $limit_from), $this );
|
||||
|
||||
$this->load->view('items/manage', $data);
|
||||
|
||||
$this->_remove_duplicate_cookies();
|
||||
}
|
||||
|
||||
function find_item_info()
|
||||
@@ -59,10 +50,68 @@ class Items extends Secure_area implements iData_controller
|
||||
|
||||
function search()
|
||||
{
|
||||
$search=$this->input->post('search');
|
||||
$stock_location=$this->item_lib->get_item_location();
|
||||
$data_rows=get_items_manage_table_data_rows($this->Item->search($search,$stock_location),$this);
|
||||
echo $data_rows;
|
||||
$search = $this->input->post('search');
|
||||
$this->item_lib->set_item_location($this->input->post('stock_location'));
|
||||
$data['search_section_state'] = $this->input->post('search_section_state');
|
||||
$limit_from = $this->input->post('limit_from');
|
||||
$lines_per_page = $this->Appconfig->get('lines_per_page');
|
||||
|
||||
// assume year 2010 as starting date for OSPOS
|
||||
$start_of_time = date($this->config->item('dateformat'), mktime(0,0,0,1,1,2010));
|
||||
$today = date($this->config->item('dateformat'));
|
||||
|
||||
$start_date = $this->input->post('start_date') != NULL ? $this->input->post('start_date', TRUE) : $start_of_time;
|
||||
$start_date_formatter = date_create_from_format($this->config->item('dateformat'), $start_date);
|
||||
$end_date = $this->input->post('end_date') != NULL ? $this->input->post('end_date', TRUE) : $today;
|
||||
$end_date_formatter = date_create_from_format($this->config->item('dateformat'), $end_date);
|
||||
|
||||
$filters = array('start_date' => $start_date_formatter->format('Y-m-d'),
|
||||
'end_date' => $end_date_formatter->format('Y-m-d'),
|
||||
'stock_location_id' => $this->item_lib->get_item_location(),
|
||||
'empty_upc' => $this->input->post('empty_upc'),
|
||||
'low_inventory' => $this->input->post('low_inventory'),
|
||||
'is_serialized' => $this->input->post('is_serialized'),
|
||||
'no_description' => $this->input->post('no_description'),
|
||||
'search_custom' => $this->input->post('search_custom'),
|
||||
'is_deleted' => $this->input->post('is_deleted'));
|
||||
|
||||
$items = $this->Item->search($search, $filters, $lines_per_page, $limit_from);
|
||||
$data_rows = get_items_manage_table_data_rows($items, $this);
|
||||
$total_rows = $this->Item->get_found_rows($search, $filters);
|
||||
$links = $this->_initialize_pagination($this->Item, $lines_per_page, $limit_from, $total_rows, 'search');
|
||||
$data_rows = get_items_manage_table_data_rows($items, $this);
|
||||
// do not move this line to be after the json_encode otherwise the searhc function won't work!!
|
||||
$this->_remove_duplicate_cookies();
|
||||
|
||||
echo json_encode(array('total_rows' => $total_rows, 'rows' => $data_rows, 'pagination' => $links));
|
||||
}
|
||||
|
||||
function pic_thumb($pic_id)
|
||||
{
|
||||
$this->load->helper('file');
|
||||
$this->load->library('image_lib');
|
||||
$base_path = "uploads/item_pics/" . $pic_id ;
|
||||
$images = glob ($base_path. "*");
|
||||
if (sizeof($images) > 0)
|
||||
{
|
||||
$image_path = $images[0];
|
||||
$ext = pathinfo($image_path, PATHINFO_EXTENSION);
|
||||
$thumb_path = $base_path . $this->image_lib->thumb_marker.'.'.$ext;
|
||||
if (sizeof($images) < 2)
|
||||
{
|
||||
$config['image_library'] = 'gd2';
|
||||
$config['source_image'] = $image_path;
|
||||
$config['maintain_ratio'] = TRUE;
|
||||
$config['create_thumb'] = TRUE;
|
||||
$config['width'] = 52;
|
||||
$config['height'] = 32;
|
||||
$this->image_lib->initialize($config);
|
||||
$image = $this->image_lib->resize();
|
||||
$thumb_path = $this->image_lib->full_dst_path;
|
||||
}
|
||||
$this->output->set_content_type(get_mime_by_extension($thumb_path));
|
||||
$this->output->set_output(file_get_contents($thumb_path));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -70,32 +119,36 @@ class Items extends Secure_area implements iData_controller
|
||||
*/
|
||||
function suggest()
|
||||
{
|
||||
$suggestions = $this->Item->get_search_suggestions($this->input->post('q'),$this->input->post('limit'));
|
||||
$suggestions = $this->Item->get_search_suggestions($this->input->post('q'), $this->input->post('limit'),
|
||||
$this->input->post('search_custom'), $this->input->post('is_deleted'));
|
||||
|
||||
echo implode("\n",$suggestions);
|
||||
}
|
||||
|
||||
function item_search()
|
||||
{
|
||||
$suggestions = $this->Item->get_item_search_suggestions($this->input->post('q'),$this->input->post('limit'),'warehouse');
|
||||
$suggestions = $this->Item->get_item_search_suggestions($this->input->post('q'), $this->input->post('limit'));
|
||||
|
||||
echo implode("\n",$suggestions);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Gives search suggestions based on what is being searched for
|
||||
*/
|
||||
function suggest_category()
|
||||
{
|
||||
$suggestions = $this->Item->get_category_suggestions($this->input->post('q'));
|
||||
|
||||
echo implode("\n",$suggestions);
|
||||
}
|
||||
|
||||
/**GARRISON ADDED 5/18/2013**/
|
||||
/*
|
||||
Gives search suggestions based on what is being searched for
|
||||
*/
|
||||
function suggest_location()
|
||||
{
|
||||
$suggestions = $this->Item->get_location_suggestions($this->input->post('q'));
|
||||
|
||||
echo implode("\n",$suggestions);
|
||||
}
|
||||
|
||||
@@ -105,6 +158,7 @@ class Items extends Secure_area implements iData_controller
|
||||
function suggest_custom1()
|
||||
{
|
||||
$suggestions = $this->Item->get_custom1_suggestions($this->input->post('q'));
|
||||
|
||||
echo implode("\n",$suggestions);
|
||||
}
|
||||
|
||||
@@ -114,6 +168,7 @@ class Items extends Secure_area implements iData_controller
|
||||
function suggest_custom2()
|
||||
{
|
||||
$suggestions = $this->Item->get_custom2_suggestions($this->input->post('q'));
|
||||
|
||||
echo implode("\n",$suggestions);
|
||||
}
|
||||
|
||||
@@ -123,6 +178,7 @@ class Items extends Secure_area implements iData_controller
|
||||
function suggest_custom3()
|
||||
{
|
||||
$suggestions = $this->Item->get_custom3_suggestions($this->input->post('q'));
|
||||
|
||||
echo implode("\n",$suggestions);
|
||||
}
|
||||
|
||||
@@ -132,6 +188,7 @@ class Items extends Secure_area implements iData_controller
|
||||
function suggest_custom4()
|
||||
{
|
||||
$suggestions = $this->Item->get_custom4_suggestions($this->input->post('q'));
|
||||
|
||||
echo implode("\n",$suggestions);
|
||||
}
|
||||
|
||||
@@ -141,6 +198,7 @@ class Items extends Secure_area implements iData_controller
|
||||
function suggest_custom5()
|
||||
{
|
||||
$suggestions = $this->Item->get_custom5_suggestions($this->input->post('q'));
|
||||
|
||||
echo implode("\n",$suggestions);
|
||||
}
|
||||
|
||||
@@ -150,6 +208,7 @@ class Items extends Secure_area implements iData_controller
|
||||
function suggest_custom6()
|
||||
{
|
||||
$suggestions = $this->Item->get_custom6_suggestions($this->input->post('q'));
|
||||
|
||||
echo implode("\n",$suggestions);
|
||||
}
|
||||
|
||||
@@ -159,6 +218,7 @@ class Items extends Secure_area implements iData_controller
|
||||
function suggest_custom7()
|
||||
{
|
||||
$suggestions = $this->Item->get_custom7_suggestions($this->input->post('q'));
|
||||
|
||||
echo implode("\n",$suggestions);
|
||||
}
|
||||
|
||||
@@ -168,6 +228,7 @@ class Items extends Secure_area implements iData_controller
|
||||
function suggest_custom8()
|
||||
{
|
||||
$suggestions = $this->Item->get_custom8_suggestions($this->input->post('q'));
|
||||
|
||||
echo implode("\n",$suggestions);
|
||||
}
|
||||
|
||||
@@ -177,6 +238,7 @@ class Items extends Secure_area implements iData_controller
|
||||
function suggest_custom9()
|
||||
{
|
||||
$suggestions = $this->Item->get_custom9_suggestions($this->input->post('q'));
|
||||
|
||||
echo implode("\n",$suggestions);
|
||||
}
|
||||
|
||||
@@ -186,21 +248,22 @@ class Items extends Secure_area implements iData_controller
|
||||
function suggest_custom10()
|
||||
{
|
||||
$suggestions = $this->Item->get_custom10_suggestions($this->input->post('q'));
|
||||
|
||||
echo implode("\n",$suggestions);
|
||||
}
|
||||
|
||||
/**END GARRISON ADDED**/
|
||||
|
||||
function get_row()
|
||||
{
|
||||
$item_id = $this->input->post('row_id');
|
||||
$item_info = $this->Item->get_info($item_id);
|
||||
$stock_location = $this->item_lib->get_item_location();
|
||||
$item_quantity = $this->Item_quantities->get_item_quantity($item_id,$stock_location);
|
||||
$item_quantity = $this->Item_quantity->get_item_quantity($item_id,$stock_location);
|
||||
$item_info->quantity = $item_quantity->quantity;
|
||||
$data_row=get_item_data_row($item_info,$this);
|
||||
$data_row = get_item_data_row($item_info,$this);
|
||||
|
||||
echo $data_row;
|
||||
|
||||
$this->_remove_duplicate_cookies();
|
||||
}
|
||||
|
||||
function view($item_id=-1)
|
||||
@@ -210,7 +273,7 @@ class Items extends Secure_area implements iData_controller
|
||||
$suppliers = array('' => $this->lang->line('items_none'));
|
||||
foreach($this->Supplier->get_all()->result_array() as $row)
|
||||
{
|
||||
$suppliers[$row['person_id']] = $row['company_name'] .' ('.$row['first_name'] .' '. $row['last_name'].')';
|
||||
$suppliers[$row['person_id']] = $row['company_name'];
|
||||
}
|
||||
|
||||
$data['suppliers']=$suppliers;
|
||||
@@ -218,33 +281,31 @@ class Items extends Secure_area implements iData_controller
|
||||
$data['default_tax_1_rate']=($item_id==-1) ? $this->Appconfig->get('default_tax_1_rate') : '';
|
||||
$data['default_tax_2_rate']=($item_id==-1) ? $this->Appconfig->get('default_tax_2_rate') : '';
|
||||
|
||||
$locations_data = $this->Stock_locations->get_undeleted_all()->result_array();
|
||||
$locations_data = $this->Stock_location->get_undeleted_all()->result_array();
|
||||
foreach($locations_data as $location)
|
||||
{
|
||||
$quantity = $this->Item_quantities->get_item_quantity($item_id,$location['location_id'])->quantity;
|
||||
$quantity = $this->Item_quantity->get_item_quantity($item_id,$location['location_id'])->quantity;
|
||||
$quantity = ($item_id == -1) ? null: $quantity;
|
||||
$location_array[$location['location_id']] = array('location_name'=>$location['location_name'],
|
||||
'quantity'=>$quantity);
|
||||
$data['stock_locations']= $location_array;
|
||||
$location_array[$location['location_id']] = array('location_name'=>$location['location_name'], 'quantity'=>$quantity);
|
||||
$data['stock_locations'] = $location_array;
|
||||
}
|
||||
$this->load->view("items/form",$data);
|
||||
}
|
||||
|
||||
$this->load->view("items/form", $data);
|
||||
}
|
||||
|
||||
//Ramel Inventory Tracking
|
||||
function inventory($item_id=-1)
|
||||
{
|
||||
$data['item_info']=$this->Item->get_info($item_id);
|
||||
|
||||
$data['stock_locations'] = array();
|
||||
$stock_locations = $this->Stock_locations->get_undeleted_all()->result_array();
|
||||
$stock_locations = $this->Stock_location->get_undeleted_all()->result_array();
|
||||
foreach($stock_locations as $location_data)
|
||||
{
|
||||
$data['stock_locations'][$location_data['location_id']] = $location_data['location_name'];
|
||||
$data['item_quantities'][$location_data['location_id']] = $this->Item_quantities->get_item_quantity($item_id,$location_data['location_id'])->quantity;
|
||||
$data['item_quantities'][$location_data['location_id']] = $this->Item_quantity->get_item_quantity($item_id,$location_data['location_id'])->quantity;
|
||||
}
|
||||
|
||||
$this->load->view("items/inventory",$data);
|
||||
$this->load->view("items/inventory", $data);
|
||||
}
|
||||
|
||||
function count_details($item_id=-1)
|
||||
@@ -252,30 +313,51 @@ class Items extends Secure_area implements iData_controller
|
||||
$data['item_info']=$this->Item->get_info($item_id);
|
||||
|
||||
$data['stock_locations'] = array();
|
||||
$stock_locations = $this->Stock_locations->get_undeleted_all()->result_array();
|
||||
$stock_locations = $this->Stock_location->get_undeleted_all()->result_array();
|
||||
foreach($stock_locations as $location_data)
|
||||
{
|
||||
$data['stock_locations'][$location_data['location_id']] = $location_data['location_name'];
|
||||
$data['item_quantities'][$location_data['location_id']] = $this->Item_quantities->get_item_quantity($item_id,$location_data['location_id'])->quantity;
|
||||
$data['item_quantities'][$location_data['location_id']] = $this->Item_quantity->get_item_quantity($item_id,$location_data['location_id'])->quantity;
|
||||
}
|
||||
|
||||
$this->load->view("items/count_details",$data);
|
||||
} //------------------------------------------- Ramel
|
||||
$this->load->view("items/count_details", $data);
|
||||
}
|
||||
|
||||
function generate_barcodes($item_ids)
|
||||
{
|
||||
$this->load->library('barcode_lib');
|
||||
$result = array();
|
||||
|
||||
$item_ids = explode(':', $item_ids);
|
||||
foreach ($item_ids as $item_id)
|
||||
$result = $this->Item->get_multiple_info($item_ids)->result_array();
|
||||
$config = $this->barcode_lib->get_barcode_config();
|
||||
|
||||
$data['barcode_config'] = $config;
|
||||
|
||||
// check the list of items to see if any item_number field is empty
|
||||
foreach($result as &$item)
|
||||
{
|
||||
$item_info = $this->Item->get_info($item_id);
|
||||
|
||||
$result[] = array('name' =>$item_info->name, 'id'=> $item_id);
|
||||
// update the UPC/EAN/ISBN field if empty / null with the newly generated barcode
|
||||
if (empty($item['item_number']) && $this->Appconfig->get('barcode_generate_if_empty'))
|
||||
{
|
||||
// get the newly generated barcode
|
||||
$barcode_instance = Barcode_lib::barcode_instance($item, $config);
|
||||
$item['item_number'] = $barcode_instance->getData();
|
||||
// remove from item any suppliers table info to avoid save failure because of unknown fields
|
||||
// WARNING: if suppliers table is changed this list needs to be upgraded, which makes the matter a bit tricky to maintain
|
||||
unset($item['person_id']);
|
||||
unset($item['company_name']);
|
||||
unset($item['account_number']);
|
||||
unset($item['agency_name']);
|
||||
|
||||
// update the item in the database in order to save the UPC/EAN/ISBN field
|
||||
$this->Item->save($item, $item['item_id']);
|
||||
}
|
||||
}
|
||||
|
||||
$data['items'] = $result;
|
||||
// display barcodes
|
||||
$this->load->view("barcode_sheet", $data);
|
||||
|
||||
}
|
||||
|
||||
function bulk_edit()
|
||||
@@ -284,7 +366,7 @@ class Items extends Secure_area implements iData_controller
|
||||
$suppliers = array('' => $this->lang->line('items_none'));
|
||||
foreach($this->Supplier->get_all()->result_array() as $row)
|
||||
{
|
||||
$suppliers[$row['person_id']] = $row['first_name'] .' '. $row['last_name'];
|
||||
$suppliers[$row['person_id']] = $row['company_name'];
|
||||
}
|
||||
$data['suppliers'] = $suppliers;
|
||||
$data['allow_alt_description_choices'] = array(
|
||||
@@ -296,56 +378,58 @@ class Items extends Secure_area implements iData_controller
|
||||
''=>$this->lang->line('items_do_nothing'),
|
||||
1 =>$this->lang->line('items_change_all_to_serialized'),
|
||||
0 =>$this->lang->line('items_change_all_to_unserialized'));
|
||||
|
||||
$this->load->view("items/form_bulk", $data);
|
||||
}
|
||||
|
||||
function save($item_id=-1)
|
||||
{
|
||||
$upload_success = $this->_handle_image_upload();
|
||||
$upload_data = $this->upload->data();
|
||||
//Save item data
|
||||
$item_data = array(
|
||||
'name'=>$this->input->post('name'),
|
||||
'description'=>$this->input->post('description'),
|
||||
'category'=>$this->input->post('category'),
|
||||
'supplier_id'=>$this->input->post('supplier_id')=='' ? null:$this->input->post('supplier_id'),
|
||||
'item_number'=>$this->input->post('item_number')=='' ? null:$this->input->post('item_number'),
|
||||
'cost_price'=>$this->input->post('cost_price'),
|
||||
'unit_price'=>$this->input->post('unit_price'),
|
||||
'reorder_level'=>$this->input->post('reorder_level'),
|
||||
'receiving_quantity'=>$this->input->post('receiving_quantity'),
|
||||
'allow_alt_description'=>$this->input->post('allow_alt_description'),
|
||||
'is_serialized'=>$this->input->post('is_serialized'),
|
||||
'deleted'=>$this->input->post('is_deleted'), /** Parq 131215 **/
|
||||
'custom1'=>$this->input->post('custom1'), /**GARRISON ADDED 4/21/2013**/
|
||||
'custom2'=>$this->input->post('custom2'),/**GARRISON ADDED 4/21/2013**/
|
||||
'custom3'=>$this->input->post('custom3'),/**GARRISON ADDED 4/21/2013**/
|
||||
'custom4'=>$this->input->post('custom4'),/**GARRISON ADDED 4/21/2013**/
|
||||
'custom5'=>$this->input->post('custom5'),/**GARRISON ADDED 4/21/2013**/
|
||||
'custom6'=>$this->input->post('custom6'),/**GARRISON ADDED 4/21/2013**/
|
||||
'custom7'=>$this->input->post('custom7'),/**GARRISON ADDED 4/21/2013**/
|
||||
'custom8'=>$this->input->post('custom8'),/**GARRISON ADDED 4/21/2013**/
|
||||
'custom9'=>$this->input->post('custom9'),/**GARRISON ADDED 4/21/2013**/
|
||||
'custom10'=>$this->input->post('custom10')/**GARRISON ADDED 4/21/2013**/
|
||||
'name'=>$this->input->post('name'),
|
||||
'description'=>$this->input->post('description'),
|
||||
'category'=>$this->input->post('category'),
|
||||
'supplier_id'=>$this->input->post('supplier_id')=='' ? null:$this->input->post('supplier_id'),
|
||||
'item_number'=>$this->input->post('item_number')=='' ? null:$this->input->post('item_number'),
|
||||
'cost_price'=>$this->input->post('cost_price'),
|
||||
'unit_price'=>$this->input->post('unit_price'),
|
||||
'reorder_level'=>$this->input->post('reorder_level'),
|
||||
'receiving_quantity'=>$this->input->post('receiving_quantity'),
|
||||
'allow_alt_description'=>$this->input->post('allow_alt_description'),
|
||||
'is_serialized'=>$this->input->post('is_serialized'),
|
||||
'deleted'=>$this->input->post('is_deleted'),
|
||||
'custom1'=>$this->input->post('custom1'),
|
||||
'custom2'=>$this->input->post('custom2'),
|
||||
'custom3'=>$this->input->post('custom3'),
|
||||
'custom4'=>$this->input->post('custom4'),
|
||||
'custom5'=>$this->input->post('custom5'),
|
||||
'custom6'=>$this->input->post('custom6'),
|
||||
'custom7'=>$this->input->post('custom7'),
|
||||
'custom8'=>$this->input->post('custom8'),
|
||||
'custom9'=>$this->input->post('custom9'),
|
||||
'custom10'=>$this->input->post('custom10')
|
||||
);
|
||||
|
||||
$employee_id=$this->Employee->get_logged_in_employee_info()->person_id;
|
||||
if (!empty($upload_data['orig_name']))
|
||||
{
|
||||
$item_data['pic_id'] = $upload_data['raw_name'];
|
||||
}
|
||||
|
||||
$employee_id = $this->Employee->get_logged_in_employee_info()->person_id;
|
||||
$cur_item_info = $this->Item->get_info($item_id);
|
||||
|
||||
$new_item = FALSE;
|
||||
|
||||
if($this->Item->save($item_data,$item_id))
|
||||
{
|
||||
$success = TRUE;
|
||||
$new_item = FALSE;
|
||||
//New item
|
||||
if($item_id==-1)
|
||||
if ($item_id==-1)
|
||||
{
|
||||
echo json_encode(array('success'=>true,'message'=>$this->lang->line('items_successful_adding').' '.
|
||||
$item_data['name'],'item_id'=>$item_data['item_id']));
|
||||
$item_id = $item_data['item_id'];
|
||||
$new_item = TRUE;
|
||||
}
|
||||
else //previous item
|
||||
{
|
||||
echo json_encode(array('success'=>true,'message'=>$this->lang->line('items_successful_updating').' '.
|
||||
$item_data['name'],'item_id'=>$item_id));
|
||||
}
|
||||
|
||||
$items_taxes_data = array();
|
||||
$tax_names = $this->input->post('tax_names');
|
||||
@@ -357,24 +441,22 @@ class Items extends Secure_area implements iData_controller
|
||||
$items_taxes_data[] = array('name'=>$tax_names[$k], 'percent'=>$tax_percents[$k] );
|
||||
}
|
||||
}
|
||||
$this->Item_taxes->save($items_taxes_data, $item_id);
|
||||
|
||||
$success &= $this->Item_taxes->save($items_taxes_data, $item_id);
|
||||
|
||||
//Save item quantity
|
||||
$stock_locations = $this->Stock_locations->get_undeleted_all()->result_array();
|
||||
$stock_locations = $this->Stock_location->get_undeleted_all()->result_array();
|
||||
foreach($stock_locations as $location_data)
|
||||
{
|
||||
$updated_quantity = $this->input->post($location_data['location_id'].'_quantity');
|
||||
$location_detail = array('item_id'=>$item_id,
|
||||
'location_id'=>$location_data['location_id'],
|
||||
'quantity'=>$updated_quantity);
|
||||
$item_quantity = $this->Item_quantities->get_item_quantity($item_id, $location_data['location_id']);
|
||||
$item_quantity = $this->Item_quantity->get_item_quantity($item_id, $location_data['location_id']);
|
||||
if ($item_quantity->quantity != $updated_quantity || $new_item)
|
||||
{
|
||||
$this->Item_quantities->save($location_detail, $item_id, $location_data['location_id']);
|
||||
$success &= $this->Item_quantity->save($location_detail, $item_id, $location_data['location_id']);
|
||||
|
||||
$inv_data = array
|
||||
(
|
||||
$inv_data = array(
|
||||
'trans_date'=>date('Y-m-d H:i:s'),
|
||||
'trans_items'=>$item_id,
|
||||
'trans_user'=>$employee_id,
|
||||
@@ -382,26 +464,67 @@ class Items extends Secure_area implements iData_controller
|
||||
'trans_comment'=>$this->lang->line('items_manually_editing_of_quantity'),
|
||||
'trans_inventory'=>$updated_quantity - $item_quantity->quantity
|
||||
);
|
||||
$this->Inventory->insert($inv_data);
|
||||
|
||||
$success &= $this->Inventory->insert($inv_data);
|
||||
}
|
||||
}
|
||||
|
||||
if ($success && $upload_success)
|
||||
{
|
||||
$success_message = $this->lang->line('items_successful_' . ($new_item ? 'adding' : 'updating')) .' '. $item_data['name'];
|
||||
|
||||
echo json_encode(array('success'=>true,'message'=>$success_message,'item_id'=>$item_id));
|
||||
}
|
||||
else
|
||||
{
|
||||
$error_message = $upload_success ?
|
||||
$this->lang->line('items_error_adding_updating') .' '. $item_data['name'] :
|
||||
$this->upload->display_errors();
|
||||
|
||||
echo json_encode(array('success'=>false,
|
||||
'message'=>$error_message,'item_id'=>$item_id));
|
||||
}
|
||||
|
||||
}
|
||||
else//failure
|
||||
{
|
||||
echo json_encode(array('success'=>false,'message'=>$this->lang->line('items_error_adding_updating').' '.
|
||||
$item_data['name'],'item_id'=>-1));
|
||||
echo json_encode(array('success'=>false,
|
||||
'message'=>$this->lang->line('items_error_adding_updating').' '
|
||||
.$item_data['name'],'item_id'=>-1));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//Ramel Inventory Tracking
|
||||
function check_item_number()
|
||||
{
|
||||
$exists = $this->Item->item_number_exists($this->input->post('item_number'),$this->input->post('item_id'));
|
||||
echo json_encode(array('success'=>!$exists,'message'=>$this->lang->line('items_item_number_duplicate')));
|
||||
}
|
||||
|
||||
function _handle_image_upload()
|
||||
{
|
||||
$this->load->helper('directory');
|
||||
$map = directory_map('./uploads/item_pics/', 1);
|
||||
// load upload library
|
||||
$config = array('upload_path' => './uploads/item_pics/',
|
||||
'allowed_types' => 'gif|jpg|png',
|
||||
'max_size' => '100',
|
||||
'max_width' => '640',
|
||||
'max_height' => '480',
|
||||
'file_name' => sizeof($map));
|
||||
$this->load->library('upload', $config);
|
||||
$this->upload->do_upload('item_image');
|
||||
|
||||
return strlen($this->upload->display_errors()) == 0 ||
|
||||
!strcmp($this->upload->display_errors(),
|
||||
'<p>'.$this->lang->line('upload_no_file_selected').'</p>');
|
||||
}
|
||||
|
||||
function save_inventory($item_id=-1)
|
||||
{
|
||||
$employee_id=$this->Employee->get_logged_in_employee_info()->person_id;
|
||||
$cur_item_info = $this->Item->get_info($item_id);
|
||||
$location_id = $this->input->post('stock_location');
|
||||
$inv_data = array
|
||||
(
|
||||
$inv_data = array(
|
||||
'trans_date'=>date('Y-m-d H:i:s'),
|
||||
'trans_items'=>$item_id,
|
||||
'trans_user'=>$employee_id,
|
||||
@@ -409,17 +532,18 @@ class Items extends Secure_area implements iData_controller
|
||||
'trans_comment'=>$this->input->post('trans_comment'),
|
||||
'trans_inventory'=>$this->input->post('newquantity')
|
||||
);
|
||||
|
||||
$this->Inventory->insert($inv_data);
|
||||
|
||||
//Update stock quantity
|
||||
|
||||
$item_quantity= $this->Item_quantities->get_item_quantity($item_id,$location_id);
|
||||
$item_quantity= $this->Item_quantity->get_item_quantity($item_id,$location_id);
|
||||
$item_quantity_data = array(
|
||||
'item_id'=>$item_id,
|
||||
'location_id'=>$location_id,
|
||||
'quantity'=>$item_quantity->quantity + $this->input->post('newquantity')
|
||||
'item_id'=>$item_id,
|
||||
'location_id'=>$location_id,
|
||||
'quantity'=>$item_quantity->quantity + $this->input->post('newquantity')
|
||||
);
|
||||
if($this->Item_quantities->save($item_quantity_data,$item_id,$location_id))
|
||||
|
||||
if($this->Item_quantity->save($item_quantity_data,$item_id,$location_id))
|
||||
{
|
||||
echo json_encode(array('success'=>true,'message'=>$this->lang->line('items_successful_updating').' '.
|
||||
$cur_item_info->name,'item_id'=>$item_id));
|
||||
@@ -429,8 +553,7 @@ class Items extends Secure_area implements iData_controller
|
||||
echo json_encode(array('success'=>false,'message'=>$this->lang->line('items_error_adding_updating').' '.
|
||||
$cur_item_info->name,'item_id'=>-1));
|
||||
}
|
||||
|
||||
}//---------------------------------------------------------------------Ramel
|
||||
}
|
||||
|
||||
function bulk_update()
|
||||
{
|
||||
@@ -444,7 +567,7 @@ class Items extends Secure_area implements iData_controller
|
||||
{
|
||||
$item_data["$key"]=$value == '' ? null : $value;
|
||||
}
|
||||
elseif($value!='' and !(in_array($key, array('item_ids', 'tax_names', 'tax_percents'))))
|
||||
elseif($value!='' and !(in_array($key, array('submit', 'item_ids', 'tax_names', 'tax_percents', 'category'))))
|
||||
{
|
||||
$item_data["$key"]=$value;
|
||||
}
|
||||
@@ -500,123 +623,158 @@ class Items extends Secure_area implements iData_controller
|
||||
$this->load->view("items/excel_import", null);
|
||||
}
|
||||
|
||||
function do_excel_import()
|
||||
{
|
||||
$msg = 'do_excel_import';
|
||||
$failCodes = array();
|
||||
if ($_FILES['file_path']['error']!=UPLOAD_ERR_OK)
|
||||
function do_excel_import()
|
||||
{
|
||||
$msg = 'do_excel_import';
|
||||
$failCodes = array();
|
||||
if ($_FILES['file_path']['error']!=UPLOAD_ERR_OK)
|
||||
{
|
||||
$msg = $this->lang->line('items_excel_import_failed');
|
||||
echo json_encode( array('success'=>false,'message'=>$msg) );
|
||||
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
$msg = $this->lang->line('items_excel_import_failed');
|
||||
echo json_encode( array('success'=>false,'message'=>$msg) );
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (($handle = fopen($_FILES['file_path']['tmp_name'], "r")) !== FALSE)
|
||||
{
|
||||
//Skip first row
|
||||
fgetcsv($handle);
|
||||
|
||||
$i=1;
|
||||
while (($data = fgetcsv($handle)) !== FALSE)
|
||||
{
|
||||
|
||||
$item_data = array(
|
||||
'name' => $data[1],
|
||||
'description' => $data[11],
|
||||
'category' => $data[2],
|
||||
'cost_price' => $data[4],
|
||||
'unit_price' => $data[5],
|
||||
'reorder_level' => $data[10],
|
||||
'supplier_id' => $this->Supplier->exists($data[3]) ? $data[3] : null,
|
||||
'allow_alt_description' => $data[12] != '' ? '1' : '0',
|
||||
'is_serialized' => $data[13] != '' ? '1' : '0',
|
||||
'custom1' => $data[14], /** GARRISON ADDED 5/6/2013 **/
|
||||
'custom2' => $data[15], /** GARRISON ADDED 5/6/2013 **/
|
||||
'custom3' => $data[16], /** GARRISON ADDED 5/6/2013 **/
|
||||
'custom4' => $data[17], /** GARRISON ADDED 5/6/2013 **/
|
||||
'custom5' => $data[18], /** GARRISON ADDED 5/6/2013 **/
|
||||
'custom6' => $data[19], /** GARRISON ADDED 5/6/2013 **/
|
||||
'custom7' => $data[20], /** GARRISON ADDED 5/6/2013 **/
|
||||
'custom8' => $data[21], /** GARRISON ADDED 5/6/2013 **/
|
||||
'custom9' => $data[22], /** GARRISON ADDED 5/6/2013 **/
|
||||
'custom10' => $data[23] /** GARRISON ADDED 5/6/2013 **/
|
||||
);
|
||||
$item_number = $data[0];
|
||||
|
||||
if ($item_number != "")
|
||||
{
|
||||
$item_data['item_number'] = $item_number;
|
||||
if (($handle = fopen($_FILES['file_path']['tmp_name'], "r")) !== FALSE)
|
||||
{
|
||||
//Skip first row
|
||||
fgetcsv($handle);
|
||||
|
||||
$i=1;
|
||||
while (($data = fgetcsv($handle)) !== FALSE)
|
||||
{
|
||||
if (sizeof($data) >= 23) {
|
||||
$item_data = array(
|
||||
'name' => $data[1],
|
||||
'description' => $data[11],
|
||||
'category' => $data[2],
|
||||
'cost_price' => $data[4],
|
||||
'unit_price' => $data[5],
|
||||
'reorder_level' => $data[10],
|
||||
'supplier_id' => $this->Supplier->exists($data[3]) ? $data[3] : null,
|
||||
'allow_alt_description' => $data[12] != '' ? '1' : '0',
|
||||
'is_serialized' => $data[13] != '' ? '1' : '0',
|
||||
'custom1' => $data[14],
|
||||
'custom2' => $data[15],
|
||||
'custom3' => $data[16],
|
||||
'custom4' => $data[17],
|
||||
'custom5' => $data[18],
|
||||
'custom6' => $data[19],
|
||||
'custom7' => $data[20],
|
||||
'custom8' => $data[21],
|
||||
'custom9' => $data[22],
|
||||
'custom10' => $data[23]
|
||||
);
|
||||
$item_number = $data[0];
|
||||
$invalidated = false;
|
||||
if ($item_number != "")
|
||||
{
|
||||
$item_data['item_number'] = $item_number;
|
||||
$invalidated = $this->Item->item_number_exists($item_number);
|
||||
}
|
||||
}
|
||||
|
||||
if($this->Item->save($item_data))
|
||||
else
|
||||
{
|
||||
$items_taxes_data = null;
|
||||
//tax 1
|
||||
if( is_numeric($data[7]) && $data[6]!='' )
|
||||
{
|
||||
$items_taxes_data[] = array('name'=>$data[6], 'percent'=>$data[7] );
|
||||
}
|
||||
|
||||
//tax 2
|
||||
if( is_numeric($data[9]) && $data[8]!='' )
|
||||
{
|
||||
$items_taxes_data[] = array('name'=>$data[8], 'percent'=>$data[9] );
|
||||
}
|
||||
|
||||
// save tax values
|
||||
if(count($items_taxes_data) > 0)
|
||||
{
|
||||
$this->Item_taxes->save($items_taxes_data, $item_data['item_id']);
|
||||
}
|
||||
|
||||
// quantities
|
||||
$cols = count($data);
|
||||
for ($col = 24; $col < $cols; $col = $col + 2)
|
||||
{
|
||||
$item_quantity_data = array(
|
||||
'item_id' => $item_data['item_id'],
|
||||
'location_id' => $data[$col],
|
||||
'quantity' => $data[$col + 1],
|
||||
);
|
||||
$this->Item_quantities->save($item_quantity_data, $data[$col], $data[$col + 1]);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Inventory Info
|
||||
|
||||
|
||||
$employee_id=$this->Employee->get_logged_in_employee_info()->person_id;
|
||||
$emp_info=$this->Employee->get_info($employee_id);
|
||||
$comment ='Qty CSV Imported';
|
||||
$excel_data = array
|
||||
(
|
||||
'trans_items'=>$item_data['item_id'],
|
||||
'trans_user'=>$employee_id,
|
||||
'trans_comment'=>$comment,
|
||||
'trans_inventory'=>$data[10]
|
||||
);
|
||||
$this->db->insert('inventory',$excel_data);
|
||||
//------------------------------------------------Ramel
|
||||
$invalidated = true;
|
||||
}
|
||||
else//insert or update item failure
|
||||
{
|
||||
$failCodes[] = $i;
|
||||
}
|
||||
}
|
||||
|
||||
$i++;
|
||||
}
|
||||
else
|
||||
{
|
||||
echo json_encode( array('success'=>false,'message'=>'Your upload file has no data or not in supported format.') );
|
||||
return;
|
||||
}
|
||||
}
|
||||
if(!$invalidated && $this->Item->save($item_data))
|
||||
{
|
||||
$items_taxes_data = null;
|
||||
//tax 1
|
||||
if( is_numeric($data[7]) && $data[6]!='' )
|
||||
{
|
||||
$items_taxes_data[] = array('name'=>$data[6], 'percent'=>$data[7] );
|
||||
}
|
||||
|
||||
//tax 2
|
||||
if( is_numeric($data[9]) && $data[8]!='' )
|
||||
{
|
||||
$items_taxes_data[] = array('name'=>$data[8], 'percent'=>$data[9] );
|
||||
}
|
||||
|
||||
// save tax values
|
||||
if(count($items_taxes_data) > 0)
|
||||
{
|
||||
$this->Item_taxes->save($items_taxes_data, $item_data['item_id']);
|
||||
}
|
||||
|
||||
// quantities & inventory Info
|
||||
$employee_id=$this->Employee->get_logged_in_employee_info()->person_id;
|
||||
$emp_info=$this->Employee->get_info($employee_id);
|
||||
$comment ='Qty CSV Imported';
|
||||
|
||||
$cols = count($data);
|
||||
|
||||
// array to store information if location got a quantity
|
||||
$allowed_locations = $this->Stock_location->get_allowed_locations();
|
||||
for ($col = 24; $col < $cols; $col = $col + 2)
|
||||
{
|
||||
$location_id = $data[$col];
|
||||
if (array_key_exists($location_id, $allowed_locations))
|
||||
{
|
||||
$item_quantity_data = array (
|
||||
'item_id' => $item_data['item_id'],
|
||||
'location_id' => $location_id,
|
||||
'quantity' => $data[$col + 1],
|
||||
);
|
||||
$this->Item_quantity->save($item_quantity_data, $item_data['item_id'], $location_id);
|
||||
|
||||
$excel_data = array(
|
||||
'trans_items'=>$item_data['item_id'],
|
||||
'trans_user'=>$employee_id,
|
||||
'trans_comment'=>$comment,
|
||||
'trans_location'=>$data[$col],
|
||||
'trans_inventory'=>$data[$col + 1]
|
||||
);
|
||||
|
||||
$this->Inventory->insert($excel_data);
|
||||
unset($allowed_locations[$location_id]);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* now iterate through the array and check for which location_id no entry into item_quantities was made yet
|
||||
* those get an entry with quantity as 0.
|
||||
* unfortunately a bit duplicate code from above...
|
||||
*/
|
||||
foreach($allowed_locations as $location_id => $location_name)
|
||||
{
|
||||
$item_quantity_data = array(
|
||||
'item_id' => $item_data['item_id'],
|
||||
'location_id' => $location_id,
|
||||
'quantity' => 0,
|
||||
);
|
||||
$this->Item_quantity->save($item_quantity_data, $item_data['item_id'], $data[$col]);
|
||||
|
||||
$excel_data = array
|
||||
(
|
||||
'trans_items'=>$item_data['item_id'],
|
||||
'trans_user'=>$employee_id,
|
||||
'trans_comment'=>$comment,
|
||||
'trans_location'=>$location_id,
|
||||
'trans_inventory'=>0
|
||||
);
|
||||
$this->db->insert('inventory',$excel_data);
|
||||
}
|
||||
}
|
||||
else//insert or update item failure
|
||||
{
|
||||
$failCodes[] = $i;
|
||||
}
|
||||
}
|
||||
$i++;
|
||||
}
|
||||
else
|
||||
{
|
||||
echo json_encode( array('success'=>false, 'message'=>'Your upload file has no data or not in supported format.') );
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
$success = true;
|
||||
if(count($failCodes) > 1)
|
||||
if(count($failCodes) > 0)
|
||||
{
|
||||
$msg = "Most items imported. But some were not, here is list of their CODE (" .count($failCodes) ."): ".implode(", ", $failCodes);
|
||||
$success = false;
|
||||
@@ -626,7 +784,7 @@ class Items extends Secure_area implements iData_controller
|
||||
$msg = "Import items successful";
|
||||
}
|
||||
|
||||
echo json_encode( array('success'=>$success,'message'=>$msg) );
|
||||
echo json_encode( array('success'=>$success, 'message'=>$msg) );
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -634,18 +792,7 @@ class Items extends Secure_area implements iData_controller
|
||||
*/
|
||||
function get_form_width()
|
||||
{
|
||||
return 360;
|
||||
return 450;
|
||||
}
|
||||
|
||||
function item_number_check($item_number)
|
||||
{
|
||||
if ($this->Item->get_item_id($item_number) != FALSE)
|
||||
{
|
||||
$this->form_validation->set_message('item_number_check', $this->lang->line('items_item_number_exists'));
|
||||
echo json_encode(array('success'=>false,'message'=>$this->lang->line('items_error_adding')));
|
||||
}
|
||||
echo json_encode(array('success'=>true,'message'=>$this->lang->line('items_successful_adding')));
|
||||
}
|
||||
|
||||
}
|
||||
?>
|
||||
|
||||
@@ -9,7 +9,7 @@ class No_Access extends CI_Controller
|
||||
function index($module_id='',$permission_id='')
|
||||
{
|
||||
$data['module_name']=$this->Module->get_module_name($module_id);
|
||||
$data['permission_id']=empty($permission_id)?$module_id:$permission_id;
|
||||
$data['permission_id']=$permission_id;
|
||||
$this->load->view('no_access',$data);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ abstract class Person_controller extends Secure_area implements iPerson_controll
|
||||
}
|
||||
echo '#';
|
||||
}
|
||||
/** GARRISON ADDED 4/25/2013 IN PROGRESS **/
|
||||
|
||||
/*
|
||||
Gives search suggestions based on what is being searched for
|
||||
*/
|
||||
@@ -49,6 +49,5 @@ abstract class Person_controller extends Secure_area implements iPerson_controll
|
||||
$data_row=get_person_data_row($this->Person->get_info($person_id),$this);
|
||||
echo $data_row;
|
||||
}
|
||||
|
||||
}
|
||||
?>
|
||||
@@ -4,8 +4,9 @@ class Receivings extends Secure_area
|
||||
{
|
||||
function __construct()
|
||||
{
|
||||
parent::__construct('receivings','items');
|
||||
parent::__construct('receivings');
|
||||
$this->load->library('receiving_lib');
|
||||
$this->load->library('barcode_lib');
|
||||
}
|
||||
|
||||
function index()
|
||||
@@ -40,11 +41,11 @@ class Receivings extends Secure_area
|
||||
if ((!$stock_source || $stock_source == $this->receiving_lib->get_stock_source()) &&
|
||||
(!$stock_destination || $stock_destination == $this->receiving_lib->get_stock_destination()))
|
||||
{
|
||||
$this->receiving_lib->empty_cart();
|
||||
$this->receiving_lib->clear_invoice_number();
|
||||
$mode = $this->input->post("mode");
|
||||
$this->receiving_lib->set_mode($mode);
|
||||
}
|
||||
else
|
||||
else if ($this->Stock_location->is_allowed_location($stock_source, 'receivings'))
|
||||
{
|
||||
$this->receiving_lib->set_stock_source($stock_source);
|
||||
$this->receiving_lib->set_stock_destination($stock_destination);
|
||||
@@ -62,6 +63,11 @@ class Receivings extends Secure_area
|
||||
$this->receiving_lib->set_invoice_number_enabled($this->input->post('recv_invoice_number_enabled'));
|
||||
}
|
||||
|
||||
function set_print_after_sale()
|
||||
{
|
||||
$this->receiving_lib->set_print_after_sale($this->input->post('recv_print_after_sale'));
|
||||
}
|
||||
|
||||
function set_invoice_number()
|
||||
{
|
||||
$this->receiving_lib->set_invoice_number($this->input->post('recv_invoice_number'));
|
||||
@@ -95,8 +101,8 @@ class Receivings extends Secure_area
|
||||
$data= array();
|
||||
|
||||
$this->form_validation->set_rules('price', 'lang:items_price', 'required|numeric');
|
||||
$this->form_validation->set_rules('quantity', 'lang:items_quantity', 'required|integer');
|
||||
$this->form_validation->set_rules('discount', 'lang:items_discount', 'required|integer');
|
||||
$this->form_validation->set_rules('quantity', 'lang:items_quantity', 'required|numeric');
|
||||
$this->form_validation->set_rules('discount', 'lang:items_discount', 'required|numeric');
|
||||
|
||||
$description = $this->input->post("description");
|
||||
$serialnumber = $this->input->post("serialnumber");
|
||||
@@ -175,10 +181,9 @@ class Receivings extends Secure_area
|
||||
$data['cart']=$this->receiving_lib->get_cart();
|
||||
$data['total']=$this->receiving_lib->get_total();
|
||||
$data['receipt_title']=$this->lang->line('recvs_receipt');
|
||||
$data['transaction_time']= date('m/d/Y h:i:s a');
|
||||
$data['transaction_time']= date($this->config->item('dateformat').' '.$this->config->item('timeformat'));
|
||||
$data['mode']=$this->receiving_lib->get_mode();
|
||||
$stock_locations = $this->Stock_locations->get_undeleted_all()->result_array();
|
||||
$data['show_stock_locations'] = count($stock_locations) > 1;
|
||||
$data['show_stock_locations']=$this->Stock_location->show_locations('receivings');
|
||||
$supplier_id=$this->receiving_lib->get_supplier();
|
||||
$employee_id=$this->Employee->get_logged_in_employee_info()->person_id;
|
||||
$comment = $this->input->post('comment');
|
||||
@@ -215,37 +220,58 @@ class Receivings extends Secure_area
|
||||
{
|
||||
$data['error_message'] = $this->lang->line('receivings_transaction_failed');
|
||||
}
|
||||
|
||||
$data['barcode']=$this->barcode_lib->generate_receipt_barcode($data['receiving_id']);
|
||||
$data['print_after_sale'] = $this->receiving_lib->is_print_after_sale();
|
||||
$this->load->view("receivings/receipt",$data);
|
||||
$this->receiving_lib->clear_all();
|
||||
}
|
||||
$this->_remove_duplicate_cookies();
|
||||
}
|
||||
|
||||
function _substitute_invoice_number($supplier_info='')
|
||||
private function _substitute_variable($text, $variable, $object, $function)
|
||||
{
|
||||
$invoice_number=$this->receiving_lib->get_invoice_number();
|
||||
if (empty($invoice_number))
|
||||
// don't query if this variable isn't used
|
||||
if (strstr($text, $variable))
|
||||
{
|
||||
$invoice_number=$this->config->config['recv_invoice_format'];
|
||||
$value = call_user_func(array($object, $function));
|
||||
$text = str_replace($variable, $value, $text);
|
||||
}
|
||||
$invoice_count=$this->Receiving->get_invoice_count();
|
||||
$invoice_number=str_replace('$CO',$invoice_count,$invoice_number);
|
||||
$invoice_number=strftime($invoice_number);
|
||||
|
||||
return $text;
|
||||
}
|
||||
|
||||
private function _substitute_variables($text,$supplier_info)
|
||||
{
|
||||
$text=$this->_substitute_variable($text, '$YCO', $this->Receiving, 'get_invoice_number_for_year');
|
||||
$text=$this->_substitute_variable($text, '$CO', $this->Receiving , 'get_invoice_count');
|
||||
$text=strftime($text);
|
||||
$text=$this->_substitute_supplier($text, $supplier_info);
|
||||
return $text;
|
||||
}
|
||||
|
||||
|
||||
private function _substitute_supplier($text,$supplier_info)
|
||||
{
|
||||
$supplier_id=$this->receiving_lib->get_supplier();
|
||||
if($supplier_id!=-1)
|
||||
{
|
||||
$invoice_number=str_replace('$SU',$supplier_info->company_name,$invoice_number);
|
||||
$words = preg_split("/\s+/", $supplier_info->company_name);
|
||||
$text=str_replace('$SU',$supplier_info->company_name,$text);
|
||||
$words = preg_split("/\s+/", trim($supplier_info->company_name));
|
||||
$acronym = "";
|
||||
foreach ($words as $w) {
|
||||
$acronym .= $w[0];
|
||||
}
|
||||
$invoice_number=str_replace('$SI',$acronym,$invoice_number);
|
||||
$text=str_replace('$SI',$acronym,$text);
|
||||
}
|
||||
return $text;
|
||||
}
|
||||
|
||||
private function _substitute_invoice_number($supplier_info='')
|
||||
{
|
||||
$invoice_number=$this->receiving_lib->get_invoice_number();
|
||||
$invoice_number=$this->config->config['recv_invoice_format'];
|
||||
$invoice_number = $this->_substitute_variables($invoice_number,$supplier_info);
|
||||
$this->receiving_lib->set_invoice_number($invoice_number);
|
||||
return $invoice_number;
|
||||
return $this->receiving_lib->get_invoice_number();
|
||||
}
|
||||
|
||||
function requisition_complete()
|
||||
@@ -276,14 +302,14 @@ class Receivings extends Secure_area
|
||||
$data['total']=$this->receiving_lib->get_total();
|
||||
$data['mode']=$this->receiving_lib->get_mode();
|
||||
$data['receipt_title']=$this->lang->line('recvs_receipt');
|
||||
$data['transaction_time']= date('m/d/Y h:i:s a', strtotime($receiving_info['receiving_time']));
|
||||
$stock_locations = $this->Stock_locations->get_undeleted_all()->result_array();
|
||||
$data['show_stock_locations'] = count($stock_locations) > 1;
|
||||
$data['transaction_time']= date($this->config->item('dateformat').' '.$this->config->item('timeformat'), strtotime($receiving_info['receiving_time']));
|
||||
$data['show_stock_locations']=$this->Stock_location->show_locations('receivings');
|
||||
$supplier_id=$this->receiving_lib->get_supplier();
|
||||
$emp_info=$this->Employee->get_info($receiving_info['employee_id']);
|
||||
$data['payment_type']=$receiving_info['payment_type'];
|
||||
$data['invoice_number']=$this->receiving_lib->get_invoice_number();
|
||||
|
||||
$data['receiving_id']='RECV '.$receiving_id;
|
||||
$data['barcode']=$this->barcode_lib->generate_receipt_barcode($data['receiving_id']);
|
||||
$data['employee']=$emp_info->first_name.' '.$emp_info->last_name;
|
||||
|
||||
if($supplier_id!=-1)
|
||||
@@ -291,20 +317,20 @@ class Receivings extends Secure_area
|
||||
$supplier_info=$this->Supplier->get_info($supplier_id);
|
||||
$data['supplier']=$supplier_info->first_name.' '.$supplier_info->last_name;
|
||||
}
|
||||
$data['receiving_id']='RECV '.$receiving_id;
|
||||
$data['print_after_sale'] = FALSE;
|
||||
$this->load->view("receivings/receipt",$data);
|
||||
$this->receiving_lib->clear_all();
|
||||
$this->_remove_duplicate_cookies();
|
||||
}
|
||||
|
||||
function _reload($data=array())
|
||||
private function _reload($data=array())
|
||||
{
|
||||
$person_info = $this->Employee->get_logged_in_employee_info();
|
||||
$data['cart']=$this->receiving_lib->get_cart();
|
||||
$data['modes']=array('receive'=>$this->lang->line('recvs_receiving'),'return'=>$this->lang->line('recvs_return'));
|
||||
$data['mode']=$this->receiving_lib->get_mode();
|
||||
|
||||
$data['stock_locations']=$this->Stock_locations->get_allowed_locations();
|
||||
|
||||
$data['stock_locations']=$this->Stock_location->get_allowed_locations('receivings');
|
||||
$show_stock_locations = count($data['stock_locations']) > 1;
|
||||
if ($show_stock_locations)
|
||||
{
|
||||
@@ -333,34 +359,37 @@ class Receivings extends Secure_area
|
||||
}
|
||||
$data['invoice_number']=$this->_substitute_invoice_number($suppl_info);
|
||||
$data['invoice_number_enabled']=$this->receiving_lib->is_invoice_number_enabled();
|
||||
$data['print_after_sale']=$this->receiving_lib->is_print_after_sale();
|
||||
$this->load->view("receivings/receiving",$data);
|
||||
$this->_remove_duplicate_cookies();
|
||||
}
|
||||
|
||||
function save($receiving_id)
|
||||
{
|
||||
$date_formatter = date_create_from_format($this->config->item('dateformat') . ' ' . $this->config->item('timeformat'), $this->input->post('date', TRUE));
|
||||
|
||||
$receiving_data = array(
|
||||
'receiving_time' => date('Y-m-d', strtotime($this->input->post('date'))),
|
||||
'supplier_id' => $this->input->post('supplier_id') ? $this->input->post('supplier_id') : null,
|
||||
'employee_id' => $this->input->post('employee_id'),
|
||||
'comment' => $this->input->post('comment'),
|
||||
'invoice_number' => $this->input->post('invoice_number')
|
||||
'receiving_time' => $date_formatter->format('Y-m-d H:i:s'),
|
||||
'supplier_id' => $this->input->post('supplier_id') ? $this->input->post('supplier_id') : null,
|
||||
'employee_id' => $this->input->post('employee_id'),
|
||||
'comment' => $this->input->post('comment'),
|
||||
'invoice_number' => $this->input->post('invoice_number') != '' ? $this->input->post('invoice_number') : null
|
||||
);
|
||||
|
||||
if ($this->Receiving->update($receiving_data, $receiving_id))
|
||||
{
|
||||
echo json_encode(array(
|
||||
'success'=>true,
|
||||
'message'=>$this->lang->line('recvs_successfully_updated'),
|
||||
'id'=>$receiving_id)
|
||||
'success'=>true,
|
||||
'message'=>$this->lang->line('recvs_successfully_updated'),
|
||||
'id'=>$receiving_id)
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
echo json_encode(array(
|
||||
'success'=>false,
|
||||
'message'=>$this->lang->line('recvs_unsuccessfully_updated'),
|
||||
'id'=>$receiving_id)
|
||||
'success'=>false,
|
||||
'message'=>$this->lang->line('recvs_unsuccessfully_updated'),
|
||||
'id'=>$receiving_id)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -378,6 +407,5 @@ class Receivings extends Secure_area
|
||||
$exists=!empty($invoice_number) && $this->Receiving->invoice_number_exists($invoice_number,$receiving_id);
|
||||
echo json_encode(array('success'=>!$exists,'message'=>$this->lang->line('recvs_invoice_number_duplicate')));
|
||||
}
|
||||
|
||||
}
|
||||
?>
|
||||
}
|
||||
?>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -4,25 +4,156 @@ class Sales extends Secure_area
|
||||
{
|
||||
function __construct()
|
||||
{
|
||||
parent::__construct('sales','items');
|
||||
parent::__construct('sales');
|
||||
$this->load->library('sale_lib');
|
||||
$this->load->library('barcode_lib');
|
||||
}
|
||||
|
||||
function index()
|
||||
{
|
||||
$this->_reload();
|
||||
}
|
||||
|
||||
function manage($only_invoices = FALSE, $only_cash = FALSE, $limit_from = 0)
|
||||
{
|
||||
$person_id = $this->session->userdata('person_id');
|
||||
|
||||
if (!$this->Employee->has_grant('reports_sales', $person_id))
|
||||
{
|
||||
redirect('no_access/sales/reports_sales');
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->Sale->create_sales_items_temp_table();
|
||||
|
||||
$data['controller_name'] = strtolower($this->uri->segment(1));
|
||||
$data['only_invoices'] = array($this->lang->line('sales_no_filter'), $this->lang->line('sales_invoice'));
|
||||
$data['search_section_state'] = $this->input->post('search_section_state');
|
||||
$lines_per_page = $this->Appconfig->get('lines_per_page');
|
||||
|
||||
$today = date($this->config->item('dateformat'));
|
||||
$start_date = $this->input->post('start_date') != NULL ? $this->input->post('start_date', TRUE) : $today;
|
||||
$start_date_formatter = date_create_from_format($this->config->item('dateformat'), $start_date);
|
||||
$end_date = $this->input->post('end_date') != NULL ? $this->input->post('end_date', TRUE) : $today;
|
||||
$end_date_formatter = date_create_from_format($this->config->item('dateformat'), $end_date);
|
||||
|
||||
$sale_type = 'all';
|
||||
$location_id = 'all';
|
||||
$is_valid_receipt = FALSE;
|
||||
$search = null;
|
||||
|
||||
$filters = array('sale_type' => $sale_type,
|
||||
'location_id' => $location_id,
|
||||
'start_date' => $start_date_formatter->format('Y-m-d'),
|
||||
'end_date' => $end_date_formatter->format('Y-m-d'),
|
||||
'only_invoices' => $only_invoices,
|
||||
'only_cash' => $only_cash,
|
||||
'is_valid_receipt' => $is_valid_receipt);
|
||||
|
||||
$sales = $this->Sale->search($search, $filters, $lines_per_page, $limit_from)->result_array();
|
||||
$payments = $this->Sale->get_payments_summary($search, $filters);
|
||||
$total_rows = $this->Sale->get_found_rows($search, $filters);
|
||||
$data['only_invoices'] = $only_invoices;
|
||||
$data['start_date'] = $start_date_formatter->format($this->config->item('dateformat'));
|
||||
$data['end_date'] = $end_date_formatter->format($this->config->item('dateformat'));
|
||||
$data['links'] = $this->_initialize_pagination($this->Sale, $lines_per_page, $limit_from, $total_rows, 'manage', $only_invoices);
|
||||
$data['manage_table'] = get_sales_manage_table($sales, $this);
|
||||
$data['payments_summary'] = get_sales_manage_payments_summary($payments, $sales, $this);
|
||||
|
||||
$this->load->view($data['controller_name'] . '/manage', $data);
|
||||
}
|
||||
|
||||
$this->_remove_duplicate_cookies();
|
||||
}
|
||||
|
||||
function get_row()
|
||||
{
|
||||
$this->Sale->create_sales_items_temp_table();
|
||||
|
||||
$sale_id = $this->input->post('row_id');
|
||||
$sale_info = $this->Sale->get_info($sale_id)->result_array();
|
||||
$data_row = get_sales_manage_sale_data_row($sale_info[0], $this);
|
||||
|
||||
echo $data_row;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Get the width for the add/edit form.
|
||||
* @return number The form width
|
||||
*/
|
||||
function get_form_width()
|
||||
{
|
||||
return 400;
|
||||
}
|
||||
|
||||
function search()
|
||||
{
|
||||
$this->Sale->create_sales_items_temp_table();
|
||||
|
||||
$only_invoices = $this->input->post('only_invoices', TRUE);
|
||||
$only_cash = $this->input->post('only_cash', TRUE);
|
||||
$lines_per_page = $this->Appconfig->get('lines_per_page');
|
||||
$limit_from = $this->input->post('limit_from', TRUE);
|
||||
$search = $this->input->post('search', TRUE);
|
||||
|
||||
$today = date($this->config->item('dateformat'));
|
||||
$start_date = $this->input->post('start_date') != NULL ? $this->input->post('start_date', TRUE) : $today;
|
||||
$start_date_formatter = date_create_from_format($this->config->item('dateformat'), $start_date);
|
||||
$end_date = $this->input->post('end_date') != NULL ? $this->input->post('end_date', TRUE) : $today;
|
||||
$end_date_formatter = date_create_from_format($this->config->item('dateformat'), $end_date);
|
||||
|
||||
$is_valid_receipt = isset($search) ? $this->sale_lib->is_valid_receipt($search) : FALSE;
|
||||
|
||||
$sale_type = 'all';
|
||||
$location_id = 'all';
|
||||
|
||||
$filters = array('sale_type' => $sale_type,
|
||||
'location_id' => $location_id,
|
||||
'start_date' => $start_date_formatter->format('Y-m-d'),
|
||||
'end_date' => $end_date_formatter->format('Y-m-d'),
|
||||
'only_invoices' => $only_invoices,
|
||||
'only_cash' => $only_cash,
|
||||
'is_valid_receipt' => $is_valid_receipt);
|
||||
|
||||
$sales = $this->Sale->search($search, $filters, $lines_per_page, $limit_from)->result_array();
|
||||
$payments = $this->Sale->get_payments_summary($search, $filters);
|
||||
$total_rows = $this->Sale->get_found_rows($search, $filters);
|
||||
$links = $this->_initialize_pagination($this->Sale, $lines_per_page, $limit_from, $total_rows, 'search', $only_invoices);
|
||||
$sale_rows = get_sales_manage_table_data_rows($sales, $this);
|
||||
$payment_summary = get_sales_manage_payments_summary($payments, $sales, $this);
|
||||
$this->_remove_duplicate_cookies();
|
||||
|
||||
echo json_encode(array('total_rows' => $total_rows, 'rows' => $sale_rows, 'pagination' => $links, 'payment_summary' => $payment_summary));
|
||||
}
|
||||
|
||||
function item_search()
|
||||
{
|
||||
$suggestions = $this->Item->get_item_search_suggestions($this->input->post('q'),$this->input->post('limit'));
|
||||
$suggestions = array();
|
||||
|
||||
if ($this->sale_lib->get_mode() == 'return')
|
||||
{
|
||||
$this->sale_lib->is_valid_receipt($this->input->post('q')) && $suggestions[] = $this->input->post('q');
|
||||
}
|
||||
$suggestions = array_merge($suggestions, $this->Item->get_item_search_suggestions($this->input->post('q'),$this->input->post('limit')));
|
||||
$suggestions = array_merge($suggestions, $this->Item_kit->get_item_kit_search_suggestions($this->input->post('q'),$this->input->post('limit')));
|
||||
echo implode("\n",$suggestions);
|
||||
|
||||
echo implode("\n", $suggestions);
|
||||
}
|
||||
|
||||
function customer_search()
|
||||
{
|
||||
$suggestions = $this->Customer->get_customer_search_suggestions($this->input->post('q'),$this->input->post('limit'));
|
||||
|
||||
echo implode("\n",$suggestions);
|
||||
}
|
||||
|
||||
function suggest()
|
||||
{
|
||||
$search = $this->input->post('q', TRUE);
|
||||
$limit = $this->input->post('limit', TRUE);
|
||||
$suggestions = $this->Sale->get_search_suggestions($search, $limit);
|
||||
|
||||
echo implode("\n",$suggestions);
|
||||
}
|
||||
|
||||
@@ -36,13 +167,12 @@ class Sales extends Secure_area
|
||||
function change_mode()
|
||||
{
|
||||
$stock_location = $this->input->post("stock_location");
|
||||
if (!$stock_location || $stock_location == $this->sale_lib->get_sale_location())
|
||||
if (!$stock_location || $stock_location == $this->sale_lib->get_sale_location())
|
||||
{
|
||||
$this->sale_lib->clear_all();
|
||||
$mode = $this->input->post("mode");
|
||||
$this->sale_lib->set_mode($mode);
|
||||
}
|
||||
else
|
||||
else if ($this->Stock_location->is_allowed_location($stock_location, 'sales'))
|
||||
{
|
||||
$this->sale_lib->set_sale_location($stock_location);
|
||||
}
|
||||
@@ -51,7 +181,7 @@ class Sales extends Secure_area
|
||||
|
||||
function set_comment()
|
||||
{
|
||||
$this->sale_lib->set_comment($this->input->post('comment'));
|
||||
$this->sale_lib->set_comment($this->input->post('comment'));
|
||||
}
|
||||
|
||||
function set_invoice_number()
|
||||
@@ -64,25 +194,35 @@ class Sales extends Secure_area
|
||||
$this->sale_lib->set_invoice_number_enabled($this->input->post('sales_invoice_number_enabled'));
|
||||
}
|
||||
|
||||
function set_print_after_sale()
|
||||
{
|
||||
$this->sale_lib->set_print_after_sale($this->input->post('sales_print_after_sale'));
|
||||
}
|
||||
|
||||
function set_email_receipt()
|
||||
{
|
||||
$this->sale_lib->set_email_receipt($this->input->post('email_receipt'));
|
||||
$this->sale_lib->set_email_receipt($this->input->post('email_receipt'));
|
||||
}
|
||||
|
||||
//Alain Multiple Payments
|
||||
// Multiple Payments
|
||||
function add_payment()
|
||||
{
|
||||
$data = array();
|
||||
$this->form_validation->set_rules( 'amount_tendered', 'lang:sales_amount_tendered', 'numeric' );
|
||||
$this->form_validation->set_rules( 'amount_tendered', 'lang:sales_amount_tendered', 'trim|required|numeric' );
|
||||
|
||||
if ( $this->form_validation->run() == FALSE )
|
||||
{
|
||||
if ( $this->input->post( 'payment_type' ) == $this->lang->line( 'sales_gift_card' ) )
|
||||
{
|
||||
$data['error']=$this->lang->line('sales_must_enter_numeric_giftcard');
|
||||
}
|
||||
else
|
||||
{
|
||||
$data['error']=$this->lang->line('sales_must_enter_numeric');
|
||||
}
|
||||
|
||||
$this->_reload( $data );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -96,14 +236,14 @@ class Sales extends Secure_area
|
||||
|
||||
if ( $cur_giftcard_value <= 0 )
|
||||
{
|
||||
$data['error'] = 'Giftcard balance is ' . to_currency( $this->Giftcard->get_giftcard_value( $this->input->post( 'amount_tendered' ) ) ) . ' !';
|
||||
$data['error'] = $this->lang->line('giftcards_remaining_balance', $this->input->post( 'amount_tendered' ), to_currency( $this->Giftcard->get_giftcard_value( $this->input->post( 'amount_tendered' ))));
|
||||
$this->_reload( $data );
|
||||
return;
|
||||
}
|
||||
|
||||
$new_giftcard_value = $this->Giftcard->get_giftcard_value( $this->input->post( 'amount_tendered' ) ) - $this->sale_lib->get_amount_due( );
|
||||
$new_giftcard_value = ( $new_giftcard_value >= 0 ) ? $new_giftcard_value : 0;
|
||||
$data['warning'] = 'Giftcard ' . $this->input->post( 'amount_tendered' ) . ' balance is ' . to_currency( $new_giftcard_value ) . ' !';
|
||||
$this->sale_lib->set_giftcard_remainder($new_giftcard_value);
|
||||
$data['warning'] = $this->lang->line('giftcards_remaining_balance', $this->input->post( 'amount_tendered' ), to_currency( $new_giftcard_value, TRUE ));
|
||||
$payment_amount = min( $this->sale_lib->get_amount_due( ), $this->Giftcard->get_giftcard_value( $this->input->post( 'amount_tendered' ) ) );
|
||||
}
|
||||
else
|
||||
@@ -119,7 +259,7 @@ class Sales extends Secure_area
|
||||
$this->_reload($data);
|
||||
}
|
||||
|
||||
//Alain Multiple Payments
|
||||
// Multiple Payments
|
||||
function delete_payment( $payment_id )
|
||||
{
|
||||
$this->sale_lib->delete_payment( $payment_id );
|
||||
@@ -138,18 +278,11 @@ class Sales extends Secure_area
|
||||
{
|
||||
$this->sale_lib->return_entire_sale($item_id_or_number_or_item_kit_or_receipt);
|
||||
}
|
||||
elseif($this->Sale_suspended->invoice_number_exists($item_id_or_number_or_item_kit_or_receipt))
|
||||
{
|
||||
$this->sale_lib->clear_all();
|
||||
$sale_id=$this->Sale_suspended->get_sale_by_invoice_number($item_id_or_number_or_item_kit_or_receipt)->row()->sale_id;
|
||||
$this->sale_lib->copy_entire_suspended_sale($sale_id);
|
||||
$this->Sale_suspended->delete($sale_id);
|
||||
}
|
||||
elseif($this->sale_lib->is_valid_item_kit($item_id_or_number_or_item_kit_or_receipt))
|
||||
else if($this->sale_lib->is_valid_item_kit($item_id_or_number_or_item_kit_or_receipt))
|
||||
{
|
||||
$this->sale_lib->add_item_kit($item_id_or_number_or_item_kit_or_receipt,$item_location);
|
||||
}
|
||||
elseif(!$this->sale_lib->add_item($item_id_or_number_or_item_kit_or_receipt,$quantity,$item_location))
|
||||
else if(!$this->sale_lib->add_item($item_id_or_number_or_item_kit_or_receipt,$quantity,$item_location,$this->config->item('default_sales_discount')))
|
||||
{
|
||||
$data['error']=$this->lang->line('sales_unable_to_add_item');
|
||||
}
|
||||
@@ -163,10 +296,11 @@ class Sales extends Secure_area
|
||||
|
||||
function edit_item($line)
|
||||
{
|
||||
$data= array();
|
||||
$data = array();
|
||||
|
||||
$this->form_validation->set_rules('price', 'lang:items_price', 'required|numeric');
|
||||
$this->form_validation->set_rules('quantity', 'lang:items_quantity', 'required|numeric');
|
||||
$this->form_validation->set_rules('discount', 'lang:items_discount', 'required|numeric');
|
||||
|
||||
$description = $this->input->post("description");
|
||||
$serialnumber = $this->input->post("serialnumber");
|
||||
@@ -175,14 +309,13 @@ class Sales extends Secure_area
|
||||
$discount = $this->input->post("discount");
|
||||
$item_location = $this->input->post("location");
|
||||
|
||||
|
||||
if ($this->form_validation->run() != FALSE)
|
||||
{
|
||||
$this->sale_lib->edit_item($line,$description,$serialnumber,$quantity,$discount,$price);
|
||||
$this->sale_lib->edit_item($line, $description, $serialnumber, $quantity, $discount, $price);
|
||||
}
|
||||
else
|
||||
{
|
||||
$data['error']=$this->lang->line('sales_error_editing_item');
|
||||
$data['error'] = $this->lang->line('sales_error_editing_item');
|
||||
}
|
||||
|
||||
if($this->sale_lib->out_of_stock($this->sale_lib->get_item_id($line),$item_location))
|
||||
@@ -190,7 +323,6 @@ class Sales extends Secure_area
|
||||
$data['warning'] = $this->lang->line('sales_quantity_less_than_zero');
|
||||
}
|
||||
|
||||
|
||||
$this->_reload($data);
|
||||
}
|
||||
|
||||
@@ -202,6 +334,7 @@ class Sales extends Secure_area
|
||||
|
||||
function remove_customer()
|
||||
{
|
||||
$this->sale_lib->clear_giftcard_remainder();
|
||||
$this->sale_lib->clear_invoice_number();
|
||||
$this->sale_lib->remove_customer();
|
||||
$this->_reload();
|
||||
@@ -209,44 +342,71 @@ class Sales extends Secure_area
|
||||
|
||||
function complete()
|
||||
{
|
||||
$data['cart']=$this->sale_lib->get_cart();
|
||||
$data['subtotal']=$this->sale_lib->get_subtotal();
|
||||
$data['taxes']=$this->sale_lib->get_taxes();
|
||||
$data['total']=$this->sale_lib->get_total();
|
||||
$data['receipt_title']=$this->lang->line('sales_receipt');
|
||||
$data['transaction_time']= date('m/d/Y h:i:s a');
|
||||
$stock_locations=$this->Stock_locations->get_undeleted_all()->result_array();
|
||||
$data['show_stock_locations']=count($stock_locations) > 1;
|
||||
$customer_id=$this->sale_lib->get_customer();
|
||||
$employee_id=$this->Employee->get_logged_in_employee_info()->person_id;
|
||||
$comment=$this->sale_lib->get_comment();
|
||||
$data['cart'] = $this->sale_lib->get_cart();
|
||||
$data['subtotal'] = $this->sale_lib->get_subtotal();
|
||||
$data['discounted_subtotal'] = $this->sale_lib->get_subtotal(TRUE);
|
||||
$data['tax_exclusive_subtotal'] = $this->sale_lib->get_subtotal(TRUE, TRUE);
|
||||
$data['taxes'] = $this->sale_lib->get_taxes();
|
||||
$data['total'] = $this->sale_lib->get_total();
|
||||
$data['discount'] = $this->sale_lib->get_discount();
|
||||
$data['receipt_title'] = $this->lang->line('sales_receipt');
|
||||
$data['transaction_time'] = date($this->config->item('dateformat').' '.$this->config->item('timeformat'));
|
||||
$data['transaction_date'] = date($this->config->item('dateformat'));
|
||||
$data['show_stock_locations'] = $this->Stock_location->show_locations('sales');
|
||||
$customer_id = $this->sale_lib->get_customer();
|
||||
$employee_id = $this->Employee->get_logged_in_employee_info()->person_id;
|
||||
$data['comments'] = $this->sale_lib->get_comment();
|
||||
$emp_info=$this->Employee->get_info($employee_id);
|
||||
$data['payments']=$this->sale_lib->get_payments();
|
||||
$data['amount_change']=to_currency($this->sale_lib->get_amount_due() * -1);
|
||||
$data['employee']=$emp_info->first_name.' '.$emp_info->last_name;
|
||||
$cust_info='';
|
||||
$data['payments'] = $this->sale_lib->get_payments();
|
||||
$data['amount_change'] = $this->sale_lib->get_amount_due() * -1;
|
||||
$data['amount_due'] = $this->sale_lib->get_amount_due();
|
||||
$data['employee'] = $emp_info->first_name.' '.$emp_info->last_name;
|
||||
$data['company_info'] = implode("\n", array(
|
||||
$this->config->item('address'),
|
||||
$this->config->item('phone'),
|
||||
$this->config->item('account_number')
|
||||
));
|
||||
$cust_info = '';
|
||||
if($customer_id!=-1)
|
||||
{
|
||||
$cust_info=$this->Customer->get_info($customer_id);
|
||||
$data['customer']=$cust_info->first_name.' '.$cust_info->last_name;
|
||||
$cust_info = $this->Customer->get_info($customer_id);
|
||||
if (isset($cust_info->company_name))
|
||||
{
|
||||
$data['customer'] = $cust_info->company_name;
|
||||
}
|
||||
else
|
||||
{
|
||||
$data['customer'] = $cust_info->first_name.' '.$cust_info->last_name;
|
||||
}
|
||||
$data['customer_address'] = $cust_info->address_1;
|
||||
$data['customer_location'] = $cust_info->zip . ' ' . $cust_info->city;
|
||||
$data['account_number'] = $cust_info->account_number;
|
||||
$data['customer_info'] = implode("\n", array(
|
||||
$data['customer'],
|
||||
$data['customer_address'],
|
||||
$data['customer_location'],
|
||||
$data['account_number']
|
||||
));
|
||||
}
|
||||
$invoice_number=$this->_substitute_invoice_number($cust_info);
|
||||
$invoice_number = $this->_substitute_invoice_number($cust_info);
|
||||
if ($this->sale_lib->is_invoice_number_enabled() && $this->Sale->invoice_number_exists($invoice_number))
|
||||
{
|
||||
$data['error']=$this->lang->line('sales_invoice_number_duplicate');
|
||||
$data['error'] = $this->lang->line('sales_invoice_number_duplicate');
|
||||
$this->_reload($data);
|
||||
}
|
||||
else
|
||||
{
|
||||
$invoice_number = $this->sale_lib->is_invoice_number_enabled() ? $invoice_number : NULL;
|
||||
$data['invoice_number']=$invoice_number;
|
||||
$data['sale_id']='POS '.$this->Sale->save($data['cart'], $customer_id,$employee_id,$comment,$invoice_number,$data['payments']);
|
||||
$data['invoice_number'] = $invoice_number;
|
||||
$data['sale_id'] = 'POS '.$this->Sale->save($data['cart'], $customer_id, $employee_id, $data['comments'], $invoice_number, $data['payments']);
|
||||
if ($data['sale_id'] == 'POS -1')
|
||||
{
|
||||
$data['error_message'] = $this->lang->line('sales_transaction_failed');
|
||||
}
|
||||
else
|
||||
{
|
||||
$data['barcode'] = $this->barcode_lib->generate_receipt_barcode($data['sale_id']);
|
||||
// if we want to email. .. just attach the pdf in there?
|
||||
if ($this->sale_lib->get_email_receipt() && !empty($cust_info->email))
|
||||
{
|
||||
$this->load->library('email');
|
||||
@@ -256,91 +416,232 @@ class Sales extends Secure_area
|
||||
$this->email->to($cust_info->email);
|
||||
|
||||
$this->email->subject($this->lang->line('sales_receipt'));
|
||||
$this->email->message($this->load->view("sales/receipt_email",$data, true));
|
||||
if ($this->config->item('use_invoice_template') && $this->sale_lib->is_invoice_number_enabled())
|
||||
{
|
||||
$data['image_prefix']="";
|
||||
$filename = $this->_invoice_email_pdf($data);
|
||||
$this->email->attach($filename);
|
||||
$text = $this->config->item('invoice_email_message');
|
||||
$text = str_replace('$INV', $invoice_number, $text);
|
||||
$text = str_replace('$CO', $data['sale_id'], $text);
|
||||
$text = $this->_substitute_customer($text, $cust_info);
|
||||
$this->email->message($text);
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->email->message($this->load->view("sales/receipt_email",$data, true));
|
||||
}
|
||||
$this->email->send();
|
||||
}
|
||||
}
|
||||
$this->load->view("sales/receipt",$data);
|
||||
$data['cur_giftcard_value'] = $this->sale_lib->get_giftcard_remainder();
|
||||
$data['print_after_sale'] = $this->sale_lib->is_print_after_sale();
|
||||
if ($this->sale_lib->is_invoice_number_enabled() && $this->config->item('use_invoice_template'))
|
||||
{
|
||||
$this->load->view("sales/invoice",$data);
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->load->view("sales/receipt",$data);
|
||||
}
|
||||
$this->sale_lib->clear_all();
|
||||
}
|
||||
|
||||
$this->_remove_duplicate_cookies();
|
||||
}
|
||||
|
||||
function _substitute_invoice_number($customer_info='')
|
||||
private function _invoice_email_pdf($data)
|
||||
{
|
||||
$invoice_number=$this->sale_lib->get_invoice_number();
|
||||
if (empty($invoice_number))
|
||||
{
|
||||
$invoice_number=$this->config->config['sales_invoice_format'];
|
||||
}
|
||||
$invoice_count=$this->Sale->get_invoice_count();
|
||||
$invoice_number=str_replace('$CO',$invoice_count,$invoice_number);
|
||||
$invoice_count=$this->Sale_suspended->get_invoice_count();
|
||||
$invoice_number=str_replace('$SCO',$invoice_count,$invoice_number);
|
||||
$invoice_number=strftime($invoice_number);
|
||||
$data['image_prefix'] = "";
|
||||
$html = $this->load->view('sales/invoice_email', $data, true);
|
||||
// load pdf helper
|
||||
$this->load->helper(array('dompdf', 'file'));
|
||||
$file_content = pdf_create($html, '', false);
|
||||
$filename = sys_get_temp_dir() . '/'. $this->lang->line('sales_invoice') .'-' . str_replace('/', '-' , $data["invoice_number"]) . '.pdf';
|
||||
write_file($filename, $file_content);
|
||||
|
||||
return $filename;
|
||||
}
|
||||
|
||||
$customer_id=$this->sale_lib->get_customer();
|
||||
if($customer_id!=-1)
|
||||
function invoice_email($sale_id)
|
||||
{
|
||||
$sale_data = $this->_load_sale_data($sale_id);
|
||||
$sale_data['image_prefix'] = base_url();
|
||||
$this->load->view('sales/invoice_email', $sale_data);
|
||||
$this->sale_lib->clear_all();
|
||||
$this->_remove_duplicate_cookies();
|
||||
}
|
||||
|
||||
function send_invoice($sale_id)
|
||||
{
|
||||
$sale_data = $this->_load_sale_data($sale_id);
|
||||
$text = $this->config->item('invoice_email_message');
|
||||
$text = str_replace('$INV', $sale_data['invoice_number'], $text);
|
||||
$text = str_replace('$CO', 'POS ' . $sale_data['sale_id'], $text);
|
||||
$text = $this->_substitute_customer($text,(object) $sale_data);
|
||||
$result = FALSE;
|
||||
$message = $this->lang->line('sales_invoice_no_email');
|
||||
if (isset($sale_data["customer_email"]) && !empty( $sale_data["customer_email"])) {
|
||||
$this->load->library('email');
|
||||
$this->email->from($this->config->item('email'), $this->config->item('company'));
|
||||
$this->email->to($sale_data['customer_email']);
|
||||
$this->email->subject($this->lang->line('sales_invoice') . ' ' . $sale_data['invoice_number']);
|
||||
$this->email->message($text);
|
||||
$filename = $this->_invoice_email_pdf($sale_data);
|
||||
$this->email->attach($filename);
|
||||
$result = $this->email->send();
|
||||
$message = $this->lang->line($result ? 'sales_invoice_sent' : 'sales_invoice_unsent') . ' ' . $sale_data["customer_email"];
|
||||
}
|
||||
echo json_encode(array(
|
||||
'success'=>$result,
|
||||
'message'=>$message,
|
||||
'id'=>$sale_id)
|
||||
);
|
||||
$this->sale_lib->clear_all();
|
||||
$this->_remove_duplicate_cookies();
|
||||
}
|
||||
|
||||
private function _substitute_variable($text, $variable, $object, $function)
|
||||
{
|
||||
// don't query if this variable isn't used
|
||||
if (strstr($text, $variable))
|
||||
{
|
||||
$invoice_number=str_replace('$CU',$customer_info->first_name . ' ' . $customer_info->last_name,$invoice_number);
|
||||
$words = preg_split("/\s+/", $customer_info->first_name . ' ' . $customer_info->last_name);
|
||||
$value = call_user_func(array($object, $function));
|
||||
$text = str_replace($variable, $value, $text);
|
||||
}
|
||||
|
||||
return $text;
|
||||
}
|
||||
|
||||
private function _substitute_customer($text, $cust_info)
|
||||
{
|
||||
// substitute customer info
|
||||
$customer_id=$this->sale_lib->get_customer();
|
||||
if($customer_id!=-1 && $cust_info!='')
|
||||
{
|
||||
$text=str_replace('$CU',$cust_info->first_name . ' ' . $cust_info->last_name,$text);
|
||||
$words = preg_split("/\s+/", trim($cust_info->first_name . ' ' . $cust_info->last_name));
|
||||
$acronym = "";
|
||||
foreach ($words as $w) {
|
||||
$acronym .= $w[0];
|
||||
}
|
||||
$invoice_number=str_replace('$CI',$acronym,$invoice_number);
|
||||
$text=str_replace('$CI',$acronym,$text);
|
||||
}
|
||||
$this->sale_lib->set_invoice_number($invoice_number);
|
||||
return $invoice_number;
|
||||
|
||||
return $text;
|
||||
}
|
||||
|
||||
private function _substitute_variables($text, $cust_info)
|
||||
{
|
||||
$text=$this->_substitute_variable($text, '$YCO', $this->Sale, 'get_invoice_number_for_year');
|
||||
$text=$this->_substitute_variable($text, '$CO', $this->Sale , 'get_invoice_count');
|
||||
$text=$this->_substitute_variable($text, '$SCO', $this->Sale_suspended, 'get_invoice_count');
|
||||
$text=strftime($text);
|
||||
$text=$this->_substitute_customer($text, $cust_info);
|
||||
|
||||
return $text;
|
||||
}
|
||||
|
||||
private function _substitute_invoice_number($cust_info)
|
||||
{
|
||||
$invoice_number = $this->config->config['sales_invoice_format'];
|
||||
$invoice_number = $this->_substitute_variables($invoice_number, $cust_info);
|
||||
$this->sale_lib->set_invoice_number($invoice_number, TRUE);
|
||||
return $this->sale_lib->get_invoice_number();
|
||||
}
|
||||
|
||||
private function _load_sale_data($sale_id)
|
||||
{
|
||||
$this->Sale->create_sales_items_temp_table();
|
||||
|
||||
$this->sale_lib->clear_all();
|
||||
$sale_info = $this->Sale->get_info($sale_id)->row_array();
|
||||
$this->sale_lib->copy_entire_sale($sale_id);
|
||||
$data['cart'] = $this->sale_lib->get_cart();
|
||||
$data['payments'] = $this->sale_lib->get_payments();
|
||||
$data['subtotal'] = $this->sale_lib->get_subtotal();
|
||||
$data['discounted_subtotal'] = $this->sale_lib->get_subtotal(TRUE);
|
||||
$data['tax_exclusive_subtotal'] = $this->sale_lib->get_subtotal(TRUE, TRUE);
|
||||
$data['taxes'] = $this->sale_lib->get_taxes();
|
||||
$data['total'] = $this->sale_lib->get_total();
|
||||
$data['discount'] = $this->sale_lib->get_discount();
|
||||
$data['receipt_title'] = $this->lang->line('sales_receipt');
|
||||
$data['transaction_time'] = date($this->config->item('dateformat').' '.$this->config->item('timeformat'), strtotime($sale_info['sale_time']));
|
||||
$data['transaction_date'] = date($this->config->item('dateformat'), strtotime($sale_info['sale_time']));
|
||||
$data['show_stock_locations'] = $this->Stock_location->show_locations('sales');
|
||||
$customer_id = $this->sale_lib->get_customer();
|
||||
$employee_id = $this->Employee->get_logged_in_employee_info()->person_id;
|
||||
$emp_info = $this->Employee->get_info($employee_id);
|
||||
$data['amount_change'] = $this->sale_lib->get_amount_due() * -1;
|
||||
$data['amount_due'] = $this->sale_lib->get_amount_due();
|
||||
$data['employee'] = $emp_info->first_name.' '.$emp_info->last_name;
|
||||
|
||||
if($customer_id!=-1)
|
||||
{
|
||||
$cust_info = $this->Customer->get_info($customer_id);
|
||||
if (isset($cust_info->company_name))
|
||||
{
|
||||
$data['customer'] = $cust_info->company_name;
|
||||
}
|
||||
else
|
||||
{
|
||||
$data['customer'] = $cust_info->first_name.' '.$cust_info->last_name;
|
||||
}
|
||||
$data['first_name'] = $cust_info->first_name;
|
||||
$data['last_name'] = $cust_info->last_name;
|
||||
$data['customer_address'] = $cust_info->address_1;
|
||||
$data['customer_location'] = $cust_info->zip . ' ' . $cust_info->city;
|
||||
$data['customer_email'] = $cust_info->email;
|
||||
$data['account_number'] = $cust_info->account_number;
|
||||
$data['customer_info'] = implode("\n", array(
|
||||
$data['customer'],
|
||||
$data['customer_address'],
|
||||
$data['customer_location'],
|
||||
$data['account_number']
|
||||
));
|
||||
}
|
||||
$data['sale_id'] = 'POS '.$sale_id;
|
||||
$data['comments'] = $sale_info['comment'];
|
||||
$data['invoice_number'] = $sale_info['invoice_number'];
|
||||
$data['company_info'] = implode("\n", array(
|
||||
$this->config->item('address'),
|
||||
$this->config->item('phone'),
|
||||
$this->config->item('account_number')
|
||||
));
|
||||
$data['barcode'] = $this->barcode_lib->generate_receipt_barcode($data['sale_id']);
|
||||
$data['print_after_sale'] = FALSE;
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
function receipt($sale_id)
|
||||
{
|
||||
$sale_info = $this->Sale->get_info($sale_id)->row_array();
|
||||
$this->sale_lib->copy_entire_sale($sale_id);
|
||||
$stock_locations = $this->Stock_locations->get_undeleted_all()->result_array();
|
||||
$data['show_stock_locations'] = count($stock_locations) > 1;
|
||||
$data['cart']=$this->sale_lib->get_cart();
|
||||
$data['payments']=$this->sale_lib->get_payments();
|
||||
$data['subtotal']=$this->sale_lib->get_subtotal();
|
||||
$data['taxes']=$this->sale_lib->get_taxes();
|
||||
$data['total']=$this->sale_lib->get_total();
|
||||
$data['receipt_title']=$this->lang->line('sales_receipt');
|
||||
$data['transaction_time']= date('m/d/Y h:i:s a', strtotime($sale_info['sale_time']));
|
||||
$customer_id=$this->sale_lib->get_customer();
|
||||
$emp_info=$this->Employee->get_info($sale_info['employee_id']);
|
||||
$data['payment_type']=$sale_info['payment_type'];
|
||||
$data['invoice_number']=$sale_info['invoice_number'];
|
||||
$data['amount_change']=to_currency($this->sale_lib->get_amount_due() * -1);
|
||||
$data['employee']=$emp_info->first_name.' '.$emp_info->last_name;
|
||||
|
||||
if($customer_id!=-1)
|
||||
{
|
||||
$cust_info=$this->Customer->get_info($customer_id);
|
||||
$data['customer']=$cust_info->first_name.' '.$cust_info->last_name;
|
||||
}
|
||||
$data['sale_id']='POS '.$sale_id;
|
||||
$data = $this->_load_sale_data($sale_id);
|
||||
$this->load->view("sales/receipt",$data);
|
||||
$this->sale_lib->clear_all();
|
||||
$this->_remove_duplicate_cookies();
|
||||
}
|
||||
|
||||
function invoice($sale_id, $sale_info='')
|
||||
{
|
||||
if ($sale_info == '') {
|
||||
$sale_info = $this->_load_sale_data($sale_id);
|
||||
}
|
||||
$this->load->view("sales/invoice",$sale_info);
|
||||
$this->sale_lib->clear_all();
|
||||
$this->_remove_duplicate_cookies();
|
||||
}
|
||||
|
||||
function edit($sale_id)
|
||||
{
|
||||
$data = array();
|
||||
|
||||
$data['customers'] = array('' => 'No Customer');
|
||||
foreach ($this->Customer->get_all()->result() as $customer)
|
||||
{
|
||||
$data['customers'][$customer->person_id] = $customer->first_name . ' '. $customer->last_name;
|
||||
}
|
||||
|
||||
$data['employees'] = array();
|
||||
foreach ($this->Employee->get_all()->result() as $employee)
|
||||
{
|
||||
$data['employees'][$employee->person_id] = $employee->first_name . ' '. $employee->last_name;
|
||||
}
|
||||
$this->Sale->create_sales_items_temp_table();
|
||||
|
||||
$sale_info = $this->Sale->get_info($sale_id)->row_array();
|
||||
$person_name = $sale_info['first_name'] . " " . $sale_info['last_name'];
|
||||
@@ -350,7 +651,8 @@ class Sales extends Secure_area
|
||||
$this->load->view('sales/form', $data);
|
||||
}
|
||||
|
||||
function delete($sale_id = -1, $update_inventory=TRUE) {
|
||||
function delete($sale_id = -1, $update_inventory=TRUE)
|
||||
{
|
||||
$employee_id=$this->Employee->get_logged_in_employee_info()->person_id;
|
||||
$sale_ids= $sale_id == -1 ? $this->input->post('ids') : array($sale_id);
|
||||
|
||||
@@ -367,8 +669,10 @@ class Sales extends Secure_area
|
||||
|
||||
function save($sale_id)
|
||||
{
|
||||
$start_date_formatter = date_create_from_format($this->config->item('dateformat') . ' ' . $this->config->item('timeformat'), $this->input->post('date', TRUE));
|
||||
|
||||
$sale_data = array(
|
||||
'sale_time' => date('Y-m-d', strtotime($this->input->post('date'))),
|
||||
'sale_time' => $start_date_formatter->format('Y-m-d H:i:s'),
|
||||
'customer_id' => $this->input->post('customer_id') ? $this->input->post('customer_id') : NULL,
|
||||
'employee_id' => $this->input->post('employee_id'),
|
||||
'comment' => $this->input->post('comment'),
|
||||
@@ -393,7 +697,7 @@ class Sales extends Secure_area
|
||||
}
|
||||
}
|
||||
|
||||
function _payments_cover_total()
|
||||
private function _payments_cover_total()
|
||||
{
|
||||
$total_payments = 0;
|
||||
|
||||
@@ -412,26 +716,28 @@ class Sales extends Secure_area
|
||||
return true;
|
||||
}
|
||||
|
||||
function _reload($data=array())
|
||||
private function _reload($data=array())
|
||||
{
|
||||
$person_info = $this->Employee->get_logged_in_employee_info();
|
||||
$data['cart']=$this->sale_lib->get_cart();
|
||||
$data['modes']=array('sale'=>$this->lang->line('sales_sale'),'return'=>$this->lang->line('sales_return'));
|
||||
$data['mode']=$this->sale_lib->get_mode();
|
||||
|
||||
$data['stock_locations']=$this->Stock_locations->get_allowed_locations();
|
||||
$data['stock_location']=$this->sale_lib->get_sale_location();
|
||||
$data['cart'] = $this->sale_lib->get_cart();
|
||||
$data['modes'] = array('sale'=>$this->lang->line('sales_sale'),'return'=>$this->lang->line('sales_return'));
|
||||
$data['mode'] = $this->sale_lib->get_mode();
|
||||
|
||||
$data['stock_locations'] = $this->Stock_location->get_allowed_locations('sales');
|
||||
$data['stock_location'] = $this->sale_lib->get_sale_location();
|
||||
|
||||
$data['subtotal']=$this->sale_lib->get_subtotal();
|
||||
$data['taxes']=$this->sale_lib->get_taxes();
|
||||
$data['total']=$this->sale_lib->get_total();
|
||||
$data['items_module_allowed']=$this->Employee->has_grant('items', $person_info->person_id);
|
||||
$data['comment']=$this->sale_lib->get_comment();
|
||||
$data['email_receipt']=$this->sale_lib->get_email_receipt();
|
||||
$data['payments_total']=$this->sale_lib->get_payments_total();
|
||||
$data['amount_due']=$this->sale_lib->get_amount_due();
|
||||
$data['payments']=$this->sale_lib->get_payments();
|
||||
$data['payment_options']=array(
|
||||
$data['subtotal'] = $this->sale_lib->get_subtotal(TRUE);
|
||||
$data['tax_exclusive_subtotal'] = $this->sale_lib->get_subtotal(TRUE, TRUE);
|
||||
$data['taxes'] = $this->sale_lib->get_taxes();
|
||||
$data['discount'] = $this->sale_lib->get_discount();
|
||||
$data['total'] = $this->sale_lib->get_total();
|
||||
$data['items_module_allowed'] = $this->Employee->has_grant('items', $person_info->person_id);
|
||||
$data['comment'] = $this->sale_lib->get_comment();
|
||||
$data['email_receipt'] = $this->sale_lib->get_email_receipt();
|
||||
$data['payments_total'] = $this->sale_lib->get_payments_total();
|
||||
$data['amount_due'] = $this->sale_lib->get_amount_due();
|
||||
$data['payments'] = $this->sale_lib->get_payments();
|
||||
$data['payment_options'] = array(
|
||||
$this->lang->line('sales_cash') => $this->lang->line('sales_cash'),
|
||||
$this->lang->line('sales_check') => $this->lang->line('sales_check'),
|
||||
$this->lang->line('sales_giftcard') => $this->lang->line('sales_giftcard'),
|
||||
@@ -439,18 +745,21 @@ class Sales extends Secure_area
|
||||
$this->lang->line('sales_credit') => $this->lang->line('sales_credit')
|
||||
);
|
||||
|
||||
$customer_id=$this->sale_lib->get_customer();
|
||||
$cust_info='';
|
||||
$customer_id = $this->sale_lib->get_customer();
|
||||
$cust_info = '';
|
||||
if($customer_id!=-1)
|
||||
{
|
||||
$cust_info=$this->Customer->get_info($customer_id);
|
||||
$data['customer']=$cust_info->first_name.' '.$cust_info->last_name;
|
||||
$data['customer_email']=$cust_info->email;
|
||||
$cust_info = $this->Customer->get_info($customer_id);
|
||||
$data['customer'] = $cust_info->first_name.' '.$cust_info->last_name;
|
||||
$data['customer_email'] = $cust_info->email;
|
||||
}
|
||||
$data['invoice_number']=$this->_substitute_invoice_number($cust_info);
|
||||
$data['invoice_number_enabled']=$this->sale_lib->is_invoice_number_enabled();
|
||||
$data['payments_cover_total']=$this->_payments_cover_total();
|
||||
$data['invoice_number'] = $this->_substitute_invoice_number($cust_info);
|
||||
$data['invoice_number_enabled'] = $this->sale_lib->is_invoice_number_enabled();
|
||||
$data['print_after_sale'] = $this->sale_lib->is_print_after_sale();
|
||||
$data['payments_cover_total'] = $this->_payments_cover_total();
|
||||
|
||||
$this->load->view("sales/register",$data);
|
||||
|
||||
$this->_remove_duplicate_cookies();
|
||||
}
|
||||
|
||||
@@ -462,53 +771,54 @@ class Sales extends Secure_area
|
||||
|
||||
function suspend()
|
||||
{
|
||||
$data['cart']=$this->sale_lib->get_cart();
|
||||
$data['subtotal']=$this->sale_lib->get_subtotal();
|
||||
$data['taxes']=$this->sale_lib->get_taxes();
|
||||
$data['total']=$this->sale_lib->get_total();
|
||||
$data['receipt_title']=$this->lang->line('sales_receipt');
|
||||
$data['transaction_time']= date('m/d/Y h:i:s a');
|
||||
$customer_id=$this->sale_lib->get_customer();
|
||||
$employee_id=$this->Employee->get_logged_in_employee_info()->person_id;
|
||||
$comment = $this->input->post('comment');
|
||||
$invoice_number=$this->sale_lib->get_invoice_number();
|
||||
|
||||
$emp_info=$this->Employee->get_info($employee_id);
|
||||
$payment_type = $this->input->post('payment_type');
|
||||
$data['payment_type']=$this->input->post('payment_type');
|
||||
//Alain Multiple payments
|
||||
$data['payments']=$this->sale_lib->get_payments();
|
||||
$data['amount_change']=to_currency($this->sale_lib->get_amount_due() * -1);
|
||||
$data['employee']=$emp_info->first_name.' '.$emp_info->last_name;
|
||||
|
||||
if ($this->Sale_suspended->invoice_number_exists($invoice_number))
|
||||
$data['cart'] = $this->sale_lib->get_cart();
|
||||
$data['subtotal'] = $this->sale_lib->get_subtotal();
|
||||
$data['taxes'] = $this->sale_lib->get_taxes();
|
||||
$data['total'] = $this->sale_lib->get_total();
|
||||
$data['receipt_title'] = $this->lang->line('sales_receipt');
|
||||
$data['transaction_time'] = date($this->config->item('dateformat').' '.$this->config->item('timeformat'));
|
||||
$customer_id = $this->sale_lib->get_customer();
|
||||
$employee_id = $this->Employee->get_logged_in_employee_info()->person_id;
|
||||
$comment = $this->sale_lib->get_comment();
|
||||
$invoice_number = $this->sale_lib->get_invoice_number();
|
||||
|
||||
$emp_info = $this->Employee->get_info($employee_id);
|
||||
$data['payment_type'] = $this->input->post('payment_type');
|
||||
// Multiple payments
|
||||
$data['payments'] = $this->sale_lib->get_payments();
|
||||
$data['amount_change'] = to_currency($this->sale_lib->get_amount_due() * -1);
|
||||
$data['employee'] = $emp_info->first_name.' '.$emp_info->last_name;
|
||||
|
||||
if($customer_id!=-1)
|
||||
{
|
||||
$this->_reload(array('error' => $data['error']=$this->lang->line('sales_invoice_number_duplicate')));
|
||||
$cust_info = $this->Customer->get_info($customer_id);
|
||||
if (isset($cust_info->company_name))
|
||||
{
|
||||
$data['customer'] = $cust_info->company_name;
|
||||
}
|
||||
else
|
||||
{
|
||||
$data['customer'] = $cust_info->first_name.' '.$cust_info->last_name;
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
$total_payments = 0;
|
||||
|
||||
foreach($data['payments'] as $payment)
|
||||
{
|
||||
if($customer_id!=-1)
|
||||
{
|
||||
$cust_info=$this->Customer->get_info($customer_id);
|
||||
$data['customer']=$cust_info->first_name.' '.$cust_info->last_name;
|
||||
}
|
||||
|
||||
$total_payments = 0;
|
||||
|
||||
foreach($data['payments'] as $payment)
|
||||
{
|
||||
$total_payments += $payment['payment_amount'];
|
||||
}
|
||||
|
||||
//SAVE sale to database
|
||||
$data['sale_id']='POS '.$this->Sale_suspended->save($data['cart'], $customer_id,$employee_id,$comment,$invoice_number,$data['payments']);
|
||||
if ($data['sale_id'] == 'POS -1')
|
||||
{
|
||||
$data['error_message'] = $this->lang->line('sales_transaction_failed');
|
||||
}
|
||||
$this->sale_lib->clear_all();
|
||||
$this->_reload(array('success' => $this->lang->line('sales_successfully_suspended_sale')));
|
||||
$total_payments = bcadd($total_payments, $payment['payment_amount'], PRECISION);
|
||||
}
|
||||
|
||||
//SAVE sale to database
|
||||
$data['sale_id'] = 'POS '.$this->Sale_suspended->save($data['cart'], $customer_id, $employee_id, $comment, $invoice_number, $data['payments']);
|
||||
if ($data['sale_id'] == 'POS -1')
|
||||
{
|
||||
$data['error_message'] = $this->lang->line('sales_transaction_failed');
|
||||
}
|
||||
|
||||
$this->sale_lib->clear_all();
|
||||
|
||||
$this->_reload(array('success' => $this->lang->line('sales_successfully_suspended_sale')));
|
||||
}
|
||||
|
||||
function suspended()
|
||||
@@ -532,7 +842,7 @@ class Sales extends Secure_area
|
||||
$sale_id=$this->input->post('sale_id');
|
||||
$invoice_number=$this->input->post('invoice_number');
|
||||
$exists=!empty($invoice_number) && $this->Sale->invoice_number_exists($invoice_number,$sale_id);
|
||||
echo json_encode(array('success'=>!$exists,'message'=>$this->lang->line('sales_invoice_number_duplicate')));
|
||||
echo json_encode(array('success'=>!$exists, 'message'=>$this->lang->line('sales_invoice_number_duplicate')));
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
<?php
|
||||
class Secure_area extends CI_Controller
|
||||
{
|
||||
|
||||
private $controller_name;
|
||||
|
||||
/*
|
||||
Controllers that are considered secure extend Secure_area, optionally a $module_id can
|
||||
be set to also check if a user can access a particular module in the system.
|
||||
@@ -23,11 +26,39 @@ class Secure_area extends CI_Controller
|
||||
//load up global data
|
||||
$logged_in_employee_info=$this->Employee->get_logged_in_employee_info();
|
||||
$data['allowed_modules']=$this->Module->get_allowed_modules($logged_in_employee_info->person_id);
|
||||
$data['backup_allowed']=false;
|
||||
foreach($data['allowed_modules']->result_array() as $module)
|
||||
{
|
||||
$data['backup_allowed']|=$module['module_id']==='config';
|
||||
}
|
||||
$data['user_info']=$logged_in_employee_info;
|
||||
$data['controller_name']=$module_id;
|
||||
$this->controller_name=$module_id;
|
||||
$this->load->vars($data);
|
||||
}
|
||||
|
||||
function get_controller_name() {
|
||||
return strtolower($this->controller_name);
|
||||
}
|
||||
|
||||
function _initialize_pagination($object, $lines_per_page, $limit_from = 0, $total_rows = -1, $function='index', $filter='')
|
||||
{
|
||||
$this->load->library('pagination');
|
||||
$config['base_url'] = site_url($this->get_controller_name() . "/$function/" . $filter);
|
||||
$config['total_rows'] = $total_rows > -1 ? $total_rows : call_user_func(array($object, 'get_total_rows'));
|
||||
$config['per_page'] = $lines_per_page;
|
||||
$config['num_links'] = 2;
|
||||
$config['last_link'] = $this->lang->line('common_last_page');
|
||||
$config['first_link'] = $this->lang->line('common_first_page');
|
||||
// page is calculated here instead of in pagination lib
|
||||
$config['cur_page'] = $limit_from > 0 ? $limit_from : 0;
|
||||
$config['page_query_string'] = FALSE;
|
||||
$config['uri_segment'] = 0;
|
||||
$this->pagination->initialize($config);
|
||||
return $this->pagination->create_links();
|
||||
}
|
||||
|
||||
|
||||
function _remove_duplicate_cookies ()
|
||||
{
|
||||
//php < 5.3 doesn't have header remove so this function will fatal error otherwise
|
||||
|
||||
@@ -7,17 +7,15 @@ class Suppliers extends Person_controller
|
||||
parent::__construct('suppliers');
|
||||
}
|
||||
|
||||
function index()
|
||||
function index($limit_from=0)
|
||||
{
|
||||
$config['base_url'] = site_url('/suppliers/index');
|
||||
$config['total_rows'] = $this->Supplier->count_all();
|
||||
$config['per_page'] = '20';
|
||||
$config['uri_segment'] = 3;
|
||||
$this->pagination->initialize($config);
|
||||
|
||||
$data['controller_name']=strtolower(get_class());
|
||||
$data['controller_name']=$this->get_controller_name();
|
||||
$data['form_width']=$this->get_form_width();
|
||||
$data['manage_table']=get_supplier_manage_table( $this->Supplier->get_all( $config['per_page'], $this->uri->segment( $config['uri_segment'] ) ), $this );
|
||||
$lines_per_page = $this->Appconfig->get('lines_per_page');
|
||||
$suppliers = $this->Supplier->get_all($lines_per_page);
|
||||
|
||||
$data['links'] = $this->_initialize_pagination($this->Supplier,$lines_per_page,$limit_from);
|
||||
$data['manage_table']=get_supplier_manage_table($suppliers,$this);
|
||||
$this->load->view('suppliers/manage',$data);
|
||||
}
|
||||
|
||||
@@ -26,9 +24,14 @@ class Suppliers extends Person_controller
|
||||
*/
|
||||
function search()
|
||||
{
|
||||
$search=$this->input->post('search');
|
||||
$data_rows=get_supplier_manage_table_data_rows($this->Supplier->search($search),$this);
|
||||
echo $data_rows;
|
||||
$search = $this->input->post('search');
|
||||
$limit_from = $this->input->post('limit_from');
|
||||
$lines_per_page = $this->Appconfig->get('lines_per_page');
|
||||
$suppliers = $this->Supplier->search($search, $lines_per_page, $limit_from);
|
||||
$total_rows = $this->Supplier->get_found_rows($search);
|
||||
$links = $this->_initialize_pagination($this->Supplier, $lines_per_page, $limit_from, $total_rows);
|
||||
$data_rows=get_supplier_manage_table_data_rows($suppliers,$this);
|
||||
echo json_encode(array('total_rows' => $total_rows, 'rows' => $data_rows, 'pagination' => $links));
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -57,6 +60,7 @@ class Suppliers extends Person_controller
|
||||
$person_data = array(
|
||||
'first_name'=>$this->input->post('first_name'),
|
||||
'last_name'=>$this->input->post('last_name'),
|
||||
'gender'=>$this->input->post('gender'),
|
||||
'email'=>$this->input->post('email'),
|
||||
'phone_number'=>$this->input->post('phone_number'),
|
||||
'address_1'=>$this->input->post('address_1'),
|
||||
@@ -69,6 +73,7 @@ class Suppliers extends Person_controller
|
||||
);
|
||||
$supplier_data=array(
|
||||
'company_name'=>$this->input->post('company_name'),
|
||||
'agency_name'=>$this->input->post('agency_name'),
|
||||
'account_number'=>$this->input->post('account_number')=='' ? null:$this->input->post('account_number'),
|
||||
);
|
||||
if($this->Supplier->save($person_data,$supplier_data,$supplier_id))
|
||||
@@ -127,5 +132,5 @@ class Suppliers extends Person_controller
|
||||
{
|
||||
return 360;
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
||||
96
application/core/MY_Lang.php
Normal file
96
application/core/MY_Lang.php
Normal file
@@ -0,0 +1,96 @@
|
||||
<?php (defined('BASEPATH')) OR exit('No direct script access allowed');
|
||||
|
||||
class MY_Lang extends CI_Lang
|
||||
{
|
||||
|
||||
function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
function switch_to( $idiom )
|
||||
{
|
||||
$CI =& get_instance();
|
||||
if( is_string( $idiom ) )
|
||||
{
|
||||
$CI->config->set_item( 'language', $idiom );
|
||||
$loaded = $this->is_loaded;
|
||||
$this->is_loaded = array();
|
||||
|
||||
foreach($loaded as $file)
|
||||
{
|
||||
$this->load( str_replace( '_lang.php', '', $file ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch a single line of text from the language array. Takes variable number
|
||||
* of arguments and supports wildcards in the form of '%1', '%2', etc.
|
||||
* Overloaded function.
|
||||
*
|
||||
* @access public
|
||||
* @return mixed false if not found or the language string
|
||||
*/
|
||||
function line($line = '')
|
||||
{
|
||||
//get the arguments passed to the function
|
||||
$args = func_get_args();
|
||||
|
||||
//count the number of arguments
|
||||
$c = count($args);
|
||||
|
||||
//if one or more arguments, perform the necessary processing
|
||||
if ($c)
|
||||
{
|
||||
//first argument should be the actual language line key
|
||||
//so remove it from the array (pop from front)
|
||||
$line = array_shift($args);
|
||||
|
||||
//check to make sure the key is valid and load the line
|
||||
if ($line == '')
|
||||
{
|
||||
$line = FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (isset($this->language[$line]))
|
||||
{
|
||||
$line = $this->language[$line];
|
||||
//if the line exists and more function arguments remain
|
||||
//perform wildcard replacements
|
||||
if ($args)
|
||||
{
|
||||
$i = 1;
|
||||
foreach ($args as $arg)
|
||||
{
|
||||
$line = preg_replace('/\%'.$i.'/', $arg, $line);
|
||||
$i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// just return label name (with TBD)
|
||||
$line = $this->line_tbd($line);
|
||||
log_message('error', 'Could not find the language line "'.$line.'"');
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//if no arguments given, no language line available
|
||||
$line = false;
|
||||
}
|
||||
|
||||
return $line;
|
||||
}
|
||||
|
||||
function line_tbd($line='')
|
||||
{
|
||||
return $line . ' (TBD)';
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -1,28 +1,29 @@
|
||||
<?php
|
||||
/** GARRISON MODIFIED 4/20/2013 **/
|
||||
function to_currency($number)
|
||||
function to_currency($number,$escape=FALSE)
|
||||
{
|
||||
$CI =& get_instance();
|
||||
$currency_symbol = $CI->config->item('currency_symbol') ? $CI->config->item('currency_symbol') : '$';
|
||||
$currency_symbol = $currency_symbol == '$' && $escape ? '\$' : $currency_symbol;
|
||||
$thousands_separator = $CI->config->item('thousands_separator') ? $CI->config->item('thousands_separator') : '';
|
||||
$decimal_point = $CI->config->item('decimal_point') ? $CI->config->item('decimal_point') : '.';
|
||||
if($number >= 0)
|
||||
{
|
||||
if($CI->config->item('currency_side') !== 'currency_side')
|
||||
return $currency_symbol.number_format($number, 2, '.', '');
|
||||
return $currency_symbol.number_format($number, 2, $decimal_point, $thousands_separator);
|
||||
else
|
||||
return number_format($number, 2, '.', '').$currency_symbol;
|
||||
return number_format($number, 2, $decimal_point, $thousands_separator).$currency_symbol;
|
||||
}
|
||||
else
|
||||
{
|
||||
if($CI->config->item('currency_side') !== 'currency_side')
|
||||
return '-'.$currency_symbol.number_format(abs($number), 2, '.', '');
|
||||
return '-'.$currency_symbol.number_format(abs($number), 2, $decimal_point, $thousands_separator);
|
||||
else
|
||||
return '-'.number_format(abs($number), 2, '.', '').$currency_symbol;
|
||||
return '-'.number_format(abs($number), 2, $decimal_point, $thousands_separator).$currency_symbol;
|
||||
}
|
||||
}
|
||||
/** END MODIFIED **/
|
||||
|
||||
function to_currency_no_money($number)
|
||||
{
|
||||
return number_format($number, 2, '.', '');
|
||||
}
|
||||
?>
|
||||
?>
|
||||
|
||||
69
application/helpers/dateformat_helper.php
Normal file
69
application/helpers/dateformat_helper.php
Normal file
@@ -0,0 +1,69 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Matches each symbol of PHP date format standard
|
||||
* with jQuery equivalent codeword
|
||||
* @author Tristan Jahier
|
||||
*/
|
||||
function dateformat_jquery($php_format)
|
||||
{
|
||||
$SYMBOLS_MATCHING = array(
|
||||
// Day
|
||||
'd' => 'dd',
|
||||
'D' => 'D',
|
||||
'j' => 'd',
|
||||
'l' => 'DD',
|
||||
'N' => '',
|
||||
'S' => '',
|
||||
'w' => '',
|
||||
'z' => 'o',
|
||||
// Week
|
||||
'W' => '',
|
||||
// Month
|
||||
'F' => 'MM',
|
||||
'm' => 'mm',
|
||||
'M' => 'M',
|
||||
'n' => 'm',
|
||||
't' => '',
|
||||
// Year
|
||||
'L' => '',
|
||||
'o' => '',
|
||||
'Y' => 'yy',
|
||||
'y' => 'y',
|
||||
// Time
|
||||
'a' => 'tt',
|
||||
'A' => 'TT',
|
||||
'B' => '',
|
||||
'g' => 'h',
|
||||
'G' => 'H',
|
||||
'h' => 'hh',
|
||||
'H' => 'HH',
|
||||
'i' => 'mm',
|
||||
's' => 'ss',
|
||||
'u' => ''
|
||||
);
|
||||
$jqueryui_format = "";
|
||||
$escaping = false;
|
||||
for($i = 0; $i < strlen($php_format); $i++)
|
||||
{
|
||||
$char = $php_format[$i];
|
||||
if($char === '\\') // PHP date format escaping character
|
||||
{
|
||||
$i++;
|
||||
if($escaping) $jqueryui_format .= $php_format[$i];
|
||||
else $jqueryui_format .= '\'' . $php_format[$i];
|
||||
$escaping = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if($escaping) { $jqueryui_format .= "'"; $escaping = false; }
|
||||
if(isset($SYMBOLS_MATCHING[$char]))
|
||||
$jqueryui_format .= $SYMBOLS_MATCHING[$char];
|
||||
else
|
||||
$jqueryui_format .= $char;
|
||||
}
|
||||
}
|
||||
return $jqueryui_format;
|
||||
}
|
||||
|
||||
?>
|
||||
76
application/helpers/dompdf/CONTRIBUTING.md
Executable file
76
application/helpers/dompdf/CONTRIBUTING.md
Executable file
@@ -0,0 +1,76 @@
|
||||
# How to contribute
|
||||
|
||||
- [Getting help](#getting-help)
|
||||
- [Submitting bug reports](#submitting-bug-reports)
|
||||
- [Contributing code](#contributing-code)
|
||||
|
||||
## Getting help
|
||||
|
||||
Community discussion, questions, and informal bug reporting is done on the
|
||||
[dompdf Google group](http://groups.google.com/group/dompdf). You may also
|
||||
seek help on
|
||||
[StackOverflow](http://stackoverflow.com/questions/tagged/dompdf).
|
||||
|
||||
## Submitting bug reports
|
||||
|
||||
The preferred way to report bugs is to use the
|
||||
[GitHub issue tracker](http://github.com/dompdf/dompdf/issues). Before
|
||||
reporting a bug, read these pointers.
|
||||
|
||||
**Please search inside the bug tracker to see if the bug you found is not already reported.**
|
||||
|
||||
**Note:** The issue tracker is for *bugs* and *feature requests*, not requests for help.
|
||||
Questions should be asked on the
|
||||
[dompdf Google group](http://groups.google.com/group/dompdf) instead.
|
||||
|
||||
### Reporting bugs effectively
|
||||
|
||||
- dompdf is maintained by volunteers. They don't owe you anything, so be
|
||||
polite. Reports with an indignant or belligerent tone tend to be moved to the
|
||||
bottom of the pile.
|
||||
|
||||
- Include information about **the PHP version on which the problem occurred**. Even
|
||||
if you tested several PHP version on different servers, and the problem occurred
|
||||
in all of them, mention this fact in the bug report.
|
||||
Also include the operating system it's installed on. PHP configuration can also help,
|
||||
and server error logs (like Apache logs)
|
||||
|
||||
- Mention which release of dompdf you're using (the zip, the master branch, etc).
|
||||
Preferably, try also with the current development snapshot, to ensure the
|
||||
problem has not already been fixed.
|
||||
|
||||
- Mention very precisely what went wrong. "X is broken" is not a good bug
|
||||
report. What did you expect to happen? What happened instead? Describe the
|
||||
exact steps a maintainer has to take to make the problem occur. We can not
|
||||
fix something that we can not observe.
|
||||
|
||||
- If the problem can not be reproduced in any of the demos included in the
|
||||
dompdf distribution, please provide an HTML document that demonstrates
|
||||
the problem. There are a few options to show us your code:
|
||||
- [JS Fiddle](http://jsfiddle.net/)
|
||||
- [dompdf debug helper](http://eclecticgeek.com/dompdf/debug.php) (provided by @bsweeney)
|
||||
- Include the HTML/CSS inside the bug report, with
|
||||
[code highlighting](https://github.com/adam-p/markdown-here/wiki/Markdown-Cheatsheet#wiki-code).
|
||||
|
||||
## Contributing code
|
||||
|
||||
- Make sure you have a [GitHub Account](https://github.com/signup/free)
|
||||
- Fork [dompdf](https://github.com/dompdf/dompdf/)
|
||||
([how to fork a repo](https://help.github.com/articles/fork-a-repo))
|
||||
- *Make your changes on the dev branch* or the most appropriate feature branch. Please only patch
|
||||
the master branch if you are attempting to address an urgent bug in the released code.
|
||||
- Add a simple test file in `www/test/`, with a comprehensive name.
|
||||
- Submit a pull request
|
||||
([how to create a pull request](https://help.github.com/articles/fork-a-repo))
|
||||
|
||||
### Coding standards
|
||||
|
||||
- 2 spaces per indentation level, no tabs.
|
||||
- spaces inside `if` like this:
|
||||
```php
|
||||
if ( $foo == "bar" ) {
|
||||
//
|
||||
}
|
||||
```
|
||||
- booleans in lowercase
|
||||
- opening braces *always* on the same line
|
||||
456
application/helpers/dompdf/LICENSE.LGPL
Executable file
456
application/helpers/dompdf/LICENSE.LGPL
Executable file
@@ -0,0 +1,456 @@
|
||||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
Version 2.1, February 1999
|
||||
|
||||
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
|
||||
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
[This is the first released version of the Lesser GPL. It also counts
|
||||
as the successor of the GNU Library Public License, version 2, hence
|
||||
the version number 2.1.]
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
Licenses are intended to guarantee your freedom to share and change
|
||||
free software--to make sure the software is free for all its users.
|
||||
|
||||
This license, the Lesser General Public License, applies to some
|
||||
specially designated software packages--typically libraries--of the
|
||||
Free Software Foundation and other authors who decide to use it. You
|
||||
can use it too, but we suggest you first think carefully about whether
|
||||
this license or the ordinary General Public License is the better
|
||||
strategy to use in any particular case, based on the explanations below.
|
||||
|
||||
When we speak of free software, we are referring to freedom of use,
|
||||
not price. Our General Public Licenses are designed to make sure that
|
||||
you have the freedom to distribute copies of free software (and charge
|
||||
for this service if you wish); that you receive source code or can get
|
||||
it if you want it; that you can change the software and use pieces of
|
||||
it in new free programs; and that you are informed that you can do
|
||||
these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
distributors to deny you these rights or to ask you to surrender these
|
||||
rights. These restrictions translate to certain responsibilities for
|
||||
you if you distribute copies of the library or if you modify it.
|
||||
|
||||
For example, if you distribute copies of the library, whether gratis
|
||||
or for a fee, you must give the recipients all the rights that we gave
|
||||
you. You must make sure that they, too, receive or can get the source
|
||||
code. If you link other code with the library, you must provide
|
||||
complete object files to the recipients, so that they can relink them
|
||||
with the library after making changes to the library and recompiling
|
||||
it. And you must show them these terms so they know their rights.
|
||||
|
||||
We protect your rights with a two-step method: (1) we copyright the
|
||||
library, and (2) we offer you this license, which gives you legal
|
||||
permission to copy, distribute and/or modify the library.
|
||||
|
||||
To protect each distributor, we want to make it very clear that
|
||||
there is no warranty for the free library. Also, if the library is
|
||||
modified by someone else and passed on, the recipients should know
|
||||
that what they have is not the original version, so that the original
|
||||
author's reputation will not be affected by problems that might be
|
||||
introduced by others.
|
||||
|
||||
Finally, software patents pose a constant threat to the existence of
|
||||
any free program. We wish to make sure that a company cannot
|
||||
effectively restrict the users of a free program by obtaining a
|
||||
restrictive license from a patent holder. Therefore, we insist that
|
||||
any patent license obtained for a version of the library must be
|
||||
consistent with the full freedom of use specified in this license.
|
||||
|
||||
Most GNU software, including some libraries, is covered by the
|
||||
ordinary GNU General Public License. This license, the GNU Lesser
|
||||
General Public License, applies to certain designated libraries, and
|
||||
is quite different from the ordinary General Public License. We use
|
||||
this license for certain libraries in order to permit linking those
|
||||
libraries into non-free programs.
|
||||
|
||||
When a program is linked with a library, whether statically or using
|
||||
a shared library, the combination of the two is legally speaking a
|
||||
combined work, a derivative of the original library. The ordinary
|
||||
General Public License therefore permits such linking only if the
|
||||
entire combination fits its criteria of freedom. The Lesser General
|
||||
Public License permits more lax criteria for linking other code with
|
||||
the library.
|
||||
|
||||
We call this license the "Lesser" General Public License because it
|
||||
does Less to protect the user's freedom than the ordinary General
|
||||
Public License. It also provides other free software developers Less
|
||||
of an advantage over competing non-free programs. These disadvantages
|
||||
are the reason we use the ordinary General Public License for many
|
||||
libraries. However, the Lesser license provides advantages in certain
|
||||
special circumstances.
|
||||
|
||||
For example, on rare occasions, there may be a special need to
|
||||
encourage the widest possible use of a certain library, so that it becomes
|
||||
a de-facto standard. To achieve this, non-free programs must be
|
||||
allowed to use the library. A more frequent case is that a free
|
||||
library does the same job as widely used non-free libraries. In this
|
||||
case, there is little to gain by limiting the free library to free
|
||||
software only, so we use the Lesser General Public License.
|
||||
|
||||
In other cases, permission to use a particular library in non-free
|
||||
programs enables a greater number of people to use a large body of
|
||||
free software. For example, permission to use the GNU C Library in
|
||||
non-free programs enables many more people to use the whole GNU
|
||||
operating system, as well as its variant, the GNU/Linux operating
|
||||
system.
|
||||
|
||||
Although the Lesser General Public License is Less protective of the
|
||||
users' freedom, it does ensure that the user of a program that is
|
||||
linked with the Library has the freedom and the wherewithal to run
|
||||
that program using a modified version of the Library.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow. Pay close attention to the difference between a
|
||||
"work based on the library" and a "work that uses the library". The
|
||||
former contains code derived from the library, whereas the latter must
|
||||
be combined with the library in order to run.
|
||||
|
||||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License Agreement applies to any software library or other
|
||||
program which contains a notice placed by the copyright holder or
|
||||
other authorized party saying it may be distributed under the terms of
|
||||
this Lesser General Public License (also called "this License").
|
||||
Each licensee is addressed as "you".
|
||||
|
||||
A "library" means a collection of software functions and/or data
|
||||
prepared so as to be conveniently linked with application programs
|
||||
(which use some of those functions and data) to form executables.
|
||||
|
||||
The "Library", below, refers to any such software library or work
|
||||
which has been distributed under these terms. A "work based on the
|
||||
Library" means either the Library or any derivative work under
|
||||
copyright law: that is to say, a work containing the Library or a
|
||||
portion of it, either verbatim or with modifications and/or translated
|
||||
straightforwardly into another language. (Hereinafter, translation is
|
||||
included without limitation in the term "modification".)
|
||||
|
||||
"Source code" for a work means the preferred form of the work for
|
||||
making modifications to it. For a library, complete source code means
|
||||
all the source code for all modules it contains, plus any associated
|
||||
interface definition files, plus the scripts used to control compilation
|
||||
and installation of the library.
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running a program using the Library is not restricted, and output from
|
||||
such a program is covered only if its contents constitute a work based
|
||||
on the Library (independent of the use of the Library in a tool for
|
||||
writing it). Whether that is true depends on what the Library does
|
||||
and what the program that uses the Library does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Library's
|
||||
complete source code as you receive it, in any medium, provided that
|
||||
you conspicuously and appropriately publish on each copy an
|
||||
appropriate copyright notice and disclaimer of warranty; keep intact
|
||||
all the notices that refer to this License and to the absence of any
|
||||
warranty; and distribute a copy of this License along with the
|
||||
Library.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy,
|
||||
and you may at your option offer warranty protection in exchange for a
|
||||
fee.
|
||||
|
||||
2. You may modify your copy or copies of the Library or any portion
|
||||
of it, thus forming a work based on the Library, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) The modified work must itself be a software library.
|
||||
|
||||
b) You must cause the files modified to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
c) You must cause the whole of the work to be licensed at no
|
||||
charge to all third parties under the terms of this License.
|
||||
|
||||
d) If a facility in the modified Library refers to a function or a
|
||||
table of data to be supplied by an application program that uses
|
||||
the facility, other than as an argument passed when the facility
|
||||
is invoked, then you must make a good faith effort to ensure that,
|
||||
in the event an application does not supply such function or
|
||||
table, the facility still operates, and performs whatever part of
|
||||
its purpose remains meaningful.
|
||||
|
||||
(For example, a function in a library to compute square roots has
|
||||
a purpose that is entirely well-defined independent of the
|
||||
application. Therefore, Subsection 2d requires that any
|
||||
application-supplied function or table used by this function must
|
||||
be optional: if the application does not supply it, the square
|
||||
root function must still compute square roots.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Library,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Library, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote
|
||||
it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Library.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Library
|
||||
with the Library (or with a work based on the Library) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may opt to apply the terms of the ordinary GNU General Public
|
||||
License instead of this License to a given copy of the Library. To do
|
||||
this, you must alter all the notices that refer to this License, so
|
||||
that they refer to the ordinary GNU General Public License, version 2,
|
||||
instead of to this License. (If a newer version than version 2 of the
|
||||
ordinary GNU General Public License has appeared, then you can specify
|
||||
that version instead if you wish.) Do not make any other change in
|
||||
these notices.
|
||||
|
||||
Once this change is made in a given copy, it is irreversible for
|
||||
that copy, so the ordinary GNU General Public License applies to all
|
||||
subsequent copies and derivative works made from that copy.
|
||||
|
||||
This option is useful when you wish to copy part of the code of
|
||||
the Library into a program that is not a library.
|
||||
|
||||
4. You may copy and distribute the Library (or a portion or
|
||||
derivative of it, under Section 2) in object code or executable form
|
||||
under the terms of Sections 1 and 2 above provided that you accompany
|
||||
it with the complete corresponding machine-readable source code, which
|
||||
must be distributed under the terms of Sections 1 and 2 above on a
|
||||
medium customarily used for software interchange.
|
||||
|
||||
If distribution of object code is made by offering access to copy
|
||||
from a designated place, then offering equivalent access to copy the
|
||||
source code from the same place satisfies the requirement to
|
||||
distribute the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
5. A program that contains no derivative of any portion of the
|
||||
Library, but is designed to work with the Library by being compiled or
|
||||
linked with it, is called a "work that uses the Library". Such a
|
||||
work, in isolation, is not a derivative work of the Library, and
|
||||
therefore falls outside the scope of this License.
|
||||
|
||||
However, linking a "work that uses the Library" with the Library
|
||||
creates an executable that is a derivative of the Library (because it
|
||||
contains portions of the Library), rather than a "work that uses the
|
||||
library". The executable is therefore covered by this License.
|
||||
Section 6 states terms for distribution of such executables.
|
||||
|
||||
When a "work that uses the Library" uses material from a header file
|
||||
that is part of the Library, the object code for the work may be a
|
||||
derivative work of the Library even though the source code is not.
|
||||
Whether this is true is especially significant if the work can be
|
||||
linked without the Library, or if the work is itself a library. The
|
||||
threshold for this to be true is not precisely defined by law.
|
||||
|
||||
If such an object file uses only numerical parameters, data
|
||||
structure layouts and accessors, and small macros and small inline
|
||||
functions (ten lines or less in length), then the use of the object
|
||||
file is unrestricted, regardless of whether it is legally a derivative
|
||||
work. (Executables containing this object code plus portions of the
|
||||
Library will still fall under Section 6.)
|
||||
|
||||
Otherwise, if the work is a derivative of the Library, you may
|
||||
distribute the object code for the work under the terms of Section 6.
|
||||
Any executables containing that work also fall under Section 6,
|
||||
whether or not they are linked directly with the Library itself.
|
||||
|
||||
6. As an exception to the Sections above, you may also combine or
|
||||
link a "work that uses the Library" with the Library to produce a
|
||||
work containing portions of the Library, and distribute that work
|
||||
under terms of your choice, provided that the terms permit
|
||||
modification of the work for the customer's own use and reverse
|
||||
engineering for debugging such modifications.
|
||||
|
||||
You must give prominent notice with each copy of the work that the
|
||||
Library is used in it and that the Library and its use are covered by
|
||||
this License. You must supply a copy of this License. If the work
|
||||
during execution displays copyright notices, you must include the
|
||||
copyright notice for the Library among them, as well as a reference
|
||||
directing the user to the copy of this License. Also, you must do one
|
||||
of these things:
|
||||
|
||||
a) Accompany the work with the complete corresponding
|
||||
machine-readable source code for the Library including whatever
|
||||
changes were used in the work (which must be distributed under
|
||||
Sections 1 and 2 above); and, if the work is an executable linked
|
||||
with the Library, with the complete machine-readable "work that
|
||||
uses the Library", as object code and/or source code, so that the
|
||||
user can modify the Library and then relink to produce a modified
|
||||
executable containing the modified Library. (It is understood
|
||||
that the user who changes the contents of definitions files in the
|
||||
Library will not necessarily be able to recompile the application
|
||||
to use the modified definitions.)
|
||||
|
||||
b) Use a suitable shared library mechanism for linking with the
|
||||
Library. A suitable mechanism is one that (1) uses at run time a
|
||||
copy of the library already present on the user's computer system,
|
||||
rather than copying library functions into the executable, and (2)
|
||||
will operate properly with a modified version of the library, if
|
||||
the user installs one, as long as the modified version is
|
||||
interface-compatible with the version that the work was made with.
|
||||
|
||||
c) Accompany the work with a written offer, valid for at
|
||||
least three years, to give the same user the materials
|
||||
specified in Subsection 6a, above, for a charge no more
|
||||
than the cost of performing this distribution.
|
||||
|
||||
d) If distribution of the work is made by offering access to copy
|
||||
from a designated place, offer equivalent access to copy the above
|
||||
specified materials from the same place.
|
||||
|
||||
e) Verify that the user has already received a copy of these
|
||||
materials or that you have already sent this user a copy.
|
||||
|
||||
For an executable, the required form of the "work that uses the
|
||||
Library" must include any data and utility programs needed for
|
||||
reproducing the executable from it. However, as a special exception,
|
||||
the materials to be distributed need not include anything that is
|
||||
normally distributed (in either source or binary form) with the major
|
||||
components (compiler, kernel, and so on) of the operating system on
|
||||
which the executable runs, unless that component itself accompanies
|
||||
the executable.
|
||||
|
||||
It may happen that this requirement contradicts the license
|
||||
restrictions of other proprietary libraries that do not normally
|
||||
accompany the operating system. Such a contradiction means you cannot
|
||||
use both them and the Library together in an executable that you
|
||||
distribute.
|
||||
|
||||
7. 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 not covered by this License, and distribute such a combined
|
||||
library, provided that the separate distribution of the work based on
|
||||
the Library and of the other library facilities is otherwise
|
||||
permitted, and provided that you do these two things:
|
||||
|
||||
a) Accompany the combined library with a copy of the same work
|
||||
based on the Library, uncombined with any other library
|
||||
facilities. This must be distributed under the terms of the
|
||||
Sections above.
|
||||
|
||||
b) Give prominent notice with the combined library of the fact
|
||||
that part of it is a work based on the Library, and explaining
|
||||
where to find the accompanying uncombined form of the same work.
|
||||
|
||||
8. You may not copy, modify, sublicense, link with, or distribute
|
||||
the Library except as expressly provided under this License. Any
|
||||
attempt otherwise to copy, modify, sublicense, link with, or
|
||||
distribute the Library is void, and will automatically terminate your
|
||||
rights under this License. However, parties who have received copies,
|
||||
or rights, from you under this License will not have their licenses
|
||||
terminated so long as such parties remain in full compliance.
|
||||
|
||||
9. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Library or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Library (or any work based on the
|
||||
Library), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Library or works based on it.
|
||||
|
||||
10. Each time you redistribute the Library (or any work based on the
|
||||
Library), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute, link with or modify the Library
|
||||
subject to these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties with
|
||||
this License.
|
||||
|
||||
11. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Library at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Library by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Library.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under any
|
||||
particular circumstance, the balance of the section is intended to apply,
|
||||
and the section as a whole is intended to apply in other circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
12. If the distribution and/or use of the Library is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Library under this License may add
|
||||
an explicit geographical distribution limitation excluding those countries,
|
||||
so that distribution is permitted only in or among countries not thus
|
||||
excluded. In such case, this License incorporates the limitation as if
|
||||
written in the body of this License.
|
||||
|
||||
13. The Free Software Foundation may publish revised and/or new
|
||||
versions of the 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
|
||||
specifies a version number of this License which applies to it and
|
||||
"any later version", you have the option of following the terms and
|
||||
conditions either of that version or of any later version published by
|
||||
the Free Software Foundation. If the Library does not specify a
|
||||
license version number, you may choose any version ever published by
|
||||
the Free Software Foundation.
|
||||
|
||||
14. If you wish to incorporate parts of the Library into other free
|
||||
programs whose distribution conditions are incompatible with these,
|
||||
write to the author to ask for permission. For software which is
|
||||
copyrighted by the Free Software Foundation, write to the Free
|
||||
Software Foundation; we sometimes make exceptions for this. Our
|
||||
decision will be guided by the two goals of preserving the free status
|
||||
of all derivatives of our free software and of promoting the sharing
|
||||
and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
|
||||
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
|
||||
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
|
||||
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
|
||||
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
|
||||
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
|
||||
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
|
||||
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
|
||||
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
|
||||
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
|
||||
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
|
||||
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
|
||||
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
|
||||
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
|
||||
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
DAMAGES.
|
||||
131
application/helpers/dompdf/README.md
Executable file
131
application/helpers/dompdf/README.md
Executable file
@@ -0,0 +1,131 @@
|
||||
**dompdf is an HTML to PDF converter**.
|
||||
At its heart, dompdf is (mostly) [CSS 2.1](http://www.w3.org/TR/CSS2/) compliant
|
||||
HTML layout and rendering engine written in PHP. It is a style-driven renderer:
|
||||
it will download and read external stylesheets, inline style tags, and the style
|
||||
attributes of individual HTML elements. It also supports most presentational
|
||||
HTML attributes.
|
||||
|
||||
----
|
||||
|
||||
**Check out the [Demo](http://pxd.me/dompdf/www/examples.php) and ask any
|
||||
question on [StackOverflow](http://stackoverflow.com/questions/tagged/dompdf) or
|
||||
on the [Google Groups](http://groups.google.com/group/dompdf)**
|
||||
|
||||
----
|
||||
|
||||
[](http://www.twitter.com/dompdf)
|
||||
[](https://plus.google.com/108710008521858993320?prsrc=3)
|
||||
|
||||
Features
|
||||
========
|
||||
* handles most CSS 2.1 and a few CSS3 properties, including @import, @media &
|
||||
@page rules
|
||||
* supports most presentational HTML 4.0 attributes
|
||||
* supports external stylesheets, either local or through http/ftp (via
|
||||
fopen-wrappers)
|
||||
* supports complex tables, including row & column spans, separate & collapsed
|
||||
border models, individual cell styling
|
||||
* image support (gif, png (8, 24 and 32 bit with alpha channel), bmp & jpeg)
|
||||
* no dependencies on external PDF libraries, thanks to the R&OS PDF class
|
||||
* inline PHP support
|
||||
|
||||
Requirements
|
||||
============
|
||||
* PHP 5.0+ (5.3+ recommended)
|
||||
* DOM extension
|
||||
* GD extension
|
||||
|
||||
Recommendations
|
||||
============
|
||||
* MBString extension: provides internationalization support. This extension is
|
||||
*not* enabled by default. dompdf has limited internationalization support
|
||||
when this extension is not enabled.
|
||||
* opcache (OPcache, XCache, APC, etc.): improves performance
|
||||
|
||||
About Fonts & Character Encoding
|
||||
============
|
||||
PDF documents internally support the following fonts: Helvetica, Times-Roman,
|
||||
Courier, Zapf-Dingbats, & Symbol. These fonts only support Windows ANSI
|
||||
encoding. In order for a PDF to display characters that are not available in
|
||||
Windows ANSI you must supply an external font. dompdf will embed any referenced
|
||||
font in the PDF so long as it has been pre-loaded or is accessible to dompdf and
|
||||
reference in CSS @font-face rules. See the
|
||||
[font overview](https://github.com/dompdf/dompdf/wiki/About-Fonts-and-Character-Encoding)
|
||||
for more information on how to use fonts.
|
||||
|
||||
The [DejaVu TrueType fonts](http://dejavu-fonts.org) have been pre-installed to
|
||||
give dompdf decent Unicode character coverage by default. To use the DejaVu
|
||||
fonts reference the font in your stylesheet, e.g. `body { font-family: Deja Vu
|
||||
Sans; }` (for DejaVu Sans).
|
||||
|
||||
Easy Installation
|
||||
============
|
||||
Install with git
|
||||
---
|
||||
From the command line switch to the directory where dompdf will reside and run
|
||||
the following commands:
|
||||
|
||||
```sh
|
||||
git clone https://github.com/dompdf/dompdf.git
|
||||
git submodule init
|
||||
git submodule update
|
||||
```
|
||||
|
||||
Install with composer
|
||||
---
|
||||
To install with Composer, simply add the requirement to your `composer.json`
|
||||
file:
|
||||
|
||||
```json
|
||||
{
|
||||
"require" : {
|
||||
"dompdf/dompdf" : "0.6.*"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
And run Composer to update your dependencies:
|
||||
|
||||
```bash
|
||||
$ curl -sS http://getcomposer.org/installer | php
|
||||
$ php composer.phar update
|
||||
```
|
||||
|
||||
Before you can use the Composer installation of DOMPDF in your application you
|
||||
must disable dompdf's default auto-loader, include the Composer autoloader, and
|
||||
load the dompdf configuration file:
|
||||
|
||||
```php
|
||||
// somewhere early in your project's loading, require the Composer autoloader
|
||||
// see: http://getcomposer.org/doc/00-intro.md
|
||||
require 'vendor/autoload.php';
|
||||
|
||||
// disable DOMPDF's internal autoloader if you are using Composer
|
||||
define('DOMPDF_ENABLE_AUTOLOAD', false);
|
||||
|
||||
// include DOMPDF's default configuration
|
||||
require_once '/path/to/vendor/dompdf/dompdf/dompdf_config.inc.php';
|
||||
```
|
||||
|
||||
Download and install
|
||||
---
|
||||
Download an archive of dompdf and extract it into the directory where dompdf
|
||||
will reside
|
||||
* You can download stable copies of dompdf from
|
||||
https://github.com/dompdf/dompdf/tags
|
||||
* Or download a nightly (the latest, unreleased code) from
|
||||
http://eclecticgeek.com/dompdf
|
||||
|
||||
Limitations (Known Issues)
|
||||
==========================
|
||||
* not particularly tolerant to poorly-formed HTML input. To avoid any
|
||||
unexpected rendering issues you should either enable the built-in HTML5
|
||||
parser (via the `DOMPDF_ENABLE_HTML5PARSER` configuration constant) or run
|
||||
your HTML through a HTML validator/cleaner (such as Tidy).
|
||||
* large files or large tables can take a while to render
|
||||
* CSS float is not supported (but is in the works, enable it through the
|
||||
`DOMPDF_ENABLE_CSS_FLOAT` configuration constant).
|
||||
* If you find this project useful, please consider making a donation.
|
||||
|
||||
(Any funds donated will be used to help further development on this project.)
|
||||
[](http://goo.gl/DSvWf)
|
||||
23
application/helpers/dompdf/composer.json
Executable file
23
application/helpers/dompdf/composer.json
Executable file
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"name": "dompdf/dompdf",
|
||||
"type": "library",
|
||||
"description": "DOMPDF is a CSS 2.1 compliant HTML to PDF converter",
|
||||
"homepage": "https://github.com/dompdf/dompdf",
|
||||
"license": "LGPL",
|
||||
"authors": [
|
||||
{
|
||||
"name": "Fabien Ménager",
|
||||
"email": "fabien.menager@gmail.com"
|
||||
},
|
||||
{
|
||||
"name": "Brian Sweeney",
|
||||
"email": "eclecticgeek@gmail.com"
|
||||
}
|
||||
],
|
||||
"autoload": {
|
||||
"classmap": ["include/"]
|
||||
},
|
||||
"require": {
|
||||
"phenx/php-font-lib": "0.2.*"
|
||||
}
|
||||
}
|
||||
289
application/helpers/dompdf/dompdf.php
Executable file
289
application/helpers/dompdf/dompdf.php
Executable file
@@ -0,0 +1,289 @@
|
||||
<?php
|
||||
/**
|
||||
* Command line utility to use dompdf.
|
||||
* Can also be used with HTTP GET parameters
|
||||
*
|
||||
* @package dompdf
|
||||
* @link http://dompdf.github.com/
|
||||
* @author Benj Carson <benjcarson@digitaljunkies.ca>
|
||||
* @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
|
||||
*/
|
||||
|
||||
/**
|
||||
* Display command line usage
|
||||
*/
|
||||
function dompdf_usage() {
|
||||
$default_paper_size = DOMPDF_DEFAULT_PAPER_SIZE;
|
||||
|
||||
echo <<<EOD
|
||||
|
||||
Usage: {$_SERVER["argv"][0]} [options] html_file
|
||||
|
||||
html_file can be a filename, a url if fopen_wrappers are enabled, or the '-' character to read from standard input.
|
||||
|
||||
Options:
|
||||
-h Show this message
|
||||
-l List available paper sizes
|
||||
-p size Paper size; something like 'letter', 'A4', 'legal', etc.
|
||||
The default is '$default_paper_size'
|
||||
-o orientation Either 'portrait' or 'landscape'. Default is 'portrait'
|
||||
-b path Set the 'document root' of the html_file.
|
||||
Relative urls (for stylesheets) are resolved using this directory.
|
||||
Default is the directory of html_file.
|
||||
-f file The output filename. Default is the input [html_file].pdf
|
||||
-v Verbose: display html parsing warnings and file not found errors.
|
||||
-d Very verbose: display oodles of debugging output: every frame
|
||||
in the tree printed to stdout.
|
||||
-t Comma separated list of debugging types (page-break,reflow,split)
|
||||
|
||||
EOD;
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses command line options
|
||||
*
|
||||
* @return array The command line options
|
||||
*/
|
||||
function getoptions() {
|
||||
|
||||
$opts = array();
|
||||
|
||||
if ( $_SERVER["argc"] == 1 )
|
||||
return $opts;
|
||||
|
||||
$i = 1;
|
||||
while ($i < $_SERVER["argc"]) {
|
||||
|
||||
switch ($_SERVER["argv"][$i]) {
|
||||
|
||||
case "--help":
|
||||
case "-h":
|
||||
$opts["h"] = true;
|
||||
$i++;
|
||||
break;
|
||||
|
||||
case "-l":
|
||||
$opts["l"] = true;
|
||||
$i++;
|
||||
break;
|
||||
|
||||
case "-p":
|
||||
if ( !isset($_SERVER["argv"][$i+1]) )
|
||||
die("-p switch requires a size parameter\n");
|
||||
$opts["p"] = $_SERVER["argv"][$i+1];
|
||||
$i += 2;
|
||||
break;
|
||||
|
||||
case "-o":
|
||||
if ( !isset($_SERVER["argv"][$i+1]) )
|
||||
die("-o switch requires an orientation parameter\n");
|
||||
$opts["o"] = $_SERVER["argv"][$i+1];
|
||||
$i += 2;
|
||||
break;
|
||||
|
||||
case "-b":
|
||||
if ( !isset($_SERVER["argv"][$i+1]) )
|
||||
die("-b switch requires a path parameter\n");
|
||||
$opts["b"] = $_SERVER["argv"][$i+1];
|
||||
$i += 2;
|
||||
break;
|
||||
|
||||
case "-f":
|
||||
if ( !isset($_SERVER["argv"][$i+1]) )
|
||||
die("-f switch requires a filename parameter\n");
|
||||
$opts["f"] = $_SERVER["argv"][$i+1];
|
||||
$i += 2;
|
||||
break;
|
||||
|
||||
case "-v":
|
||||
$opts["v"] = true;
|
||||
$i++;
|
||||
break;
|
||||
|
||||
case "-d":
|
||||
$opts["d"] = true;
|
||||
$i++;
|
||||
break;
|
||||
|
||||
case "-t":
|
||||
if ( !isset($_SERVER['argv'][$i + 1]) )
|
||||
die("-t switch requires a comma separated list of types\n");
|
||||
$opts["t"] = $_SERVER['argv'][$i+1];
|
||||
$i += 2;
|
||||
break;
|
||||
|
||||
default:
|
||||
$opts["filename"] = $_SERVER["argv"][$i];
|
||||
$i++;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
return $opts;
|
||||
}
|
||||
|
||||
require_once("dompdf_config.inc.php");
|
||||
global $_dompdf_show_warnings, $_dompdf_debug, $_DOMPDF_DEBUG_TYPES;
|
||||
|
||||
$sapi = php_sapi_name();
|
||||
$options = array();
|
||||
|
||||
switch ( $sapi ) {
|
||||
|
||||
case "cli":
|
||||
|
||||
$opts = getoptions();
|
||||
|
||||
if ( isset($opts["h"]) || (!isset($opts["filename"]) && !isset($opts["l"])) ) {
|
||||
dompdf_usage();
|
||||
exit;
|
||||
}
|
||||
|
||||
if ( isset($opts["l"]) ) {
|
||||
echo "\nUnderstood paper sizes:\n";
|
||||
|
||||
foreach (array_keys(CPDF_Adapter::$PAPER_SIZES) as $size)
|
||||
echo " " . mb_strtoupper($size) . "\n";
|
||||
exit;
|
||||
}
|
||||
$file = $opts["filename"];
|
||||
|
||||
if ( isset($opts["p"]) )
|
||||
$paper = $opts["p"];
|
||||
else
|
||||
$paper = DOMPDF_DEFAULT_PAPER_SIZE;
|
||||
|
||||
if ( isset($opts["o"]) )
|
||||
$orientation = $opts["o"];
|
||||
else
|
||||
$orientation = "portrait";
|
||||
|
||||
if ( isset($opts["b"]) )
|
||||
$base_path = $opts["b"];
|
||||
|
||||
if ( isset($opts["f"]) )
|
||||
$outfile = $opts["f"];
|
||||
else {
|
||||
if ( $file === "-" )
|
||||
$outfile = "dompdf_out.pdf";
|
||||
else
|
||||
$outfile = str_ireplace(array(".html", ".htm", ".php"), "", $file) . ".pdf";
|
||||
}
|
||||
|
||||
if ( isset($opts["v"]) )
|
||||
$_dompdf_show_warnings = true;
|
||||
|
||||
if ( isset($opts["d"]) ) {
|
||||
$_dompdf_show_warnings = true;
|
||||
$_dompdf_debug = true;
|
||||
}
|
||||
|
||||
if ( isset($opts['t']) ) {
|
||||
$arr = split(',',$opts['t']);
|
||||
$types = array();
|
||||
foreach ($arr as $type)
|
||||
$types[ trim($type) ] = 1;
|
||||
$_DOMPDF_DEBUG_TYPES = $types;
|
||||
}
|
||||
|
||||
$save_file = true;
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
if ( isset($_GET["input_file"]) )
|
||||
$file = rawurldecode($_GET["input_file"]);
|
||||
else
|
||||
throw new DOMPDF_Exception("An input file is required (i.e. input_file _GET variable).");
|
||||
|
||||
if ( isset($_GET["paper"]) )
|
||||
$paper = rawurldecode($_GET["paper"]);
|
||||
else
|
||||
$paper = DOMPDF_DEFAULT_PAPER_SIZE;
|
||||
|
||||
if ( isset($_GET["orientation"]) )
|
||||
$orientation = rawurldecode($_GET["orientation"]);
|
||||
else
|
||||
$orientation = "portrait";
|
||||
|
||||
if ( isset($_GET["base_path"]) ) {
|
||||
$base_path = rawurldecode($_GET["base_path"]);
|
||||
$file = $base_path . $file; # Set the input file
|
||||
}
|
||||
|
||||
if ( isset($_GET["options"]) ) {
|
||||
$options = $_GET["options"];
|
||||
}
|
||||
|
||||
$file_parts = explode_url($file);
|
||||
|
||||
/* Check to see if the input file is local and, if so, that the base path falls within that specified by DOMDPF_CHROOT */
|
||||
if(($file_parts['protocol'] == '' || $file_parts['protocol'] === 'file://')) {
|
||||
$file = realpath($file);
|
||||
if ( strpos($file, DOMPDF_CHROOT) !== 0 ) {
|
||||
throw new DOMPDF_Exception("Permission denied on $file. The file could not be found under the directory specified by DOMPDF_CHROOT.");
|
||||
}
|
||||
}
|
||||
|
||||
if($file_parts['protocol'] === 'php://') {
|
||||
throw new DOMPDF_Exception("Permission denied on $file. This script does not allow PHP streams.");
|
||||
}
|
||||
|
||||
$outfile = "dompdf_out.pdf"; # Don't allow them to set the output file
|
||||
$save_file = false; # Don't save the file
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
$dompdf = new DOMPDF();
|
||||
|
||||
if ( $file === "-" ) {
|
||||
$str = "";
|
||||
while ( !feof(STDIN) )
|
||||
$str .= fread(STDIN, 4096);
|
||||
|
||||
$dompdf->load_html($str);
|
||||
|
||||
} else
|
||||
$dompdf->load_html_file($file);
|
||||
|
||||
if ( isset($base_path) ) {
|
||||
$dompdf->set_base_path($base_path);
|
||||
}
|
||||
|
||||
$dompdf->set_paper($paper, $orientation);
|
||||
|
||||
$dompdf->render();
|
||||
|
||||
if ( $_dompdf_show_warnings ) {
|
||||
global $_dompdf_warnings;
|
||||
foreach ($_dompdf_warnings as $msg)
|
||||
echo $msg . "\n";
|
||||
echo $dompdf->get_canvas()->get_cpdf()->messages;
|
||||
flush();
|
||||
}
|
||||
|
||||
if ( $save_file ) {
|
||||
// if ( !is_writable($outfile) )
|
||||
// throw new DOMPDF_Exception("'$outfile' is not writable.");
|
||||
if ( strtolower(DOMPDF_PDF_BACKEND) === "gd" )
|
||||
$outfile = str_replace(".pdf", ".png", $outfile);
|
||||
|
||||
list($proto, $host, $path, $file) = explode_url($outfile);
|
||||
if ( $proto != "" ) // i.e. not file://
|
||||
$outfile = $file; // just save it locally, FIXME? could save it like wget: ./host/basepath/file
|
||||
|
||||
$outfile = realpath(dirname($outfile)) . DIRECTORY_SEPARATOR . basename($outfile);
|
||||
|
||||
if ( strpos($outfile, DOMPDF_CHROOT) !== 0 )
|
||||
throw new DOMPDF_Exception("Permission denied.");
|
||||
|
||||
file_put_contents($outfile, $dompdf->output( array("compress" => 0) ));
|
||||
exit(0);
|
||||
}
|
||||
|
||||
if ( !headers_sent() ) {
|
||||
$dompdf->stream($outfile, $options);
|
||||
}
|
||||
31
application/helpers/dompdf/dompdf_config.custom.inc.php
Executable file
31
application/helpers/dompdf/dompdf_config.custom.inc.php
Executable file
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
//define("DOMPDF_TEMP_DIR", "/tmp");
|
||||
//define("DOMPDF_CHROOT", DOMPDF_DIR);
|
||||
//define("DOMPDF_FONT_DIR", DOMPDF_DIR."/lib/fonts/");
|
||||
//define("DOMPDF_FONT_CACHE", DOMPDF_DIR."/lib/fonts/");
|
||||
//define("DOMPDF_UNICODE_ENABLED", true);
|
||||
//define("DOMPDF_PDF_BACKEND", "PDFLib");
|
||||
//define("DOMPDF_DEFAULT_MEDIA_TYPE", "print");
|
||||
//define("DOMPDF_DEFAULT_PAPER_SIZE", "letter");
|
||||
//define("DOMPDF_DEFAULT_FONT", "serif");
|
||||
//define("DOMPDF_DPI", 72);
|
||||
//define("DOMPDF_ENABLE_PHP", true);
|
||||
//define("DOMPDF_ENABLE_REMOTE", true);
|
||||
//define("DOMPDF_ENABLE_CSS_FLOAT", true);
|
||||
//define("DOMPDF_ENABLE_JAVASCRIPT", false);
|
||||
//define("DEBUGPNG", true);
|
||||
//define("DEBUGKEEPTEMP", true);
|
||||
//define("DEBUGCSS", true);
|
||||
//define("DEBUG_LAYOUT", true);
|
||||
//define("DEBUG_LAYOUT_LINES", false);
|
||||
//define("DEBUG_LAYOUT_BLOCKS", false);
|
||||
//define("DEBUG_LAYOUT_INLINE", false);
|
||||
//define("DOMPDF_FONT_HEIGHT_RATIO", 1.0);
|
||||
//define("DEBUG_LAYOUT_PADDINGBOX", false);
|
||||
//define("DOMPDF_LOG_OUTPUT_FILE", DOMPDF_FONT_DIR."log.htm");
|
||||
//define("DOMPDF_ENABLE_HTML5PARSER", true);
|
||||
//define("DOMPDF_ENABLE_FONTSUBSETTING", true);
|
||||
|
||||
// DOMPDF authentication
|
||||
//define("DOMPDF_ADMIN_USERNAME", "user");
|
||||
//define("DOMPDF_ADMIN_PASSWORD", "password");
|
||||
393
application/helpers/dompdf/dompdf_config.inc.php
Executable file
393
application/helpers/dompdf/dompdf_config.inc.php
Executable file
@@ -0,0 +1,393 @@
|
||||
<?php
|
||||
/**
|
||||
* @package dompdf
|
||||
* @link http://dompdf.github.com/
|
||||
* @author Benj Carson <benjcarson@digitaljunkies.ca>
|
||||
* @author Helmut Tischer <htischer@weihenstephan.org>
|
||||
* @author Fabien Ménager <fabien.menager@gmail.com>
|
||||
* @autho Brian Sweeney <eclecticgeek@gmail.com>
|
||||
* @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
|
||||
*/
|
||||
|
||||
if ( class_exists( 'DOMPDF' , false ) ) { return; }
|
||||
|
||||
PHP_VERSION >= 5.0 or die("DOMPDF requires PHP 5.0+");
|
||||
|
||||
/**
|
||||
* The root of your DOMPDF installation
|
||||
*/
|
||||
define("DOMPDF_DIR", str_replace(DIRECTORY_SEPARATOR, '/', realpath(dirname(__FILE__))));
|
||||
|
||||
/**
|
||||
* The location of the DOMPDF include directory
|
||||
*/
|
||||
define("DOMPDF_INC_DIR", DOMPDF_DIR . "/include");
|
||||
|
||||
/**
|
||||
* The location of the DOMPDF lib directory
|
||||
*/
|
||||
define("DOMPDF_LIB_DIR", DOMPDF_DIR . "/lib");
|
||||
|
||||
/**
|
||||
* Some installations don't have $_SERVER['DOCUMENT_ROOT']
|
||||
* http://fyneworks.blogspot.com/2007/08/php-documentroot-in-iis-windows-servers.html
|
||||
*/
|
||||
if( !isset($_SERVER['DOCUMENT_ROOT']) ) {
|
||||
$path = "";
|
||||
|
||||
if ( isset($_SERVER['SCRIPT_FILENAME']) )
|
||||
$path = $_SERVER['SCRIPT_FILENAME'];
|
||||
elseif ( isset($_SERVER['PATH_TRANSLATED']) )
|
||||
$path = str_replace('\\\\', '\\', $_SERVER['PATH_TRANSLATED']);
|
||||
|
||||
$_SERVER['DOCUMENT_ROOT'] = str_replace( '\\', '/', substr($path, 0, 0-strlen($_SERVER['PHP_SELF'])));
|
||||
}
|
||||
|
||||
/** Include the custom config file if it exists */
|
||||
if ( file_exists(DOMPDF_DIR . "/dompdf_config.custom.inc.php") ){
|
||||
require_once(DOMPDF_DIR . "/dompdf_config.custom.inc.php");
|
||||
}
|
||||
|
||||
//FIXME: Some function definitions rely on the constants defined by DOMPDF. However, might this location prove problematic?
|
||||
require_once(DOMPDF_INC_DIR . "/functions.inc.php");
|
||||
|
||||
/**
|
||||
* Username and password used by the configuration utility in www/
|
||||
*/
|
||||
def("DOMPDF_ADMIN_USERNAME", "user");
|
||||
def("DOMPDF_ADMIN_PASSWORD", "password");
|
||||
|
||||
/**
|
||||
* The location of the DOMPDF font directory
|
||||
*
|
||||
* The location of the directory where DOMPDF will store fonts and font metrics
|
||||
* Note: This directory must exist and be writable by the webserver process.
|
||||
* *Please note the trailing slash.*
|
||||
*
|
||||
* Notes regarding fonts:
|
||||
* Additional .afm font metrics can be added by executing load_font.php from command line.
|
||||
*
|
||||
* Only the original "Base 14 fonts" are present on all pdf viewers. Additional fonts must
|
||||
* be embedded in the pdf file or the PDF may not display correctly. This can significantly
|
||||
* increase file size unless font subsetting is enabled. Before embedding a font please
|
||||
* review your rights under the font license.
|
||||
*
|
||||
* Any font specification in the source HTML is translated to the closest font available
|
||||
* in the font directory.
|
||||
*
|
||||
* The pdf standard "Base 14 fonts" are:
|
||||
* Courier, Courier-Bold, Courier-BoldOblique, Courier-Oblique,
|
||||
* Helvetica, Helvetica-Bold, Helvetica-BoldOblique, Helvetica-Oblique,
|
||||
* Times-Roman, Times-Bold, Times-BoldItalic, Times-Italic,
|
||||
* Symbol, ZapfDingbats.
|
||||
*/
|
||||
def("DOMPDF_FONT_DIR", DOMPDF_DIR . "/lib/fonts/");
|
||||
|
||||
/**
|
||||
* The location of the DOMPDF font cache directory
|
||||
*
|
||||
* This directory contains the cached font metrics for the fonts used by DOMPDF.
|
||||
* This directory can be the same as DOMPDF_FONT_DIR
|
||||
*
|
||||
* Note: This directory must exist and be writable by the webserver process.
|
||||
*/
|
||||
def("DOMPDF_FONT_CACHE", DOMPDF_FONT_DIR);
|
||||
|
||||
/**
|
||||
* The location of a temporary directory.
|
||||
*
|
||||
* The directory specified must be writeable by the webserver process.
|
||||
* The temporary directory is required to download remote images and when
|
||||
* using the PFDLib back end.
|
||||
*/
|
||||
def("DOMPDF_TEMP_DIR", sys_get_temp_dir());
|
||||
|
||||
/**
|
||||
* ==== IMPORTANT ====
|
||||
*
|
||||
* dompdf's "chroot": Prevents dompdf from accessing system files or other
|
||||
* files on the webserver. All local files opened by dompdf must be in a
|
||||
* subdirectory of this directory. DO NOT set it to '/' since this could
|
||||
* allow an attacker to use dompdf to read any files on the server. This
|
||||
* should be an absolute path.
|
||||
* This is only checked on command line call by dompdf.php, but not by
|
||||
* direct class use like:
|
||||
* $dompdf = new DOMPDF(); $dompdf->load_html($htmldata); $dompdf->render(); $pdfdata = $dompdf->output();
|
||||
*/
|
||||
def("DOMPDF_CHROOT", realpath(DOMPDF_DIR));
|
||||
|
||||
/**
|
||||
* Whether to use Unicode fonts or not.
|
||||
*
|
||||
* When set to true the PDF backend must be set to "CPDF" and fonts must be
|
||||
* loaded via load_font.php.
|
||||
*
|
||||
* When enabled, dompdf can support all Unicode glyphs. Any glyphs used in a
|
||||
* document must be present in your fonts, however.
|
||||
*/
|
||||
def("DOMPDF_UNICODE_ENABLED", true);
|
||||
|
||||
/**
|
||||
* Whether to enable font subsetting or not.
|
||||
*/
|
||||
def("DOMPDF_ENABLE_FONTSUBSETTING", true);
|
||||
|
||||
/**
|
||||
* The PDF rendering backend to use
|
||||
*
|
||||
* Valid settings are 'PDFLib', 'CPDF' (the bundled R&OS PDF class), 'GD' and
|
||||
* 'auto'. 'auto' will look for PDFLib and use it if found, or if not it will
|
||||
* fall back on CPDF. 'GD' renders PDFs to graphic files. {@link
|
||||
* Canvas_Factory} ultimately determines which rendering class to instantiate
|
||||
* based on this setting.
|
||||
*
|
||||
* Both PDFLib & CPDF rendering backends provide sufficient rendering
|
||||
* capabilities for dompdf, however additional features (e.g. object,
|
||||
* image and font support, etc.) differ between backends. Please see
|
||||
* {@link PDFLib_Adapter} for more information on the PDFLib backend
|
||||
* and {@link CPDF_Adapter} and lib/class.pdf.php for more information
|
||||
* on CPDF. Also see the documentation for each backend at the links
|
||||
* below.
|
||||
*
|
||||
* The GD rendering backend is a little different than PDFLib and
|
||||
* CPDF. Several features of CPDF and PDFLib are not supported or do
|
||||
* not make any sense when creating image files. For example,
|
||||
* multiple pages are not supported, nor are PDF 'objects'. Have a
|
||||
* look at {@link GD_Adapter} for more information. GD support is
|
||||
* experimental, so use it at your own risk.
|
||||
*
|
||||
* @link http://www.pdflib.com
|
||||
* @link http://www.ros.co.nz/pdf
|
||||
* @link http://www.php.net/image
|
||||
*/
|
||||
def("DOMPDF_PDF_BACKEND", "CPDF");
|
||||
|
||||
/**
|
||||
* PDFlib license key
|
||||
*
|
||||
* If you are using a licensed, commercial version of PDFlib, specify
|
||||
* your license key here. If you are using PDFlib-Lite or are evaluating
|
||||
* the commercial version of PDFlib, comment out this setting.
|
||||
*
|
||||
* @link http://www.pdflib.com
|
||||
*
|
||||
* If pdflib present in web server and auto or selected explicitely above,
|
||||
* a real license code must exist!
|
||||
*/
|
||||
//def("DOMPDF_PDFLIB_LICENSE", "your license key here");
|
||||
|
||||
/**
|
||||
* html target media view which should be rendered into pdf.
|
||||
* List of types and parsing rules for future extensions:
|
||||
* http://www.w3.org/TR/REC-html40/types.html
|
||||
* screen, tty, tv, projection, handheld, print, braille, aural, all
|
||||
* Note: aural is deprecated in CSS 2.1 because it is replaced by speech in CSS 3.
|
||||
* Note, even though the generated pdf file is intended for print output,
|
||||
* the desired content might be different (e.g. screen or projection view of html file).
|
||||
* Therefore allow specification of content here.
|
||||
*/
|
||||
def("DOMPDF_DEFAULT_MEDIA_TYPE", "screen");
|
||||
|
||||
/**
|
||||
* The default paper size.
|
||||
*
|
||||
* North America standard is "letter"; other countries generally "a4"
|
||||
*
|
||||
* @see CPDF_Adapter::PAPER_SIZES for valid sizes
|
||||
*/
|
||||
def("DOMPDF_DEFAULT_PAPER_SIZE", "letter");
|
||||
|
||||
/**
|
||||
* The default font family
|
||||
*
|
||||
* Used if no suitable fonts can be found. This must exist in the font folder.
|
||||
* @var string
|
||||
*/
|
||||
def("DOMPDF_DEFAULT_FONT", "Helvetica");
|
||||
|
||||
/**
|
||||
* Image DPI setting
|
||||
*
|
||||
* This setting determines the default DPI setting for images and fonts. The
|
||||
* DPI may be overridden for inline images by explictly setting the
|
||||
* image's width & height style attributes (i.e. if the image's native
|
||||
* width is 600 pixels and you specify the image's width as 72 points,
|
||||
* the image will have a DPI of 600 in the rendered PDF. The DPI of
|
||||
* background images can not be overridden and is controlled entirely
|
||||
* via this parameter.
|
||||
*
|
||||
* For the purposes of DOMPDF, pixels per inch (PPI) = dots per inch (DPI).
|
||||
* If a size in html is given as px (or without unit as image size),
|
||||
* this tells the corresponding size in pt at 72 DPI.
|
||||
* This adjusts the relative sizes to be similar to the rendering of the
|
||||
* html page in a reference browser.
|
||||
*
|
||||
* In pdf, always 1 pt = 1/72 inch
|
||||
*
|
||||
* Rendering resolution of various browsers in px per inch:
|
||||
* Windows Firefox and Internet Explorer:
|
||||
* SystemControl->Display properties->FontResolution: Default:96, largefonts:120, custom:?
|
||||
* Linux Firefox:
|
||||
* about:config *resolution: Default:96
|
||||
* (xorg screen dimension in mm and Desktop font dpi settings are ignored)
|
||||
*
|
||||
* Take care about extra font/image zoom factor of browser.
|
||||
*
|
||||
* In images, <img> size in pixel attribute, img css style, are overriding
|
||||
* the real image dimension in px for rendering.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
def("DOMPDF_DPI", 96);
|
||||
|
||||
/**
|
||||
* Enable inline PHP
|
||||
*
|
||||
* If this setting is set to true then DOMPDF will automatically evaluate
|
||||
* inline PHP contained within <script type="text/php"> ... </script> tags.
|
||||
*
|
||||
* Enabling this for documents you do not trust (e.g. arbitrary remote html
|
||||
* pages) is a security risk. Set this option to false if you wish to process
|
||||
* untrusted documents.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
def("DOMPDF_ENABLE_PHP", false);
|
||||
|
||||
/**
|
||||
* Enable inline Javascript
|
||||
*
|
||||
* If this setting is set to true then DOMPDF will automatically insert
|
||||
* JavaScript code contained within <script type="text/javascript"> ... </script> tags.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
def("DOMPDF_ENABLE_JAVASCRIPT", true);
|
||||
|
||||
/**
|
||||
* Enable remote file access
|
||||
*
|
||||
* If this setting is set to true, DOMPDF will access remote sites for
|
||||
* images and CSS files as required.
|
||||
* This is required for part of test case www/test/image_variants.html through www/examples.php
|
||||
*
|
||||
* Attention!
|
||||
* This can be a security risk, in particular in combination with DOMPDF_ENABLE_PHP and
|
||||
* allowing remote access to dompdf.php or on allowing remote html code to be passed to
|
||||
* $dompdf = new DOMPDF(); $dompdf->load_html(...);
|
||||
* This allows anonymous users to download legally doubtful internet content which on
|
||||
* tracing back appears to being downloaded by your server, or allows malicious php code
|
||||
* in remote html pages to be executed by your server with your account privileges.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
def("DOMPDF_ENABLE_REMOTE", false);
|
||||
|
||||
/**
|
||||
* The debug output log
|
||||
* @var string
|
||||
*/
|
||||
def("DOMPDF_LOG_OUTPUT_FILE", DOMPDF_FONT_DIR."log.htm");
|
||||
|
||||
/**
|
||||
* A ratio applied to the fonts height to be more like browsers' line height
|
||||
*/
|
||||
def("DOMPDF_FONT_HEIGHT_RATIO", 1.1);
|
||||
|
||||
/**
|
||||
* Enable CSS float
|
||||
*
|
||||
* Allows people to disabled CSS float support
|
||||
* @var bool
|
||||
*/
|
||||
def("DOMPDF_ENABLE_CSS_FLOAT", true);
|
||||
|
||||
/**
|
||||
* Enable the built in DOMPDF autoloader
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
def("DOMPDF_ENABLE_AUTOLOAD", true);
|
||||
|
||||
/**
|
||||
* Prepend the DOMPDF autoload function to the spl_autoload stack
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
def("DOMPDF_AUTOLOAD_PREPEND", false);
|
||||
|
||||
/**
|
||||
* Use the more-than-experimental HTML5 Lib parser
|
||||
*/
|
||||
def("DOMPDF_ENABLE_HTML5PARSER", false);
|
||||
require_once(DOMPDF_LIB_DIR . "/html5lib/Parser.php");
|
||||
|
||||
// ### End of user-configurable options ###
|
||||
|
||||
/**
|
||||
* Load autoloader
|
||||
*/
|
||||
if (DOMPDF_ENABLE_AUTOLOAD) {
|
||||
require_once(DOMPDF_INC_DIR . "/autoload.inc.php");
|
||||
require_once(DOMPDF_LIB_DIR . "/php-font-lib/classes/Font.php");
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure that PHP is working with text internally using UTF8 character encoding.
|
||||
*/
|
||||
mb_internal_encoding('UTF-8');
|
||||
|
||||
/**
|
||||
* Global array of warnings generated by DomDocument parser and
|
||||
* stylesheet class
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
global $_dompdf_warnings;
|
||||
$_dompdf_warnings = array();
|
||||
|
||||
/**
|
||||
* If true, $_dompdf_warnings is dumped on script termination when using
|
||||
* dompdf/dompdf.php or after rendering when using the DOMPDF class.
|
||||
* When using the class, setting this value to true will prevent you from
|
||||
* streaming the PDF.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
global $_dompdf_show_warnings;
|
||||
$_dompdf_show_warnings = false;
|
||||
|
||||
/**
|
||||
* If true, the entire tree is dumped to stdout in dompdf.cls.php.
|
||||
* Setting this value to true will prevent you from streaming the PDF.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
global $_dompdf_debug;
|
||||
$_dompdf_debug = false;
|
||||
|
||||
/**
|
||||
* Array of enabled debug message types
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
global $_DOMPDF_DEBUG_TYPES;
|
||||
$_DOMPDF_DEBUG_TYPES = array(); //array("page-break" => 1);
|
||||
|
||||
/* Optionally enable different classes of debug output before the pdf content.
|
||||
* Visible if displaying pdf as text,
|
||||
* E.g. on repeated display of same pdf in browser when pdf is not taken out of
|
||||
* the browser cache and the premature output prevents setting of the mime type.
|
||||
*/
|
||||
def('DEBUGPNG', false);
|
||||
def('DEBUGKEEPTEMP', false);
|
||||
def('DEBUGCSS', false);
|
||||
|
||||
/* Layout debugging. Will display rectangles around different block levels.
|
||||
* Visible in the PDF itself.
|
||||
*/
|
||||
def('DEBUG_LAYOUT', false);
|
||||
def('DEBUG_LAYOUT_LINES', false);
|
||||
def('DEBUG_LAYOUT_BLOCKS', false);
|
||||
def('DEBUG_LAYOUT_INLINE', false);
|
||||
def('DEBUG_LAYOUT_PADDINGBOX', false);
|
||||
125
application/helpers/dompdf/include/absolute_positioner.cls.php
Executable file
125
application/helpers/dompdf/include/absolute_positioner.cls.php
Executable file
@@ -0,0 +1,125 @@
|
||||
<?php
|
||||
/**
|
||||
* @package dompdf
|
||||
* @link http://dompdf.github.com/
|
||||
* @author Benj Carson <benjcarson@digitaljunkies.ca>
|
||||
* @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
|
||||
*/
|
||||
|
||||
/**
|
||||
* Positions absolutely positioned frames
|
||||
*/
|
||||
class Absolute_Positioner extends Positioner {
|
||||
|
||||
function __construct(Frame_Decorator $frame) { parent::__construct($frame); }
|
||||
|
||||
function position() {
|
||||
|
||||
$frame = $this->_frame;
|
||||
$style = $frame->get_style();
|
||||
|
||||
$p = $frame->find_positionned_parent();
|
||||
|
||||
list($x, $y, $w, $h) = $frame->get_containing_block();
|
||||
|
||||
$top = $style->length_in_pt($style->top, $h);
|
||||
$right = $style->length_in_pt($style->right, $w);
|
||||
$bottom = $style->length_in_pt($style->bottom, $h);
|
||||
$left = $style->length_in_pt($style->left, $w);
|
||||
|
||||
if ( $p && !($left === "auto" && $right === "auto") ) {
|
||||
// Get the parent's padding box (see http://www.w3.org/TR/CSS21/visuren.html#propdef-top)
|
||||
list($x, $y, $w, $h) = $p->get_padding_box();
|
||||
}
|
||||
|
||||
list($width, $height) = array($frame->get_margin_width(), $frame->get_margin_height());
|
||||
|
||||
$orig_style = $this->_frame->get_original_style();
|
||||
$orig_width = $orig_style->width;
|
||||
$orig_height = $orig_style->height;
|
||||
|
||||
/****************************
|
||||
|
||||
Width auto:
|
||||
____________| left=auto | left=fixed |
|
||||
right=auto | A | B |
|
||||
right=fixed | C | D |
|
||||
|
||||
Width fixed:
|
||||
____________| left=auto | left=fixed |
|
||||
right=auto | E | F |
|
||||
right=fixed | G | H |
|
||||
|
||||
*****************************/
|
||||
|
||||
if ( $left === "auto" ) {
|
||||
if ( $right === "auto" ) {
|
||||
// A or E - Keep the frame at the same position
|
||||
$x = $x + $frame->find_block_parent()->get_current_line_box()->w;
|
||||
}
|
||||
else {
|
||||
if ( $orig_width === "auto" ) {
|
||||
// C
|
||||
$x += $w - $width - $right;
|
||||
}
|
||||
else {
|
||||
// G
|
||||
$x += $w - $width - $right;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if ( $right === "auto" ) {
|
||||
// B or F
|
||||
$x += $left;
|
||||
}
|
||||
else {
|
||||
if ( $orig_width === "auto" ) {
|
||||
// D - TODO change width
|
||||
$x += $left;
|
||||
}
|
||||
else {
|
||||
// H - Everything is fixed: left + width win
|
||||
$x += $left;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// The same vertically
|
||||
if ( $top === "auto" ) {
|
||||
if ( $bottom === "auto" ) {
|
||||
// A or E - Keep the frame at the same position
|
||||
$y = $frame->find_block_parent()->get_current_line_box()->y;
|
||||
}
|
||||
else {
|
||||
if ( $orig_height === "auto" ) {
|
||||
// C
|
||||
$y += $h - $height - $bottom;
|
||||
}
|
||||
else {
|
||||
// G
|
||||
$y += $h - $height - $bottom;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if ( $bottom === "auto" ) {
|
||||
// B or F
|
||||
$y += $top;
|
||||
}
|
||||
else {
|
||||
if ( $orig_height === "auto" ) {
|
||||
// D - TODO change height
|
||||
$y += $top;
|
||||
}
|
||||
else {
|
||||
// H - Everything is fixed: top + height win
|
||||
$y += $top;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$frame->set_position($x, $y);
|
||||
|
||||
}
|
||||
}
|
||||
759
application/helpers/dompdf/include/abstract_renderer.cls.php
Executable file
759
application/helpers/dompdf/include/abstract_renderer.cls.php
Executable file
@@ -0,0 +1,759 @@
|
||||
<?php
|
||||
/**
|
||||
* @package dompdf
|
||||
* @link http://dompdf.github.com/
|
||||
* @author Benj Carson <benjcarson@digitaljunkies.ca>
|
||||
* @author Helmut Tischer <htischer@weihenstephan.org>
|
||||
* @author Fabien Ménager <fabien.menager@gmail.com>
|
||||
* @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
|
||||
*/
|
||||
|
||||
/**
|
||||
* Base renderer class
|
||||
*
|
||||
* @access private
|
||||
* @package dompdf
|
||||
*/
|
||||
abstract class Abstract_Renderer {
|
||||
|
||||
/**
|
||||
* Rendering backend
|
||||
*
|
||||
* @var Canvas
|
||||
*/
|
||||
protected $_canvas;
|
||||
|
||||
/**
|
||||
* Current dompdf instance
|
||||
*
|
||||
* @var DOMPDF
|
||||
*/
|
||||
protected $_dompdf;
|
||||
|
||||
/**
|
||||
* Class constructor
|
||||
*
|
||||
* @param DOMPDF $dompdf The current dompdf instance
|
||||
*/
|
||||
function __construct(DOMPDF $dompdf) {
|
||||
$this->_dompdf = $dompdf;
|
||||
$this->_canvas = $dompdf->get_canvas();
|
||||
}
|
||||
|
||||
/**
|
||||
* Render a frame.
|
||||
*
|
||||
* Specialized in child classes
|
||||
*
|
||||
* @param Frame $frame The frame to render
|
||||
*/
|
||||
abstract function render(Frame $frame);
|
||||
|
||||
//........................................................................
|
||||
|
||||
/**
|
||||
* Render a background image over a rectangular area
|
||||
*
|
||||
* @param string $url The background image to load
|
||||
* @param float $x The left edge of the rectangular area
|
||||
* @param float $y The top edge of the rectangular area
|
||||
* @param float $width The width of the rectangular area
|
||||
* @param float $height The height of the rectangular area
|
||||
* @param Style $style The associated Style object
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function _background_image($url, $x, $y, $width, $height, $style) {
|
||||
if ( !function_exists("imagecreatetruecolor") ) {
|
||||
throw new Exception("The PHP GD extension is required, but is not installed.");
|
||||
}
|
||||
|
||||
$sheet = $style->get_stylesheet();
|
||||
|
||||
// Skip degenerate cases
|
||||
if ( $width == 0 || $height == 0 ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$box_width = $width;
|
||||
$box_height = $height;
|
||||
|
||||
//debugpng
|
||||
if (DEBUGPNG) print '[_background_image '.$url.']';
|
||||
|
||||
list($img, $type, /*$msg*/) = Image_Cache::resolve_url(
|
||||
$url,
|
||||
$sheet->get_protocol(),
|
||||
$sheet->get_host(),
|
||||
$sheet->get_base_path(),
|
||||
$this->_dompdf
|
||||
);
|
||||
|
||||
// Bail if the image is no good
|
||||
if ( Image_Cache::is_broken($img) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
//Try to optimize away reading and composing of same background multiple times
|
||||
//Postponing read with imagecreatefrom ...()
|
||||
//final composition parameters and name not known yet
|
||||
//Therefore read dimension directly from file, instead of creating gd object first.
|
||||
//$img_w = imagesx($src); $img_h = imagesy($src);
|
||||
|
||||
list($img_w, $img_h) = dompdf_getimagesize($img);
|
||||
if (!isset($img_w) || $img_w == 0 || !isset($img_h) || $img_h == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
$repeat = $style->background_repeat;
|
||||
$dpi = $this->_dompdf->get_option("dpi");
|
||||
|
||||
//Increase background resolution and dependent box size according to image resolution to be placed in
|
||||
//Then image can be copied in without resize
|
||||
$bg_width = round((float)($width * $dpi) / 72);
|
||||
$bg_height = round((float)($height * $dpi) / 72);
|
||||
|
||||
//Need %bg_x, $bg_y as background pos, where img starts, converted to pixel
|
||||
|
||||
list($bg_x, $bg_y) = $style->background_position;
|
||||
|
||||
if ( is_percent($bg_x) ) {
|
||||
// The point $bg_x % from the left edge of the image is placed
|
||||
// $bg_x % from the left edge of the background rectangle
|
||||
$p = ((float)$bg_x)/100.0;
|
||||
$x1 = $p * $img_w;
|
||||
$x2 = $p * $bg_width;
|
||||
|
||||
$bg_x = $x2 - $x1;
|
||||
}
|
||||
else {
|
||||
$bg_x = (float)($style->length_in_pt($bg_x)*$dpi) / 72;
|
||||
}
|
||||
|
||||
$bg_x = round($bg_x + $style->length_in_pt($style->border_left_width)*$dpi / 72);
|
||||
|
||||
if ( is_percent($bg_y) ) {
|
||||
// The point $bg_y % from the left edge of the image is placed
|
||||
// $bg_y % from the left edge of the background rectangle
|
||||
$p = ((float)$bg_y)/100.0;
|
||||
$y1 = $p * $img_h;
|
||||
$y2 = $p * $bg_height;
|
||||
|
||||
$bg_y = $y2 - $y1;
|
||||
}
|
||||
else {
|
||||
$bg_y = (float)($style->length_in_pt($bg_y)*$dpi) / 72;
|
||||
}
|
||||
|
||||
$bg_y = round($bg_y + $style->length_in_pt($style->border_top_width)*$dpi / 72);
|
||||
|
||||
//clip background to the image area on partial repeat. Nothing to do if img off area
|
||||
//On repeat, normalize start position to the tile at immediate left/top or 0/0 of area
|
||||
//On no repeat with positive offset: move size/start to have offset==0
|
||||
//Handle x/y Dimensions separately
|
||||
|
||||
if ( $repeat !== "repeat" && $repeat !== "repeat-x" ) {
|
||||
//No repeat x
|
||||
if ($bg_x < 0) {
|
||||
$bg_width = $img_w + $bg_x;
|
||||
}
|
||||
else {
|
||||
$x += ($bg_x * 72)/$dpi;
|
||||
$bg_width = $bg_width - $bg_x;
|
||||
if ($bg_width > $img_w) {
|
||||
$bg_width = $img_w;
|
||||
}
|
||||
$bg_x = 0;
|
||||
}
|
||||
|
||||
if ($bg_width <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
$width = (float)($bg_width * 72)/$dpi;
|
||||
}
|
||||
else {
|
||||
//repeat x
|
||||
if ($bg_x < 0) {
|
||||
$bg_x = - ((-$bg_x) % $img_w);
|
||||
}
|
||||
else {
|
||||
$bg_x = $bg_x % $img_w;
|
||||
if ($bg_x > 0) {
|
||||
$bg_x -= $img_w;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( $repeat !== "repeat" && $repeat !== "repeat-y" ) {
|
||||
//no repeat y
|
||||
if ($bg_y < 0) {
|
||||
$bg_height = $img_h + $bg_y;
|
||||
}
|
||||
else {
|
||||
$y += ($bg_y * 72)/$dpi;
|
||||
$bg_height = $bg_height - $bg_y;
|
||||
if ($bg_height > $img_h) {
|
||||
$bg_height = $img_h;
|
||||
}
|
||||
$bg_y = 0;
|
||||
}
|
||||
if ($bg_height <= 0) {
|
||||
return;
|
||||
}
|
||||
$height = (float)($bg_height * 72)/$dpi;
|
||||
}
|
||||
else {
|
||||
//repeat y
|
||||
if ($bg_y < 0) {
|
||||
$bg_y = - ((-$bg_y) % $img_h);
|
||||
}
|
||||
else {
|
||||
$bg_y = $bg_y % $img_h;
|
||||
if ($bg_y > 0) {
|
||||
$bg_y -= $img_h;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Optimization, if repeat has no effect
|
||||
if ( $repeat === "repeat" && $bg_y <= 0 && $img_h+$bg_y >= $bg_height ) {
|
||||
$repeat = "repeat-x";
|
||||
}
|
||||
|
||||
if ( $repeat === "repeat" && $bg_x <= 0 && $img_w+$bg_x >= $bg_width ) {
|
||||
$repeat = "repeat-y";
|
||||
}
|
||||
|
||||
if ( ($repeat === "repeat-x" && $bg_x <= 0 && $img_w+$bg_x >= $bg_width) ||
|
||||
($repeat === "repeat-y" && $bg_y <= 0 && $img_h+$bg_y >= $bg_height) ) {
|
||||
$repeat = "no-repeat";
|
||||
}
|
||||
|
||||
//Use filename as indicator only
|
||||
//different names for different variants to have different copies in the pdf
|
||||
//This is not dependent of background color of box! .'_'.(is_array($bg_color) ? $bg_color["hex"] : $bg_color)
|
||||
//Note: Here, bg_* are the start values, not end values after going through the tile loops!
|
||||
|
||||
$filedummy = $img;
|
||||
|
||||
$is_png = false;
|
||||
$filedummy .= '_'.$bg_width.'_'.$bg_height.'_'.$bg_x.'_'.$bg_y.'_'.$repeat;
|
||||
|
||||
//Optimization to avoid multiple times rendering the same image.
|
||||
//If check functions are existing and identical image already cached,
|
||||
//then skip creation of duplicate, because it is not needed by addImagePng
|
||||
if ( $this->_canvas instanceof CPDF_Adapter &&
|
||||
$this->_canvas->get_cpdf()->image_iscached($filedummy) ) {
|
||||
$bg = null;
|
||||
}
|
||||
|
||||
else {
|
||||
|
||||
// Create a new image to fit over the background rectangle
|
||||
$bg = imagecreatetruecolor($bg_width, $bg_height);
|
||||
|
||||
switch (strtolower($type)) {
|
||||
case IMAGETYPE_PNG:
|
||||
$is_png = true;
|
||||
imagesavealpha($bg, true);
|
||||
imagealphablending($bg, false);
|
||||
$src = imagecreatefrompng($img);
|
||||
break;
|
||||
|
||||
case IMAGETYPE_JPEG:
|
||||
$src = imagecreatefromjpeg($img);
|
||||
break;
|
||||
|
||||
case IMAGETYPE_GIF:
|
||||
$src = imagecreatefromgif($img);
|
||||
break;
|
||||
|
||||
case IMAGETYPE_BMP:
|
||||
$src = imagecreatefrombmp($img);
|
||||
break;
|
||||
|
||||
default:
|
||||
return; // Unsupported image type
|
||||
}
|
||||
|
||||
if ( $src == null ) {
|
||||
return;
|
||||
}
|
||||
|
||||
//Background color if box is not relevant here
|
||||
//Non transparent image: box clipped to real size. Background non relevant.
|
||||
//Transparent image: The image controls the transparency and lets shine through whatever background.
|
||||
//However on transparent image preset the composed image with the transparency color,
|
||||
//to keep the transparency when copying over the non transparent parts of the tiles.
|
||||
$ti = imagecolortransparent($src);
|
||||
|
||||
if ( $ti >= 0 ) {
|
||||
$tc = imagecolorsforindex($src, $ti);
|
||||
$ti = imagecolorallocate($bg, $tc['red'], $tc['green'], $tc['blue']);
|
||||
imagefill($bg, 0, 0, $ti);
|
||||
imagecolortransparent($bg, $ti);
|
||||
}
|
||||
|
||||
//This has only an effect for the non repeatable dimension.
|
||||
//compute start of src and dest coordinates of the single copy
|
||||
if ( $bg_x < 0 ) {
|
||||
$dst_x = 0;
|
||||
$src_x = -$bg_x;
|
||||
}
|
||||
else {
|
||||
$src_x = 0;
|
||||
$dst_x = $bg_x;
|
||||
}
|
||||
|
||||
if ( $bg_y < 0 ) {
|
||||
$dst_y = 0;
|
||||
$src_y = -$bg_y;
|
||||
}
|
||||
else {
|
||||
$src_y = 0;
|
||||
$dst_y = $bg_y;
|
||||
}
|
||||
|
||||
//For historical reasons exchange meanings of variables:
|
||||
//start_* will be the start values, while bg_* will be the temporary start values in the loops
|
||||
$start_x = $bg_x;
|
||||
$start_y = $bg_y;
|
||||
|
||||
// Copy regions from the source image to the background
|
||||
if ( $repeat === "no-repeat" ) {
|
||||
|
||||
// Simply place the image on the background
|
||||
imagecopy($bg, $src, $dst_x, $dst_y, $src_x, $src_y, $img_w, $img_h);
|
||||
|
||||
}
|
||||
else if ( $repeat === "repeat-x" ) {
|
||||
|
||||
for ( $bg_x = $start_x; $bg_x < $bg_width; $bg_x += $img_w ) {
|
||||
if ( $bg_x < 0 ) {
|
||||
$dst_x = 0;
|
||||
$src_x = -$bg_x;
|
||||
$w = $img_w + $bg_x;
|
||||
}
|
||||
else {
|
||||
$dst_x = $bg_x;
|
||||
$src_x = 0;
|
||||
$w = $img_w;
|
||||
}
|
||||
imagecopy($bg, $src, $dst_x, $dst_y, $src_x, $src_y, $w, $img_h);
|
||||
}
|
||||
|
||||
}
|
||||
else if ( $repeat === "repeat-y" ) {
|
||||
|
||||
for ( $bg_y = $start_y; $bg_y < $bg_height; $bg_y += $img_h ) {
|
||||
if ( $bg_y < 0 ) {
|
||||
$dst_y = 0;
|
||||
$src_y = -$bg_y;
|
||||
$h = $img_h + $bg_y;
|
||||
}
|
||||
else {
|
||||
$dst_y = $bg_y;
|
||||
$src_y = 0;
|
||||
$h = $img_h;
|
||||
}
|
||||
imagecopy($bg, $src, $dst_x, $dst_y, $src_x, $src_y, $img_w, $h);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
else if ( $repeat === "repeat" ) {
|
||||
|
||||
for ( $bg_y = $start_y; $bg_y < $bg_height; $bg_y += $img_h ) {
|
||||
for ( $bg_x = $start_x; $bg_x < $bg_width; $bg_x += $img_w ) {
|
||||
|
||||
if ( $bg_x < 0 ) {
|
||||
$dst_x = 0;
|
||||
$src_x = -$bg_x;
|
||||
$w = $img_w + $bg_x;
|
||||
}
|
||||
else {
|
||||
$dst_x = $bg_x;
|
||||
$src_x = 0;
|
||||
$w = $img_w;
|
||||
}
|
||||
|
||||
if ( $bg_y < 0 ) {
|
||||
$dst_y = 0;
|
||||
$src_y = -$bg_y;
|
||||
$h = $img_h + $bg_y;
|
||||
}
|
||||
else {
|
||||
$dst_y = $bg_y;
|
||||
$src_y = 0;
|
||||
$h = $img_h;
|
||||
}
|
||||
imagecopy($bg, $src, $dst_x, $dst_y, $src_x, $src_y, $w, $h);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
else {
|
||||
print 'Unknown repeat!';
|
||||
}
|
||||
|
||||
imagedestroy($src);
|
||||
|
||||
} /* End optimize away creation of duplicates */
|
||||
|
||||
$this->_canvas->clipping_rectangle($x, $y, $box_width, $box_height);
|
||||
|
||||
//img: image url string
|
||||
//img_w, img_h: original image size in px
|
||||
//width, height: box size in pt
|
||||
//bg_width, bg_height: box size in px
|
||||
//x, y: left/top edge of box on page in pt
|
||||
//start_x, start_y: placement of image relative to pattern
|
||||
//$repeat: repeat mode
|
||||
//$bg: GD object of result image
|
||||
//$src: GD object of original image
|
||||
//When using cpdf and optimization to direct png creation from gd object is available,
|
||||
//don't create temp file, but place gd object directly into the pdf
|
||||
if ( !$is_png && $this->_canvas instanceof CPDF_Adapter ) {
|
||||
// Note: CPDF_Adapter image converts y position
|
||||
$this->_canvas->get_cpdf()->addImagePng($filedummy, $x, $this->_canvas->get_height() - $y - $height, $width, $height, $bg);
|
||||
}
|
||||
|
||||
else {
|
||||
$tmp_dir = $this->_dompdf->get_option("temp_dir");
|
||||
$tmp_name = tempnam($tmp_dir, "bg_dompdf_img_");
|
||||
@unlink($tmp_name);
|
||||
$tmp_file = "$tmp_name.png";
|
||||
|
||||
//debugpng
|
||||
if (DEBUGPNG) print '[_background_image '.$tmp_file.']';
|
||||
|
||||
imagepng($bg, $tmp_file);
|
||||
$this->_canvas->image($tmp_file, $x, $y, $width, $height);
|
||||
imagedestroy($bg);
|
||||
|
||||
//debugpng
|
||||
if (DEBUGPNG) print '[_background_image unlink '.$tmp_file.']';
|
||||
|
||||
if (!DEBUGKEEPTEMP) {
|
||||
unlink($tmp_file);
|
||||
}
|
||||
}
|
||||
|
||||
$this->_canvas->clipping_end();
|
||||
}
|
||||
|
||||
protected function _get_dash_pattern($style, $width) {
|
||||
$pattern = array();
|
||||
|
||||
switch ($style) {
|
||||
default:
|
||||
/*case "solid":
|
||||
case "double":
|
||||
case "groove":
|
||||
case "inset":
|
||||
case "outset":
|
||||
case "ridge":*/
|
||||
case "none": break;
|
||||
|
||||
case "dotted":
|
||||
if ( $width <= 1 )
|
||||
$pattern = array($width, $width*2);
|
||||
else
|
||||
$pattern = array($width);
|
||||
break;
|
||||
|
||||
case "dashed":
|
||||
$pattern = array(3 * $width);
|
||||
break;
|
||||
}
|
||||
|
||||
return $pattern;
|
||||
}
|
||||
|
||||
protected function _border_none($x, $y, $length, $color, $widths, $side, $corner_style = "bevel", $r1 = 0, $r2 = 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
protected function _border_hidden($x, $y, $length, $color, $widths, $side, $corner_style = "bevel", $r1 = 0, $r2 = 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Border rendering functions
|
||||
|
||||
protected function _border_dotted($x, $y, $length, $color, $widths, $side, $corner_style = "bevel", $r1 = 0, $r2 = 0) {
|
||||
$this->_border_line($x, $y, $length, $color, $widths, $side, $corner_style, "dotted", $r1, $r2);
|
||||
}
|
||||
|
||||
|
||||
protected function _border_dashed($x, $y, $length, $color, $widths, $side, $corner_style = "bevel", $r1 = 0, $r2 = 0) {
|
||||
$this->_border_line($x, $y, $length, $color, $widths, $side, $corner_style, "dashed", $r1, $r2);
|
||||
}
|
||||
|
||||
|
||||
protected function _border_solid($x, $y, $length, $color, $widths, $side, $corner_style = "bevel", $r1 = 0, $r2 = 0) {
|
||||
// TODO: Solve rendering where one corner is beveled (radius == 0), one corner isn't.
|
||||
if ( $corner_style !== "bevel" || $r1 > 0 || $r2 > 0 ) {
|
||||
// do it the simple way
|
||||
$this->_border_line($x, $y, $length, $color, $widths, $side, $corner_style, "solid", $r1, $r2);
|
||||
return;
|
||||
}
|
||||
|
||||
list($top, $right, $bottom, $left) = $widths;
|
||||
|
||||
// All this polygon business is for beveled corners...
|
||||
switch ($side) {
|
||||
case "top":
|
||||
$points = array($x, $y,
|
||||
$x + $length, $y,
|
||||
$x + $length - $right, $y + $top,
|
||||
$x + $left, $y + $top);
|
||||
$this->_canvas->polygon($points, $color, null, null, true);
|
||||
break;
|
||||
|
||||
case "bottom":
|
||||
$points = array($x, $y,
|
||||
$x + $length, $y,
|
||||
$x + $length - $right, $y - $bottom,
|
||||
$x + $left, $y - $bottom);
|
||||
$this->_canvas->polygon($points, $color, null, null, true);
|
||||
break;
|
||||
|
||||
case "left":
|
||||
$points = array($x, $y,
|
||||
$x, $y + $length,
|
||||
$x + $left, $y + $length - $bottom,
|
||||
$x + $left, $y + $top);
|
||||
$this->_canvas->polygon($points, $color, null, null, true);
|
||||
break;
|
||||
|
||||
case "right":
|
||||
$points = array($x, $y,
|
||||
$x, $y + $length,
|
||||
$x - $right, $y + $length - $bottom,
|
||||
$x - $right, $y + $top);
|
||||
$this->_canvas->polygon($points, $color, null, null, true);
|
||||
break;
|
||||
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
protected function _apply_ratio($side, $ratio, $top, $right, $bottom, $left, &$x, &$y, &$length, &$r1, &$r2) {
|
||||
switch ($side) {
|
||||
|
||||
case "top":
|
||||
$r1 -= $left * $ratio;
|
||||
$r2 -= $right * $ratio;
|
||||
$x += $left * $ratio;
|
||||
$y += $top * $ratio;
|
||||
$length -= $left * $ratio + $right * $ratio;
|
||||
break;
|
||||
|
||||
case "bottom":
|
||||
$r1 -= $right * $ratio;
|
||||
$r2 -= $left * $ratio;
|
||||
$x += $left * $ratio;
|
||||
$y -= $bottom * $ratio;
|
||||
$length -= $left * $ratio + $right * $ratio;
|
||||
break;
|
||||
|
||||
case "left":
|
||||
$r1 -= $top * $ratio;
|
||||
$r2 -= $bottom * $ratio;
|
||||
$x += $left * $ratio;
|
||||
$y += $top * $ratio;
|
||||
$length -= $top * $ratio + $bottom * $ratio;
|
||||
break;
|
||||
|
||||
case "right":
|
||||
$r1 -= $bottom * $ratio;
|
||||
$r2 -= $top * $ratio;
|
||||
$x -= $right * $ratio;
|
||||
$y += $top * $ratio;
|
||||
$length -= $top * $ratio + $bottom * $ratio;
|
||||
break;
|
||||
|
||||
default:
|
||||
return;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
protected function _border_double($x, $y, $length, $color, $widths, $side, $corner_style = "bevel", $r1 = 0, $r2 = 0) {
|
||||
list($top, $right, $bottom, $left) = $widths;
|
||||
|
||||
$third_widths = array($top / 3, $right / 3, $bottom / 3, $left / 3);
|
||||
|
||||
// draw the outer border
|
||||
$this->_border_solid($x, $y, $length, $color, $third_widths, $side, $corner_style, $r1, $r2);
|
||||
|
||||
$this->_apply_ratio($side, 2/3, $top, $right, $bottom, $left, $x, $y, $length, $r1, $r2);
|
||||
|
||||
$this->_border_solid($x, $y, $length, $color, $third_widths, $side, $corner_style, $r1, $r2);
|
||||
}
|
||||
|
||||
protected function _border_groove($x, $y, $length, $color, $widths, $side, $corner_style = "bevel", $r1 = 0, $r2 = 0) {
|
||||
list($top, $right, $bottom, $left) = $widths;
|
||||
|
||||
$half_widths = array($top / 2, $right / 2, $bottom / 2, $left / 2);
|
||||
|
||||
$this->_border_inset($x, $y, $length, $color, $half_widths, $side, $corner_style, $r1, $r2);
|
||||
|
||||
$this->_apply_ratio($side, 0.5, $top, $right, $bottom, $left, $x, $y, $length, $r1, $r2);
|
||||
|
||||
$this->_border_outset($x, $y, $length, $color, $half_widths, $side, $corner_style, $r1, $r2);
|
||||
|
||||
}
|
||||
|
||||
protected function _border_ridge($x, $y, $length, $color, $widths, $side, $corner_style = "bevel", $r1 = 0, $r2 = 0) {
|
||||
list($top, $right, $bottom, $left) = $widths;
|
||||
|
||||
$half_widths = array($top / 2, $right / 2, $bottom / 2, $left / 2);
|
||||
|
||||
$this->_border_outset($x, $y, $length, $color, $half_widths, $side, $corner_style, $r1, $r2);
|
||||
|
||||
$this->_apply_ratio($side, 0.5, $top, $right, $bottom, $left, $x, $y, $length, $r1, $r2);
|
||||
|
||||
$this->_border_inset($x, $y, $length, $color, $half_widths, $side, $corner_style, $r1, $r2);
|
||||
|
||||
}
|
||||
|
||||
protected function _tint($c) {
|
||||
if ( !is_numeric($c) )
|
||||
return $c;
|
||||
|
||||
return min(1, $c + 0.16);
|
||||
}
|
||||
|
||||
protected function _shade($c) {
|
||||
if ( !is_numeric($c) )
|
||||
return $c;
|
||||
|
||||
return max(0, $c - 0.33);
|
||||
}
|
||||
|
||||
protected function _border_inset($x, $y, $length, $color, $widths, $side, $corner_style = "bevel", $r1 = 0, $r2 = 0) {
|
||||
switch ($side) {
|
||||
case "top":
|
||||
case "left":
|
||||
$shade = array_map(array($this, "_shade"), $color);
|
||||
$this->_border_solid($x, $y, $length, $shade, $widths, $side, $corner_style, $r1, $r2);
|
||||
break;
|
||||
|
||||
case "bottom":
|
||||
case "right":
|
||||
$tint = array_map(array($this, "_tint"), $color);
|
||||
$this->_border_solid($x, $y, $length, $tint, $widths, $side, $corner_style, $r1, $r2);
|
||||
break;
|
||||
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
protected function _border_outset($x, $y, $length, $color, $widths, $side, $corner_style = "bevel", $r1 = 0, $r2 = 0) {
|
||||
switch ($side) {
|
||||
case "top":
|
||||
case "left":
|
||||
$tint = array_map(array($this, "_tint"), $color);
|
||||
$this->_border_solid($x, $y, $length, $tint, $widths, $side, $corner_style, $r1, $r2);
|
||||
break;
|
||||
|
||||
case "bottom":
|
||||
case "right":
|
||||
$shade = array_map(array($this, "_shade"), $color);
|
||||
$this->_border_solid($x, $y, $length, $shade, $widths, $side, $corner_style, $r1, $r2);
|
||||
break;
|
||||
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
// Draws a solid, dotted, or dashed line, observing the border radius
|
||||
protected function _border_line($x, $y, $length, $color, $widths, $side, $corner_style = "bevel", $pattern_name, $r1 = 0, $r2 = 0) {
|
||||
list($top, $right, $bottom, $left) = $widths;
|
||||
|
||||
$width = $$side;
|
||||
$pattern = $this->_get_dash_pattern($pattern_name, $width);
|
||||
|
||||
$half_width = $width/2;
|
||||
$r1 -= $half_width;
|
||||
$r2 -= $half_width;
|
||||
$adjust = $r1/80;
|
||||
$length -= $width;
|
||||
|
||||
switch ($side) {
|
||||
case "top":
|
||||
$x += $half_width;
|
||||
$y += $half_width;
|
||||
|
||||
if ( $r1 > 0 ) {
|
||||
$this->_canvas->arc($x + $r1, $y + $r1, $r1, $r1, 90-$adjust, 135+$adjust, $color, $width, $pattern);
|
||||
}
|
||||
|
||||
$this->_canvas->line($x + $r1, $y, $x + $length - $r2, $y, $color, $width, $pattern);
|
||||
|
||||
if ( $r2 > 0 ) {
|
||||
$this->_canvas->arc($x + $length - $r2, $y + $r2, $r2, $r2, 45-$adjust, 90+$adjust, $color, $width, $pattern);
|
||||
}
|
||||
break;
|
||||
|
||||
case "bottom":
|
||||
$x += $half_width;
|
||||
$y -= $half_width;
|
||||
|
||||
if ( $r1 > 0 ) {
|
||||
$this->_canvas->arc($x + $r1, $y - $r1, $r1, $r1, 225-$adjust, 270+$adjust, $color, $width, $pattern);
|
||||
}
|
||||
|
||||
$this->_canvas->line($x + $r1, $y, $x + $length - $r2, $y, $color, $width, $pattern);
|
||||
|
||||
if ( $r2 > 0 ) {
|
||||
$this->_canvas->arc($x + $length - $r2, $y - $r2, $r2, $r2, 270-$adjust, 315+$adjust, $color, $width, $pattern);
|
||||
}
|
||||
break;
|
||||
|
||||
case "left":
|
||||
$y += $half_width;
|
||||
$x += $half_width;
|
||||
|
||||
if ( $r1 > 0 ) {
|
||||
$this->_canvas->arc($x + $r1, $y + $r1, $r1, $r1, 135-$adjust, 180+$adjust, $color, $width, $pattern);
|
||||
}
|
||||
|
||||
$this->_canvas->line($x, $y + $r1, $x, $y + $length - $r2, $color, $width, $pattern);
|
||||
|
||||
if ( $r2 > 0 ) {
|
||||
$this->_canvas->arc($x + $r2, $y + $length - $r2, $r2, $r2, 180-$adjust, 225+$adjust, $color, $width, $pattern);
|
||||
}
|
||||
break;
|
||||
|
||||
case "right":
|
||||
$y += $half_width;
|
||||
$x -= $half_width;
|
||||
|
||||
if ( $r1 > 0 ) {
|
||||
$this->_canvas->arc($x - $r1, $y + $r1, $r1, $r1, 0-$adjust, 45+$adjust, $color, $width, $pattern);
|
||||
}
|
||||
|
||||
$this->_canvas->line($x, $y + $r1, $x, $y + $length - $r2, $color, $width, $pattern);
|
||||
|
||||
if ( $r2 > 0 ) {
|
||||
$this->_canvas->arc($x - $r2, $y + $length - $r2, $r2, $r2, 315-$adjust, 360+$adjust, $color, $width, $pattern);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
protected function _set_opacity($opacity) {
|
||||
if ( is_numeric($opacity) && $opacity <= 1.0 && $opacity >= 0.0 ) {
|
||||
$this->_canvas->set_opacity( $opacity );
|
||||
}
|
||||
}
|
||||
|
||||
protected function _debug_layout($box, $color = "red", $style = array()) {
|
||||
$this->_canvas->rectangle($box[0], $box[1], $box[2], $box[3], CSS_Color::parse($color), 0.1, $style);
|
||||
}
|
||||
}
|
||||
592
application/helpers/dompdf/include/attribute_translator.cls.php
Executable file
592
application/helpers/dompdf/include/attribute_translator.cls.php
Executable file
@@ -0,0 +1,592 @@
|
||||
<?php
|
||||
/**
|
||||
* @package dompdf
|
||||
* @link http://dompdf.github.com/
|
||||
* @author Benj Carson <benjcarson@digitaljunkies.ca>
|
||||
* @author Fabien Ménager <fabien.menager@gmail.com>
|
||||
* @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
|
||||
*/
|
||||
|
||||
/**
|
||||
* Translates HTML 4.0 attributes into CSS rules
|
||||
*
|
||||
* @package dompdf
|
||||
*/
|
||||
class Attribute_Translator {
|
||||
static $_style_attr = "_html_style_attribute";
|
||||
|
||||
// Munged data originally from
|
||||
// http://www.w3.org/TR/REC-html40/index/attributes.html
|
||||
// http://www.cs.tut.fi/~jkorpela/html2css.html
|
||||
static private $__ATTRIBUTE_LOOKUP = array(
|
||||
//'caption' => array ( 'align' => '', ),
|
||||
'img' => array(
|
||||
'align' => array(
|
||||
'bottom' => 'vertical-align: baseline;',
|
||||
'middle' => 'vertical-align: middle;',
|
||||
'top' => 'vertical-align: top;',
|
||||
'left' => 'float: left;',
|
||||
'right' => 'float: right;'
|
||||
),
|
||||
'border' => 'border: %0.2F px solid;',
|
||||
'height' => 'height: %s px;',
|
||||
'hspace' => 'padding-left: %1$0.2F px; padding-right: %1$0.2F px;',
|
||||
'vspace' => 'padding-top: %1$0.2F px; padding-bottom: %1$0.2F px;',
|
||||
'width' => 'width: %s px;',
|
||||
),
|
||||
'table' => array(
|
||||
'align' => array(
|
||||
'left' => 'margin-left: 0; margin-right: auto;',
|
||||
'center' => 'margin-left: auto; margin-right: auto;',
|
||||
'right' => 'margin-left: auto; margin-right: 0;'
|
||||
),
|
||||
'bgcolor' => 'background-color: %s;',
|
||||
'border' => '!set_table_border',
|
||||
'cellpadding' => '!set_table_cellpadding',//'border-spacing: %0.2F; border-collapse: separate;',
|
||||
'cellspacing' => '!set_table_cellspacing',
|
||||
'frame' => array(
|
||||
'void' => 'border-style: none;',
|
||||
'above' => 'border-top-style: solid;',
|
||||
'below' => 'border-bottom-style: solid;',
|
||||
'hsides' => 'border-left-style: solid; border-right-style: solid;',
|
||||
'vsides' => 'border-top-style: solid; border-bottom-style: solid;',
|
||||
'lhs' => 'border-left-style: solid;',
|
||||
'rhs' => 'border-right-style: solid;',
|
||||
'box' => 'border-style: solid;',
|
||||
'border' => 'border-style: solid;'
|
||||
),
|
||||
'rules' => '!set_table_rules',
|
||||
'width' => 'width: %s;',
|
||||
),
|
||||
'hr' => array(
|
||||
'align' => '!set_hr_align', // Need to grab width to set 'left' & 'right' correctly
|
||||
'noshade' => 'border-style: solid;',
|
||||
'size' => '!set_hr_size', //'border-width: %0.2F px;',
|
||||
'width' => 'width: %s;',
|
||||
),
|
||||
'div' => array(
|
||||
'align' => 'text-align: %s;',
|
||||
),
|
||||
'h1' => array(
|
||||
'align' => 'text-align: %s;',
|
||||
),
|
||||
'h2' => array(
|
||||
'align' => 'text-align: %s;',
|
||||
),
|
||||
'h3' => array(
|
||||
'align' => 'text-align: %s;',
|
||||
),
|
||||
'h4' => array(
|
||||
'align' => 'text-align: %s;',
|
||||
),
|
||||
'h5' => array(
|
||||
'align' => 'text-align: %s;',
|
||||
),
|
||||
'h6' => array(
|
||||
'align' => 'text-align: %s;',
|
||||
),
|
||||
'p' => array(
|
||||
'align' => 'text-align: %s;',
|
||||
),
|
||||
// 'col' => array(
|
||||
// 'align' => '',
|
||||
// 'valign' => '',
|
||||
// ),
|
||||
// 'colgroup' => array(
|
||||
// 'align' => '',
|
||||
// 'valign' => '',
|
||||
// ),
|
||||
'tbody' => array(
|
||||
'align' => '!set_table_row_align',
|
||||
'valign' => '!set_table_row_valign',
|
||||
),
|
||||
'td' => array(
|
||||
'align' => 'text-align: %s;',
|
||||
'bgcolor' => '!set_background_color',
|
||||
'height' => 'height: %s;',
|
||||
'nowrap' => 'white-space: nowrap;',
|
||||
'valign' => 'vertical-align: %s;',
|
||||
'width' => 'width: %s;',
|
||||
),
|
||||
'tfoot' => array(
|
||||
'align' => '!set_table_row_align',
|
||||
'valign' => '!set_table_row_valign',
|
||||
),
|
||||
'th' => array(
|
||||
'align' => 'text-align: %s;',
|
||||
'bgcolor' => '!set_background_color',
|
||||
'height' => 'height: %s;',
|
||||
'nowrap' => 'white-space: nowrap;',
|
||||
'valign' => 'vertical-align: %s;',
|
||||
'width' => 'width: %s;',
|
||||
),
|
||||
'thead' => array(
|
||||
'align' => '!set_table_row_align',
|
||||
'valign' => '!set_table_row_valign',
|
||||
),
|
||||
'tr' => array(
|
||||
'align' => '!set_table_row_align',
|
||||
'bgcolor' => '!set_table_row_bgcolor',
|
||||
'valign' => '!set_table_row_valign',
|
||||
),
|
||||
'body' => array(
|
||||
'background' => 'background-image: url(%s);',
|
||||
'bgcolor' => '!set_background_color',
|
||||
'link' => '!set_body_link',
|
||||
'text' => '!set_color',
|
||||
),
|
||||
'br' => array(
|
||||
'clear' => 'clear: %s;',
|
||||
),
|
||||
'basefont' => array(
|
||||
'color' => '!set_color',
|
||||
'face' => 'font-family: %s;',
|
||||
'size' => '!set_basefont_size',
|
||||
),
|
||||
'font' => array(
|
||||
'color' => '!set_color',
|
||||
'face' => 'font-family: %s;',
|
||||
'size' => '!set_font_size',
|
||||
),
|
||||
'dir' => array(
|
||||
'compact' => 'margin: 0.5em 0;',
|
||||
),
|
||||
'dl' => array(
|
||||
'compact' => 'margin: 0.5em 0;',
|
||||
),
|
||||
'menu' => array(
|
||||
'compact' => 'margin: 0.5em 0;',
|
||||
),
|
||||
'ol' => array(
|
||||
'compact' => 'margin: 0.5em 0;',
|
||||
'start' => 'counter-reset: -dompdf-default-counter %d;',
|
||||
'type' => 'list-style-type: %s;',
|
||||
),
|
||||
'ul' => array(
|
||||
'compact' => 'margin: 0.5em 0;',
|
||||
'type' => 'list-style-type: %s;',
|
||||
),
|
||||
'li' => array(
|
||||
'type' => 'list-style-type: %s;',
|
||||
'value' => 'counter-reset: -dompdf-default-counter %d;',
|
||||
),
|
||||
'pre' => array(
|
||||
'width' => 'width: %s;',
|
||||
),
|
||||
);
|
||||
|
||||
static protected $_last_basefont_size = 3;
|
||||
static protected $_font_size_lookup = array(
|
||||
// For basefont support
|
||||
-3 => "4pt",
|
||||
-2 => "5pt",
|
||||
-1 => "6pt",
|
||||
0 => "7pt",
|
||||
|
||||
1 => "8pt",
|
||||
2 => "10pt",
|
||||
3 => "12pt",
|
||||
4 => "14pt",
|
||||
5 => "18pt",
|
||||
6 => "24pt",
|
||||
7 => "34pt",
|
||||
|
||||
// For basefont support
|
||||
8 => "48pt",
|
||||
9 => "44pt",
|
||||
10 => "52pt",
|
||||
11 => "60pt",
|
||||
);
|
||||
|
||||
/**
|
||||
* @param Frame $frame
|
||||
*/
|
||||
static function translate_attributes(Frame $frame) {
|
||||
$node = $frame->get_node();
|
||||
$tag = $node->nodeName;
|
||||
|
||||
if ( !isset(self::$__ATTRIBUTE_LOOKUP[$tag]) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$valid_attrs = self::$__ATTRIBUTE_LOOKUP[$tag];
|
||||
$attrs = $node->attributes;
|
||||
$style = rtrim($node->getAttribute(self::$_style_attr), "; ");
|
||||
if ( $style != "" ) {
|
||||
$style .= ";";
|
||||
}
|
||||
|
||||
foreach ($attrs as $attr => $attr_node ) {
|
||||
if ( !isset($valid_attrs[$attr]) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$value = $attr_node->value;
|
||||
|
||||
$target = $valid_attrs[$attr];
|
||||
|
||||
// Look up $value in $target, if $target is an array:
|
||||
if ( is_array($target) ) {
|
||||
if ( isset($target[$value]) ) {
|
||||
$style .= " " . self::_resolve_target($node, $target[$value], $value);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// otherwise use target directly
|
||||
$style .= " " . self::_resolve_target($node, $target, $value);
|
||||
}
|
||||
}
|
||||
|
||||
if ( !is_null($style) ) {
|
||||
$style = ltrim($style);
|
||||
$node->setAttribute(self::$_style_attr, $style);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param DOMNode $node
|
||||
* @param string $target
|
||||
* @param string $value
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
static protected function _resolve_target(DOMNode $node, $target, $value) {
|
||||
if ( $target[0] === "!" ) {
|
||||
// Function call
|
||||
$func = "_" . mb_substr($target, 1);
|
||||
return self::$func($node, $value);
|
||||
}
|
||||
|
||||
return $value ? sprintf($target, $value) : "";
|
||||
}
|
||||
|
||||
/**
|
||||
* @param DOMElement $node
|
||||
* @param string $new_style
|
||||
*/
|
||||
static function append_style(DOMElement $node, $new_style) {
|
||||
$style = rtrim($node->getAttribute(self::$_style_attr), ";");
|
||||
$style .= $new_style;
|
||||
$style = ltrim($style, ";");
|
||||
$node->setAttribute(self::$_style_attr, $style);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param DOMNode $node
|
||||
*
|
||||
* @return DOMNodeList|DOMElement[]
|
||||
*/
|
||||
static protected function get_cell_list(DOMNode $node) {
|
||||
$xpath = new DOMXpath($node->ownerDocument);
|
||||
|
||||
switch($node->nodeName) {
|
||||
default:
|
||||
case "table":
|
||||
$query = "tr/td | thead/tr/td | tbody/tr/td | tfoot/tr/td | tr/th | thead/tr/th | tbody/tr/th | tfoot/tr/th";
|
||||
break;
|
||||
|
||||
case "tbody":
|
||||
case "tfoot":
|
||||
case "thead":
|
||||
$query = "tr/td | tr/th";
|
||||
break;
|
||||
|
||||
case "tr":
|
||||
$query = "td | th";
|
||||
break;
|
||||
}
|
||||
|
||||
return $xpath->query($query, $node);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $value
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
static protected function _get_valid_color($value) {
|
||||
if ( preg_match('/^#?([0-9A-F]{6})$/i', $value, $matches) ) {
|
||||
$value = "#$matches[1]";
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param DOMElement $node
|
||||
* @param string $value
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
static protected function _set_color(DOMElement $node, $value) {
|
||||
$value = self::_get_valid_color($value);
|
||||
return "color: $value;";
|
||||
}
|
||||
|
||||
/**
|
||||
* @param DOMElement $node
|
||||
* @param string $value
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
static protected function _set_background_color(DOMElement $node, $value) {
|
||||
$value = self::_get_valid_color($value);
|
||||
return "background-color: $value;";
|
||||
}
|
||||
|
||||
/**
|
||||
* @param DOMElement $node
|
||||
* @param string $value
|
||||
*
|
||||
* @return null
|
||||
*/
|
||||
static protected function _set_table_cellpadding(DOMElement $node, $value) {
|
||||
$cell_list = self::get_cell_list($node);
|
||||
|
||||
foreach ($cell_list as $cell) {
|
||||
self::append_style($cell, "; padding: {$value}px;");
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param DOMElement $node
|
||||
* @param string $value
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
static protected function _set_table_border(DOMElement $node, $value) {
|
||||
$cell_list = self::get_cell_list($node);
|
||||
|
||||
foreach ($cell_list as $cell) {
|
||||
$style = rtrim($cell->getAttribute(self::$_style_attr));
|
||||
$style .= "; border-width: " . ($value > 0 ? 1 : 0) . "pt; border-style: inset;";
|
||||
$style = ltrim($style, ";");
|
||||
$cell->setAttribute(self::$_style_attr, $style);
|
||||
}
|
||||
|
||||
$style = rtrim($node->getAttribute(self::$_style_attr), ";");
|
||||
$style .= "; border-width: $value" . "px; ";
|
||||
return ltrim($style, "; ");
|
||||
}
|
||||
|
||||
/**
|
||||
* @param DOMElement $node
|
||||
* @param string $value
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
static protected function _set_table_cellspacing(DOMElement $node, $value) {
|
||||
$style = rtrim($node->getAttribute(self::$_style_attr), ";");
|
||||
|
||||
if ( $value == 0 ) {
|
||||
$style .= "; border-collapse: collapse;";
|
||||
}
|
||||
else {
|
||||
$style .= "; border-spacing: {$value}px; border-collapse: separate;";
|
||||
}
|
||||
|
||||
return ltrim($style, ";");
|
||||
}
|
||||
|
||||
/**
|
||||
* @param DOMElement $node
|
||||
* @param string $value
|
||||
*
|
||||
* @return null|string
|
||||
*/
|
||||
static protected function _set_table_rules(DOMElement $node, $value) {
|
||||
$new_style = "; border-collapse: collapse;";
|
||||
|
||||
switch ($value) {
|
||||
case "none":
|
||||
$new_style .= "border-style: none;";
|
||||
break;
|
||||
|
||||
case "groups":
|
||||
// FIXME: unsupported
|
||||
return null;
|
||||
|
||||
case "rows":
|
||||
$new_style .= "border-style: solid none solid none; border-width: 1px; ";
|
||||
break;
|
||||
|
||||
case "cols":
|
||||
$new_style .= "border-style: none solid none solid; border-width: 1px; ";
|
||||
break;
|
||||
|
||||
case "all":
|
||||
$new_style .= "border-style: solid; border-width: 1px; ";
|
||||
break;
|
||||
|
||||
default:
|
||||
// Invalid value
|
||||
return null;
|
||||
}
|
||||
|
||||
$cell_list = self::get_cell_list($node);
|
||||
|
||||
foreach ($cell_list as $cell) {
|
||||
$style = $cell->getAttribute(self::$_style_attr);
|
||||
$style .= $new_style;
|
||||
$cell->setAttribute(self::$_style_attr, $style);
|
||||
}
|
||||
|
||||
$style = rtrim($node->getAttribute(self::$_style_attr), ";");
|
||||
$style .= "; border-collapse: collapse; ";
|
||||
|
||||
return ltrim($style, "; ");
|
||||
}
|
||||
|
||||
/**
|
||||
* @param DOMElement $node
|
||||
* @param string $value
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
static protected function _set_hr_size(DOMElement $node, $value) {
|
||||
$style = rtrim($node->getAttribute(self::$_style_attr), ";");
|
||||
$style .= "; border-width: ".max(0, $value-2)."; ";
|
||||
return ltrim($style, "; ");
|
||||
}
|
||||
|
||||
/**
|
||||
* @param DOMElement $node
|
||||
* @param string $value
|
||||
*
|
||||
* @return null|string
|
||||
*/
|
||||
static protected function _set_hr_align(DOMElement $node, $value) {
|
||||
$style = rtrim($node->getAttribute(self::$_style_attr),";");
|
||||
$width = $node->getAttribute("width");
|
||||
|
||||
if ( $width == "" ) {
|
||||
$width = "100%";
|
||||
}
|
||||
|
||||
$remainder = 100 - (double)rtrim($width, "% ");
|
||||
|
||||
switch ($value) {
|
||||
case "left":
|
||||
$style .= "; margin-right: $remainder %;";
|
||||
break;
|
||||
|
||||
case "right":
|
||||
$style .= "; margin-left: $remainder %;";
|
||||
break;
|
||||
|
||||
case "center":
|
||||
$style .= "; margin-left: auto; margin-right: auto;";
|
||||
break;
|
||||
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
|
||||
return ltrim($style, "; ");
|
||||
}
|
||||
|
||||
/**
|
||||
* @param DOMElement $node
|
||||
* @param string $value
|
||||
*
|
||||
* @return null
|
||||
*/
|
||||
static protected function _set_table_row_align(DOMElement $node, $value) {
|
||||
$cell_list = self::get_cell_list($node);
|
||||
|
||||
foreach ($cell_list as $cell) {
|
||||
self::append_style($cell, "; text-align: $value;");
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param DOMElement $node
|
||||
* @param string $value
|
||||
*
|
||||
* @return null
|
||||
*/
|
||||
static protected function _set_table_row_valign(DOMElement $node, $value) {
|
||||
$cell_list = self::get_cell_list($node);
|
||||
|
||||
foreach ($cell_list as $cell) {
|
||||
self::append_style($cell, "; vertical-align: $value;");
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param DOMElement $node
|
||||
* @param string $value
|
||||
*
|
||||
* @return null
|
||||
*/
|
||||
static protected function _set_table_row_bgcolor(DOMElement $node, $value) {
|
||||
$cell_list = self::get_cell_list($node);
|
||||
$value = self::_get_valid_color($value);
|
||||
|
||||
foreach ($cell_list as $cell) {
|
||||
self::append_style($cell, "; background-color: $value;");
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param DOMElement $node
|
||||
* @param string $value
|
||||
*
|
||||
* @return null
|
||||
*/
|
||||
static protected function _set_body_link(DOMElement $node, $value) {
|
||||
$a_list = $node->getElementsByTagName("a");
|
||||
$value = self::_get_valid_color($value);
|
||||
|
||||
foreach ($a_list as $a) {
|
||||
self::append_style($a, "; color: $value;");
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param DOMElement $node
|
||||
* @param string $value
|
||||
*
|
||||
* @return null
|
||||
*/
|
||||
static protected function _set_basefont_size(DOMElement $node, $value) {
|
||||
// FIXME: ? we don't actually set the font size of anything here, just
|
||||
// the base size for later modification by <font> tags.
|
||||
self::$_last_basefont_size = $value;
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param DOMElement $node
|
||||
* @param string $value
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
static protected function _set_font_size(DOMElement $node, $value) {
|
||||
$style = $node->getAttribute(self::$_style_attr);
|
||||
|
||||
if ( $value[0] === "-" || $value[0] === "+" ) {
|
||||
$value = self::$_last_basefont_size + (int)$value;
|
||||
}
|
||||
|
||||
if ( isset(self::$_font_size_lookup[$value]) ) {
|
||||
$style .= "; font-size: " . self::$_font_size_lookup[$value] . ";";
|
||||
}
|
||||
else {
|
||||
$style .= "; font-size: $value;";
|
||||
}
|
||||
|
||||
return ltrim($style, "; ");
|
||||
}
|
||||
}
|
||||
86
application/helpers/dompdf/include/autoload.inc.php
Executable file
86
application/helpers/dompdf/include/autoload.inc.php
Executable file
@@ -0,0 +1,86 @@
|
||||
<?php
|
||||
/**
|
||||
* @package dompdf
|
||||
* @link http://dompdf.github.com/
|
||||
* @author Benj Carson <benjcarson@digitaljunkies.ca>
|
||||
* @author Fabien Ménager <fabien.menager@gmail.com>
|
||||
* @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
|
||||
*/
|
||||
|
||||
/**
|
||||
* DOMPDF autoload function
|
||||
*
|
||||
* If you have an existing autoload function, add a call to this function
|
||||
* from your existing __autoload() implementation.
|
||||
*
|
||||
* @param string $class
|
||||
*/
|
||||
function DOMPDF_autoload($class) {
|
||||
$filename = DOMPDF_INC_DIR . "/" . mb_strtolower($class) . ".cls.php";
|
||||
|
||||
if ( is_file($filename) ) {
|
||||
include_once $filename;
|
||||
}
|
||||
}
|
||||
|
||||
// If SPL autoload functions are available (PHP >= 5.1.2)
|
||||
if ( function_exists("spl_autoload_register") ) {
|
||||
$autoload = "DOMPDF_autoload";
|
||||
$funcs = spl_autoload_functions();
|
||||
|
||||
// No functions currently in the stack.
|
||||
if ( !DOMPDF_AUTOLOAD_PREPEND || $funcs === false ) {
|
||||
spl_autoload_register($autoload);
|
||||
}
|
||||
|
||||
// If PHP >= 5.3 the $prepend argument is available
|
||||
else if ( PHP_VERSION_ID >= 50300 ) {
|
||||
spl_autoload_register($autoload, true, true);
|
||||
}
|
||||
|
||||
else {
|
||||
// Unregister existing autoloaders...
|
||||
$compat = (PHP_VERSION_ID <= 50102 && PHP_VERSION_ID >= 50100);
|
||||
|
||||
foreach ($funcs as $func) {
|
||||
if (is_array($func)) {
|
||||
// :TRICKY: There are some compatibility issues and some
|
||||
// places where we need to error out
|
||||
$reflector = new ReflectionMethod($func[0], $func[1]);
|
||||
if (!$reflector->isStatic()) {
|
||||
throw new Exception('This function is not compatible with non-static object methods due to PHP Bug #44144.');
|
||||
}
|
||||
|
||||
// Suprisingly, spl_autoload_register supports the
|
||||
// Class::staticMethod callback format, although call_user_func doesn't
|
||||
if ($compat) $func = implode('::', $func);
|
||||
}
|
||||
|
||||
spl_autoload_unregister($func);
|
||||
}
|
||||
|
||||
// Register the new one, thus putting it at the front of the stack...
|
||||
spl_autoload_register($autoload);
|
||||
|
||||
// Now, go back and re-register all of our old ones.
|
||||
foreach ($funcs as $func) {
|
||||
spl_autoload_register($func);
|
||||
}
|
||||
|
||||
// Be polite and ensure that userland autoload gets retained
|
||||
if ( function_exists("__autoload") ) {
|
||||
spl_autoload_register("__autoload");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
else if ( !function_exists("__autoload") ) {
|
||||
/**
|
||||
* Default __autoload() function
|
||||
*
|
||||
* @param string $class
|
||||
*/
|
||||
function __autoload($class) {
|
||||
DOMPDF_autoload($class);
|
||||
}
|
||||
}
|
||||
234
application/helpers/dompdf/include/block_frame_decorator.cls.php
Executable file
234
application/helpers/dompdf/include/block_frame_decorator.cls.php
Executable file
@@ -0,0 +1,234 @@
|
||||
<?php
|
||||
/**
|
||||
* @package dompdf
|
||||
* @link http://dompdf.github.com/
|
||||
* @author Benj Carson <benjcarson@digitaljunkies.ca>
|
||||
* @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
|
||||
*/
|
||||
|
||||
/**
|
||||
* Decorates frames for block layout
|
||||
*
|
||||
* @access private
|
||||
* @package dompdf
|
||||
*/
|
||||
class Block_Frame_Decorator extends Frame_Decorator {
|
||||
/**
|
||||
* Current line index
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $_cl;
|
||||
|
||||
/**
|
||||
* The block's line boxes
|
||||
*
|
||||
* @var Line_Box[]
|
||||
*/
|
||||
protected $_line_boxes;
|
||||
|
||||
function __construct(Frame $frame, DOMPDF $dompdf) {
|
||||
parent::__construct($frame, $dompdf);
|
||||
|
||||
$this->_line_boxes = array(new Line_Box($this));
|
||||
$this->_cl = 0;
|
||||
}
|
||||
|
||||
function reset() {
|
||||
parent::reset();
|
||||
|
||||
$this->_line_boxes = array(new Line_Box($this));
|
||||
$this->_cl = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Line_Box
|
||||
*/
|
||||
function get_current_line_box() {
|
||||
return $this->_line_boxes[$this->_cl];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return integer
|
||||
*/
|
||||
function get_current_line_number() {
|
||||
return $this->_cl;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Line_Box[]
|
||||
*/
|
||||
function get_line_boxes() {
|
||||
return $this->_line_boxes;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param integer $i
|
||||
*/
|
||||
function clear_line($i) {
|
||||
if ( isset($this->_line_boxes[$i]) ) {
|
||||
unset($this->_line_boxes[$i]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Frame $frame
|
||||
*/
|
||||
function add_frame_to_line(Frame $frame) {
|
||||
if ( !$frame->is_in_flow() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$style = $frame->get_style();
|
||||
|
||||
$frame->set_containing_line($this->_line_boxes[$this->_cl]);
|
||||
|
||||
/*
|
||||
// Adds a new line after a block, only if certain conditions are met
|
||||
if ((($frame instanceof Inline_Frame_Decorator && $frame->get_node()->nodeName !== "br") ||
|
||||
$frame instanceof Text_Frame_Decorator && trim($frame->get_text())) &&
|
||||
($frame->get_prev_sibling() && $frame->get_prev_sibling()->get_style()->display === "block" &&
|
||||
$this->_line_boxes[$this->_cl]->w > 0 )) {
|
||||
|
||||
$this->maximize_line_height( $style->length_in_pt($style->line_height), $frame );
|
||||
$this->add_line();
|
||||
|
||||
// Add each child of the inline frame to the line individually
|
||||
foreach ($frame->get_children() as $child)
|
||||
$this->add_frame_to_line( $child );
|
||||
}
|
||||
else*/
|
||||
|
||||
// Handle inline frames (which are effectively wrappers)
|
||||
if ( $frame instanceof Inline_Frame_Decorator ) {
|
||||
|
||||
// Handle line breaks
|
||||
if ( $frame->get_node()->nodeName === "br" ) {
|
||||
$this->maximize_line_height( $style->length_in_pt($style->line_height), $frame );
|
||||
$this->add_line(true);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Trim leading text if this is an empty line. Kinda a hack to put it here,
|
||||
// but what can you do...
|
||||
if ( $this->get_current_line_box()->w == 0 &&
|
||||
$frame->is_text_node() &&
|
||||
!$frame->is_pre() ) {
|
||||
|
||||
$frame->set_text( ltrim($frame->get_text()) );
|
||||
$frame->recalculate_width();
|
||||
}
|
||||
|
||||
$w = $frame->get_margin_width();
|
||||
|
||||
if ( $w == 0 ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Debugging code:
|
||||
/*
|
||||
pre_r("\n<h3>Adding frame to line:</h3>");
|
||||
|
||||
// pre_r("Me: " . $this->get_node()->nodeName . " (" . spl_object_hash($this->get_node()) . ")");
|
||||
// pre_r("Node: " . $frame->get_node()->nodeName . " (" . spl_object_hash($frame->get_node()) . ")");
|
||||
if ( $frame->is_text_node() )
|
||||
pre_r('"'.$frame->get_node()->nodeValue.'"');
|
||||
|
||||
pre_r("Line width: " . $this->_line_boxes[$this->_cl]->w);
|
||||
pre_r("Frame: " . get_class($frame));
|
||||
pre_r("Frame width: " . $w);
|
||||
pre_r("Frame height: " . $frame->get_margin_height());
|
||||
pre_r("Containing block width: " . $this->get_containing_block("w"));
|
||||
*/
|
||||
// End debugging
|
||||
|
||||
$line = $this->_line_boxes[$this->_cl];
|
||||
if ( $line->left + $line->w + $line->right + $w > $this->get_containing_block("w")) {
|
||||
$this->add_line();
|
||||
}
|
||||
|
||||
$frame->position();
|
||||
|
||||
$current_line = $this->_line_boxes[$this->_cl];
|
||||
$current_line->add_frame($frame);
|
||||
|
||||
if ( $frame->is_text_node() ) {
|
||||
$current_line->wc += count(preg_split("/\s+/", trim($frame->get_text())));
|
||||
}
|
||||
|
||||
$this->increase_line_width($w);
|
||||
|
||||
$this->maximize_line_height($frame->get_margin_height(), $frame);
|
||||
}
|
||||
|
||||
function remove_frames_from_line(Frame $frame) {
|
||||
// Search backwards through the lines for $frame
|
||||
$i = $this->_cl;
|
||||
$j = null;
|
||||
|
||||
while ($i >= 0) {
|
||||
if ( ($j = in_array($frame, $this->_line_boxes[$i]->get_frames(), true)) !== false ) {
|
||||
break;
|
||||
}
|
||||
|
||||
$i--;
|
||||
}
|
||||
|
||||
if ( $j === false ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Remove $frame and all frames that follow
|
||||
while ($j < count($this->_line_boxes[$i]->get_frames())) {
|
||||
$frames = $this->_line_boxes[$i]->get_frames();
|
||||
$f = $frames[$j];
|
||||
$frames[$j] = null;
|
||||
unset($frames[$j]);
|
||||
$j++;
|
||||
$this->_line_boxes[$i]->w -= $f->get_margin_width();
|
||||
}
|
||||
|
||||
// Recalculate the height of the line
|
||||
$h = 0;
|
||||
foreach ($this->_line_boxes[$i]->get_frames() as $f) {
|
||||
$h = max( $h, $f->get_margin_height() );
|
||||
}
|
||||
|
||||
$this->_line_boxes[$i]->h = $h;
|
||||
|
||||
// Remove all lines that follow
|
||||
while ($this->_cl > $i) {
|
||||
$this->_line_boxes[ $this->_cl ] = null;
|
||||
unset($this->_line_boxes[ $this->_cl ]);
|
||||
$this->_cl--;
|
||||
}
|
||||
}
|
||||
|
||||
function increase_line_width($w) {
|
||||
$this->_line_boxes[ $this->_cl ]->w += $w;
|
||||
}
|
||||
|
||||
function maximize_line_height($val, Frame $frame) {
|
||||
if ( $val > $this->_line_boxes[ $this->_cl ]->h ) {
|
||||
$this->_line_boxes[ $this->_cl ]->tallest_frame = $frame;
|
||||
$this->_line_boxes[ $this->_cl ]->h = $val;
|
||||
}
|
||||
}
|
||||
|
||||
function add_line($br = false) {
|
||||
|
||||
// if ( $this->_line_boxes[$this->_cl]["h"] == 0 ) //count($this->_line_boxes[$i]["frames"]) == 0 ||
|
||||
// return;
|
||||
|
||||
$this->_line_boxes[$this->_cl]->br = $br;
|
||||
$y = $this->_line_boxes[$this->_cl]->y + $this->_line_boxes[$this->_cl]->h;
|
||||
|
||||
$new_line = new Line_Box($this, $y);
|
||||
|
||||
$this->_line_boxes[ ++$this->_cl ] = $new_line;
|
||||
}
|
||||
|
||||
//........................................................................
|
||||
}
|
||||
805
application/helpers/dompdf/include/block_frame_reflower.cls.php
Executable file
805
application/helpers/dompdf/include/block_frame_reflower.cls.php
Executable file
@@ -0,0 +1,805 @@
|
||||
<?php
|
||||
/**
|
||||
* @package dompdf
|
||||
* @link http://dompdf.github.com/
|
||||
* @author Benj Carson <benjcarson@digitaljunkies.ca>
|
||||
* @author Fabien Ménager <fabien.menager@gmail.com>
|
||||
* @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
|
||||
*/
|
||||
|
||||
/**
|
||||
* Reflows block frames
|
||||
*
|
||||
* @access private
|
||||
* @package dompdf
|
||||
*/
|
||||
class Block_Frame_Reflower extends Frame_Reflower {
|
||||
// Minimum line width to justify, as fraction of available width
|
||||
const MIN_JUSTIFY_WIDTH = 0.80;
|
||||
|
||||
/**
|
||||
* @var Block_Frame_Decorator
|
||||
*/
|
||||
protected $_frame;
|
||||
|
||||
function __construct(Block_Frame_Decorator $frame) { parent::__construct($frame); }
|
||||
|
||||
/**
|
||||
* Calculate the ideal used value for the width property as per:
|
||||
* http://www.w3.org/TR/CSS21/visudet.html#Computing_widths_and_margins
|
||||
*
|
||||
* @param float $width
|
||||
* @return array
|
||||
*/
|
||||
protected function _calculate_width($width) {
|
||||
$frame = $this->_frame;
|
||||
$style = $frame->get_style();
|
||||
$w = $frame->get_containing_block("w");
|
||||
|
||||
if ( $style->position === "fixed" ) {
|
||||
$w = $frame->get_parent()->get_containing_block("w");
|
||||
}
|
||||
|
||||
$rm = $style->length_in_pt($style->margin_right, $w);
|
||||
$lm = $style->length_in_pt($style->margin_left, $w);
|
||||
|
||||
$left = $style->length_in_pt($style->left, $w);
|
||||
$right = $style->length_in_pt($style->right, $w);
|
||||
|
||||
// Handle 'auto' values
|
||||
$dims = array($style->border_left_width,
|
||||
$style->border_right_width,
|
||||
$style->padding_left,
|
||||
$style->padding_right,
|
||||
$width !== "auto" ? $width : 0,
|
||||
$rm !== "auto" ? $rm : 0,
|
||||
$lm !== "auto" ? $lm : 0);
|
||||
|
||||
// absolutely positioned boxes take the 'left' and 'right' properties into account
|
||||
if ( $frame->is_absolute() ) {
|
||||
$absolute = true;
|
||||
$dims[] = $left !== "auto" ? $left : 0;
|
||||
$dims[] = $right !== "auto" ? $right : 0;
|
||||
}
|
||||
else {
|
||||
$absolute = false;
|
||||
}
|
||||
|
||||
$sum = $style->length_in_pt($dims, $w);
|
||||
|
||||
// Compare to the containing block
|
||||
$diff = $w - $sum;
|
||||
|
||||
if ( $diff > 0 ) {
|
||||
|
||||
if ( $absolute ) {
|
||||
|
||||
// resolve auto properties: see
|
||||
// http://www.w3.org/TR/CSS21/visudet.html#abs-non-replaced-width
|
||||
|
||||
if ( $width === "auto" && $left === "auto" && $right === "auto" ) {
|
||||
|
||||
if ( $lm === "auto" ) $lm = 0;
|
||||
if ( $rm === "auto" ) $rm = 0;
|
||||
|
||||
// Technically, the width should be "shrink-to-fit" i.e. based on the
|
||||
// preferred width of the content... a little too costly here as a
|
||||
// special case. Just get the width to take up the slack:
|
||||
$left = 0;
|
||||
$right = 0;
|
||||
$width = $diff;
|
||||
}
|
||||
else if ( $width === "auto" ) {
|
||||
|
||||
if ( $lm === "auto" ) $lm = 0;
|
||||
if ( $rm === "auto" ) $rm = 0;
|
||||
if ( $left === "auto" ) $left = 0;
|
||||
if ( $right === "auto" ) $right = 0;
|
||||
|
||||
$width = $diff;
|
||||
}
|
||||
else if ( $left === "auto" ) {
|
||||
|
||||
if ( $lm === "auto" ) $lm = 0;
|
||||
if ( $rm === "auto" ) $rm = 0;
|
||||
if ( $right === "auto" ) $right = 0;
|
||||
|
||||
$left = $diff;
|
||||
}
|
||||
else if ( $right === "auto" ) {
|
||||
|
||||
if ( $lm === "auto" ) $lm = 0;
|
||||
if ( $rm === "auto" ) $rm = 0;
|
||||
|
||||
$right = $diff;
|
||||
}
|
||||
|
||||
}
|
||||
else {
|
||||
|
||||
// Find auto properties and get them to take up the slack
|
||||
if ( $width === "auto" ) {
|
||||
$width = $diff;
|
||||
}
|
||||
else if ( $lm === "auto" && $rm === "auto" ) {
|
||||
$lm = $rm = round($diff / 2);
|
||||
}
|
||||
else if ( $lm === "auto" ) {
|
||||
$lm = $diff;
|
||||
}
|
||||
else if ( $rm === "auto" ) {
|
||||
$rm = $diff;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
else if ($diff < 0) {
|
||||
|
||||
// We are over constrained--set margin-right to the difference
|
||||
$rm = $diff;
|
||||
|
||||
}
|
||||
|
||||
return array(
|
||||
"width" => $width,
|
||||
"margin_left" => $lm,
|
||||
"margin_right" => $rm,
|
||||
"left" => $left,
|
||||
"right" => $right,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Call the above function, but resolve max/min widths
|
||||
*
|
||||
* @throws DOMPDF_Exception
|
||||
* @return array
|
||||
*/
|
||||
protected function _calculate_restricted_width() {
|
||||
$frame = $this->_frame;
|
||||
$style = $frame->get_style();
|
||||
$cb = $frame->get_containing_block();
|
||||
|
||||
if ( $style->position === "fixed" ) {
|
||||
$cb = $frame->get_root()->get_containing_block();
|
||||
}
|
||||
|
||||
//if ( $style->position === "absolute" )
|
||||
// $cb = $frame->find_positionned_parent()->get_containing_block();
|
||||
|
||||
if ( !isset($cb["w"]) ) {
|
||||
throw new DOMPDF_Exception("Box property calculation requires containing block width");
|
||||
}
|
||||
|
||||
// Treat width 100% as auto
|
||||
if ( $style->width === "100%" ) {
|
||||
$width = "auto";
|
||||
}
|
||||
else {
|
||||
$width = $style->length_in_pt($style->width, $cb["w"]);
|
||||
}
|
||||
|
||||
extract($this->_calculate_width($width));
|
||||
|
||||
// Handle min/max width
|
||||
$min_width = $style->length_in_pt($style->min_width, $cb["w"]);
|
||||
$max_width = $style->length_in_pt($style->max_width, $cb["w"]);
|
||||
|
||||
if ( $max_width !== "none" && $min_width > $max_width ) {
|
||||
list($max_width, $min_width) = array($min_width, $max_width);
|
||||
}
|
||||
|
||||
if ( $max_width !== "none" && $width > $max_width ) {
|
||||
extract($this->_calculate_width($max_width));
|
||||
}
|
||||
|
||||
if ( $width < $min_width ) {
|
||||
extract($this->_calculate_width($min_width));
|
||||
}
|
||||
|
||||
return array($width, $margin_left, $margin_right, $left, $right);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the unrestricted height of content within the block
|
||||
* not by adding each line's height, but by getting the last line's position.
|
||||
* This because lines could have been pushed lower by a clearing element.
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
protected function _calculate_content_height() {
|
||||
$lines = $this->_frame->get_line_boxes();
|
||||
$height = 0;
|
||||
|
||||
foreach ($lines as $line) {
|
||||
$height += $line->h;
|
||||
}
|
||||
|
||||
/*
|
||||
$first_line = reset($lines);
|
||||
$last_line = end($lines);
|
||||
$height2 = $last_line->y + $last_line->h - $first_line->y;
|
||||
*/
|
||||
|
||||
return $height;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the frame's restricted height
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function _calculate_restricted_height() {
|
||||
$frame = $this->_frame;
|
||||
$style = $frame->get_style();
|
||||
$content_height = $this->_calculate_content_height();
|
||||
$cb = $frame->get_containing_block();
|
||||
|
||||
$height = $style->length_in_pt($style->height, $cb["h"]);
|
||||
|
||||
$top = $style->length_in_pt($style->top, $cb["h"]);
|
||||
$bottom = $style->length_in_pt($style->bottom, $cb["h"]);
|
||||
|
||||
$margin_top = $style->length_in_pt($style->margin_top, $cb["h"]);
|
||||
$margin_bottom = $style->length_in_pt($style->margin_bottom, $cb["h"]);
|
||||
|
||||
if ( $frame->is_absolute() ) {
|
||||
|
||||
// see http://www.w3.org/TR/CSS21/visudet.html#abs-non-replaced-height
|
||||
|
||||
$dims = array($top !== "auto" ? $top : 0,
|
||||
$style->margin_top !== "auto" ? $style->margin_top : 0,
|
||||
$style->padding_top,
|
||||
$style->border_top_width,
|
||||
$height !== "auto" ? $height : 0,
|
||||
$style->border_bottom_width,
|
||||
$style->padding_bottom,
|
||||
$style->margin_bottom !== "auto" ? $style->margin_bottom : 0,
|
||||
$bottom !== "auto" ? $bottom : 0);
|
||||
|
||||
$sum = $style->length_in_pt($dims, $cb["h"]);
|
||||
|
||||
$diff = $cb["h"] - $sum;
|
||||
|
||||
if ( $diff > 0 ) {
|
||||
|
||||
if ( $height === "auto" && $top === "auto" && $bottom === "auto" ) {
|
||||
|
||||
if ( $margin_top === "auto" ) $margin_top = 0;
|
||||
if ( $margin_bottom === "auto" ) $margin_bottom = 0;
|
||||
|
||||
$height = $diff;
|
||||
}
|
||||
else if ( $height === "auto" && $top === "auto" ) {
|
||||
|
||||
if ( $margin_top === "auto" ) $margin_top = 0;
|
||||
if ( $margin_bottom === "auto" ) $margin_bottom = 0;
|
||||
|
||||
$height = $content_height;
|
||||
$top = $diff - $content_height;
|
||||
}
|
||||
else if ( $height === "auto" && $bottom === "auto" ) {
|
||||
|
||||
if ( $margin_top === "auto" ) $margin_top = 0;
|
||||
if ( $margin_bottom === "auto" ) $margin_bottom = 0;
|
||||
|
||||
$height = $content_height;
|
||||
$bottom = $diff - $content_height;
|
||||
}
|
||||
else if ( $top === "auto" && $bottom === "auto" ) {
|
||||
|
||||
if ( $margin_top === "auto" ) $margin_top = 0;
|
||||
if ( $margin_bottom === "auto" ) $margin_bottom = 0;
|
||||
|
||||
$bottom = $diff;
|
||||
}
|
||||
else if ( $top === "auto" ) {
|
||||
|
||||
if ( $margin_top === "auto" ) $margin_top = 0;
|
||||
if ( $margin_bottom === "auto" ) $margin_bottom = 0;
|
||||
|
||||
$top = $diff;
|
||||
}
|
||||
else if ( $height === "auto" ) {
|
||||
|
||||
if ( $margin_top === "auto" ) $margin_top = 0;
|
||||
if ( $margin_bottom === "auto" ) $margin_bottom = 0;
|
||||
|
||||
$height = $diff;
|
||||
}
|
||||
else if ( $bottom === "auto" ) {
|
||||
|
||||
if ( $margin_top === "auto" ) $margin_top = 0;
|
||||
if ( $margin_bottom === "auto" ) $margin_bottom = 0;
|
||||
|
||||
$bottom = $diff;
|
||||
}
|
||||
else {
|
||||
|
||||
if ( $style->overflow === "visible" ) {
|
||||
// set all autos to zero
|
||||
if ( $margin_top === "auto" ) $margin_top = 0;
|
||||
if ( $margin_bottom === "auto" ) $margin_bottom = 0;
|
||||
if ( $top === "auto" ) $top = 0;
|
||||
if ( $bottom === "auto" ) $bottom = 0;
|
||||
if ( $height === "auto" ) $height = $content_height;
|
||||
}
|
||||
|
||||
// FIXME: overflow hidden
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
else {
|
||||
|
||||
// Expand the height if overflow is visible
|
||||
if ( $height === "auto" && $content_height > $height /* && $style->overflow === "visible" */) {
|
||||
$height = $content_height;
|
||||
}
|
||||
|
||||
// FIXME: this should probably be moved to a seperate function as per
|
||||
// _calculate_restricted_width
|
||||
|
||||
// Only handle min/max height if the height is independent of the frame's content
|
||||
if ( !($style->overflow === "visible" ||
|
||||
($style->overflow === "hidden" && $height === "auto")) ) {
|
||||
|
||||
$min_height = $style->min_height;
|
||||
$max_height = $style->max_height;
|
||||
|
||||
if ( isset($cb["h"]) ) {
|
||||
$min_height = $style->length_in_pt($min_height, $cb["h"]);
|
||||
$max_height = $style->length_in_pt($max_height, $cb["h"]);
|
||||
|
||||
}
|
||||
else if ( isset($cb["w"]) ) {
|
||||
|
||||
if ( mb_strpos($min_height, "%") !== false ) {
|
||||
$min_height = 0;
|
||||
}
|
||||
else {
|
||||
$min_height = $style->length_in_pt($min_height, $cb["w"]);
|
||||
}
|
||||
|
||||
if ( mb_strpos($max_height, "%") !== false ) {
|
||||
$max_height = "none";
|
||||
}
|
||||
else {
|
||||
$max_height = $style->length_in_pt($max_height, $cb["w"]);
|
||||
}
|
||||
}
|
||||
|
||||
if ( $max_height !== "none" && $min_height > $max_height ) {
|
||||
// Swap 'em
|
||||
list($max_height, $min_height) = array($min_height, $max_height);
|
||||
}
|
||||
|
||||
if ( $max_height !== "none" && $height > $max_height ) {
|
||||
$height = $max_height;
|
||||
}
|
||||
|
||||
if ( $height < $min_height ) {
|
||||
$height = $min_height;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return array($height, $margin_top, $margin_bottom, $top, $bottom);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Adjust the justification of each of our lines.
|
||||
* http://www.w3.org/TR/CSS21/text.html#propdef-text-align
|
||||
*/
|
||||
protected function _text_align() {
|
||||
$style = $this->_frame->get_style();
|
||||
$w = $this->_frame->get_containing_block("w");
|
||||
$width = $style->length_in_pt($style->width, $w);
|
||||
|
||||
switch ($style->text_align) {
|
||||
default:
|
||||
case "left":
|
||||
foreach ($this->_frame->get_line_boxes() as $line) {
|
||||
if ( !$line->left ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach($line->get_frames() as $frame) {
|
||||
if ( $frame instanceof Block_Frame_Decorator) {
|
||||
continue;
|
||||
}
|
||||
$frame->set_position( $frame->get_position("x") + $line->left );
|
||||
}
|
||||
}
|
||||
return;
|
||||
|
||||
case "right":
|
||||
foreach ($this->_frame->get_line_boxes() as $line) {
|
||||
// Move each child over by $dx
|
||||
$dx = $width - $line->w - $line->right;
|
||||
|
||||
foreach($line->get_frames() as $frame) {
|
||||
// Block frames are not aligned by text-align
|
||||
if ($frame instanceof Block_Frame_Decorator) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$frame->set_position( $frame->get_position("x") + $dx );
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case "justify":
|
||||
// We justify all lines except the last one
|
||||
$lines = $this->_frame->get_line_boxes(); // needs to be a variable (strict standards)
|
||||
array_pop($lines);
|
||||
|
||||
foreach($lines as $i => $line) {
|
||||
if ( $line->br ) {
|
||||
unset($lines[$i]);
|
||||
}
|
||||
}
|
||||
|
||||
// One space character's width. Will be used to get a more accurate spacing
|
||||
$space_width = Font_Metrics::get_text_width(" ", $style->font_family, $style->font_size);
|
||||
|
||||
foreach ($lines as $line) {
|
||||
if ( $line->left ) {
|
||||
foreach ( $line->get_frames() as $frame ) {
|
||||
if ( !$frame instanceof Text_Frame_Decorator ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$frame->set_position( $frame->get_position("x") + $line->left );
|
||||
}
|
||||
}
|
||||
|
||||
// Only set the spacing if the line is long enough. This is really
|
||||
// just an aesthetic choice ;)
|
||||
//if ( $line["left"] + $line["w"] + $line["right"] > self::MIN_JUSTIFY_WIDTH * $width ) {
|
||||
|
||||
// Set the spacing for each child
|
||||
if ( $line->wc > 1 ) {
|
||||
$spacing = ($width - ($line->left + $line->w + $line->right) + $space_width) / ($line->wc - 1);
|
||||
}
|
||||
else {
|
||||
$spacing = 0;
|
||||
}
|
||||
|
||||
$dx = 0;
|
||||
foreach($line->get_frames() as $frame) {
|
||||
if ( !$frame instanceof Text_Frame_Decorator ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$text = $frame->get_text();
|
||||
$spaces = mb_substr_count($text, " ");
|
||||
|
||||
$char_spacing = $style->length_in_pt($style->letter_spacing);
|
||||
$_spacing = $spacing + $char_spacing;
|
||||
|
||||
$frame->set_position( $frame->get_position("x") + $dx );
|
||||
$frame->set_text_spacing($_spacing);
|
||||
|
||||
$dx += $spaces * $_spacing;
|
||||
}
|
||||
|
||||
// The line (should) now occupy the entire width
|
||||
$line->w = $width;
|
||||
|
||||
//}
|
||||
}
|
||||
break;
|
||||
|
||||
case "center":
|
||||
case "centre":
|
||||
foreach ($this->_frame->get_line_boxes() as $line) {
|
||||
// Centre each line by moving each frame in the line by:
|
||||
$dx = ($width + $line->left - $line->w - $line->right ) / 2;
|
||||
|
||||
foreach ($line->get_frames() as $frame) {
|
||||
// Block frames are not aligned by text-align
|
||||
if ($frame instanceof Block_Frame_Decorator) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$frame->set_position( $frame->get_position("x") + $dx );
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Align inline children vertically.
|
||||
* Aligns each child vertically after each line is reflowed
|
||||
*/
|
||||
function vertical_align() {
|
||||
|
||||
$canvas = null;
|
||||
|
||||
foreach ( $this->_frame->get_line_boxes() as $line ) {
|
||||
|
||||
$height = $line->h;
|
||||
|
||||
foreach ( $line->get_frames() as $frame ) {
|
||||
$style = $frame->get_style();
|
||||
|
||||
if ( $style->display !== "inline" ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$align = $frame->get_parent()->get_style()->vertical_align;
|
||||
|
||||
if ( !isset($canvas) ) {
|
||||
$canvas = $frame->get_root()->get_dompdf()->get_canvas();
|
||||
}
|
||||
|
||||
$baseline = $canvas->get_font_baseline($style->font_family, $style->font_size);
|
||||
$y_offset = 0;
|
||||
|
||||
switch ($align) {
|
||||
case "baseline":
|
||||
$y_offset = $height*0.8 - $baseline; // The 0.8 ratio is arbitrary until we find it's meaning
|
||||
break;
|
||||
|
||||
case "middle":
|
||||
$y_offset = ($height*0.8 - $baseline) / 2;
|
||||
break;
|
||||
|
||||
case "sub":
|
||||
$y_offset = 0.3 * $height;
|
||||
break;
|
||||
|
||||
case "super":
|
||||
$y_offset = -0.2 * $height;
|
||||
break;
|
||||
|
||||
case "text-top":
|
||||
case "top": // Not strictly accurate, but good enough for now
|
||||
break;
|
||||
|
||||
case "text-bottom":
|
||||
case "bottom":
|
||||
$y_offset = $height*0.8 - $baseline;
|
||||
break;
|
||||
}
|
||||
|
||||
if ( $y_offset ) {
|
||||
$frame->move(0, $y_offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Frame $child
|
||||
*/
|
||||
function process_clear(Frame $child){
|
||||
$enable_css_float = $this->get_dompdf()->get_option("enable_css_float");
|
||||
if ( !$enable_css_float ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$child_style = $child->get_style();
|
||||
$root = $this->_frame->get_root();
|
||||
|
||||
// Handle "clear"
|
||||
if ( $child_style->clear !== "none" ) {
|
||||
$lowest_y = $root->get_lowest_float_offset($child);
|
||||
|
||||
// If a float is still applying, we handle it
|
||||
if ( $lowest_y ) {
|
||||
if ( $child->is_in_flow() ) {
|
||||
$line_box = $this->_frame->get_current_line_box();
|
||||
$line_box->y = $lowest_y + $child->get_margin_height();
|
||||
$line_box->left = 0;
|
||||
$line_box->right = 0;
|
||||
}
|
||||
|
||||
$child->move(0, $lowest_y - $child->get_position("y"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Frame $child
|
||||
* @param float $cb_x
|
||||
* @param float $cb_w
|
||||
*/
|
||||
function process_float(Frame $child, $cb_x, $cb_w){
|
||||
$enable_css_float = $this->_frame->get_dompdf()->get_option("enable_css_float");
|
||||
if ( !$enable_css_float ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$child_style = $child->get_style();
|
||||
$root = $this->_frame->get_root();
|
||||
|
||||
// Handle "float"
|
||||
if ( $child_style->float !== "none" ) {
|
||||
$root->add_floating_frame($child);
|
||||
|
||||
// Remove next frame's beginning whitespace
|
||||
$next = $child->get_next_sibling();
|
||||
if ( $next && $next instanceof Text_Frame_Decorator) {
|
||||
$next->set_text(ltrim($next->get_text()));
|
||||
}
|
||||
|
||||
$line_box = $this->_frame->get_current_line_box();
|
||||
list($old_x, $old_y) = $child->get_position();
|
||||
|
||||
$float_x = $cb_x;
|
||||
$float_y = $old_y;
|
||||
$float_w = $child->get_margin_width();
|
||||
|
||||
if ( $child_style->clear === "none" ) {
|
||||
switch( $child_style->float ) {
|
||||
case "left":
|
||||
$float_x += $line_box->left;
|
||||
break;
|
||||
case "right":
|
||||
$float_x += ($cb_w - $line_box->right - $float_w);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if ( $child_style->float === "right" ) {
|
||||
$float_x += ($cb_w - $float_w);
|
||||
}
|
||||
}
|
||||
|
||||
if ( $cb_w < $float_x + $float_w - $old_x ) {
|
||||
// TODO handle when floating elements don't fit
|
||||
}
|
||||
|
||||
$line_box->get_float_offsets();
|
||||
|
||||
if ( $child->_float_next_line ) {
|
||||
$float_y += $line_box->h;
|
||||
}
|
||||
|
||||
$child->set_position($float_x, $float_y);
|
||||
$child->move($float_x - $old_x, $float_y - $old_y, true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Frame_Decorator $block
|
||||
*/
|
||||
function reflow(Block_Frame_Decorator $block = null) {
|
||||
|
||||
// Check if a page break is forced
|
||||
$page = $this->_frame->get_root();
|
||||
$page->check_forced_page_break($this->_frame);
|
||||
|
||||
// Bail if the page is full
|
||||
if ( $page->is_full() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Generated content
|
||||
$this->_set_content();
|
||||
|
||||
// Collapse margins if required
|
||||
$this->_collapse_margins();
|
||||
|
||||
$style = $this->_frame->get_style();
|
||||
$cb = $this->_frame->get_containing_block();
|
||||
|
||||
if ( $style->position === "fixed" ) {
|
||||
$cb = $this->_frame->get_root()->get_containing_block();
|
||||
}
|
||||
|
||||
// Determine the constraints imposed by this frame: calculate the width
|
||||
// of the content area:
|
||||
list($w, $left_margin, $right_margin, $left, $right) = $this->_calculate_restricted_width();
|
||||
|
||||
// Store the calculated properties
|
||||
$style->width = $w . "pt";
|
||||
$style->margin_left = $left_margin."pt";
|
||||
$style->margin_right = $right_margin."pt";
|
||||
$style->left = $left ."pt";
|
||||
$style->right = $right . "pt";
|
||||
|
||||
// Update the position
|
||||
$this->_frame->position();
|
||||
list($x, $y) = $this->_frame->get_position();
|
||||
|
||||
// Adjust the first line based on the text-indent property
|
||||
$indent = $style->length_in_pt($style->text_indent, $cb["w"]);
|
||||
$this->_frame->increase_line_width($indent);
|
||||
|
||||
// Determine the content edge
|
||||
$top = $style->length_in_pt(array($style->margin_top,
|
||||
$style->padding_top,
|
||||
$style->border_top_width), $cb["h"]);
|
||||
|
||||
$bottom = $style->length_in_pt(array($style->border_bottom_width,
|
||||
$style->margin_bottom,
|
||||
$style->padding_bottom), $cb["h"]);
|
||||
|
||||
$cb_x = $x + $left_margin + $style->length_in_pt(array($style->border_left_width,
|
||||
$style->padding_left), $cb["w"]);
|
||||
|
||||
$cb_y = $y + $top;
|
||||
|
||||
$cb_h = ($cb["h"] + $cb["y"]) - $bottom - $cb_y;
|
||||
|
||||
// Set the y position of the first line in this block
|
||||
$line_box = $this->_frame->get_current_line_box();
|
||||
$line_box->y = $cb_y;
|
||||
$line_box->get_float_offsets();
|
||||
|
||||
// Set the containing blocks and reflow each child
|
||||
foreach ( $this->_frame->get_children() as $child ) {
|
||||
|
||||
// Bail out if the page is full
|
||||
if ( $page->is_full() ) {
|
||||
break;
|
||||
}
|
||||
|
||||
$child->set_containing_block($cb_x, $cb_y, $w, $cb_h);
|
||||
|
||||
$this->process_clear($child);
|
||||
|
||||
$child->reflow($this->_frame);
|
||||
|
||||
// Don't add the child to the line if a page break has occurred
|
||||
if ( $page->check_page_break($child) ) {
|
||||
break;
|
||||
}
|
||||
|
||||
$this->process_float($child, $cb_x, $w);
|
||||
}
|
||||
|
||||
// Determine our height
|
||||
list($height, $margin_top, $margin_bottom, $top, $bottom) = $this->_calculate_restricted_height();
|
||||
$style->height = $height;
|
||||
$style->margin_top = $margin_top;
|
||||
$style->margin_bottom = $margin_bottom;
|
||||
$style->top = $top;
|
||||
$style->bottom = $bottom;
|
||||
|
||||
$needs_reposition = ($style->position === "absolute" && ($style->right !== "auto" || $style->bottom !== "auto"));
|
||||
|
||||
// Absolute positioning measurement
|
||||
if ( $needs_reposition ) {
|
||||
$orig_style = $this->_frame->get_original_style();
|
||||
if ( $orig_style->width === "auto" && ($orig_style->left === "auto" || $orig_style->right === "auto") ) {
|
||||
$width = 0;
|
||||
foreach ($this->_frame->get_line_boxes() as $line) {
|
||||
$width = max($line->w, $width);
|
||||
}
|
||||
$style->width = $width;
|
||||
}
|
||||
|
||||
$style->left = $orig_style->left;
|
||||
$style->right = $orig_style->right;
|
||||
}
|
||||
|
||||
$this->_text_align();
|
||||
$this->vertical_align();
|
||||
|
||||
// Absolute positioning
|
||||
if ( $needs_reposition ) {
|
||||
list($x, $y) = $this->_frame->get_position();
|
||||
$this->_frame->position();
|
||||
list($new_x, $new_y) = $this->_frame->get_position();
|
||||
$this->_frame->move($new_x-$x, $new_y-$y, true);
|
||||
}
|
||||
|
||||
if ( $block && $this->_frame->is_in_flow() ) {
|
||||
$block->add_frame_to_line($this->_frame);
|
||||
|
||||
// May be inline-block
|
||||
if ( $style->display === "block" ) {
|
||||
$block->add_line();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
57
application/helpers/dompdf/include/block_positioner.cls.php
Executable file
57
application/helpers/dompdf/include/block_positioner.cls.php
Executable file
@@ -0,0 +1,57 @@
|
||||
<?php
|
||||
/**
|
||||
* @package dompdf
|
||||
* @link http://dompdf.github.com/
|
||||
* @author Benj Carson <benjcarson@digitaljunkies.ca>
|
||||
* @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
|
||||
*/
|
||||
|
||||
/**
|
||||
* Positions block frames
|
||||
*
|
||||
* @access private
|
||||
* @package dompdf
|
||||
*/
|
||||
class Block_Positioner extends Positioner {
|
||||
|
||||
|
||||
function __construct(Frame_Decorator $frame) { parent::__construct($frame); }
|
||||
|
||||
//........................................................................
|
||||
|
||||
function position() {
|
||||
$frame = $this->_frame;
|
||||
$style = $frame->get_style();
|
||||
$cb = $frame->get_containing_block();
|
||||
$p = $frame->find_block_parent();
|
||||
|
||||
if ( $p ) {
|
||||
$float = $style->float;
|
||||
|
||||
$enable_css_float = $frame->get_dompdf()->get_option("enable_css_float");
|
||||
if ( !$enable_css_float || !$float || $float === "none" ) {
|
||||
$p->add_line(true);
|
||||
}
|
||||
$y = $p->get_current_line_box()->y;
|
||||
|
||||
}
|
||||
else {
|
||||
$y = $cb["y"];
|
||||
}
|
||||
|
||||
$x = $cb["x"];
|
||||
|
||||
// Relative positionning
|
||||
if ( $style->position === "relative" ) {
|
||||
$top = $style->length_in_pt($style->top, $cb["h"]);
|
||||
//$right = $style->length_in_pt($style->right, $cb["w"]);
|
||||
//$bottom = $style->length_in_pt($style->bottom, $cb["h"]);
|
||||
$left = $style->length_in_pt($style->left, $cb["w"]);
|
||||
|
||||
$x += $left;
|
||||
$y += $top;
|
||||
}
|
||||
|
||||
$frame->set_position($x, $y);
|
||||
}
|
||||
}
|
||||
230
application/helpers/dompdf/include/block_renderer.cls.php
Executable file
230
application/helpers/dompdf/include/block_renderer.cls.php
Executable file
@@ -0,0 +1,230 @@
|
||||
<?php
|
||||
/**
|
||||
* @package dompdf
|
||||
* @link http://dompdf.github.com/
|
||||
* @author Benj Carson <benjcarson@digitaljunkies.ca>
|
||||
* @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
|
||||
*/
|
||||
|
||||
/**
|
||||
* Renders block frames
|
||||
*
|
||||
* @access private
|
||||
* @package dompdf
|
||||
*/
|
||||
class Block_Renderer extends Abstract_Renderer {
|
||||
|
||||
//........................................................................
|
||||
|
||||
function render(Frame $frame) {
|
||||
$style = $frame->get_style();
|
||||
$node = $frame->get_node();
|
||||
|
||||
list($x, $y, $w, $h) = $frame->get_border_box();
|
||||
|
||||
$this->_set_opacity( $frame->get_opacity( $style->opacity ) );
|
||||
|
||||
if ( $node->nodeName === "body" ) {
|
||||
$h = $frame->get_containing_block("h") - $style->length_in_pt(array(
|
||||
$style->margin_top,
|
||||
$style->border_top_width,
|
||||
$style->border_bottom_width,
|
||||
$style->margin_bottom),
|
||||
$style->width);
|
||||
}
|
||||
|
||||
// Handle anchors & links
|
||||
if ( $node->nodeName === "a" && $href = $node->getAttribute("href") ) {
|
||||
$this->_canvas->add_link($href, $x, $y, $w, $h);
|
||||
}
|
||||
|
||||
// Draw our background, border and content
|
||||
list($tl, $tr, $br, $bl) = $style->get_computed_border_radius($w, $h);
|
||||
|
||||
if ( $tl + $tr + $br + $bl > 0 ) {
|
||||
$this->_canvas->clipping_roundrectangle( $x, $y, $w, $h, $tl, $tr, $br, $bl );
|
||||
}
|
||||
|
||||
if ( ($bg = $style->background_color) !== "transparent" ) {
|
||||
$this->_canvas->filled_rectangle( $x, $y, $w, $h, $bg );
|
||||
}
|
||||
|
||||
if ( ($url = $style->background_image) && $url !== "none" ) {
|
||||
$this->_background_image($url, $x, $y, $w, $h, $style);
|
||||
}
|
||||
|
||||
if ( $tl + $tr + $br + $bl > 0 ) {
|
||||
$this->_canvas->clipping_end();
|
||||
}
|
||||
|
||||
$border_box = array($x, $y, $w, $h);
|
||||
$this->_render_border($frame, $border_box);
|
||||
$this->_render_outline($frame, $border_box);
|
||||
|
||||
if (DEBUG_LAYOUT && DEBUG_LAYOUT_BLOCKS) {
|
||||
$this->_debug_layout($frame->get_border_box(), "red");
|
||||
if (DEBUG_LAYOUT_PADDINGBOX) {
|
||||
$this->_debug_layout($frame->get_padding_box(), "red", array(0.5, 0.5));
|
||||
}
|
||||
}
|
||||
|
||||
if (DEBUG_LAYOUT && DEBUG_LAYOUT_LINES && $frame->get_decorator()) {
|
||||
foreach ($frame->get_decorator()->get_line_boxes() as $line) {
|
||||
$frame->_debug_layout(array($line->x, $line->y, $line->w, $line->h), "orange");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected function _render_border(Frame_Decorator $frame, $border_box = null, $corner_style = "bevel") {
|
||||
$style = $frame->get_style();
|
||||
$bp = $style->get_border_properties();
|
||||
|
||||
if ( empty($border_box) ) {
|
||||
$border_box = $frame->get_border_box();
|
||||
}
|
||||
|
||||
// find the radius
|
||||
$radius = $style->get_computed_border_radius($border_box[2], $border_box[3]); // w, h
|
||||
|
||||
// Short-cut: If all the borders are "solid" with the same color and style, and no radius, we'd better draw a rectangle
|
||||
if (
|
||||
in_array($bp["top"]["style"], array("solid", "dashed", "dotted")) &&
|
||||
$bp["top"] == $bp["right"] &&
|
||||
$bp["right"] == $bp["bottom"] &&
|
||||
$bp["bottom"] == $bp["left"] &&
|
||||
array_sum($radius) == 0
|
||||
) {
|
||||
$props = $bp["top"];
|
||||
if ( $props["color"] === "transparent" || $props["width"] <= 0 ) return;
|
||||
|
||||
list($x, $y, $w, $h) = $border_box;
|
||||
$width = $style->length_in_pt($props["width"]);
|
||||
$pattern = $this->_get_dash_pattern($props["style"], $width);
|
||||
$this->_canvas->rectangle($x + $width / 2, $y + $width / 2, $w - $width, $h - $width, $props["color"], $width, $pattern);
|
||||
return;
|
||||
}
|
||||
|
||||
// Do it the long way
|
||||
$widths = array($style->length_in_pt($bp["top"]["width"]),
|
||||
$style->length_in_pt($bp["right"]["width"]),
|
||||
$style->length_in_pt($bp["bottom"]["width"]),
|
||||
$style->length_in_pt($bp["left"]["width"]));
|
||||
|
||||
foreach ($bp as $side => $props) {
|
||||
list($x, $y, $w, $h) = $border_box;
|
||||
$length = 0;
|
||||
$r1 = 0;
|
||||
$r2 = 0;
|
||||
|
||||
if ( !$props["style"] ||
|
||||
$props["style"] === "none" ||
|
||||
$props["width"] <= 0 ||
|
||||
$props["color"] == "transparent" )
|
||||
continue;
|
||||
|
||||
switch($side) {
|
||||
case "top":
|
||||
$length = $w;
|
||||
$r1 = $radius["top-left"];
|
||||
$r2 = $radius["top-right"];
|
||||
break;
|
||||
|
||||
case "bottom":
|
||||
$length = $w;
|
||||
$y += $h;
|
||||
$r1 = $radius["bottom-left"];
|
||||
$r2 = $radius["bottom-right"];
|
||||
break;
|
||||
|
||||
case "left":
|
||||
$length = $h;
|
||||
$r1 = $radius["top-left"];
|
||||
$r2 = $radius["bottom-left"];
|
||||
break;
|
||||
|
||||
case "right":
|
||||
$length = $h;
|
||||
$x += $w;
|
||||
$r1 = $radius["top-right"];
|
||||
$r2 = $radius["bottom-right"];
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
$method = "_border_" . $props["style"];
|
||||
|
||||
// draw rounded corners
|
||||
$this->$method($x, $y, $length, $props["color"], $widths, $side, $corner_style, $r1, $r2);
|
||||
}
|
||||
}
|
||||
|
||||
protected function _render_outline(Frame_Decorator $frame, $border_box = null, $corner_style = "bevel") {
|
||||
$style = $frame->get_style();
|
||||
|
||||
$props = array(
|
||||
"width" => $style->outline_width,
|
||||
"style" => $style->outline_style,
|
||||
"color" => $style->outline_color,
|
||||
);
|
||||
|
||||
if ( !$props["style"] || $props["style"] === "none" || $props["width"] <= 0 )
|
||||
return;
|
||||
|
||||
if ( empty($border_box) ) {
|
||||
$border_box = $frame->get_border_box();
|
||||
}
|
||||
|
||||
$offset = $style->length_in_pt($props["width"]);
|
||||
$pattern = $this->_get_dash_pattern($props["style"], $offset);
|
||||
|
||||
// If the outline style is "solid" we'd better draw a rectangle
|
||||
if ( in_array($props["style"], array("solid", "dashed", "dotted")) ) {
|
||||
$border_box[0] -= $offset / 2;
|
||||
$border_box[1] -= $offset / 2;
|
||||
$border_box[2] += $offset;
|
||||
$border_box[3] += $offset;
|
||||
|
||||
list($x, $y, $w, $h) = $border_box;
|
||||
$this->_canvas->rectangle($x, $y, $w, $h, $props["color"], $offset, $pattern);
|
||||
return;
|
||||
}
|
||||
|
||||
$border_box[0] -= $offset;
|
||||
$border_box[1] -= $offset;
|
||||
$border_box[2] += $offset * 2;
|
||||
$border_box[3] += $offset * 2;
|
||||
|
||||
$method = "_border_" . $props["style"];
|
||||
$widths = array_fill(0, 4, $props["width"]);
|
||||
$sides = array("top", "right", "left", "bottom");
|
||||
$length = 0;
|
||||
|
||||
foreach ($sides as $side) {
|
||||
list($x, $y, $w, $h) = $border_box;
|
||||
|
||||
switch($side) {
|
||||
case "top":
|
||||
$length = $w;
|
||||
break;
|
||||
|
||||
case "bottom":
|
||||
$length = $w;
|
||||
$y += $h;
|
||||
break;
|
||||
|
||||
case "left":
|
||||
$length = $h;
|
||||
break;
|
||||
|
||||
case "right":
|
||||
$length = $h;
|
||||
$x += $w;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
$this->$method($x, $y, $length, $props["color"], $widths, $side, $corner_style);
|
||||
}
|
||||
}
|
||||
}
|
||||
164
application/helpers/dompdf/include/cached_pdf_decorator.cls.php
Executable file
164
application/helpers/dompdf/include/cached_pdf_decorator.cls.php
Executable file
@@ -0,0 +1,164 @@
|
||||
<?php
|
||||
/**
|
||||
* @package dompdf
|
||||
* @link http://dompdf.github.com/
|
||||
* @author Benj Carson <benjcarson@digitaljunkies.ca>
|
||||
* @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
|
||||
*/
|
||||
|
||||
/**
|
||||
* Caching canvas implementation
|
||||
*
|
||||
* Each rendered page is serialized and stored in the {@link Page_Cache}.
|
||||
* This is useful for static forms/pages that do not need to be re-rendered
|
||||
* all the time.
|
||||
*
|
||||
* This class decorates normal CPDF_Adapters. It is currently completely
|
||||
* experimental.
|
||||
*
|
||||
* @access private
|
||||
* @package dompdf
|
||||
*/
|
||||
class Cached_PDF_Decorator extends CPDF_Adapter implements Canvas {
|
||||
/**
|
||||
* @var CPDF_Adapter
|
||||
*/
|
||||
protected $_pdf;
|
||||
protected $_cache_id;
|
||||
protected $_current_page_id;
|
||||
protected $_fonts; // fonts used in this document
|
||||
|
||||
function __construct($paper = "letter", $orientation = "portrait", DOMPDF $dompdf) {
|
||||
$this->_fonts = array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Must be called after constructor
|
||||
*
|
||||
* @param int $cache_id
|
||||
* @param CPDF_Adapter $pdf
|
||||
*/
|
||||
function init($cache_id, CPDF_Adapter $pdf) {
|
||||
$this->_cache_id = $cache_id;
|
||||
$this->_pdf = $pdf;
|
||||
$this->_current_page_id = $this->_pdf->open_object();
|
||||
}
|
||||
|
||||
//........................................................................
|
||||
|
||||
function get_cpdf() { return $this->_pdf->get_cpdf(); }
|
||||
|
||||
function open_object() { $this->_pdf->open_object(); }
|
||||
function reopen_object($object) { $this->_pdf->reopen_object($object); }
|
||||
|
||||
function close_object() { $this->_pdf->close_object(); }
|
||||
|
||||
function add_object($object, $where = 'all') { $this->_pdf->add_object($object, $where); }
|
||||
|
||||
function serialize_object($id) { $this->_pdf->serialize_object($id); }
|
||||
|
||||
function reopen_serialized_object($obj) { $this->_pdf->reopen_serialized_object($obj); }
|
||||
|
||||
//........................................................................
|
||||
|
||||
function get_width() { return $this->_pdf->get_width(); }
|
||||
function get_height() { return $this->_pdf->get_height(); }
|
||||
function get_page_number() { return $this->_pdf->get_page_number(); }
|
||||
function get_page_count() { return $this->_pdf->get_page_count(); }
|
||||
|
||||
function set_page_number($num) { $this->_pdf->set_page_number($num); }
|
||||
function set_page_count($count) { $this->_pdf->set_page_count($count); }
|
||||
|
||||
function line($x1, $y1, $x2, $y2, $color, $width, $style = array()) {
|
||||
$this->_pdf->line($x1, $y1, $x2, $y2, $color, $width, $style);
|
||||
}
|
||||
|
||||
function rectangle($x1, $y1, $w, $h, $color, $width, $style = array()) {
|
||||
$this->_pdf->rectangle($x1, $y1, $w, $h, $color, $width, $style);
|
||||
}
|
||||
|
||||
function filled_rectangle($x1, $y1, $w, $h, $color) {
|
||||
$this->_pdf->filled_rectangle($x1, $y1, $w, $h, $color);
|
||||
}
|
||||
|
||||
function polygon($points, $color, $width = null, $style = array(), $fill = false) {
|
||||
$this->_pdf->polygon($points, $color, $width, $style, $fill);
|
||||
}
|
||||
|
||||
function circle($x, $y, $r1, $color, $width = null, $style = null, $fill = false) {
|
||||
$this->_pdf->circle($x, $y, $r1, $color, $width, $style, $fill);
|
||||
}
|
||||
|
||||
function image($img_url, $x, $y, $w, $h, $resolution = "normal") {
|
||||
$this->_pdf->image($img_url, $x, $y, $w, $h, $resolution);
|
||||
}
|
||||
|
||||
function text($x, $y, $text, $font, $size, $color = array(0,0,0), $word_space = 0.0, $char_space = 0.0, $angle = 0.0) {
|
||||
$this->_fonts[$font] = true;
|
||||
$this->_pdf->text($x, $y, $text, $font, $size, $color, $word_space, $char_space, $angle);
|
||||
}
|
||||
|
||||
function page_text($x, $y, $text, $font, $size, $color = array(0,0,0), $word_space = 0.0, $char_space = 0.0, $angle = 0.0) {
|
||||
|
||||
// We want to remove this from cached pages since it may not be correct
|
||||
$this->_pdf->close_object();
|
||||
$this->_pdf->page_text($x, $y, $text, $font, $size, $color, $word_space, $char_space, $angle);
|
||||
$this->_pdf->reopen_object($this->_current_page_id);
|
||||
}
|
||||
|
||||
function page_script($script, $type = 'text/php') {
|
||||
|
||||
// We want to remove this from cached pages since it may not be correct
|
||||
$this->_pdf->close_object();
|
||||
$this->_pdf->page_script($script, $type);
|
||||
$this->_pdf->reopen_object($this->_current_page_id);
|
||||
}
|
||||
|
||||
function new_page() {
|
||||
$this->_pdf->close_object();
|
||||
|
||||
// Add the object to the current page
|
||||
$this->_pdf->add_object($this->_current_page_id, "add");
|
||||
$this->_pdf->new_page();
|
||||
|
||||
Page_Cache::store_page($this->_cache_id,
|
||||
$this->_pdf->get_page_number() - 1,
|
||||
$this->_pdf->serialize_object($this->_current_page_id));
|
||||
|
||||
$this->_current_page_id = $this->_pdf->open_object();
|
||||
return $this->_current_page_id;
|
||||
}
|
||||
|
||||
function stream($filename, $options = null) {
|
||||
// Store the last page in the page cache
|
||||
if ( !is_null($this->_current_page_id) ) {
|
||||
$this->_pdf->close_object();
|
||||
$this->_pdf->add_object($this->_current_page_id, "add");
|
||||
Page_Cache::store_page($this->_cache_id,
|
||||
$this->_pdf->get_page_number(),
|
||||
$this->_pdf->serialize_object($this->_current_page_id));
|
||||
Page_Cache::store_fonts($this->_cache_id, $this->_fonts);
|
||||
$this->_current_page_id = null;
|
||||
}
|
||||
|
||||
$this->_pdf->stream($filename);
|
||||
|
||||
}
|
||||
|
||||
function output($options = null) {
|
||||
// Store the last page in the page cache
|
||||
if ( !is_null($this->_current_page_id) ) {
|
||||
$this->_pdf->close_object();
|
||||
$this->_pdf->add_object($this->_current_page_id, "add");
|
||||
Page_Cache::store_page($this->_cache_id,
|
||||
$this->_pdf->get_page_number(),
|
||||
$this->_pdf->serialize_object($this->_current_page_id));
|
||||
$this->_current_page_id = null;
|
||||
}
|
||||
|
||||
return $this->_pdf->output();
|
||||
}
|
||||
|
||||
function get_messages() { return $this->_pdf->get_messages(); }
|
||||
|
||||
}
|
||||
385
application/helpers/dompdf/include/canvas.cls.php
Executable file
385
application/helpers/dompdf/include/canvas.cls.php
Executable file
@@ -0,0 +1,385 @@
|
||||
<?php
|
||||
/**
|
||||
* @package dompdf
|
||||
* @link http://dompdf.github.com/
|
||||
* @author Benj Carson <benjcarson@digitaljunkies.ca>
|
||||
* @author Fabien Ménager <fabien.menager@gmail.com>
|
||||
* @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
|
||||
*/
|
||||
|
||||
/**
|
||||
* Main rendering interface
|
||||
*
|
||||
* Currently {@link CPDF_Adapter}, {@link PDFLib_Adapter}, {@link TCPDF_Adapter}, and {@link GD_Adapter}
|
||||
* implement this interface.
|
||||
*
|
||||
* Implementations should measure x and y increasing to the left and down,
|
||||
* respectively, with the origin in the top left corner. Implementations
|
||||
* are free to use a unit other than points for length, but I can't
|
||||
* guarantee that the results will look any good.
|
||||
*
|
||||
* @package dompdf
|
||||
*/
|
||||
interface Canvas {
|
||||
function __construct($paper = "letter", $orientation = "portrait", DOMPDF $dompdf);
|
||||
|
||||
/**
|
||||
* @return DOMPDF
|
||||
*/
|
||||
function get_dompdf();
|
||||
|
||||
/**
|
||||
* Returns the current page number
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
function get_page_number();
|
||||
|
||||
/**
|
||||
* Returns the total number of pages
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
function get_page_count();
|
||||
|
||||
/**
|
||||
* Sets the total number of pages
|
||||
*
|
||||
* @param int $count
|
||||
*/
|
||||
function set_page_count($count);
|
||||
|
||||
/**
|
||||
* Draws a line from x1,y1 to x2,y2
|
||||
*
|
||||
* See {@link Style::munge_color()} for the format of the color array.
|
||||
* See {@link Cpdf::setLineStyle()} for a description of the format of the
|
||||
* $style parameter (aka dash).
|
||||
*
|
||||
* @param float $x1
|
||||
* @param float $y1
|
||||
* @param float $x2
|
||||
* @param float $y2
|
||||
* @param array $color
|
||||
* @param float $width
|
||||
* @param array $style
|
||||
*/
|
||||
function line($x1, $y1, $x2, $y2, $color, $width, $style = null);
|
||||
|
||||
/**
|
||||
* Draws a rectangle at x1,y1 with width w and height h
|
||||
*
|
||||
* See {@link Style::munge_color()} for the format of the color array.
|
||||
* See {@link Cpdf::setLineStyle()} for a description of the $style
|
||||
* parameter (aka dash)
|
||||
*
|
||||
* @param float $x1
|
||||
* @param float $y1
|
||||
* @param float $w
|
||||
* @param float $h
|
||||
* @param array $color
|
||||
* @param float $width
|
||||
* @param array $style
|
||||
*/
|
||||
function rectangle($x1, $y1, $w, $h, $color, $width, $style = null);
|
||||
|
||||
/**
|
||||
* Draws a filled rectangle at x1,y1 with width w and height h
|
||||
*
|
||||
* See {@link Style::munge_color()} for the format of the color array.
|
||||
*
|
||||
* @param float $x1
|
||||
* @param float $y1
|
||||
* @param float $w
|
||||
* @param float $h
|
||||
* @param array $color
|
||||
*/
|
||||
function filled_rectangle($x1, $y1, $w, $h, $color);
|
||||
|
||||
/**
|
||||
* Starts a clipping rectangle at x1,y1 with width w and height h
|
||||
*
|
||||
* @param float $x1
|
||||
* @param float $y1
|
||||
* @param float $w
|
||||
* @param float $h
|
||||
*/
|
||||
function clipping_rectangle($x1, $y1, $w, $h);
|
||||
|
||||
/**
|
||||
* Starts a rounded clipping rectangle at x1,y1 with width w and height h
|
||||
*
|
||||
* @param float $x1
|
||||
* @param float $y1
|
||||
* @param float $w
|
||||
* @param float $h
|
||||
* @param float $tl
|
||||
* @param float $tr
|
||||
* @param float $br
|
||||
* @param float $bl
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
function clipping_roundrectangle($x1, $y1, $w, $h, $tl, $tr, $br, $bl);
|
||||
|
||||
/**
|
||||
* Ends the last clipping shape
|
||||
*/
|
||||
function clipping_end();
|
||||
|
||||
/**
|
||||
* Save current state
|
||||
*/
|
||||
function save();
|
||||
|
||||
/**
|
||||
* Restore last state
|
||||
*/
|
||||
function restore();
|
||||
|
||||
/**
|
||||
* Rotate
|
||||
*/
|
||||
function rotate($angle, $x, $y);
|
||||
|
||||
/**
|
||||
* Skew
|
||||
*/
|
||||
function skew($angle_x, $angle_y, $x, $y);
|
||||
|
||||
/**
|
||||
* Scale
|
||||
*/
|
||||
function scale($s_x, $s_y, $x, $y);
|
||||
|
||||
/**
|
||||
* Translate
|
||||
*/
|
||||
function translate($t_x, $t_y);
|
||||
|
||||
/**
|
||||
* Transform
|
||||
*/
|
||||
function transform($a, $b, $c, $d, $e, $f);
|
||||
|
||||
/**
|
||||
* Draws a polygon
|
||||
*
|
||||
* The polygon is formed by joining all the points stored in the $points
|
||||
* array. $points has the following structure:
|
||||
* <code>
|
||||
* array(0 => x1,
|
||||
* 1 => y1,
|
||||
* 2 => x2,
|
||||
* 3 => y2,
|
||||
* ...
|
||||
* );
|
||||
* </code>
|
||||
*
|
||||
* See {@link Style::munge_color()} for the format of the color array.
|
||||
* See {@link Cpdf::setLineStyle()} for a description of the $style
|
||||
* parameter (aka dash)
|
||||
*
|
||||
* @param array $points
|
||||
* @param array $color
|
||||
* @param float $width
|
||||
* @param array $style
|
||||
* @param bool $fill Fills the polygon if true
|
||||
*/
|
||||
function polygon($points, $color, $width = null, $style = null, $fill = false);
|
||||
|
||||
/**
|
||||
* Draws a circle at $x,$y with radius $r
|
||||
*
|
||||
* See {@link Style::munge_color()} for the format of the color array.
|
||||
* See {@link Cpdf::setLineStyle()} for a description of the $style
|
||||
* parameter (aka dash)
|
||||
*
|
||||
* @param float $x
|
||||
* @param float $y
|
||||
* @param float $r
|
||||
* @param array $color
|
||||
* @param float $width
|
||||
* @param array $style
|
||||
* @param bool $fill Fills the circle if true
|
||||
*/
|
||||
function circle($x, $y, $r, $color, $width = null, $style = null, $fill = false);
|
||||
|
||||
/**
|
||||
* Add an image to the pdf.
|
||||
*
|
||||
* The image is placed at the specified x and y coordinates with the
|
||||
* given width and height.
|
||||
*
|
||||
* @param string $img_url the path to the image
|
||||
* @param float $x x position
|
||||
* @param float $y y position
|
||||
* @param int $w width (in pixels)
|
||||
* @param int $h height (in pixels)
|
||||
* @param string $resolution The resolution of the image
|
||||
*/
|
||||
function image($img_url, $x, $y, $w, $h, $resolution = "normal");
|
||||
|
||||
/**
|
||||
* Add an arc to the PDF
|
||||
* See {@link Style::munge_color()} for the format of the color array.
|
||||
*
|
||||
* @param float $x X coordinate of the arc
|
||||
* @param float $y Y coordinate of the arc
|
||||
* @param float $r1 Radius 1
|
||||
* @param float $r2 Radius 2
|
||||
* @param float $astart Start angle in degrees
|
||||
* @param float $aend End angle in degrees
|
||||
* @param array $color Color
|
||||
* @param float $width
|
||||
* @param array $style
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function arc($x, $y, $r1, $r2, $astart, $aend, $color, $width, $style = array());
|
||||
|
||||
/**
|
||||
* Writes text at the specified x and y coordinates
|
||||
* See {@link Style::munge_color()} for the format of the color array.
|
||||
*
|
||||
* @param float $x
|
||||
* @param float $y
|
||||
* @param string $text the text to write
|
||||
* @param string $font the font file to use
|
||||
* @param float $size the font size, in points
|
||||
* @param array $color
|
||||
* @param float $word_space word spacing adjustment
|
||||
* @param float $char_space char spacing adjustment
|
||||
* @param float $angle angle
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function text($x, $y, $text, $font, $size, $color = array(0,0,0), $word_space = 0.0, $char_space = 0.0, $angle = 0.0);
|
||||
|
||||
/**
|
||||
* Add a named destination (similar to <a name="foo">...</a> in html)
|
||||
*
|
||||
* @param string $anchorname The name of the named destination
|
||||
*/
|
||||
function add_named_dest($anchorname);
|
||||
|
||||
/**
|
||||
* Add a link to the pdf
|
||||
*
|
||||
* @param string $url The url to link to
|
||||
* @param float $x The x position of the link
|
||||
* @param float $y The y position of the link
|
||||
* @param float $width The width of the link
|
||||
* @param float $height The height of the link
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function add_link($url, $x, $y, $width, $height);
|
||||
|
||||
/**
|
||||
* Add meta information to the pdf
|
||||
*
|
||||
* @param string $name Label of the value (Creator, Producer, etc.)
|
||||
* @param string $value The text to set
|
||||
*/
|
||||
function add_info($name, $value);
|
||||
|
||||
/**
|
||||
* Calculates text size, in points
|
||||
*
|
||||
* @param string $text the text to be sized
|
||||
* @param string $font the desired font
|
||||
* @param float $size the desired font size
|
||||
* @param float $word_spacing word spacing, if any
|
||||
* @param float $char_spacing
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
function get_text_width($text, $font, $size, $word_spacing = 0.0, $char_spacing = 0.0);
|
||||
|
||||
/**
|
||||
* Calculates font height, in points
|
||||
*
|
||||
* @param string $font
|
||||
* @param float $size
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
function get_font_height($font, $size);
|
||||
|
||||
/**
|
||||
* Calculates font baseline, in points
|
||||
*
|
||||
* @param string $font
|
||||
* @param float $size
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
function get_font_baseline($font, $size);
|
||||
|
||||
/**
|
||||
* Returns the font x-height, in points
|
||||
*
|
||||
* @param string $font
|
||||
* @param float $size
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
//function get_font_x_height($font, $size);
|
||||
|
||||
/**
|
||||
* Sets the opacity
|
||||
*
|
||||
* @param float $opacity
|
||||
* @param string $mode
|
||||
*/
|
||||
function set_opacity($opacity, $mode = "Normal");
|
||||
|
||||
/**
|
||||
* Sets the default view
|
||||
*
|
||||
* @param string $view
|
||||
* 'XYZ' left, top, zoom
|
||||
* 'Fit'
|
||||
* 'FitH' top
|
||||
* 'FitV' left
|
||||
* 'FitR' left,bottom,right
|
||||
* 'FitB'
|
||||
* 'FitBH' top
|
||||
* 'FitBV' left
|
||||
* @param array $options
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function set_default_view($view, $options = array());
|
||||
|
||||
/**
|
||||
* @param string $script
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function javascript($script);
|
||||
|
||||
/**
|
||||
* Starts a new page
|
||||
*
|
||||
* Subsequent drawing operations will appear on the new page.
|
||||
*/
|
||||
function new_page();
|
||||
|
||||
/**
|
||||
* Streams the PDF directly to the browser
|
||||
*
|
||||
* @param string $filename the name of the PDF file
|
||||
* @param array $options associative array, 'Attachment' => 0 or 1, 'compress' => 1 or 0
|
||||
*/
|
||||
function stream($filename, $options = null);
|
||||
|
||||
/**
|
||||
* Returns the PDF as a string
|
||||
*
|
||||
* @param array $options associative array: 'compress' => 1 or 0
|
||||
* @return string
|
||||
*/
|
||||
function output($options = null);
|
||||
}
|
||||
63
application/helpers/dompdf/include/canvas_factory.cls.php
Executable file
63
application/helpers/dompdf/include/canvas_factory.cls.php
Executable file
@@ -0,0 +1,63 @@
|
||||
<?php
|
||||
/**
|
||||
* @package dompdf
|
||||
* @link http://dompdf.github.com/
|
||||
* @author Benj Carson <benjcarson@digitaljunkies.ca>
|
||||
* @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
|
||||
*/
|
||||
|
||||
/**
|
||||
* Create canvas instances
|
||||
*
|
||||
* The canvas factory creates canvas instances based on the
|
||||
* availability of rendering backends and config options.
|
||||
*
|
||||
* @package dompdf
|
||||
*/
|
||||
class Canvas_Factory {
|
||||
|
||||
/**
|
||||
* Constructor is private: this is a static class
|
||||
*/
|
||||
private function __construct() { }
|
||||
|
||||
/**
|
||||
* @param DOMPDF $dompdf
|
||||
* @param string|array $paper
|
||||
* @param string $orientation
|
||||
* @param string $class
|
||||
*
|
||||
* @return Canvas
|
||||
*/
|
||||
static function get_instance(DOMPDF $dompdf, $paper = null, $orientation = null, $class = null) {
|
||||
|
||||
$backend = strtolower(DOMPDF_PDF_BACKEND);
|
||||
|
||||
if ( isset($class) && class_exists($class, false) ) {
|
||||
$class .= "_Adapter";
|
||||
}
|
||||
|
||||
else if ( (DOMPDF_PDF_BACKEND === "auto" || $backend === "pdflib" ) &&
|
||||
class_exists("PDFLib", false) ) {
|
||||
$class = "PDFLib_Adapter";
|
||||
}
|
||||
|
||||
// FIXME The TCPDF adapter is not ready yet
|
||||
//else if ( (DOMPDF_PDF_BACKEND === "auto" || $backend === "cpdf") )
|
||||
// $class = "CPDF_Adapter";
|
||||
|
||||
else if ( $backend === "tcpdf" ) {
|
||||
$class = "TCPDF_Adapter";
|
||||
}
|
||||
|
||||
else if ( $backend === "gd" ) {
|
||||
$class = "GD_Adapter";
|
||||
}
|
||||
|
||||
else {
|
||||
$class = "CPDF_Adapter";
|
||||
}
|
||||
|
||||
return new $class($paper, $orientation, $dompdf);
|
||||
}
|
||||
}
|
||||
790
application/helpers/dompdf/include/cellmap.cls.php
Executable file
790
application/helpers/dompdf/include/cellmap.cls.php
Executable file
@@ -0,0 +1,790 @@
|
||||
<?php
|
||||
/**
|
||||
* @package dompdf
|
||||
* @link http://dompdf.github.com/
|
||||
* @author Benj Carson <benjcarson@digitaljunkies.ca>
|
||||
* @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
|
||||
*/
|
||||
|
||||
/**
|
||||
* Maps table cells to the table grid.
|
||||
*
|
||||
* This class resolves borders in tables with collapsed borders and helps
|
||||
* place row & column spanned table cells.
|
||||
*
|
||||
* @access private
|
||||
* @package dompdf
|
||||
*/
|
||||
class Cellmap {
|
||||
|
||||
/**
|
||||
* Border style weight lookup for collapsed border resolution.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
static protected $_BORDER_STYLE_SCORE = array(
|
||||
"inset" => 1,
|
||||
"groove" => 2,
|
||||
"outset" => 3,
|
||||
"ridge" => 4,
|
||||
"dotted" => 5,
|
||||
"dashed" => 6,
|
||||
"solid" => 7,
|
||||
"double" => 8,
|
||||
"hidden" => 9,
|
||||
"none" => 0,
|
||||
);
|
||||
|
||||
/**
|
||||
* The table object this cellmap is attached to.
|
||||
*
|
||||
* @var Table_Frame_Decorator
|
||||
*/
|
||||
protected $_table;
|
||||
|
||||
/**
|
||||
* The total number of rows in the table
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $_num_rows;
|
||||
|
||||
/**
|
||||
* The total number of columns in the table
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $_num_cols;
|
||||
|
||||
/**
|
||||
* 2D array mapping <row,column> to frames
|
||||
*
|
||||
* @var Frame[][]
|
||||
*/
|
||||
protected $_cells;
|
||||
|
||||
/**
|
||||
* 1D array of column dimensions
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $_columns;
|
||||
|
||||
/**
|
||||
* 1D array of row dimensions
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $_rows;
|
||||
|
||||
/**
|
||||
* 2D array of border specs
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $_borders;
|
||||
|
||||
/**
|
||||
* 1D Array mapping frames to (multiple) <row, col> pairs, keyed on frame_id.
|
||||
*
|
||||
* @var Frame[]
|
||||
*/
|
||||
protected $_frames;
|
||||
|
||||
/**
|
||||
* Current column when adding cells, 0-based
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
private $__col;
|
||||
|
||||
/**
|
||||
* Current row when adding cells, 0-based
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
private $__row;
|
||||
|
||||
/**
|
||||
* Tells wether the columns' width can be modified
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
private $_columns_locked = false;
|
||||
|
||||
/**
|
||||
* Tells wether the table has table-layout:fixed
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
private $_fixed_layout = false;
|
||||
|
||||
//........................................................................
|
||||
|
||||
function __construct(Table_Frame_Decorator $table) {
|
||||
$this->_table = $table;
|
||||
$this->reset();
|
||||
}
|
||||
|
||||
function __destruct() {
|
||||
clear_object($this);
|
||||
}
|
||||
//........................................................................
|
||||
|
||||
function reset() {
|
||||
$this->_num_rows = 0;
|
||||
$this->_num_cols = 0;
|
||||
|
||||
$this->_cells = array();
|
||||
$this->_frames = array();
|
||||
|
||||
if ( !$this->_columns_locked ) {
|
||||
$this->_columns = array();
|
||||
}
|
||||
|
||||
$this->_rows = array();
|
||||
|
||||
$this->_borders = array();
|
||||
|
||||
$this->__col = $this->__row = 0;
|
||||
}
|
||||
|
||||
//........................................................................
|
||||
|
||||
function lock_columns() {
|
||||
$this->_columns_locked = true;
|
||||
}
|
||||
|
||||
function is_columns_locked() {
|
||||
return $this->_columns_locked;
|
||||
}
|
||||
|
||||
function set_layout_fixed($fixed) {
|
||||
$this->_fixed_layout = $fixed;
|
||||
}
|
||||
|
||||
function is_layout_fixed() {
|
||||
return $this->_fixed_layout;
|
||||
}
|
||||
|
||||
function get_num_rows() { return $this->_num_rows; }
|
||||
function get_num_cols() { return $this->_num_cols; }
|
||||
|
||||
function &get_columns() {
|
||||
return $this->_columns;
|
||||
}
|
||||
|
||||
function set_columns($columns) {
|
||||
$this->_columns = $columns;
|
||||
}
|
||||
|
||||
function &get_column($i) {
|
||||
if ( !isset($this->_columns[$i]) ) {
|
||||
$this->_columns[$i] = array(
|
||||
"x" => 0,
|
||||
"min-width" => 0,
|
||||
"max-width" => 0,
|
||||
"used-width" => null,
|
||||
"absolute" => 0,
|
||||
"percent" => 0,
|
||||
"auto" => true,
|
||||
);
|
||||
}
|
||||
|
||||
return $this->_columns[$i];
|
||||
}
|
||||
|
||||
function &get_rows() {
|
||||
return $this->_rows;
|
||||
}
|
||||
|
||||
function &get_row($j) {
|
||||
if ( !isset($this->_rows[$j]) ) {
|
||||
$this->_rows[$j] = array(
|
||||
"y" => 0,
|
||||
"first-column" => 0,
|
||||
"height" => null,
|
||||
);
|
||||
}
|
||||
|
||||
return $this->_rows[$j];
|
||||
}
|
||||
|
||||
function get_border($i, $j, $h_v, $prop = null) {
|
||||
if ( !isset($this->_borders[$i][$j][$h_v]) ) {
|
||||
$this->_borders[$i][$j][$h_v] = array(
|
||||
"width" => 0,
|
||||
"style" => "solid",
|
||||
"color" => "black",
|
||||
);
|
||||
}
|
||||
|
||||
if ( isset($prop) ) {
|
||||
return $this->_borders[$i][$j][$h_v][$prop];
|
||||
}
|
||||
|
||||
return $this->_borders[$i][$j][$h_v];
|
||||
}
|
||||
|
||||
function get_border_properties($i, $j) {
|
||||
return array(
|
||||
"top" => $this->get_border($i, $j, "horizontal"),
|
||||
"right" => $this->get_border($i, $j+1, "vertical"),
|
||||
"bottom" => $this->get_border($i+1, $j, "horizontal"),
|
||||
"left" => $this->get_border($i, $j, "vertical"),
|
||||
);
|
||||
}
|
||||
|
||||
//........................................................................
|
||||
|
||||
function get_spanned_cells(Frame $frame) {
|
||||
$key = $frame->get_id();
|
||||
|
||||
if ( !isset($this->_frames[$key]) ) {
|
||||
throw new DOMPDF_Exception("Frame not found in cellmap");
|
||||
}
|
||||
|
||||
return $this->_frames[$key];
|
||||
|
||||
}
|
||||
|
||||
function frame_exists_in_cellmap(Frame $frame) {
|
||||
$key = $frame->get_id();
|
||||
return isset($this->_frames[$key]);
|
||||
}
|
||||
|
||||
function get_frame_position(Frame $frame) {
|
||||
global $_dompdf_warnings;
|
||||
|
||||
$key = $frame->get_id();
|
||||
|
||||
if ( !isset($this->_frames[$key]) ) {
|
||||
throw new DOMPDF_Exception("Frame not found in cellmap");
|
||||
}
|
||||
|
||||
$col = $this->_frames[$key]["columns"][0];
|
||||
$row = $this->_frames[$key]["rows"][0];
|
||||
|
||||
if ( !isset($this->_columns[$col])) {
|
||||
$_dompdf_warnings[] = "Frame not found in columns array. Check your table layout for missing or extra TDs.";
|
||||
$x = 0;
|
||||
}
|
||||
else {
|
||||
$x = $this->_columns[$col]["x"];
|
||||
}
|
||||
|
||||
if ( !isset($this->_rows[$row])) {
|
||||
$_dompdf_warnings[] = "Frame not found in row array. Check your table layout for missing or extra TDs.";
|
||||
$y = 0;
|
||||
}
|
||||
else {
|
||||
$y = $this->_rows[$row]["y"];
|
||||
}
|
||||
|
||||
return array($x, $y, "x" => $x, "y" => $y);
|
||||
}
|
||||
|
||||
function get_frame_width(Frame $frame) {
|
||||
$key = $frame->get_id();
|
||||
|
||||
if ( !isset($this->_frames[$key]) ) {
|
||||
throw new DOMPDF_Exception("Frame not found in cellmap");
|
||||
}
|
||||
|
||||
$cols = $this->_frames[$key]["columns"];
|
||||
$w = 0;
|
||||
foreach ($cols as $i) {
|
||||
$w += $this->_columns[$i]["used-width"];
|
||||
}
|
||||
|
||||
return $w;
|
||||
}
|
||||
|
||||
function get_frame_height(Frame $frame) {
|
||||
$key = $frame->get_id();
|
||||
|
||||
if ( !isset($this->_frames[$key]) ) {
|
||||
throw new DOMPDF_Exception("Frame not found in cellmap");
|
||||
}
|
||||
|
||||
$rows = $this->_frames[$key]["rows"];
|
||||
$h = 0;
|
||||
foreach ($rows as $i) {
|
||||
if ( !isset($this->_rows[$i]) ) {
|
||||
throw new Exception("The row #$i could not be found, please file an issue in the tracker with the HTML code");
|
||||
}
|
||||
|
||||
$h += $this->_rows[$i]["height"];
|
||||
}
|
||||
|
||||
return $h;
|
||||
}
|
||||
|
||||
|
||||
//........................................................................
|
||||
|
||||
function set_column_width($j, $width) {
|
||||
if ( $this->_columns_locked ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$col =& $this->get_column($j);
|
||||
$col["used-width"] = $width;
|
||||
$next_col =& $this->get_column($j+1);
|
||||
$next_col["x"] = $next_col["x"] + $width;
|
||||
}
|
||||
|
||||
function set_row_height($i, $height) {
|
||||
$row =& $this->get_row($i);
|
||||
|
||||
if ( $row["height"] !== null && $height <= $row["height"] ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$row["height"] = $height;
|
||||
$next_row =& $this->get_row($i+1);
|
||||
$next_row["y"] = $row["y"] + $height;
|
||||
|
||||
}
|
||||
|
||||
//........................................................................
|
||||
|
||||
|
||||
protected function _resolve_border($i, $j, $h_v, $border_spec) {
|
||||
$n_width = $border_spec["width"];
|
||||
$n_style = $border_spec["style"];
|
||||
|
||||
if ( !isset($this->_borders[$i][$j][$h_v]) ) {
|
||||
$this->_borders[$i][$j][$h_v] = $border_spec;
|
||||
return $this->_borders[$i][$j][$h_v]["width"];
|
||||
}
|
||||
|
||||
$border = &$this->_borders[$i][$j][$h_v];
|
||||
|
||||
$o_width = $border["width"];
|
||||
$o_style = $border["style"];
|
||||
|
||||
if ( ($n_style === "hidden" ||
|
||||
$n_width > $o_width ||
|
||||
$o_style === "none")
|
||||
|
||||
or
|
||||
|
||||
($o_width == $n_width &&
|
||||
in_array($n_style, self::$_BORDER_STYLE_SCORE) &&
|
||||
self::$_BORDER_STYLE_SCORE[ $n_style ] > self::$_BORDER_STYLE_SCORE[ $o_style ]) ) {
|
||||
$border = $border_spec;
|
||||
}
|
||||
|
||||
return $border["width"];
|
||||
}
|
||||
|
||||
//........................................................................
|
||||
|
||||
function add_frame(Frame $frame) {
|
||||
|
||||
$style = $frame->get_style();
|
||||
$display = $style->display;
|
||||
|
||||
$collapse = $this->_table->get_style()->border_collapse == "collapse";
|
||||
|
||||
// Recursively add the frames within tables, table-row-groups and table-rows
|
||||
if ( $display === "table-row" ||
|
||||
$display === "table" ||
|
||||
$display === "inline-table" ||
|
||||
in_array($display, Table_Frame_Decorator::$ROW_GROUPS) ) {
|
||||
|
||||
$start_row = $this->__row;
|
||||
foreach ( $frame->get_children() as $child ) {
|
||||
$this->add_frame( $child );
|
||||
}
|
||||
|
||||
if ( $display === "table-row" ) {
|
||||
$this->add_row();
|
||||
}
|
||||
|
||||
$num_rows = $this->__row - $start_row - 1;
|
||||
$key = $frame->get_id();
|
||||
|
||||
// Row groups always span across the entire table
|
||||
$this->_frames[$key]["columns"] = range(0,max(0,$this->_num_cols-1));
|
||||
$this->_frames[$key]["rows"] = range($start_row, max(0, $this->__row - 1));
|
||||
$this->_frames[$key]["frame"] = $frame;
|
||||
|
||||
if ( $display !== "table-row" && $collapse ) {
|
||||
|
||||
$bp = $style->get_border_properties();
|
||||
|
||||
// Resolve the borders
|
||||
for ( $i = 0; $i < $num_rows+1; $i++) {
|
||||
$this->_resolve_border($start_row + $i, 0, "vertical", $bp["left"]);
|
||||
$this->_resolve_border($start_row + $i, $this->_num_cols, "vertical", $bp["right"]);
|
||||
}
|
||||
|
||||
for ( $j = 0; $j < $this->_num_cols; $j++) {
|
||||
$this->_resolve_border($start_row, $j, "horizontal", $bp["top"]);
|
||||
$this->_resolve_border($this->__row, $j, "horizontal", $bp["bottom"]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$node = $frame->get_node();
|
||||
|
||||
// Determine where this cell is going
|
||||
$colspan = $node->getAttribute("colspan");
|
||||
$rowspan = $node->getAttribute("rowspan");
|
||||
|
||||
if ( !$colspan ) {
|
||||
$colspan = 1;
|
||||
$node->setAttribute("colspan",1);
|
||||
}
|
||||
|
||||
if ( !$rowspan ) {
|
||||
$rowspan = 1;
|
||||
$node->setAttribute("rowspan",1);
|
||||
}
|
||||
$key = $frame->get_id();
|
||||
|
||||
$bp = $style->get_border_properties();
|
||||
|
||||
|
||||
// Add the frame to the cellmap
|
||||
$max_left = $max_right = 0;
|
||||
|
||||
// Find the next available column (fix by Ciro Mondueri)
|
||||
$ac = $this->__col;
|
||||
while ( isset($this->_cells[$this->__row][$ac]) ) {
|
||||
$ac++;
|
||||
}
|
||||
|
||||
$this->__col = $ac;
|
||||
|
||||
// Rows:
|
||||
for ( $i = 0; $i < $rowspan; $i++ ) {
|
||||
$row = $this->__row + $i;
|
||||
|
||||
$this->_frames[$key]["rows"][] = $row;
|
||||
|
||||
for ( $j = 0; $j < $colspan; $j++) {
|
||||
$this->_cells[$row][$this->__col + $j] = $frame;
|
||||
}
|
||||
|
||||
if ( $collapse ) {
|
||||
// Resolve vertical borders
|
||||
$max_left = max($max_left, $this->_resolve_border($row, $this->__col, "vertical", $bp["left"]));
|
||||
$max_right = max($max_right, $this->_resolve_border($row, $this->__col + $colspan, "vertical", $bp["right"]));
|
||||
}
|
||||
}
|
||||
|
||||
$max_top = $max_bottom = 0;
|
||||
|
||||
// Columns:
|
||||
for ( $j = 0; $j < $colspan; $j++ ) {
|
||||
$col = $this->__col + $j;
|
||||
$this->_frames[$key]["columns"][] = $col;
|
||||
|
||||
if ( $collapse ) {
|
||||
// Resolve horizontal borders
|
||||
$max_top = max($max_top, $this->_resolve_border($this->__row, $col, "horizontal", $bp["top"]));
|
||||
$max_bottom = max($max_bottom, $this->_resolve_border($this->__row + $rowspan, $col, "horizontal", $bp["bottom"]));
|
||||
}
|
||||
}
|
||||
|
||||
$this->_frames[$key]["frame"] = $frame;
|
||||
|
||||
// Handle seperated border model
|
||||
if ( !$collapse ) {
|
||||
list($h, $v) = $this->_table->get_style()->border_spacing;
|
||||
|
||||
// Border spacing is effectively a margin between cells
|
||||
$v = $style->length_in_pt($v) / 2;
|
||||
$h = $style->length_in_pt($h) / 2;
|
||||
$style->margin = "$v $h";
|
||||
|
||||
// The additional 1/2 width gets added to the table proper
|
||||
}
|
||||
else {
|
||||
// Drop the frame's actual border
|
||||
$style->border_left_width = $max_left / 2;
|
||||
$style->border_right_width = $max_right / 2;
|
||||
$style->border_top_width = $max_top / 2;
|
||||
$style->border_bottom_width = $max_bottom / 2;
|
||||
$style->margin = "none";
|
||||
}
|
||||
|
||||
if ( !$this->_columns_locked ) {
|
||||
// Resolve the frame's width
|
||||
if ( $this->_fixed_layout ) {
|
||||
list($frame_min, $frame_max) = array(0, 10e-10);
|
||||
}
|
||||
else {
|
||||
list($frame_min, $frame_max) = $frame->get_min_max_width();
|
||||
}
|
||||
|
||||
$width = $style->width;
|
||||
|
||||
$val = null;
|
||||
if ( is_percent($width) ) {
|
||||
$var = "percent";
|
||||
$val = (float)rtrim($width, "% ") / $colspan;
|
||||
}
|
||||
else if ( $width !== "auto" ) {
|
||||
$var = "absolute";
|
||||
$val = $style->length_in_pt($frame_min) / $colspan;
|
||||
}
|
||||
|
||||
$min = 0;
|
||||
$max = 0;
|
||||
for ( $cs = 0; $cs < $colspan; $cs++ ) {
|
||||
|
||||
// Resolve the frame's width(s) with other cells
|
||||
$col =& $this->get_column( $this->__col + $cs );
|
||||
|
||||
// Note: $var is either 'percent' or 'absolute'. We compare the
|
||||
// requested percentage or absolute values with the existing widths
|
||||
// and adjust accordingly.
|
||||
if ( isset($var) && $val > $col[$var] ) {
|
||||
$col[$var] = $val;
|
||||
$col["auto"] = false;
|
||||
}
|
||||
|
||||
$min += $col["min-width"];
|
||||
$max += $col["max-width"];
|
||||
}
|
||||
|
||||
if ( $frame_min > $min ) {
|
||||
// The frame needs more space. Expand each sub-column
|
||||
// FIXME try to avoid putting this dummy value when table-layout:fixed
|
||||
$inc = ($this->is_layout_fixed() ? 10e-10 : ($frame_min - $min) / $colspan);
|
||||
for ($c = 0; $c < $colspan; $c++) {
|
||||
$col =& $this->get_column($this->__col + $c);
|
||||
$col["min-width"] += $inc;
|
||||
}
|
||||
}
|
||||
|
||||
if ( $frame_max > $max ) {
|
||||
// FIXME try to avoid putting this dummy value when table-layout:fixed
|
||||
$inc = ($this->is_layout_fixed() ? 10e-10 : ($frame_max - $max) / $colspan);
|
||||
for ($c = 0; $c < $colspan; $c++) {
|
||||
$col =& $this->get_column($this->__col + $c);
|
||||
$col["max-width"] += $inc;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$this->__col += $colspan;
|
||||
if ( $this->__col > $this->_num_cols )
|
||||
$this->_num_cols = $this->__col;
|
||||
|
||||
}
|
||||
|
||||
//........................................................................
|
||||
|
||||
function add_row() {
|
||||
|
||||
$this->__row++;
|
||||
$this->_num_rows++;
|
||||
|
||||
// Find the next available column
|
||||
$i = 0;
|
||||
while ( isset($this->_cells[$this->__row][$i]) ) {
|
||||
$i++;
|
||||
}
|
||||
|
||||
$this->__col = $i;
|
||||
|
||||
}
|
||||
|
||||
//........................................................................
|
||||
|
||||
/**
|
||||
* Remove a row from the cellmap.
|
||||
*
|
||||
* @param Frame
|
||||
*/
|
||||
function remove_row(Frame $row) {
|
||||
|
||||
$key = $row->get_id();
|
||||
if ( !isset($this->_frames[$key]) ) {
|
||||
return; // Presumably this row has alredy been removed
|
||||
}
|
||||
|
||||
$this->_row = $this->_num_rows--;
|
||||
|
||||
$rows = $this->_frames[$key]["rows"];
|
||||
$columns = $this->_frames[$key]["columns"];
|
||||
|
||||
// Remove all frames from this row
|
||||
foreach ( $rows as $r ) {
|
||||
foreach ( $columns as $c ) {
|
||||
if ( isset($this->_cells[$r][$c]) ) {
|
||||
$id = $this->_cells[$r][$c]->get_id();
|
||||
|
||||
$this->_frames[$id] = null;
|
||||
unset($this->_frames[$id]);
|
||||
|
||||
$this->_cells[$r][$c] = null;
|
||||
unset($this->_cells[$r][$c]);
|
||||
}
|
||||
}
|
||||
|
||||
$this->_rows[$r] = null;
|
||||
unset($this->_rows[$r]);
|
||||
}
|
||||
|
||||
$this->_frames[$key] = null;
|
||||
unset($this->_frames[$key]);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a row group from the cellmap.
|
||||
*
|
||||
* @param Frame $group The group to remove
|
||||
*/
|
||||
function remove_row_group(Frame $group) {
|
||||
|
||||
$key = $group->get_id();
|
||||
if ( !isset($this->_frames[$key]) ) {
|
||||
return; // Presumably this row has alredy been removed
|
||||
}
|
||||
|
||||
$iter = $group->get_first_child();
|
||||
while ($iter) {
|
||||
$this->remove_row($iter);
|
||||
$iter = $iter->get_next_sibling();
|
||||
}
|
||||
|
||||
$this->_frames[$key] = null;
|
||||
unset($this->_frames[$key]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update a row group after rows have been removed
|
||||
*
|
||||
* @param Frame $group The group to update
|
||||
* @param Frame $last_row The last row in the row group
|
||||
*/
|
||||
function update_row_group(Frame $group, Frame $last_row) {
|
||||
|
||||
$g_key = $group->get_id();
|
||||
$r_key = $last_row->get_id();
|
||||
|
||||
$r_rows = $this->_frames[$r_key]["rows"];
|
||||
$this->_frames[$g_key]["rows"] = range( $this->_frames[$g_key]["rows"][0], end($r_rows) );
|
||||
|
||||
}
|
||||
|
||||
//........................................................................
|
||||
|
||||
function assign_x_positions() {
|
||||
// Pre-condition: widths must be resolved and assigned to columns and
|
||||
// column[0]["x"] must be set.
|
||||
|
||||
if ( $this->_columns_locked ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$x = $this->_columns[0]["x"];
|
||||
foreach ( array_keys($this->_columns) as $j ) {
|
||||
$this->_columns[$j]["x"] = $x;
|
||||
$x += $this->_columns[$j]["used-width"];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function assign_frame_heights() {
|
||||
// Pre-condition: widths and heights of each column & row must be
|
||||
// calcluated
|
||||
|
||||
foreach ( $this->_frames as $arr ) {
|
||||
$frame = $arr["frame"];
|
||||
|
||||
$h = 0;
|
||||
foreach( $arr["rows"] as $row ) {
|
||||
if ( !isset($this->_rows[$row]) ) {
|
||||
// The row has been removed because of a page split, so skip it.
|
||||
continue;
|
||||
}
|
||||
|
||||
$h += $this->_rows[$row]["height"];
|
||||
}
|
||||
|
||||
if ( $frame instanceof Table_Cell_Frame_Decorator ) {
|
||||
$frame->set_cell_height($h);
|
||||
}
|
||||
else {
|
||||
$frame->get_style()->height = $h;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//........................................................................
|
||||
|
||||
/**
|
||||
* Re-adjust frame height if the table height is larger than its content
|
||||
*/
|
||||
function set_frame_heights($table_height, $content_height) {
|
||||
|
||||
|
||||
// Distribute the increased height proportionally amongst each row
|
||||
foreach ( $this->_frames as $arr ) {
|
||||
$frame = $arr["frame"];
|
||||
|
||||
$h = 0;
|
||||
foreach ($arr["rows"] as $row ) {
|
||||
if ( !isset($this->_rows[$row]) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$h += $this->_rows[$row]["height"];
|
||||
}
|
||||
|
||||
if ( $content_height > 0 ) {
|
||||
$new_height = ($h / $content_height) * $table_height;
|
||||
}
|
||||
else {
|
||||
$new_height = 0;
|
||||
}
|
||||
|
||||
if ( $frame instanceof Table_Cell_Frame_Decorator ) {
|
||||
$frame->set_cell_height($new_height);
|
||||
}
|
||||
else {
|
||||
$frame->get_style()->height = $new_height;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//........................................................................
|
||||
|
||||
// Used for debugging:
|
||||
function __toString() {
|
||||
$str = "";
|
||||
$str .= "Columns:<br/>";
|
||||
$str .= pre_r($this->_columns, true);
|
||||
$str .= "Rows:<br/>";
|
||||
$str .= pre_r($this->_rows, true);
|
||||
|
||||
$str .= "Frames:<br/>";
|
||||
$arr = array();
|
||||
foreach ( $this->_frames as $key => $val ) {
|
||||
$arr[$key] = array("columns" => $val["columns"], "rows" => $val["rows"]);
|
||||
}
|
||||
|
||||
$str .= pre_r($arr, true);
|
||||
|
||||
if ( php_sapi_name() == "cli" ) {
|
||||
$str = strip_tags(str_replace(array("<br/>","<b>","</b>"),
|
||||
array("\n",chr(27)."[01;33m", chr(27)."[0m"),
|
||||
$str));
|
||||
}
|
||||
|
||||
return $str;
|
||||
}
|
||||
}
|
||||
877
application/helpers/dompdf/include/cpdf_adapter.cls.php
Executable file
877
application/helpers/dompdf/include/cpdf_adapter.cls.php
Executable file
@@ -0,0 +1,877 @@
|
||||
<?php
|
||||
/**
|
||||
* @package dompdf
|
||||
* @link http://dompdf.github.com/
|
||||
* @author Benj Carson <benjcarson@digitaljunkies.ca>
|
||||
* @author Orion Richardson <orionr@yahoo.com>
|
||||
* @author Helmut Tischer <htischer@weihenstephan.org>
|
||||
* @author Fabien Ménager <fabien.menager@gmail.com>
|
||||
* @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
|
||||
*/
|
||||
|
||||
// FIXME: Need to sanity check inputs to this class
|
||||
require_once(DOMPDF_LIB_DIR . "/class.pdf.php");
|
||||
|
||||
/**
|
||||
* PDF rendering interface
|
||||
*
|
||||
* CPDF_Adapter provides a simple stateless interface to the stateful one
|
||||
* provided by the Cpdf class.
|
||||
*
|
||||
* Unless otherwise mentioned, all dimensions are in points (1/72 in). The
|
||||
* coordinate origin is in the top left corner, and y values increase
|
||||
* downwards.
|
||||
*
|
||||
* See {@link http://www.ros.co.nz/pdf/} for more complete documentation
|
||||
* on the underlying {@link Cpdf} class.
|
||||
*
|
||||
* @package dompdf
|
||||
*/
|
||||
class CPDF_Adapter implements Canvas {
|
||||
|
||||
/**
|
||||
* Dimensions of paper sizes in points
|
||||
*
|
||||
* @var array;
|
||||
*/
|
||||
static $PAPER_SIZES = array(
|
||||
"4a0" => array(0,0,4767.87,6740.79),
|
||||
"2a0" => array(0,0,3370.39,4767.87),
|
||||
"a0" => array(0,0,2383.94,3370.39),
|
||||
"a1" => array(0,0,1683.78,2383.94),
|
||||
"a2" => array(0,0,1190.55,1683.78),
|
||||
"a3" => array(0,0,841.89,1190.55),
|
||||
"a4" => array(0,0,595.28,841.89),
|
||||
"a5" => array(0,0,419.53,595.28),
|
||||
"a6" => array(0,0,297.64,419.53),
|
||||
"a7" => array(0,0,209.76,297.64),
|
||||
"a8" => array(0,0,147.40,209.76),
|
||||
"a9" => array(0,0,104.88,147.40),
|
||||
"a10" => array(0,0,73.70,104.88),
|
||||
"b0" => array(0,0,2834.65,4008.19),
|
||||
"b1" => array(0,0,2004.09,2834.65),
|
||||
"b2" => array(0,0,1417.32,2004.09),
|
||||
"b3" => array(0,0,1000.63,1417.32),
|
||||
"b4" => array(0,0,708.66,1000.63),
|
||||
"b5" => array(0,0,498.90,708.66),
|
||||
"b6" => array(0,0,354.33,498.90),
|
||||
"b7" => array(0,0,249.45,354.33),
|
||||
"b8" => array(0,0,175.75,249.45),
|
||||
"b9" => array(0,0,124.72,175.75),
|
||||
"b10" => array(0,0,87.87,124.72),
|
||||
"c0" => array(0,0,2599.37,3676.54),
|
||||
"c1" => array(0,0,1836.85,2599.37),
|
||||
"c2" => array(0,0,1298.27,1836.85),
|
||||
"c3" => array(0,0,918.43,1298.27),
|
||||
"c4" => array(0,0,649.13,918.43),
|
||||
"c5" => array(0,0,459.21,649.13),
|
||||
"c6" => array(0,0,323.15,459.21),
|
||||
"c7" => array(0,0,229.61,323.15),
|
||||
"c8" => array(0,0,161.57,229.61),
|
||||
"c9" => array(0,0,113.39,161.57),
|
||||
"c10" => array(0,0,79.37,113.39),
|
||||
"ra0" => array(0,0,2437.80,3458.27),
|
||||
"ra1" => array(0,0,1729.13,2437.80),
|
||||
"ra2" => array(0,0,1218.90,1729.13),
|
||||
"ra3" => array(0,0,864.57,1218.90),
|
||||
"ra4" => array(0,0,609.45,864.57),
|
||||
"sra0" => array(0,0,2551.18,3628.35),
|
||||
"sra1" => array(0,0,1814.17,2551.18),
|
||||
"sra2" => array(0,0,1275.59,1814.17),
|
||||
"sra3" => array(0,0,907.09,1275.59),
|
||||
"sra4" => array(0,0,637.80,907.09),
|
||||
"letter" => array(0,0,612.00,792.00),
|
||||
"legal" => array(0,0,612.00,1008.00),
|
||||
"ledger" => array(0,0,1224.00, 792.00),
|
||||
"tabloid" => array(0,0,792.00, 1224.00),
|
||||
"executive" => array(0,0,521.86,756.00),
|
||||
"folio" => array(0,0,612.00,936.00),
|
||||
"commercial #10 envelope" => array(0,0,684,297),
|
||||
"catalog #10 1/2 envelope" => array(0,0,648,864),
|
||||
"8.5x11" => array(0,0,612.00,792.00),
|
||||
"8.5x14" => array(0,0,612.00,1008.0),
|
||||
"11x17" => array(0,0,792.00, 1224.00),
|
||||
);
|
||||
|
||||
/**
|
||||
* The DOMPDF object
|
||||
*
|
||||
* @var DOMPDF
|
||||
*/
|
||||
private $_dompdf;
|
||||
|
||||
/**
|
||||
* Instance of Cpdf class
|
||||
*
|
||||
* @var Cpdf
|
||||
*/
|
||||
private $_pdf;
|
||||
|
||||
/**
|
||||
* PDF width, in points
|
||||
*
|
||||
* @var float
|
||||
*/
|
||||
private $_width;
|
||||
|
||||
/**
|
||||
* PDF height, in points
|
||||
*
|
||||
* @var float;
|
||||
*/
|
||||
private $_height;
|
||||
|
||||
/**
|
||||
* Current page number
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
private $_page_number;
|
||||
|
||||
/**
|
||||
* Total number of pages
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
private $_page_count;
|
||||
|
||||
/**
|
||||
* Text to display on every page
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $_page_text;
|
||||
|
||||
/**
|
||||
* Array of pages for accesing after rendering is initially complete
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $_pages;
|
||||
|
||||
/**
|
||||
* Array of temporary cached images to be deleted when processing is complete
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $_image_cache;
|
||||
|
||||
/**
|
||||
* Class constructor
|
||||
*
|
||||
* @param mixed $paper The size of paper to use in this PDF ({@link CPDF_Adapter::$PAPER_SIZES})
|
||||
* @param string $orientation The orientation of the document (either 'landscape' or 'portrait')
|
||||
* @param DOMPDF $dompdf The DOMPDF instance
|
||||
*/
|
||||
function __construct($paper = "letter", $orientation = "portrait", DOMPDF $dompdf) {
|
||||
if ( is_array($paper) ) {
|
||||
$size = $paper;
|
||||
}
|
||||
else if ( isset(self::$PAPER_SIZES[mb_strtolower($paper)]) ) {
|
||||
$size = self::$PAPER_SIZES[mb_strtolower($paper)];
|
||||
}
|
||||
else {
|
||||
$size = self::$PAPER_SIZES["letter"];
|
||||
}
|
||||
|
||||
if ( mb_strtolower($orientation) === "landscape" ) {
|
||||
list($size[2], $size[3]) = array($size[3], $size[2]);
|
||||
}
|
||||
|
||||
$this->_dompdf = $dompdf;
|
||||
|
||||
$this->_pdf = new Cpdf(
|
||||
$size,
|
||||
$dompdf->get_option("enable_unicode"),
|
||||
$dompdf->get_option("font_cache"),
|
||||
$dompdf->get_option("temp_dir")
|
||||
);
|
||||
|
||||
$this->_pdf->addInfo("Creator", "DOMPDF");
|
||||
$time = substr_replace(date('YmdHisO'), '\'', -2, 0).'\'';
|
||||
$this->_pdf->addInfo("CreationDate", "D:$time");
|
||||
$this->_pdf->addInfo("ModDate", "D:$time");
|
||||
|
||||
$this->_width = $size[2] - $size[0];
|
||||
$this->_height= $size[3] - $size[1];
|
||||
|
||||
$this->_page_number = $this->_page_count = 1;
|
||||
$this->_page_text = array();
|
||||
|
||||
$this->_pages = array($this->_pdf->getFirstPageId());
|
||||
|
||||
$this->_image_cache = array();
|
||||
}
|
||||
|
||||
function get_dompdf(){
|
||||
return $this->_dompdf;
|
||||
}
|
||||
|
||||
/**
|
||||
* Class destructor
|
||||
*
|
||||
* Deletes all temporary image files
|
||||
*/
|
||||
function __destruct() {
|
||||
foreach ($this->_image_cache as $img) {
|
||||
// The file might be already deleted by 3rd party tmp cleaner,
|
||||
// the file might not have been created at all
|
||||
// (if image outputting commands failed)
|
||||
// or because the destructor was called twice accidentally.
|
||||
if (!file_exists($img)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (DEBUGPNG) print '[__destruct unlink '.$img.']';
|
||||
if (!DEBUGKEEPTEMP) unlink($img);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Cpdf instance
|
||||
*
|
||||
* @return Cpdf
|
||||
*/
|
||||
function get_cpdf() {
|
||||
return $this->_pdf;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add meta information to the PDF
|
||||
*
|
||||
* @param string $label label of the value (Creator, Producer, etc.)
|
||||
* @param string $value the text to set
|
||||
*/
|
||||
function add_info($label, $value) {
|
||||
$this->_pdf->addInfo($label, $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens a new 'object'
|
||||
*
|
||||
* While an object is open, all drawing actions are recored in the object,
|
||||
* as opposed to being drawn on the current page. Objects can be added
|
||||
* later to a specific page or to several pages.
|
||||
*
|
||||
* The return value is an integer ID for the new object.
|
||||
*
|
||||
* @see CPDF_Adapter::close_object()
|
||||
* @see CPDF_Adapter::add_object()
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
function open_object() {
|
||||
$ret = $this->_pdf->openObject();
|
||||
$this->_pdf->saveState();
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reopens an existing 'object'
|
||||
*
|
||||
* @see CPDF_Adapter::open_object()
|
||||
* @param int $object the ID of a previously opened object
|
||||
*/
|
||||
function reopen_object($object) {
|
||||
$this->_pdf->reopenObject($object);
|
||||
$this->_pdf->saveState();
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the current 'object'
|
||||
*
|
||||
* @see CPDF_Adapter::open_object()
|
||||
*/
|
||||
function close_object() {
|
||||
$this->_pdf->restoreState();
|
||||
$this->_pdf->closeObject();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a specified 'object' to the document
|
||||
*
|
||||
* $object int specifying an object created with {@link
|
||||
* CPDF_Adapter::open_object()}. $where can be one of:
|
||||
* - 'add' add to current page only
|
||||
* - 'all' add to every page from the current one onwards
|
||||
* - 'odd' add to all odd numbered pages from now on
|
||||
* - 'even' add to all even numbered pages from now on
|
||||
* - 'next' add the object to the next page only
|
||||
* - 'nextodd' add to all odd numbered pages from the next one
|
||||
* - 'nexteven' add to all even numbered pages from the next one
|
||||
*
|
||||
* @see Cpdf::addObject()
|
||||
*
|
||||
* @param int $object
|
||||
* @param string $where
|
||||
*/
|
||||
function add_object($object, $where = 'all') {
|
||||
$this->_pdf->addObject($object, $where);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops the specified 'object' from appearing in the document.
|
||||
*
|
||||
* The object will stop being displayed on the page following the current
|
||||
* one.
|
||||
*
|
||||
* @param int $object
|
||||
*/
|
||||
function stop_object($object) {
|
||||
$this->_pdf->stopObject($object);
|
||||
}
|
||||
|
||||
/**
|
||||
* @access private
|
||||
*/
|
||||
function serialize_object($id) {
|
||||
// Serialize the pdf object's current state for retrieval later
|
||||
return $this->_pdf->serializeObject($id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @access private
|
||||
*/
|
||||
function reopen_serialized_object($obj) {
|
||||
return $this->_pdf->restoreSerializedObject($obj);
|
||||
}
|
||||
|
||||
//........................................................................
|
||||
|
||||
/**
|
||||
* Returns the PDF's width in points
|
||||
* @return float
|
||||
*/
|
||||
function get_width() { return $this->_width; }
|
||||
|
||||
/**
|
||||
* Returns the PDF's height in points
|
||||
* @return float
|
||||
*/
|
||||
function get_height() { return $this->_height; }
|
||||
|
||||
/**
|
||||
* Returns the current page number
|
||||
* @return int
|
||||
*/
|
||||
function get_page_number() { return $this->_page_number; }
|
||||
|
||||
/**
|
||||
* Returns the total number of pages in the document
|
||||
* @return int
|
||||
*/
|
||||
function get_page_count() { return $this->_page_count; }
|
||||
|
||||
/**
|
||||
* Sets the current page number
|
||||
*
|
||||
* @param int $num
|
||||
*/
|
||||
function set_page_number($num) { $this->_page_number = $num; }
|
||||
|
||||
/**
|
||||
* Sets the page count
|
||||
*
|
||||
* @param int $count
|
||||
*/
|
||||
function set_page_count($count) { $this->_page_count = $count; }
|
||||
|
||||
/**
|
||||
* Sets the stroke color
|
||||
*
|
||||
* See {@link Style::set_color()} for the format of the color array.
|
||||
* @param array $color
|
||||
*/
|
||||
protected function _set_stroke_color($color) {
|
||||
$this->_pdf->setStrokeColor($color);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the fill colour
|
||||
*
|
||||
* See {@link Style::set_color()} for the format of the colour array.
|
||||
* @param array $color
|
||||
*/
|
||||
protected function _set_fill_color($color) {
|
||||
$this->_pdf->setColor($color);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets line transparency
|
||||
* @see Cpdf::setLineTransparency()
|
||||
*
|
||||
* Valid blend modes are (case-sensitive):
|
||||
*
|
||||
* Normal, Multiply, Screen, Overlay, Darken, Lighten,
|
||||
* ColorDodge, ColorBurn, HardLight, SoftLight, Difference,
|
||||
* Exclusion
|
||||
*
|
||||
* @param string $mode the blending mode to use
|
||||
* @param float $opacity 0.0 fully transparent, 1.0 fully opaque
|
||||
*/
|
||||
protected function _set_line_transparency($mode, $opacity) {
|
||||
$this->_pdf->setLineTransparency($mode, $opacity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets fill transparency
|
||||
* @see Cpdf::setFillTransparency()
|
||||
*
|
||||
* Valid blend modes are (case-sensitive):
|
||||
*
|
||||
* Normal, Multiply, Screen, Overlay, Darken, Lighten,
|
||||
* ColorDogde, ColorBurn, HardLight, SoftLight, Difference,
|
||||
* Exclusion
|
||||
*
|
||||
* @param string $mode the blending mode to use
|
||||
* @param float $opacity 0.0 fully transparent, 1.0 fully opaque
|
||||
*/
|
||||
protected function _set_fill_transparency($mode, $opacity) {
|
||||
$this->_pdf->setFillTransparency($mode, $opacity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the line style
|
||||
*
|
||||
* @see Cpdf::setLineStyle()
|
||||
*
|
||||
* @param float $width
|
||||
* @param string $cap
|
||||
* @param string $join
|
||||
* @param array $dash
|
||||
*/
|
||||
protected function _set_line_style($width, $cap, $join, $dash) {
|
||||
$this->_pdf->setLineStyle($width, $cap, $join, $dash);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the opacity
|
||||
*
|
||||
* @param $opacity
|
||||
* @param $mode
|
||||
*/
|
||||
function set_opacity($opacity, $mode = "Normal") {
|
||||
$this->_set_line_transparency($mode, $opacity);
|
||||
$this->_set_fill_transparency($mode, $opacity);
|
||||
}
|
||||
|
||||
function set_default_view($view, $options = array()) {
|
||||
array_unshift($options, $view);
|
||||
call_user_func_array(array($this->_pdf, "openHere"), $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remaps y coords from 4th to 1st quadrant
|
||||
*
|
||||
* @param float $y
|
||||
* @return float
|
||||
*/
|
||||
protected function y($y) {
|
||||
return $this->_height - $y;
|
||||
}
|
||||
|
||||
// Canvas implementation
|
||||
function line($x1, $y1, $x2, $y2, $color, $width, $style = array()) {
|
||||
$this->_set_stroke_color($color);
|
||||
$this->_set_line_style($width, "butt", "", $style);
|
||||
|
||||
$this->_pdf->line($x1, $this->y($y1),
|
||||
$x2, $this->y($y2));
|
||||
}
|
||||
|
||||
function arc($x, $y, $r1, $r2, $astart, $aend, $color, $width, $style = array()) {
|
||||
$this->_set_stroke_color($color);
|
||||
$this->_set_line_style($width, "butt", "", $style);
|
||||
|
||||
$this->_pdf->ellipse($x, $this->y($y), $r1, $r2, 0, 8, $astart, $aend, false, false, true, false);
|
||||
}
|
||||
|
||||
//........................................................................
|
||||
|
||||
/**
|
||||
* Convert a GIF or BMP image to a PNG image
|
||||
*
|
||||
* @param string $image_url
|
||||
* @param integer $type
|
||||
*
|
||||
* @throws DOMPDF_Exception
|
||||
* @return string The url of the newly converted image
|
||||
*/
|
||||
protected function _convert_gif_bmp_to_png($image_url, $type) {
|
||||
$image_type = Image_Cache::type_to_ext($type);
|
||||
$func_name = "imagecreatefrom$image_type";
|
||||
|
||||
if ( !function_exists($func_name) ) {
|
||||
throw new DOMPDF_Exception("Function $func_name() not found. Cannot convert $image_type image: $image_url. Please install the image PHP extension.");
|
||||
}
|
||||
|
||||
set_error_handler("record_warnings");
|
||||
$im = $func_name($image_url);
|
||||
|
||||
if ( $im ) {
|
||||
imageinterlace($im, false);
|
||||
|
||||
$tmp_dir = $this->_dompdf->get_option("temp_dir");
|
||||
$tmp_name = tempnam($tmp_dir, "{$image_type}dompdf_img_");
|
||||
@unlink($tmp_name);
|
||||
$filename = "$tmp_name.png";
|
||||
$this->_image_cache[] = $filename;
|
||||
|
||||
imagepng($im, $filename);
|
||||
imagedestroy($im);
|
||||
}
|
||||
else {
|
||||
$filename = Image_Cache::$broken_image;
|
||||
}
|
||||
|
||||
restore_error_handler();
|
||||
|
||||
return $filename;
|
||||
}
|
||||
|
||||
function rectangle($x1, $y1, $w, $h, $color, $width, $style = array()) {
|
||||
$this->_set_stroke_color($color);
|
||||
$this->_set_line_style($width, "butt", "", $style);
|
||||
$this->_pdf->rectangle($x1, $this->y($y1) - $h, $w, $h);
|
||||
}
|
||||
|
||||
function filled_rectangle($x1, $y1, $w, $h, $color) {
|
||||
$this->_set_fill_color($color);
|
||||
$this->_pdf->filledRectangle($x1, $this->y($y1) - $h, $w, $h);
|
||||
}
|
||||
|
||||
function clipping_rectangle($x1, $y1, $w, $h) {
|
||||
$this->_pdf->clippingRectangle($x1, $this->y($y1) - $h, $w, $h);
|
||||
}
|
||||
|
||||
function clipping_roundrectangle($x1, $y1, $w, $h, $rTL, $rTR, $rBR, $rBL) {
|
||||
$this->_pdf->clippingRectangleRounded($x1, $this->y($y1) - $h, $w, $h, $rTL, $rTR, $rBR, $rBL);
|
||||
}
|
||||
|
||||
function clipping_end() {
|
||||
$this->_pdf->clippingEnd();
|
||||
}
|
||||
|
||||
function save() {
|
||||
$this->_pdf->saveState();
|
||||
}
|
||||
|
||||
function restore() {
|
||||
$this->_pdf->restoreState();
|
||||
}
|
||||
|
||||
function rotate($angle, $x, $y) {
|
||||
$this->_pdf->rotate($angle, $x, $y);
|
||||
}
|
||||
|
||||
function skew($angle_x, $angle_y, $x, $y) {
|
||||
$this->_pdf->skew($angle_x, $angle_y, $x, $y);
|
||||
}
|
||||
|
||||
function scale($s_x, $s_y, $x, $y) {
|
||||
$this->_pdf->scale($s_x, $s_y, $x, $y);
|
||||
}
|
||||
|
||||
function translate($t_x, $t_y) {
|
||||
$this->_pdf->translate($t_x, $t_y);
|
||||
}
|
||||
|
||||
function transform($a, $b, $c, $d, $e, $f) {
|
||||
$this->_pdf->transform(array($a, $b, $c, $d, $e, $f));
|
||||
}
|
||||
|
||||
function polygon($points, $color, $width = null, $style = array(), $fill = false) {
|
||||
$this->_set_fill_color($color);
|
||||
$this->_set_stroke_color($color);
|
||||
|
||||
// Adjust y values
|
||||
for ( $i = 1; $i < count($points); $i += 2) {
|
||||
$points[$i] = $this->y($points[$i]);
|
||||
}
|
||||
|
||||
$this->_pdf->polygon($points, count($points) / 2, $fill);
|
||||
}
|
||||
|
||||
function circle($x, $y, $r1, $color, $width = null, $style = null, $fill = false) {
|
||||
$this->_set_fill_color($color);
|
||||
$this->_set_stroke_color($color);
|
||||
|
||||
if ( !$fill && isset($width) ) {
|
||||
$this->_set_line_style($width, "round", "round", $style);
|
||||
}
|
||||
|
||||
$this->_pdf->ellipse($x, $this->y($y), $r1, 0, 0, 8, 0, 360, 1, $fill);
|
||||
}
|
||||
|
||||
function image($img, $x, $y, $w, $h, $resolution = "normal") {
|
||||
list($width, $height, $type) = dompdf_getimagesize($img);
|
||||
|
||||
$debug_png = $this->_dompdf->get_option("debug_png");
|
||||
|
||||
if ($debug_png) print "[image:$img|$width|$height|$type]";
|
||||
|
||||
switch ($type) {
|
||||
case IMAGETYPE_JPEG:
|
||||
if ($debug_png) print '!!!jpg!!!';
|
||||
$this->_pdf->addJpegFromFile($img, $x, $this->y($y) - $h, $w, $h);
|
||||
break;
|
||||
|
||||
case IMAGETYPE_GIF:
|
||||
case IMAGETYPE_BMP:
|
||||
if ($debug_png) print '!!!bmp or gif!!!';
|
||||
// @todo use cache for BMP and GIF
|
||||
$img = $this->_convert_gif_bmp_to_png($img, $type);
|
||||
|
||||
case IMAGETYPE_PNG:
|
||||
if ($debug_png) print '!!!png!!!';
|
||||
|
||||
$this->_pdf->addPngFromFile($img, $x, $this->y($y) - $h, $w, $h);
|
||||
break;
|
||||
|
||||
default:
|
||||
if ($debug_png) print '!!!unknown!!!';
|
||||
}
|
||||
}
|
||||
|
||||
function text($x, $y, $text, $font, $size, $color = array(0,0,0), $word_space = 0.0, $char_space = 0.0, $angle = 0.0) {
|
||||
$pdf = $this->_pdf;
|
||||
|
||||
$pdf->setColor($color);
|
||||
|
||||
$font .= ".afm";
|
||||
$pdf->selectFont($font);
|
||||
|
||||
//Font_Metrics::get_font_height($font, $size) ==
|
||||
//$this->get_font_height($font, $size) ==
|
||||
//$this->_pdf->selectFont($font),$this->_pdf->getFontHeight($size)
|
||||
//- FontBBoxheight+FontHeightOffset, scaled to $size, in pt
|
||||
//$this->_pdf->getFontDescender($size)
|
||||
//- Descender scaled to size
|
||||
//
|
||||
//$this->_pdf->fonts[$this->_pdf->currentFont] sizes:
|
||||
//['FontBBox'][0] left, ['FontBBox'][1] bottom, ['FontBBox'][2] right, ['FontBBox'][3] top
|
||||
//Maximum extent of all glyphs of the font from the baseline point
|
||||
//['Ascender'] maximum height above baseline except accents
|
||||
//['Descender'] maximum depth below baseline, negative number means below baseline
|
||||
//['FontHeightOffset'] manual enhancement of .afm files to trim windows fonts. currently not used.
|
||||
//Values are in 1/1000 pt for a font size of 1 pt
|
||||
//
|
||||
//['FontBBox'][1] should be close to ['Descender']
|
||||
//['FontBBox'][3] should be close to ['Ascender']+Accents
|
||||
//in practice, FontBBox values are a little bigger
|
||||
//
|
||||
//The text position is referenced to the baseline, not to the lower corner of the FontBBox,
|
||||
//for what the left,top corner is given.
|
||||
//FontBBox spans also the background box for the text.
|
||||
//If the lower corner would be used as reference point, the Descents of the glyphs would
|
||||
//hang over the background box border.
|
||||
//Therefore compensate only the extent above the Baseline.
|
||||
//
|
||||
//print '<pre>['.$font.','.$size.','.$pdf->getFontHeight($size).','.$pdf->getFontDescender($size).','.$pdf->fonts[$pdf->currentFont]['FontBBox'][3].','.$pdf->fonts[$pdf->currentFont]['FontBBox'][1].','.$pdf->fonts[$pdf->currentFont]['FontHeightOffset'].','.$pdf->fonts[$pdf->currentFont]['Ascender'].','.$pdf->fonts[$pdf->currentFont]['Descender'].']</pre>';
|
||||
//
|
||||
//$pdf->addText($x, $this->y($y) - ($pdf->fonts[$pdf->currentFont]['FontBBox'][3]*$size)/1000, $size, $text, $angle, $word_space, $char_space);
|
||||
$pdf->addText($x, $this->y($y) - $pdf->getFontHeight($size), $size, $text, $angle, $word_space, $char_space);
|
||||
}
|
||||
|
||||
//........................................................................
|
||||
|
||||
function javascript($code) {
|
||||
$this->_pdf->addJavascript($code);
|
||||
}
|
||||
|
||||
//........................................................................
|
||||
|
||||
/**
|
||||
* Add a named destination (similar to <a name="foo">...</a> in html)
|
||||
*
|
||||
* @param string $anchorname The name of the named destination
|
||||
*/
|
||||
function add_named_dest($anchorname) {
|
||||
$this->_pdf->addDestination($anchorname, "Fit");
|
||||
}
|
||||
|
||||
//........................................................................
|
||||
|
||||
/**
|
||||
* Add a link to the pdf
|
||||
*
|
||||
* @param string $url The url to link to
|
||||
* @param float $x The x position of the link
|
||||
* @param float $y The y position of the link
|
||||
* @param float $width The width of the link
|
||||
* @param float $height The height of the link
|
||||
*/
|
||||
function add_link($url, $x, $y, $width, $height) {
|
||||
|
||||
$y = $this->y($y) - $height;
|
||||
|
||||
if ( strpos($url, '#') === 0 ) {
|
||||
// Local link
|
||||
$name = substr($url,1);
|
||||
if ( $name ) {
|
||||
$this->_pdf->addInternalLink($name, $x, $y, $x + $width, $y + $height);
|
||||
}
|
||||
|
||||
}
|
||||
else {
|
||||
$this->_pdf->addLink(rawurldecode($url), $x, $y, $x + $width, $y + $height);
|
||||
}
|
||||
}
|
||||
|
||||
function get_text_width($text, $font, $size, $word_spacing = 0, $char_spacing = 0) {
|
||||
$this->_pdf->selectFont($font);
|
||||
|
||||
$unicode = $this->_dompdf->get_option("enable_unicode");
|
||||
if (!$unicode) {
|
||||
$text = mb_convert_encoding($text, 'Windows-1252', 'UTF-8');
|
||||
}
|
||||
|
||||
return $this->_pdf->getTextWidth($size, $text, $word_spacing, $char_spacing);
|
||||
}
|
||||
|
||||
function register_string_subset($font, $string) {
|
||||
$this->_pdf->registerText($font, $string);
|
||||
}
|
||||
|
||||
function get_font_height($font, $size) {
|
||||
$this->_pdf->selectFont($font);
|
||||
|
||||
$ratio = $this->_dompdf->get_option("font_height_ratio");
|
||||
return $this->_pdf->getFontHeight($size) * $ratio;
|
||||
}
|
||||
|
||||
/*function get_font_x_height($font, $size) {
|
||||
$this->_pdf->selectFont($font);
|
||||
$ratio = $this->_dompdf->get_option("font_height_ratio");
|
||||
return $this->_pdf->getFontXHeight($size) * $ratio;
|
||||
}*/
|
||||
|
||||
function get_font_baseline($font, $size) {
|
||||
$ratio = $this->_dompdf->get_option("font_height_ratio");
|
||||
return $this->get_font_height($font, $size) / $ratio;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes text at the specified x and y coordinates on every page
|
||||
*
|
||||
* The strings '{PAGE_NUM}' and '{PAGE_COUNT}' are automatically replaced
|
||||
* with their current values.
|
||||
*
|
||||
* See {@link Style::munge_color()} for the format of the colour array.
|
||||
*
|
||||
* @param float $x
|
||||
* @param float $y
|
||||
* @param string $text the text to write
|
||||
* @param string $font the font file to use
|
||||
* @param float $size the font size, in points
|
||||
* @param array $color
|
||||
* @param float $word_space word spacing adjustment
|
||||
* @param float $char_space char spacing adjustment
|
||||
* @param float $angle angle to write the text at, measured CW starting from the x-axis
|
||||
*/
|
||||
function page_text($x, $y, $text, $font, $size, $color = array(0,0,0), $word_space = 0.0, $char_space = 0.0, $angle = 0.0) {
|
||||
$_t = "text";
|
||||
$this->_page_text[] = compact("_t", "x", "y", "text", "font", "size", "color", "word_space", "char_space", "angle");
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes a script on every page
|
||||
*
|
||||
* The variables $pdf, $PAGE_NUM, and $PAGE_COUNT are available.
|
||||
*
|
||||
* This function can be used to add page numbers to all pages
|
||||
* after the first one, for example.
|
||||
*
|
||||
* @param string $code the script code
|
||||
* @param string $type the language type for script
|
||||
*/
|
||||
function page_script($code, $type = "text/php") {
|
||||
$_t = "script";
|
||||
$this->_page_text[] = compact("_t", "code", "type");
|
||||
}
|
||||
|
||||
function new_page() {
|
||||
$this->_page_number++;
|
||||
$this->_page_count++;
|
||||
|
||||
$ret = $this->_pdf->newPage();
|
||||
$this->_pages[] = $ret;
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add text to each page after rendering is complete
|
||||
*/
|
||||
protected function _add_page_text() {
|
||||
|
||||
if ( !count($this->_page_text) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$page_number = 1;
|
||||
$eval = null;
|
||||
|
||||
foreach ($this->_pages as $pid) {
|
||||
$this->reopen_object($pid);
|
||||
|
||||
foreach ($this->_page_text as $pt) {
|
||||
extract($pt);
|
||||
|
||||
switch ($_t) {
|
||||
case "text":
|
||||
$text = str_replace(array("{PAGE_NUM}","{PAGE_COUNT}"),
|
||||
array($page_number, $this->_page_count), $text);
|
||||
$this->text($x, $y, $text, $font, $size, $color, $word_space, $char_space, $angle);
|
||||
break;
|
||||
|
||||
case "script":
|
||||
if ( !$eval ) {
|
||||
$eval = new PHP_Evaluator($this);
|
||||
}
|
||||
$eval->evaluate($code, array('PAGE_NUM' => $page_number, 'PAGE_COUNT' => $this->_page_count));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$this->close_object();
|
||||
$page_number++;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Streams the PDF directly to the browser
|
||||
*
|
||||
* @param string $filename the name of the PDF file
|
||||
* @param array $options associative array, 'Attachment' => 0 or 1, 'compress' => 1 or 0
|
||||
*/
|
||||
function stream($filename, $options = null) {
|
||||
// Add page text
|
||||
$this->_add_page_text();
|
||||
|
||||
$options["Content-Disposition"] = $filename;
|
||||
$this->_pdf->stream($options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the PDF as a string
|
||||
*
|
||||
* @param array $options Output options
|
||||
* @return string
|
||||
*/
|
||||
function output($options = null) {
|
||||
$this->_add_page_text();
|
||||
|
||||
$debug = isset($options["compress"]) && $options["compress"] != 1;
|
||||
|
||||
return $this->_pdf->output($debug);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns logging messages generated by the Cpdf class
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
function get_messages() {
|
||||
return $this->_pdf->messages;
|
||||
}
|
||||
}
|
||||
287
application/helpers/dompdf/include/css_color.cls.php
Executable file
287
application/helpers/dompdf/include/css_color.cls.php
Executable file
@@ -0,0 +1,287 @@
|
||||
<?php
|
||||
/**
|
||||
* @package dompdf
|
||||
* @link http://dompdf.github.com/
|
||||
* @author Benj Carson <benjcarson@digitaljunkies.ca>
|
||||
* @author Fabien Ménager <fabien.menager@gmail.com>
|
||||
* @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
|
||||
*/
|
||||
|
||||
class CSS_Color {
|
||||
static $cssColorNames = array(
|
||||
"aliceblue" => "F0F8FF",
|
||||
"antiquewhite" => "FAEBD7",
|
||||
"aqua" => "00FFFF",
|
||||
"aquamarine" => "7FFFD4",
|
||||
"azure" => "F0FFFF",
|
||||
"beige" => "F5F5DC",
|
||||
"bisque" => "FFE4C4",
|
||||
"black" => "000000",
|
||||
"blanchedalmond" => "FFEBCD",
|
||||
"blue" => "0000FF",
|
||||
"blueviolet" => "8A2BE2",
|
||||
"brown" => "A52A2A",
|
||||
"burlywood" => "DEB887",
|
||||
"cadetblue" => "5F9EA0",
|
||||
"chartreuse" => "7FFF00",
|
||||
"chocolate" => "D2691E",
|
||||
"coral" => "FF7F50",
|
||||
"cornflowerblue" => "6495ED",
|
||||
"cornsilk" => "FFF8DC",
|
||||
"crimson" => "DC143C",
|
||||
"cyan" => "00FFFF",
|
||||
"darkblue" => "00008B",
|
||||
"darkcyan" => "008B8B",
|
||||
"darkgoldenrod" => "B8860B",
|
||||
"darkgray" => "A9A9A9",
|
||||
"darkgreen" => "006400",
|
||||
"darkgrey" => "A9A9A9",
|
||||
"darkkhaki" => "BDB76B",
|
||||
"darkmagenta" => "8B008B",
|
||||
"darkolivegreen" => "556B2F",
|
||||
"darkorange" => "FF8C00",
|
||||
"darkorchid" => "9932CC",
|
||||
"darkred" => "8B0000",
|
||||
"darksalmon" => "E9967A",
|
||||
"darkseagreen" => "8FBC8F",
|
||||
"darkslateblue" => "483D8B",
|
||||
"darkslategray" => "2F4F4F",
|
||||
"darkslategrey" => "2F4F4F",
|
||||
"darkturquoise" => "00CED1",
|
||||
"darkviolet" => "9400D3",
|
||||
"deeppink" => "FF1493",
|
||||
"deepskyblue" => "00BFFF",
|
||||
"dimgray" => "696969",
|
||||
"dimgrey" => "696969",
|
||||
"dodgerblue" => "1E90FF",
|
||||
"firebrick" => "B22222",
|
||||
"floralwhite" => "FFFAF0",
|
||||
"forestgreen" => "228B22",
|
||||
"fuchsia" => "FF00FF",
|
||||
"gainsboro" => "DCDCDC",
|
||||
"ghostwhite" => "F8F8FF",
|
||||
"gold" => "FFD700",
|
||||
"goldenrod" => "DAA520",
|
||||
"gray" => "808080",
|
||||
"green" => "008000",
|
||||
"greenyellow" => "ADFF2F",
|
||||
"grey" => "808080",
|
||||
"honeydew" => "F0FFF0",
|
||||
"hotpink" => "FF69B4",
|
||||
"indianred" => "CD5C5C",
|
||||
"indigo" => "4B0082",
|
||||
"ivory" => "FFFFF0",
|
||||
"khaki" => "F0E68C",
|
||||
"lavender" => "E6E6FA",
|
||||
"lavenderblush" => "FFF0F5",
|
||||
"lawngreen" => "7CFC00",
|
||||
"lemonchiffon" => "FFFACD",
|
||||
"lightblue" => "ADD8E6",
|
||||
"lightcoral" => "F08080",
|
||||
"lightcyan" => "E0FFFF",
|
||||
"lightgoldenrodyellow" => "FAFAD2",
|
||||
"lightgray" => "D3D3D3",
|
||||
"lightgreen" => "90EE90",
|
||||
"lightgrey" => "D3D3D3",
|
||||
"lightpink" => "FFB6C1",
|
||||
"lightsalmon" => "FFA07A",
|
||||
"lightseagreen" => "20B2AA",
|
||||
"lightskyblue" => "87CEFA",
|
||||
"lightslategray" => "778899",
|
||||
"lightslategrey" => "778899",
|
||||
"lightsteelblue" => "B0C4DE",
|
||||
"lightyellow" => "FFFFE0",
|
||||
"lime" => "00FF00",
|
||||
"limegreen" => "32CD32",
|
||||
"linen" => "FAF0E6",
|
||||
"magenta" => "FF00FF",
|
||||
"maroon" => "800000",
|
||||
"mediumaquamarine" => "66CDAA",
|
||||
"mediumblue" => "0000CD",
|
||||
"mediumorchid" => "BA55D3",
|
||||
"mediumpurple" => "9370DB",
|
||||
"mediumseagreen" => "3CB371",
|
||||
"mediumslateblue" => "7B68EE",
|
||||
"mediumspringgreen" => "00FA9A",
|
||||
"mediumturquoise" => "48D1CC",
|
||||
"mediumvioletred" => "C71585",
|
||||
"midnightblue" => "191970",
|
||||
"mintcream" => "F5FFFA",
|
||||
"mistyrose" => "FFE4E1",
|
||||
"moccasin" => "FFE4B5",
|
||||
"navajowhite" => "FFDEAD",
|
||||
"navy" => "000080",
|
||||
"oldlace" => "FDF5E6",
|
||||
"olive" => "808000",
|
||||
"olivedrab" => "6B8E23",
|
||||
"orange" => "FFA500",
|
||||
"orangered" => "FF4500",
|
||||
"orchid" => "DA70D6",
|
||||
"palegoldenrod" => "EEE8AA",
|
||||
"palegreen" => "98FB98",
|
||||
"paleturquoise" => "AFEEEE",
|
||||
"palevioletred" => "DB7093",
|
||||
"papayawhip" => "FFEFD5",
|
||||
"peachpuff" => "FFDAB9",
|
||||
"peru" => "CD853F",
|
||||
"pink" => "FFC0CB",
|
||||
"plum" => "DDA0DD",
|
||||
"powderblue" => "B0E0E6",
|
||||
"purple" => "800080",
|
||||
"red" => "FF0000",
|
||||
"rosybrown" => "BC8F8F",
|
||||
"royalblue" => "4169E1",
|
||||
"saddlebrown" => "8B4513",
|
||||
"salmon" => "FA8072",
|
||||
"sandybrown" => "F4A460",
|
||||
"seagreen" => "2E8B57",
|
||||
"seashell" => "FFF5EE",
|
||||
"sienna" => "A0522D",
|
||||
"silver" => "C0C0C0",
|
||||
"skyblue" => "87CEEB",
|
||||
"slateblue" => "6A5ACD",
|
||||
"slategray" => "708090",
|
||||
"slategrey" => "708090",
|
||||
"snow" => "FFFAFA",
|
||||
"springgreen" => "00FF7F",
|
||||
"steelblue" => "4682B4",
|
||||
"tan" => "D2B48C",
|
||||
"teal" => "008080",
|
||||
"thistle" => "D8BFD8",
|
||||
"tomato" => "FF6347",
|
||||
"turquoise" => "40E0D0",
|
||||
"violet" => "EE82EE",
|
||||
"wheat" => "F5DEB3",
|
||||
"white" => "FFFFFF",
|
||||
"whitesmoke" => "F5F5F5",
|
||||
"yellow" => "FFFF00",
|
||||
"yellowgreen" => "9ACD32",
|
||||
);
|
||||
|
||||
static function parse($color) {
|
||||
if ( is_array($color) ) {
|
||||
// Assume the array has the right format...
|
||||
// FIXME: should/could verify this.
|
||||
return $color;
|
||||
}
|
||||
|
||||
static $cache = array();
|
||||
|
||||
$color = strtolower($color);
|
||||
|
||||
if ( isset($cache[$color]) ) {
|
||||
return $cache[$color];
|
||||
}
|
||||
|
||||
if ( in_array($color, array("transparent", "inherit")) ) {
|
||||
return $cache[$color] = $color;
|
||||
}
|
||||
|
||||
if ( isset(self::$cssColorNames[$color]) ) {
|
||||
return $cache[$color] = self::getArray(self::$cssColorNames[$color]);
|
||||
}
|
||||
|
||||
$length = mb_strlen($color);
|
||||
|
||||
// #rgb format
|
||||
if ( $length == 4 && $color[0] === "#" ) {
|
||||
return $cache[$color] = self::getArray($color[1].$color[1].$color[2].$color[2].$color[3].$color[3]);
|
||||
}
|
||||
|
||||
// #rrggbb format
|
||||
else if ( $length == 7 && $color[0] === "#" ) {
|
||||
return $cache[$color] = self::getArray(mb_substr($color, 1, 6));
|
||||
}
|
||||
|
||||
// rgb( r,g,b ) / rgbaa( r,g,b,α ) format
|
||||
else if ( mb_strpos($color, "rgb") !== false ) {
|
||||
$i = mb_strpos($color, "(");
|
||||
$j = mb_strpos($color, ")");
|
||||
|
||||
// Bad color value
|
||||
if ( $i === false || $j === false ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$triplet = explode(",", mb_substr($color, $i+1, $j-$i-1));
|
||||
|
||||
// alpha transparency
|
||||
// FIXME: not currently using transparency
|
||||
$alpha = 1;
|
||||
if ( count( $triplet ) == 4 ) {
|
||||
$alpha = (float) ( trim( array_pop( $triplet ) ) );
|
||||
// bad value, set to fully opaque
|
||||
if ( $alpha > 1 || $alpha < 0 ) {
|
||||
$alpha = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if ( count($triplet) != 3 ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
foreach (array_keys($triplet) as $c) {
|
||||
$triplet[$c] = trim($triplet[$c]);
|
||||
|
||||
if ( $triplet[$c][mb_strlen($triplet[$c]) - 1] === "%" ) {
|
||||
$triplet[$c] = round($triplet[$c] * 2.55);
|
||||
}
|
||||
}
|
||||
|
||||
return $cache[$color] = self::getArray(vsprintf("%02X%02X%02X", $triplet));
|
||||
|
||||
}
|
||||
|
||||
// cmyk( c,m,y,k ) format
|
||||
// http://www.w3.org/TR/css3-gcpm/#cmyk-colors
|
||||
else if ( mb_strpos($color, "cmyk") !== false ) {
|
||||
$i = mb_strpos($color, "(");
|
||||
$j = mb_strpos($color, ")");
|
||||
|
||||
// Bad color value
|
||||
if ( $i === false || $j === false ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$values = explode(",", mb_substr($color, $i+1, $j-$i-1));
|
||||
|
||||
if ( count($values) != 4 ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
foreach ($values as &$c) {
|
||||
$c = floatval(trim($c));
|
||||
if ($c > 1.0) $c = 1.0;
|
||||
if ($c < 0.0) $c = 0.0;
|
||||
}
|
||||
|
||||
return $cache[$color] = self::getArray($values);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
static function getArray($color) {
|
||||
$c = array(null, null, null, null, "hex" => null);
|
||||
|
||||
if (is_array($color)) {
|
||||
$c = $color;
|
||||
$c["c"] = $c[0];
|
||||
$c["m"] = $c[1];
|
||||
$c["y"] = $c[2];
|
||||
$c["k"] = $c[3];
|
||||
$c["hex"] = "cmyk($c[0],$c[1],$c[2],$c[3])";
|
||||
}
|
||||
else {
|
||||
$c[0] = hexdec(mb_substr($color, 0, 2)) / 0xff;
|
||||
$c[1] = hexdec(mb_substr($color, 2, 2)) / 0xff;
|
||||
$c[2] = hexdec(mb_substr($color, 4, 2)) / 0xff;
|
||||
$c["r"] = $c[0];
|
||||
$c["g"] = $c[1];
|
||||
$c["b"] = $c[2];
|
||||
$c["hex"] = "#$color";
|
||||
}
|
||||
|
||||
return $c;
|
||||
}
|
||||
}
|
||||
1077
application/helpers/dompdf/include/dompdf.cls.php
Executable file
1077
application/helpers/dompdf/include/dompdf.cls.php
Executable file
File diff suppressed because it is too large
Load Diff
26
application/helpers/dompdf/include/dompdf_exception.cls.php
Executable file
26
application/helpers/dompdf/include/dompdf_exception.cls.php
Executable file
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
/**
|
||||
* @package dompdf
|
||||
* @link http://dompdf.github.com/
|
||||
* @author Benj Carson <benjcarson@digitaljunkies.ca>
|
||||
* @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
|
||||
*/
|
||||
|
||||
/**
|
||||
* Standard exception thrown by DOMPDF classes
|
||||
*
|
||||
* @package dompdf
|
||||
*/
|
||||
class DOMPDF_Exception extends Exception {
|
||||
|
||||
/**
|
||||
* Class constructor
|
||||
*
|
||||
* @param string $message Error message
|
||||
* @param int $code Error code
|
||||
*/
|
||||
function __construct($message = null, $code = 0) {
|
||||
parent::__construct($message, $code);
|
||||
}
|
||||
|
||||
}
|
||||
26
application/helpers/dompdf/include/dompdf_image_exception.cls.php
Executable file
26
application/helpers/dompdf/include/dompdf_image_exception.cls.php
Executable file
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
/**
|
||||
* @package dompdf
|
||||
* @link http://dompdf.github.com/
|
||||
* @author Benj Carson <benjcarson@digitaljunkies.ca>
|
||||
* @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
|
||||
*/
|
||||
|
||||
/**
|
||||
* Image exception thrown by DOMPDF
|
||||
*
|
||||
* @package dompdf
|
||||
*/
|
||||
class DOMPDF_Image_Exception extends DOMPDF_Exception {
|
||||
|
||||
/**
|
||||
* Class constructor
|
||||
*
|
||||
* @param string $message Error message
|
||||
* @param int $code Error code
|
||||
*/
|
||||
function __construct($message = null, $code = 0) {
|
||||
parent::__construct($message, $code);
|
||||
}
|
||||
|
||||
}
|
||||
8
application/helpers/dompdf/include/file.skel
Executable file
8
application/helpers/dompdf/include/file.skel
Executable file
@@ -0,0 +1,8 @@
|
||||
<?php
|
||||
/**
|
||||
* @package dompdf
|
||||
* @link http://dompdf.github.com/
|
||||
* @author Benj Carson <benjcarson@digitaljunkies.ca>
|
||||
* @author ...
|
||||
* @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
|
||||
*/
|
||||
88
application/helpers/dompdf/include/fixed_positioner.cls.php
Executable file
88
application/helpers/dompdf/include/fixed_positioner.cls.php
Executable file
@@ -0,0 +1,88 @@
|
||||
<?php
|
||||
/**
|
||||
* @package dompdf
|
||||
* @link http://dompdf.github.com/
|
||||
* @author Benj Carson <benjcarson@digitaljunkies.ca>
|
||||
* @author Fabien Ménager <fabien.menager@gmail.com>
|
||||
* @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
|
||||
*/
|
||||
|
||||
/**
|
||||
* Positions fixely positioned frames
|
||||
*/
|
||||
class Fixed_Positioner extends Positioner {
|
||||
|
||||
function __construct(Frame_Decorator $frame) { parent::__construct($frame); }
|
||||
|
||||
function position() {
|
||||
|
||||
$frame = $this->_frame;
|
||||
$style = $frame->get_original_style();
|
||||
$root = $frame->get_root();
|
||||
$initialcb = $root->get_containing_block();
|
||||
$initialcb_style = $root->get_style();
|
||||
|
||||
$p = $frame->find_block_parent();
|
||||
if ( $p ) {
|
||||
$p->add_line();
|
||||
}
|
||||
|
||||
// Compute the margins of the @page style
|
||||
$margin_top = $initialcb_style->length_in_pt($initialcb_style->margin_top, $initialcb["h"]);
|
||||
$margin_right = $initialcb_style->length_in_pt($initialcb_style->margin_right, $initialcb["w"]);
|
||||
$margin_bottom = $initialcb_style->length_in_pt($initialcb_style->margin_bottom, $initialcb["h"]);
|
||||
$margin_left = $initialcb_style->length_in_pt($initialcb_style->margin_left, $initialcb["w"]);
|
||||
|
||||
// The needed computed style of the element
|
||||
$height = $style->length_in_pt($style->height, $initialcb["h"]);
|
||||
$width = $style->length_in_pt($style->width, $initialcb["w"]);
|
||||
|
||||
$top = $style->length_in_pt($style->top, $initialcb["h"]);
|
||||
$right = $style->length_in_pt($style->right, $initialcb["w"]);
|
||||
$bottom = $style->length_in_pt($style->bottom, $initialcb["h"]);
|
||||
$left = $style->length_in_pt($style->left, $initialcb["w"]);
|
||||
|
||||
$y = $margin_top;
|
||||
if ( isset($top) ) {
|
||||
$y = $top + $margin_top;
|
||||
if ( $top === "auto" ) {
|
||||
$y = $margin_top;
|
||||
if ( isset($bottom) && $bottom !== "auto" ) {
|
||||
$y = $initialcb["h"] - $bottom - $margin_bottom;
|
||||
$margin_height = $this->_frame->get_margin_height();
|
||||
if ( $margin_height !== "auto" ) {
|
||||
$y -= $margin_height;
|
||||
}
|
||||
else {
|
||||
$y -= $height;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$x = $margin_left;
|
||||
if ( isset($left) ) {
|
||||
$x = $left + $margin_left;
|
||||
if ( $left === "auto" ) {
|
||||
$x = $margin_left;
|
||||
if ( isset($right) && $right !== "auto" ) {
|
||||
$x = $initialcb["w"] - $right - $margin_right;
|
||||
$margin_width = $this->_frame->get_margin_width();
|
||||
if ( $margin_width !== "auto" ) {
|
||||
$x -= $margin_width;
|
||||
}
|
||||
else {
|
||||
$x -= $width;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$frame->set_position($x, $y);
|
||||
|
||||
$children = $frame->get_children();
|
||||
foreach($children as $child) {
|
||||
$child->set_position($x, $y);
|
||||
}
|
||||
}
|
||||
}
|
||||
363
application/helpers/dompdf/include/font_metrics.cls.php
Executable file
363
application/helpers/dompdf/include/font_metrics.cls.php
Executable file
@@ -0,0 +1,363 @@
|
||||
<?php
|
||||
/**
|
||||
* @package dompdf
|
||||
* @link http://dompdf.github.com/
|
||||
* @author Benj Carson <benjcarson@digitaljunkies.ca>
|
||||
* @author Helmut Tischer <htischer@weihenstephan.org>
|
||||
* @author Fabien Ménager <fabien.menager@gmail.com>
|
||||
* @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
|
||||
*/
|
||||
|
||||
require_once DOMPDF_LIB_DIR . "/class.pdf.php";
|
||||
|
||||
/**
|
||||
* Name of the font cache file
|
||||
*
|
||||
* This file must be writable by the webserver process only to update it
|
||||
* with save_font_families() after adding the .afm file references of a new font family
|
||||
* with Font_Metrics::save_font_families().
|
||||
* This is typically done only from command line with load_font.php on converting
|
||||
* ttf fonts to ufm with php-font-lib.
|
||||
*
|
||||
* Declared here because PHP5 prevents constants from being declared with expressions
|
||||
*/
|
||||
define('__DOMPDF_FONT_CACHE_FILE', DOMPDF_FONT_DIR . "dompdf_font_family_cache.php");
|
||||
|
||||
/**
|
||||
* The font metrics class
|
||||
*
|
||||
* This class provides information about fonts and text. It can resolve
|
||||
* font names into actual installed font files, as well as determine the
|
||||
* size of text in a particular font and size.
|
||||
*
|
||||
* @static
|
||||
* @package dompdf
|
||||
*/
|
||||
class Font_Metrics {
|
||||
|
||||
/**
|
||||
* @see __DOMPDF_FONT_CACHE_FILE
|
||||
*/
|
||||
const CACHE_FILE = __DOMPDF_FONT_CACHE_FILE;
|
||||
|
||||
/**
|
||||
* Underlying {@link Canvas} object to perform text size calculations
|
||||
*
|
||||
* @var Canvas
|
||||
*/
|
||||
static protected $_pdf = null;
|
||||
|
||||
/**
|
||||
* Array of font family names to font files
|
||||
*
|
||||
* Usually cached by the {@link load_font.php} script
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
static protected $_font_lookup = array();
|
||||
|
||||
|
||||
/**
|
||||
* Class initialization
|
||||
*
|
||||
*/
|
||||
static function init(Canvas $canvas = null) {
|
||||
if (!self::$_pdf) {
|
||||
if (!$canvas) {
|
||||
$canvas = Canvas_Factory::get_instance(new DOMPDF());
|
||||
}
|
||||
|
||||
self::$_pdf = $canvas;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates text size, in points
|
||||
*
|
||||
* @param string $text the text to be sized
|
||||
* @param string $font the desired font
|
||||
* @param float $size the desired font size
|
||||
* @param float $word_spacing
|
||||
* @param float $char_spacing
|
||||
*
|
||||
* @internal param float $spacing word spacing, if any
|
||||
* @return float
|
||||
*/
|
||||
static function get_text_width($text, $font, $size, $word_spacing = 0.0, $char_spacing = 0.0) {
|
||||
//return self::$_pdf->get_text_width($text, $font, $size, $word_spacing, $char_spacing);
|
||||
|
||||
// @todo Make sure this cache is efficient before enabling it
|
||||
static $cache = array();
|
||||
|
||||
if ( $text === "" ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Don't cache long strings
|
||||
$use_cache = !isset($text[50]); // Faster than strlen
|
||||
|
||||
$key = "$font/$size/$word_spacing/$char_spacing";
|
||||
|
||||
if ( $use_cache && isset($cache[$key][$text]) ) {
|
||||
return $cache[$key]["$text"];
|
||||
}
|
||||
|
||||
$width = self::$_pdf->get_text_width($text, $font, $size, $word_spacing, $char_spacing);
|
||||
|
||||
if ( $use_cache ) {
|
||||
$cache[$key][$text] = $width;
|
||||
}
|
||||
|
||||
return $width;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates font height
|
||||
*
|
||||
* @param string $font
|
||||
* @param float $size
|
||||
* @return float
|
||||
*/
|
||||
static function get_font_height($font, $size) {
|
||||
return self::$_pdf->get_font_height($font, $size);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves a font family & subtype into an actual font file
|
||||
* Subtype can be one of 'normal', 'bold', 'italic' or 'bold_italic'. If
|
||||
* the particular font family has no suitable font file, the default font
|
||||
* ({@link DOMPDF_DEFAULT_FONT}) is used. The font file returned
|
||||
* is the absolute pathname to the font file on the system.
|
||||
*
|
||||
* @param string $family_raw
|
||||
* @param string $subtype_raw
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
static function get_font($family_raw, $subtype_raw = "normal") {
|
||||
static $cache = array();
|
||||
|
||||
if ( isset($cache[$family_raw][$subtype_raw]) ) {
|
||||
return $cache[$family_raw][$subtype_raw];
|
||||
}
|
||||
|
||||
/* Allow calling for various fonts in search path. Therefore not immediately
|
||||
* return replacement on non match.
|
||||
* Only when called with NULL try replacement.
|
||||
* When this is also missing there is really trouble.
|
||||
* If only the subtype fails, nevertheless return failure.
|
||||
* Only on checking the fallback font, check various subtypes on same font.
|
||||
*/
|
||||
|
||||
$subtype = strtolower($subtype_raw);
|
||||
|
||||
if ( $family_raw ) {
|
||||
$family = str_replace( array("'", '"'), "", strtolower($family_raw));
|
||||
|
||||
if ( isset(self::$_font_lookup[$family][$subtype]) ) {
|
||||
return $cache[$family_raw][$subtype_raw] = self::$_font_lookup[$family][$subtype];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
$family = "serif";
|
||||
|
||||
if ( isset(self::$_font_lookup[$family][$subtype]) ) {
|
||||
return $cache[$family_raw][$subtype_raw] = self::$_font_lookup[$family][$subtype];
|
||||
}
|
||||
|
||||
if ( !isset(self::$_font_lookup[$family]) ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$family = self::$_font_lookup[$family];
|
||||
|
||||
foreach ( $family as $sub => $font ) {
|
||||
if (strpos($subtype, $sub) !== false) {
|
||||
return $cache[$family_raw][$subtype_raw] = $font;
|
||||
}
|
||||
}
|
||||
|
||||
if ($subtype !== "normal") {
|
||||
foreach ( $family as $sub => $font ) {
|
||||
if ($sub !== "normal") {
|
||||
return $cache[$family_raw][$subtype_raw] = $font;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$subtype = "normal";
|
||||
|
||||
if ( isset($family[$subtype]) ) {
|
||||
return $cache[$family_raw][$subtype_raw] = $family[$subtype];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
static function get_family($family) {
|
||||
$family = str_replace( array("'", '"'), "", mb_strtolower($family));
|
||||
|
||||
if ( isset(self::$_font_lookup[$family]) ) {
|
||||
return self::$_font_lookup[$family];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the stored font family cache
|
||||
*
|
||||
* The name and location of the cache file are determined by {@link
|
||||
* Font_Metrics::CACHE_FILE}. This file should be writable by the
|
||||
* webserver process.
|
||||
*
|
||||
* @see Font_Metrics::load_font_families()
|
||||
*/
|
||||
static function save_font_families() {
|
||||
// replace the path to the DOMPDF font directories with the corresponding constants (allows for more portability)
|
||||
$cache_data = var_export(self::$_font_lookup, true);
|
||||
$cache_data = str_replace('\''.DOMPDF_FONT_DIR , 'DOMPDF_FONT_DIR . \'' , $cache_data);
|
||||
$cache_data = str_replace('\''.DOMPDF_DIR , 'DOMPDF_DIR . \'' , $cache_data);
|
||||
$cache_data = "<"."?php return $cache_data ?".">";
|
||||
file_put_contents(self::CACHE_FILE, $cache_data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the stored font family cache
|
||||
*
|
||||
* @see save_font_families()
|
||||
*/
|
||||
static function load_font_families() {
|
||||
$dist_fonts = require_once DOMPDF_DIR . "/lib/fonts/dompdf_font_family_cache.dist.php";
|
||||
|
||||
// FIXME: temporary step for font cache created before the font cache fix
|
||||
if ( is_readable( DOMPDF_FONT_DIR . "dompdf_font_family_cache" ) ) {
|
||||
$old_fonts = require_once DOMPDF_FONT_DIR . "dompdf_font_family_cache";
|
||||
// If the font family cache is still in the old format
|
||||
if ( $old_fonts === 1 ) {
|
||||
$cache_data = file_get_contents(DOMPDF_FONT_DIR . "dompdf_font_family_cache");
|
||||
file_put_contents(DOMPDF_FONT_DIR . "dompdf_font_family_cache", "<"."?php return $cache_data ?".">");
|
||||
$old_fonts = require_once DOMPDF_FONT_DIR . "dompdf_font_family_cache";
|
||||
}
|
||||
$dist_fonts += $old_fonts;
|
||||
}
|
||||
|
||||
if ( !is_readable(self::CACHE_FILE) ) {
|
||||
self::$_font_lookup = $dist_fonts;
|
||||
return;
|
||||
}
|
||||
|
||||
self::$_font_lookup = require_once self::CACHE_FILE;
|
||||
|
||||
// If the font family cache is still in the old format
|
||||
if ( self::$_font_lookup === 1 ) {
|
||||
$cache_data = file_get_contents(self::CACHE_FILE);
|
||||
file_put_contents(self::CACHE_FILE, "<"."?php return $cache_data ?".">");
|
||||
self::$_font_lookup = require_once self::CACHE_FILE;
|
||||
}
|
||||
|
||||
// Merge provided fonts
|
||||
self::$_font_lookup += $dist_fonts;
|
||||
}
|
||||
|
||||
static function get_type($type) {
|
||||
if (preg_match("/bold/i", $type)) {
|
||||
if (preg_match("/italic|oblique/i", $type)) {
|
||||
$type = "bold_italic";
|
||||
}
|
||||
else {
|
||||
$type = "bold";
|
||||
}
|
||||
}
|
||||
elseif (preg_match("/italic|oblique/i", $type)) {
|
||||
$type = "italic";
|
||||
}
|
||||
else {
|
||||
$type = "normal";
|
||||
}
|
||||
|
||||
return $type;
|
||||
}
|
||||
|
||||
static function install_fonts($files) {
|
||||
$names = array();
|
||||
|
||||
foreach($files as $file) {
|
||||
$font = Font::load($file);
|
||||
$records = $font->getData("name", "records");
|
||||
$type = self::get_type($records[2]);
|
||||
$names[mb_strtolower($records[1])][$type] = $file;
|
||||
}
|
||||
|
||||
return $names;
|
||||
}
|
||||
|
||||
static function get_system_fonts() {
|
||||
$files = glob("/usr/share/fonts/truetype/*.ttf") +
|
||||
glob("/usr/share/fonts/truetype/*/*.ttf") +
|
||||
glob("/usr/share/fonts/truetype/*/*/*.ttf") +
|
||||
glob("C:\\Windows\\fonts\\*.ttf") +
|
||||
glob("C:\\WinNT\\fonts\\*.ttf") +
|
||||
glob("/mnt/c_drive/WINDOWS/Fonts/");
|
||||
|
||||
return self::install_fonts($files);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current font lookup table
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
static function get_font_families() {
|
||||
return self::$_font_lookup;
|
||||
}
|
||||
|
||||
static function set_font_family($fontname, $entry) {
|
||||
self::$_font_lookup[mb_strtolower($fontname)] = $entry;
|
||||
}
|
||||
|
||||
static function register_font($style, $remote_file) {
|
||||
$fontname = mb_strtolower($style["family"]);
|
||||
$families = Font_Metrics::get_font_families();
|
||||
|
||||
$entry = array();
|
||||
if ( isset($families[$fontname]) ) {
|
||||
$entry = $families[$fontname];
|
||||
}
|
||||
|
||||
$local_file = DOMPDF_FONT_DIR . md5($remote_file);
|
||||
$cache_entry = $local_file;
|
||||
$local_file .= ".ttf";
|
||||
|
||||
$style_string = Font_Metrics::get_type("{$style['weight']} {$style['style']}");
|
||||
|
||||
if ( !isset($entry[$style_string]) ) {
|
||||
$entry[$style_string] = $cache_entry;
|
||||
|
||||
Font_Metrics::set_font_family($fontname, $entry);
|
||||
|
||||
// Download the remote file
|
||||
if ( !is_file($local_file) ) {
|
||||
file_put_contents($local_file, file_get_contents($remote_file));
|
||||
}
|
||||
|
||||
$font = Font::load($local_file);
|
||||
|
||||
if (!$font) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$font->parse();
|
||||
$font->saveAdobeFontMetrics("$cache_entry.ufm");
|
||||
|
||||
// Save the changes
|
||||
Font_Metrics::save_font_families();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
Font_Metrics::load_font_families();
|
||||
1191
application/helpers/dompdf/include/frame.cls.php
Executable file
1191
application/helpers/dompdf/include/frame.cls.php
Executable file
File diff suppressed because it is too large
Load Diff
717
application/helpers/dompdf/include/frame_decorator.cls.php
Executable file
717
application/helpers/dompdf/include/frame_decorator.cls.php
Executable file
@@ -0,0 +1,717 @@
|
||||
<?php
|
||||
/**
|
||||
* @package dompdf
|
||||
* @link http://dompdf.github.com/
|
||||
* @author Benj Carson <benjcarson@digitaljunkies.ca>
|
||||
* @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
|
||||
*/
|
||||
|
||||
/**
|
||||
* Base Frame_Decorator class
|
||||
*
|
||||
* @access private
|
||||
* @package dompdf
|
||||
*/
|
||||
abstract class Frame_Decorator extends Frame {
|
||||
const DEFAULT_COUNTER = "-dompdf-default-counter";
|
||||
|
||||
public $_counters = array(); // array([id] => counter_value) (for generated content)
|
||||
|
||||
/**
|
||||
* The root node of the DOM tree
|
||||
*
|
||||
* @var Frame
|
||||
*/
|
||||
protected $_root;
|
||||
|
||||
/**
|
||||
* The decorated frame
|
||||
*
|
||||
* @var Frame
|
||||
*/
|
||||
protected $_frame;
|
||||
|
||||
/**
|
||||
* Positioner object used to position this frame (Strategy pattern)
|
||||
*
|
||||
* @var Positioner
|
||||
*/
|
||||
protected $_positioner;
|
||||
|
||||
/**
|
||||
* Reflower object used to calculate frame dimensions (Strategy pattern)
|
||||
*
|
||||
* @var Frame_Reflower
|
||||
*/
|
||||
protected $_reflower;
|
||||
|
||||
/**
|
||||
* Reference to the current dompdf instance
|
||||
*
|
||||
* @var DOMPDF
|
||||
*/
|
||||
protected $_dompdf;
|
||||
|
||||
/**
|
||||
* First block parent
|
||||
*
|
||||
* @var Block_Frame_Decorator
|
||||
*/
|
||||
private $_block_parent;
|
||||
|
||||
/**
|
||||
* First positionned parent (position: relative | absolute | fixed)
|
||||
*
|
||||
* @var Frame_Decorator
|
||||
*/
|
||||
private $_positionned_parent;
|
||||
|
||||
/**
|
||||
* Class constructor
|
||||
*
|
||||
* @param Frame $frame The decoration target
|
||||
* @param DOMPDF $dompdf The DOMPDF object
|
||||
*/
|
||||
function __construct(Frame $frame, DOMPDF $dompdf) {
|
||||
$this->_frame = $frame;
|
||||
$this->_root = null;
|
||||
$this->_dompdf = $dompdf;
|
||||
$frame->set_decorator($this);
|
||||
}
|
||||
|
||||
/**
|
||||
* "Destructor": foribly free all references held by this object
|
||||
*
|
||||
* @param bool $recursive if true, call dispose on all children
|
||||
*/
|
||||
function dispose($recursive = false) {
|
||||
if ( $recursive ) {
|
||||
while ( $child = $this->get_first_child() ) {
|
||||
$child->dispose(true);
|
||||
}
|
||||
}
|
||||
|
||||
$this->_root = null;
|
||||
unset($this->_root);
|
||||
|
||||
$this->_frame->dispose(true);
|
||||
$this->_frame = null;
|
||||
unset($this->_frame);
|
||||
|
||||
$this->_positioner = null;
|
||||
unset($this->_positioner);
|
||||
|
||||
$this->_reflower = null;
|
||||
unset($this->_reflower);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a copy of this frame with $node as its node
|
||||
*
|
||||
* @param DOMNode $node
|
||||
*
|
||||
* @return Frame
|
||||
*/
|
||||
function copy(DOMNode $node) {
|
||||
$frame = new Frame($node);
|
||||
$frame->set_style(clone $this->_frame->get_original_style());
|
||||
|
||||
return Frame_Factory::decorate_frame($frame, $this->_dompdf, $this->_root);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a deep copy: copy this node and all children
|
||||
*
|
||||
* @return Frame
|
||||
*/
|
||||
function deep_copy() {
|
||||
$frame = new Frame($this->get_node()->cloneNode());
|
||||
$frame->set_style(clone $this->_frame->get_original_style());
|
||||
|
||||
$deco = Frame_Factory::decorate_frame($frame, $this->_dompdf, $this->_root);
|
||||
|
||||
foreach ($this->get_children() as $child) {
|
||||
$deco->append_child($child->deep_copy());
|
||||
}
|
||||
|
||||
return $deco;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delegate calls to decorated frame object
|
||||
*/
|
||||
function reset() {
|
||||
$this->_frame->reset();
|
||||
|
||||
$this->_counters = array();
|
||||
|
||||
// Reset all children
|
||||
foreach ($this->get_children() as $child) {
|
||||
$child->reset();
|
||||
}
|
||||
}
|
||||
|
||||
// Getters -----------
|
||||
function get_id() {
|
||||
return $this->_frame->get_id();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Frame
|
||||
*/
|
||||
function get_frame() {
|
||||
return $this->_frame;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return DOMElement|DOMText
|
||||
*/
|
||||
function get_node() {
|
||||
return $this->_frame->get_node();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Style
|
||||
*/
|
||||
function get_style() {
|
||||
return $this->_frame->get_style();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Style
|
||||
*/
|
||||
function get_original_style() {
|
||||
return $this->_frame->get_original_style();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param integer $i
|
||||
*
|
||||
* @return array|float
|
||||
*/
|
||||
function get_containing_block($i = null) {
|
||||
return $this->_frame->get_containing_block($i);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param integer $i
|
||||
*
|
||||
* @return array|float
|
||||
*/
|
||||
function get_position($i = null) {
|
||||
return $this->_frame->get_position($i);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return DOMPDF
|
||||
*/
|
||||
function get_dompdf() {
|
||||
return $this->_dompdf;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return float
|
||||
*/
|
||||
function get_margin_height() {
|
||||
return $this->_frame->get_margin_height();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return float
|
||||
*/
|
||||
function get_margin_width() {
|
||||
return $this->_frame->get_margin_width();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
function get_padding_box() {
|
||||
return $this->_frame->get_padding_box();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
function get_border_box() {
|
||||
return $this->_frame->get_border_box();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param integer $id
|
||||
*/
|
||||
function set_id($id) {
|
||||
$this->_frame->set_id($id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Style $style
|
||||
*/
|
||||
function set_style(Style $style) {
|
||||
$this->_frame->set_style($style);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param float $x
|
||||
* @param float $y
|
||||
* @param float $w
|
||||
* @param float $h
|
||||
*/
|
||||
function set_containing_block($x = null, $y = null, $w = null, $h = null) {
|
||||
$this->_frame->set_containing_block($x, $y, $w, $h);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param float $x
|
||||
* @param float $y
|
||||
*/
|
||||
function set_position($x = null, $y = null) {
|
||||
$this->_frame->set_position($x, $y);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
function __toString() {
|
||||
return $this->_frame->__toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Frame $child
|
||||
* @param bool $update_node
|
||||
*/
|
||||
function prepend_child(Frame $child, $update_node = true) {
|
||||
while ( $child instanceof Frame_Decorator ) {
|
||||
$child = $child->_frame;
|
||||
}
|
||||
|
||||
$this->_frame->prepend_child($child, $update_node);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Frame $child
|
||||
* @param bool $update_node
|
||||
*/
|
||||
function append_child(Frame $child, $update_node = true) {
|
||||
while ( $child instanceof Frame_Decorator ) {
|
||||
$child = $child->_frame;
|
||||
}
|
||||
|
||||
$this->_frame->append_child($child, $update_node);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Frame $new_child
|
||||
* @param Frame $ref
|
||||
* @param bool $update_node
|
||||
*/
|
||||
function insert_child_before(Frame $new_child, Frame $ref, $update_node = true) {
|
||||
while ( $new_child instanceof Frame_Decorator ) {
|
||||
$new_child = $new_child->_frame;
|
||||
}
|
||||
|
||||
if ( $ref instanceof Frame_Decorator ) {
|
||||
$ref = $ref->_frame;
|
||||
}
|
||||
|
||||
$this->_frame->insert_child_before($new_child, $ref, $update_node);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Frame $new_child
|
||||
* @param Frame $ref
|
||||
* @param bool $update_node
|
||||
*/
|
||||
function insert_child_after(Frame $new_child, Frame $ref, $update_node = true) {
|
||||
while ( $new_child instanceof Frame_Decorator ) {
|
||||
$new_child = $new_child->_frame;
|
||||
}
|
||||
|
||||
while ( $ref instanceof Frame_Decorator ) {
|
||||
$ref = $ref->_frame;
|
||||
}
|
||||
|
||||
$this->_frame->insert_child_after($new_child, $ref, $update_node);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Frame $child
|
||||
* @param bool $update_node
|
||||
*
|
||||
* @return Frame
|
||||
*/
|
||||
function remove_child(Frame $child, $update_node = true) {
|
||||
while ( $child instanceof Frame_Decorator ) {
|
||||
$child = $child->_frame;
|
||||
}
|
||||
|
||||
return $this->_frame->remove_child($child, $update_node);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Frame_Decorator
|
||||
*/
|
||||
function get_parent() {
|
||||
$p = $this->_frame->get_parent();
|
||||
if ( $p && $deco = $p->get_decorator() ) {
|
||||
while ( $tmp = $deco->get_decorator() ) {
|
||||
$deco = $tmp;
|
||||
}
|
||||
|
||||
return $deco;
|
||||
}
|
||||
else if ( $p ) {
|
||||
return $p;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Frame_Decorator
|
||||
*/
|
||||
function get_first_child() {
|
||||
$c = $this->_frame->get_first_child();
|
||||
if ( $c && $deco = $c->get_decorator() ) {
|
||||
while ( $tmp = $deco->get_decorator() ) {
|
||||
$deco = $tmp;
|
||||
}
|
||||
|
||||
return $deco;
|
||||
}
|
||||
else if ( $c ) {
|
||||
return $c;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Frame_Decorator
|
||||
*/
|
||||
function get_last_child() {
|
||||
$c = $this->_frame->get_last_child();
|
||||
if ( $c && $deco = $c->get_decorator() ) {
|
||||
while ( $tmp = $deco->get_decorator() ) {
|
||||
$deco = $tmp;
|
||||
}
|
||||
|
||||
return $deco;
|
||||
}
|
||||
else if ( $c ) {
|
||||
return $c;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Frame_Decorator
|
||||
*/
|
||||
function get_prev_sibling() {
|
||||
$s = $this->_frame->get_prev_sibling();
|
||||
if ( $s && $deco = $s->get_decorator() ) {
|
||||
while ( $tmp = $deco->get_decorator() ) {
|
||||
$deco = $tmp;
|
||||
}
|
||||
return $deco;
|
||||
}
|
||||
else if ( $s ) {
|
||||
return $s;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Frame_Decorator
|
||||
*/
|
||||
function get_next_sibling() {
|
||||
$s = $this->_frame->get_next_sibling();
|
||||
if ( $s && $deco = $s->get_decorator() ) {
|
||||
while ( $tmp = $deco->get_decorator() ) {
|
||||
$deco = $tmp;
|
||||
}
|
||||
|
||||
return $deco;
|
||||
}
|
||||
else if ( $s ) {
|
||||
return $s;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return FrameTreeList
|
||||
*/
|
||||
function get_subtree() {
|
||||
return new FrameTreeList($this);
|
||||
}
|
||||
|
||||
function set_positioner(Positioner $posn) {
|
||||
$this->_positioner = $posn;
|
||||
if ( $this->_frame instanceof Frame_Decorator ) {
|
||||
$this->_frame->set_positioner($posn);
|
||||
}
|
||||
}
|
||||
|
||||
function set_reflower(Frame_Reflower $reflower) {
|
||||
$this->_reflower = $reflower;
|
||||
if ( $this->_frame instanceof Frame_Decorator ) {
|
||||
$this->_frame->set_reflower( $reflower );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Frame_Reflower
|
||||
*/
|
||||
function get_reflower() {
|
||||
return $this->_reflower;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Frame $root
|
||||
*/
|
||||
function set_root(Frame $root) {
|
||||
$this->_root = $root;
|
||||
|
||||
if ( $this->_frame instanceof Frame_Decorator ) {
|
||||
$this->_frame->set_root($root);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Page_Frame_Decorator
|
||||
*/
|
||||
function get_root() {
|
||||
return $this->_root;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Block_Frame_Decorator
|
||||
*/
|
||||
function find_block_parent() {
|
||||
// Find our nearest block level parent
|
||||
$p = $this->get_parent();
|
||||
|
||||
while ( $p ) {
|
||||
if ( $p->is_block() ) {
|
||||
break;
|
||||
}
|
||||
|
||||
$p = $p->get_parent();
|
||||
}
|
||||
|
||||
return $this->_block_parent = $p;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Frame_Decorator
|
||||
*/
|
||||
function find_positionned_parent() {
|
||||
// Find our nearest relative positionned parent
|
||||
$p = $this->get_parent();
|
||||
while ( $p ) {
|
||||
if ( $p->is_positionned() ) {
|
||||
break;
|
||||
}
|
||||
|
||||
$p = $p->get_parent();
|
||||
}
|
||||
|
||||
if ( !$p ) {
|
||||
$p = $this->_root->get_first_child(); // <body>
|
||||
}
|
||||
|
||||
return $this->_positionned_parent = $p;
|
||||
}
|
||||
|
||||
/**
|
||||
* split this frame at $child.
|
||||
* The current frame is cloned and $child and all children following
|
||||
* $child are added to the clone. The clone is then passed to the
|
||||
* current frame's parent->split() method.
|
||||
*
|
||||
* @param Frame $child
|
||||
* @param boolean $force_pagebreak
|
||||
*
|
||||
* @throws DOMPDF_Exception
|
||||
* @return void
|
||||
*/
|
||||
function split(Frame $child = null, $force_pagebreak = false) {
|
||||
// decrement any counters that were incremented on the current node, unless that node is the body
|
||||
$style = $this->_frame->get_style();
|
||||
if ( $this->_frame->get_node()->nodeName !== "body" && $style->counter_increment && ($decrement = $style->counter_increment) !== "none" ) {
|
||||
$this->decrement_counters($decrement);
|
||||
}
|
||||
|
||||
if ( is_null( $child ) ) {
|
||||
// check for counter increment on :before content (always a child of the selected element @link Frame_Reflower::_set_content)
|
||||
// this can push the current node to the next page before counter rules have bubbled up (but only if
|
||||
// it's been rendered, thus the position check)
|
||||
if ( !$this->is_text_node() && $this->get_node()->hasAttribute("dompdf_before_frame_id") ) {
|
||||
foreach($this->_frame->get_children() as $child) {
|
||||
if ( $this->get_node()->getAttribute("dompdf_before_frame_id") == $child->get_id() && $child->get_position('x') !== NULL ) {
|
||||
$style = $child->get_style();
|
||||
if ( $style->counter_increment && ($decrement = $style->counter_increment) !== "none" ) {
|
||||
$this->decrement_counters($decrement);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
$this->get_parent()->split($this, $force_pagebreak);
|
||||
return;
|
||||
}
|
||||
|
||||
if ( $child->get_parent() !== $this ) {
|
||||
throw new DOMPDF_Exception("Unable to split: frame is not a child of this one.");
|
||||
}
|
||||
|
||||
$node = $this->_frame->get_node();
|
||||
|
||||
$split = $this->copy( $node->cloneNode() );
|
||||
$split->reset();
|
||||
$split->get_original_style()->text_indent = 0;
|
||||
$split->_splitted = true;
|
||||
|
||||
// The body's properties must be kept
|
||||
if ( $node->nodeName !== "body" ) {
|
||||
// Style reset on the first and second parts
|
||||
$style = $this->_frame->get_style();
|
||||
$style->margin_bottom = 0;
|
||||
$style->padding_bottom = 0;
|
||||
$style->border_bottom = 0;
|
||||
|
||||
// second
|
||||
$orig_style = $split->get_original_style();
|
||||
$orig_style->text_indent = 0;
|
||||
$orig_style->margin_top = 0;
|
||||
$orig_style->padding_top = 0;
|
||||
$orig_style->border_top = 0;
|
||||
}
|
||||
|
||||
$this->get_parent()->insert_child_after($split, $this);
|
||||
|
||||
// Add $frame and all following siblings to the new split node
|
||||
$iter = $child;
|
||||
while ($iter) {
|
||||
$frame = $iter;
|
||||
$iter = $iter->get_next_sibling();
|
||||
$frame->reset();
|
||||
$split->append_child($frame);
|
||||
}
|
||||
|
||||
$this->get_parent()->split($split, $force_pagebreak);
|
||||
|
||||
// If this node resets a counter save the current value to use when rendering on the next page
|
||||
if ( $style->counter_reset && ( $reset = $style->counter_reset ) !== "none" ) {
|
||||
$vars = preg_split( '/\s+/' , trim( $reset ) , 2 );
|
||||
$split->_counters[ '__' . $vars[0] ] = $this->lookup_counter_frame( $vars[0] )->_counters[$vars[0]];
|
||||
}
|
||||
}
|
||||
|
||||
function reset_counter($id = self::DEFAULT_COUNTER, $value = 0) {
|
||||
$this->get_parent()->_counters[$id] = intval($value);
|
||||
}
|
||||
|
||||
function decrement_counters($counters) {
|
||||
foreach($counters as $id => $increment) {
|
||||
$this->increment_counter($id, intval($increment) * -1);
|
||||
}
|
||||
}
|
||||
|
||||
function increment_counters($counters) {
|
||||
foreach($counters as $id => $increment) {
|
||||
$this->increment_counter($id, intval($increment));
|
||||
}
|
||||
}
|
||||
|
||||
function increment_counter($id = self::DEFAULT_COUNTER, $increment = 1) {
|
||||
$counter_frame = $this->lookup_counter_frame($id);
|
||||
|
||||
if ( $counter_frame ) {
|
||||
if ( !isset($counter_frame->_counters[$id]) ) {
|
||||
$counter_frame->_counters[$id] = 0;
|
||||
}
|
||||
|
||||
$counter_frame->_counters[$id] += $increment;
|
||||
}
|
||||
}
|
||||
|
||||
function lookup_counter_frame($id = self::DEFAULT_COUNTER) {
|
||||
$f = $this->get_parent();
|
||||
|
||||
while( $f ) {
|
||||
if( isset($f->_counters[$id]) ) {
|
||||
return $f;
|
||||
}
|
||||
$fp = $f->get_parent();
|
||||
|
||||
if ( !$fp ) {
|
||||
return $f;
|
||||
}
|
||||
|
||||
$f = $fp;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: What version is the best : this one or the one in List_Bullet_Renderer ?
|
||||
function counter_value($id = self::DEFAULT_COUNTER, $type = "decimal") {
|
||||
$type = mb_strtolower($type);
|
||||
|
||||
if ( !isset($this->_counters[$id]) ) {
|
||||
$this->_counters[$id] = 0;
|
||||
}
|
||||
|
||||
$value = $this->_counters[$id];
|
||||
|
||||
switch ($type) {
|
||||
default:
|
||||
case "decimal":
|
||||
return $value;
|
||||
|
||||
case "decimal-leading-zero":
|
||||
return str_pad($value, 2, "0");
|
||||
|
||||
case "lower-roman":
|
||||
return dec2roman($value);
|
||||
|
||||
case "upper-roman":
|
||||
return mb_strtoupper(dec2roman($value));
|
||||
|
||||
case "lower-latin":
|
||||
case "lower-alpha":
|
||||
return chr( ($value % 26) + ord('a') - 1);
|
||||
|
||||
case "upper-latin":
|
||||
case "upper-alpha":
|
||||
return chr( ($value % 26) + ord('A') - 1);
|
||||
|
||||
case "lower-greek":
|
||||
return unichr($value + 944);
|
||||
|
||||
case "upper-greek":
|
||||
return unichr($value + 912);
|
||||
}
|
||||
}
|
||||
|
||||
final function position() {
|
||||
$this->_positioner->position();
|
||||
}
|
||||
|
||||
final function move($offset_x, $offset_y, $ignore_self = false) {
|
||||
$this->_positioner->move($offset_x, $offset_y, $ignore_self);
|
||||
}
|
||||
|
||||
final function reflow(Block_Frame_Decorator $block = null) {
|
||||
// Uncomment this to see the frames before they're laid out, instead of
|
||||
// during rendering.
|
||||
//echo $this->_frame; flush();
|
||||
$this->_reflower->reflow($block);
|
||||
}
|
||||
|
||||
final function get_min_max_width() {
|
||||
return $this->_reflower->get_min_max_width();
|
||||
}
|
||||
}
|
||||
252
application/helpers/dompdf/include/frame_factory.cls.php
Executable file
252
application/helpers/dompdf/include/frame_factory.cls.php
Executable file
@@ -0,0 +1,252 @@
|
||||
<?php
|
||||
/**
|
||||
* @package dompdf
|
||||
* @link http://dompdf.github.com/
|
||||
* @author Benj Carson <benjcarson@digitaljunkies.ca>
|
||||
* @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
|
||||
*/
|
||||
|
||||
/**
|
||||
* Contains frame decorating logic
|
||||
*
|
||||
* This class is responsible for assigning the correct {@link Frame_Decorator},
|
||||
* {@link Positioner}, and {@link Frame_Reflower} objects to {@link Frame}
|
||||
* objects. This is determined primarily by the Frame's display type, but
|
||||
* also by the Frame's node's type (e.g. DomElement vs. #text)
|
||||
*
|
||||
* @access private
|
||||
* @package dompdf
|
||||
*/
|
||||
class Frame_Factory {
|
||||
|
||||
/**
|
||||
* Decorate the root Frame
|
||||
*
|
||||
* @param $root Frame The frame to decorate
|
||||
* @param $dompdf DOMPDF The dompdf instance
|
||||
* @return Page_Frame_Decorator
|
||||
*/
|
||||
static function decorate_root(Frame $root, DOMPDF $dompdf) {
|
||||
$frame = new Page_Frame_Decorator($root, $dompdf);
|
||||
$frame->set_reflower( new Page_Frame_Reflower($frame) );
|
||||
$root->set_decorator($frame);
|
||||
return $frame;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decorate a Frame
|
||||
*
|
||||
* @param Frame $frame The frame to decorate
|
||||
* @param DOMPDF $dompdf The dompdf instance
|
||||
* @param Frame $root The frame to decorate
|
||||
*
|
||||
* @throws DOMPDF_Exception
|
||||
* @return Frame_Decorator
|
||||
* FIXME: this is admittedly a little smelly...
|
||||
*/
|
||||
static function decorate_frame(Frame $frame, DOMPDF $dompdf, Frame $root = null) {
|
||||
if ( is_null($dompdf) ) {
|
||||
throw new DOMPDF_Exception("The DOMPDF argument is required");
|
||||
}
|
||||
|
||||
$style = $frame->get_style();
|
||||
|
||||
// Floating (and more generally out-of-flow) elements are blocks
|
||||
// http://coding.smashingmagazine.com/2007/05/01/css-float-theory-things-you-should-know/
|
||||
if ( !$frame->is_in_flow() && in_array($style->display, Style::$INLINE_TYPES)) {
|
||||
$style->display = "block";
|
||||
}
|
||||
|
||||
$display = $style->display;
|
||||
|
||||
switch ($display) {
|
||||
|
||||
case "block":
|
||||
$positioner = "Block";
|
||||
$decorator = "Block";
|
||||
$reflower = "Block";
|
||||
break;
|
||||
|
||||
case "inline-block":
|
||||
$positioner = "Inline";
|
||||
$decorator = "Block";
|
||||
$reflower = "Block";
|
||||
break;
|
||||
|
||||
case "inline":
|
||||
$positioner = "Inline";
|
||||
if ( $frame->is_text_node() ) {
|
||||
$decorator = "Text";
|
||||
$reflower = "Text";
|
||||
}
|
||||
else {
|
||||
$enable_css_float = $dompdf->get_option("enable_css_float");
|
||||
if ( $enable_css_float && $style->float !== "none" ) {
|
||||
$decorator = "Block";
|
||||
$reflower = "Block";
|
||||
}
|
||||
else {
|
||||
$decorator = "Inline";
|
||||
$reflower = "Inline";
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case "table":
|
||||
$positioner = "Block";
|
||||
$decorator = "Table";
|
||||
$reflower = "Table";
|
||||
break;
|
||||
|
||||
case "inline-table":
|
||||
$positioner = "Inline";
|
||||
$decorator = "Table";
|
||||
$reflower = "Table";
|
||||
break;
|
||||
|
||||
case "table-row-group":
|
||||
case "table-header-group":
|
||||
case "table-footer-group":
|
||||
$positioner = "Null";
|
||||
$decorator = "Table_Row_Group";
|
||||
$reflower = "Table_Row_Group";
|
||||
break;
|
||||
|
||||
case "table-row":
|
||||
$positioner = "Null";
|
||||
$decorator = "Table_Row";
|
||||
$reflower = "Table_Row";
|
||||
break;
|
||||
|
||||
case "table-cell":
|
||||
$positioner = "Table_Cell";
|
||||
$decorator = "Table_Cell";
|
||||
$reflower = "Table_Cell";
|
||||
break;
|
||||
|
||||
case "list-item":
|
||||
$positioner = "Block";
|
||||
$decorator = "Block";
|
||||
$reflower = "Block";
|
||||
break;
|
||||
|
||||
case "-dompdf-list-bullet":
|
||||
if ( $style->list_style_position === "inside" ) {
|
||||
$positioner = "Inline";
|
||||
}
|
||||
else {
|
||||
$positioner = "List_Bullet";
|
||||
}
|
||||
|
||||
if ( $style->list_style_image !== "none" ) {
|
||||
$decorator = "List_Bullet_Image";
|
||||
}
|
||||
else {
|
||||
$decorator = "List_Bullet";
|
||||
}
|
||||
|
||||
$reflower = "List_Bullet";
|
||||
break;
|
||||
|
||||
case "-dompdf-image":
|
||||
$positioner = "Inline";
|
||||
$decorator = "Image";
|
||||
$reflower = "Image";
|
||||
break;
|
||||
|
||||
case "-dompdf-br":
|
||||
$positioner = "Inline";
|
||||
$decorator = "Inline";
|
||||
$reflower = "Inline";
|
||||
break;
|
||||
|
||||
default:
|
||||
// FIXME: should throw some sort of warning or something?
|
||||
case "none":
|
||||
if ( $style->_dompdf_keep !== "yes" ) {
|
||||
// Remove the node and the frame
|
||||
$frame->get_parent()->remove_child($frame);
|
||||
return;
|
||||
}
|
||||
|
||||
$positioner = "Null";
|
||||
$decorator = "Null";
|
||||
$reflower = "Null";
|
||||
break;
|
||||
}
|
||||
|
||||
// Handle CSS position
|
||||
$position = $style->position;
|
||||
|
||||
if ( $position === "absolute" ) {
|
||||
$positioner = "Absolute";
|
||||
}
|
||||
else if ( $position === "fixed" ) {
|
||||
$positioner = "Fixed";
|
||||
}
|
||||
|
||||
$node = $frame->get_node();
|
||||
|
||||
// Handle nodeName
|
||||
if ( $node->nodeName === "img" ) {
|
||||
$style->display = "-dompdf-image";
|
||||
$decorator = "Image";
|
||||
$reflower = "Image";
|
||||
}
|
||||
|
||||
$positioner .= "_Positioner";
|
||||
$decorator .= "_Frame_Decorator";
|
||||
$reflower .= "_Frame_Reflower";
|
||||
|
||||
$deco = new $decorator($frame, $dompdf);
|
||||
|
||||
$deco->set_positioner( new $positioner($deco) );
|
||||
$deco->set_reflower( new $reflower($deco) );
|
||||
|
||||
if ( $root ) {
|
||||
$deco->set_root($root);
|
||||
}
|
||||
|
||||
if ( $display === "list-item" ) {
|
||||
// Insert a list-bullet frame
|
||||
$xml = $dompdf->get_dom();
|
||||
$bullet_node = $xml->createElement("bullet"); // arbitrary choice
|
||||
$b_f = new Frame($bullet_node);
|
||||
|
||||
$node = $frame->get_node();
|
||||
$parent_node = $node->parentNode;
|
||||
|
||||
if ( $parent_node ) {
|
||||
if ( !$parent_node->hasAttribute("dompdf-children-count") ) {
|
||||
$xpath = new DOMXPath($xml);
|
||||
$count = $xpath->query("li", $parent_node)->length;
|
||||
$parent_node->setAttribute("dompdf-children-count", $count);
|
||||
}
|
||||
|
||||
if ( is_numeric($node->getAttribute("value")) ) {
|
||||
$index = intval($node->getAttribute("value"));
|
||||
}
|
||||
else {
|
||||
if ( !$parent_node->hasAttribute("dompdf-counter") ) {
|
||||
$index = ($parent_node->hasAttribute("start") ? $parent_node->getAttribute("start") : 1);
|
||||
}
|
||||
else {
|
||||
$index = $parent_node->getAttribute("dompdf-counter")+1;
|
||||
}
|
||||
}
|
||||
|
||||
$parent_node->setAttribute("dompdf-counter", $index);
|
||||
$bullet_node->setAttribute("dompdf-counter", $index);
|
||||
}
|
||||
|
||||
$new_style = $dompdf->get_css()->create_style();
|
||||
$new_style->display = "-dompdf-list-bullet";
|
||||
$new_style->inherit($style);
|
||||
$b_f->set_style($new_style);
|
||||
|
||||
$deco->prepend_child( Frame_Factory::decorate_frame($b_f, $dompdf, $root) );
|
||||
}
|
||||
|
||||
return $deco;
|
||||
}
|
||||
}
|
||||
458
application/helpers/dompdf/include/frame_reflower.cls.php
Executable file
458
application/helpers/dompdf/include/frame_reflower.cls.php
Executable file
@@ -0,0 +1,458 @@
|
||||
<?php
|
||||
/**
|
||||
* @package dompdf
|
||||
* @link http://dompdf.github.com/
|
||||
* @author Benj Carson <benjcarson@digitaljunkies.ca>
|
||||
* @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
|
||||
*/
|
||||
|
||||
/**
|
||||
* Base reflower class
|
||||
*
|
||||
* Reflower objects are responsible for determining the width and height of
|
||||
* individual frames. They also create line and page breaks as necessary.
|
||||
*
|
||||
* @access private
|
||||
* @package dompdf
|
||||
*/
|
||||
abstract class Frame_Reflower {
|
||||
|
||||
/**
|
||||
* Frame for this reflower
|
||||
*
|
||||
* @var Frame
|
||||
*/
|
||||
protected $_frame;
|
||||
|
||||
/**
|
||||
* Cached min/max size
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $_min_max_cache;
|
||||
|
||||
function __construct(Frame $frame) {
|
||||
$this->_frame = $frame;
|
||||
$this->_min_max_cache = null;
|
||||
}
|
||||
|
||||
function dispose() {
|
||||
clear_object($this);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return DOMPDF
|
||||
*/
|
||||
function get_dompdf() {
|
||||
return $this->_frame->get_dompdf();
|
||||
}
|
||||
|
||||
/**
|
||||
* Collapse frames margins
|
||||
* http://www.w3.org/TR/CSS2/box.html#collapsing-margins
|
||||
*/
|
||||
protected function _collapse_margins() {
|
||||
$frame = $this->_frame;
|
||||
$cb = $frame->get_containing_block();
|
||||
$style = $frame->get_style();
|
||||
|
||||
if ( !$frame->is_in_flow() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$t = $style->length_in_pt($style->margin_top, $cb["h"]);
|
||||
$b = $style->length_in_pt($style->margin_bottom, $cb["h"]);
|
||||
|
||||
// Handle 'auto' values
|
||||
if ( $t === "auto" ) {
|
||||
$style->margin_top = "0pt";
|
||||
$t = 0;
|
||||
}
|
||||
|
||||
if ( $b === "auto" ) {
|
||||
$style->margin_bottom = "0pt";
|
||||
$b = 0;
|
||||
}
|
||||
|
||||
// Collapse vertical margins:
|
||||
$n = $frame->get_next_sibling();
|
||||
if ( $n && !$n->is_block() ) {
|
||||
while ( $n = $n->get_next_sibling() ) {
|
||||
if ( $n->is_block() ) {
|
||||
break;
|
||||
}
|
||||
|
||||
if ( !$n->get_first_child() ) {
|
||||
$n = null;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( $n ) {
|
||||
$n_style = $n->get_style();
|
||||
$b = max($b, $n_style->length_in_pt($n_style->margin_top, $cb["h"]));
|
||||
$n_style->margin_top = "0pt";
|
||||
$style->margin_bottom = $b."pt";
|
||||
}
|
||||
|
||||
// Collapse our first child's margin
|
||||
/*$f = $this->_frame->get_first_child();
|
||||
if ( $f && !$f->is_block() ) {
|
||||
while ( $f = $f->get_next_sibling() ) {
|
||||
if ( $f->is_block() ) {
|
||||
break;
|
||||
}
|
||||
|
||||
if ( !$f->get_first_child() ) {
|
||||
$f = null;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Margin are collapsed only between block elements
|
||||
if ( $f ) {
|
||||
$f_style = $f->get_style();
|
||||
$t = max($t, $f_style->length_in_pt($f_style->margin_top, $cb["h"]));
|
||||
$style->margin_top = $t."pt";
|
||||
$f_style->margin_bottom = "0pt";
|
||||
}*/
|
||||
}
|
||||
|
||||
//........................................................................
|
||||
|
||||
abstract function reflow(Block_Frame_Decorator $block = null);
|
||||
|
||||
//........................................................................
|
||||
|
||||
// Required for table layout: Returns an array(0 => min, 1 => max, "min"
|
||||
// => min, "max" => max) of the minimum and maximum widths of this frame.
|
||||
// This provides a basic implementation. Child classes should override
|
||||
// this if necessary.
|
||||
function get_min_max_width() {
|
||||
if ( !is_null($this->_min_max_cache) ) {
|
||||
return $this->_min_max_cache;
|
||||
}
|
||||
|
||||
$style = $this->_frame->get_style();
|
||||
|
||||
// Account for margins & padding
|
||||
$dims = array($style->padding_left,
|
||||
$style->padding_right,
|
||||
$style->border_left_width,
|
||||
$style->border_right_width,
|
||||
$style->margin_left,
|
||||
$style->margin_right);
|
||||
|
||||
$cb_w = $this->_frame->get_containing_block("w");
|
||||
$delta = $style->length_in_pt($dims, $cb_w);
|
||||
|
||||
// Handle degenerate case
|
||||
if ( !$this->_frame->get_first_child() ) {
|
||||
return $this->_min_max_cache = array(
|
||||
$delta, $delta,
|
||||
"min" => $delta,
|
||||
"max" => $delta,
|
||||
);
|
||||
}
|
||||
|
||||
$low = array();
|
||||
$high = array();
|
||||
|
||||
for ( $iter = $this->_frame->get_children()->getIterator();
|
||||
$iter->valid();
|
||||
$iter->next() ) {
|
||||
|
||||
$inline_min = 0;
|
||||
$inline_max = 0;
|
||||
|
||||
// Add all adjacent inline widths together to calculate max width
|
||||
while ( $iter->valid() && in_array( $iter->current()->get_style()->display, Style::$INLINE_TYPES ) ) {
|
||||
|
||||
$child = $iter->current();
|
||||
|
||||
$minmax = $child->get_min_max_width();
|
||||
|
||||
if ( in_array( $iter->current()->get_style()->white_space, array("pre", "nowrap") ) ) {
|
||||
$inline_min += $minmax["min"];
|
||||
}
|
||||
else {
|
||||
$low[] = $minmax["min"];
|
||||
}
|
||||
|
||||
$inline_max += $minmax["max"];
|
||||
$iter->next();
|
||||
|
||||
}
|
||||
|
||||
if ( $inline_max > 0 ) $high[] = $inline_max;
|
||||
if ( $inline_min > 0 ) $low[] = $inline_min;
|
||||
|
||||
if ( $iter->valid() ) {
|
||||
list($low[], $high[]) = $iter->current()->get_min_max_width();
|
||||
continue;
|
||||
}
|
||||
|
||||
}
|
||||
$min = count($low) ? max($low) : 0;
|
||||
$max = count($high) ? max($high) : 0;
|
||||
|
||||
// Use specified width if it is greater than the minimum defined by the
|
||||
// content. If the width is a percentage ignore it for now.
|
||||
$width = $style->width;
|
||||
if ( $width !== "auto" && !is_percent($width) ) {
|
||||
$width = $style->length_in_pt($width, $cb_w);
|
||||
if ( $min < $width ) $min = $width;
|
||||
if ( $max < $width ) $max = $width;
|
||||
}
|
||||
|
||||
$min += $delta;
|
||||
$max += $delta;
|
||||
return $this->_min_max_cache = array($min, $max, "min"=>$min, "max"=>$max);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a CSS string containing quotes and escaped hex characters
|
||||
*
|
||||
* @param $string string The CSS string to parse
|
||||
* @param $single_trim
|
||||
* @return string
|
||||
*/
|
||||
protected function _parse_string($string, $single_trim = false) {
|
||||
if ( $single_trim ) {
|
||||
$string = preg_replace('/^[\"\']/', "", $string);
|
||||
$string = preg_replace('/[\"\']$/', "", $string);
|
||||
}
|
||||
else {
|
||||
$string = trim($string, "'\"");
|
||||
}
|
||||
|
||||
$string = str_replace(array("\\\n",'\\"',"\\'"),
|
||||
array("",'"',"'"), $string);
|
||||
|
||||
// Convert escaped hex characters into ascii characters (e.g. \A => newline)
|
||||
$string = preg_replace_callback("/\\\\([0-9a-fA-F]{0,6})/",
|
||||
create_function('$matches',
|
||||
'return unichr(hexdec($matches[1]));'),
|
||||
$string);
|
||||
return $string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a CSS "quotes" property
|
||||
*
|
||||
* @return array|null An array of pairs of quotes
|
||||
*/
|
||||
protected function _parse_quotes() {
|
||||
|
||||
// Matches quote types
|
||||
$re = '/(\'[^\']*\')|(\"[^\"]*\")/';
|
||||
|
||||
$quotes = $this->_frame->get_style()->quotes;
|
||||
|
||||
// split on spaces, except within quotes
|
||||
if ( !preg_match_all($re, "$quotes", $matches, PREG_SET_ORDER) ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$quotes_array = array();
|
||||
foreach($matches as &$_quote){
|
||||
$quotes_array[] = $this->_parse_string($_quote[0], true);
|
||||
}
|
||||
|
||||
if ( empty($quotes_array) ) {
|
||||
$quotes_array = array('"', '"');
|
||||
}
|
||||
|
||||
return array_chunk($quotes_array, 2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the CSS "content" property
|
||||
*
|
||||
* @return string|null The resulting string
|
||||
*/
|
||||
protected function _parse_content() {
|
||||
|
||||
// Matches generated content
|
||||
$re = "/\n".
|
||||
"\s(counters?\\([^)]*\\))|\n".
|
||||
"\A(counters?\\([^)]*\\))|\n".
|
||||
"\s([\"']) ( (?:[^\"']|\\\\[\"'])+ )(?<!\\\\)\\3|\n".
|
||||
"\A([\"']) ( (?:[^\"']|\\\\[\"'])+ )(?<!\\\\)\\5|\n" .
|
||||
"\s([^\s\"']+)|\n" .
|
||||
"\A([^\s\"']+)\n".
|
||||
"/xi";
|
||||
|
||||
$content = $this->_frame->get_style()->content;
|
||||
|
||||
$quotes = $this->_parse_quotes();
|
||||
|
||||
// split on spaces, except within quotes
|
||||
if ( !preg_match_all($re, $content, $matches, PREG_SET_ORDER) ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$text = "";
|
||||
|
||||
foreach ($matches as $match) {
|
||||
|
||||
if ( isset($match[2]) && $match[2] !== "" ) {
|
||||
$match[1] = $match[2];
|
||||
}
|
||||
|
||||
if ( isset($match[6]) && $match[6] !== "" ) {
|
||||
$match[4] = $match[6];
|
||||
}
|
||||
|
||||
if ( isset($match[8]) && $match[8] !== "" ) {
|
||||
$match[7] = $match[8];
|
||||
}
|
||||
|
||||
if ( isset($match[1]) && $match[1] !== "" ) {
|
||||
|
||||
// counters?(...)
|
||||
$match[1] = mb_strtolower(trim($match[1]));
|
||||
|
||||
// Handle counter() references:
|
||||
// http://www.w3.org/TR/CSS21/generate.html#content
|
||||
|
||||
$i = mb_strpos($match[1], ")");
|
||||
if ( $i === false ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
preg_match( '/(counters?)(^\()*?\(\s*([^\s,]+)\s*(,\s*["\']?([^"\'\)]+)["\']?\s*(,\s*([^\s)]+)\s*)?)?\)/i' , $match[1] , $args );
|
||||
$counter_id = $args[3];
|
||||
if ( strtolower( $args[1] ) == 'counter' ) {
|
||||
// counter(name [,style])
|
||||
if ( isset( $args[5] ) ) {
|
||||
$type = trim( $args[5] );
|
||||
}
|
||||
else {
|
||||
$type = null;
|
||||
}
|
||||
$p = $this->_frame->lookup_counter_frame( $counter_id );
|
||||
|
||||
$text .= $p->counter_value($counter_id, $type);
|
||||
|
||||
}
|
||||
else if ( strtolower( $args[1] ) == 'counters' ) {
|
||||
// counters(name, string [,style])
|
||||
if ( isset($args[5]) ) {
|
||||
$string = $this->_parse_string( $args[5] );
|
||||
}
|
||||
else {
|
||||
$string = "";
|
||||
}
|
||||
|
||||
if ( isset( $args[7] ) ) {
|
||||
$type = trim( $args[7] );
|
||||
}
|
||||
else {
|
||||
$type = null;
|
||||
}
|
||||
|
||||
$p = $this->_frame->lookup_counter_frame($counter_id);
|
||||
$tmp = array();
|
||||
while ($p) {
|
||||
// We only want to use the counter values when they actually increment the counter
|
||||
if ( array_key_exists( $counter_id , $p->_counters ) ) {
|
||||
array_unshift( $tmp , $p->counter_value($counter_id, $type) );
|
||||
}
|
||||
$p = $p->lookup_counter_frame($counter_id);
|
||||
|
||||
}
|
||||
$text .= implode( $string , $tmp );
|
||||
|
||||
}
|
||||
else {
|
||||
// countertops?
|
||||
continue;
|
||||
}
|
||||
|
||||
}
|
||||
else if ( isset($match[4]) && $match[4] !== "" ) {
|
||||
// String match
|
||||
$text .= $this->_parse_string($match[4]);
|
||||
}
|
||||
else if ( isset($match[7]) && $match[7] !== "" ) {
|
||||
// Directive match
|
||||
|
||||
if ( $match[7] === "open-quote" ) {
|
||||
// FIXME: do something here
|
||||
$text .= $quotes[0][0];
|
||||
}
|
||||
else if ( $match[7] === "close-quote" ) {
|
||||
// FIXME: do something else here
|
||||
$text .= $quotes[0][1];
|
||||
}
|
||||
else if ( $match[7] === "no-open-quote" ) {
|
||||
// FIXME:
|
||||
}
|
||||
else if ( $match[7] === "no-close-quote" ) {
|
||||
// FIXME:
|
||||
}
|
||||
else if ( mb_strpos($match[7],"attr(") === 0 ) {
|
||||
|
||||
$i = mb_strpos($match[7],")");
|
||||
if ( $i === false ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$attr = mb_substr($match[7], 5, $i - 5);
|
||||
if ( $attr == "" ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$text .= $this->_frame->get_parent()->get_node()->getAttribute($attr);
|
||||
}
|
||||
else {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $text;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the generated content of a generated frame
|
||||
*/
|
||||
protected function _set_content(){
|
||||
$frame = $this->_frame;
|
||||
$style = $frame->get_style();
|
||||
|
||||
// if the element was pushed to a new page use the saved counter value, otherwise use the CSS reset value
|
||||
if ( $style->counter_reset && ($reset = $style->counter_reset) !== "none" ) {
|
||||
$vars = preg_split('/\s+/', trim($reset), 2);
|
||||
$frame->reset_counter( $vars[0] , ( isset($frame->_counters['__'.$vars[0]]) ? $frame->_counters['__'.$vars[0]] : ( isset($vars[1]) ? $vars[1] : 0 ) ) );
|
||||
}
|
||||
|
||||
if ( $style->counter_increment && ($increment = $style->counter_increment) !== "none" ) {
|
||||
$frame->increment_counters($increment);
|
||||
}
|
||||
|
||||
if ( $style->content && !$frame->get_first_child() && $frame->get_node()->nodeName === "dompdf_generated" ) {
|
||||
$content = $this->_parse_content();
|
||||
// add generated content to the font subset
|
||||
// FIXME: This is currently too late because the font subset has already been generated.
|
||||
// See notes in issue #750.
|
||||
if ( $frame->get_dompdf()->get_option("enable_font_subsetting") && $frame->get_dompdf()->get_canvas() instanceof CPDF_Adapter ) {
|
||||
$frame->get_dompdf()->get_canvas()->register_string_subset($style->font_family, $content);
|
||||
}
|
||||
|
||||
$node = $frame->get_node()->ownerDocument->createTextNode($content);
|
||||
|
||||
$new_style = $style->get_stylesheet()->create_style();
|
||||
$new_style->inherit($style);
|
||||
|
||||
$new_frame = new Frame($node);
|
||||
$new_frame->set_style($new_style);
|
||||
|
||||
Frame_Factory::decorate_frame($new_frame, $frame->get_dompdf(), $frame->get_root());
|
||||
$frame->append_child($new_frame);
|
||||
}
|
||||
}
|
||||
}
|
||||
241
application/helpers/dompdf/include/frame_tree.cls.php
Executable file
241
application/helpers/dompdf/include/frame_tree.cls.php
Executable file
@@ -0,0 +1,241 @@
|
||||
<?php
|
||||
/**
|
||||
* @package dompdf
|
||||
* @link http://dompdf.github.com/
|
||||
* @author Benj Carson <benjcarson@digitaljunkies.ca>
|
||||
* @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
|
||||
*/
|
||||
|
||||
/**
|
||||
* Represents an entire document as a tree of frames
|
||||
*
|
||||
* The Frame_Tree consists of {@link Frame} objects each tied to specific
|
||||
* DOMNode objects in a specific DomDocument. The Frame_Tree has the same
|
||||
* structure as the DomDocument, but adds additional capabalities for
|
||||
* styling and layout.
|
||||
*
|
||||
* @package dompdf
|
||||
* @access protected
|
||||
*/
|
||||
class Frame_Tree {
|
||||
|
||||
/**
|
||||
* Tags to ignore while parsing the tree
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
static protected $_HIDDEN_TAGS = array("area", "base", "basefont", "head", "style",
|
||||
"meta", "title", "colgroup",
|
||||
"noembed", "noscript", "param", "#comment");
|
||||
/**
|
||||
* The main DomDocument
|
||||
*
|
||||
* @see http://ca2.php.net/manual/en/ref.dom.php
|
||||
* @var DomDocument
|
||||
*/
|
||||
protected $_dom;
|
||||
|
||||
/**
|
||||
* The root node of the FrameTree.
|
||||
*
|
||||
* @var Frame
|
||||
*/
|
||||
protected $_root;
|
||||
|
||||
/**
|
||||
* Subtrees of absolutely positioned elements
|
||||
*
|
||||
* @var array of Frames
|
||||
*/
|
||||
protected $_absolute_frames;
|
||||
|
||||
/**
|
||||
* A mapping of {@link Frame} objects to DOMNode objects
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $_registry;
|
||||
|
||||
|
||||
/**
|
||||
* Class constructor
|
||||
*
|
||||
* @param DomDocument $dom the main DomDocument object representing the current html document
|
||||
*/
|
||||
function __construct(DomDocument $dom) {
|
||||
$this->_dom = $dom;
|
||||
$this->_root = null;
|
||||
$this->_registry = array();
|
||||
}
|
||||
|
||||
function __destruct() {
|
||||
clear_object($this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the DomDocument object representing the curent html document
|
||||
*
|
||||
* @return DOMDocument
|
||||
*/
|
||||
function get_dom() {
|
||||
return $this->_dom;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the root frame of the tree
|
||||
*
|
||||
* @return Page_Frame_Decorator
|
||||
*/
|
||||
function get_root() {
|
||||
return $this->_root;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a specific frame given its id
|
||||
*
|
||||
* @param string $id
|
||||
* @return Frame
|
||||
*/
|
||||
function get_frame($id) {
|
||||
return isset($this->_registry[$id]) ? $this->_registry[$id] : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a post-order iterator for all frames in the tree
|
||||
*
|
||||
* @return FrameTreeList|Frame[]
|
||||
*/
|
||||
function get_frames() {
|
||||
return new FrameTreeList($this->_root);
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the tree
|
||||
*/
|
||||
function build_tree() {
|
||||
$html = $this->_dom->getElementsByTagName("html")->item(0);
|
||||
if ( is_null($html) ) {
|
||||
$html = $this->_dom->firstChild;
|
||||
}
|
||||
|
||||
if ( is_null($html) ) {
|
||||
throw new DOMPDF_Exception("Requested HTML document contains no data.");
|
||||
}
|
||||
|
||||
$this->fix_tables();
|
||||
|
||||
$this->_root = $this->_build_tree_r($html);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds missing TBODYs around TR
|
||||
*/
|
||||
protected function fix_tables(){
|
||||
$xp = new DOMXPath($this->_dom);
|
||||
|
||||
// Move table caption before the table
|
||||
// FIXME find a better way to deal with it...
|
||||
$captions = $xp->query("//table/caption");
|
||||
foreach($captions as $caption) {
|
||||
$table = $caption->parentNode;
|
||||
$table->parentNode->insertBefore($caption, $table);
|
||||
}
|
||||
|
||||
$rows = $xp->query("//table/tr");
|
||||
foreach($rows as $row) {
|
||||
$tbody = $this->_dom->createElement("tbody");
|
||||
$tbody = $row->parentNode->insertBefore($tbody, $row);
|
||||
$tbody->appendChild($row);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively adds {@link Frame} objects to the tree
|
||||
*
|
||||
* Recursively build a tree of Frame objects based on a dom tree.
|
||||
* No layout information is calculated at this time, although the
|
||||
* tree may be adjusted (i.e. nodes and frames for generated content
|
||||
* and images may be created).
|
||||
*
|
||||
* @param DOMNode $node the current DOMNode being considered
|
||||
* @return Frame
|
||||
*/
|
||||
protected function _build_tree_r(DOMNode $node) {
|
||||
|
||||
$frame = new Frame($node);
|
||||
$id = $frame->get_id();
|
||||
$this->_registry[ $id ] = $frame;
|
||||
|
||||
if ( !$node->hasChildNodes() ) {
|
||||
return $frame;
|
||||
}
|
||||
|
||||
// Fixes 'cannot access undefined property for object with
|
||||
// overloaded access', fix by Stefan radulian
|
||||
// <stefan.radulian@symbion.at>
|
||||
//foreach ($node->childNodes as $child) {
|
||||
|
||||
// Store the children in an array so that the tree can be modified
|
||||
$children = array();
|
||||
for ($i = 0; $i < $node->childNodes->length; $i++) {
|
||||
$children[] = $node->childNodes->item($i);
|
||||
}
|
||||
|
||||
foreach ($children as $child) {
|
||||
$node_name = mb_strtolower($child->nodeName);
|
||||
|
||||
// Skip non-displaying nodes
|
||||
if ( in_array($node_name, self::$_HIDDEN_TAGS) ) {
|
||||
if ( $node_name !== "head" && $node_name !== "style" ) {
|
||||
$child->parentNode->removeChild($child);
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// Skip empty text nodes
|
||||
if ( $node_name === "#text" && $child->nodeValue == "" ) {
|
||||
$child->parentNode->removeChild($child);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Skip empty image nodes
|
||||
if ( $node_name === "img" && $child->getAttribute("src") == "" ) {
|
||||
$child->parentNode->removeChild($child);
|
||||
continue;
|
||||
}
|
||||
|
||||
$frame->append_child($this->_build_tree_r($child), false);
|
||||
}
|
||||
|
||||
return $frame;
|
||||
}
|
||||
|
||||
public function insert_node(DOMNode $node, DOMNode $new_node, $pos) {
|
||||
if ( $pos === "after" || !$node->firstChild ) {
|
||||
$node->appendChild($new_node);
|
||||
}
|
||||
else {
|
||||
$node->insertBefore($new_node, $node->firstChild);
|
||||
}
|
||||
|
||||
$this->_build_tree_r($new_node);
|
||||
|
||||
$frame_id = $new_node->getAttribute("frame_id");
|
||||
$frame = $this->get_frame($frame_id);
|
||||
|
||||
$parent_id = $node->getAttribute("frame_id");
|
||||
$parent = $this->get_frame($parent_id);
|
||||
|
||||
if ( $parent ) {
|
||||
if ( $pos === "before" ) {
|
||||
$parent->prepend_child($frame, false);
|
||||
}
|
||||
else {
|
||||
$parent->append_child($frame, false);
|
||||
}
|
||||
}
|
||||
|
||||
return $frame_id;
|
||||
}
|
||||
}
|
||||
1054
application/helpers/dompdf/include/functions.inc.php
Executable file
1054
application/helpers/dompdf/include/functions.inc.php
Executable file
File diff suppressed because it is too large
Load Diff
840
application/helpers/dompdf/include/gd_adapter.cls.php
Executable file
840
application/helpers/dompdf/include/gd_adapter.cls.php
Executable file
@@ -0,0 +1,840 @@
|
||||
<?php
|
||||
/**
|
||||
* @package dompdf
|
||||
* @link http://dompdf.github.com/
|
||||
* @author Benj Carson <benjcarson@digitaljunkies.ca>
|
||||
* @author Fabien Ménager <fabien.menager@gmail.com>
|
||||
* @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
|
||||
*/
|
||||
|
||||
/**
|
||||
* Image rendering interface
|
||||
*
|
||||
* Renders to an image format supported by GD (jpeg, gif, png, xpm).
|
||||
* Not super-useful day-to-day but handy nonetheless
|
||||
*
|
||||
* @package dompdf
|
||||
*/
|
||||
class GD_Adapter implements Canvas {
|
||||
/**
|
||||
* @var DOMPDF
|
||||
*/
|
||||
private $_dompdf;
|
||||
|
||||
/**
|
||||
* Resource handle for the image
|
||||
*
|
||||
* @var resource
|
||||
*/
|
||||
private $_img;
|
||||
|
||||
/**
|
||||
* Image width in pixels
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
private $_width;
|
||||
|
||||
/**
|
||||
* Image height in pixels
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
private $_height;
|
||||
|
||||
/**
|
||||
* Current page number
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
private $_page_number;
|
||||
|
||||
/**
|
||||
* Total number of pages
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
private $_page_count;
|
||||
|
||||
/**
|
||||
* Image antialias factor
|
||||
*
|
||||
* @var float
|
||||
*/
|
||||
private $_aa_factor;
|
||||
|
||||
/**
|
||||
* Allocated colors
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $_colors;
|
||||
|
||||
/**
|
||||
* Background color
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
private $_bg_color;
|
||||
|
||||
/**
|
||||
* Class constructor
|
||||
*
|
||||
* @param mixed $size The size of image to create: array(x1,y1,x2,y2) or "letter", "legal", etc.
|
||||
* @param string $orientation The orientation of the document (either 'landscape' or 'portrait')
|
||||
* @param DOMPDF $dompdf
|
||||
* @param float $aa_factor Anti-aliasing factor, 1 for no AA
|
||||
* @param array $bg_color Image background color: array(r,g,b,a), 0 <= r,g,b,a <= 1
|
||||
*/
|
||||
function __construct($size, $orientation = "portrait", DOMPDF $dompdf, $aa_factor = 1.0, $bg_color = array(1,1,1,0) ) {
|
||||
|
||||
if ( !is_array($size) ) {
|
||||
$size = strtolower($size);
|
||||
|
||||
if ( isset(CPDF_Adapter::$PAPER_SIZES[$size]) ) {
|
||||
$size = CPDF_Adapter::$PAPER_SIZES[$size];
|
||||
}
|
||||
else {
|
||||
$size = CPDF_Adapter::$PAPER_SIZES["letter"];
|
||||
}
|
||||
}
|
||||
|
||||
if ( strtolower($orientation) === "landscape" ) {
|
||||
list($size[2],$size[3]) = array($size[3],$size[2]);
|
||||
}
|
||||
|
||||
$this->_dompdf = $dompdf;
|
||||
|
||||
if ( $aa_factor < 1 ) {
|
||||
$aa_factor = 1;
|
||||
}
|
||||
|
||||
$this->_aa_factor = $aa_factor;
|
||||
|
||||
$size[2] *= $aa_factor;
|
||||
$size[3] *= $aa_factor;
|
||||
|
||||
$this->_width = $size[2] - $size[0];
|
||||
$this->_height = $size[3] - $size[1];
|
||||
|
||||
$this->_img = imagecreatetruecolor($this->_width, $this->_height);
|
||||
|
||||
if ( is_null($bg_color) || !is_array($bg_color) ) {
|
||||
// Pure white bg
|
||||
$bg_color = array(1,1,1,0);
|
||||
}
|
||||
|
||||
$this->_bg_color = $this->_allocate_color($bg_color);
|
||||
imagealphablending($this->_img, true);
|
||||
imagesavealpha($this->_img, true);
|
||||
imagefill($this->_img, 0, 0, $this->_bg_color);
|
||||
|
||||
}
|
||||
|
||||
function get_dompdf(){
|
||||
return $this->_dompdf;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the GF image resource
|
||||
*
|
||||
* @return resource
|
||||
*/
|
||||
function get_image() { return $this->_img; }
|
||||
|
||||
/**
|
||||
* Return the image's width in pixels
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
function get_width() { return $this->_width / $this->_aa_factor; }
|
||||
|
||||
/**
|
||||
* Return the image's height in pixels
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
function get_height() { return $this->_height / $this->_aa_factor; }
|
||||
|
||||
/**
|
||||
* Returns the current page number
|
||||
* @return int
|
||||
*/
|
||||
function get_page_number() { return $this->_page_number; }
|
||||
|
||||
/**
|
||||
* Returns the total number of pages in the document
|
||||
* @return int
|
||||
*/
|
||||
function get_page_count() { return $this->_page_count; }
|
||||
|
||||
/**
|
||||
* Sets the current page number
|
||||
*
|
||||
* @param int $num
|
||||
*/
|
||||
function set_page_number($num) { $this->_page_number = $num; }
|
||||
|
||||
/**
|
||||
* Sets the page count
|
||||
*
|
||||
* @param int $count
|
||||
*/
|
||||
function set_page_count($count) { $this->_page_count = $count; }
|
||||
|
||||
/**
|
||||
* Sets the opacity
|
||||
*
|
||||
* @param $opacity
|
||||
* @param $mode
|
||||
*/
|
||||
function set_opacity($opacity, $mode = "Normal") {
|
||||
// FIXME
|
||||
}
|
||||
|
||||
/**
|
||||
* Allocate a new color. Allocate with GD as needed and store
|
||||
* previously allocated colors in $this->_colors.
|
||||
*
|
||||
* @param array $color The new current color
|
||||
* @return int The allocated color
|
||||
*/
|
||||
private function _allocate_color($color) {
|
||||
|
||||
if ( isset($color["c"]) ) {
|
||||
$color = cmyk_to_rgb($color);
|
||||
}
|
||||
|
||||
// Full opacity if no alpha set
|
||||
if ( !isset($color[3]) )
|
||||
$color[3] = 0;
|
||||
|
||||
list($r,$g,$b,$a) = $color;
|
||||
|
||||
$r *= 255;
|
||||
$g *= 255;
|
||||
$b *= 255;
|
||||
$a *= 127;
|
||||
|
||||
// Clip values
|
||||
$r = $r > 255 ? 255 : $r;
|
||||
$g = $g > 255 ? 255 : $g;
|
||||
$b = $b > 255 ? 255 : $b;
|
||||
$a = $a > 127 ? 127 : $a;
|
||||
|
||||
$r = $r < 0 ? 0 : $r;
|
||||
$g = $g < 0 ? 0 : $g;
|
||||
$b = $b < 0 ? 0 : $b;
|
||||
$a = $a < 0 ? 0 : $a;
|
||||
|
||||
$key = sprintf("#%02X%02X%02X%02X", $r, $g, $b, $a);
|
||||
|
||||
if ( isset($this->_colors[$key]) )
|
||||
return $this->_colors[$key];
|
||||
|
||||
if ( $a != 0 )
|
||||
$this->_colors[$key] = imagecolorallocatealpha($this->_img, $r, $g, $b, $a);
|
||||
else
|
||||
$this->_colors[$key] = imagecolorallocate($this->_img, $r, $g, $b);
|
||||
|
||||
return $this->_colors[$key];
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws a line from x1,y1 to x2,y2
|
||||
*
|
||||
* See {@link Style::munge_color()} for the format of the color array.
|
||||
* See {@link Cpdf::setLineStyle()} for a description of the format of the
|
||||
* $style parameter (aka dash).
|
||||
*
|
||||
* @param float $x1
|
||||
* @param float $y1
|
||||
* @param float $x2
|
||||
* @param float $y2
|
||||
* @param array $color
|
||||
* @param float $width
|
||||
* @param array $style
|
||||
*/
|
||||
function line($x1, $y1, $x2, $y2, $color, $width, $style = null) {
|
||||
|
||||
// Scale by the AA factor
|
||||
$x1 *= $this->_aa_factor;
|
||||
$y1 *= $this->_aa_factor;
|
||||
$x2 *= $this->_aa_factor;
|
||||
$y2 *= $this->_aa_factor;
|
||||
$width *= $this->_aa_factor;
|
||||
|
||||
$c = $this->_allocate_color($color);
|
||||
|
||||
// Convert the style array if required
|
||||
if ( !is_null($style) ) {
|
||||
$gd_style = array();
|
||||
|
||||
if ( count($style) == 1 ) {
|
||||
for ($i = 0; $i < $style[0] * $this->_aa_factor; $i++) {
|
||||
$gd_style[] = $c;
|
||||
}
|
||||
|
||||
for ($i = 0; $i < $style[0] * $this->_aa_factor; $i++) {
|
||||
$gd_style[] = $this->_bg_color;
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
$i = 0;
|
||||
foreach ($style as $length) {
|
||||
|
||||
if ( $i % 2 == 0 ) {
|
||||
// 'On' pattern
|
||||
for ($i = 0; $i < $style[0] * $this->_aa_factor; $i++)
|
||||
$gd_style[] = $c;
|
||||
|
||||
} else {
|
||||
// Off pattern
|
||||
for ($i = 0; $i < $style[0] * $this->_aa_factor; $i++)
|
||||
$gd_style[] = $this->_bg_color;
|
||||
|
||||
}
|
||||
$i++;
|
||||
}
|
||||
}
|
||||
|
||||
imagesetstyle($this->_img, $gd_style);
|
||||
$c = IMG_COLOR_STYLED;
|
||||
}
|
||||
|
||||
imagesetthickness($this->_img, $width);
|
||||
|
||||
imageline($this->_img, $x1, $y1, $x2, $y2, $c);
|
||||
|
||||
}
|
||||
|
||||
function arc($x1, $y1, $r1, $r2, $astart, $aend, $color, $width, $style = array()) {
|
||||
// @todo
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws a rectangle at x1,y1 with width w and height h
|
||||
*
|
||||
* See {@link Style::munge_color()} for the format of the color array.
|
||||
* See {@link Cpdf::setLineStyle()} for a description of the $style
|
||||
* parameter (aka dash)
|
||||
*
|
||||
* @param float $x1
|
||||
* @param float $y1
|
||||
* @param float $w
|
||||
* @param float $h
|
||||
* @param array $color
|
||||
* @param float $width
|
||||
* @param array $style
|
||||
*/
|
||||
function rectangle($x1, $y1, $w, $h, $color, $width, $style = null) {
|
||||
|
||||
// Scale by the AA factor
|
||||
$x1 *= $this->_aa_factor;
|
||||
$y1 *= $this->_aa_factor;
|
||||
$w *= $this->_aa_factor;
|
||||
$h *= $this->_aa_factor;
|
||||
|
||||
$c = $this->_allocate_color($color);
|
||||
|
||||
// Convert the style array if required
|
||||
if ( !is_null($style) ) {
|
||||
$gd_style = array();
|
||||
|
||||
foreach ($style as $length) {
|
||||
for ($i = 0; $i < $length; $i++) {
|
||||
$gd_style[] = $c;
|
||||
}
|
||||
}
|
||||
|
||||
imagesetstyle($this->_img, $gd_style);
|
||||
$c = IMG_COLOR_STYLED;
|
||||
}
|
||||
|
||||
imagesetthickness($this->_img, $width);
|
||||
|
||||
imagerectangle($this->_img, $x1, $y1, $x1 + $w, $y1 + $h, $c);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws a filled rectangle at x1,y1 with width w and height h
|
||||
*
|
||||
* See {@link Style::munge_color()} for the format of the color array.
|
||||
*
|
||||
* @param float $x1
|
||||
* @param float $y1
|
||||
* @param float $w
|
||||
* @param float $h
|
||||
* @param array $color
|
||||
*/
|
||||
function filled_rectangle($x1, $y1, $w, $h, $color) {
|
||||
|
||||
// Scale by the AA factor
|
||||
$x1 *= $this->_aa_factor;
|
||||
$y1 *= $this->_aa_factor;
|
||||
$w *= $this->_aa_factor;
|
||||
$h *= $this->_aa_factor;
|
||||
|
||||
$c = $this->_allocate_color($color);
|
||||
|
||||
imagefilledrectangle($this->_img, $x1, $y1, $x1 + $w, $y1 + $h, $c);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts a clipping rectangle at x1,y1 with width w and height h
|
||||
*
|
||||
* @param float $x1
|
||||
* @param float $y1
|
||||
* @param float $w
|
||||
* @param float $h
|
||||
*/
|
||||
function clipping_rectangle($x1, $y1, $w, $h) {
|
||||
// @todo
|
||||
}
|
||||
|
||||
function clipping_roundrectangle($x1, $y1, $w, $h, $rTL, $rTR, $rBR, $rBL) {
|
||||
// @todo
|
||||
}
|
||||
|
||||
/**
|
||||
* Ends the last clipping shape
|
||||
*/
|
||||
function clipping_end() {
|
||||
// @todo
|
||||
}
|
||||
|
||||
function save() {
|
||||
// @todo
|
||||
}
|
||||
|
||||
function restore() {
|
||||
// @todo
|
||||
}
|
||||
|
||||
function rotate($angle, $x, $y) {
|
||||
// @todo
|
||||
}
|
||||
|
||||
function skew($angle_x, $angle_y, $x, $y) {
|
||||
// @todo
|
||||
}
|
||||
|
||||
function scale($s_x, $s_y, $x, $y) {
|
||||
// @todo
|
||||
}
|
||||
|
||||
function translate($t_x, $t_y) {
|
||||
// @todo
|
||||
}
|
||||
|
||||
function transform($a, $b, $c, $d, $e, $f) {
|
||||
// @todo
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws a polygon
|
||||
*
|
||||
* The polygon is formed by joining all the points stored in the $points
|
||||
* array. $points has the following structure:
|
||||
* <code>
|
||||
* array(0 => x1,
|
||||
* 1 => y1,
|
||||
* 2 => x2,
|
||||
* 3 => y2,
|
||||
* ...
|
||||
* );
|
||||
* </code>
|
||||
*
|
||||
* See {@link Style::munge_color()} for the format of the color array.
|
||||
* See {@link Cpdf::setLineStyle()} for a description of the $style
|
||||
* parameter (aka dash)
|
||||
*
|
||||
* @param array $points
|
||||
* @param array $color
|
||||
* @param float $width
|
||||
* @param array $style
|
||||
* @param bool $fill Fills the polygon if true
|
||||
*/
|
||||
function polygon($points, $color, $width = null, $style = null, $fill = false) {
|
||||
|
||||
// Scale each point by the AA factor
|
||||
foreach (array_keys($points) as $i)
|
||||
$points[$i] *= $this->_aa_factor;
|
||||
|
||||
$c = $this->_allocate_color($color);
|
||||
|
||||
// Convert the style array if required
|
||||
if ( !is_null($style) && !$fill ) {
|
||||
$gd_style = array();
|
||||
|
||||
foreach ($style as $length) {
|
||||
for ($i = 0; $i < $length; $i++) {
|
||||
$gd_style[] = $c;
|
||||
}
|
||||
}
|
||||
|
||||
imagesetstyle($this->_img, $gd_style);
|
||||
$c = IMG_COLOR_STYLED;
|
||||
}
|
||||
|
||||
imagesetthickness($this->_img, $width);
|
||||
|
||||
if ( $fill )
|
||||
imagefilledpolygon($this->_img, $points, count($points) / 2, $c);
|
||||
else
|
||||
imagepolygon($this->_img, $points, count($points) / 2, $c);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws a circle at $x,$y with radius $r
|
||||
*
|
||||
* See {@link Style::munge_color()} for the format of the color array.
|
||||
* See {@link Cpdf::setLineStyle()} for a description of the $style
|
||||
* parameter (aka dash)
|
||||
*
|
||||
* @param float $x
|
||||
* @param float $y
|
||||
* @param float $r
|
||||
* @param array $color
|
||||
* @param float $width
|
||||
* @param array $style
|
||||
* @param bool $fill Fills the circle if true
|
||||
*/
|
||||
function circle($x, $y, $r, $color, $width = null, $style = null, $fill = false) {
|
||||
|
||||
// Scale by the AA factor
|
||||
$x *= $this->_aa_factor;
|
||||
$y *= $this->_aa_factor;
|
||||
$r *= $this->_aa_factor;
|
||||
|
||||
$c = $this->_allocate_color($color);
|
||||
|
||||
// Convert the style array if required
|
||||
if ( !is_null($style) && !$fill ) {
|
||||
$gd_style = array();
|
||||
|
||||
foreach ($style as $length) {
|
||||
for ($i = 0; $i < $length; $i++) {
|
||||
$gd_style[] = $c;
|
||||
}
|
||||
}
|
||||
|
||||
imagesetstyle($this->_img, $gd_style);
|
||||
$c = IMG_COLOR_STYLED;
|
||||
}
|
||||
|
||||
imagesetthickness($this->_img, $width);
|
||||
|
||||
if ( $fill )
|
||||
imagefilledellipse($this->_img, $x, $y, $r, $r, $c);
|
||||
else
|
||||
imageellipse($this->_img, $x, $y, $r, $r, $c);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an image to the pdf.
|
||||
* The image is placed at the specified x and y coordinates with the
|
||||
* given width and height.
|
||||
*
|
||||
* @param string $img_url the path to the image
|
||||
* @param float $x x position
|
||||
* @param float $y y position
|
||||
* @param int $w width (in pixels)
|
||||
* @param int $h height (in pixels)
|
||||
* @param string $resolution
|
||||
*
|
||||
* @return void
|
||||
* @internal param string $img_type the type (e.g. extension) of the image
|
||||
*/
|
||||
function image($img_url, $x, $y, $w, $h, $resolution = "normal") {
|
||||
$img_type = Image_Cache::detect_type($img_url);
|
||||
$img_ext = Image_Cache::type_to_ext($img_type);
|
||||
|
||||
if ( !$img_ext ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$func = "imagecreatefrom$img_ext";
|
||||
$src = @$func($img_url);
|
||||
|
||||
if ( !$src ) {
|
||||
return; // Probably should add to $_dompdf_errors or whatever here
|
||||
}
|
||||
|
||||
// Scale by the AA factor
|
||||
$x *= $this->_aa_factor;
|
||||
$y *= $this->_aa_factor;
|
||||
|
||||
$w *= $this->_aa_factor;
|
||||
$h *= $this->_aa_factor;
|
||||
|
||||
$img_w = imagesx($src);
|
||||
$img_h = imagesy($src);
|
||||
|
||||
imagecopyresampled($this->_img, $src, $x, $y, 0, 0, $w, $h, $img_w, $img_h);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes text at the specified x and y coordinates
|
||||
* See {@link Style::munge_color()} for the format of the color array.
|
||||
*
|
||||
* @param float $x
|
||||
* @param float $y
|
||||
* @param string $text the text to write
|
||||
* @param string $font the font file to use
|
||||
* @param float $size the font size, in points
|
||||
* @param array $color
|
||||
* @param float $word_spacing word spacing adjustment
|
||||
* @param float $char_spacing
|
||||
* @param float $angle Text angle
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function text($x, $y, $text, $font, $size, $color = array(0,0,0), $word_spacing = 0.0, $char_spacing = 0.0, $angle = 0.0) {
|
||||
|
||||
// Scale by the AA factor
|
||||
$x *= $this->_aa_factor;
|
||||
$y *= $this->_aa_factor;
|
||||
$size *= $this->_aa_factor;
|
||||
|
||||
$h = $this->get_font_height($font, $size);
|
||||
$c = $this->_allocate_color($color);
|
||||
|
||||
$text = mb_encode_numericentity($text, array(0x0080, 0xff, 0, 0xff), 'UTF-8');
|
||||
|
||||
$font = $this->get_ttf_file($font);
|
||||
|
||||
// FIXME: word spacing
|
||||
@imagettftext($this->_img, $size, $angle, $x, $y + $h, $c, $font, $text);
|
||||
|
||||
}
|
||||
|
||||
function javascript($code) {
|
||||
// Not implemented
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a named destination (similar to <a name="foo">...</a> in html)
|
||||
*
|
||||
* @param string $anchorname The name of the named destination
|
||||
*/
|
||||
function add_named_dest($anchorname) {
|
||||
// Not implemented
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a link to the pdf
|
||||
*
|
||||
* @param string $url The url to link to
|
||||
* @param float $x The x position of the link
|
||||
* @param float $y The y position of the link
|
||||
* @param float $width The width of the link
|
||||
* @param float $height The height of the link
|
||||
*/
|
||||
function add_link($url, $x, $y, $width, $height) {
|
||||
// Not implemented
|
||||
}
|
||||
|
||||
/**
|
||||
* Add meta information to the PDF
|
||||
*
|
||||
* @param string $label label of the value (Creator, Producer, etc.)
|
||||
* @param string $value the text to set
|
||||
*/
|
||||
function add_info($label, $value) {
|
||||
// N/A
|
||||
}
|
||||
|
||||
function set_default_view($view, $options = array()) {
|
||||
// N/A
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates text size, in points
|
||||
*
|
||||
* @param string $text the text to be sized
|
||||
* @param string $font the desired font
|
||||
* @param float $size the desired font size
|
||||
* @param float $word_spacing word spacing, if any
|
||||
* @param float $char_spacing char spacing, if any
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
function get_text_width($text, $font, $size, $word_spacing = 0.0, $char_spacing = 0.0) {
|
||||
$font = $this->get_ttf_file($font);
|
||||
|
||||
$text = mb_encode_numericentity($text, array(0x0080, 0xffff, 0, 0xffff), 'UTF-8');
|
||||
|
||||
// FIXME: word spacing
|
||||
list($x1,,$x2) = @imagettfbbox($size, 0, $font, $text);
|
||||
return $x2 - $x1;
|
||||
}
|
||||
|
||||
function get_ttf_file($font) {
|
||||
if ( strpos($font, '.ttf') === false )
|
||||
$font .= ".ttf";
|
||||
|
||||
/*$filename = substr(strtolower(basename($font)), 0, -4);
|
||||
|
||||
if ( in_array($filename, DOMPDF::$native_fonts) ) {
|
||||
return "arial.ttf";
|
||||
}*/
|
||||
|
||||
return $font;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates font height, in points
|
||||
*
|
||||
* @param string $font
|
||||
* @param float $size
|
||||
* @return float
|
||||
*/
|
||||
function get_font_height($font, $size) {
|
||||
$font = $this->get_ttf_file($font);
|
||||
$ratio = $this->_dompdf->get_option("font_height_ratio");
|
||||
|
||||
// FIXME: word spacing
|
||||
list(,$y2,,,,$y1) = imagettfbbox($size, 0, $font, "MXjpqytfhl"); // Test string with ascenders, descenders and caps
|
||||
return ($y2 - $y1) * $ratio;
|
||||
}
|
||||
|
||||
function get_font_baseline($font, $size) {
|
||||
$ratio = $this->_dompdf->get_option("font_height_ratio");
|
||||
return $this->get_font_height($font, $size) / $ratio;
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts a new page
|
||||
*
|
||||
* Subsequent drawing operations will appear on the new page.
|
||||
*/
|
||||
function new_page() {
|
||||
$this->_page_number++;
|
||||
$this->_page_count++;
|
||||
}
|
||||
|
||||
function open_object(){
|
||||
// N/A
|
||||
}
|
||||
|
||||
function close_object(){
|
||||
// N/A
|
||||
}
|
||||
|
||||
function add_object(){
|
||||
// N/A
|
||||
}
|
||||
|
||||
function page_text(){
|
||||
// N/A
|
||||
}
|
||||
|
||||
/**
|
||||
* Streams the image directly to the browser
|
||||
*
|
||||
* @param string $filename the name of the image file (ignored)
|
||||
* @param array $options associative array, 'type' => jpeg|jpg|png, 'quality' => 0 - 100 (jpeg only)
|
||||
*/
|
||||
function stream($filename, $options = null) {
|
||||
|
||||
// Perform any antialiasing
|
||||
if ( $this->_aa_factor != 1 ) {
|
||||
$dst_w = $this->_width / $this->_aa_factor;
|
||||
$dst_h = $this->_height / $this->_aa_factor;
|
||||
$dst = imagecreatetruecolor($dst_w, $dst_h);
|
||||
imagecopyresampled($dst, $this->_img, 0, 0, 0, 0,
|
||||
$dst_w, $dst_h,
|
||||
$this->_width, $this->_height);
|
||||
} else {
|
||||
$dst = $this->_img;
|
||||
}
|
||||
|
||||
if ( !isset($options["type"]) )
|
||||
$options["type"] = "png";
|
||||
|
||||
$type = strtolower($options["type"]);
|
||||
|
||||
header("Cache-Control: private");
|
||||
|
||||
switch ($type) {
|
||||
|
||||
case "jpg":
|
||||
case "jpeg":
|
||||
if ( !isset($options["quality"]) )
|
||||
$options["quality"] = 75;
|
||||
|
||||
header("Content-type: image/jpeg");
|
||||
imagejpeg($dst, '', $options["quality"]);
|
||||
break;
|
||||
|
||||
case "png":
|
||||
default:
|
||||
header("Content-type: image/png");
|
||||
imagepng($dst);
|
||||
break;
|
||||
}
|
||||
|
||||
if ( $this->_aa_factor != 1 )
|
||||
imagedestroy($dst);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the PNG as a string
|
||||
*
|
||||
* @param array $options associative array, 'type' => jpeg|jpg|png, 'quality' => 0 - 100 (jpeg only)
|
||||
* @return string
|
||||
*/
|
||||
function output($options = null) {
|
||||
|
||||
if ( $this->_aa_factor != 1 ) {
|
||||
$dst_w = $this->_width / $this->_aa_factor;
|
||||
$dst_h = $this->_height / $this->_aa_factor;
|
||||
$dst = imagecreatetruecolor($dst_w, $dst_h);
|
||||
imagecopyresampled($dst, $this->_img, 0, 0, 0, 0,
|
||||
$dst_w, $dst_h,
|
||||
$this->_width, $this->_height);
|
||||
} else {
|
||||
$dst = $this->_img;
|
||||
}
|
||||
|
||||
if ( !isset($options["type"]) )
|
||||
$options["type"] = "png";
|
||||
|
||||
$type = $options["type"];
|
||||
|
||||
ob_start();
|
||||
|
||||
switch ($type) {
|
||||
|
||||
case "jpg":
|
||||
case "jpeg":
|
||||
if ( !isset($options["quality"]) )
|
||||
$options["quality"] = 75;
|
||||
|
||||
imagejpeg($dst, '', $options["quality"]);
|
||||
break;
|
||||
|
||||
case "png":
|
||||
default:
|
||||
imagepng($dst);
|
||||
break;
|
||||
}
|
||||
|
||||
$image = ob_get_clean();
|
||||
|
||||
if ( $this->_aa_factor != 1 )
|
||||
imagedestroy($dst);
|
||||
|
||||
return $image;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
183
application/helpers/dompdf/include/image_cache.cls.php
Executable file
183
application/helpers/dompdf/include/image_cache.cls.php
Executable file
@@ -0,0 +1,183 @@
|
||||
<?php
|
||||
/**
|
||||
* @package dompdf
|
||||
* @link http://dompdf.github.com/
|
||||
* @author Benj Carson <benjcarson@digitaljunkies.ca>
|
||||
* @author Helmut Tischer <htischer@weihenstephan.org>
|
||||
* @author Fabien Ménager <fabien.menager@gmail.com>
|
||||
* @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
|
||||
*/
|
||||
|
||||
/**
|
||||
* Static class that resolves image urls and downloads and caches
|
||||
* remote images if required.
|
||||
*
|
||||
* @access private
|
||||
* @package dompdf
|
||||
*/
|
||||
class Image_Cache {
|
||||
|
||||
/**
|
||||
* Array of downloaded images. Cached so that identical images are
|
||||
* not needlessly downloaded.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
static protected $_cache = array();
|
||||
|
||||
/**
|
||||
* The url to the "broken image" used when images can't be loade
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public static $broken_image;
|
||||
|
||||
/**
|
||||
* Resolve and fetch an image for use.
|
||||
*
|
||||
* @param string $url The url of the image
|
||||
* @param string $protocol Default protocol if none specified in $url
|
||||
* @param string $host Default host if none specified in $url
|
||||
* @param string $base_path Default path if none specified in $url
|
||||
* @param DOMPDF $dompdf The DOMPDF instance
|
||||
*
|
||||
* @throws DOMPDF_Image_Exception
|
||||
* @return array An array with two elements: The local path to the image and the image extension
|
||||
*/
|
||||
static function resolve_url($url, $protocol, $host, $base_path, DOMPDF $dompdf) {
|
||||
$parsed_url = explode_url($url);
|
||||
$message = null;
|
||||
|
||||
$remote = ($protocol && $protocol !== "file://") || ($parsed_url['protocol'] != "");
|
||||
|
||||
$data_uri = strpos($parsed_url['protocol'], "data:") === 0;
|
||||
$full_url = null;
|
||||
$enable_remote = $dompdf->get_option("enable_remote");
|
||||
|
||||
try {
|
||||
|
||||
// Remote not allowed and is not DataURI
|
||||
if ( !$enable_remote && $remote && !$data_uri ) {
|
||||
throw new DOMPDF_Image_Exception("DOMPDF_ENABLE_REMOTE is set to FALSE");
|
||||
}
|
||||
|
||||
// Remote allowed or DataURI
|
||||
else if ( $enable_remote && $remote || $data_uri ) {
|
||||
// Download remote files to a temporary directory
|
||||
$full_url = build_url($protocol, $host, $base_path, $url);
|
||||
|
||||
// From cache
|
||||
if ( isset(self::$_cache[$full_url]) ) {
|
||||
$resolved_url = self::$_cache[$full_url];
|
||||
}
|
||||
|
||||
// From remote
|
||||
else {
|
||||
$tmp_dir = $dompdf->get_option("temp_dir");
|
||||
$resolved_url = tempnam($tmp_dir, "ca_dompdf_img_");
|
||||
$image = "";
|
||||
|
||||
if ($data_uri) {
|
||||
if ($parsed_data_uri = parse_data_uri($url)) {
|
||||
$image = $parsed_data_uri['data'];
|
||||
}
|
||||
}
|
||||
else {
|
||||
set_error_handler("record_warnings");
|
||||
$image = file_get_contents($full_url);
|
||||
restore_error_handler();
|
||||
}
|
||||
|
||||
// Image not found or invalid
|
||||
if ( strlen($image) == 0 ) {
|
||||
$msg = ($data_uri ? "Data-URI could not be parsed" : "Image not found");
|
||||
throw new DOMPDF_Image_Exception($msg);
|
||||
}
|
||||
|
||||
// Image found, put in cache and process
|
||||
else {
|
||||
//e.g. fetch.php?media=url.jpg&cache=1
|
||||
//- Image file name might be one of the dynamic parts of the url, don't strip off!
|
||||
//- a remote url does not need to have a file extension at all
|
||||
//- local cached file does not have a matching file extension
|
||||
//Therefore get image type from the content
|
||||
file_put_contents($resolved_url, $image);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Not remote, local image
|
||||
else {
|
||||
$resolved_url = build_url($protocol, $host, $base_path, $url);
|
||||
}
|
||||
|
||||
// Check if the local file is readable
|
||||
if ( !is_readable($resolved_url) || !filesize($resolved_url) ) {
|
||||
throw new DOMPDF_Image_Exception("Image not readable or empty");
|
||||
}
|
||||
|
||||
// Check is the file is an image
|
||||
else {
|
||||
list($width, $height, $type) = dompdf_getimagesize($resolved_url);
|
||||
|
||||
// Known image type
|
||||
if ( $width && $height && in_array($type, array(IMAGETYPE_GIF, IMAGETYPE_PNG, IMAGETYPE_JPEG, IMAGETYPE_BMP)) ) {
|
||||
//Don't put replacement image into cache - otherwise it will be deleted on cache cleanup.
|
||||
//Only execute on successful caching of remote image.
|
||||
if ( $enable_remote && $remote || $data_uri ) {
|
||||
self::$_cache[$full_url] = $resolved_url;
|
||||
}
|
||||
}
|
||||
|
||||
// Unknown image type
|
||||
else {
|
||||
throw new DOMPDF_Image_Exception("Image type unknown");
|
||||
}
|
||||
}
|
||||
}
|
||||
catch(DOMPDF_Image_Exception $e) {
|
||||
$resolved_url = self::$broken_image;
|
||||
$type = IMAGETYPE_PNG;
|
||||
$message = $e->getMessage()." \n $url";
|
||||
}
|
||||
|
||||
return array($resolved_url, $type, $message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unlink all cached images (i.e. temporary images either downloaded
|
||||
* or converted)
|
||||
*/
|
||||
static function clear() {
|
||||
if ( empty(self::$_cache) || DEBUGKEEPTEMP ) return;
|
||||
|
||||
foreach ( self::$_cache as $file ) {
|
||||
if (DEBUGPNG) print "[clear unlink $file]";
|
||||
unlink($file);
|
||||
}
|
||||
|
||||
self::$_cache = array();
|
||||
}
|
||||
|
||||
static function detect_type($file) {
|
||||
list(, , $type) = dompdf_getimagesize($file);
|
||||
return $type;
|
||||
}
|
||||
|
||||
static function type_to_ext($type) {
|
||||
$image_types = array(
|
||||
IMAGETYPE_GIF => "gif",
|
||||
IMAGETYPE_PNG => "png",
|
||||
IMAGETYPE_JPEG => "jpeg",
|
||||
IMAGETYPE_BMP => "bmp",
|
||||
);
|
||||
|
||||
return (isset($image_types[$type]) ? $image_types[$type] : null);
|
||||
}
|
||||
|
||||
static function is_broken($url) {
|
||||
return $url === self::$broken_image;
|
||||
}
|
||||
}
|
||||
|
||||
Image_Cache::$broken_image = DOMPDF_LIB_DIR . "/res/broken_image.png";
|
||||
80
application/helpers/dompdf/include/image_frame_decorator.cls.php
Executable file
80
application/helpers/dompdf/include/image_frame_decorator.cls.php
Executable file
@@ -0,0 +1,80 @@
|
||||
<?php
|
||||
/**
|
||||
* @package dompdf
|
||||
* @link http://dompdf.github.com/
|
||||
* @author Benj Carson <benjcarson@digitaljunkies.ca>
|
||||
* @author Fabien Ménager <fabien.menager@gmail.com>
|
||||
* @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
|
||||
*/
|
||||
|
||||
/**
|
||||
* Decorates frames for image layout and rendering
|
||||
*
|
||||
* @access private
|
||||
* @package dompdf
|
||||
*/
|
||||
class Image_Frame_Decorator extends Frame_Decorator {
|
||||
|
||||
/**
|
||||
* The path to the image file (note that remote images are
|
||||
* downloaded locally to DOMPDF_TEMP_DIR).
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $_image_url;
|
||||
|
||||
/**
|
||||
* The image's file error message
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $_image_msg;
|
||||
|
||||
/**
|
||||
* Class constructor
|
||||
*
|
||||
* @param Frame $frame the frame to decorate
|
||||
* @param DOMPDF $dompdf the document's dompdf object (required to resolve relative & remote urls)
|
||||
*/
|
||||
function __construct(Frame $frame, DOMPDF $dompdf) {
|
||||
parent::__construct($frame, $dompdf);
|
||||
$url = $frame->get_node()->getAttribute("src");
|
||||
|
||||
$debug_png = $dompdf->get_option("debug_png");
|
||||
if ($debug_png) print '[__construct '.$url.']';
|
||||
|
||||
list($this->_image_url, /*$type*/, $this->_image_msg) = Image_Cache::resolve_url(
|
||||
$url,
|
||||
$dompdf->get_protocol(),
|
||||
$dompdf->get_host(),
|
||||
$dompdf->get_base_path(),
|
||||
$dompdf
|
||||
);
|
||||
|
||||
if ( Image_Cache::is_broken($this->_image_url) &&
|
||||
$alt = $frame->get_node()->getAttribute("alt") ) {
|
||||
$style = $frame->get_style();
|
||||
$style->width = (4/3)*Font_Metrics::get_text_width($alt, $style->font_family, $style->font_size, $style->word_spacing);
|
||||
$style->height = Font_Metrics::get_font_height($style->font_family, $style->font_size);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the image's url
|
||||
*
|
||||
* @return string The url of this image
|
||||
*/
|
||||
function get_image_url() {
|
||||
return $this->_image_url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the image's error message
|
||||
*
|
||||
* @return string The image's error message
|
||||
*/
|
||||
function get_image_msg() {
|
||||
return $this->_image_msg;
|
||||
}
|
||||
|
||||
}
|
||||
186
application/helpers/dompdf/include/image_frame_reflower.cls.php
Executable file
186
application/helpers/dompdf/include/image_frame_reflower.cls.php
Executable file
@@ -0,0 +1,186 @@
|
||||
<?php
|
||||
/**
|
||||
* @package dompdf
|
||||
* @link http://dompdf.github.com/
|
||||
* @author Benj Carson <benjcarson@digitaljunkies.ca>
|
||||
* @author Fabien Ménager <fabien.menager@gmail.com>
|
||||
* @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
|
||||
*/
|
||||
|
||||
/**
|
||||
* Image reflower class
|
||||
*
|
||||
* @access private
|
||||
* @package dompdf
|
||||
*/
|
||||
class Image_Frame_Reflower extends Frame_Reflower {
|
||||
|
||||
function __construct(Image_Frame_Decorator $frame) {
|
||||
parent::__construct($frame);
|
||||
}
|
||||
|
||||
function reflow(Block_Frame_Decorator $block = null) {
|
||||
$this->_frame->position();
|
||||
|
||||
//FLOAT
|
||||
//$frame = $this->_frame;
|
||||
//$page = $frame->get_root();
|
||||
|
||||
//$enable_css_float = $this->get_dompdf()->get_option("enable_css_float");
|
||||
//if ($enable_css_float && $frame->get_style()->float !== "none" ) {
|
||||
// $page->add_floating_frame($this);
|
||||
//}
|
||||
// Set the frame's width
|
||||
$this->get_min_max_width();
|
||||
|
||||
if ( $block ) {
|
||||
$block->add_frame_to_line($this->_frame);
|
||||
}
|
||||
}
|
||||
|
||||
function get_min_max_width() {
|
||||
if (DEBUGPNG) {
|
||||
// Determine the image's size. Time consuming. Only when really needed?
|
||||
list($img_width, $img_height) = dompdf_getimagesize($this->_frame->get_image_url());
|
||||
print "get_min_max_width() ".
|
||||
$this->_frame->get_style()->width.' '.
|
||||
$this->_frame->get_style()->height.';'.
|
||||
$this->_frame->get_parent()->get_style()->width." ".
|
||||
$this->_frame->get_parent()->get_style()->height.";".
|
||||
$this->_frame->get_parent()->get_parent()->get_style()->width.' '.
|
||||
$this->_frame->get_parent()->get_parent()->get_style()->height.';'.
|
||||
$img_width. ' '.
|
||||
$img_height.'|' ;
|
||||
}
|
||||
|
||||
$style = $this->_frame->get_style();
|
||||
|
||||
$width_forced = true;
|
||||
$height_forced = true;
|
||||
|
||||
//own style auto or invalid value: use natural size in px
|
||||
//own style value: ignore suffix text including unit, use given number as px
|
||||
//own style %: walk up parent chain until found available space in pt; fill available space
|
||||
//
|
||||
//special ignored unit: e.g. 10ex: e treated as exponent; x ignored; 10e completely invalid ->like auto
|
||||
|
||||
$width = ($style->width > 0 ? $style->width : 0);
|
||||
if ( is_percent($width) ) {
|
||||
$t = 0.0;
|
||||
for ($f = $this->_frame->get_parent(); $f; $f = $f->get_parent()) {
|
||||
$f_style = $f->get_style();
|
||||
$t = $f_style->length_in_pt($f_style->width);
|
||||
if ($t != 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
$width = ((float)rtrim($width,"%") * $t)/100; //maybe 0
|
||||
} elseif ( !mb_strpos($width, 'pt') ) {
|
||||
// Don't set image original size if "%" branch was 0 or size not given.
|
||||
// Otherwise aspect changed on %/auto combination for width/height
|
||||
// Resample according to px per inch
|
||||
// See also List_Bullet_Image_Frame_Decorator::__construct
|
||||
$width = $style->length_in_pt($width);
|
||||
}
|
||||
|
||||
$height = ($style->height > 0 ? $style->height : 0);
|
||||
if ( is_percent($height) ) {
|
||||
$t = 0.0;
|
||||
for ($f = $this->_frame->get_parent(); $f; $f = $f->get_parent()) {
|
||||
$f_style = $f->get_style();
|
||||
$t = $f_style->length_in_pt($f_style->height);
|
||||
if ($t != 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
$height = ((float)rtrim($height,"%") * $t)/100; //maybe 0
|
||||
} elseif ( !mb_strpos($height, 'pt') ) {
|
||||
// Don't set image original size if "%" branch was 0 or size not given.
|
||||
// Otherwise aspect changed on %/auto combination for width/height
|
||||
// Resample according to px per inch
|
||||
// See also List_Bullet_Image_Frame_Decorator::__construct
|
||||
$height = $style->length_in_pt($height);
|
||||
}
|
||||
|
||||
if ($width == 0 || $height == 0) {
|
||||
// Determine the image's size. Time consuming. Only when really needed!
|
||||
list($img_width, $img_height) = dompdf_getimagesize($this->_frame->get_image_url());
|
||||
|
||||
// don't treat 0 as error. Can be downscaled or can be catched elsewhere if image not readable.
|
||||
// Resample according to px per inch
|
||||
// See also List_Bullet_Image_Frame_Decorator::__construct
|
||||
if ($width == 0 && $height == 0) {
|
||||
$dpi = $this->_frame->get_dompdf()->get_option("dpi");
|
||||
$width = (float)($img_width * 72) / $dpi;
|
||||
$height = (float)($img_height * 72) / $dpi;
|
||||
$width_forced = false;
|
||||
$height_forced = false;
|
||||
} elseif ($height == 0 && $width != 0) {
|
||||
$height_forced = false;
|
||||
$height = ($width / $img_width) * $img_height; //keep aspect ratio
|
||||
} elseif ($width == 0 && $height != 0) {
|
||||
$width_forced = false;
|
||||
$width = ($height / $img_height) * $img_width; //keep aspect ratio
|
||||
}
|
||||
}
|
||||
|
||||
// Handle min/max width/height
|
||||
if ( $style->min_width !== "none" ||
|
||||
$style->max_width !== "none" ||
|
||||
$style->min_height !== "none" ||
|
||||
$style->max_height !== "none" ) {
|
||||
|
||||
list(/*$x*/, /*$y*/, $w, $h) = $this->_frame->get_containing_block();
|
||||
|
||||
$min_width = $style->length_in_pt($style->min_width, $w);
|
||||
$max_width = $style->length_in_pt($style->max_width, $w);
|
||||
$min_height = $style->length_in_pt($style->min_height, $h);
|
||||
$max_height = $style->length_in_pt($style->max_height, $h);
|
||||
|
||||
if ( $max_width !== "none" && $width > $max_width ) {
|
||||
if ( !$height_forced ) {
|
||||
$height *= $max_width / $width;
|
||||
}
|
||||
|
||||
$width = $max_width;
|
||||
}
|
||||
|
||||
if ( $min_width !== "none" && $width < $min_width ) {
|
||||
if ( !$height_forced ) {
|
||||
$height *= $min_width / $width;
|
||||
}
|
||||
|
||||
$width = $min_width;
|
||||
}
|
||||
|
||||
if ( $max_height !== "none" && $height > $max_height ) {
|
||||
if ( !$width_forced ) {
|
||||
$width *= $max_height / $height;
|
||||
}
|
||||
|
||||
$height = $max_height;
|
||||
}
|
||||
|
||||
if ( $min_height !== "none" && $height < $min_height ) {
|
||||
if ( !$width_forced ) {
|
||||
$width *= $min_height / $height;
|
||||
}
|
||||
|
||||
$height = $min_height;
|
||||
}
|
||||
}
|
||||
|
||||
if (DEBUGPNG) print $width.' '.$height.';';
|
||||
|
||||
$style->width = $width . "pt";
|
||||
$style->height = $height . "pt";
|
||||
|
||||
$style->min_width = "none";
|
||||
$style->max_width = "none";
|
||||
$style->min_height = "none";
|
||||
$style->max_height = "none";
|
||||
|
||||
return array( $width, $width, "min" => $width, "max" => $width);
|
||||
|
||||
}
|
||||
}
|
||||
119
application/helpers/dompdf/include/image_renderer.cls.php
Executable file
119
application/helpers/dompdf/include/image_renderer.cls.php
Executable file
@@ -0,0 +1,119 @@
|
||||
<?php
|
||||
/**
|
||||
* @package dompdf
|
||||
* @link http://dompdf.github.com/
|
||||
* @author Benj Carson <benjcarson@digitaljunkies.ca>
|
||||
* @author Fabien Ménager <fabien.menager@gmail.com>
|
||||
* @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
|
||||
*/
|
||||
|
||||
/**
|
||||
* Image renderer
|
||||
*
|
||||
* @access private
|
||||
* @package dompdf
|
||||
*/
|
||||
class Image_Renderer extends Block_Renderer {
|
||||
|
||||
function render(Frame $frame) {
|
||||
// Render background & borders
|
||||
$style = $frame->get_style();
|
||||
$cb = $frame->get_containing_block();
|
||||
list($x, $y, $w, $h) = $frame->get_border_box();
|
||||
|
||||
$this->_set_opacity( $frame->get_opacity( $style->opacity ) );
|
||||
|
||||
list($tl, $tr, $br, $bl) = $style->get_computed_border_radius($w, $h);
|
||||
|
||||
$has_border_radius = $tl + $tr + $br + $bl > 0;
|
||||
|
||||
if ( $has_border_radius ) {
|
||||
$this->_canvas->clipping_roundrectangle( $x, $y, $w, $h, $tl, $tr, $br, $bl );
|
||||
}
|
||||
|
||||
if ( ($bg = $style->background_color) !== "transparent" ) {
|
||||
$this->_canvas->filled_rectangle($x, $y, $w, $h, $bg);
|
||||
}
|
||||
|
||||
if ( ($url = $style->background_image) && $url !== "none" ) {
|
||||
$this->_background_image($url, $x, $y, $w, $h, $style);
|
||||
}
|
||||
|
||||
if ( $has_border_radius ) {
|
||||
$this->_canvas->clipping_end();
|
||||
}
|
||||
|
||||
$this->_render_border($frame);
|
||||
$this->_render_outline($frame);
|
||||
|
||||
list($x, $y) = $frame->get_padding_box();
|
||||
|
||||
$x += $style->length_in_pt($style->padding_left, $cb["w"]);
|
||||
$y += $style->length_in_pt($style->padding_top, $cb["h"]);
|
||||
|
||||
$w = $style->length_in_pt($style->width, $cb["w"]);
|
||||
$h = $style->length_in_pt($style->height, $cb["h"]);
|
||||
|
||||
if ( $has_border_radius ) {
|
||||
list($wt, $wr, $wb, $wl) = array(
|
||||
$style->border_top_width,
|
||||
$style->border_right_width,
|
||||
$style->border_bottom_width,
|
||||
$style->border_left_width,
|
||||
);
|
||||
|
||||
// we have to get the "inner" radius
|
||||
if ( $tl > 0 ) {
|
||||
$tl -= ($wt + $wl) / 2;
|
||||
}
|
||||
if ( $tr > 0 ) {
|
||||
$tr -= ($wt + $wr) / 2;
|
||||
}
|
||||
if ( $br > 0 ) {
|
||||
$br -= ($wb + $wr) / 2;
|
||||
}
|
||||
if ( $bl > 0 ) {
|
||||
$bl -= ($wb + $wl) / 2;
|
||||
}
|
||||
|
||||
$this->_canvas->clipping_roundrectangle( $x, $y, $w, $h, $tl, $tr, $br, $bl );
|
||||
}
|
||||
|
||||
$src = $frame->get_image_url();
|
||||
$alt = null;
|
||||
|
||||
if ( Image_Cache::is_broken($src) &&
|
||||
$alt = $frame->get_node()->getAttribute("alt") ) {
|
||||
$font = $style->font_family;
|
||||
$size = $style->font_size;
|
||||
$spacing = $style->word_spacing;
|
||||
$this->_canvas->text($x, $y, $alt,
|
||||
$font, $size,
|
||||
$style->color, $spacing);
|
||||
}
|
||||
else {
|
||||
$this->_canvas->image( $src, $x, $y, $w, $h, $style->image_resolution);
|
||||
}
|
||||
|
||||
if ( $has_border_radius ) {
|
||||
$this->_canvas->clipping_end();
|
||||
}
|
||||
|
||||
if ( $msg = $frame->get_image_msg() ) {
|
||||
$parts = preg_split("/\s*\n\s*/", $msg);
|
||||
$height = 10;
|
||||
$_y = $alt ? $y+$h-count($parts)*$height : $y;
|
||||
|
||||
foreach($parts as $i => $_part) {
|
||||
$this->_canvas->text($x, $_y + $i*$height, $_part, "times", $height*0.8, array(0.5, 0.5, 0.5));
|
||||
}
|
||||
}
|
||||
|
||||
if (DEBUG_LAYOUT && DEBUG_LAYOUT_BLOCKS) {
|
||||
$this->_debug_layout($frame->get_border_box(), "blue");
|
||||
if (DEBUG_LAYOUT_PADDINGBOX) {
|
||||
$this->_debug_layout($frame->get_padding_box(), "blue", array(0.5, 0.5));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
74
application/helpers/dompdf/include/inline_frame_decorator.cls.php
Executable file
74
application/helpers/dompdf/include/inline_frame_decorator.cls.php
Executable file
@@ -0,0 +1,74 @@
|
||||
<?php
|
||||
/**
|
||||
* @package dompdf
|
||||
* @link http://dompdf.github.com/
|
||||
* @author Benj Carson <benjcarson@digitaljunkies.ca>
|
||||
* @author Helmut Tischer <htischer@weihenstephan.org>
|
||||
* @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
|
||||
*/
|
||||
|
||||
/**
|
||||
* Decorates frames for inline layout
|
||||
*
|
||||
* @access private
|
||||
* @package dompdf
|
||||
*/
|
||||
class Inline_Frame_Decorator extends Frame_Decorator {
|
||||
|
||||
function __construct(Frame $frame, DOMPDF $dompdf) { parent::__construct($frame, $dompdf); }
|
||||
|
||||
function split(Frame $frame = null, $force_pagebreak = false) {
|
||||
|
||||
if ( is_null($frame) ) {
|
||||
$this->get_parent()->split($this, $force_pagebreak);
|
||||
return;
|
||||
}
|
||||
|
||||
if ( $frame->get_parent() !== $this )
|
||||
throw new DOMPDF_Exception("Unable to split: frame is not a child of this one.");
|
||||
|
||||
$split = $this->copy( $this->_frame->get_node()->cloneNode() );
|
||||
$this->get_parent()->insert_child_after($split, $this);
|
||||
|
||||
// Unset the current node's right style properties
|
||||
$style = $this->_frame->get_style();
|
||||
$style->margin_right = 0;
|
||||
$style->padding_right = 0;
|
||||
$style->border_right_width = 0;
|
||||
|
||||
// Unset the split node's left style properties since we don't want them
|
||||
// to propagate
|
||||
$style = $split->get_style();
|
||||
$style->margin_left = 0;
|
||||
$style->padding_left = 0;
|
||||
$style->border_left_width = 0;
|
||||
|
||||
//On continuation of inline element on next line,
|
||||
//don't repeat non-vertically repeatble background images
|
||||
//See e.g. in testcase image_variants, long desriptions
|
||||
if ( ($url = $style->background_image) && $url !== "none"
|
||||
&& ($repeat = $style->background_repeat) && $repeat !== "repeat" && $repeat !== "repeat-y"
|
||||
) {
|
||||
$style->background_image = "none";
|
||||
}
|
||||
|
||||
// Add $frame and all following siblings to the new split node
|
||||
$iter = $frame;
|
||||
while ($iter) {
|
||||
$frame = $iter;
|
||||
$iter = $iter->get_next_sibling();
|
||||
$frame->reset();
|
||||
$split->append_child($frame);
|
||||
}
|
||||
|
||||
$page_breaks = array("always", "left", "right");
|
||||
$frame_style = $frame->get_style();
|
||||
if( $force_pagebreak ||
|
||||
in_array($frame_style->page_break_before, $page_breaks) ||
|
||||
in_array($frame_style->page_break_after, $page_breaks) ) {
|
||||
|
||||
$this->get_parent()->split($split, true);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
66
application/helpers/dompdf/include/inline_frame_reflower.cls.php
Executable file
66
application/helpers/dompdf/include/inline_frame_reflower.cls.php
Executable file
@@ -0,0 +1,66 @@
|
||||
<?php
|
||||
/**
|
||||
* @package dompdf
|
||||
* @link http://dompdf.github.com/
|
||||
* @author Benj Carson <benjcarson@digitaljunkies.ca>
|
||||
* @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
|
||||
*/
|
||||
|
||||
/**
|
||||
* Reflows inline frames
|
||||
*
|
||||
* @access private
|
||||
* @package dompdf
|
||||
*/
|
||||
class Inline_Frame_Reflower extends Frame_Reflower {
|
||||
|
||||
function __construct(Frame $frame) { parent::__construct($frame); }
|
||||
|
||||
//........................................................................
|
||||
|
||||
function reflow(Block_Frame_Decorator $block = null) {
|
||||
$frame = $this->_frame;
|
||||
|
||||
// Check if a page break is forced
|
||||
$page = $frame->get_root();
|
||||
$page->check_forced_page_break($frame);
|
||||
|
||||
if ( $page->is_full() )
|
||||
return;
|
||||
|
||||
$style = $frame->get_style();
|
||||
|
||||
// Generated content
|
||||
$this->_set_content();
|
||||
|
||||
$frame->position();
|
||||
|
||||
$cb = $frame->get_containing_block();
|
||||
|
||||
// Add our margin, padding & border to the first and last children
|
||||
if ( ($f = $frame->get_first_child()) && $f instanceof Text_Frame_Decorator ) {
|
||||
$f_style = $f->get_style();
|
||||
$f_style->margin_left = $style->margin_left;
|
||||
$f_style->padding_left = $style->padding_left;
|
||||
$f_style->border_left = $style->border_left;
|
||||
}
|
||||
|
||||
if ( ($l = $frame->get_last_child()) && $l instanceof Text_Frame_Decorator ) {
|
||||
$l_style = $l->get_style();
|
||||
$l_style->margin_right = $style->margin_right;
|
||||
$l_style->padding_right = $style->padding_right;
|
||||
$l_style->border_right = $style->border_right;
|
||||
}
|
||||
|
||||
if ( $block ) {
|
||||
$block->add_frame_to_line($this->_frame);
|
||||
}
|
||||
|
||||
// Set the containing blocks and reflow each child. The containing
|
||||
// block is not changed by line boxes.
|
||||
foreach ( $frame->get_children() as $child ) {
|
||||
$child->set_containing_block($cb);
|
||||
$child->reflow($block);
|
||||
}
|
||||
}
|
||||
}
|
||||
70
application/helpers/dompdf/include/inline_positioner.cls.php
Executable file
70
application/helpers/dompdf/include/inline_positioner.cls.php
Executable file
@@ -0,0 +1,70 @@
|
||||
<?php
|
||||
/**
|
||||
* @package dompdf
|
||||
* @link http://dompdf.github.com/
|
||||
* @author Benj Carson <benjcarson@digitaljunkies.ca>
|
||||
* @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
|
||||
*/
|
||||
|
||||
/**
|
||||
* Positions inline frames
|
||||
*
|
||||
* @access private
|
||||
* @package dompdf
|
||||
*/
|
||||
class Inline_Positioner extends Positioner {
|
||||
|
||||
function __construct(Frame_Decorator $frame) { parent::__construct($frame); }
|
||||
|
||||
//........................................................................
|
||||
|
||||
function position() {
|
||||
/**
|
||||
* Find our nearest block level parent and access its lines property.
|
||||
* @var Block_Frame_Decorator
|
||||
*/
|
||||
$p = $this->_frame->find_block_parent();
|
||||
|
||||
// Debugging code:
|
||||
|
||||
// pre_r("\nPositioning:");
|
||||
// pre_r("Me: " . $this->_frame->get_node()->nodeName . " (" . spl_object_hash($this->_frame->get_node()) . ")");
|
||||
// pre_r("Parent: " . $p->get_node()->nodeName . " (" . spl_object_hash($p->get_node()) . ")");
|
||||
|
||||
// End debugging
|
||||
|
||||
if ( !$p )
|
||||
throw new DOMPDF_Exception("No block-level parent found. Not good.");
|
||||
|
||||
$f = $this->_frame;
|
||||
|
||||
$cb = $f->get_containing_block();
|
||||
$line = $p->get_current_line_box();
|
||||
|
||||
// Skip the page break if in a fixed position element
|
||||
$is_fixed = false;
|
||||
while($f = $f->get_parent()) {
|
||||
if($f->get_style()->position === "fixed") {
|
||||
$is_fixed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$f = $this->_frame;
|
||||
|
||||
if ( !$is_fixed && $f->get_parent() &&
|
||||
$f->get_parent() instanceof Inline_Frame_Decorator &&
|
||||
$f->is_text_node() ) {
|
||||
|
||||
$min_max = $f->get_reflower()->get_min_max_width();
|
||||
|
||||
// If the frame doesn't fit in the current line, a line break occurs
|
||||
if ( $min_max["min"] > ($cb["w"] - $line->left - $line->w - $line->right) ) {
|
||||
$p->add_line();
|
||||
}
|
||||
}
|
||||
|
||||
$f->set_position($cb["x"] + $line->w, $line->y);
|
||||
|
||||
}
|
||||
}
|
||||
190
application/helpers/dompdf/include/inline_renderer.cls.php
Executable file
190
application/helpers/dompdf/include/inline_renderer.cls.php
Executable file
@@ -0,0 +1,190 @@
|
||||
<?php
|
||||
/**
|
||||
* @package dompdf
|
||||
* @link http://dompdf.github.com/
|
||||
* @author Benj Carson <benjcarson@digitaljunkies.ca>
|
||||
* @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
|
||||
*/
|
||||
|
||||
/**
|
||||
* Renders inline frames
|
||||
*
|
||||
* @access private
|
||||
* @package dompdf
|
||||
*/
|
||||
class Inline_Renderer extends Abstract_Renderer {
|
||||
|
||||
//........................................................................
|
||||
|
||||
function render(Frame $frame) {
|
||||
$style = $frame->get_style();
|
||||
|
||||
if ( !$frame->get_first_child() )
|
||||
return; // No children, no service
|
||||
|
||||
// Draw the left border if applicable
|
||||
$bp = $style->get_border_properties();
|
||||
$widths = array($style->length_in_pt($bp["top"]["width"]),
|
||||
$style->length_in_pt($bp["right"]["width"]),
|
||||
$style->length_in_pt($bp["bottom"]["width"]),
|
||||
$style->length_in_pt($bp["left"]["width"]));
|
||||
|
||||
// Draw the background & border behind each child. To do this we need
|
||||
// to figure out just how much space each child takes:
|
||||
list($x, $y) = $frame->get_first_child()->get_position();
|
||||
$w = null;
|
||||
$h = 0;
|
||||
// $x += $widths[3];
|
||||
// $y += $widths[0];
|
||||
|
||||
$this->_set_opacity( $frame->get_opacity( $style->opacity ) );
|
||||
|
||||
$first_row = true;
|
||||
|
||||
foreach ($frame->get_children() as $child) {
|
||||
list($child_x, $child_y, $child_w, $child_h) = $child->get_padding_box();
|
||||
|
||||
if ( !is_null($w) && $child_x < $x + $w ) {
|
||||
//This branch seems to be supposed to being called on the first part
|
||||
//of an inline html element, and the part after the if clause for the
|
||||
//parts after a line break.
|
||||
//But because $w initially mostly is 0, and gets updated only on the next
|
||||
//round, this seem to be never executed and the common close always.
|
||||
|
||||
// The next child is on another line. Draw the background &
|
||||
// borders on this line.
|
||||
|
||||
// Background:
|
||||
if ( ($bg = $style->background_color) !== "transparent" )
|
||||
$this->_canvas->filled_rectangle( $x, $y, $w, $h, $bg);
|
||||
|
||||
if ( ($url = $style->background_image) && $url !== "none" ) {
|
||||
$this->_background_image($url, $x, $y, $w, $h, $style);
|
||||
}
|
||||
|
||||
// If this is the first row, draw the left border
|
||||
if ( $first_row ) {
|
||||
|
||||
if ( $bp["left"]["style"] !== "none" && $bp["left"]["color"] !== "transparent" && $bp["left"]["width"] > 0 ) {
|
||||
$method = "_border_" . $bp["left"]["style"];
|
||||
$this->$method($x, $y, $h + $widths[0] + $widths[2], $bp["left"]["color"], $widths, "left");
|
||||
}
|
||||
$first_row = false;
|
||||
}
|
||||
|
||||
// Draw the top & bottom borders
|
||||
if ( $bp["top"]["style"] !== "none" && $bp["top"]["color"] !== "transparent" && $bp["top"]["width"] > 0 ) {
|
||||
$method = "_border_" . $bp["top"]["style"];
|
||||
$this->$method($x, $y, $w + $widths[1] + $widths[3], $bp["top"]["color"], $widths, "top");
|
||||
}
|
||||
|
||||
if ( $bp["bottom"]["style"] !== "none" && $bp["bottom"]["color"] !== "transparent" && $bp["bottom"]["width"] > 0 ) {
|
||||
$method = "_border_" . $bp["bottom"]["style"];
|
||||
$this->$method($x, $y + $h + $widths[0] + $widths[2], $w + $widths[1] + $widths[3], $bp["bottom"]["color"], $widths, "bottom");
|
||||
}
|
||||
|
||||
// Handle anchors & links
|
||||
$link_node = null;
|
||||
if ( $frame->get_node()->nodeName === "a" ) {
|
||||
$link_node = $frame->get_node();
|
||||
}
|
||||
else if ( $frame->get_parent()->get_node()->nodeName === "a" ){
|
||||
$link_node = $frame->get_parent()->get_node();
|
||||
}
|
||||
|
||||
if ( $link_node && $href = $link_node->getAttribute("href") ) {
|
||||
$this->_canvas->add_link($href, $x, $y, $w, $h);
|
||||
}
|
||||
|
||||
$x = $child_x;
|
||||
$y = $child_y;
|
||||
$w = $child_w;
|
||||
$h = $child_h;
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( is_null($w) )
|
||||
$w = $child_w;
|
||||
else
|
||||
$w += $child_w;
|
||||
|
||||
$h = max($h, $child_h);
|
||||
|
||||
if (DEBUG_LAYOUT && DEBUG_LAYOUT_INLINE) {
|
||||
$this->_debug_layout($child->get_border_box(), "blue");
|
||||
if (DEBUG_LAYOUT_PADDINGBOX) {
|
||||
$this->_debug_layout($child->get_padding_box(), "blue", array(0.5, 0.5));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Handle the last child
|
||||
if ( ($bg = $style->background_color) !== "transparent" )
|
||||
$this->_canvas->filled_rectangle( $x + $widths[3], $y + $widths[0], $w, $h, $bg);
|
||||
|
||||
//On continuation lines (after line break) of inline elements, the style got copied.
|
||||
//But a non repeatable background image should not be repeated on the next line.
|
||||
//But removing the background image above has never an effect, and removing it below
|
||||
//removes it always, even on the initial line.
|
||||
//Need to handle it elsewhere, e.g. on certain ...clone()... usages.
|
||||
// Repeat not given: default is Style::__construct
|
||||
// ... && (!($repeat = $style->background_repeat) || $repeat === "repeat" ...
|
||||
//different position? $this->_background_image($url, $x, $y, $w, $h, $style);
|
||||
if ( ($url = $style->background_image) && $url !== "none" )
|
||||
$this->_background_image($url, $x + $widths[3], $y + $widths[0], $w, $h, $style);
|
||||
|
||||
// Add the border widths
|
||||
$w += $widths[1] + $widths[3];
|
||||
$h += $widths[0] + $widths[2];
|
||||
|
||||
// make sure the border and background start inside the left margin
|
||||
$left_margin = $style->length_in_pt($style->margin_left);
|
||||
$x += $left_margin;
|
||||
|
||||
// If this is the first row, draw the left border too
|
||||
if ( $first_row && $bp["left"]["style"] !== "none" && $bp["left"]["color"] !== "transparent" && $widths[3] > 0 ) {
|
||||
$method = "_border_" . $bp["left"]["style"];
|
||||
$this->$method($x, $y, $h, $bp["left"]["color"], $widths, "left");
|
||||
}
|
||||
|
||||
// Draw the top & bottom borders
|
||||
if ( $bp["top"]["style"] !== "none" && $bp["top"]["color"] !== "transparent" && $widths[0] > 0 ) {
|
||||
$method = "_border_" . $bp["top"]["style"];
|
||||
$this->$method($x, $y, $w, $bp["top"]["color"], $widths, "top");
|
||||
}
|
||||
|
||||
if ( $bp["bottom"]["style"] !== "none" && $bp["bottom"]["color"] !== "transparent" && $widths[2] > 0 ) {
|
||||
$method = "_border_" . $bp["bottom"]["style"];
|
||||
$this->$method($x, $y + $h, $w, $bp["bottom"]["color"], $widths, "bottom");
|
||||
}
|
||||
|
||||
// pre_var_dump(get_class($frame->get_next_sibling()));
|
||||
// $last_row = get_class($frame->get_next_sibling()) !== 'Inline_Frame_Decorator';
|
||||
// Draw the right border if this is the last row
|
||||
if ( $bp["right"]["style"] !== "none" && $bp["right"]["color"] !== "transparent" && $widths[1] > 0 ) {
|
||||
$method = "_border_" . $bp["right"]["style"];
|
||||
$this->$method($x + $w, $y, $h, $bp["right"]["color"], $widths, "right");
|
||||
}
|
||||
|
||||
// Only two levels of links frames
|
||||
$link_node = null;
|
||||
if ( $frame->get_node()->nodeName === "a" ) {
|
||||
$link_node = $frame->get_node();
|
||||
|
||||
if ( ($name = $link_node->getAttribute("name")) || ($name = $link_node->getAttribute("id")) ) {
|
||||
$this->_canvas->add_named_dest($name);
|
||||
}
|
||||
}
|
||||
|
||||
if ( $frame->get_parent() && $frame->get_parent()->get_node()->nodeName === "a" ){
|
||||
$link_node = $frame->get_parent()->get_node();
|
||||
}
|
||||
|
||||
// Handle anchors & links
|
||||
if ( $link_node ) {
|
||||
if ( $href = $link_node->getAttribute("href") )
|
||||
$this->_canvas->add_link($href, $x, $y, $w, $h);
|
||||
}
|
||||
}
|
||||
}
|
||||
37
application/helpers/dompdf/include/javascript_embedder.cls.php
Executable file
37
application/helpers/dompdf/include/javascript_embedder.cls.php
Executable file
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
/**
|
||||
* @package dompdf
|
||||
* @link http://dompdf.github.com/
|
||||
* @author Fabien Ménager <fabien.menager@gmail.com>
|
||||
* @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
|
||||
*/
|
||||
|
||||
/**
|
||||
* Embeds Javascript into the PDF document
|
||||
*
|
||||
* @access private
|
||||
* @package dompdf
|
||||
*/
|
||||
class Javascript_Embedder {
|
||||
|
||||
/**
|
||||
* @var DOMPDF
|
||||
*/
|
||||
protected $_dompdf;
|
||||
|
||||
function __construct(DOMPDF $dompdf) {
|
||||
$this->_dompdf = $dompdf;
|
||||
}
|
||||
|
||||
function insert($script) {
|
||||
$this->_dompdf->get_canvas()->javascript($script);
|
||||
}
|
||||
|
||||
function render(Frame $frame) {
|
||||
if ( !$this->_dompdf->get_option("enable_javascript") ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->insert($frame->get_node()->nodeValue);
|
||||
}
|
||||
}
|
||||
252
application/helpers/dompdf/include/line_box.cls.php
Executable file
252
application/helpers/dompdf/include/line_box.cls.php
Executable file
@@ -0,0 +1,252 @@
|
||||
<?php
|
||||
/**
|
||||
* @package dompdf
|
||||
* @link http://dompdf.github.com/
|
||||
* @author Fabien Ménager <fabien.menager@gmail.com>
|
||||
* @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
|
||||
*/
|
||||
|
||||
/**
|
||||
* The line box class
|
||||
*
|
||||
* This class represents a line box
|
||||
* http://www.w3.org/TR/CSS2/visuren.html#line-box
|
||||
*
|
||||
* @access protected
|
||||
* @package dompdf
|
||||
*/
|
||||
class Line_Box {
|
||||
|
||||
/**
|
||||
* @var Block_Frame_Decorator
|
||||
*/
|
||||
protected $_block_frame;
|
||||
|
||||
/**
|
||||
* @var Frame[]
|
||||
*/
|
||||
protected $_frames = array();
|
||||
|
||||
/**
|
||||
* @var integer
|
||||
*/
|
||||
public $wc = 0;
|
||||
|
||||
/**
|
||||
* @var float
|
||||
*/
|
||||
public $y = null;
|
||||
|
||||
/**
|
||||
* @var float
|
||||
*/
|
||||
public $w = 0.0;
|
||||
|
||||
/**
|
||||
* @var float
|
||||
*/
|
||||
public $h = 0.0;
|
||||
|
||||
/**
|
||||
* @var float
|
||||
*/
|
||||
public $left = 0.0;
|
||||
|
||||
/**
|
||||
* @var float
|
||||
*/
|
||||
public $right = 0.0;
|
||||
|
||||
/**
|
||||
* @var Frame
|
||||
*/
|
||||
public $tallest_frame = null;
|
||||
|
||||
/**
|
||||
* @var bool[]
|
||||
*/
|
||||
public $floating_blocks = array();
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
public $br = false;
|
||||
|
||||
/**
|
||||
* Class constructor
|
||||
*
|
||||
* @param Block_Frame_Decorator $frame the Block_Frame_Decorator containing this line
|
||||
*/
|
||||
function __construct(Block_Frame_Decorator $frame, $y = 0) {
|
||||
$this->_block_frame = $frame;
|
||||
$this->_frames = array();
|
||||
$this->y = $y;
|
||||
|
||||
$this->get_float_offsets();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the floating elements inside the first floating parent
|
||||
*
|
||||
* @param Page_Frame_Decorator $root
|
||||
*
|
||||
* @return Frame[]
|
||||
*/
|
||||
function get_floats_inside(Page_Frame_Decorator $root) {
|
||||
$floating_frames = $root->get_floating_frames();
|
||||
|
||||
if ( count($floating_frames) == 0 ) {
|
||||
return $floating_frames;
|
||||
}
|
||||
|
||||
// Find nearest floating element
|
||||
$p = $this->_block_frame;
|
||||
while( $p->get_style()->float === "none" ) {
|
||||
$parent = $p->get_parent();
|
||||
|
||||
if ( !$parent ) {
|
||||
break;
|
||||
}
|
||||
|
||||
$p = $parent;
|
||||
}
|
||||
|
||||
if ( $p == $root ) {
|
||||
return $floating_frames;
|
||||
}
|
||||
|
||||
$parent = $p;
|
||||
|
||||
$childs = array();
|
||||
|
||||
foreach ($floating_frames as $_floating) {
|
||||
$p = $_floating->get_parent();
|
||||
|
||||
while (($p = $p->get_parent()) && $p !== $parent);
|
||||
|
||||
if ( $p ) {
|
||||
$childs[] = $p;
|
||||
}
|
||||
}
|
||||
|
||||
return $childs;
|
||||
}
|
||||
|
||||
function get_float_offsets() {
|
||||
$enable_css_float = $this->_block_frame->get_dompdf()->get_option("enable_css_float");
|
||||
if ( !$enable_css_float ) {
|
||||
return;
|
||||
}
|
||||
|
||||
static $anti_infinite_loop = 500; // FIXME smelly hack
|
||||
|
||||
$reflower = $this->_block_frame->get_reflower();
|
||||
|
||||
if ( !$reflower ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$cb_w = null;
|
||||
|
||||
$block = $this->_block_frame;
|
||||
$root = $block->get_root();
|
||||
|
||||
if ( !$root ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$floating_frames = $this->get_floats_inside($root);
|
||||
|
||||
foreach ( $floating_frames as $child_key => $floating_frame ) {
|
||||
$id = $floating_frame->get_id();
|
||||
|
||||
if ( isset($this->floating_blocks[$id]) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$floating_style = $floating_frame->get_style();
|
||||
$float = $floating_style->float;
|
||||
|
||||
$floating_width = $floating_frame->get_margin_width();
|
||||
|
||||
if (!$cb_w) {
|
||||
$cb_w = $floating_frame->get_containing_block("w");
|
||||
}
|
||||
|
||||
$line_w = $this->get_width();
|
||||
|
||||
if ( !$floating_frame->_float_next_line && ($cb_w <= $line_w + $floating_width) && ($cb_w > $line_w) ) {
|
||||
$floating_frame->_float_next_line = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
// If the child is still shifted by the floating element
|
||||
if ( $anti_infinite_loop-- > 0 &&
|
||||
$floating_frame->get_position("y") + $floating_frame->get_margin_height() > $this->y &&
|
||||
$block->get_position("x") + $block->get_margin_width() > $floating_frame->get_position("x")
|
||||
) {
|
||||
if ( $float === "left" )
|
||||
$this->left += $floating_width;
|
||||
else
|
||||
$this->right += $floating_width;
|
||||
|
||||
$this->floating_blocks[$id] = true;
|
||||
}
|
||||
|
||||
// else, the floating element won't shift anymore
|
||||
else {
|
||||
$root->remove_floating_frame($child_key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return float
|
||||
*/
|
||||
function get_width(){
|
||||
return $this->left + $this->w + $this->right;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Block_Frame_Decorator
|
||||
*/
|
||||
function get_block_frame() {
|
||||
return $this->_block_frame;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Frame[]
|
||||
*/
|
||||
function &get_frames() {
|
||||
return $this->_frames;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Frame $frame
|
||||
*/
|
||||
function add_frame(Frame $frame) {
|
||||
$this->_frames[] = $frame;
|
||||
}
|
||||
|
||||
function __toString(){
|
||||
$props = array("wc", "y", "w", "h", "left", "right", "br");
|
||||
$s = "";
|
||||
foreach($props as $prop) {
|
||||
$s .= "$prop: ".$this->$prop."\n";
|
||||
}
|
||||
$s .= count($this->_frames)." frames\n";
|
||||
return $s;
|
||||
}
|
||||
/*function __get($prop) {
|
||||
if (!isset($this->{"_$prop"})) return;
|
||||
return $this->{"_$prop"};
|
||||
}*/
|
||||
}
|
||||
|
||||
/*
|
||||
class LineBoxList implements Iterator {
|
||||
private $_p = 0;
|
||||
private $_lines = array();
|
||||
|
||||
}
|
||||
*/
|
||||
65
application/helpers/dompdf/include/list_bullet_frame_decorator.cls.php
Executable file
65
application/helpers/dompdf/include/list_bullet_frame_decorator.cls.php
Executable file
@@ -0,0 +1,65 @@
|
||||
<?php
|
||||
/**
|
||||
* @package dompdf
|
||||
* @link http://dompdf.github.com/
|
||||
* @author Benj Carson <benjcarson@digitaljunkies.ca>
|
||||
* @author Helmut Tischer <htischer@weihenstephan.org>
|
||||
* @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
|
||||
*/
|
||||
|
||||
/**
|
||||
* Decorates frames for list bullet rendering
|
||||
*
|
||||
* @access private
|
||||
* @package dompdf
|
||||
*/
|
||||
class List_Bullet_Frame_Decorator extends Frame_Decorator {
|
||||
|
||||
const BULLET_PADDING = 1; // Distance from bullet to text in pt
|
||||
// As fraction of font size (including descent). See also DECO_THICKNESS.
|
||||
const BULLET_THICKNESS = 0.04; // Thickness of bullet outline. Screen: 0.08, print: better less, e.g. 0.04
|
||||
const BULLET_DESCENT = 0.3; //descent of font below baseline. Todo: Guessed for now.
|
||||
const BULLET_SIZE = 0.35; // bullet diameter. For now 0.5 of font_size without descent.
|
||||
|
||||
static $BULLET_TYPES = array("disc", "circle", "square");
|
||||
|
||||
//........................................................................
|
||||
|
||||
function __construct(Frame $frame, DOMPDF $dompdf) {
|
||||
parent::__construct($frame, $dompdf);
|
||||
}
|
||||
|
||||
function get_margin_width() {
|
||||
$style = $this->_frame->get_style();
|
||||
|
||||
// Small hack to prevent extra indenting of list text on list_style_position === "inside"
|
||||
// and on suppressed bullet
|
||||
if ( $style->list_style_position === "outside" ||
|
||||
$style->list_style_type === "none" ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return $style->get_font_size() * self::BULLET_SIZE + 2 * self::BULLET_PADDING;
|
||||
}
|
||||
|
||||
//hits only on "inset" lists items, to increase height of box
|
||||
function get_margin_height() {
|
||||
$style = $this->_frame->get_style();
|
||||
|
||||
if ( $style->list_style_type === "none" ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return $style->get_font_size() * self::BULLET_SIZE + 2 * self::BULLET_PADDING;
|
||||
}
|
||||
|
||||
function get_width() {
|
||||
return $this->get_margin_height();
|
||||
}
|
||||
|
||||
function get_height() {
|
||||
return $this->get_margin_height();
|
||||
}
|
||||
|
||||
//........................................................................
|
||||
}
|
||||
33
application/helpers/dompdf/include/list_bullet_frame_reflower.cls.php
Executable file
33
application/helpers/dompdf/include/list_bullet_frame_reflower.cls.php
Executable file
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
/**
|
||||
* @package dompdf
|
||||
* @link http://dompdf.github.com/
|
||||
* @author Benj Carson <benjcarson@digitaljunkies.ca>
|
||||
* @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
|
||||
*/
|
||||
|
||||
/**
|
||||
* Reflows list bullets
|
||||
*
|
||||
* @access private
|
||||
* @package dompdf
|
||||
*/
|
||||
class List_Bullet_Frame_Reflower extends Frame_Reflower {
|
||||
|
||||
function __construct(Frame_Decorator $frame) { parent::__construct($frame); }
|
||||
|
||||
//........................................................................
|
||||
|
||||
function reflow(Block_Frame_Decorator $block = null) {
|
||||
$style = $this->_frame->get_style();
|
||||
|
||||
$style->width = $this->_frame->get_width();
|
||||
$this->_frame->position();
|
||||
|
||||
if ( $style->list_style_position === "inside" ) {
|
||||
$p = $this->_frame->find_block_parent();
|
||||
$p->add_frame_to_line($this->_frame);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
143
application/helpers/dompdf/include/list_bullet_image_frame_decorator.cls.php
Executable file
143
application/helpers/dompdf/include/list_bullet_image_frame_decorator.cls.php
Executable file
@@ -0,0 +1,143 @@
|
||||
<?php
|
||||
/**
|
||||
* @package dompdf
|
||||
* @link http://dompdf.github.com/
|
||||
* @author Benj Carson <benjcarson@digitaljunkies.ca>
|
||||
* @author Helmut Tischer <htischer@weihenstephan.org>
|
||||
* @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
|
||||
*/
|
||||
|
||||
/**
|
||||
* Decorates frames for list bullets with custom images
|
||||
*
|
||||
* @access private
|
||||
* @package dompdf
|
||||
*/
|
||||
class List_Bullet_Image_Frame_Decorator extends Frame_Decorator {
|
||||
|
||||
/**
|
||||
* The underlying image frame
|
||||
*
|
||||
* @var Image_Frame_Decorator
|
||||
*/
|
||||
protected $_img;
|
||||
|
||||
/**
|
||||
* The image's width in pixels
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $_width;
|
||||
|
||||
/**
|
||||
* The image's height in pixels
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $_height;
|
||||
|
||||
/**
|
||||
* Class constructor
|
||||
*
|
||||
* @param Frame $frame the bullet frame to decorate
|
||||
* @param DOMPDF $dompdf the document's dompdf object
|
||||
*/
|
||||
function __construct(Frame $frame, DOMPDF $dompdf) {
|
||||
$style = $frame->get_style();
|
||||
$url = $style->list_style_image;
|
||||
$frame->get_node()->setAttribute("src", $url);
|
||||
$this->_img = new Image_Frame_Decorator($frame, $dompdf);
|
||||
parent::__construct($this->_img, $dompdf);
|
||||
list($width, $height) = dompdf_getimagesize($this->_img->get_image_url());
|
||||
|
||||
// Resample the bullet image to be consistent with 'auto' sized images
|
||||
// See also Image_Frame_Reflower::get_min_max_width
|
||||
// Tested php ver: value measured in px, suffix "px" not in value: rtrim unnecessary.
|
||||
$dpi = $this->_dompdf->get_option("dpi");
|
||||
$this->_width = ((float)rtrim($width, "px") * 72) / $dpi;
|
||||
$this->_height = ((float)rtrim($height, "px") * 72) / $dpi;
|
||||
|
||||
//If an image is taller as the containing block/box, the box should be extended.
|
||||
//Neighbour elements are overwriting the overlapping image areas.
|
||||
//Todo: Where can the box size be extended?
|
||||
//Code below has no effect.
|
||||
//See block_frame_reflower _calculate_restricted_height
|
||||
//See generated_frame_reflower, Dompdf:render() "list-item", "-dompdf-list-bullet"S.
|
||||
//Leave for now
|
||||
//if ($style->min_height < $this->_height ) {
|
||||
// $style->min_height = $this->_height;
|
||||
//}
|
||||
//$style->height = "auto";
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the bullet's width
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
function get_width() {
|
||||
//ignore image width, use same width as on predefined bullet List_Bullet_Frame_Decorator
|
||||
//for proper alignment of bullet image and text. Allow image to not fitting on left border.
|
||||
//This controls the distance between bullet image and text
|
||||
//return $this->_width;
|
||||
return $this->_frame->get_style()->get_font_size()*List_Bullet_Frame_Decorator::BULLET_SIZE +
|
||||
2 * List_Bullet_Frame_Decorator::BULLET_PADDING;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the bullet's height
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
function get_height() {
|
||||
//based on image height
|
||||
return $this->_height;
|
||||
}
|
||||
|
||||
/**
|
||||
* Override get_margin_width
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
function get_margin_width() {
|
||||
//ignore image width, use same width as on predefined bullet List_Bullet_Frame_Decorator
|
||||
//for proper alignment of bullet image and text. Allow image to not fitting on left border.
|
||||
//This controls the extra indentation of text to make room for the bullet image.
|
||||
//Here use actual image size, not predefined bullet size
|
||||
//return $this->_frame->get_style()->get_font_size()*List_Bullet_Frame_Decorator::BULLET_SIZE +
|
||||
// 2 * List_Bullet_Frame_Decorator::BULLET_PADDING;
|
||||
|
||||
// Small hack to prevent indenting of list text
|
||||
// Image Might not exist, then position like on list_bullet_frame_decorator fallback to none.
|
||||
if ( $this->_frame->get_style()->list_style_position === "outside" ||
|
||||
$this->_width == 0)
|
||||
return 0;
|
||||
//This aligns the "inside" image position with the text.
|
||||
//The text starts to the right of the image.
|
||||
//Between the image and the text there is an added margin of image width.
|
||||
//Where this comes from is unknown.
|
||||
//The corresponding List_Bullet_Frame_Decorator sets a smaller margin. bullet size?
|
||||
return $this->_width + 2 * List_Bullet_Frame_Decorator::BULLET_PADDING;
|
||||
}
|
||||
|
||||
/**
|
||||
* Override get_margin_height()
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
function get_margin_height() {
|
||||
//Hits only on "inset" lists items, to increase height of box
|
||||
//based on image height
|
||||
return $this->_height + 2 * List_Bullet_Frame_Decorator::BULLET_PADDING;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return image url
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
function get_image_url() {
|
||||
return $this->_img->get_image_url();
|
||||
}
|
||||
|
||||
}
|
||||
73
application/helpers/dompdf/include/list_bullet_positioner.cls.php
Executable file
73
application/helpers/dompdf/include/list_bullet_positioner.cls.php
Executable file
@@ -0,0 +1,73 @@
|
||||
<?php
|
||||
/**
|
||||
* @package dompdf
|
||||
* @link http://dompdf.github.com/
|
||||
* @author Benj Carson <benjcarson@digitaljunkies.ca>
|
||||
* @author Helmut Tischer <htischer@weihenstephan.org>
|
||||
* @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
|
||||
*/
|
||||
|
||||
/**
|
||||
* Positions list bullets
|
||||
*
|
||||
* @access private
|
||||
* @package dompdf
|
||||
*/
|
||||
class List_Bullet_Positioner extends Positioner {
|
||||
|
||||
function __construct(Frame_Decorator $frame) { parent::__construct($frame); }
|
||||
|
||||
//........................................................................
|
||||
|
||||
function position() {
|
||||
|
||||
// Bullets & friends are positioned an absolute distance to the left of
|
||||
// the content edge of their parent element
|
||||
$cb = $this->_frame->get_containing_block();
|
||||
|
||||
// Note: this differs from most frames in that we must position
|
||||
// ourselves after determining our width
|
||||
$x = $cb["x"] - $this->_frame->get_width();
|
||||
|
||||
$p = $this->_frame->find_block_parent();
|
||||
|
||||
$y = $p->get_current_line_box()->y;
|
||||
|
||||
// This is a bit of a hack...
|
||||
$n = $this->_frame->get_next_sibling();
|
||||
if ( $n ) {
|
||||
$style = $n->get_style();
|
||||
$line_height = $style->length_in_pt($style->line_height, $style->get_font_size());
|
||||
$offset = $style->length_in_pt($line_height, $n->get_containing_block("h")) - $this->_frame->get_height();
|
||||
$y += $offset / 2;
|
||||
}
|
||||
|
||||
// Now the position is the left top of the block which should be marked with the bullet.
|
||||
// We tried to find out the y of the start of the first text character within the block.
|
||||
// But the top margin/padding does not fit, neither from this nor from the next sibling
|
||||
// The "bit of a hack" above does not work also.
|
||||
|
||||
// Instead let's position the bullet vertically centered to the block which should be marked.
|
||||
// But for get_next_sibling() the get_containing_block is all zero, and for find_block_parent()
|
||||
// the get_containing_block is paper width and the entire list as height.
|
||||
|
||||
// if ($p) {
|
||||
// //$cb = $n->get_containing_block();
|
||||
// $cb = $p->get_containing_block();
|
||||
// $y += $cb["h"]/2;
|
||||
// print 'cb:'.$cb["x"].':'.$cb["y"].':'.$cb["w"].':'.$cb["h"].':';
|
||||
// }
|
||||
|
||||
// Todo:
|
||||
// For now give up on the above. Use Guesswork with font y-pos in the middle of the line spacing
|
||||
|
||||
/*$style = $p->get_style();
|
||||
$font_size = $style->get_font_size();
|
||||
$line_height = $style->length_in_pt($style->line_height, $font_size);
|
||||
$y += ($line_height - $font_size) / 2; */
|
||||
|
||||
//Position is x-end y-top of character position of the bullet.
|
||||
$this->_frame->set_position($x, $y);
|
||||
|
||||
}
|
||||
}
|
||||
236
application/helpers/dompdf/include/list_bullet_renderer.cls.php
Executable file
236
application/helpers/dompdf/include/list_bullet_renderer.cls.php
Executable file
@@ -0,0 +1,236 @@
|
||||
<?php
|
||||
/**
|
||||
* @package dompdf
|
||||
* @link http://dompdf.github.com/
|
||||
* @author Benj Carson <benjcarson@digitaljunkies.ca>
|
||||
* @author Helmut Tischer <htischer@weihenstephan.org>
|
||||
* @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
|
||||
*/
|
||||
|
||||
/**
|
||||
* Renders list bullets
|
||||
*
|
||||
* @access private
|
||||
* @package dompdf
|
||||
*/
|
||||
class List_Bullet_Renderer extends Abstract_Renderer {
|
||||
static function get_counter_chars($type) {
|
||||
static $cache = array();
|
||||
|
||||
if ( isset($cache[$type]) ) {
|
||||
return $cache[$type];
|
||||
}
|
||||
|
||||
$uppercase = false;
|
||||
$text = "";
|
||||
|
||||
switch ($type) {
|
||||
case "decimal-leading-zero":
|
||||
case "decimal":
|
||||
case "1":
|
||||
return "0123456789";
|
||||
|
||||
case "upper-alpha":
|
||||
case "upper-latin":
|
||||
case "A":
|
||||
$uppercase = true;
|
||||
case "lower-alpha":
|
||||
case "lower-latin":
|
||||
case "a":
|
||||
$text = "abcdefghijklmnopqrstuvwxyz";
|
||||
break;
|
||||
|
||||
case "upper-roman":
|
||||
case "I":
|
||||
$uppercase = true;
|
||||
case "lower-roman":
|
||||
case "i":
|
||||
$text = "ivxlcdm";
|
||||
break;
|
||||
|
||||
case "lower-greek":
|
||||
for($i = 0; $i < 24; $i++) {
|
||||
$text .= unichr($i+944);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if ( $uppercase ) {
|
||||
$text = strtoupper($text);
|
||||
}
|
||||
|
||||
return $cache[$type] = "$text.";
|
||||
}
|
||||
|
||||
/**
|
||||
* @param integer $n
|
||||
* @param string $type
|
||||
* @param integer $pad
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function make_counter($n, $type, $pad = null){
|
||||
$n = intval($n);
|
||||
$text = "";
|
||||
$uppercase = false;
|
||||
|
||||
switch ($type) {
|
||||
case "decimal-leading-zero":
|
||||
case "decimal":
|
||||
case "1":
|
||||
if ($pad)
|
||||
$text = str_pad($n, $pad, "0", STR_PAD_LEFT);
|
||||
else
|
||||
$text = $n;
|
||||
break;
|
||||
|
||||
case "upper-alpha":
|
||||
case "upper-latin":
|
||||
case "A":
|
||||
$uppercase = true;
|
||||
case "lower-alpha":
|
||||
case "lower-latin":
|
||||
case "a":
|
||||
$text = chr( ($n % 26) + ord('a') - 1);
|
||||
break;
|
||||
|
||||
case "upper-roman":
|
||||
case "I":
|
||||
$uppercase = true;
|
||||
case "lower-roman":
|
||||
case "i":
|
||||
$text = dec2roman($n);
|
||||
break;
|
||||
|
||||
case "lower-greek":
|
||||
$text = unichr($n + 944);
|
||||
break;
|
||||
}
|
||||
|
||||
if ( $uppercase ) {
|
||||
$text = strtoupper($text);
|
||||
}
|
||||
|
||||
return "$text.";
|
||||
}
|
||||
|
||||
function render(Frame $frame) {
|
||||
$style = $frame->get_style();
|
||||
$font_size = $style->get_font_size();
|
||||
$line_height = $style->length_in_pt($style->line_height, $frame->get_containing_block("w"));
|
||||
|
||||
$this->_set_opacity( $frame->get_opacity( $style->opacity ) );
|
||||
|
||||
$li = $frame->get_parent();
|
||||
|
||||
// Don't render bullets twice if if was split
|
||||
if ($li->_splitted) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Handle list-style-image
|
||||
// If list style image is requested but missing, fall back to predefined types
|
||||
if ( $style->list_style_image !== "none" &&
|
||||
!Image_Cache::is_broken($img = $frame->get_image_url())) {
|
||||
|
||||
list($x,$y) = $frame->get_position();
|
||||
|
||||
//For expected size and aspect, instead of box size, use image natural size scaled to DPI.
|
||||
// Resample the bullet image to be consistent with 'auto' sized images
|
||||
// See also Image_Frame_Reflower::get_min_max_width
|
||||
// Tested php ver: value measured in px, suffix "px" not in value: rtrim unnecessary.
|
||||
//$w = $frame->get_width();
|
||||
//$h = $frame->get_height();
|
||||
list($width, $height) = dompdf_getimagesize($img);
|
||||
$dpi = $this->_dompdf->get_option("dpi");
|
||||
$w = ((float)rtrim($width, "px") * 72) / $dpi;
|
||||
$h = ((float)rtrim($height, "px") * 72) / $dpi;
|
||||
|
||||
$x -= $w;
|
||||
$y -= ($line_height - $font_size)/2; //Reverse hinting of list_bullet_positioner
|
||||
|
||||
$this->_canvas->image( $img, $x, $y, $w, $h);
|
||||
|
||||
} else {
|
||||
|
||||
$bullet_style = $style->list_style_type;
|
||||
|
||||
$fill = false;
|
||||
|
||||
switch ($bullet_style) {
|
||||
|
||||
default:
|
||||
case "disc":
|
||||
$fill = true;
|
||||
|
||||
case "circle":
|
||||
list($x,$y) = $frame->get_position();
|
||||
$r = ($font_size*(List_Bullet_Frame_Decorator::BULLET_SIZE /*-List_Bullet_Frame_Decorator::BULLET_THICKNESS*/ ))/2;
|
||||
$x -= $font_size*(List_Bullet_Frame_Decorator::BULLET_SIZE/2);
|
||||
$y += ($font_size*(1-List_Bullet_Frame_Decorator::BULLET_DESCENT))/2;
|
||||
$o = $font_size*List_Bullet_Frame_Decorator::BULLET_THICKNESS;
|
||||
$this->_canvas->circle($x, $y, $r, $style->color, $o, null, $fill);
|
||||
break;
|
||||
|
||||
case "square":
|
||||
list($x, $y) = $frame->get_position();
|
||||
$w = $font_size*List_Bullet_Frame_Decorator::BULLET_SIZE;
|
||||
$x -= $w;
|
||||
$y += ($font_size*(1-List_Bullet_Frame_Decorator::BULLET_DESCENT-List_Bullet_Frame_Decorator::BULLET_SIZE))/2;
|
||||
$this->_canvas->filled_rectangle($x, $y, $w, $w, $style->color);
|
||||
break;
|
||||
|
||||
case "decimal-leading-zero":
|
||||
case "decimal":
|
||||
case "lower-alpha":
|
||||
case "lower-latin":
|
||||
case "lower-roman":
|
||||
case "lower-greek":
|
||||
case "upper-alpha":
|
||||
case "upper-latin":
|
||||
case "upper-roman":
|
||||
case "1": // HTML 4.0 compatibility
|
||||
case "a":
|
||||
case "i":
|
||||
case "A":
|
||||
case "I":
|
||||
$pad = null;
|
||||
if ( $bullet_style === "decimal-leading-zero" ) {
|
||||
$pad = strlen($li->get_parent()->get_node()->getAttribute("dompdf-children-count"));
|
||||
}
|
||||
|
||||
$node = $frame->get_node();
|
||||
|
||||
if ( !$node->hasAttribute("dompdf-counter") ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$index = $node->getAttribute("dompdf-counter");
|
||||
$text = $this->make_counter($index, $bullet_style, $pad);
|
||||
|
||||
if ( trim($text) == "" ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$spacing = 0;
|
||||
$font_family = $style->font_family;
|
||||
|
||||
$line = $li->get_containing_line();
|
||||
list($x, $y) = array($frame->get_position("x"), $line->y);
|
||||
|
||||
$x -= Font_Metrics::get_text_width($text, $font_family, $font_size, $spacing);
|
||||
|
||||
// Take line-height into account
|
||||
$line_height = $style->line_height;
|
||||
$y += ($line_height - $font_size) / 4; // FIXME I thought it should be 2, but 4 gives better results
|
||||
|
||||
$this->_canvas->text($x, $y, $text,
|
||||
$font_family, $font_size,
|
||||
$style->color, $spacing);
|
||||
|
||||
case "none":
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
26
application/helpers/dompdf/include/null_frame_decorator.cls.php
Executable file
26
application/helpers/dompdf/include/null_frame_decorator.cls.php
Executable file
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
/**
|
||||
* @package dompdf
|
||||
* @link http://dompdf.github.com/
|
||||
* @author Benj Carson <benjcarson@digitaljunkies.ca>
|
||||
* @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
|
||||
*/
|
||||
|
||||
/**
|
||||
* Dummy decorator
|
||||
*
|
||||
* @access private
|
||||
* @package dompdf
|
||||
*/
|
||||
class Null_Frame_Decorator extends Frame_Decorator {
|
||||
|
||||
function __construct(Frame $frame, DOMPDF $dompdf) {
|
||||
parent::__construct($frame, $dompdf);
|
||||
$style = $this->_frame->get_style();
|
||||
$style->width = 0;
|
||||
$style->height = 0;
|
||||
$style->margin = 0;
|
||||
$style->padding = 0;
|
||||
}
|
||||
|
||||
}
|
||||
21
application/helpers/dompdf/include/null_frame_reflower.cls.php
Executable file
21
application/helpers/dompdf/include/null_frame_reflower.cls.php
Executable file
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
/**
|
||||
* @package dompdf
|
||||
* @link http://dompdf.github.com/
|
||||
* @author Benj Carson <benjcarson@digitaljunkies.ca>
|
||||
* @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
|
||||
*/
|
||||
|
||||
/**
|
||||
* Dummy reflower
|
||||
*
|
||||
* @access private
|
||||
* @package dompdf
|
||||
*/
|
||||
class Null_Frame_Reflower extends Frame_Reflower {
|
||||
|
||||
function __construct(Frame $frame) { parent::__construct($frame); }
|
||||
|
||||
function reflow(Block_Frame_Decorator $block = null) { return; }
|
||||
|
||||
}
|
||||
23
application/helpers/dompdf/include/null_positioner.cls.php
Executable file
23
application/helpers/dompdf/include/null_positioner.cls.php
Executable file
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
/**
|
||||
* @package dompdf
|
||||
* @link http://dompdf.github.com/
|
||||
* @author Benj Carson <benjcarson@digitaljunkies.ca>
|
||||
* @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
|
||||
*/
|
||||
|
||||
/**
|
||||
* Dummy positioner
|
||||
*
|
||||
* @access private
|
||||
* @package dompdf
|
||||
*/
|
||||
class Null_Positioner extends Positioner {
|
||||
|
||||
function __construct(Frame_Decorator $frame) {
|
||||
parent::__construct($frame);
|
||||
}
|
||||
|
||||
function position() { return; }
|
||||
|
||||
}
|
||||
126
application/helpers/dompdf/include/page_cache.cls.php
Executable file
126
application/helpers/dompdf/include/page_cache.cls.php
Executable file
@@ -0,0 +1,126 @@
|
||||
<?php
|
||||
/**
|
||||
* @package dompdf
|
||||
* @link http://dompdf.github.com/
|
||||
* @author Benj Carson <benjcarson@digitaljunkies.ca>
|
||||
* @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
|
||||
*/
|
||||
|
||||
/**
|
||||
* Caches individual rendered PDF pages
|
||||
*
|
||||
* Not totally implemented yet. Use at your own risk ;)
|
||||
*
|
||||
* @access private
|
||||
* @package dompdf
|
||||
* @static
|
||||
*/
|
||||
class Page_Cache {
|
||||
|
||||
const DB_USER = "dompdf_page_cache";
|
||||
const DB_PASS = "some meaningful password";
|
||||
const DB_NAME = "dompdf_page_cache";
|
||||
|
||||
static private $__connection = null;
|
||||
|
||||
static function init() {
|
||||
if ( is_null(self::$__connection) ) {
|
||||
$con_str = "host=" . DB_HOST .
|
||||
" dbname=" . self::DB_NAME .
|
||||
" user=" . self::DB_USER .
|
||||
" password=" . self::DB_PASS;
|
||||
|
||||
if ( !self::$__connection = pg_connect($con_str) )
|
||||
throw new Exception("Database connection failed.");
|
||||
}
|
||||
}
|
||||
|
||||
function __construct() { throw new Exception("Can not create instance of Page_Class. Class is static."); }
|
||||
|
||||
private static function __query($sql) {
|
||||
if ( !($res = pg_query(self::$__connection, $sql)) )
|
||||
throw new Exception(pg_last_error(self::$__connection));
|
||||
return $res;
|
||||
}
|
||||
|
||||
static function store_page($id, $page_num, $data) {
|
||||
$where = "WHERE id='" . pg_escape_string($id) . "' AND ".
|
||||
"page_num=". pg_escape_string($page_num);
|
||||
|
||||
$res = self::__query("SELECT timestamp FROM page_cache ". $where);
|
||||
|
||||
$row = pg_fetch_assoc($res);
|
||||
|
||||
if ( $row )
|
||||
self::__query("UPDATE page_cache SET data='" . pg_escape_string($data) . "' " . $where);
|
||||
else
|
||||
self::__query("INSERT INTO page_cache (id, page_num, data) VALUES ('" . pg_escape_string($id) . "', ".
|
||||
pg_escape_string($page_num) . ", ".
|
||||
"'". pg_escape_string($data) . "')");
|
||||
|
||||
}
|
||||
|
||||
static function store_fonts($id, $fonts) {
|
||||
self::__query("BEGIN");
|
||||
// Update the font information
|
||||
self::__query("DELETE FROM page_fonts WHERE id='" . pg_escape_string($id) . "'");
|
||||
|
||||
foreach (array_keys($fonts) as $font)
|
||||
self::__query("INSERT INTO page_fonts (id, font_name) VALUES ('" .
|
||||
pg_escape_string($id) . "', '" . pg_escape_string($font) . "')");
|
||||
self::__query("COMMIT");
|
||||
}
|
||||
|
||||
// static function retrieve_page($id, $page_num) {
|
||||
|
||||
// $res = self::__query("SELECT data FROM page_cache WHERE id='" . pg_escape_string($id) . "' AND ".
|
||||
// "page_num=". pg_escape_string($page_num));
|
||||
|
||||
// $row = pg_fetch_assoc($res);
|
||||
|
||||
// return pg_unescape_bytea($row["data"]);
|
||||
|
||||
// }
|
||||
|
||||
static function get_page_timestamp($id, $page_num) {
|
||||
$res = self::__query("SELECT timestamp FROM page_cache WHERE id='" . pg_escape_string($id) . "' AND ".
|
||||
"page_num=". pg_escape_string($page_num));
|
||||
|
||||
$row = pg_fetch_assoc($res);
|
||||
|
||||
return $row["timestamp"];
|
||||
|
||||
}
|
||||
|
||||
// Adds the cached document referenced by $id to the provided pdf
|
||||
static function insert_cached_document(CPDF_Adapter $pdf, $id, $new_page = true) {
|
||||
$res = self::__query("SELECT font_name FROM page_fonts WHERE id='" . pg_escape_string($id) . "'");
|
||||
|
||||
// Ensure that the fonts needed by the cached document are loaded into
|
||||
// the pdf
|
||||
while ($row = pg_fetch_assoc($res))
|
||||
$pdf->get_cpdf()->selectFont($row["font_name"]);
|
||||
|
||||
$res = self::__query("SELECT data FROM page_cache WHERE id='" . pg_escape_string($id) . "'");
|
||||
|
||||
if ( $new_page )
|
||||
$pdf->new_page();
|
||||
|
||||
$first = true;
|
||||
while ($row = pg_fetch_assoc($res)) {
|
||||
|
||||
if ( !$first )
|
||||
$pdf->new_page();
|
||||
else
|
||||
$first = false;
|
||||
|
||||
$page = $pdf->reopen_serialized_object($row["data"]);
|
||||
//$pdf->close_object();
|
||||
$pdf->add_object($page, "add");
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Page_Cache::init();
|
||||
592
application/helpers/dompdf/include/page_frame_decorator.cls.php
Executable file
592
application/helpers/dompdf/include/page_frame_decorator.cls.php
Executable file
@@ -0,0 +1,592 @@
|
||||
<?php
|
||||
/**
|
||||
* @package dompdf
|
||||
* @link http://dompdf.github.com/
|
||||
* @author Benj Carson <benjcarson@digitaljunkies.ca>
|
||||
* @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
|
||||
*/
|
||||
|
||||
/**
|
||||
* Decorates frames for page layout
|
||||
*
|
||||
* @access private
|
||||
* @package dompdf
|
||||
*/
|
||||
class Page_Frame_Decorator extends Frame_Decorator {
|
||||
|
||||
/**
|
||||
* y value of bottom page margin
|
||||
*
|
||||
* @var float
|
||||
*/
|
||||
protected $_bottom_page_margin;
|
||||
|
||||
/**
|
||||
* Flag indicating page is full.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $_page_full;
|
||||
|
||||
/**
|
||||
* Number of tables currently being reflowed
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $_in_table;
|
||||
|
||||
/**
|
||||
* The pdf renderer
|
||||
*
|
||||
* @var Renderer
|
||||
*/
|
||||
protected $_renderer;
|
||||
|
||||
/**
|
||||
* This page's floating frames
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $_floating_frames = array();
|
||||
|
||||
//........................................................................
|
||||
|
||||
/**
|
||||
* Class constructor
|
||||
*
|
||||
* @param Frame $frame the frame to decorate
|
||||
* @param DOMPDF $dompdf
|
||||
*/
|
||||
function __construct(Frame $frame, DOMPDF $dompdf) {
|
||||
parent::__construct($frame, $dompdf);
|
||||
$this->_page_full = false;
|
||||
$this->_in_table = 0;
|
||||
$this->_bottom_page_margin = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the renderer used for this pdf
|
||||
*
|
||||
* @param Renderer $renderer the renderer to use
|
||||
*/
|
||||
function set_renderer($renderer) {
|
||||
$this->_renderer = $renderer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the renderer used for this pdf
|
||||
*
|
||||
* @return Renderer
|
||||
*/
|
||||
function get_renderer() {
|
||||
return $this->_renderer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the frame's containing block. Overridden to set $this->_bottom_page_margin.
|
||||
*
|
||||
* @param float $x
|
||||
* @param float $y
|
||||
* @param float $w
|
||||
* @param float $h
|
||||
*/
|
||||
function set_containing_block($x = null, $y = null, $w = null, $h = null) {
|
||||
parent::set_containing_block($x,$y,$w,$h);
|
||||
//$w = $this->get_containing_block("w");
|
||||
if ( isset($h) )
|
||||
$this->_bottom_page_margin = $h; // - $this->_frame->get_style()->length_in_pt($this->_frame->get_style()->margin_bottom, $w);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the page is full and is no longer accepting frames.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
function is_full() {
|
||||
return $this->_page_full;
|
||||
}
|
||||
|
||||
/**
|
||||
* Start a new page by resetting the full flag.
|
||||
*/
|
||||
function next_page() {
|
||||
$this->_floating_frames = array();
|
||||
$this->_renderer->new_page();
|
||||
$this->_page_full = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicate to the page that a table is currently being reflowed.
|
||||
*/
|
||||
function table_reflow_start() {
|
||||
$this->_in_table++;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicate to the page that table reflow is finished.
|
||||
*/
|
||||
function table_reflow_end() {
|
||||
$this->_in_table--;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether we are currently in a nested table or not
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
function in_nested_table() {
|
||||
return $this->_in_table > 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a forced page break is required before $frame. This uses the
|
||||
* frame's page_break_before property as well as the preceeding frame's
|
||||
* page_break_after property.
|
||||
*
|
||||
* @link http://www.w3.org/TR/CSS21/page.html#forced
|
||||
*
|
||||
* @param Frame $frame the frame to check
|
||||
* @return bool true if a page break occured
|
||||
*/
|
||||
function check_forced_page_break(Frame $frame) {
|
||||
|
||||
// Skip check if page is already split
|
||||
if ( $this->_page_full )
|
||||
return null;
|
||||
|
||||
$block_types = array("block", "list-item", "table", "inline");
|
||||
$page_breaks = array("always", "left", "right");
|
||||
|
||||
$style = $frame->get_style();
|
||||
|
||||
if ( !in_array($style->display, $block_types) )
|
||||
return false;
|
||||
|
||||
// Find the previous block-level sibling
|
||||
$prev = $frame->get_prev_sibling();
|
||||
|
||||
while ( $prev && !in_array($prev->get_style()->display, $block_types) )
|
||||
$prev = $prev->get_prev_sibling();
|
||||
|
||||
|
||||
if ( in_array($style->page_break_before, $page_breaks) ) {
|
||||
|
||||
// Prevent cascading splits
|
||||
$frame->split(null, true);
|
||||
// We have to grab the style again here because split() resets
|
||||
// $frame->style to the frame's orignal style.
|
||||
$frame->get_style()->page_break_before = "auto";
|
||||
$this->_page_full = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if ( $prev && in_array($prev->get_style()->page_break_after, $page_breaks) ) {
|
||||
// Prevent cascading splits
|
||||
$frame->split(null, true);
|
||||
$prev->get_style()->page_break_after = "auto";
|
||||
$this->_page_full = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
if( $prev && $prev->get_last_child() && $frame->get_node()->nodeName != "body" ) {
|
||||
$prev_last_child = $prev->get_last_child();
|
||||
if ( in_array($prev_last_child->get_style()->page_break_after, $page_breaks) ) {
|
||||
$frame->split(null, true);
|
||||
$prev_last_child->get_style()->page_break_after = "auto";
|
||||
$this->_page_full = true;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if a page break is allowed before $frame
|
||||
* http://www.w3.org/TR/CSS21/page.html#allowed-page-breaks
|
||||
*
|
||||
* In the normal flow, page breaks can occur at the following places:
|
||||
*
|
||||
* 1. In the vertical margin between block boxes. When a page
|
||||
* break occurs here, the used values of the relevant
|
||||
* 'margin-top' and 'margin-bottom' properties are set to '0'.
|
||||
* 2. Between line boxes inside a block box.
|
||||
*
|
||||
* These breaks are subject to the following rules:
|
||||
*
|
||||
* * Rule A: Breaking at (1) is allowed only if the
|
||||
* 'page-break-after' and 'page-break-before' properties of
|
||||
* all the elements generating boxes that meet at this margin
|
||||
* allow it, which is when at least one of them has the value
|
||||
* 'always', 'left', or 'right', or when all of them are
|
||||
* 'auto'.
|
||||
*
|
||||
* * Rule B: However, if all of them are 'auto' and the
|
||||
* nearest common ancestor of all the elements has a
|
||||
* 'page-break-inside' value of 'avoid', then breaking here is
|
||||
* not allowed.
|
||||
*
|
||||
* * Rule C: Breaking at (2) is allowed only if the number of
|
||||
* line boxes between the break and the start of the enclosing
|
||||
* block box is the value of 'orphans' or more, and the number
|
||||
* of line boxes between the break and the end of the box is
|
||||
* the value of 'widows' or more.
|
||||
*
|
||||
* * Rule D: In addition, breaking at (2) is allowed only if
|
||||
* the 'page-break-inside' property is 'auto'.
|
||||
*
|
||||
* If the above doesn't provide enough break points to keep
|
||||
* content from overflowing the page boxes, then rules B and D are
|
||||
* dropped in order to find additional breakpoints.
|
||||
*
|
||||
* If that still does not lead to sufficient break points, rules A
|
||||
* and C are dropped as well, to find still more break points.
|
||||
*
|
||||
* We will also allow breaks between table rows. However, when
|
||||
* splitting a table, the table headers should carry over to the
|
||||
* next page (but they don't yet).
|
||||
*
|
||||
* @param Frame $frame the frame to check
|
||||
* @return bool true if a break is allowed, false otherwise
|
||||
*/
|
||||
protected function _page_break_allowed(Frame $frame) {
|
||||
|
||||
$block_types = array("block", "list-item", "table", "-dompdf-image");
|
||||
dompdf_debug("page-break", "_page_break_allowed(" . $frame->get_node()->nodeName. ")");
|
||||
$display = $frame->get_style()->display;
|
||||
|
||||
// Block Frames (1):
|
||||
if ( in_array($display, $block_types) ) {
|
||||
|
||||
// Avoid breaks within table-cells
|
||||
if ( $this->_in_table ) {
|
||||
dompdf_debug("page-break", "In table: " . $this->_in_table);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Rules A & B
|
||||
|
||||
if ( $frame->get_style()->page_break_before === "avoid" ) {
|
||||
dompdf_debug("page-break", "before: avoid");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Find the preceeding block-level sibling
|
||||
$prev = $frame->get_prev_sibling();
|
||||
while ( $prev && !in_array($prev->get_style()->display, $block_types) )
|
||||
$prev = $prev->get_prev_sibling();
|
||||
|
||||
// Does the previous element allow a page break after?
|
||||
if ( $prev && $prev->get_style()->page_break_after === "avoid" ) {
|
||||
dompdf_debug("page-break", "after: avoid");
|
||||
return false;
|
||||
}
|
||||
|
||||
// If both $prev & $frame have the same parent, check the parent's
|
||||
// page_break_inside property.
|
||||
$parent = $frame->get_parent();
|
||||
if ( $prev && $parent && $parent->get_style()->page_break_inside === "avoid" ) {
|
||||
dompdf_debug("page-break", "parent inside: avoid");
|
||||
return false;
|
||||
}
|
||||
|
||||
// To prevent cascading page breaks when a top-level element has
|
||||
// page-break-inside: avoid, ensure that at least one frame is
|
||||
// on the page before splitting.
|
||||
if ( $parent->get_node()->nodeName === "body" && !$prev ) {
|
||||
// We are the body's first child
|
||||
dompdf_debug("page-break", "Body's first child.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// If the frame is the first block-level frame, use the value from
|
||||
// $frame's parent instead.
|
||||
if ( !$prev && $parent )
|
||||
return $this->_page_break_allowed( $parent );
|
||||
|
||||
dompdf_debug("page-break", "block: break allowed");
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
// Inline frames (2):
|
||||
else if ( in_array($display, Style::$INLINE_TYPES) ) {
|
||||
|
||||
// Avoid breaks within table-cells
|
||||
if ( $this->_in_table ) {
|
||||
dompdf_debug("page-break", "In table: " . $this->_in_table);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Rule C
|
||||
$block_parent = $frame->find_block_parent();
|
||||
if ( count($block_parent->get_line_boxes() ) < $frame->get_style()->orphans ) {
|
||||
dompdf_debug("page-break", "orphans");
|
||||
return false;
|
||||
}
|
||||
|
||||
// FIXME: Checking widows is tricky without having laid out the
|
||||
// remaining line boxes. Just ignore it for now...
|
||||
|
||||
// Rule D
|
||||
$p = $block_parent;
|
||||
while ($p) {
|
||||
if ( $p->get_style()->page_break_inside === "avoid" ) {
|
||||
dompdf_debug("page-break", "parent->inside: avoid");
|
||||
return false;
|
||||
}
|
||||
$p = $p->find_block_parent();
|
||||
}
|
||||
|
||||
// To prevent cascading page breaks when a top-level element has
|
||||
// page-break-inside: avoid, ensure that at least one frame with
|
||||
// some content is on the page before splitting.
|
||||
$prev = $frame->get_prev_sibling();
|
||||
while ( $prev && ($prev->is_text_node() && trim($prev->get_node()->nodeValue) == "") )
|
||||
$prev = $prev->get_prev_sibling();
|
||||
|
||||
if ( $block_parent->get_node()->nodeName === "body" && !$prev ) {
|
||||
// We are the body's first child
|
||||
dompdf_debug("page-break", "Body's first child.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Skip breaks on empty text nodes
|
||||
if ( $frame->is_text_node() &&
|
||||
$frame->get_node()->nodeValue == "" )
|
||||
return false;
|
||||
|
||||
dompdf_debug("page-break", "inline: break allowed");
|
||||
return true;
|
||||
|
||||
// Table-rows
|
||||
} else if ( $display === "table-row" ) {
|
||||
|
||||
// Simply check if the parent table's page_break_inside property is
|
||||
// not 'avoid'
|
||||
$p = Table_Frame_Decorator::find_parent_table($frame);
|
||||
|
||||
while ($p) {
|
||||
if ( $p->get_style()->page_break_inside === "avoid" ) {
|
||||
dompdf_debug("page-break", "parent->inside: avoid");
|
||||
return false;
|
||||
}
|
||||
$p = $p->find_block_parent();
|
||||
}
|
||||
|
||||
// Avoid breaking after the first row of a table
|
||||
if ( $p && $p->get_first_child() === $frame) {
|
||||
dompdf_debug("page-break", "table: first-row");
|
||||
return false;
|
||||
}
|
||||
|
||||
// If this is a nested table, prevent the page from breaking
|
||||
if ( $this->_in_table > 1 ) {
|
||||
dompdf_debug("page-break", "table: nested table");
|
||||
return false;
|
||||
}
|
||||
|
||||
dompdf_debug("page-break","table-row/row-groups: break allowed");
|
||||
return true;
|
||||
|
||||
} else if ( in_array($display, Table_Frame_Decorator::$ROW_GROUPS) ) {
|
||||
|
||||
// Disallow breaks at row-groups: only split at row boundaries
|
||||
return false;
|
||||
|
||||
} else {
|
||||
|
||||
dompdf_debug("page-break", "? " . $frame->get_style()->display . "");
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if $frame will fit on the page. If the frame does not fit,
|
||||
* the frame tree is modified so that a page break occurs in the
|
||||
* correct location.
|
||||
*
|
||||
* @param Frame $frame the frame to check
|
||||
* @return Frame the frame following the page break
|
||||
*/
|
||||
function check_page_break(Frame $frame) {
|
||||
// Do not split if we have already or if the frame was already
|
||||
// pushed to the next page (prevents infinite loops)
|
||||
if ( $this->_page_full || $frame->_already_pushed ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If the frame is absolute of fixed it shouldn't break
|
||||
$p = $frame;
|
||||
do {
|
||||
if ( $p->is_absolute() )
|
||||
return false;
|
||||
} while ( $p = $p->get_parent() );
|
||||
|
||||
$margin_height = $frame->get_margin_height();
|
||||
|
||||
// FIXME If the row is taller than the page and
|
||||
// if it the first of the page, we don't break
|
||||
if ( $frame->get_style()->display === "table-row" &&
|
||||
!$frame->get_prev_sibling() &&
|
||||
$margin_height > $this->get_margin_height() )
|
||||
return false;
|
||||
|
||||
// Determine the frame's maximum y value
|
||||
$max_y = $frame->get_position("y") + $margin_height;
|
||||
|
||||
// If a split is to occur here, then the bottom margins & paddings of all
|
||||
// parents of $frame must fit on the page as well:
|
||||
$p = $frame->get_parent();
|
||||
while ( $p ) {
|
||||
$style = $p->get_style();
|
||||
$max_y += $style->length_in_pt(array($style->margin_bottom,
|
||||
$style->padding_bottom,
|
||||
$style->border_bottom_width));
|
||||
$p = $p->get_parent();
|
||||
}
|
||||
|
||||
|
||||
// Check if $frame flows off the page
|
||||
if ( $max_y <= $this->_bottom_page_margin )
|
||||
// no: do nothing
|
||||
return false;
|
||||
|
||||
dompdf_debug("page-break", "check_page_break");
|
||||
dompdf_debug("page-break", "in_table: " . $this->_in_table);
|
||||
|
||||
// yes: determine page break location
|
||||
$iter = $frame;
|
||||
$flg = false;
|
||||
|
||||
$in_table = $this->_in_table;
|
||||
|
||||
dompdf_debug("page-break","Starting search");
|
||||
while ( $iter ) {
|
||||
// echo "\nbacktrack: " .$iter->get_node()->nodeName ." ".spl_object_hash($iter->get_node()). "";
|
||||
if ( $iter === $this ) {
|
||||
dompdf_debug("page-break", "reached root.");
|
||||
// We've reached the root in our search. Just split at $frame.
|
||||
break;
|
||||
}
|
||||
|
||||
if ( $this->_page_break_allowed($iter) ) {
|
||||
dompdf_debug("page-break","break allowed, splitting.");
|
||||
$iter->split(null, true);
|
||||
$this->_page_full = true;
|
||||
$this->_in_table = $in_table;
|
||||
$frame->_already_pushed = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
if ( !$flg && $next = $iter->get_last_child() ) {
|
||||
dompdf_debug("page-break", "following last child.");
|
||||
|
||||
if ( $next->is_table() )
|
||||
$this->_in_table++;
|
||||
|
||||
$iter = $next;
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( $next = $iter->get_prev_sibling() ) {
|
||||
dompdf_debug("page-break", "following prev sibling.");
|
||||
|
||||
if ( $next->is_table() && !$iter->is_table() )
|
||||
$this->_in_table++;
|
||||
|
||||
else if ( !$next->is_table() && $iter->is_table() )
|
||||
$this->_in_table--;
|
||||
|
||||
$iter = $next;
|
||||
$flg = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( $next = $iter->get_parent() ) {
|
||||
dompdf_debug("page-break", "following parent.");
|
||||
|
||||
if ( $iter->is_table() )
|
||||
$this->_in_table--;
|
||||
|
||||
$iter = $next;
|
||||
$flg = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
$this->_in_table = $in_table;
|
||||
|
||||
// No valid page break found. Just break at $frame.
|
||||
dompdf_debug("page-break", "no valid break found, just splitting.");
|
||||
|
||||
// If we are in a table, backtrack to the nearest top-level table row
|
||||
if ( $this->_in_table ) {
|
||||
$iter = $frame;
|
||||
while ($iter && $iter->get_style()->display !== "table-row")
|
||||
$iter = $iter->get_parent();
|
||||
|
||||
$iter->split(null, true);
|
||||
} else {
|
||||
$frame->split(null, true);
|
||||
}
|
||||
|
||||
$this->_page_full = true;
|
||||
$frame->_already_pushed = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
//........................................................................
|
||||
|
||||
function split(Frame $frame = null, $force_pagebreak = false) {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a floating frame
|
||||
*
|
||||
* @param Frame $frame
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function add_floating_frame(Frame $frame) {
|
||||
array_unshift($this->_floating_frames, $frame);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Frame[]
|
||||
*/
|
||||
function get_floating_frames() {
|
||||
return $this->_floating_frames;
|
||||
}
|
||||
|
||||
public function remove_floating_frame($key) {
|
||||
unset($this->_floating_frames[$key]);
|
||||
}
|
||||
|
||||
public function get_lowest_float_offset(Frame $child) {
|
||||
$style = $child->get_style();
|
||||
$side = $style->clear;
|
||||
$float = $style->float;
|
||||
|
||||
$y = 0;
|
||||
|
||||
foreach($this->_floating_frames as $key => $frame) {
|
||||
if ( $side === "both" || $frame->get_style()->float === $side ) {
|
||||
$y = max($y, $frame->get_position("y") + $frame->get_margin_height());
|
||||
|
||||
if ( $float !== "none" ) {
|
||||
$this->remove_floating_frame($key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $y;
|
||||
}
|
||||
|
||||
}
|
||||
186
application/helpers/dompdf/include/page_frame_reflower.cls.php
Executable file
186
application/helpers/dompdf/include/page_frame_reflower.cls.php
Executable file
@@ -0,0 +1,186 @@
|
||||
<?php
|
||||
/**
|
||||
* @package dompdf
|
||||
* @link http://dompdf.github.com/
|
||||
* @author Benj Carson <benjcarson@digitaljunkies.ca>
|
||||
* @author Fabien Ménager <fabien.menager@gmail.com>
|
||||
* @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
|
||||
*/
|
||||
|
||||
/**
|
||||
* Reflows pages
|
||||
*
|
||||
* @access private
|
||||
* @package dompdf
|
||||
*/
|
||||
class Page_Frame_Reflower extends Frame_Reflower {
|
||||
|
||||
/**
|
||||
* Cache of the callbacks array
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $_callbacks;
|
||||
|
||||
/**
|
||||
* Cache of the canvas
|
||||
*
|
||||
* @var Canvas
|
||||
*/
|
||||
private $_canvas;
|
||||
|
||||
function __construct(Page_Frame_Decorator $frame) { parent::__construct($frame); }
|
||||
|
||||
function apply_page_style(Frame $frame, $page_number){
|
||||
$style = $frame->get_style();
|
||||
$page_styles = $style->get_stylesheet()->get_page_styles();
|
||||
|
||||
// http://www.w3.org/TR/CSS21/page.html#page-selectors
|
||||
if ( count($page_styles) > 1 ) {
|
||||
$odd = $page_number % 2 == 1;
|
||||
$first = $page_number == 1;
|
||||
|
||||
$style = clone $page_styles["base"];
|
||||
|
||||
// FIXME RTL
|
||||
if ( $odd && isset($page_styles[":right"]) ) {
|
||||
$style->merge($page_styles[":right"]);
|
||||
}
|
||||
|
||||
if ( $odd && isset($page_styles[":odd"]) ) {
|
||||
$style->merge($page_styles[":odd"]);
|
||||
}
|
||||
|
||||
// FIXME RTL
|
||||
if ( !$odd && isset($page_styles[":left"]) ) {
|
||||
$style->merge($page_styles[":left"]);
|
||||
}
|
||||
|
||||
if ( !$odd && isset($page_styles[":even"]) ) {
|
||||
$style->merge($page_styles[":even"]);
|
||||
}
|
||||
|
||||
if ( $first && isset($page_styles[":first"]) ) {
|
||||
$style->merge($page_styles[":first"]);
|
||||
}
|
||||
|
||||
$frame->set_style($style);
|
||||
}
|
||||
}
|
||||
|
||||
//........................................................................
|
||||
|
||||
/**
|
||||
* Paged layout:
|
||||
* http://www.w3.org/TR/CSS21/page.html
|
||||
*/
|
||||
function reflow(Block_Frame_Decorator $block = null) {
|
||||
$fixed_children = array();
|
||||
$prev_child = null;
|
||||
$child = $this->_frame->get_first_child();
|
||||
$current_page = 0;
|
||||
|
||||
while ($child) {
|
||||
$this->apply_page_style($this->_frame, $current_page + 1);
|
||||
|
||||
$style = $this->_frame->get_style();
|
||||
|
||||
// Pages are only concerned with margins
|
||||
$cb = $this->_frame->get_containing_block();
|
||||
$left = $style->length_in_pt($style->margin_left, $cb["w"]);
|
||||
$right = $style->length_in_pt($style->margin_right, $cb["w"]);
|
||||
$top = $style->length_in_pt($style->margin_top, $cb["h"]);
|
||||
$bottom = $style->length_in_pt($style->margin_bottom, $cb["h"]);
|
||||
|
||||
$content_x = $cb["x"] + $left;
|
||||
$content_y = $cb["y"] + $top;
|
||||
$content_width = $cb["w"] - $left - $right;
|
||||
$content_height = $cb["h"] - $top - $bottom;
|
||||
|
||||
// Only if it's the first page, we save the nodes with a fixed position
|
||||
if ($current_page == 0) {
|
||||
$children = $child->get_children();
|
||||
foreach ($children as $onechild) {
|
||||
if ($onechild->get_style()->position === "fixed") {
|
||||
$fixed_children[] = $onechild->deep_copy();
|
||||
}
|
||||
}
|
||||
$fixed_children = array_reverse($fixed_children);
|
||||
}
|
||||
|
||||
$child->set_containing_block($content_x, $content_y, $content_width, $content_height);
|
||||
|
||||
// Check for begin reflow callback
|
||||
$this->_check_callbacks("begin_page_reflow", $child);
|
||||
|
||||
//Insert a copy of each node which have a fixed position
|
||||
if ($current_page >= 1) {
|
||||
foreach ($fixed_children as $fixed_child) {
|
||||
$child->insert_child_before($fixed_child->deep_copy(), $child->get_first_child());
|
||||
}
|
||||
}
|
||||
|
||||
$child->reflow();
|
||||
$next_child = $child->get_next_sibling();
|
||||
|
||||
// Check for begin render callback
|
||||
$this->_check_callbacks("begin_page_render", $child);
|
||||
|
||||
// Render the page
|
||||
$this->_frame->get_renderer()->render($child);
|
||||
|
||||
// Check for end render callback
|
||||
$this->_check_callbacks("end_page_render", $child);
|
||||
|
||||
if ( $next_child ) {
|
||||
$this->_frame->next_page();
|
||||
}
|
||||
|
||||
// Wait to dispose of all frames on the previous page
|
||||
// so callback will have access to them
|
||||
if ( $prev_child ) {
|
||||
$prev_child->dispose(true);
|
||||
}
|
||||
$prev_child = $child;
|
||||
$child = $next_child;
|
||||
$current_page++;
|
||||
}
|
||||
|
||||
// Dispose of previous page if it still exists
|
||||
if ( $prev_child ) {
|
||||
$prev_child->dispose(true);
|
||||
}
|
||||
}
|
||||
|
||||
//........................................................................
|
||||
|
||||
/**
|
||||
* Check for callbacks that need to be performed when a given event
|
||||
* gets triggered on a page
|
||||
*
|
||||
* @param string $event the type of event
|
||||
* @param Frame $frame the frame that event is triggered on
|
||||
*/
|
||||
protected function _check_callbacks($event, $frame) {
|
||||
if (!isset($this->_callbacks)) {
|
||||
$dompdf = $this->_frame->get_dompdf();
|
||||
$this->_callbacks = $dompdf->get_callbacks();
|
||||
$this->_canvas = $dompdf->get_canvas();
|
||||
}
|
||||
|
||||
if (is_array($this->_callbacks) && isset($this->_callbacks[$event])) {
|
||||
$info = array(0 => $this->_canvas, "canvas" => $this->_canvas,
|
||||
1 => $frame, "frame" => $frame);
|
||||
$fs = $this->_callbacks[$event];
|
||||
foreach ($fs as $f) {
|
||||
if (is_callable($f)) {
|
||||
if (is_array($f)) {
|
||||
$f[0]->$f[1]($info);
|
||||
} else {
|
||||
$f($info);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
1085
application/helpers/dompdf/include/pdflib_adapter.cls.php
Executable file
1085
application/helpers/dompdf/include/pdflib_adapter.cls.php
Executable file
File diff suppressed because it is too large
Load Diff
48
application/helpers/dompdf/include/php_evaluator.cls.php
Executable file
48
application/helpers/dompdf/include/php_evaluator.cls.php
Executable file
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
/**
|
||||
* @package dompdf
|
||||
* @link http://dompdf.github.com/
|
||||
* @author Benj Carson <benjcarson@digitaljunkies.ca>
|
||||
* @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
|
||||
*/
|
||||
|
||||
/**
|
||||
* Executes inline PHP code during the rendering process
|
||||
*
|
||||
* @access private
|
||||
* @package dompdf
|
||||
*/
|
||||
class PHP_Evaluator {
|
||||
|
||||
/**
|
||||
* @var Canvas
|
||||
*/
|
||||
protected $_canvas;
|
||||
|
||||
function __construct(Canvas $canvas) {
|
||||
$this->_canvas = $canvas;
|
||||
}
|
||||
|
||||
function evaluate($code, $vars = array()) {
|
||||
if ( !$this->_canvas->get_dompdf()->get_option("enable_php") ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Set up some variables for the inline code
|
||||
$pdf = $this->_canvas;
|
||||
$PAGE_NUM = $pdf->get_page_number();
|
||||
$PAGE_COUNT = $pdf->get_page_count();
|
||||
|
||||
// Override those variables if passed in
|
||||
foreach ($vars as $k => $v) {
|
||||
$$k = $v;
|
||||
}
|
||||
|
||||
//$code = html_entity_decode($code); // @todo uncomment this when tested
|
||||
eval($code);
|
||||
}
|
||||
|
||||
function render(Frame $frame) {
|
||||
$this->evaluate($frame->get_node()->nodeValue);
|
||||
}
|
||||
}
|
||||
51
application/helpers/dompdf/include/positioner.cls.php
Executable file
51
application/helpers/dompdf/include/positioner.cls.php
Executable file
@@ -0,0 +1,51 @@
|
||||
<?php
|
||||
/**
|
||||
* @package dompdf
|
||||
* @link http://dompdf.github.com/
|
||||
* @author Benj Carson <benjcarson@digitaljunkies.ca>
|
||||
* @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
|
||||
*/
|
||||
|
||||
/**
|
||||
* Base Positioner class
|
||||
*
|
||||
* Defines postioner interface
|
||||
*
|
||||
* @access private
|
||||
* @package dompdf
|
||||
*/
|
||||
abstract class Positioner {
|
||||
|
||||
/**
|
||||
* @var Frame_Decorator
|
||||
*/
|
||||
protected $_frame;
|
||||
|
||||
//........................................................................
|
||||
|
||||
function __construct(Frame_Decorator $frame) {
|
||||
$this->_frame = $frame;
|
||||
}
|
||||
|
||||
/**
|
||||
* Class destructor
|
||||
*/
|
||||
function __destruct() {
|
||||
clear_object($this);
|
||||
}
|
||||
//........................................................................
|
||||
|
||||
abstract function position();
|
||||
|
||||
function move($offset_x, $offset_y, $ignore_self = false) {
|
||||
list($x, $y) = $this->_frame->get_position();
|
||||
|
||||
if ( !$ignore_self ) {
|
||||
$this->_frame->set_position($x + $offset_x, $y + $offset_y);
|
||||
}
|
||||
|
||||
foreach($this->_frame->get_children() as $child) {
|
||||
$child->move($offset_x, $offset_y);
|
||||
}
|
||||
}
|
||||
}
|
||||
290
application/helpers/dompdf/include/renderer.cls.php
Executable file
290
application/helpers/dompdf/include/renderer.cls.php
Executable file
@@ -0,0 +1,290 @@
|
||||
<?php
|
||||
/**
|
||||
* @package dompdf
|
||||
* @link http://dompdf.github.com/
|
||||
* @author Benj Carson <benjcarson@digitaljunkies.ca>
|
||||
* @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
|
||||
*/
|
||||
|
||||
/**
|
||||
* Concrete renderer
|
||||
*
|
||||
* Instantiates several specific renderers in order to render any given
|
||||
* frame.
|
||||
*
|
||||
* @access private
|
||||
* @package dompdf
|
||||
*/
|
||||
class Renderer extends Abstract_Renderer {
|
||||
|
||||
/**
|
||||
* Array of renderers for specific frame types
|
||||
*
|
||||
* @var Abstract_Renderer[]
|
||||
*/
|
||||
protected $_renderers;
|
||||
|
||||
/**
|
||||
* Cache of the callbacks array
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $_callbacks;
|
||||
|
||||
/**
|
||||
* Class destructor
|
||||
*/
|
||||
function __destruct() {
|
||||
clear_object($this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Advance the canvas to the next page
|
||||
*/
|
||||
function new_page() {
|
||||
$this->_canvas->new_page();
|
||||
}
|
||||
|
||||
/**
|
||||
* Render frames recursively
|
||||
*
|
||||
* @param Frame $frame the frame to render
|
||||
*/
|
||||
function render(Frame $frame) {
|
||||
global $_dompdf_debug;
|
||||
|
||||
if ( $_dompdf_debug ) {
|
||||
echo $frame;
|
||||
flush();
|
||||
}
|
||||
|
||||
$style = $frame->get_style();
|
||||
|
||||
if ( in_array($style->visibility, array("hidden", "collapse")) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$display = $style->display;
|
||||
|
||||
// Starts the CSS transformation
|
||||
if ( $style->transform && is_array($style->transform) ) {
|
||||
$this->_canvas->save();
|
||||
list($x, $y) = $frame->get_padding_box();
|
||||
$origin = $style->transform_origin;
|
||||
|
||||
foreach($style->transform as $transform) {
|
||||
list($function, $values) = $transform;
|
||||
if ( $function === "matrix" ) {
|
||||
$function = "transform";
|
||||
}
|
||||
|
||||
$values = array_map("floatval", $values);
|
||||
$values[] = $x + $style->length_in_pt($origin[0], $style->width);
|
||||
$values[] = $y + $style->length_in_pt($origin[1], $style->height);
|
||||
|
||||
call_user_func_array(array($this->_canvas, $function), $values);
|
||||
}
|
||||
}
|
||||
|
||||
switch ($display) {
|
||||
|
||||
case "block":
|
||||
case "list-item":
|
||||
case "inline-block":
|
||||
case "table":
|
||||
case "inline-table":
|
||||
$this->_render_frame("block", $frame);
|
||||
break;
|
||||
|
||||
case "inline":
|
||||
if ( $frame->is_text_node() )
|
||||
$this->_render_frame("text", $frame);
|
||||
else
|
||||
$this->_render_frame("inline", $frame);
|
||||
break;
|
||||
|
||||
case "table-cell":
|
||||
$this->_render_frame("table-cell", $frame);
|
||||
break;
|
||||
|
||||
case "table-row-group":
|
||||
case "table-header-group":
|
||||
case "table-footer-group":
|
||||
$this->_render_frame("table-row-group", $frame);
|
||||
break;
|
||||
|
||||
case "-dompdf-list-bullet":
|
||||
$this->_render_frame("list-bullet", $frame);
|
||||
break;
|
||||
|
||||
case "-dompdf-image":
|
||||
$this->_render_frame("image", $frame);
|
||||
break;
|
||||
|
||||
case "none":
|
||||
$node = $frame->get_node();
|
||||
|
||||
if ( $node->nodeName === "script" ) {
|
||||
if ( $node->getAttribute("type") === "text/php" ||
|
||||
$node->getAttribute("language") === "php" ) {
|
||||
// Evaluate embedded php scripts
|
||||
$this->_render_frame("php", $frame);
|
||||
}
|
||||
|
||||
elseif ( $node->getAttribute("type") === "text/javascript" ||
|
||||
$node->getAttribute("language") === "javascript" ) {
|
||||
// Insert JavaScript
|
||||
$this->_render_frame("javascript", $frame);
|
||||
}
|
||||
}
|
||||
|
||||
// Don't render children, so skip to next iter
|
||||
return;
|
||||
|
||||
default:
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
// Starts the overflow: hidden box
|
||||
if ( $style->overflow === "hidden" ) {
|
||||
list($x, $y, $w, $h) = $frame->get_padding_box();
|
||||
|
||||
// get border radii
|
||||
$style = $frame->get_style();
|
||||
list($tl, $tr, $br, $bl) = $style->get_computed_border_radius($w, $h);
|
||||
|
||||
if ( $tl + $tr + $br + $bl > 0 ) {
|
||||
$this->_canvas->clipping_roundrectangle($x, $y, $w, $h, $tl, $tr, $br, $bl);
|
||||
}
|
||||
else {
|
||||
$this->_canvas->clipping_rectangle($x, $y, $w, $h);
|
||||
}
|
||||
}
|
||||
|
||||
$stack = array();
|
||||
|
||||
foreach ($frame->get_children() as $child) {
|
||||
// < 0 : nagative z-index
|
||||
// = 0 : no z-index, no stacking context
|
||||
// = 1 : stacking context without z-index
|
||||
// > 1 : z-index
|
||||
$child_style = $child->get_style();
|
||||
$child_z_index = $child_style->z_index;
|
||||
$z_index = 0;
|
||||
|
||||
if ( $child_z_index !== "auto" ) {
|
||||
$z_index = intval($child_z_index) + 1;
|
||||
}
|
||||
elseif ( $child_style->float !== "none" || $child->is_positionned()) {
|
||||
$z_index = 1;
|
||||
}
|
||||
|
||||
$stack[$z_index][] = $child;
|
||||
}
|
||||
|
||||
ksort($stack);
|
||||
|
||||
foreach ($stack as $by_index) {
|
||||
foreach($by_index as $child) {
|
||||
$this->render($child);
|
||||
}
|
||||
}
|
||||
|
||||
// Ends the overflow: hidden box
|
||||
if ( $style->overflow === "hidden" ) {
|
||||
$this->_canvas->clipping_end();
|
||||
}
|
||||
|
||||
if ( $style->transform && is_array($style->transform) ) {
|
||||
$this->_canvas->restore();
|
||||
}
|
||||
|
||||
// Check for end frame callback
|
||||
$this->_check_callbacks("end_frame", $frame);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check for callbacks that need to be performed when a given event
|
||||
* gets triggered on a frame
|
||||
*
|
||||
* @param string $event the type of event
|
||||
* @param Frame $frame the frame that event is triggered on
|
||||
*/
|
||||
protected function _check_callbacks($event, $frame) {
|
||||
if (!isset($this->_callbacks)) {
|
||||
$this->_callbacks = $this->_dompdf->get_callbacks();
|
||||
}
|
||||
|
||||
if (is_array($this->_callbacks) && isset($this->_callbacks[$event])) {
|
||||
$info = array(0 => $this->_canvas, "canvas" => $this->_canvas,
|
||||
1 => $frame, "frame" => $frame);
|
||||
$fs = $this->_callbacks[$event];
|
||||
foreach ($fs as $f) {
|
||||
if (is_callable($f)) {
|
||||
if (is_array($f)) {
|
||||
$f[0]->$f[1]($info);
|
||||
} else {
|
||||
$f($info);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Render a single frame
|
||||
*
|
||||
* Creates Renderer objects on demand
|
||||
*
|
||||
* @param string $type type of renderer to use
|
||||
* @param Frame $frame the frame to render
|
||||
*/
|
||||
protected function _render_frame($type, $frame) {
|
||||
|
||||
if ( !isset($this->_renderers[$type]) ) {
|
||||
|
||||
switch ($type) {
|
||||
case "block":
|
||||
$this->_renderers[$type] = new Block_Renderer($this->_dompdf);
|
||||
break;
|
||||
|
||||
case "inline":
|
||||
$this->_renderers[$type] = new Inline_Renderer($this->_dompdf);
|
||||
break;
|
||||
|
||||
case "text":
|
||||
$this->_renderers[$type] = new Text_Renderer($this->_dompdf);
|
||||
break;
|
||||
|
||||
case "image":
|
||||
$this->_renderers[$type] = new Image_Renderer($this->_dompdf);
|
||||
break;
|
||||
|
||||
case "table-cell":
|
||||
$this->_renderers[$type] = new Table_Cell_Renderer($this->_dompdf);
|
||||
break;
|
||||
|
||||
case "table-row-group":
|
||||
$this->_renderers[$type] = new Table_Row_Group_Renderer($this->_dompdf);
|
||||
break;
|
||||
|
||||
case "list-bullet":
|
||||
$this->_renderers[$type] = new List_Bullet_Renderer($this->_dompdf);
|
||||
break;
|
||||
|
||||
case "php":
|
||||
$this->_renderers[$type] = new PHP_Evaluator($this->_canvas);
|
||||
break;
|
||||
|
||||
case "javascript":
|
||||
$this->_renderers[$type] = new Javascript_Embedder($this->_dompdf);
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
$this->_renderers[$type]->render($frame);
|
||||
|
||||
}
|
||||
}
|
||||
2435
application/helpers/dompdf/include/style.cls.php
Executable file
2435
application/helpers/dompdf/include/style.cls.php
Executable file
File diff suppressed because it is too large
Load Diff
1418
application/helpers/dompdf/include/stylesheet.cls.php
Executable file
1418
application/helpers/dompdf/include/stylesheet.cls.php
Executable file
File diff suppressed because it is too large
Load Diff
102
application/helpers/dompdf/include/table_cell_frame_decorator.cls.php
Executable file
102
application/helpers/dompdf/include/table_cell_frame_decorator.cls.php
Executable file
@@ -0,0 +1,102 @@
|
||||
<?php
|
||||
/**
|
||||
* @package dompdf
|
||||
* @link http://dompdf.github.com/
|
||||
* @author Benj Carson <benjcarson@digitaljunkies.ca>
|
||||
* @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
|
||||
*/
|
||||
|
||||
/**
|
||||
* Decorates table cells for layout
|
||||
*
|
||||
* @access private
|
||||
* @package dompdf
|
||||
*/
|
||||
class Table_Cell_Frame_Decorator extends Block_Frame_Decorator {
|
||||
|
||||
protected $_resolved_borders;
|
||||
protected $_content_height;
|
||||
|
||||
//........................................................................
|
||||
|
||||
function __construct(Frame $frame, DOMPDF $dompdf) {
|
||||
parent::__construct($frame, $dompdf);
|
||||
$this->_resolved_borders = array();
|
||||
$this->_content_height = 0;
|
||||
}
|
||||
|
||||
//........................................................................
|
||||
|
||||
function reset() {
|
||||
parent::reset();
|
||||
$this->_resolved_borders = array();
|
||||
$this->_content_height = 0;
|
||||
$this->_frame->reset();
|
||||
}
|
||||
|
||||
function get_content_height() {
|
||||
return $this->_content_height;
|
||||
}
|
||||
|
||||
function set_content_height($height) {
|
||||
$this->_content_height = $height;
|
||||
}
|
||||
|
||||
function set_cell_height($height) {
|
||||
$style = $this->get_style();
|
||||
$v_space = $style->length_in_pt(array($style->margin_top,
|
||||
$style->padding_top,
|
||||
$style->border_top_width,
|
||||
$style->border_bottom_width,
|
||||
$style->padding_bottom,
|
||||
$style->margin_bottom),
|
||||
$style->width);
|
||||
|
||||
$new_height = $height - $v_space;
|
||||
$style->height = $new_height;
|
||||
|
||||
if ( $new_height > $this->_content_height ) {
|
||||
$y_offset = 0;
|
||||
|
||||
// Adjust our vertical alignment
|
||||
switch ($style->vertical_align) {
|
||||
default:
|
||||
case "baseline":
|
||||
// FIXME: this isn't right
|
||||
|
||||
case "top":
|
||||
// Don't need to do anything
|
||||
return;
|
||||
|
||||
case "middle":
|
||||
$y_offset = ($new_height - $this->_content_height) / 2;
|
||||
break;
|
||||
|
||||
case "bottom":
|
||||
$y_offset = $new_height - $this->_content_height;
|
||||
break;
|
||||
}
|
||||
|
||||
if ( $y_offset ) {
|
||||
// Move our children
|
||||
foreach ( $this->get_line_boxes() as $line ) {
|
||||
foreach ( $line->get_frames() as $frame )
|
||||
$frame->move( 0, $y_offset );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function set_resolved_border($side, $border_spec) {
|
||||
$this->_resolved_borders[$side] = $border_spec;
|
||||
}
|
||||
|
||||
//........................................................................
|
||||
|
||||
function get_resolved_border($side) {
|
||||
return $this->_resolved_borders[$side];
|
||||
}
|
||||
|
||||
function get_resolved_borders() { return $this->_resolved_borders; }
|
||||
}
|
||||
119
application/helpers/dompdf/include/table_cell_frame_reflower.cls.php
Executable file
119
application/helpers/dompdf/include/table_cell_frame_reflower.cls.php
Executable file
@@ -0,0 +1,119 @@
|
||||
<?php
|
||||
/**
|
||||
* @package dompdf
|
||||
* @link http://dompdf.github.com/
|
||||
* @author Benj Carson <benjcarson@digitaljunkies.ca>
|
||||
* @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
|
||||
*/
|
||||
|
||||
/**
|
||||
* Reflows table cells
|
||||
*
|
||||
* @access private
|
||||
* @package dompdf
|
||||
*/
|
||||
class Table_Cell_Frame_Reflower extends Block_Frame_Reflower {
|
||||
|
||||
//........................................................................
|
||||
|
||||
function __construct(Block_Frame_Decorator $frame) {
|
||||
parent::__construct($frame);
|
||||
}
|
||||
|
||||
//........................................................................
|
||||
|
||||
function reflow(Block_Frame_Decorator $block = null) {
|
||||
|
||||
$style = $this->_frame->get_style();
|
||||
|
||||
$table = Table_Frame_Decorator::find_parent_table($this->_frame);
|
||||
$cellmap = $table->get_cellmap();
|
||||
|
||||
list($x, $y) = $cellmap->get_frame_position($this->_frame);
|
||||
$this->_frame->set_position($x, $y);
|
||||
|
||||
$cells = $cellmap->get_spanned_cells($this->_frame);
|
||||
|
||||
$w = 0;
|
||||
foreach ( $cells["columns"] as $i ) {
|
||||
$col = $cellmap->get_column( $i );
|
||||
$w += $col["used-width"];
|
||||
}
|
||||
|
||||
//FIXME?
|
||||
$h = $this->_frame->get_containing_block("h");
|
||||
|
||||
$left_space = $style->length_in_pt(array($style->margin_left,
|
||||
$style->padding_left,
|
||||
$style->border_left_width),
|
||||
$w);
|
||||
|
||||
$right_space = $style->length_in_pt(array($style->padding_right,
|
||||
$style->margin_right,
|
||||
$style->border_right_width),
|
||||
$w);
|
||||
|
||||
$top_space = $style->length_in_pt(array($style->margin_top,
|
||||
$style->padding_top,
|
||||
$style->border_top_width),
|
||||
$h);
|
||||
$bottom_space = $style->length_in_pt(array($style->margin_bottom,
|
||||
$style->padding_bottom,
|
||||
$style->border_bottom_width),
|
||||
$h);
|
||||
|
||||
$style->width = $cb_w = $w - $left_space - $right_space;
|
||||
|
||||
$content_x = $x + $left_space;
|
||||
$content_y = $line_y = $y + $top_space;
|
||||
|
||||
// Adjust the first line based on the text-indent property
|
||||
$indent = $style->length_in_pt($style->text_indent, $w);
|
||||
$this->_frame->increase_line_width($indent);
|
||||
|
||||
$page = $this->_frame->get_root();
|
||||
|
||||
// Set the y position of the first line in the cell
|
||||
$line_box = $this->_frame->get_current_line_box();
|
||||
$line_box->y = $line_y;
|
||||
|
||||
// Set the containing blocks and reflow each child
|
||||
foreach ( $this->_frame->get_children() as $child ) {
|
||||
|
||||
if ( $page->is_full() )
|
||||
break;
|
||||
|
||||
$child->set_containing_block($content_x, $content_y, $cb_w, $h);
|
||||
|
||||
$this->process_clear($child);
|
||||
|
||||
$child->reflow($this->_frame);
|
||||
|
||||
$this->process_float($child, $x + $left_space, $w - $right_space - $left_space);
|
||||
}
|
||||
|
||||
// Determine our height
|
||||
$style_height = $style->length_in_pt($style->height, $h);
|
||||
|
||||
$this->_frame->set_content_height($this->_calculate_content_height());
|
||||
|
||||
$height = max($style_height, $this->_frame->get_content_height());
|
||||
|
||||
// Let the cellmap know our height
|
||||
$cell_height = $height / count($cells["rows"]);
|
||||
|
||||
if ($style_height <= $height)
|
||||
$cell_height += $top_space + $bottom_space;
|
||||
|
||||
foreach ($cells["rows"] as $i)
|
||||
$cellmap->set_row_height($i, $cell_height);
|
||||
|
||||
$style->height = $height;
|
||||
|
||||
$this->_text_align();
|
||||
|
||||
$this->vertical_align();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
28
application/helpers/dompdf/include/table_cell_positioner.cls.php
Executable file
28
application/helpers/dompdf/include/table_cell_positioner.cls.php
Executable file
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
/**
|
||||
* @package dompdf
|
||||
* @link http://dompdf.github.com/
|
||||
* @author Benj Carson <benjcarson@digitaljunkies.ca>
|
||||
* @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
|
||||
*/
|
||||
|
||||
/**
|
||||
* Positions table cells
|
||||
*
|
||||
* @access private
|
||||
* @package dompdf
|
||||
*/
|
||||
class Table_Cell_Positioner extends Positioner {
|
||||
|
||||
function __construct(Frame_Decorator $frame) { parent::__construct($frame); }
|
||||
|
||||
//........................................................................
|
||||
|
||||
function position() {
|
||||
|
||||
$table = Table_Frame_Decorator::find_parent_table($this->_frame);
|
||||
$cellmap = $table->get_cellmap();
|
||||
$this->_frame->set_position($cellmap->get_frame_position($this->_frame));
|
||||
|
||||
}
|
||||
}
|
||||
155
application/helpers/dompdf/include/table_cell_renderer.cls.php
Executable file
155
application/helpers/dompdf/include/table_cell_renderer.cls.php
Executable file
@@ -0,0 +1,155 @@
|
||||
<?php
|
||||
/**
|
||||
* @package dompdf
|
||||
* @link http://dompdf.github.com/
|
||||
* @author Benj Carson <benjcarson@digitaljunkies.ca>
|
||||
* @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
|
||||
*/
|
||||
|
||||
/**
|
||||
* Renders table cells
|
||||
*
|
||||
* @access private
|
||||
* @package dompdf
|
||||
*/
|
||||
class Table_Cell_Renderer extends Block_Renderer {
|
||||
|
||||
//........................................................................
|
||||
|
||||
function render(Frame $frame) {
|
||||
$style = $frame->get_style();
|
||||
|
||||
if ( trim($frame->get_node()->nodeValue) === "" && $style->empty_cells === "hide" ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->_set_opacity( $frame->get_opacity( $style->opacity ) );
|
||||
list($x, $y, $w, $h) = $frame->get_border_box();
|
||||
|
||||
// Draw our background, border and content
|
||||
if ( ($bg = $style->background_color) !== "transparent" ) {
|
||||
$this->_canvas->filled_rectangle($x, $y, $w, $h, $bg);
|
||||
}
|
||||
|
||||
if ( ($url = $style->background_image) && $url !== "none" ) {
|
||||
$this->_background_image($url, $x, $y, $w, $h, $style);
|
||||
}
|
||||
|
||||
$table = Table_Frame_Decorator::find_parent_table($frame);
|
||||
|
||||
if ( $table->get_style()->border_collapse !== "collapse" ) {
|
||||
$this->_render_border($frame);
|
||||
$this->_render_outline($frame);
|
||||
return;
|
||||
}
|
||||
|
||||
// The collapsed case is slightly complicated...
|
||||
// @todo Add support for outlines here
|
||||
|
||||
$cellmap = $table->get_cellmap();
|
||||
$cells = $cellmap->get_spanned_cells($frame);
|
||||
$num_rows = $cellmap->get_num_rows();
|
||||
$num_cols = $cellmap->get_num_cols();
|
||||
|
||||
// Determine the top row spanned by this cell
|
||||
$i = $cells["rows"][0];
|
||||
$top_row = $cellmap->get_row($i);
|
||||
|
||||
// Determine if this cell borders on the bottom of the table. If so,
|
||||
// then we draw its bottom border. Otherwise the next row down will
|
||||
// draw its top border instead.
|
||||
if (in_array( $num_rows - 1, $cells["rows"])) {
|
||||
$draw_bottom = true;
|
||||
$bottom_row = $cellmap->get_row($num_rows - 1);
|
||||
} else
|
||||
$draw_bottom = false;
|
||||
|
||||
|
||||
// Draw the horizontal borders
|
||||
foreach ( $cells["columns"] as $j ) {
|
||||
$bp = $cellmap->get_border_properties($i, $j);
|
||||
|
||||
$y = $top_row["y"] - $bp["top"]["width"] / 2;
|
||||
|
||||
$col = $cellmap->get_column($j);
|
||||
$x = $col["x"] - $bp["left"]["width"] / 2;
|
||||
$w = $col["used-width"] + ($bp["left"]["width"] + $bp["right"]["width"] ) / 2;
|
||||
|
||||
if ( $bp["top"]["style"] !== "none" && $bp["top"]["width"] > 0 ) {
|
||||
$widths = array($bp["top"]["width"],
|
||||
$bp["right"]["width"],
|
||||
$bp["bottom"]["width"],
|
||||
$bp["left"]["width"]);
|
||||
$method = "_border_". $bp["top"]["style"];
|
||||
$this->$method($x, $y, $w, $bp["top"]["color"], $widths, "top", "square");
|
||||
}
|
||||
|
||||
if ( $draw_bottom ) {
|
||||
$bp = $cellmap->get_border_properties($num_rows - 1, $j);
|
||||
if ( $bp["bottom"]["style"] === "none" || $bp["bottom"]["width"] <= 0 )
|
||||
continue;
|
||||
|
||||
$y = $bottom_row["y"] + $bottom_row["height"] + $bp["bottom"]["width"] / 2;
|
||||
|
||||
$widths = array($bp["top"]["width"],
|
||||
$bp["right"]["width"],
|
||||
$bp["bottom"]["width"],
|
||||
$bp["left"]["width"]);
|
||||
$method = "_border_". $bp["bottom"]["style"];
|
||||
$this->$method($x, $y, $w, $bp["bottom"]["color"], $widths, "bottom", "square");
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
$j = $cells["columns"][0];
|
||||
|
||||
$left_col = $cellmap->get_column($j);
|
||||
|
||||
if (in_array($num_cols - 1, $cells["columns"])) {
|
||||
$draw_right = true;
|
||||
$right_col = $cellmap->get_column($num_cols - 1);
|
||||
} else
|
||||
$draw_right = false;
|
||||
|
||||
// Draw the vertical borders
|
||||
foreach ( $cells["rows"] as $i ) {
|
||||
$bp = $cellmap->get_border_properties($i, $j);
|
||||
|
||||
$x = $left_col["x"] - $bp["left"]["width"] / 2;
|
||||
|
||||
$row = $cellmap->get_row($i);
|
||||
|
||||
$y = $row["y"] - $bp["top"]["width"] / 2;
|
||||
$h = $row["height"] + ($bp["top"]["width"] + $bp["bottom"]["width"])/ 2;
|
||||
|
||||
if ( $bp["left"]["style"] !== "none" && $bp["left"]["width"] > 0 ) {
|
||||
|
||||
$widths = array($bp["top"]["width"],
|
||||
$bp["right"]["width"],
|
||||
$bp["bottom"]["width"],
|
||||
$bp["left"]["width"]);
|
||||
|
||||
$method = "_border_" . $bp["left"]["style"];
|
||||
$this->$method($x, $y, $h, $bp["left"]["color"], $widths, "left", "square");
|
||||
}
|
||||
|
||||
if ( $draw_right ) {
|
||||
$bp = $cellmap->get_border_properties($i, $num_cols - 1);
|
||||
if ( $bp["right"]["style"] === "none" || $bp["right"]["width"] <= 0 )
|
||||
continue;
|
||||
|
||||
$x = $right_col["x"] + $right_col["used-width"] + $bp["right"]["width"] / 2;
|
||||
|
||||
$widths = array($bp["top"]["width"],
|
||||
$bp["right"]["width"],
|
||||
$bp["bottom"]["width"],
|
||||
$bp["left"]["width"]);
|
||||
|
||||
$method = "_border_" . $bp["right"]["style"];
|
||||
$this->$method($x, $y, $h, $bp["right"]["color"], $widths, "right", "square");
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
334
application/helpers/dompdf/include/table_frame_decorator.cls.php
Executable file
334
application/helpers/dompdf/include/table_frame_decorator.cls.php
Executable file
@@ -0,0 +1,334 @@
|
||||
<?php
|
||||
/**
|
||||
* @package dompdf
|
||||
* @link http://dompdf.github.com/
|
||||
* @author Benj Carson <benjcarson@digitaljunkies.ca>
|
||||
* @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
|
||||
*/
|
||||
|
||||
/**
|
||||
* Decorates Frames for table layout
|
||||
*
|
||||
* @access private
|
||||
* @package dompdf
|
||||
*/
|
||||
class Table_Frame_Decorator extends Frame_Decorator {
|
||||
static $VALID_CHILDREN = array("table-row-group",
|
||||
"table-row",
|
||||
"table-header-group",
|
||||
"table-footer-group",
|
||||
"table-column",
|
||||
"table-column-group",
|
||||
"table-caption",
|
||||
"table-cell");
|
||||
|
||||
static $ROW_GROUPS = array('table-row-group',
|
||||
'table-header-group',
|
||||
'table-footer-group');
|
||||
|
||||
/**
|
||||
* The Cellmap object for this table. The cellmap maps table cells
|
||||
* to rows and columns, and aids in calculating column widths.
|
||||
*
|
||||
* @var Cellmap
|
||||
*/
|
||||
protected $_cellmap;
|
||||
|
||||
/**
|
||||
* The minimum width of the table, in pt
|
||||
*
|
||||
* @var float
|
||||
*/
|
||||
protected $_min_width;
|
||||
|
||||
/**
|
||||
* The maximum width of the table, in pt
|
||||
*
|
||||
* @var float
|
||||
*/
|
||||
protected $_max_width;
|
||||
|
||||
/**
|
||||
* Table header rows. Each table header is duplicated when a table
|
||||
* spans pages.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $_headers;
|
||||
|
||||
/**
|
||||
* Table footer rows. Each table footer is duplicated when a table
|
||||
* spans pages.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $_footers;
|
||||
|
||||
/**
|
||||
* Class constructor
|
||||
*
|
||||
* @param Frame $frame the frame to decorate
|
||||
* @param DOMPDF $dompdf
|
||||
*/
|
||||
function __construct(Frame $frame, DOMPDF $dompdf) {
|
||||
parent::__construct($frame, $dompdf);
|
||||
$this->_cellmap = new Cellmap($this);
|
||||
|
||||
if ( $frame->get_style()->table_layout === "fixed" ) {
|
||||
$this->_cellmap->set_layout_fixed(true);
|
||||
}
|
||||
|
||||
$this->_min_width = null;
|
||||
$this->_max_width = null;
|
||||
$this->_headers = array();
|
||||
$this->_footers = array();
|
||||
}
|
||||
|
||||
|
||||
function reset() {
|
||||
parent::reset();
|
||||
$this->_cellmap->reset();
|
||||
$this->_min_width = null;
|
||||
$this->_max_width = null;
|
||||
$this->_headers = array();
|
||||
$this->_footers = array();
|
||||
$this->_reflower->reset();
|
||||
}
|
||||
|
||||
//........................................................................
|
||||
|
||||
/**
|
||||
* split the table at $row. $row and all subsequent rows will be
|
||||
* added to the clone. This method is overidden in order to remove
|
||||
* frames from the cellmap properly.
|
||||
*
|
||||
* @param Frame $child
|
||||
* @param bool $force_pagebreak
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function split(Frame $child = null, $force_pagebreak = false) {
|
||||
|
||||
if ( is_null($child) ) {
|
||||
parent::split();
|
||||
return;
|
||||
}
|
||||
|
||||
// If $child is a header or if it is the first non-header row, do
|
||||
// not duplicate headers, simply move the table to the next page.
|
||||
if ( count($this->_headers) && !in_array($child, $this->_headers, true) &&
|
||||
!in_array($child->get_prev_sibling(), $this->_headers, true) ) {
|
||||
|
||||
$first_header = null;
|
||||
|
||||
// Insert copies of the table headers before $child
|
||||
foreach ($this->_headers as $header) {
|
||||
|
||||
$new_header = $header->deep_copy();
|
||||
|
||||
if ( is_null($first_header) )
|
||||
$first_header = $new_header;
|
||||
|
||||
$this->insert_child_before($new_header, $child);
|
||||
}
|
||||
|
||||
parent::split($first_header);
|
||||
|
||||
} else if ( in_array($child->get_style()->display, self::$ROW_GROUPS) ) {
|
||||
|
||||
// Individual rows should have already been handled
|
||||
parent::split($child);
|
||||
|
||||
} else {
|
||||
|
||||
$iter = $child;
|
||||
|
||||
while ($iter) {
|
||||
$this->_cellmap->remove_row($iter);
|
||||
$iter = $iter->get_next_sibling();
|
||||
}
|
||||
|
||||
parent::split($child);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a copy of this frame with $node as its node
|
||||
*
|
||||
* @param DOMNode $node
|
||||
* @return Frame
|
||||
*/
|
||||
function copy(DOMNode $node) {
|
||||
$deco = parent::copy($node);
|
||||
|
||||
// In order to keep columns' widths through pages
|
||||
$deco->_cellmap->set_columns($this->_cellmap->get_columns());
|
||||
$deco->_cellmap->lock_columns();
|
||||
|
||||
return $deco;
|
||||
}
|
||||
|
||||
/**
|
||||
* Static function to locate the parent table of a frame
|
||||
*
|
||||
* @param Frame $frame
|
||||
* @return Table_Frame_Decorator the table that is an ancestor of $frame
|
||||
*/
|
||||
static function find_parent_table(Frame $frame) {
|
||||
|
||||
while ( $frame = $frame->get_parent() )
|
||||
if ( $frame->is_table() )
|
||||
break;
|
||||
|
||||
return $frame;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return this table's Cellmap
|
||||
*
|
||||
* @return Cellmap
|
||||
*/
|
||||
function get_cellmap() { return $this->_cellmap; }
|
||||
|
||||
/**
|
||||
* Return the minimum width of this table
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
function get_min_width() { return $this->_min_width; }
|
||||
|
||||
/**
|
||||
* Return the maximum width of this table
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
function get_max_width() { return $this->_max_width; }
|
||||
|
||||
/**
|
||||
* Set the minimum width of the table
|
||||
*
|
||||
* @param float $width the new minimum width
|
||||
*/
|
||||
function set_min_width($width) { $this->_min_width = $width; }
|
||||
|
||||
/**
|
||||
* Set the maximum width of the table
|
||||
*
|
||||
* @param float $width the new maximum width
|
||||
*/
|
||||
function set_max_width($width) { $this->_max_width = $width; }
|
||||
|
||||
/**
|
||||
* Restructure tree so that the table has the correct structure.
|
||||
* Invalid children (i.e. all non-table-rows) are moved below the
|
||||
* table.
|
||||
*/
|
||||
function normalise() {
|
||||
|
||||
// Store frames generated by invalid tags and move them outside the table
|
||||
$erroneous_frames = array();
|
||||
$anon_row = false;
|
||||
$iter = $this->get_first_child();
|
||||
while ( $iter ) {
|
||||
$child = $iter;
|
||||
$iter = $iter->get_next_sibling();
|
||||
|
||||
$display = $child->get_style()->display;
|
||||
|
||||
if ( $anon_row ) {
|
||||
|
||||
if ( $display === "table-row" ) {
|
||||
// Add the previous anonymous row
|
||||
$this->insert_child_before($table_row, $child);
|
||||
|
||||
$table_row->normalise();
|
||||
$child->normalise();
|
||||
$anon_row = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
// add the child to the anonymous row
|
||||
$table_row->append_child($child);
|
||||
continue;
|
||||
|
||||
} else {
|
||||
|
||||
if ( $display === "table-row" ) {
|
||||
$child->normalise();
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( $display === "table-cell" ) {
|
||||
// Create an anonymous table row
|
||||
$tr = $this->get_node()->ownerDocument->createElement("tr");
|
||||
|
||||
$frame = new Frame($tr);
|
||||
|
||||
$css = $this->get_style()->get_stylesheet();
|
||||
$style = $css->create_style();
|
||||
$style->inherit($this->get_style());
|
||||
|
||||
// Lookup styles for tr tags. If the user wants styles to work
|
||||
// better, they should make the tr explicit... I'm not going to
|
||||
// try to guess what they intended.
|
||||
if ( $tr_style = $css->lookup("tr") )
|
||||
$style->merge($tr_style);
|
||||
|
||||
// Okay, I have absolutely no idea why I need this clone here, but
|
||||
// if it's omitted, php (as of 2004-07-28) segfaults.
|
||||
$frame->set_style(clone $style);
|
||||
$table_row = Frame_Factory::decorate_frame($frame, $this->_dompdf, $this->_root);
|
||||
|
||||
// Add the cell to the row
|
||||
$table_row->append_child($child);
|
||||
|
||||
$anon_row = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( !in_array($display, self::$VALID_CHILDREN) ) {
|
||||
$erroneous_frames[] = $child;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Normalise other table parts (i.e. row groups)
|
||||
foreach ($child->get_children() as $grandchild) {
|
||||
if ( $grandchild->get_style()->display === "table-row" ) {
|
||||
$grandchild->normalise();
|
||||
}
|
||||
}
|
||||
|
||||
// Add headers and footers
|
||||
if ( $display === "table-header-group" )
|
||||
$this->_headers[] = $child;
|
||||
|
||||
else if ( $display === "table-footer-group" )
|
||||
$this->_footers[] = $child;
|
||||
}
|
||||
}
|
||||
|
||||
if ( $anon_row ) {
|
||||
// Add the row to the table
|
||||
$this->_frame->append_child($table_row);
|
||||
$table_row->normalise();
|
||||
$this->_cellmap->add_row();
|
||||
}
|
||||
|
||||
foreach ($erroneous_frames as $frame)
|
||||
$this->move_after($frame);
|
||||
|
||||
}
|
||||
|
||||
//........................................................................
|
||||
|
||||
/**
|
||||
* Moves the specified frame and it's corresponding node outside of
|
||||
* the table.
|
||||
*
|
||||
* @param Frame $frame the frame to move
|
||||
*/
|
||||
function move_after(Frame $frame) {
|
||||
$this->get_parent()->insert_child_after($frame, $this);
|
||||
}
|
||||
|
||||
}
|
||||
578
application/helpers/dompdf/include/table_frame_reflower.cls.php
Executable file
578
application/helpers/dompdf/include/table_frame_reflower.cls.php
Executable file
@@ -0,0 +1,578 @@
|
||||
<?php
|
||||
/**
|
||||
* @package dompdf
|
||||
* @link http://dompdf.github.com/
|
||||
* @author Benj Carson <benjcarson@digitaljunkies.ca>
|
||||
* @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
|
||||
*/
|
||||
|
||||
/**
|
||||
* Reflows tables
|
||||
*
|
||||
* @access private
|
||||
* @package dompdf
|
||||
*/
|
||||
class Table_Frame_Reflower extends Frame_Reflower {
|
||||
/**
|
||||
* Frame for this reflower
|
||||
*
|
||||
* @var Table_Frame_Decorator
|
||||
*/
|
||||
protected $_frame;
|
||||
|
||||
/**
|
||||
* Cache of results between call to get_min_max_width and assign_widths
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $_state;
|
||||
|
||||
function __construct(Table_Frame_Decorator $frame) {
|
||||
$this->_state = null;
|
||||
parent::__construct($frame);
|
||||
}
|
||||
|
||||
/**
|
||||
* State is held here so it needs to be reset along with the decorator
|
||||
*/
|
||||
function reset() {
|
||||
$this->_state = null;
|
||||
$this->_min_max_cache = null;
|
||||
}
|
||||
|
||||
//........................................................................
|
||||
|
||||
protected function _assign_widths() {
|
||||
$style = $this->_frame->get_style();
|
||||
|
||||
// Find the min/max width of the table and sort the columns into
|
||||
// absolute/percent/auto arrays
|
||||
$min_width = $this->_state["min_width"];
|
||||
$max_width = $this->_state["max_width"];
|
||||
$percent_used = $this->_state["percent_used"];
|
||||
$absolute_used = $this->_state["absolute_used"];
|
||||
$auto_min = $this->_state["auto_min"];
|
||||
|
||||
$absolute =& $this->_state["absolute"];
|
||||
$percent =& $this->_state["percent"];
|
||||
$auto =& $this->_state["auto"];
|
||||
|
||||
// Determine the actual width of the table
|
||||
$cb = $this->_frame->get_containing_block();
|
||||
$columns =& $this->_frame->get_cellmap()->get_columns();
|
||||
|
||||
$width = $style->width;
|
||||
|
||||
// Calculate padding & border fudge factor
|
||||
$left = $style->margin_left;
|
||||
$right = $style->margin_right;
|
||||
|
||||
$centered = ( $left === "auto" && $right === "auto" );
|
||||
|
||||
$left = $left === "auto" ? 0 : $style->length_in_pt($left, $cb["w"]);
|
||||
$right = $right === "auto" ? 0 : $style->length_in_pt($right, $cb["w"]);
|
||||
|
||||
$delta = $left + $right;
|
||||
|
||||
if ( !$centered ) {
|
||||
$delta += $style->length_in_pt(array(
|
||||
$style->padding_left,
|
||||
$style->border_left_width,
|
||||
$style->border_right_width,
|
||||
$style->padding_right),
|
||||
$cb["w"]);
|
||||
}
|
||||
|
||||
$min_table_width = $style->length_in_pt( $style->min_width, $cb["w"] - $delta );
|
||||
|
||||
// min & max widths already include borders & padding
|
||||
$min_width -= $delta;
|
||||
$max_width -= $delta;
|
||||
|
||||
if ( $width !== "auto" ) {
|
||||
|
||||
$preferred_width = $style->length_in_pt($width, $cb["w"]) - $delta;
|
||||
|
||||
if ( $preferred_width < $min_table_width )
|
||||
$preferred_width = $min_table_width;
|
||||
|
||||
if ( $preferred_width > $min_width )
|
||||
$width = $preferred_width;
|
||||
else
|
||||
$width = $min_width;
|
||||
|
||||
} else {
|
||||
|
||||
if ( $max_width + $delta < $cb["w"] )
|
||||
$width = $max_width;
|
||||
else if ( $cb["w"] - $delta > $min_width )
|
||||
$width = $cb["w"] - $delta;
|
||||
else
|
||||
$width = $min_width;
|
||||
|
||||
if ( $width < $min_table_width )
|
||||
$width = $min_table_width;
|
||||
|
||||
}
|
||||
|
||||
// Store our resolved width
|
||||
$style->width = $width;
|
||||
|
||||
$cellmap = $this->_frame->get_cellmap();
|
||||
|
||||
if ( $cellmap->is_columns_locked() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If the whole table fits on the page, then assign each column it's max width
|
||||
if ( $width == $max_width ) {
|
||||
|
||||
foreach (array_keys($columns) as $i)
|
||||
$cellmap->set_column_width($i, $columns[$i]["max-width"]);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Determine leftover and assign it evenly to all columns
|
||||
if ( $width > $min_width ) {
|
||||
|
||||
// We have four cases to deal with:
|
||||
//
|
||||
// 1. All columns are auto--no widths have been specified. In this
|
||||
// case we distribute extra space across all columns weighted by max-width.
|
||||
//
|
||||
// 2. Only absolute widths have been specified. In this case we
|
||||
// distribute any extra space equally among 'width: auto' columns, or all
|
||||
// columns if no auto columns have been specified.
|
||||
//
|
||||
// 3. Only percentage widths have been specified. In this case we
|
||||
// normalize the percentage values and distribute any remaining % to
|
||||
// width: auto columns. We then proceed to assign widths as fractions
|
||||
// of the table width.
|
||||
//
|
||||
// 4. Both absolute and percentage widths have been specified.
|
||||
|
||||
$increment = 0;
|
||||
|
||||
// Case 1:
|
||||
if ( $absolute_used == 0 && $percent_used == 0 ) {
|
||||
$increment = $width - $min_width;
|
||||
|
||||
foreach (array_keys($columns) as $i) {
|
||||
$cellmap->set_column_width($i, $columns[$i]["min-width"] + $increment * ($columns[$i]["max-width"] / $max_width));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Case 2
|
||||
if ( $absolute_used > 0 && $percent_used == 0 ) {
|
||||
|
||||
if ( count($auto) > 0 )
|
||||
$increment = ($width - $auto_min - $absolute_used) / count($auto);
|
||||
|
||||
// Use the absolutely specified width or the increment
|
||||
foreach (array_keys($columns) as $i) {
|
||||
|
||||
if ( $columns[$i]["absolute"] > 0 && count($auto) )
|
||||
$cellmap->set_column_width($i, $columns[$i]["min-width"]);
|
||||
else if ( count($auto) )
|
||||
$cellmap->set_column_width($i, $columns[$i]["min-width"] + $increment);
|
||||
else {
|
||||
// All absolute columns
|
||||
$increment = ($width - $absolute_used) * $columns[$i]["absolute"] / $absolute_used;
|
||||
|
||||
$cellmap->set_column_width($i, $columns[$i]["min-width"] + $increment);
|
||||
}
|
||||
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Case 3:
|
||||
if ( $absolute_used == 0 && $percent_used > 0 ) {
|
||||
|
||||
$scale = null;
|
||||
$remaining = null;
|
||||
|
||||
// Scale percent values if the total percentage is > 100, or if all
|
||||
// values are specified as percentages.
|
||||
if ( $percent_used > 100 || count($auto) == 0)
|
||||
$scale = 100 / $percent_used;
|
||||
else
|
||||
$scale = 1;
|
||||
|
||||
// Account for the minimum space used by the unassigned auto columns
|
||||
$used_width = $auto_min;
|
||||
|
||||
foreach ($percent as $i) {
|
||||
$columns[$i]["percent"] *= $scale;
|
||||
|
||||
$slack = $width - $used_width;
|
||||
|
||||
$w = min($columns[$i]["percent"] * $width/100, $slack);
|
||||
|
||||
if ( $w < $columns[$i]["min-width"] )
|
||||
$w = $columns[$i]["min-width"];
|
||||
|
||||
$cellmap->set_column_width($i, $w);
|
||||
$used_width += $w;
|
||||
|
||||
}
|
||||
|
||||
// This works because $used_width includes the min-width of each
|
||||
// unassigned column
|
||||
if ( count($auto) > 0 ) {
|
||||
$increment = ($width - $used_width) / count($auto);
|
||||
|
||||
foreach ($auto as $i)
|
||||
$cellmap->set_column_width($i, $columns[$i]["min-width"] + $increment);
|
||||
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Case 4:
|
||||
|
||||
// First-come, first served
|
||||
if ( $absolute_used > 0 && $percent_used > 0 ) {
|
||||
|
||||
$used_width = $auto_min;
|
||||
|
||||
foreach ($absolute as $i) {
|
||||
$cellmap->set_column_width($i, $columns[$i]["min-width"]);
|
||||
$used_width += $columns[$i]["min-width"];
|
||||
}
|
||||
|
||||
// Scale percent values if the total percentage is > 100 or there
|
||||
// are no auto values to take up slack
|
||||
if ( $percent_used > 100 || count($auto) == 0 )
|
||||
$scale = 100 / $percent_used;
|
||||
else
|
||||
$scale = 1;
|
||||
|
||||
$remaining_width = $width - $used_width;
|
||||
|
||||
foreach ($percent as $i) {
|
||||
$slack = $remaining_width - $used_width;
|
||||
|
||||
$columns[$i]["percent"] *= $scale;
|
||||
$w = min($columns[$i]["percent"] * $remaining_width / 100, $slack);
|
||||
|
||||
if ( $w < $columns[$i]["min-width"] )
|
||||
$w = $columns[$i]["min-width"];
|
||||
|
||||
$columns[$i]["used-width"] = $w;
|
||||
$used_width += $w;
|
||||
}
|
||||
|
||||
if ( count($auto) > 0 ) {
|
||||
$increment = ($width - $used_width) / count($auto);
|
||||
|
||||
foreach ($auto as $i)
|
||||
$cellmap->set_column_width($i, $columns[$i]["min-width"] + $increment);
|
||||
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
} else { // we are over constrained
|
||||
|
||||
// Each column gets its minimum width
|
||||
foreach (array_keys($columns) as $i)
|
||||
$cellmap->set_column_width($i, $columns[$i]["min-width"]);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
//........................................................................
|
||||
|
||||
// Determine the frame's height based on min/max height
|
||||
protected function _calculate_height() {
|
||||
|
||||
$style = $this->_frame->get_style();
|
||||
$height = $style->height;
|
||||
|
||||
$cellmap = $this->_frame->get_cellmap();
|
||||
$cellmap->assign_frame_heights();
|
||||
$rows = $cellmap->get_rows();
|
||||
|
||||
// Determine our content height
|
||||
$content_height = 0;
|
||||
foreach ( $rows as $r )
|
||||
$content_height += $r["height"];
|
||||
|
||||
$cb = $this->_frame->get_containing_block();
|
||||
|
||||
if ( !($style->overflow === "visible" ||
|
||||
($style->overflow === "hidden" && $height === "auto")) ) {
|
||||
|
||||
// Only handle min/max height if the height is independent of the frame's content
|
||||
|
||||
$min_height = $style->min_height;
|
||||
$max_height = $style->max_height;
|
||||
|
||||
if ( isset($cb["h"]) ) {
|
||||
$min_height = $style->length_in_pt($min_height, $cb["h"]);
|
||||
$max_height = $style->length_in_pt($max_height, $cb["h"]);
|
||||
|
||||
} else if ( isset($cb["w"]) ) {
|
||||
|
||||
if ( mb_strpos($min_height, "%") !== false )
|
||||
$min_height = 0;
|
||||
else
|
||||
$min_height = $style->length_in_pt($min_height, $cb["w"]);
|
||||
|
||||
if ( mb_strpos($max_height, "%") !== false )
|
||||
$max_height = "none";
|
||||
else
|
||||
$max_height = $style->length_in_pt($max_height, $cb["w"]);
|
||||
}
|
||||
|
||||
if ( $max_height !== "none" && $min_height > $max_height )
|
||||
// Swap 'em
|
||||
list($max_height, $min_height) = array($min_height, $max_height);
|
||||
|
||||
if ( $max_height !== "none" && $height > $max_height )
|
||||
$height = $max_height;
|
||||
|
||||
if ( $height < $min_height )
|
||||
$height = $min_height;
|
||||
|
||||
} else {
|
||||
|
||||
// Use the content height or the height value, whichever is greater
|
||||
if ( $height !== "auto" ) {
|
||||
$height = $style->length_in_pt($height, $cb["h"]);
|
||||
|
||||
if ( $height <= $content_height )
|
||||
$height = $content_height;
|
||||
else
|
||||
$cellmap->set_frame_heights($height,$content_height);
|
||||
|
||||
} else
|
||||
$height = $content_height;
|
||||
|
||||
}
|
||||
|
||||
return $height;
|
||||
|
||||
}
|
||||
//........................................................................
|
||||
|
||||
/**
|
||||
* @param Block_Frame_Decorator $block
|
||||
*/
|
||||
function reflow(Block_Frame_Decorator $block = null) {
|
||||
/**
|
||||
* @var Table_Frame_Decorator
|
||||
*/
|
||||
$frame = $this->_frame;
|
||||
|
||||
// Check if a page break is forced
|
||||
$page = $frame->get_root();
|
||||
$page->check_forced_page_break($frame);
|
||||
|
||||
// Bail if the page is full
|
||||
if ( $page->is_full() )
|
||||
return;
|
||||
|
||||
// Let the page know that we're reflowing a table so that splits
|
||||
// are suppressed (simply setting page-break-inside: avoid won't
|
||||
// work because we may have an arbitrary number of block elements
|
||||
// inside tds.)
|
||||
$page->table_reflow_start();
|
||||
|
||||
// Collapse vertical margins, if required
|
||||
$this->_collapse_margins();
|
||||
|
||||
$frame->position();
|
||||
|
||||
// Table layout algorithm:
|
||||
// http://www.w3.org/TR/CSS21/tables.html#auto-table-layout
|
||||
|
||||
if ( is_null($this->_state) )
|
||||
$this->get_min_max_width();
|
||||
|
||||
$cb = $frame->get_containing_block();
|
||||
$style = $frame->get_style();
|
||||
|
||||
// This is slightly inexact, but should be okay. Add half the
|
||||
// border-spacing to the table as padding. The other half is added to
|
||||
// the cells themselves.
|
||||
if ( $style->border_collapse === "separate" ) {
|
||||
list($h, $v) = $style->border_spacing;
|
||||
|
||||
$v = $style->length_in_pt($v) / 2;
|
||||
$h = $style->length_in_pt($h) / 2;
|
||||
|
||||
$style->padding_left = $style->length_in_pt($style->padding_left, $cb["w"]) + $h;
|
||||
$style->padding_right = $style->length_in_pt($style->padding_right, $cb["w"]) + $h;
|
||||
$style->padding_top = $style->length_in_pt($style->padding_top, $cb["h"]) + $v;
|
||||
$style->padding_bottom = $style->length_in_pt($style->padding_bottom, $cb["h"]) + $v;
|
||||
|
||||
}
|
||||
|
||||
$this->_assign_widths();
|
||||
|
||||
// Adjust left & right margins, if they are auto
|
||||
$width = $style->width;
|
||||
$left = $style->margin_left;
|
||||
$right = $style->margin_right;
|
||||
|
||||
$diff = $cb["w"] - $width;
|
||||
|
||||
if ( $left === "auto" && $right === "auto" ) {
|
||||
if ( $diff < 0 ) {
|
||||
$left = 0;
|
||||
$right = $diff;
|
||||
}
|
||||
else {
|
||||
$left = $right = $diff / 2;
|
||||
}
|
||||
|
||||
$style->margin_left = "$left pt";
|
||||
$style->margin_right = "$right pt";
|
||||
|
||||
} else {
|
||||
if ( $left === "auto" ) {
|
||||
$left = $style->length_in_pt($cb["w"] - $right - $width, $cb["w"]);
|
||||
}
|
||||
if ( $right === "auto" ) {
|
||||
$left = $style->length_in_pt($left, $cb["w"]);
|
||||
}
|
||||
}
|
||||
|
||||
list($x, $y) = $frame->get_position();
|
||||
|
||||
// Determine the content edge
|
||||
$content_x = $x + $left + $style->length_in_pt(array($style->padding_left,
|
||||
$style->border_left_width), $cb["w"]);
|
||||
$content_y = $y + $style->length_in_pt(array($style->margin_top,
|
||||
$style->border_top_width,
|
||||
$style->padding_top), $cb["h"]);
|
||||
|
||||
if ( isset($cb["h"]) )
|
||||
$h = $cb["h"];
|
||||
else
|
||||
$h = null;
|
||||
|
||||
$cellmap = $frame->get_cellmap();
|
||||
$col =& $cellmap->get_column(0);
|
||||
$col["x"] = $content_x;
|
||||
|
||||
$row =& $cellmap->get_row(0);
|
||||
$row["y"] = $content_y;
|
||||
|
||||
$cellmap->assign_x_positions();
|
||||
|
||||
// Set the containing block of each child & reflow
|
||||
foreach ( $frame->get_children() as $child ) {
|
||||
|
||||
// Bail if the page is full
|
||||
if ( !$page->in_nested_table() && $page->is_full() )
|
||||
break;
|
||||
|
||||
$child->set_containing_block($content_x, $content_y, $width, $h);
|
||||
$child->reflow();
|
||||
|
||||
if ( !$page->in_nested_table() )
|
||||
// Check if a split has occured
|
||||
$page->check_page_break($child);
|
||||
|
||||
}
|
||||
|
||||
// Assign heights to our cells:
|
||||
$style->height = $this->_calculate_height();
|
||||
|
||||
if ( $style->border_collapse === "collapse" ) {
|
||||
// Unset our borders because our cells are now using them
|
||||
$style->border_style = "none";
|
||||
}
|
||||
|
||||
$page->table_reflow_end();
|
||||
|
||||
// Debugging:
|
||||
//echo ($this->_frame->get_cellmap());
|
||||
|
||||
if ( $block && $style->float === "none" && $frame->is_in_flow() ) {
|
||||
$block->add_frame_to_line($frame);
|
||||
$block->add_line();
|
||||
}
|
||||
}
|
||||
|
||||
//........................................................................
|
||||
|
||||
function get_min_max_width() {
|
||||
|
||||
if ( !is_null($this->_min_max_cache) )
|
||||
return $this->_min_max_cache;
|
||||
|
||||
$style = $this->_frame->get_style();
|
||||
|
||||
$this->_frame->normalise();
|
||||
|
||||
// Add the cells to the cellmap (this will calcluate column widths as
|
||||
// frames are added)
|
||||
$this->_frame->get_cellmap()->add_frame($this->_frame);
|
||||
|
||||
// Find the min/max width of the table and sort the columns into
|
||||
// absolute/percent/auto arrays
|
||||
$this->_state = array();
|
||||
$this->_state["min_width"] = 0;
|
||||
$this->_state["max_width"] = 0;
|
||||
|
||||
$this->_state["percent_used"] = 0;
|
||||
$this->_state["absolute_used"] = 0;
|
||||
$this->_state["auto_min"] = 0;
|
||||
|
||||
$this->_state["absolute"] = array();
|
||||
$this->_state["percent"] = array();
|
||||
$this->_state["auto"] = array();
|
||||
|
||||
$columns =& $this->_frame->get_cellmap()->get_columns();
|
||||
foreach (array_keys($columns) as $i) {
|
||||
$this->_state["min_width"] += $columns[$i]["min-width"];
|
||||
$this->_state["max_width"] += $columns[$i]["max-width"];
|
||||
|
||||
if ( $columns[$i]["absolute"] > 0 ) {
|
||||
$this->_state["absolute"][] = $i;
|
||||
$this->_state["absolute_used"] += $columns[$i]["absolute"];
|
||||
|
||||
} else if ( $columns[$i]["percent"] > 0 ) {
|
||||
$this->_state["percent"][] = $i;
|
||||
$this->_state["percent_used"] += $columns[$i]["percent"];
|
||||
|
||||
} else {
|
||||
$this->_state["auto"][] = $i;
|
||||
$this->_state["auto_min"] += $columns[$i]["min-width"];
|
||||
}
|
||||
}
|
||||
|
||||
// Account for margins & padding
|
||||
$dims = array($style->border_left_width,
|
||||
$style->border_right_width,
|
||||
$style->padding_left,
|
||||
$style->padding_right,
|
||||
$style->margin_left,
|
||||
$style->margin_right);
|
||||
|
||||
if ( $style->border_collapse !== "collapse" )
|
||||
list($dims[]) = $style->border_spacing;
|
||||
|
||||
$delta = $style->length_in_pt($dims, $this->_frame->get_containing_block("w"));
|
||||
|
||||
$this->_state["min_width"] += $delta;
|
||||
$this->_state["max_width"] += $delta;
|
||||
|
||||
return $this->_min_max_cache = array(
|
||||
$this->_state["min_width"],
|
||||
$this->_state["max_width"],
|
||||
"min" => $this->_state["min_width"],
|
||||
"max" => $this->_state["max_width"],
|
||||
);
|
||||
}
|
||||
}
|
||||
48
application/helpers/dompdf/include/table_row_frame_decorator.cls.php
Executable file
48
application/helpers/dompdf/include/table_row_frame_decorator.cls.php
Executable file
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
/**
|
||||
* @package dompdf
|
||||
* @link http://dompdf.github.com/
|
||||
* @author Benj Carson <benjcarson@digitaljunkies.ca>
|
||||
* @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
|
||||
*/
|
||||
|
||||
/**
|
||||
* Decorates Frames for table row layout
|
||||
*
|
||||
* @access private
|
||||
* @package dompdf
|
||||
*/
|
||||
class Table_Row_Frame_Decorator extends Frame_Decorator {
|
||||
|
||||
// protected members
|
||||
|
||||
function __construct(Frame $frame, DOMPDF $dompdf) {
|
||||
parent::__construct($frame, $dompdf);
|
||||
}
|
||||
|
||||
//........................................................................
|
||||
|
||||
/**
|
||||
* Remove all non table-cell frames from this row and move them after
|
||||
* the table.
|
||||
*/
|
||||
function normalise() {
|
||||
|
||||
// Find our table parent
|
||||
$p = Table_Frame_Decorator::find_parent_table($this);
|
||||
|
||||
$erroneous_frames = array();
|
||||
foreach ($this->get_children() as $child) {
|
||||
$display = $child->get_style()->display;
|
||||
|
||||
if ( $display !== "table-cell" )
|
||||
$erroneous_frames[] = $child;
|
||||
}
|
||||
|
||||
// dump the extra nodes after the table.
|
||||
foreach ($erroneous_frames as $frame)
|
||||
$p->move_after($frame);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
61
application/helpers/dompdf/include/table_row_frame_reflower.cls.php
Executable file
61
application/helpers/dompdf/include/table_row_frame_reflower.cls.php
Executable file
@@ -0,0 +1,61 @@
|
||||
<?php
|
||||
/**
|
||||
* @package dompdf
|
||||
* @link http://dompdf.github.com/
|
||||
* @author Benj Carson <benjcarson@digitaljunkies.ca>
|
||||
* @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
|
||||
*/
|
||||
|
||||
/**
|
||||
* Reflows table rows
|
||||
*
|
||||
* @access private
|
||||
* @package dompdf
|
||||
*/
|
||||
class Table_Row_Frame_Reflower extends Frame_Reflower {
|
||||
|
||||
|
||||
function __construct(Table_Row_Frame_Decorator $frame) {
|
||||
parent::__construct($frame);
|
||||
}
|
||||
|
||||
//........................................................................
|
||||
|
||||
function reflow(Block_Frame_Decorator $block = null) {
|
||||
$page = $this->_frame->get_root();
|
||||
|
||||
if ( $page->is_full() )
|
||||
return;
|
||||
|
||||
$this->_frame->position();
|
||||
$style = $this->_frame->get_style();
|
||||
$cb = $this->_frame->get_containing_block();
|
||||
|
||||
foreach ($this->_frame->get_children() as $child) {
|
||||
|
||||
if ( $page->is_full() )
|
||||
return;
|
||||
|
||||
$child->set_containing_block($cb);
|
||||
$child->reflow();
|
||||
|
||||
}
|
||||
|
||||
if ( $page->is_full() )
|
||||
return;
|
||||
|
||||
$table = Table_Frame_Decorator::find_parent_table($this->_frame);
|
||||
$cellmap = $table->get_cellmap();
|
||||
$style->width = $cellmap->get_frame_width($this->_frame);
|
||||
$style->height = $cellmap->get_frame_height($this->_frame);
|
||||
|
||||
$this->_frame->set_position($cellmap->get_frame_position($this->_frame));
|
||||
|
||||
}
|
||||
|
||||
//........................................................................
|
||||
|
||||
function get_min_max_width() {
|
||||
throw new DOMPDF_Exception("Min/max width is undefined for table rows");
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user