Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Initial commit

  • Loading branch information...
commit bfbf3afb13fa699b044bae4163e1848a63976749 1 parent 31f5397
tokolist@gmail.com authored
Showing with 5,222 additions and 0 deletions.
  1. BIN  css/bg.gif
  2. +160 −0 css/form.css
  3. +36 −0 css/ie.css
  4. +229 −0 css/main.css
  5. +29 −0 css/print.css
  6. +238 −0 css/screen.css
  7. +15 −0 index-test.php
  8. +13 −0 index.php
  9. +7 −0 nbproject/project.properties
  10. +9 −0 nbproject/project.xml
  11. +1 −0  protected/.htaccess
  12. +23 −0 protected/components/Controller.php
  13. +33 −0 protected/components/UserIdentity.php
  14. +24 −0 protected/config/console.php
  15. +90 −0 protected/config/main.php
  16. +17 −0 protected/config/test.php
  17. +103 −0 protected/controllers/SiteController.php
  18. +28 −0 protected/data/schema.mysql.sql
  19. +28 −0 protected/data/schema.sqlite.sql
  20. BIN  protected/data/testdrive.db
  21. +69 −0 protected/extensions/yiicomp/behaviors/DateTimeBehavior/CDateTimeBehavior.php
  22. +209 −0 protected/extensions/yiicomp/behaviors/TreeComments/CTreeCommentsControllerBehavior.php
  23. +75 −0 protected/extensions/yiicomp/behaviors/TreeComments/CTreeCommentsModelBehavior.php
  24. +112 −0 protected/extensions/yiicomp/behaviors/TreeComments/js/comments_tree.js
  25. +14 −0 protected/extensions/yiicomp/behaviors/TreeComments/schema.sql
  26. +23 −0 protected/extensions/yiicomp/behaviors/TreeComments/views/comment.php
  27. +15 −0 protected/extensions/yiicomp/behaviors/TreeComments/views/comments.php
  28. +1 −0  protected/extensions/yiicomp/behaviors/TreeComments/views/errors.php
  29. +23 −0 protected/extensions/yiicomp/behaviors/TreeComments/views/form.php
  30. +27 −0 protected/extensions/yiicomp/components/ButtonColumnEx/CButtonColumnEx.php
  31. +597 −0 protected/extensions/yiicomp/components/ImageHandler/CImageHandler.php
  32. +107 −0 protected/extensions/yiicomp/components/LangUrlManager/CLangUrlManager.php
  33. +91 −0 protected/extensions/yiicomp/components/TimeZoneHelper/CTimeZoneHelper.php
  34. +140 −0 protected/extensions/yiicomp/components/TimeZoneHelper/timezones.csv
  35. +217 −0 protected/extensions/yiicomp/helpers/StringHelper/CStringHelper.php
  36. +123 −0 protected/extensions/yiicomp/widgets/TagCloud/CTagCloud.php
  37. +112 −0 protected/extensions/yiicomp/widgets/YiiJevix/CJevixEx.php
  38. +57 −0 protected/extensions/yiicomp/widgets/YiiJevix/CYiiJevix.php
  39. +1,369 −0 protected/extensions/yiicomp/widgets/YiiJevix/jevix/jevix.class.php
  40. +52 −0 protected/extensions/yiicomp/widgets/YiiJevix/jevix/symclass.php
  41. +157 −0 protected/extensions/yiicomp/widgets/YiiJevix/jevix/tests/jevixtest.php
  42. +53 −0 protected/extensions/yiicomp/widgets/YiiJevix/readme.txt
  43. +42 −0 protected/models/ContactForm.php
  44. +77 −0 protected/models/LoginForm.php
  45. +25 −0 protected/tests/WebTestCase.php
  46. +10 −0 protected/tests/bootstrap.php
  47. +47 −0 protected/tests/functional/SiteTest.php
  48. +13 −0 protected/tests/phpunit.xml
  49. +7 −0 protected/views/layouts/column1.php
  50. +23 −0 protected/views/layouts/column2.php
  51. +56 −0 protected/views/layouts/main.php
  52. +81 −0 protected/views/site/contact.php
  53. +12 −0 protected/views/site/error.php
  54. +16 −0 protected/views/site/index.php
  55. +49 −0 protected/views/site/login.php
  56. +10 −0 protected/views/site/pages/about.php
  57. +4 −0 protected/yiic
  58. +16 −0 protected/yiic.bat
  59. +7 −0 protected/yiic.php
  60. +1 −0  themes/classic/views/.htaccess
View
BIN  css/bg.gif
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
160 css/form.css
@@ -0,0 +1,160 @@
+/**
+ * CSS styles for forms generated by yiic.
+ *
+ * The styles can be applied to the following form structure:
+ *
+ * <div class="form">
+ * <div class="row">
+ * <label for="inputid">xyz</label>
+ * <input name="inputid" id="inputid" type="text" />
+ * <p class="hint">hint text</p>
+ * </div>
+ * <div class="row">
+ * <label for="inputid">xyz</label>
+ * <input name="inputid" id="inputid" type="text" />
+ * <p class="hint">hint text</p>
+ * </div>
+ * <div class="row buttons">
+ * <label for="inputid">xyz</label>
+ * <input name="inputid" id="inputid" type="text" />
+ * <p class="hint">hint text</p>
+ * </div>
+ * </div>
+ *
+ * The above code will render the labels and input fields in separate lines.
+ * In order to render them in the same line, please use the "wide" form as follows,
+ *
+ * <div class="wide form">
+ * ......
+ * </div>
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link http://www.yiiframework.com/
+ * @copyright Copyright &copy; 2008-2010 Yii Software LLC
+ * @license http://www.yiiframework.com/license/
+ */
+
+div.form
+{
+}
+
+div.form input,
+div.form textarea,
+div.form select
+{
+ margin: 0.2em 0 0.5em 0;
+}
+
+div.form fieldset
+{
+ border: 1px solid #DDD;
+ padding: 10px;
+ margin: 0 0 10px 0;
+ -moz-border-radius:7px;
+}
+
+div.form label
+{
+ font-weight: bold;
+ font-size: 0.9em;
+ display: block;
+}
+
+div.form .row
+{
+ margin: 5px 0;
+}
+
+div.form .hint
+{
+ margin: 0;
+ padding: 0;
+ color: #999;
+}
+
+div.form .note
+{
+ font-style: italic;
+}
+
+div.form span.required
+{
+ color: red;
+}
+
+div.form div.error label,
+div.form label.error,
+div.form span.error
+{
+ color: #C00;
+}
+
+div.form div.error input,
+div.form div.error textarea,
+div.form div.error select,
+div.form input.error,
+div.form textarea.error,
+div.form select.error
+{
+ background: #FEE;
+ border-color: #C00;
+}
+
+div.form div.success input,
+div.form div.success textarea,
+div.form div.success select,
+div.form input.success,
+div.form textarea.success,
+div.form select.success
+{
+ background: #E6EFC2;
+ border-color: #C6D880;
+}
+
+
+div.form .errorSummary
+{
+ border: 2px solid #C00;
+ padding: 7px 7px 12px 7px;
+ margin: 0 0 20px 0;
+ background: #FEE;
+ font-size: 0.9em;
+}
+
+div.form .errorMessage
+{
+ color: red;
+ font-size: 0.9em;
+}
+
+div.form .errorSummary p
+{
+ margin: 0;
+ padding: 5px;
+}
+
+div.form .errorSummary ul
+{
+ margin: 0;
+ padding: 0 0 0 20px;
+}
+
+div.wide.form label
+{
+ float: left;
+ margin-right: 10px;
+ position: relative;
+ text-align: right;
+ width: 100px;
+}
+
+div.wide.form .row
+{
+ clear: left;
+}
+
+div.wide.form .buttons, div.wide.form .hint, div.wide.form .errorMessage
+{
+ clear: left;
+ padding-left: 110px;
+}
View
36 css/ie.css
@@ -0,0 +1,36 @@
+/* -----------------------------------------------------------------------
+
+
+ Blueprint CSS Framework 1.0.1
+ http://blueprintcss.org
+
+ * Copyright (c) 2007-Present. See LICENSE for more info.
+ * See README for instructions on how to use Blueprint.
+ * For credits and origins, see AUTHORS.
+ * This is a compressed file. See the sources in the 'src' directory.
+
+----------------------------------------------------------------------- */
+
+/* ie.css */
+body {text-align:center;}
+.container {text-align:left;}
+* html .column, * html .span-1, * html .span-2, * html .span-3, * html .span-4, * html .span-5, * html .span-6, * html .span-7, * html .span-8, * html .span-9, * html .span-10, * html .span-11, * html .span-12, * html .span-13, * html .span-14, * html .span-15, * html .span-16, * html .span-17, * html .span-18, * html .span-19, * html .span-20, * html .span-21, * html .span-22, * html .span-23, * html .span-24 {display:inline;overflow-x:hidden;}
+* html legend {margin:0px -8px 16px 0;padding:0;}
+sup {vertical-align:text-top;}
+sub {vertical-align:text-bottom;}
+html>body p code {*white-space:normal;}
+hr {margin:-8px auto 11px;}
+img {-ms-interpolation-mode:bicubic;}
+.clearfix, .container {display:inline-block;}
+* html .clearfix, * html .container {height:1%;}
+fieldset {padding-top:0;}
+legend {margin-top:-0.2em;margin-bottom:1em;margin-left:-0.5em;}
+textarea {overflow:auto;}
+label {vertical-align:middle;position:relative;top:-0.25em;}
+input.text, input.title, textarea {background-color:#fff;border:1px solid #bbb;}
+input.text:focus, input.title:focus {border-color:#666;}
+input.text, input.title, textarea, select {margin:0.5em 0;}
+input.checkbox, input.radio {position:relative;top:.25em;}
+form.inline div, form.inline p {vertical-align:middle;}
+form.inline input.checkbox, form.inline input.radio, form.inline input.button, form.inline button {margin:0.5em 0;}
+button, input.button {position:relative;top:0.25em;}
View
229 css/main.css
@@ -0,0 +1,229 @@
+body
+{
+ margin: 0;
+ padding: 0;
+ color: #555;
+ font: normal 10pt Arial,Helvetica,sans-serif;
+ background: #EFEFEF;
+}
+
+#page
+{
+ margin-top: 5px;
+ margin-bottom: 5px;
+ background: white;
+ border: 1px solid #C9E0ED;
+}
+
+#header
+{
+ margin: 0;
+ padding: 0;
+ border-top: 3px solid #C9E0ED;
+}
+
+#content
+{
+ padding: 20px;
+}
+
+#sidebar
+{
+ padding: 20px 20px 20px 0;
+}
+
+#footer
+{
+ padding: 10px;
+ margin: 10px 20px;
+ font-size: 0.8em;
+ text-align: center;
+ border-top: 1px solid #C9E0ED;
+}
+
+#logo
+{
+ padding: 10px 20px;
+ font-size: 200%;
+}
+
+#mainmenu
+{
+ background:white url(bg.gif) repeat-x left top;
+}
+
+#mainmenu ul
+{
+ padding:6px 20px 5px 20px;
+ margin:0px;
+}
+
+#mainmenu ul li
+{
+ display: inline;
+}
+
+#mainmenu ul li a
+{
+ color:#ffffff;
+ background-color:transparent;
+ font-size:12px;
+ font-weight:bold;
+ text-decoration:none;
+ padding:5px 8px;
+}
+
+#mainmenu ul li a:hover, #mainmenu ul li.active a
+{
+ color: #6399cd;
+ background-color:#EFF4FA;
+ text-decoration:none;
+}
+
+div.flash-error, div.flash-notice, div.flash-success
+{
+ padding:.8em;
+ margin-bottom:1em;
+ border:2px solid #ddd;
+}
+
+div.flash-error
+{
+ background:#FBE3E4;
+ color:#8a1f11;
+ border-color:#FBC2C4;
+}
+
+div.flash-notice
+{
+ background:#FFF6BF;
+ color:#514721;
+ border-color:#FFD324;
+}
+
+div.flash-success
+{
+ background:#E6EFC2;
+ color:#264409;
+ border-color:#C6D880;
+}
+
+div.flash-error a
+{
+ color:#8a1f11;
+}
+
+div.flash-notice a
+{
+ color:#514721;
+}
+
+div.flash-success a
+{
+ color:#264409;
+}
+
+div.form .rememberMe label
+{
+ display: inline;
+}
+
+div.view
+{
+ padding: 10px;
+ margin: 10px 0;
+ border: 1px solid #C9E0ED;
+}
+
+div.breadcrumbs
+{
+ font-size: 0.9em;
+ padding: 5px 20px;
+}
+
+div.breadcrumbs span
+{
+ font-weight: bold;
+}
+
+div.search-form
+{
+ padding: 10px;
+ margin: 10px 0;
+ background: #eee;
+}
+
+.portlet
+{
+
+}
+
+.portlet-decoration
+{
+ padding: 3px 8px;
+ background: #B7D6E7;
+ border-left: 5px solid #6FACCF;
+}
+
+.portlet-title
+{
+ font-size: 12px;
+ font-weight: bold;
+ padding: 0;
+ margin: 0;
+ color: #298dcd;
+}
+
+.portlet-content
+{
+ font-size:0.9em;
+ margin: 0 0 15px 0;
+ padding: 5px 8px;
+ background:#EFFDFF;
+}
+
+.portlet-content ul
+{
+ list-style-image:none;
+ list-style-position:outside;
+ list-style-type:none;
+ margin: 0;
+ padding: 0;
+}
+
+.portlet-content li
+{
+ padding: 2px 0 4px 0px;
+}
+
+.operations
+{
+ list-style-type: none;
+ margin: 0;
+ padding: 0;
+}
+
+.operations li
+{
+ padding-bottom: 2px;
+}
+
+.operations li a
+{
+ font: bold 12px Arial;
+ color: #0066A4;
+ display: block;
+ padding: 2px 0 2px 8px;
+ line-height: 15px;
+ text-decoration: none;
+}
+
+.operations li a:visited
+{
+ color: #0066A4;
+}
+
+.operations li a:hover
+{
+ background: #80CFFF;
+}
View
29 css/print.css
@@ -0,0 +1,29 @@
+/* -----------------------------------------------------------------------
+
+
+ Blueprint CSS Framework 1.0.1
+ http://blueprintcss.org
+
+ * Copyright (c) 2007-Present. See LICENSE for more info.
+ * See README for instructions on how to use Blueprint.
+ * For credits and origins, see AUTHORS.
+ * This is a compressed file. See the sources in the 'src' directory.
+
+----------------------------------------------------------------------- */
+
+/* print.css */
+body {line-height:1.5;font-family:"Helvetica Neue", Arial, Helvetica, sans-serif;color:#000;background:none;font-size:10pt;}
+.container {background:none;}
+hr {background:#ccc;color:#ccc;width:100%;height:2px;margin:2em 0;padding:0;border:none;}
+hr.space {background:#fff;color:#fff;visibility:hidden;}
+h1, h2, h3, h4, h5, h6 {font-family:"Helvetica Neue", Arial, "Lucida Grande", sans-serif;}
+code {font:.9em "Courier New", Monaco, Courier, monospace;}
+a img {border:none;}
+p img.top {margin-top:0;}
+blockquote {margin:1.5em;padding:1em;font-style:italic;font-size:.9em;}
+.small {font-size:.9em;}
+.large {font-size:1.1em;}
+.quiet {color:#999;}
+.hide {display:none;}
+a:link, a:visited {background:transparent;font-weight:700;text-decoration:underline;}
+a:link:after, a:visited:after {content:" (" attr(href) ")";font-size:90%;}
View
238 css/screen.css
@@ -0,0 +1,238 @@
+/* -----------------------------------------------------------------------
+
+
+ Blueprint CSS Framework 1.0.1
+ http://blueprintcss.org
+
+ * Copyright (c) 2007-Present. See LICENSE for more info.
+ * See README for instructions on how to use Blueprint.
+ * For credits and origins, see AUTHORS.
+ * This is a compressed file. See the sources in the 'src' directory.
+
+----------------------------------------------------------------------- */
+
+/* reset.css */
+html {margin:0;padding:0;border:0;}
+body, div, span, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, code, del, dfn, em, img, q, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td, article, aside, dialog, figure, footer, header, hgroup, nav, section {margin:0;padding:0;border:0;font-size:100%;font:inherit;vertical-align:baseline;}
+article, aside, details, figcaption, figure, dialog, footer, header, hgroup, menu, nav, section {display:block;}
+body {line-height:1.5;background:white;}
+table {border-collapse:separate;border-spacing:0;}
+caption, th, td {text-align:left;font-weight:normal;float:none !important;}
+table, th, td {vertical-align:middle;}
+blockquote:before, blockquote:after, q:before, q:after {content:'';}
+blockquote, q {quotes:"" "";}
+a img {border:none;}
+:focus {outline:0;}
+
+/* typography.css */
+html {font-size:100.01%;}
+body {font-size:75%;color:#222;background:#fff;font-family:"Helvetica Neue", Arial, Helvetica, sans-serif;}
+h1, h2, h3, h4, h5, h6 {font-weight:normal;color:#111;}
+h1 {font-size:2em;line-height:1;margin-bottom:0.5em;}
+h2 {font-size:1.6em;margin-bottom:0.75em;}
+h3 {font-size:1.4em;line-height:1;margin-bottom:1em;}
+h4 {font-size:1.2em;line-height:1.25;margin-bottom:1.25em;}
+h5 {font-size:1em;font-weight:bold;margin-bottom:1.5em;}
+h6 {font-size:1em;font-weight:bold;}
+h1 img, h2 img, h3 img, h4 img, h5 img, h6 img {margin:0;}
+p {margin:0 0 1.5em;}
+.left {float:left !important;}
+p .left {margin:1.5em 1.5em 1.5em 0;padding:0;}
+.right {float:right !important;}
+p .right {margin:1.5em 0 1.5em 1.5em;padding:0;}
+a:focus, a:hover {color:#09f;}
+a {color:#06c;text-decoration:underline;}
+blockquote {margin:1.5em;color:#666;font-style:italic;}
+strong, dfn {font-weight:bold;}
+em, dfn {font-style:italic;}
+sup, sub {line-height:0;}
+abbr, acronym {border-bottom:1px dotted #666;}
+address {margin:0 0 1.5em;font-style:italic;}
+del {color:#666;}
+pre {margin:1.5em 0;white-space:pre;}
+pre, code, tt {font:1em 'andale mono', 'lucida console', monospace;line-height:1.5;}
+li ul, li ol {margin:0;}
+ul, ol {margin:0 1.5em 1.5em 0;padding-left:1.5em;}
+ul {list-style-type:disc;}
+ol {list-style-type:decimal;}
+dl {margin:0 0 1.5em 0;}
+dl dt {font-weight:bold;}
+dd {margin-left:1.5em;}
+table {margin-bottom:1.4em;width:100%;}
+th {font-weight:bold;}
+thead th {background:#c3d9ff;}
+th, td, caption {padding:4px 10px 4px 5px;}
+tfoot {font-style:italic;}
+caption {background:#eee;}
+.small {font-size:.8em;margin-bottom:1.875em;line-height:1.875em;}
+.large {font-size:1.2em;line-height:2.5em;margin-bottom:1.25em;}
+.hide {display:none;}
+.quiet {color:#666;}
+.loud {color:#000;}
+.highlight {background:#ff0;}
+.added {background:#060;color:#fff;}
+.removed {background:#900;color:#fff;}
+.first {margin-left:0;padding-left:0;}
+.last {margin-right:0;padding-right:0;}
+.top {margin-top:0;padding-top:0;}
+.bottom {margin-bottom:0;padding-bottom:0;}
+
+/* grid.css */
+.container {width:950px;margin:0 auto;}
+.column, .span-1, .span-2, .span-3, .span-4, .span-5, .span-6, .span-7, .span-8, .span-9, .span-10, .span-11, .span-12, .span-13, .span-14, .span-15, .span-16, .span-17, .span-18, .span-19, .span-20, .span-21, .span-22, .span-23, .span-24 {float:left;margin-right:10px;}
+.last {margin-right:0;}
+.span-1 {width:30px;}
+.span-2 {width:70px;}
+.span-3 {width:110px;}
+.span-4 {width:150px;}
+.span-5 {width:190px;}
+.span-6 {width:230px;}
+.span-7 {width:270px;}
+.span-8 {width:310px;}
+.span-9 {width:350px;}
+.span-10 {width:390px;}
+.span-11 {width:430px;}
+.span-12 {width:470px;}
+.span-13 {width:510px;}
+.span-14 {width:550px;}
+.span-15 {width:590px;}
+.span-16 {width:630px;}
+.span-17 {width:670px;}
+.span-18 {width:710px;}
+.span-19 {width:750px;}
+.span-20 {width:790px;}
+.span-21 {width:830px;}
+.span-22 {width:870px;}
+.span-23 {width:910px;}
+.span-24 {width:950px;margin-right:0;}
+input.span-1, textarea.span-1, input.span-2, textarea.span-2, input.span-3, textarea.span-3, input.span-4, textarea.span-4, input.span-5, textarea.span-5, input.span-6, textarea.span-6, input.span-7, textarea.span-7, input.span-8, textarea.span-8, input.span-9, textarea.span-9, input.span-10, textarea.span-10, input.span-11, textarea.span-11, input.span-12, textarea.span-12, input.span-13, textarea.span-13, input.span-14, textarea.span-14, input.span-15, textarea.span-15, input.span-16, textarea.span-16, input.span-17, textarea.span-17, input.span-18, textarea.span-18, input.span-19, textarea.span-19, input.span-20, textarea.span-20, input.span-21, textarea.span-21, input.span-22, textarea.span-22, input.span-23, textarea.span-23, input.span-24, textarea.span-24 {border-left-width:1px;border-right-width:1px;padding-left:5px;padding-right:5px;}
+input.span-1, textarea.span-1 {width:18px;}
+input.span-2, textarea.span-2 {width:58px;}
+input.span-3, textarea.span-3 {width:98px;}
+input.span-4, textarea.span-4 {width:138px;}
+input.span-5, textarea.span-5 {width:178px;}
+input.span-6, textarea.span-6 {width:218px;}
+input.span-7, textarea.span-7 {width:258px;}
+input.span-8, textarea.span-8 {width:298px;}
+input.span-9, textarea.span-9 {width:338px;}
+input.span-10, textarea.span-10 {width:378px;}
+input.span-11, textarea.span-11 {width:418px;}
+input.span-12, textarea.span-12 {width:458px;}
+input.span-13, textarea.span-13 {width:498px;}
+input.span-14, textarea.span-14 {width:538px;}
+input.span-15, textarea.span-15 {width:578px;}
+input.span-16, textarea.span-16 {width:618px;}
+input.span-17, textarea.span-17 {width:658px;}
+input.span-18, textarea.span-18 {width:698px;}
+input.span-19, textarea.span-19 {width:738px;}
+input.span-20, textarea.span-20 {width:778px;}
+input.span-21, textarea.span-21 {width:818px;}
+input.span-22, textarea.span-22 {width:858px;}
+input.span-23, textarea.span-23 {width:898px;}
+input.span-24, textarea.span-24 {width:938px;}
+.append-1 {padding-right:40px;}
+.append-2 {padding-right:80px;}
+.append-3 {padding-right:120px;}
+.append-4 {padding-right:160px;}
+.append-5 {padding-right:200px;}
+.append-6 {padding-right:240px;}
+.append-7 {padding-right:280px;}
+.append-8 {padding-right:320px;}
+.append-9 {padding-right:360px;}
+.append-10 {padding-right:400px;}
+.append-11 {padding-right:440px;}
+.append-12 {padding-right:480px;}
+.append-13 {padding-right:520px;}
+.append-14 {padding-right:560px;}
+.append-15 {padding-right:600px;}
+.append-16 {padding-right:640px;}
+.append-17 {padding-right:680px;}
+.append-18 {padding-right:720px;}
+.append-19 {padding-right:760px;}
+.append-20 {padding-right:800px;}
+.append-21 {padding-right:840px;}
+.append-22 {padding-right:880px;}
+.append-23 {padding-right:920px;}
+.prepend-1 {padding-left:40px;}
+.prepend-2 {padding-left:80px;}
+.prepend-3 {padding-left:120px;}
+.prepend-4 {padding-left:160px;}
+.prepend-5 {padding-left:200px;}
+.prepend-6 {padding-left:240px;}
+.prepend-7 {padding-left:280px;}
+.prepend-8 {padding-left:320px;}
+.prepend-9 {padding-left:360px;}
+.prepend-10 {padding-left:400px;}
+.prepend-11 {padding-left:440px;}
+.prepend-12 {padding-left:480px;}
+.prepend-13 {padding-left:520px;}
+.prepend-14 {padding-left:560px;}
+.prepend-15 {padding-left:600px;}
+.prepend-16 {padding-left:640px;}
+.prepend-17 {padding-left:680px;}
+.prepend-18 {padding-left:720px;}
+.prepend-19 {padding-left:760px;}
+.prepend-20 {padding-left:800px;}
+.prepend-21 {padding-left:840px;}
+.prepend-22 {padding-left:880px;}
+.prepend-23 {padding-left:920px;}
+.border {padding-right:4px;margin-right:5px;border-right:1px solid #ddd;}
+.colborder {padding-right:24px;margin-right:25px;border-right:1px solid #ddd;}
+.pull-1 {margin-left:-40px;}
+.pull-2 {margin-left:-80px;}
+.pull-3 {margin-left:-120px;}
+.pull-4 {margin-left:-160px;}
+.pull-5 {margin-left:-200px;}
+.pull-6 {margin-left:-240px;}
+.pull-7 {margin-left:-280px;}
+.pull-8 {margin-left:-320px;}
+.pull-9 {margin-left:-360px;}
+.pull-10 {margin-left:-400px;}
+.pull-11 {margin-left:-440px;}
+.pull-12 {margin-left:-480px;}
+.pull-13 {margin-left:-520px;}
+.pull-14 {margin-left:-560px;}
+.pull-15 {margin-left:-600px;}
+.pull-16 {margin-left:-640px;}
+.pull-17 {margin-left:-680px;}
+.pull-18 {margin-left:-720px;}
+.pull-19 {margin-left:-760px;}
+.pull-20 {margin-left:-800px;}
+.pull-21 {margin-left:-840px;}
+.pull-22 {margin-left:-880px;}
+.pull-23 {margin-left:-920px;}
+.pull-24 {margin-left:-960px;}
+.pull-1, .pull-2, .pull-3, .pull-4, .pull-5, .pull-6, .pull-7, .pull-8, .pull-9, .pull-10, .pull-11, .pull-12, .pull-13, .pull-14, .pull-15, .pull-16, .pull-17, .pull-18, .pull-19, .pull-20, .pull-21, .pull-22, .pull-23, .pull-24 {float:left;position:relative;}
+.push-1 {margin:0 -40px 1.5em 40px;}
+.push-2 {margin:0 -80px 1.5em 80px;}
+.push-3 {margin:0 -120px 1.5em 120px;}
+.push-4 {margin:0 -160px 1.5em 160px;}
+.push-5 {margin:0 -200px 1.5em 200px;}
+.push-6 {margin:0 -240px 1.5em 240px;}
+.push-7 {margin:0 -280px 1.5em 280px;}
+.push-8 {margin:0 -320px 1.5em 320px;}
+.push-9 {margin:0 -360px 1.5em 360px;}
+.push-10 {margin:0 -400px 1.5em 400px;}
+.push-11 {margin:0 -440px 1.5em 440px;}
+.push-12 {margin:0 -480px 1.5em 480px;}
+.push-13 {margin:0 -520px 1.5em 520px;}
+.push-14 {margin:0 -560px 1.5em 560px;}
+.push-15 {margin:0 -600px 1.5em 600px;}
+.push-16 {margin:0 -640px 1.5em 640px;}
+.push-17 {margin:0 -680px 1.5em 680px;}
+.push-18 {margin:0 -720px 1.5em 720px;}
+.push-19 {margin:0 -760px 1.5em 760px;}
+.push-20 {margin:0 -800px 1.5em 800px;}
+.push-21 {margin:0 -840px 1.5em 840px;}
+.push-22 {margin:0 -880px 1.5em 880px;}
+.push-23 {margin:0 -920px 1.5em 920px;}
+.push-24 {margin:0 -960px 1.5em 960px;}
+.push-1, .push-2, .push-3, .push-4, .push-5, .push-6, .push-7, .push-8, .push-9, .push-10, .push-11, .push-12, .push-13, .push-14, .push-15, .push-16, .push-17, .push-18, .push-19, .push-20, .push-21, .push-22, .push-23, .push-24 {float:left;position:relative;}
+div.prepend-top, .prepend-top {margin-top:1.5em;}
+div.append-bottom, .append-bottom {margin-bottom:1.5em;}
+.box {padding:1.5em;margin-bottom:1.5em;background:#e5eCf9;}
+hr {background:#ddd;color:#ddd;clear:both;float:none;width:100%;height:1px;margin:0 0 17px;border:none;}
+hr.space {background:#fff;color:#fff;visibility:hidden;}
+.clearfix:after, .container:after {content:"\0020";display:block;height:0;clear:both;visibility:hidden;overflow:hidden;}
+.clearfix, .container {display:block;}
+.clear {clear:both;}
View
15 index-test.php
@@ -0,0 +1,15 @@
+<?php
+/**
+ * This is the bootstrap file for test application.
+ * This file should be removed when the application is deployed for production.
+ */
+
+// change the following paths if necessary
+$yii=dirname(__FILE__).'/../framework/yii.php';
+$config=dirname(__FILE__).'/protected/config/test.php';
+
+// remove the following line when in production mode
+defined('YII_DEBUG') or define('YII_DEBUG',true);
+
+require_once($yii);
+Yii::createWebApplication($config)->run();
View
13 index.php
@@ -0,0 +1,13 @@
+<?php
+
+// change the following paths if necessary
+$yii=dirname(__FILE__).'/../framework/yii.php';
+$config=dirname(__FILE__).'/protected/config/main.php';
+
+// remove the following lines when in production mode
+defined('YII_DEBUG') or define('YII_DEBUG',true);
+// specify how many levels of call stack should be shown in each log message
+defined('YII_TRACE_LEVEL') or define('YII_TRACE_LEVEL',3);
+
+require_once($yii);
+Yii::createWebApplication($config)->run();
View
7 nbproject/project.properties
@@ -0,0 +1,7 @@
+include.path=${php.global.include.path}
+php.version=PHP_5
+source.encoding=UTF-8
+src.dir=.
+tags.asp=false
+tags.short=true
+web.root=.
View
9 nbproject/project.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://www.netbeans.org/ns/project/1">
+ <type>org.netbeans.modules.php.project</type>
+ <configuration>
+ <data xmlns="http://www.netbeans.org/ns/php-project/1">
+ <name>yii-components</name>
+ </data>
+ </configuration>
+</project>
View
1  protected/.htaccess
@@ -0,0 +1 @@
+deny from all
View
23 protected/components/Controller.php
@@ -0,0 +1,23 @@
+<?php
+/**
+ * Controller is the customized base controller class.
+ * All controller classes for this application should extend from this base class.
+ */
+class Controller extends CController
+{
+ /**
+ * @var string the default layout for the controller view. Defaults to '//layouts/column1',
+ * meaning using a single column layout. See 'protected/views/layouts/column1.php'.
+ */
+ public $layout='//layouts/column1';
+ /**
+ * @var array context menu items. This property will be assigned to {@link CMenu::items}.
+ */
+ public $menu=array();
+ /**
+ * @var array the breadcrumbs of the current page. The value of this property will
+ * be assigned to {@link CBreadcrumbs::links}. Please refer to {@link CBreadcrumbs::links}
+ * for more details on how to specify this property.
+ */
+ public $breadcrumbs=array();
+}
View
33 protected/components/UserIdentity.php
@@ -0,0 +1,33 @@
+<?php
+
+/**
+ * UserIdentity represents the data needed to identity a user.
+ * It contains the authentication method that checks if the provided
+ * data can identity the user.
+ */
+class UserIdentity extends CUserIdentity
+{
+ /**
+ * Authenticates a user.
+ * The example implementation makes sure if the username and password
+ * are both 'demo'.
+ * In practical applications, this should be changed to authenticate
+ * against some persistent user identity storage (e.g. database).
+ * @return boolean whether authentication succeeds.
+ */
+ public function authenticate()
+ {
+ $users=array(
+ // username => password
+ 'demo'=>'demo',
+ 'admin'=>'admin',
+ );
+ if(!isset($users[$this->username]))
+ $this->errorCode=self::ERROR_USERNAME_INVALID;
+ else if($users[$this->username]!==$this->password)
+ $this->errorCode=self::ERROR_PASSWORD_INVALID;
+ else
+ $this->errorCode=self::ERROR_NONE;
+ return !$this->errorCode;
+ }
+}
View
24 protected/config/console.php
@@ -0,0 +1,24 @@
+<?php
+
+// This is the configuration for yiic console application.
+// Any writable CConsoleApplication properties can be configured here.
+return array(
+ 'basePath'=>dirname(__FILE__).DIRECTORY_SEPARATOR.'..',
+ 'name'=>'My Console Application',
+ // application components
+ 'components'=>array(
+ 'db'=>array(
+ 'connectionString' => 'sqlite:'.dirname(__FILE__).'/../data/testdrive.db',
+ ),
+ // uncomment the following to use a MySQL database
+ /*
+ 'db'=>array(
+ 'connectionString' => 'mysql:host=localhost;dbname=testdrive',
+ 'emulatePrepare' => true,
+ 'username' => 'root',
+ 'password' => '',
+ 'charset' => 'utf8',
+ ),
+ */
+ ),
+);
View
90 protected/config/main.php
@@ -0,0 +1,90 @@
+<?php
+
+// uncomment the following to define a path alias
+// Yii::setPathOfAlias('local','path/to/local-folder');
+
+// This is the main Web application configuration. Any writable
+// CWebApplication properties can be configured here.
+return array(
+ 'basePath'=>dirname(__FILE__).DIRECTORY_SEPARATOR.'..',
+ 'name'=>'My Web Application',
+
+ // preloading 'log' component
+ 'preload'=>array('log'),
+
+ // autoloading model and component classes
+ 'import'=>array(
+ 'application.models.*',
+ 'application.components.*',
+ ),
+
+ 'modules'=>array(
+ // uncomment the following to enable the Gii tool
+ /*
+ 'gii'=>array(
+ 'class'=>'system.gii.GiiModule',
+ 'password'=>'Enter Your Password Here',
+ // If removed, Gii defaults to localhost only. Edit carefully to taste.
+ 'ipFilters'=>array('127.0.0.1','::1'),
+ ),
+ */
+ ),
+
+ // application components
+ 'components'=>array(
+ 'user'=>array(
+ // enable cookie-based authentication
+ 'allowAutoLogin'=>true,
+ ),
+ // uncomment the following to enable URLs in path-format
+ /*
+ 'urlManager'=>array(
+ 'urlFormat'=>'path',
+ 'rules'=>array(
+ '<controller:\w+>/<id:\d+>'=>'<controller>/view',
+ '<controller:\w+>/<action:\w+>/<id:\d+>'=>'<controller>/<action>',
+ '<controller:\w+>/<action:\w+>'=>'<controller>/<action>',
+ ),
+ ),
+ */
+ 'db'=>array(
+ 'connectionString' => 'sqlite:'.dirname(__FILE__).'/../data/testdrive.db',
+ ),
+ // uncomment the following to use a MySQL database
+ /*
+ 'db'=>array(
+ 'connectionString' => 'mysql:host=localhost;dbname=testdrive',
+ 'emulatePrepare' => true,
+ 'username' => 'root',
+ 'password' => '',
+ 'charset' => 'utf8',
+ ),
+ */
+ 'errorHandler'=>array(
+ // use 'site/error' action to display errors
+ 'errorAction'=>'site/error',
+ ),
+ 'log'=>array(
+ 'class'=>'CLogRouter',
+ 'routes'=>array(
+ array(
+ 'class'=>'CFileLogRoute',
+ 'levels'=>'error, warning',
+ ),
+ // uncomment the following to show log messages on web pages
+ /*
+ array(
+ 'class'=>'CWebLogRoute',
+ ),
+ */
+ ),
+ ),
+ ),
+
+ // application-level parameters that can be accessed
+ // using Yii::app()->params['paramName']
+ 'params'=>array(
+ // this is used in contact page
+ 'adminEmail'=>'webmaster@example.com',
+ ),
+);
View
17 protected/config/test.php
@@ -0,0 +1,17 @@
+<?php
+
+return CMap::mergeArray(
+ require(dirname(__FILE__).'/main.php'),
+ array(
+ 'components'=>array(
+ 'fixture'=>array(
+ 'class'=>'system.test.CDbFixtureManager',
+ ),
+ /* uncomment the following to provide test database connection
+ 'db'=>array(
+ 'connectionString'=>'DSN for test database',
+ ),
+ */
+ ),
+ )
+);
View
103 protected/controllers/SiteController.php
@@ -0,0 +1,103 @@
+<?php
+
+class SiteController extends Controller
+{
+ /**
+ * Declares class-based actions.
+ */
+ public function actions()
+ {
+ return array(
+ // captcha action renders the CAPTCHA image displayed on the contact page
+ 'captcha'=>array(
+ 'class'=>'CCaptchaAction',
+ 'backColor'=>0xFFFFFF,
+ ),
+ // page action renders "static" pages stored under 'protected/views/site/pages'
+ // They can be accessed via: index.php?r=site/page&view=FileName
+ 'page'=>array(
+ 'class'=>'CViewAction',
+ ),
+ );
+ }
+
+ /**
+ * This is the default 'index' action that is invoked
+ * when an action is not explicitly requested by users.
+ */
+ public function actionIndex()
+ {
+ // renders the view file 'protected/views/site/index.php'
+ // using the default layout 'protected/views/layouts/main.php'
+ $this->render('index');
+ }
+
+ /**
+ * This is the action to handle external exceptions.
+ */
+ public function actionError()
+ {
+ if($error=Yii::app()->errorHandler->error)
+ {
+ if(Yii::app()->request->isAjaxRequest)
+ echo $error['message'];
+ else
+ $this->render('error', $error);
+ }
+ }
+
+ /**
+ * Displays the contact page
+ */
+ public function actionContact()
+ {
+ $model=new ContactForm;
+ if(isset($_POST['ContactForm']))
+ {
+ $model->attributes=$_POST['ContactForm'];
+ if($model->validate())
+ {
+ $headers="From: {$model->email}\r\nReply-To: {$model->email}";
+ mail(Yii::app()->params['adminEmail'],$model->subject,$model->body,$headers);
+ Yii::app()->user->setFlash('contact','Thank you for contacting us. We will respond to you as soon as possible.');
+ $this->refresh();
+ }
+ }
+ $this->render('contact',array('model'=>$model));
+ }
+
+ /**
+ * Displays the login page
+ */
+ public function actionLogin()
+ {
+ $model=new LoginForm;
+
+ // if it is ajax validation request
+ if(isset($_POST['ajax']) && $_POST['ajax']==='login-form')
+ {
+ echo CActiveForm::validate($model);
+ Yii::app()->end();
+ }
+
+ // collect user input data
+ if(isset($_POST['LoginForm']))
+ {
+ $model->attributes=$_POST['LoginForm'];
+ // validate user input and redirect to the previous page if valid
+ if($model->validate() && $model->login())
+ $this->redirect(Yii::app()->user->returnUrl);
+ }
+ // display the login form
+ $this->render('login',array('model'=>$model));
+ }
+
+ /**
+ * Logs out the current user and redirect to homepage.
+ */
+ public function actionLogout()
+ {
+ Yii::app()->user->logout();
+ $this->redirect(Yii::app()->homeUrl);
+ }
+}
View
28 protected/data/schema.mysql.sql
@@ -0,0 +1,28 @@
+CREATE TABLE tbl_user (
+ id INTEGER NOT NULL PRIMARY KEY AUTO_INCREMENT,
+ username VARCHAR(128) NOT NULL,
+ password VARCHAR(128) NOT NULL,
+ email VARCHAR(128) NOT NULL
+);
+
+INSERT INTO tbl_user (username, password, email) VALUES ('test1', 'pass1', 'test1@example.com');
+INSERT INTO tbl_user (username, password, email) VALUES ('test2', 'pass2', 'test2@example.com');
+INSERT INTO tbl_user (username, password, email) VALUES ('test3', 'pass3', 'test3@example.com');
+INSERT INTO tbl_user (username, password, email) VALUES ('test4', 'pass4', 'test4@example.com');
+INSERT INTO tbl_user (username, password, email) VALUES ('test5', 'pass5', 'test5@example.com');
+INSERT INTO tbl_user (username, password, email) VALUES ('test6', 'pass6', 'test6@example.com');
+INSERT INTO tbl_user (username, password, email) VALUES ('test7', 'pass7', 'test7@example.com');
+INSERT INTO tbl_user (username, password, email) VALUES ('test8', 'pass8', 'test8@example.com');
+INSERT INTO tbl_user (username, password, email) VALUES ('test9', 'pass9', 'test9@example.com');
+INSERT INTO tbl_user (username, password, email) VALUES ('test10', 'pass10', 'test10@example.com');
+INSERT INTO tbl_user (username, password, email) VALUES ('test11', 'pass11', 'test11@example.com');
+INSERT INTO tbl_user (username, password, email) VALUES ('test12', 'pass12', 'test12@example.com');
+INSERT INTO tbl_user (username, password, email) VALUES ('test13', 'pass13', 'test13@example.com');
+INSERT INTO tbl_user (username, password, email) VALUES ('test14', 'pass14', 'test14@example.com');
+INSERT INTO tbl_user (username, password, email) VALUES ('test15', 'pass15', 'test15@example.com');
+INSERT INTO tbl_user (username, password, email) VALUES ('test16', 'pass16', 'test16@example.com');
+INSERT INTO tbl_user (username, password, email) VALUES ('test17', 'pass17', 'test17@example.com');
+INSERT INTO tbl_user (username, password, email) VALUES ('test18', 'pass18', 'test18@example.com');
+INSERT INTO tbl_user (username, password, email) VALUES ('test19', 'pass19', 'test19@example.com');
+INSERT INTO tbl_user (username, password, email) VALUES ('test20', 'pass20', 'test20@example.com');
+INSERT INTO tbl_user (username, password, email) VALUES ('test21', 'pass21', 'test21@example.com');
View
28 protected/data/schema.sqlite.sql
@@ -0,0 +1,28 @@
+CREATE TABLE tbl_user (
+ id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
+ username VARCHAR(128) NOT NULL,
+ password VARCHAR(128) NOT NULL,
+ email VARCHAR(128) NOT NULL
+);
+
+INSERT INTO tbl_user (username, password, email) VALUES ('test1', 'pass1', 'test1@example.com');
+INSERT INTO tbl_user (username, password, email) VALUES ('test2', 'pass2', 'test2@example.com');
+INSERT INTO tbl_user (username, password, email) VALUES ('test3', 'pass3', 'test3@example.com');
+INSERT INTO tbl_user (username, password, email) VALUES ('test4', 'pass4', 'test4@example.com');
+INSERT INTO tbl_user (username, password, email) VALUES ('test5', 'pass5', 'test5@example.com');
+INSERT INTO tbl_user (username, password, email) VALUES ('test6', 'pass6', 'test6@example.com');
+INSERT INTO tbl_user (username, password, email) VALUES ('test7', 'pass7', 'test7@example.com');
+INSERT INTO tbl_user (username, password, email) VALUES ('test8', 'pass8', 'test8@example.com');
+INSERT INTO tbl_user (username, password, email) VALUES ('test9', 'pass9', 'test9@example.com');
+INSERT INTO tbl_user (username, password, email) VALUES ('test10', 'pass10', 'test10@example.com');
+INSERT INTO tbl_user (username, password, email) VALUES ('test11', 'pass11', 'test11@example.com');
+INSERT INTO tbl_user (username, password, email) VALUES ('test12', 'pass12', 'test12@example.com');
+INSERT INTO tbl_user (username, password, email) VALUES ('test13', 'pass13', 'test13@example.com');
+INSERT INTO tbl_user (username, password, email) VALUES ('test14', 'pass14', 'test14@example.com');
+INSERT INTO tbl_user (username, password, email) VALUES ('test15', 'pass15', 'test15@example.com');
+INSERT INTO tbl_user (username, password, email) VALUES ('test16', 'pass16', 'test16@example.com');
+INSERT INTO tbl_user (username, password, email) VALUES ('test17', 'pass17', 'test17@example.com');
+INSERT INTO tbl_user (username, password, email) VALUES ('test18', 'pass18', 'test18@example.com');
+INSERT INTO tbl_user (username, password, email) VALUES ('test19', 'pass19', 'test19@example.com');
+INSERT INTO tbl_user (username, password, email) VALUES ('test20', 'pass20', 'test20@example.com');
+INSERT INTO tbl_user (username, password, email) VALUES ('test21', 'pass21', 'test21@example.com');
View
BIN  protected/data/testdrive.db
Binary file not shown
View
69 protected/extensions/yiicomp/behaviors/DateTimeBehavior/CDateTimeBehavior.php
@@ -0,0 +1,69 @@
+<?php
+/**
+ * Behaviour for converting date formats between the DB and model
+ * @author Pelesh Yaroslav aka Tokolist http://tokolist.com
+ * @link http://code.google.com/p/yii-components/
+ * @version 1.0
+ * @license http://www.opensource.org/licenses/mit-license.php The MIT License
+ */
+
+class CDateTimeBehavior extends CActiveRecordBehavior
+{
+ const DIRECTION_DB = 0;
+ const DIRECTION_CLIENT = 1;
+
+ public $dbFormat = 'yyyy-MM-dd';
+ public $clientFormat = 'dd.MM.yyyy';
+ public $attributes = array();
+
+ protected function convertDateTimeFormat($date, $fromFormat, $toFormat)
+ {
+ return Yii::app()->dateFormatter->format(
+ $toFormat,
+ CDateTimeParser::parse($date, $fromFormat)
+ );
+ }
+
+ protected function processAttributes($model, $direction)
+ {
+ $attributes = $this->attributes;
+
+ if(!is_array($attributes))
+ $attributes = array($attributes);
+
+ foreach($attributes as $attribute)
+ {
+ if(!is_array($attribute))
+ $attribute = array($attribute);
+
+ $attributeNames = split(',', $attribute[0]);
+
+ foreach($attributeNames as $attributeName)
+ {
+ $attributeName = trim($attributeName);
+
+ if(empty($model->$attributeName))
+ continue;
+
+ $fromFormat = isset($attribute['dbFormat']) ? $attribute['dbFormat'] : $this->dbFormat;
+ $toFormat = isset($attribute['clientFormat']) ? $attribute['clientFormat'] : $this->clientFormat;
+
+ if($direction == self::DIRECTION_DB)
+ list($fromFormat, $toFormat) = array($toFormat, $fromFormat);
+
+ $model->$attributeName = $this->convertDateTimeFormat(
+ $model->$attributeName, $fromFormat, $toFormat);
+ }
+ }
+ }
+
+ public function beforeSave($event)
+ {
+ $this->processAttributes($event->sender, self::DIRECTION_DB);
+ }
+
+ public function afterFind($event)
+ {
+ $this->processAttributes($event->sender, self::DIRECTION_CLIENT);
+ }
+}
View
209 protected/extensions/yiicomp/behaviors/TreeComments/CTreeCommentsControllerBehavior.php
@@ -0,0 +1,209 @@
+<?php
+/**
+ * Controller behaviour for tree comments functionality
+ * @author Pelesh Yaroslav aka Tokolist http://tokolist.com
+ * @link http://code.google.com/p/yii-components/
+ * @version 1.0
+ * @license http://www.opensource.org/licenses/mit-license.php The MIT License
+ */
+
+class CTreeCommentsControllerBehavior extends CBehavior
+{
+
+ public $maxLevel = 20;
+
+ public $hEntryBegin = '<ul class="hentry">';
+ public $hEntryEnd = '</ul>';
+
+ public $commentBegin = '<li class="comment" id="comment_{commentId}">';
+ public $commentEnd = '</li>';
+
+ public $commentsView = 'application.components.TreeComments.views.comments';
+ public $commentView = 'application.components.TreeComments.views.comment';
+ public $formView = 'application.components.TreeComments.views.form';
+ public $errorsView = 'application.components.TreeComments.views.errors';
+
+ public $scriptFile;
+
+ public $jsAjaxUrl;
+
+ public $jsCommentsSelector = '#comments';
+ public $jsReplyLinksSelector = 'a.reply';
+ public $jsAddCommentFormSelector = '#add_comment_form';
+ public $jsParentIdInputSelector = '#comment_parent_id';
+ public $jsHEntrySelector = '.hentry:first';
+ public $jsErrorsSelector = '.errorSummary';
+ public $jsNoCommentsSelector = '#comment_0 .no_comments';
+ public $jsCommentsCountSelector = '.comments_count';
+
+ private function jsonEncode($value)
+ {
+ return function_exists('json_encode') ? json_encode($value) : CJSON::encode($value);
+ }
+
+ public function registerClientScripts()
+ {
+
+ Yii::app()->clientScript->registerCoreScript('jquery');
+
+ if($this->scriptFile != null)
+ $scriptFile = $this->scriptFile;
+ else
+ $scriptFile = Yii::app()->assetManager->publish(dirname(__FILE__).'/js/comments_tree.js');
+
+ Yii::app()->clientScript->registerScriptFile($scriptFile);
+
+ if($this->jsAjaxUrl != null)
+ $ajaxUrl = $this->jsAjaxUrl;
+ else
+ $ajaxUrl = Yii::app()->request->requestUri;
+
+ $jsOptions = array(
+ 'commentsSelector' => $this->jsCommentsSelector,
+ 'replyLinksSelector' => $this->jsReplyLinksSelector,
+ 'addCommentFormSelector' => $this->jsAddCommentFormSelector,
+ 'parentIdInputSelector' => $this->jsParentIdInputSelector,
+ 'hEntrySelector' => $this->jsHEntrySelector,
+ 'errorsSelector' => $this->jsErrorsSelector,
+ 'ajaxUrl' => $ajaxUrl,
+ 'hEntryBegin' => $this->hEntryBegin,
+ 'hEntryEnd' => $this->hEntryEnd,
+ 'noCommentsSelector' => $this->jsNoCommentsSelector,
+ 'commentsCountSelector' => $this->jsCommentsCountSelector,
+ );
+
+ $script = '$().treeComments(' . $this->jsonEncode($jsOptions) . ');';
+
+ Yii::app()->clientScript->registerScript('TreeComments', $script, CClientScript::POS_READY);
+ }
+
+ public function renderComments($model, $targetType, $targetId, $viewData = array(), &$commentsCount=null)
+ {
+ $html = '';
+
+ $behaviorOwner = $this->getOwner();
+
+ $comments = $model->getComments($targetType, $targetId);
+ $commentsCount = count($comments);
+
+ if($commentsCount > 0)
+ {
+ $html .= $this->hEntryBegin;
+
+ $previousLevel = 0;
+
+ foreach($comments as $index => $comment)
+ {
+ $level = min($comment->getAttribute($model->commentsLevelField), $this->maxLevel);
+
+
+ if($index > 0)
+ {
+ if($level > $previousLevel)
+ {
+ $html .= $this->hEntryBegin;
+ }
+ elseif($level == $previousLevel)
+ {
+ $html .= $this->commentEnd;
+ }
+ else // $level < $previousLevel
+ {
+ $html .= str_repeat($this->commentEnd . $this->hEntryEnd, $previousLevel - $level);
+ $html .= $this->commentEnd;
+ }
+ }
+
+ $html .= strtr($this->commentBegin, array('{commentId}'=>$comment->id));
+
+ $html .= $behaviorOwner->renderPartial(
+ $this->commentView,
+ array_merge(array('model' => $comment), $viewData),
+ true
+ );
+
+ $previousLevel = $level;
+ }
+
+ $html .= str_repeat($this->commentEnd . $this->hEntryEnd, $level + 1);
+ }
+
+ return $html;
+ }
+
+ public function renderCommentsForm($model, $viewData = array())
+ {
+ $html = '';
+
+ $behaviorOwner = $this->getOwner();
+
+ $html .= $behaviorOwner->renderPartial(
+ $this->formView,
+ array_merge(array('model' => $model), $viewData),
+ true
+ );
+
+ return $html;
+ }
+
+ public function renderCommentsFull($model, $targetType, $targetId, $viewData = array())
+ {
+ $html = '';
+
+ $behaviorOwner = $this->getOwner();
+
+ $this->registerClientScripts();
+
+ //$commentsCount
+
+ $comments = $this->renderComments($model, $targetType, $targetId, $viewData, $commentsCount);
+ $form = $this->renderCommentsForm($model, $viewData);
+
+ $html .= $behaviorOwner->renderPartial(
+ $this->commentsView,
+ array_merge(
+ array(
+ 'model' => $model,
+ 'comments'=>$comments,
+ 'form'=>$form,
+ 'commentsCount'=>$commentsCount,
+ ),
+ $viewData
+ ),
+ true
+ );
+
+ return $html;
+ }
+
+ public function renderAjaxAddCommentResponse($model, $viewData = array())
+ {
+ $behaviorOwner = $this->getOwner();
+
+ $response = array();
+ $response['validated'] = !$model->hasErrors();
+
+ if($response['validated'])
+ {
+ $commentHtml = $behaviorOwner->renderPartial(
+ $this->commentView,
+ array_merge(array('model' => $model), $viewData),
+ true
+ );
+
+ $response['html'] = strtr($this->commentBegin, array('{commentId}'=>$model->id))
+ . $commentHtml . $this->commentEnd;
+ }
+ else
+ {
+ $response['html'] = $behaviorOwner->renderPartial(
+ $this->errorsView,
+ array_merge(array('model' => $model), $viewData),
+ true
+ );
+ }
+
+ return $this->jsonEncode($response);
+ }
+
+}
View
75 protected/extensions/yiicomp/behaviors/TreeComments/CTreeCommentsModelBehavior.php
@@ -0,0 +1,75 @@
+<?php
+/**
+ * Active Record behaviour for tree comments functionality
+ * @author Pelesh Yaroslav aka Tokolist http://tokolist.com
+ * @link http://code.google.com/p/yii-components/
+ * @version 1.0
+ * @license http://www.opensource.org/licenses/mit-license.php The MIT License
+ */
+
+class CTreeCommentsModelBehavior extends CActiveRecordBehavior
+{
+ public $commentsPkField = 'id';
+ public $commentsTargetField = 'target_id';
+ public $commentsTargetTypeField = 'target_type';
+ public $commentsParentField = 'parent';
+ public $commentsOrderField = 'order';
+ public $commentsLevelField = 'level';
+
+
+
+ function saveComment()
+ {
+ $owner = $this->getOwner();
+
+
+ if ($owner->isNewRecord)
+ {
+ $tableName = $owner->tableName();
+ $targetId = intval($owner->getAttribute($this->commentsTargetField));
+ $parentId = intval($owner->getAttribute($this->commentsParentField));
+
+
+ $sql = "SELECT COUNT(`{$this->commentsPkField}`) FROM `{$tableName}` WHERE "
+ . "`{$this->commentsTargetField}`='{$targetId}' "
+ . "AND `{$this->commentsParentField}`='{$parentId}'";
+
+ $count = Yii::app()->db->createCommand($sql)->queryScalar();
+
+ $parentOrder = '';
+ if ($parentId > 0)
+ {
+ $sql = "SELECT `{$this->commentsOrderField}` FROM `{$tableName}` WHERE "
+ . "`{$this->commentsPkField}`='{$parentId}'";
+
+ $parentOrder = Yii::app()->db->createCommand($sql)->queryScalar();
+ }
+
+ $order = $parentOrder . str_pad($count+1, 5, '0', STR_PAD_LEFT);
+ $owner->setAttribute($this->commentsOrderField, $order);
+ $owner->setAttribute($this->commentsLevelField, strlen($order)/5 - 1);
+ }
+
+
+ return $owner->save();
+ }
+
+
+ function getComments($targetType, $targetId)
+ {
+ $owner = $this->getOwner();
+
+ $criteria = new CDbCriteria();
+ $criteria->compare($this->commentsTargetField, $targetId);
+ $criteria->compare($this->commentsTargetTypeField, $targetType);
+ $criteria->order = "`{$this->commentsOrderField}` ASC";
+
+ return $owner->findAll($criteria);
+ }
+
+ function getCommentsCount($targetType, $targetId)
+ {
+ //TODO comments count
+ }
+
+}
View
112 protected/extensions/yiicomp/behaviors/TreeComments/js/comments_tree.js
@@ -0,0 +1,112 @@
+(function($) {
+ $.fn.treeComments = function(options){
+
+
+ var addCommentForm = $(options.addCommentFormSelector);
+
+ $(options.replyLinksSelector).live('click', function(){
+
+ var parentCommentId = /comment_(\d+)/.exec($(this).attr('rel'))[1];
+
+ $(options.parentIdInputSelector).val(parentCommentId);
+
+ addCommentForm.find('textarea').val('');
+
+ addCommentForm.find(options.errorsSelector).remove();
+
+
+ var commentContainer = $('#comment_' + parentCommentId);
+
+
+ if(commentContainer.length > 0) {
+ var hentry = commentContainer.find(options.hEntrySelector);
+
+ if(hentry.length > 0 && parentCommentId > 0) {
+ hentry.before(addCommentForm);
+ } else {
+ commentContainer.append(addCommentForm);
+ }
+ }
+ else
+ {
+ $(this).after(addCommentForm);
+ }
+
+
+ return false;
+ });
+
+ addCommentForm.submit(function(){
+ var form = $(this);
+ var textarea = form.find('textarea');
+ var submitButton = form.find("input[type='submit']");
+
+
+ var ajaxData = form.serialize();//Disabled inputs not serialized
+
+ textarea.attr('disabled', 'disabled');
+ submitButton.attr('disabled', 'disabled');
+ form.addClass('loading');
+
+ $.ajax({
+ type: 'POST',
+ url: options.ajaxUrl,
+ cache: false,
+ data: ajaxData,
+ dataType: 'json',
+ success: function(response){
+
+ if(response.validated) {
+ //if first comment, remove "no comments" message
+ $(options.noCommentsSelector).remove();
+
+ var parentCommentId = $(options.parentIdInputSelector).val();
+
+ if(parentCommentId == '') {
+ parentCommentId = 0;
+ }
+ var commentContainer = $('#comment_' + parentCommentId);
+
+ var hentry = commentContainer.find(options.hEntrySelector);
+
+ if(hentry.length > 0) {
+ hentry.append(response.html);
+ } else {
+ var commentHtml = options.hEntryBegin + response.html
+ + options.hEntryEnd;
+
+ if(parentCommentId > 0) {
+ commentContainer.append(commentHtml);
+ } else {
+ commentContainer.prepend(commentHtml);
+ }
+ }
+
+ $(options.commentsCountSelector).each(function(){
+ var element = $(this);
+ var currentCount = parseInt(element.text());
+
+ if(currentCount == Number.NaN) currentCount = 0;
+
+ element.text(currentCount + 1);
+ })
+
+ } else {
+ form.find(options.errorsSelector).remove();
+ form.prepend(response.html);
+ }
+
+ form.removeClass('loading');
+ textarea.attr('disabled', '');
+ submitButton.attr('disabled', '');
+
+ if(response.validated) {
+ $("a[rel='comment_0']").click();
+ }
+ }
+ });
+
+ return false;
+ });
+ }
+})(jQuery);
View
14 protected/extensions/yiicomp/behaviors/TreeComments/schema.sql
@@ -0,0 +1,14 @@
+CREATE TABLE `comments` (
+ `id` int(11) NOT NULL auto_increment,
+ `order` varchar(255) NOT NULL,
+ `level` int(11) NOT NULL,
+ `parent` int(11) NOT NULL,
+ `target_id` int(11) NOT NULL,
+ `target_type` enum('thing') NOT NULL,
+ `user_id` int(11) NOT NULL,
+ `comment` text NOT NULL,
+ `date` timestamp NOT NULL default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP,
+ `deleted` tinyint(1) unsigned NOT NULL default '0',
+ PRIMARY KEY (`id`),
+ KEY `fk_comments_user_id` (`user_id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
View
23 protected/extensions/yiicomp/behaviors/TreeComments/views/comment.php
@@ -0,0 +1,23 @@
+<?php if(!$model->deleted): ?>
+ <ul class="comment_meta">
+ <li class="avatar"><?php echo CHtml::image($model->user->getAvatarUrl()); ?></li>
+ <li class="user_name"><a href="#"><?php echo $model->user->login; ?></a></li>
+ <li class="date"><?php echo date('d.m.Y H:i:s', strtotime($model->date)); ?></li>
+ <li class="anchor"><?php echo CHtml::link('#', '#comment_' . $model->id); ?></li>
+ </ul>
+
+ <div class="comment_text"><?php echo CHtml::encode($model->comment); ?></div>
+
+ <?php if($canPostComments): ?>
+ <ul class="comment_control">
+ <li class="reply">
+ <?php echo CHtml::link(Yii::t('comments', 'Reply'), '#', array(
+ 'class'=>'reply',
+ 'rel'=>'comment_' . $model->id)
+ ); ?>
+ </li>
+ </ul>
+ <?php endif; ?>
+<?php else: ?>
+ <p class="comment_deleted"><?php echo Yii::t('comments', 'This comment was deleted'); ?></p>
+<?php endif; ?>
View
15 protected/extensions/yiicomp/behaviors/TreeComments/views/comments.php
@@ -0,0 +1,15 @@
+<div id="comments">
+ <h3><?php echo Yii::t('comments', 'Comments ({count})', array(
+ '{count}'=>'<span class="comments_count">' . $commentsCount . '</span>',
+ )); ?></h3>
+
+ <div id="comment_0">
+ <?php if($commentsCount > 0): ?>
+ <?php echo $comments; ?>
+ <?php else: ?>
+ <p class="no_comments"><?php echo Yii::t('comments', 'No comments yet'); ?></p>
+ <?php endif; ?>
+
+ <?php echo $form; ?>
+ </div>
+</div>
View
1  protected/extensions/yiicomp/behaviors/TreeComments/views/errors.php
@@ -0,0 +1 @@
+<?php echo CHtml::errorSummary($model); ?>
View
23 protected/extensions/yiicomp/behaviors/TreeComments/views/form.php
@@ -0,0 +1,23 @@
+<?php if($canPostComments): ?>
+ <h3>
+ <?php
+ echo CHtml::link(Yii::t('comments', 'Post new comment'), '#', array(
+ 'class'=>'reply',
+ 'rel'=>'comment_0',
+ ));
+ ?>
+ </h3>
+
+ <?php $form=$this->beginWidget('CActiveForm', array(
+ 'id'=>'add_comment_form',
+ )); ?>
+
+ <?php echo $form->errorSummary($model); ?>
+ <?php echo $form->hiddenField($model,'parent',array('id'=>'comment_parent_id')); ?>
+ <p><?php echo $form->textArea($model,'comment',array('rows'=>6, 'cols'=>50)); ?></p>
+ <p><?php echo CHtml::submitButton(Yii::t('comments', 'Add comment')); ?></p>
+
+ <?php $this->endWidget(); ?>
+<?php else: ?>
+ <p><?php echo Yii::t('comments', 'Only authorized users can post comments. Please <a href="{loginLink}">login</a> or <a href="{registerLink}">register</a>.'); ?></p>
+<?php endif; ?>
View
27 protected/extensions/yiicomp/components/ButtonColumnEx/CButtonColumnEx.php
@@ -0,0 +1,27 @@
+<?php
+/**
+ * Extended CButtonColumn, that can be used with dynamic templates
+ * @author Pelesh Yaroslav aka Tokolist http://tokolist.com
+ * @link http://code.google.com/p/yii-components/
+ * @version 1.0
+ * @license http://www.opensource.org/licenses/mit-license.php The MIT License
+ */
+
+class CButtonColumnEx extends CButtonColumn
+{
+ public $templateExpression;
+
+ protected function renderDataCellContent($row,$data)
+ {
+ $tmp = $this->template;
+
+ if($this->templateExpression !== null) {
+ $this->template = $this->evaluateExpression($this->templateExpression,array('data'=>$data,'row'=>$row));
+ }
+
+ parent::renderDataCellContent($row,$data);
+
+ $this->template = $tmp;
+ }
+
+}
View
597 protected/extensions/yiicomp/components/ImageHandler/CImageHandler.php
@@ -0,0 +1,597 @@
+<?php
+/**
+ * Image handler
+ * @author Pelesh Yaroslav aka Tokolist http://tokolist.com
+ * @link http://code.google.com/p/yii-components/
+ * @version 0.9 beta
+ * @license http://www.opensource.org/licenses/mit-license.php The MIT License
+ */
+
+class CImageHandler extends CApplicationComponent
+{
+
+ private $image = null;
+
+ private $format = 0;
+
+ private $width = 0;
+ private $height = 0;
+
+ private $mimeType = '';
+
+ private $fileName = '';
+
+ public $transparencyColor = array(0, 0, 0);
+
+
+ const IMG_GIF = 1;
+ const IMG_JPEG = 2;
+ const IMG_PNG = 3;
+
+ const CORNER_LEFT_TOP = 1;
+ const CORNER_RIGHT_TOP = 2;
+ const CORNER_LEFT_BOTTOM = 3;
+ const CORNER_RIGHT_BOTTOM = 4;
+ const CORNER_CENTER = 5;
+
+
+ const FLIP_HORIZONTAL = 1;
+ const FLIP_VERTICAL = 2;
+ const FLIP_BOTH = 3;
+
+
+ public function getImage()
+ {
+ return $this->image;
+ }
+
+ public function getFormat()
+ {
+ return $this->format;
+ }
+
+ public function getWidth()
+ {
+ return $this->width;
+ }
+
+ public function getHeight()
+ {
+ return $this->height;
+ }
+
+ public function getMimeType()
+ {
+ return $this->mimeType;
+ }
+
+ public function __destruct()
+ {
+ $this->freeImage();
+ }
+
+ private function freeImage()
+ {
+ if (is_resource($this->image))
+ {
+ imagedestroy($this->image);
+ }
+ }
+
+ private function checkLoaded()
+ {
+ if (!is_resource($this->image))
+ {
+ throw new Exception('Load image first');
+ }
+ }
+
+ private function loadImage($file)
+ {
+ $result = array();
+
+
+
+ if ($imageInfo = @getimagesize($file))
+ {
+ $result['width'] = $imageInfo[0];
+ $result['height'] = $imageInfo[1];
+
+ $result['mimeType'] = $imageInfo['mime'];
+
+ switch ($result['format'] = $imageInfo[2])
+ {
+ case self::IMG_GIF:
+ if ($result['image'] = imagecreatefromgif($file))
+ {
+ return $result;
+ }
+ else
+ {
+ throw new Exception('Invalid image gif format');
+ }
+ break;
+ case self::IMG_JPEG:
+ if ($result['image'] = imagecreatefromjpeg($file))
+ {
+ return $result;
+ }
+ else
+ {
+ throw new Exception('Invalid image jpeg format');
+ }
+ break;
+ case self::IMG_PNG:
+ if ($result['image'] = imagecreatefrompng($file))
+ {
+ return $result;
+ }
+ else
+ {
+ throw new Exception('Invalid image png format');
+ }
+ break;
+ default:
+ throw new Exception('Not supported image format');
+ }
+ }
+ else
+ {
+ throw new Exception('Invalid image file');
+ }
+
+
+ }
+
+ public function load($file)
+ {
+ $this->freeImage();
+
+ if ($img = $this->loadImage($file))
+ {
+ $this->width = $img['width'];
+ $this->height = $img['height'];
+ $this->mimeType = $img['mimeType'];
+ $this->format = $img['format'];
+ $this->image = $img['image'];
+
+ $this->fileName = $file;
+
+
+ return $this;
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ public function reload()
+ {
+ $this->checkLoaded();
+
+ if ($this->fileName != '')
+ {
+ return $this->load($this->fileName);
+ }
+
+ }
+
+ private function preserveTransparency($newImage)
+ {
+ switch($this->format)
+ {
+ case self::IMG_GIF:
+ $color = imagecolorallocate(
+ $newImage,
+ $this->transparencyColor[0],
+ $this->transparencyColor[1],
+ $this->transparencyColor[2]
+ );
+
+ imagecolortransparent($newImage, $color);
+ imagetruecolortopalette($newImage, false, 256);
+ break;
+ case self::IMG_PNG:
+ imagealphablending($newImage, false);
+
+ $color = imagecolorallocatealpha (
+ $newImage,
+ $this->transparencyColor[0],
+ $this->transparencyColor[1],
+ $this->transparencyColor[2],
+ 0
+ );
+
+ imagefill($newImage, 0, 0, $color);
+ imagesavealpha($newImage, true);
+ break;
+ }
+ }
+
+ public function resize($toWidth, $toHeight, $proportional = true)
+ {
+ $this->checkLoaded();
+
+ $toWidth = $toWidth !== false ? $toWidth : $this->width;
+ $toHeight = $toHeight !== false ? $toHeight : $this->height;
+
+ if($proportional)
+ {
+ $newHeight = $toHeight;
+ $newWidth = round($newHeight / $this->height * $this->width);
+
+
+ if($newWidth > $toWidth)
+ {
+ $newWidth = $toWidth;
+ $newHeight = round($newWidth / $this->width * $this->height);
+ }
+ }
+ else
+ {
+ $newWidth = $toWidth;
+ $newHeight = $toHeight;
+ }
+
+ $newImage = imagecreatetruecolor($newWidth, $newHeight);
+
+ $this->preserveTransparency($newImage);
+
+ imagecopyresampled($newImage, $this->image, 0, 0, 0, 0, $newWidth, $newHeight, $this->width, $this->height);
+
+
+
+ imagedestroy($this->image);
+
+ $this->image = $newImage;
+ $this->width = $newWidth;
+ $this->height = $newHeight;
+
+ return $this;
+
+ }
+
+ public function thumb($toWidth, $toHeight, $proportional = true)
+ {
+ $this->checkLoaded();
+
+ if($toWidth !== false)
+ $toWidth = min($toWidth, $this->width);
+
+ if($toHeight !== false)
+ $toHeight = min($toHeight, $this->height);
+
+
+ $this->resize($toWidth, $toHeight, $proportional);
+
+ return $this;
+
+ }
+
+ public function watermark($watermarkFile, $offsetX, $offsetY, $corner = self::CORNER_RIGHT_BOTTOM)
+ {
+
+ $this->checkLoaded();
+
+ if ($wImg = $this->loadImage($watermarkFile))
+ {
+
+ $posX = 0;
+ $posY = 0;
+
+ switch ($corner)
+ {
+ case self::CORNER_LEFT_TOP:
+ $posX = $offsetX;
+ $posY = $offsetY;
+ break;
+ case self::CORNER_RIGHT_TOP:
+ $posX = $this->width - $wImg['width'] - $offsetX;
+ $posY = $offsetY;
+ break;
+ case self::CORNER_LEFT_BOTTOM:
+ $posX = $offsetX;
+ $posY = $this->height - $wImg['height'] - $offsetY;
+ break;
+ case self::CORNER_RIGHT_BOTTOM:
+ $posX = $this->width - $wImg['width'] - $offsetX;
+ $posY = $this->height - $wImg['height'] - $offsetY;
+ break;
+ case self::CORNER_CENTER:
+ $posX = floor(($this->width - $wImg['width']) / 2);
+ $posY = floor(($this->height - $wImg['height']) / 2);
+ break;