+
+
\ No newline at end of file
diff --git a/assets/css/edit-profile.css b/assets/css/edit-profile.css
new file mode 100644
index 00000000000..75465431998
--- /dev/null
+++ b/assets/css/edit-profile.css
@@ -0,0 +1,100 @@
+#edit-profile {
+ display: flex;
+ justify-content: center;
+}
+
+#edit-profile .edit-profile__container {
+ background-color: white;
+ border: 1px solid #e6e6e6;
+ width: 100%;
+ max-width: 800px;
+}
+
+#edit-profile .edit-profile__container {
+ padding: 40px 0;
+}
+
+#edit-profile .edit-profile__header {
+ display: flex;
+ align-items: center;
+ margin-bottom: 50px;
+}
+
+.edit-profile__header .edit-profile__avatar-container {
+ width: 200px;
+}
+
+.edit-profile__avatar-container {
+ display: flex;
+ justify-content: flex-end;
+ margin-right: 35px;
+}
+
+.edit-profile__avatar-container img {
+ width: 38px;
+ height: 38px;
+ border-radius: 50%;
+}
+.edit-profile__header h4 {
+ font-size: 18px;
+ font-weight: 600;
+}
+
+.edit-profile__form .form__row {
+ display: flex;
+}
+
+.form__row {
+ margin-bottom: 20px;
+ display: flex;
+ align-items: center;
+}
+
+.form__row .form__label {
+ width: 200px;
+ display: block;
+ text-align: right;
+ margin-right: 35px;
+ font-weight: 600;
+ font-size: 16px;
+}
+
+.form__row label {
+ font-size: 15px;
+ width: 80%;
+}
+
+.form__row .form__input,
+.form__row textarea {
+ padding: 8px;
+ width: 255px;
+ resize: vertical;
+ border: 0;
+ border: 1px solid #e6e6e6;
+ border-radius: 3px;
+}
+
+.form__row input[type="checkbox"] {
+ margin-right: 15px;
+}
+
+#edit-profile select {
+ background: 0 0;
+ border: 1px solid #efefef;
+ border-radius: 3px;
+ color: #262626;
+ font-size: 16px;
+ height: 32px;
+ padding: 0 30px 0 10px;
+}
+
+#edit-profile input[type="submit"] {
+ margin-left: 235px;
+ border: 0;
+ color: white;
+ font-weight: 600;
+ border-radius: 3px;
+ background-color: var(--fd-blue);
+ font-size: 14px;
+ padding: 7px 25px;
+}
diff --git a/assets/css/explore.css b/assets/css/explore.css
new file mode 100644
index 00000000000..d4a8f6ba2af
--- /dev/null
+++ b/assets/css/explore.css
@@ -0,0 +1,70 @@
+#explore {
+ display: flex;
+ justify-content: center;
+ align-items: flex-start;
+ min-height: 500px;
+}
+
+#explore .explore__users {
+ background-color: white;
+ border: 1px solid #e6e6e6;
+ border-radius: 3px;
+ width: 100%;
+ max-width: 600px;
+}
+
+.explore__users .explore__user {
+ padding: 10px 15px;
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ border-bottom: 1px solid #e6e6e6;
+}
+
+.explore__users .explore__user:last-child {
+ border: 0;
+}
+
+.explore__user .explore__avatar {
+ width: 55px;
+ border-radius: 50%;
+}
+
+.explore__user .explore__user-column {
+ display: flex;
+ align-items: center;
+}
+
+.explore__user .explore__info {
+ margin-left: 15px;
+}
+
+.explore__info .explore__username {
+ display: block;
+ font-weight: 600;
+ margin-bottom: 5px;
+}
+
+.explore__info .explore__full-name {
+ color: #999;
+}
+
+.explore__user-column button {
+ background-color: var(--fd-blue);
+ color: white;
+ border: 0;
+ font-weight: 600;
+ padding: 5px 10px;
+ font-size: 14px;
+ border-radius: 3px;
+ cursor: pointer;
+}
+
+.explore__user-column button:active,
+.explore__user-column button:focus {
+ outline: none;
+}
+
+.explore__user-column:active {
+ opacity: 0.9;
+}
diff --git a/assets/css/feed.css b/assets/css/feed.css
new file mode 100644
index 00000000000..cc88c16ef17
--- /dev/null
+++ b/assets/css/feed.css
@@ -0,0 +1,101 @@
+#feed {
+ display: flex;
+ align-items: center;
+ flex-direction: column;
+}
+
+#feed .photo {
+ background-color: white;
+ border: 1px solid #e6e6e6;
+ border-radius: 3px;
+ width: 100%;
+ max-width: 600px;
+ margin-bottom: 65px;
+}
+
+.photo .photo__header {
+ padding: 15px;
+ display: flex;
+ align-items: center;
+}
+
+.photo__header .photo__avatar {
+ width: 32px;
+ border-radius: 50%;
+ margin-right: 10px;
+}
+
+.photo .photo__user-info .photo__author {
+ display: block;
+ font-weight: 600;
+ margin-bottom: 5px;
+}
+
+.photo > img {
+ max-width: 100%;
+}
+
+.photo .photo__info {
+ padding: 15px 20px;
+}
+
+.photo__actions {
+ margin-bottom: 15px;
+ font-size: 115%;
+}
+
+.photo__actions .photo__action:first-child {
+ margin-right: 15px;
+}
+
+.photo__actions .photo__action {
+ cursor: pointer;
+}
+
+.photo .photo__likes {
+ font-weight: 600;
+ margin-bottom: 10px;
+ display: block;
+}
+
+.photo .photo__add-comment-container {
+ margin-top: 15px;
+ border-top: 1px solid #e6e6e6;
+ padding-top: 10px;
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+}
+
+.photo__add-comment-container textarea {
+ width: 90%;
+ border: 0;
+ font-size: 14px;
+ resize: none;
+ height: 20px;
+}
+
+.photo__add-comment-container textarea:focus,
+.photo__add-comment-container textarea:active {
+ outline: none;
+}
+
+.photo__add-comment-container i {
+ cursor: pointer;
+}
+
+.photo .photo__time-ago {
+ font-size: 10px;
+ text-transform: uppercase;
+ color: #999;
+ margin-top: 10px;
+ display: block;
+}
+
+.photo__comment {
+ margin-bottom: 10px;
+}
+
+.photo__comments .photo__comment-author {
+ font-weight: 600;
+}
diff --git a/assets/css/footer.css b/assets/css/footer.css
new file mode 100644
index 00000000000..0d5b8cbae0e
--- /dev/null
+++ b/assets/css/footer.css
@@ -0,0 +1,30 @@
+.footer {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ width: 100%;
+ max-width: 900px;
+ margin: 30px auto;
+ text-transform: uppercase;
+ font-size: 12px;
+ font-weight: 600;
+}
+
+.footer .footer__list {
+ padding: 0;
+ list-style-type: none;
+ display: flex;
+}
+
+.footer .footer__copyright {
+ color: hsl(0, 0%, 60%);
+}
+
+.footer__list .footer__list-item {
+ margin-right: 10px;
+}
+
+.footer .footer__link {
+ text-decoration: none;
+ color: var(--link-color);
+}
diff --git a/assets/css/globals.css b/assets/css/globals.css
new file mode 100644
index 00000000000..cea96117b23
--- /dev/null
+++ b/assets/css/globals.css
@@ -0,0 +1,21 @@
+body {
+ background-color: white;
+ background-color: var(--background-color);
+ font-size: 14px;
+ font-family: "Open Sans", sans-serif;
+}
+
+main {
+ animation: fadeInMain 0.5s linear;
+}
+
+@keyframes fadeInMain {
+ from {
+ opacity: 0;
+ transform: translateY(10px);
+ }
+ to {
+ opacity: 1;
+ transform: translateY(0px);
+ }
+}
diff --git a/assets/css/login.css b/assets/css/login.css
new file mode 100644
index 00000000000..f5657f0c13a
--- /dev/null
+++ b/assets/css/login.css
@@ -0,0 +1,128 @@
+#login {
+ width: 100%;
+ max-width: 800px;
+ margin: 45px auto;
+ display: flex;
+ justify-content: space-around;
+}
+
+#login .login__column {
+ width: 45%;
+}
+
+.login__column .login__phone {
+ max-width: 100%;
+}
+
+.login__column .login__box {
+ background-color: white;
+ border: 1px solid #e6e6e6;
+}
+
+.login__column .login__box--transparent {
+ background: none;
+ border: 0;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ margin-top: 35px;
+}
+
+.login__column .login__appstores {
+ margin-top: 20px;
+}
+
+.login__appstores .login__appstore {
+ height: 40px;
+}
+
+#login .login__box {
+ padding: 30px 0;
+ text-align: center;
+}
+
+#login .login__box:first-child {
+ margin-bottom: 10px;
+ padding-left: 40px;
+ padding-right: 40px;
+}
+
+.login__column .login__logo {
+ height: 50px;
+}
+
+.login__form input {
+ display: block;
+ width: 100%;
+ box-sizing: border-box;
+ padding: 7px;
+ font-size: 14px;
+ border: 0;
+ border: 1px solid #e6e6e6;
+ border-radius: 5px;
+ background: #fafafa;
+}
+
+.login__form input:focus {
+ outline: none;
+ border: 1px solid #a9a9a9;
+}
+
+.login__form input:first-child {
+ margin-bottom: 5px;
+}
+
+.login__form input[type="submit"] {
+ background-color: #3f99ed;
+ border: 0;
+ padding: 5px;
+ margin-top: 15px;
+ margin-bottom: 20px;
+ color: white;
+ font-weight: 600;
+}
+
+#login .login__divider {
+ display: block;
+ text-transform: uppercase;
+ font-weight: 600;
+ color: #999;
+ margin-bottom: 20px;
+ position: relative;
+ width: 100%;
+}
+
+#login .login__link {
+ display: block;
+ text-decoration: none;
+ color: #003569;
+}
+
+#login .login__link--small {
+ margin-top: 30px;
+}
+
+.login__box a {
+ text-decoration: none;
+ color: var(--fd-blue);
+}
+
+#login .login__divider:before {
+ content: "";
+ height: 1px;
+ background-color: rgba(153, 153, 153, 0.5);
+ width: 40%;
+ position: absolute;
+ left: 0;
+ top: 10px;
+}
+
+#login .login__divider:after {
+ content: "";
+ height: 1px;
+ background-color: rgba(153, 153, 153, 0.5);
+ width: 40%;
+ position: absolute;
+ right: 0;
+ top: 10px;
+}
diff --git a/assets/css/mobile.css b/assets/css/mobile.css
new file mode 100644
index 00000000000..fc236e0553c
--- /dev/null
+++ b/assets/css/mobile.css
@@ -0,0 +1,110 @@
+@media screen and (min-width: 375px) and (max-width: 667px) {
+ .navigation {
+ padding: 0 20px;
+ margin-bottom: 0;
+ }
+ .navigation input,
+ .navigation .fa-search {
+ display: none;
+ }
+ #feed .photo {
+ background-color: transparent;
+ border: 0;
+ margin-bottom: 20px;
+ }
+ #feed .photo .photo__add-comment-container {
+ display: none;
+ }
+ .footer {
+ width: 80%;
+ }
+ .footer,
+ .footer .footer__list {
+ flex-wrap: wrap;
+ justify-content: center;
+ }
+ .footer__list .footer__list-item {
+ margin-bottom: 10px;
+ }
+ #login .login__column {
+ width: 100%;
+ }
+ #login .login__column:first-child {
+ display: none;
+ }
+ #login .login__box {
+ background-color: transparent;
+ border: 0;
+ }
+ #profile {
+ margin-top: 50px;
+ }
+ #profile .profile__header {
+ flex-direction: column;
+ align-items: center;
+ }
+ #profile .profile__title {
+ flex-wrap: wrap;
+ justify-content: center;
+ width: 100%;
+ }
+ .profile__title h3 {
+ margin: 20px 0;
+ }
+ .profile__title a {
+ margin-right: auto;
+ }
+ .profile__stats {
+ justify-content: space-between;
+ }
+ .profile__stats .profile__stat {
+ text-align: center;
+ margin-right: 0;
+ }
+ .profile__stat span {
+ display: block;
+ }
+ .profile__photos .profile__photo {
+ width: 33%;
+ margin-bottom: 0;
+ }
+ .profile__photos {
+ margin-bottom: 50px;
+ }
+ #explore .explore__users {
+ background-color: transparent;
+ border: 0;
+ }
+ .explore__users .explore__user {
+ border: 0;
+ }
+ #edit-profile > .edit-profile__container {
+ border: 0;
+ }
+ #edit-profile .form__row {
+ flex-direction: column;
+ }
+ .form__row .form__label {
+ margin: 0;
+ text-align: center;
+ margin-bottom: 10px;
+ }
+ #edit-profile input[type="submit"] {
+ width: 120px;
+ margin: 0;
+ margin-top: 20px;
+ }
+ #edit-profile .edit-profile__container {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ }
+ #edit-profile .edit-profile__form {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ }
+ .edit-profile__header .edit-profile__avatar-container {
+ width: 0;
+ }
+}
diff --git a/assets/css/navigation.css b/assets/css/navigation.css
new file mode 100644
index 00000000000..cb729669732
--- /dev/null
+++ b/assets/css/navigation.css
@@ -0,0 +1,77 @@
+.navigation {
+ height: 75px;
+ background-color: white;
+ border-bottom: 1px solid #e6e6e6;
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ padding: 0 100px;
+ margin-bottom: 60px;
+}
+
+.navigation .navigation__column:first-child img {
+ height: 45px;
+}
+
+.navigation .navigations__links {
+ display: flex;
+ padding: 0;
+ list-style-type: none;
+}
+
+.navigation .navigation__list-item {
+ margin-left: 30px;
+ padding: 0 2px;
+ opacity: 0;
+ animation: slideNavLink 0.5s ease-out forwards;
+}
+
+@keyframes slideNavLink {
+ from {
+ transform: translateY(-10px);
+ }
+ to {
+ opacity: 1;
+ transform: none;
+ }
+}
+
+.navigation .navigation__list-item:nth-child(2) {
+ animation-delay: 0.2s;
+}
+
+.navigation .navigation__list-item:last-child {
+ animation-delay: 0.3s;
+}
+
+.navigation__link {
+ color: rgba(0, 0, 0, 0.8);
+ font-size: 18px;
+}
+
+.navigation__column input {
+ padding: 5px 0;
+ padding-left: 60px;
+ border: 0;
+ border: 1px solid #e6e6e6;
+ border-radius: 3px;
+ background: #fafafa;
+ font-size: 16px;
+}
+
+.navigation__column input:focus {
+ outline: none;
+ border: 1px solid #a9a9a9;
+}
+
+.navigation__column {
+ position: relative;
+}
+
+.navigation__column .fa-search {
+ position: absolute;
+ top: 10px;
+ left: 10px;
+ color: rgba(0, 0, 0, 0.5);
+ font-size: 12px;
+}
diff --git a/assets/css/profile.css b/assets/css/profile.css
new file mode 100644
index 00000000000..5d115215978
--- /dev/null
+++ b/assets/css/profile.css
@@ -0,0 +1,161 @@
+#profile {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+}
+
+#profile .profile__header {
+ max-width: 935px;
+ width: 100%;
+ display: flex;
+ margin-bottom: 50px;
+ font-size: 110%;
+}
+
+.profile__header .profile__column {
+ width: 70%;
+}
+
+.profile__header .profile__column:first-child {
+ width: 30%;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+}
+
+.profile__column:first-child img {
+ border-radius: 50%;
+ transform-style: preserve-3d;
+ transition: transform 0.5s linear;
+ animation: rotateLynn 1s linear infinite;
+}
+
+@keyframes rotateLynn {
+ from {
+ transform: rotateY(0turn);
+ }
+ to {
+ transform: rotateY(1turn);
+ }
+}
+
+.profile__column .profile__title,
+.profile__column .profile__stats {
+ display: flex;
+ align-items: center;
+}
+
+.profile__column .profile__title {
+ margin-bottom: 30px;
+}
+
+.profile__title .profile__username {
+ margin-right: 25px;
+ font-size: 32px;
+ font-weight: 300;
+}
+
+.profile__title a {
+ margin-right: 10px;
+ text-decoration: none;
+ color: inherit;
+ font-weight: 600;
+ padding: 5px 25px;
+ border: 1px solid #e6e6e6;
+ border-radius: 3px;
+ transition: all 0.3s ease-in-out;
+}
+
+.profile__title a:hover {
+ background-color: #3f99ed;
+ color: white;
+ border-color: #3f99ed;
+}
+
+.profile__title i {
+ cursor: pointer;
+ transition: transform 1s ease-in;
+}
+
+.profile__title i:hover {
+ transform: rotate(2turn);
+}
+
+.profile__column .profile__stats {
+ margin-bottom: 30px;
+}
+
+.profile__stats .profile__stat {
+ margin-right: 40px;
+}
+
+.profile__stat .stat__number {
+ font-weight: 600;
+}
+
+.profile__bio .profile__full-name {
+ font-weight: 600;
+}
+
+.profile__bio a {
+ color: var(--link-color);
+ font-weight: 600;
+ text-decoration: none;
+ display: block;
+}
+
+.profile__column .profile__bio {
+ line-height: 125%;
+}
+
+#profile .profile__photos {
+ display: flex;
+ flex-wrap: wrap;
+ justify-content: space-between;
+ max-width: 936px;
+ width: 100%;
+}
+
+.profile__photos .profile__photo {
+ width: 31%;
+ margin-bottom: 35px;
+ position: relative;
+}
+
+.profile__photo img {
+ max-width: 100%;
+}
+
+.profile__photo .profile__photo-overlay {
+ position: absolute;
+ top: 0;
+ background-color: rgba(0, 0, 0, 0.5);
+ width: 100%;
+ height: 100%;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ color: white;
+ font-weight: 600;
+ opacity: 0;
+ transition: opacity 0.2s linear;
+}
+
+.profile__photo:hover .profile__photo-overlay {
+ opacity: 1;
+}
+
+.profile__photo-overlay .overlay__item {
+ font-size: 130%;
+ display: flex;
+ align-items: center;
+}
+.profile__photo-overlay .overlay__item:last-child {
+ margin-left: 10px;
+ /**/
+}
+
+.profile__photo-overlay .overlay__item i {
+ font-size: 130%;
+ margin-right: 5px;
+}
diff --git a/assets/css/reset.css b/assets/css/reset.css
new file mode 100644
index 00000000000..82935aeceff
--- /dev/null
+++ b/assets/css/reset.css
@@ -0,0 +1,124 @@
+html,
+body,
+div,
+span,
+applet,
+object,
+iframe,
+h1,
+h2,
+h3,
+h4,
+h5,
+h6,
+p,
+blockquote,
+pre,
+a,
+abbr,
+acronym,
+address,
+big,
+cite,
+code,
+del,
+dfn,
+em,
+img,
+ins,
+kbd,
+q,
+s,
+samp,
+small,
+strike,
+strong,
+sub,
+sup,
+tt,
+var,
+b,
+u,
+i,
+center,
+dl,
+dt,
+dd,
+ol,
+ul,
+li,
+fieldset,
+form,
+label,
+legend,
+table,
+caption,
+tbody,
+tfoot,
+thead,
+tr,
+th,
+td,
+article,
+aside,
+canvas,
+details,
+embed,
+figure,
+figcaption,
+footer,
+header,
+hgroup,
+menu,
+nav,
+output,
+ruby,
+section,
+summary,
+time,
+mark,
+audio,
+video {
+ margin: 0;
+ padding: 0;
+ border: 0;
+ font-size: 100%;
+ font: inherit;
+ vertical-align: baseline;
+}
+/* HTML5 display-role reset for older browsers */
+article,
+aside,
+details,
+figcaption,
+figure,
+footer,
+header,
+hgroup,
+menu,
+nav,
+section {
+ display: block;
+}
+body {
+ line-height: 1;
+}
+ol,
+ul {
+ list-style: none;
+}
+blockquote,
+q {
+ quotes: none;
+}
+blockquote:before,
+blockquote:after,
+q:before,
+q:after {
+ content: "";
+ content: none;
+}
+table {
+ border-collapse: collapse;
+ border-spacing: 0;
+}
diff --git a/assets/css/styles.css b/assets/css/styles.css
new file mode 100644
index 00000000000..09dd98497fc
--- /dev/null
+++ b/assets/css/styles.css
@@ -0,0 +1,12 @@
+@import url("https://fonts.googleapis.com/css?family=Open+Sans:300,400,600");
+@import "reset.css";
+@import "variables.css";
+@import "globals.css";
+@import "login.css";
+@import "footer.css";
+@import "navigation.css";
+@import "explore.css";
+@import "feed.css";
+@import "profile.css";
+@import "edit-profile.css";
+@import "mobile.css";
diff --git a/assets/css/variables.css b/assets/css/variables.css
new file mode 100644
index 00000000000..0620c7ea3f3
--- /dev/null
+++ b/assets/css/variables.css
@@ -0,0 +1,5 @@
+:root {
+ --background-color: #fafafa;
+ --fd-blue: #3897f0;
+ --link-color: #003569;
+}
diff --git a/assets/images/android.png b/assets/images/android.png
new file mode 100644
index 00000000000..306aa45f29e
Binary files /dev/null and b/assets/images/android.png differ
diff --git a/assets/images/avatar.jpg b/assets/images/avatar.jpg
new file mode 100644
index 00000000000..5ef783b9abf
Binary files /dev/null and b/assets/images/avatar.jpg differ
diff --git a/assets/images/farrel.jpg b/assets/images/farrel.jpg
new file mode 100644
index 00000000000..02770da822a
Binary files /dev/null and b/assets/images/farrel.jpg differ
diff --git a/assets/images/feedPhoto.jpg b/assets/images/feedPhoto.jpg
new file mode 100644
index 00000000000..f1da1a8cf0d
Binary files /dev/null and b/assets/images/feedPhoto.jpg differ
diff --git a/assets/images/gabungan.png b/assets/images/gabungan.png
new file mode 100644
index 00000000000..3c99fc97233
Binary files /dev/null and b/assets/images/gabungan.png differ
diff --git a/assets/images/ios.png b/assets/images/ios.png
new file mode 100644
index 00000000000..460f81ab32d
Binary files /dev/null and b/assets/images/ios.png differ
diff --git a/assets/images/loginLogo.png b/assets/images/loginLogo.png
new file mode 100644
index 00000000000..332881b2ad3
Binary files /dev/null and b/assets/images/loginLogo.png differ
diff --git a/assets/images/logo.png b/assets/images/logo.png
new file mode 100644
index 00000000000..e2ab02a7522
Binary files /dev/null and b/assets/images/logo.png differ
diff --git a/assets/images/phoneImage.png b/assets/images/phoneImage.png
new file mode 100644
index 00000000000..949173e7366
Binary files /dev/null and b/assets/images/phoneImage.png differ
diff --git a/assets/images/silvia.png b/assets/images/silvia.png
new file mode 100644
index 00000000000..218880a4dca
Binary files /dev/null and b/assets/images/silvia.png differ
diff --git a/build-release.sh b/build-release.sh
old mode 100755
new mode 100644
diff --git a/composer.json b/composer.json
index 39c7e77c4d9..4a1b33313c4 100644
--- a/composer.json
+++ b/composer.json
@@ -5,13 +5,13 @@
"homepage": "https://codeigniter.com",
"license": "MIT",
"support": {
- "forum": "https://forum.codeigniter.com/",
+ "forum": "http://forum.codeigniter.com/",
"wiki": "https://github.com/bcit-ci/CodeIgniter/wiki",
"slack": "https://codeigniterchat.slack.com",
"source": "https://github.com/bcit-ci/CodeIgniter"
},
"require": {
- "php": ">=5.4.8"
+ "php": ">=5.3.7"
},
"suggest": {
"paragonie/random_compat": "Provides better randomness in PHP 5.x"
diff --git a/contributing.md b/contributing.md
index 8f43c45a652..703fe8f44a2 100644
--- a/contributing.md
+++ b/contributing.md
@@ -28,14 +28,14 @@ If you change anything that requires a change to documentation then you will nee
### Compatibility
-CodeIgniter recommends PHP 5.5 or newer to be used, but it should be
+CodeIgniter recommends PHP 5.4 or newer to be used, but it should be
compatible with PHP 5.2.4 so all code supplied must stick to this
requirement. If PHP 5.3 (and above) functions or features are used then
there must be a fallback for PHP 5.2.4.
### Branching
-CodeIgniter uses the [Git-Flow](https://nvie.com/posts/a-successful-git-branching-model/) branching model which requires all pull requests to be sent to the "develop" branch. This is
+CodeIgniter uses the [Git-Flow](http://nvie.com/posts/a-successful-git-branching-model/) branching model which requires all pull requests to be sent to the "develop" branch. This is
where the next planned version will be developed. The "master" branch will always contain the latest stable version and is kept clean so a "hotfix" (e.g: an emergency security patch) can be applied to master to create a new version, without worrying about other features holding it up. For this reason all commits need to be made to "develop" and any sent to "master" will be closed automatically. If you have multiple changes to submit, please place all changes into their own branch on your fork.
One thing at a time: A pull request should only contain one change. That does not mean only one commit, but one change - however many commits it took. The reason for this is that if you change X and Y but send a pull request for both at the same time, we might really want X but disagree with Y, meaning we cannot merge the request. Using the Git-Flow branching model you can create new branches for both of these features and send two requests.
@@ -54,7 +54,7 @@ This will sign your commits with the information setup in your git config, e.g.
`Signed-off-by: John Q Public `
-If you are using [Tower](https://www.git-tower.com/) there is a "Sign-Off" checkbox in the commit window. You could even alias git commit to use the `-s` flag so you don’t have to think about it.
+If you are using [Tower](http://www.git-tower.com/) there is a "Sign-Off" checkbox in the commit window. You could even alias git commit to use the `-s` flag so you don’t have to think about it.
By signing your work in this manner, you certify to a "Developer's Certificate of Origin". The current version of this certificate is in the `DCO.txt` file in the root of this repository.
diff --git a/database/insta.sql b/database/insta.sql
new file mode 100644
index 00000000000..f1361d8c2ac
--- /dev/null
+++ b/database/insta.sql
@@ -0,0 +1,123 @@
+-- phpMyAdmin SQL Dump
+-- version 4.9.1
+-- https://www.phpmyadmin.net/
+--
+-- Host: localhost
+-- Generation Time: Apr 18, 2020 at 03:33 PM
+-- Server version: 10.4.8-MariaDB
+-- PHP Version: 7.1.32
+
+SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO";
+SET AUTOCOMMIT = 0;
+START TRANSACTION;
+SET time_zone = "+00:00";
+
+
+/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
+/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
+/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
+/*!40101 SET NAMES utf8mb4 */;
+
+--
+-- Database: `insta`
+--
+
+-- --------------------------------------------------------
+
+--
+-- Table structure for table `photo`
+--
+
+CREATE TABLE `photo` (
+ `id` int(11) NOT NULL,
+ `url` varchar(30) NOT NULL,
+ `caption` varchar(100) NOT NULL,
+ `like` bigint(255) DEFAULT NULL
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
+
+--
+-- Dumping data for table `photo`
+--
+
+INSERT INTO `photo` (`id`, `url`, `caption`, `like`) VALUES
+(1, 'silvia.png', 'kok bisa?', 696969),
+(2, 'gabungan.png', 'lah kok bisa???', 6969);
+
+-- --------------------------------------------------------
+
+--
+-- Table structure for table `profile`
+--
+
+CREATE TABLE `profile` (
+ `name` varchar(25) NOT NULL,
+ `username` varchar(25) NOT NULL,
+ `website` varchar(30) NOT NULL,
+ `bio` varchar(100) NOT NULL,
+ `email` varchar(30) NOT NULL,
+ `phonenumber` varchar(12) NOT NULL,
+ `gender` varchar(6) NOT NULL
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
+
+--
+-- Dumping data for table `profile`
+--
+
+INSERT INTO `profile` (`name`, `username`, `website`, `bio`, `email`, `phonenumber`, `gender`) VALUES
+('Muhammad Farrel', 'farrelm__', 'muhammadfarrel.github.io', 'phusying rek', 'farrel@gmail.com', '08114551997', 'male');
+
+-- --------------------------------------------------------
+
+--
+-- Table structure for table `user`
+--
+
+CREATE TABLE `user` (
+ `username` varchar(25) NOT NULL,
+ `password` varchar(50) NOT NULL,
+ `email` varchar(30) NOT NULL
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
+
+--
+-- Dumping data for table `user`
+--
+
+INSERT INTO `user` (`username`, `password`, `email`) VALUES
+('farrelm__', '123', 'farrel@gmail.com');
+
+--
+-- Indexes for dumped tables
+--
+
+--
+-- Indexes for table `photo`
+--
+ALTER TABLE `photo`
+ ADD PRIMARY KEY (`id`);
+
+--
+-- Indexes for table `profile`
+--
+ALTER TABLE `profile`
+ ADD PRIMARY KEY (`username`);
+
+--
+-- Indexes for table `user`
+--
+ALTER TABLE `user`
+ ADD PRIMARY KEY (`username`);
+
+--
+-- AUTO_INCREMENT for dumped tables
+--
+
+--
+-- AUTO_INCREMENT for table `photo`
+--
+ALTER TABLE `photo`
+ MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=9;
+COMMIT;
+
+/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
+/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
+/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
diff --git a/index.php b/index.php
old mode 100755
new mode 100644
index e7aab3b0381..e50550472ae
--- a/index.php
+++ b/index.php
@@ -73,7 +73,14 @@
case 'testing':
case 'production':
ini_set('display_errors', 0);
- error_reporting(E_ALL & ~E_NOTICE & ~E_DEPRECATED & ~E_STRICT & ~E_USER_NOTICE & ~E_USER_DEPRECATED);
+ if (version_compare(PHP_VERSION, '5.3', '>='))
+ {
+ error_reporting(E_ALL & ~E_NOTICE & ~E_DEPRECATED & ~E_STRICT & ~E_USER_NOTICE & ~E_USER_DEPRECATED);
+ }
+ else
+ {
+ error_reporting(E_ALL & ~E_NOTICE & ~E_STRICT & ~E_USER_NOTICE);
+ }
break;
default:
diff --git a/readme.rst b/readme.rst
index 3e1382fbd8a..b6520080e91 100644
--- a/readme.rst
+++ b/readme.rst
@@ -31,7 +31,7 @@ Server Requirements
PHP version 5.6 or newer is recommended.
-It should work on 5.4.8 as well, but we strongly advise you NOT to run
+It should work on 5.3.7 as well, but we strongly advise you NOT to run
such old versions of PHP, because of potential security and performance
issues, as well as missing features.
@@ -55,7 +55,7 @@ Resources
- `User Guide `_
- `Language File Translations `_
-- `Community Forums `_
+- `Community Forums `_
- `Community Wiki `_
- `Community Slack Channel `_
diff --git a/system/database/drivers/sqlite/index.html b/system/database/drivers/sqlite/index.html
new file mode 100644
index 00000000000..b702fbc3967
--- /dev/null
+++ b/system/database/drivers/sqlite/index.html
@@ -0,0 +1,11 @@
+
+
+
+ 403 Forbidden
+
+
+
+
Directory access is forbidden.
+
+
+
diff --git a/system/database/drivers/sqlite/sqlite_driver.php b/system/database/drivers/sqlite/sqlite_driver.php
new file mode 100644
index 00000000000..aec3d748c14
--- /dev/null
+++ b/system/database/drivers/sqlite/sqlite_driver.php
@@ -0,0 +1,330 @@
+database, 0666, $error)
+ : sqlite_open($this->database, 0666, $error);
+
+ isset($error) && log_message('error', $error);
+
+ return $conn_id;
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Database version number
+ *
+ * @return string
+ */
+ public function version()
+ {
+ return isset($this->data_cache['version'])
+ ? $this->data_cache['version']
+ : $this->data_cache['version'] = sqlite_libversion();
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Execute the query
+ *
+ * @param string $sql an SQL query
+ * @return resource
+ */
+ protected function _execute($sql)
+ {
+ return $this->is_write_type($sql)
+ ? sqlite_exec($this->conn_id, $sql)
+ : sqlite_query($this->conn_id, $sql);
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Begin Transaction
+ *
+ * @return bool
+ */
+ protected function _trans_begin()
+ {
+ return $this->simple_query('BEGIN TRANSACTION');
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Commit Transaction
+ *
+ * @return bool
+ */
+ protected function _trans_commit()
+ {
+ return $this->simple_query('COMMIT');
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Rollback Transaction
+ *
+ * @return bool
+ */
+ protected function _trans_rollback()
+ {
+ return $this->simple_query('ROLLBACK');
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Platform-dependant string escape
+ *
+ * @param string
+ * @return string
+ */
+ protected function _escape_str($str)
+ {
+ return sqlite_escape_string($str);
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Affected Rows
+ *
+ * @return int
+ */
+ public function affected_rows()
+ {
+ return sqlite_changes($this->conn_id);
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Insert ID
+ *
+ * @return int
+ */
+ public function insert_id()
+ {
+ return sqlite_last_insert_rowid($this->conn_id);
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * List table query
+ *
+ * Generates a platform-specific query string so that the table names can be fetched
+ *
+ * @param bool $prefix_limit
+ * @return string
+ */
+ protected function _list_tables($prefix_limit = FALSE)
+ {
+ $sql = "SELECT name FROM sqlite_master WHERE type='table'";
+
+ if ($prefix_limit !== FALSE && $this->dbprefix != '')
+ {
+ return $sql." AND 'name' LIKE '".$this->escape_like_str($this->dbprefix)."%' ".sprintf($this->_like_escape_str, $this->_like_escape_chr);
+ }
+
+ return $sql;
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Show column query
+ *
+ * Generates a platform-specific query string so that the column names can be fetched
+ *
+ * @param string $table
+ * @return bool
+ */
+ protected function _list_columns($table = '')
+ {
+ // Not supported
+ return FALSE;
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Returns an object with field data
+ *
+ * @param string $table
+ * @return array
+ */
+ public function field_data($table)
+ {
+ if (($query = $this->query('PRAGMA TABLE_INFO('.$this->protect_identifiers($table, TRUE, NULL, FALSE).')')) === FALSE)
+ {
+ return FALSE;
+ }
+
+ $query = $query->result_array();
+ if (empty($query))
+ {
+ return FALSE;
+ }
+
+ $retval = array();
+ for ($i = 0, $c = count($query); $i < $c; $i++)
+ {
+ $retval[$i] = new stdClass();
+ $retval[$i]->name = $query[$i]['name'];
+ $retval[$i]->type = $query[$i]['type'];
+ $retval[$i]->max_length = NULL;
+ $retval[$i]->default = $query[$i]['dflt_value'];
+ $retval[$i]->primary_key = isset($query[$i]['pk']) ? (int) $query[$i]['pk'] : 0;
+ }
+
+ return $retval;
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Error
+ *
+ * Returns an array containing code and message of the last
+ * database error that has occured.
+ *
+ * @return array
+ */
+ public function error()
+ {
+ $error = array('code' => sqlite_last_error($this->conn_id));
+ $error['message'] = sqlite_error_string($error['code']);
+ return $error;
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Replace statement
+ *
+ * Generates a platform-specific replace string from the supplied data
+ *
+ * @param string $table Table name
+ * @param array $keys INSERT keys
+ * @param array $values INSERT values
+ * @return string
+ */
+ protected function _replace($table, $keys, $values)
+ {
+ return 'INSERT OR '.parent::_replace($table, $keys, $values);
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Truncate statement
+ *
+ * Generates a platform-specific truncate string from the supplied data
+ *
+ * If the database does not support the TRUNCATE statement,
+ * then this function maps to 'DELETE FROM table'
+ *
+ * @param string $table
+ * @return string
+ */
+ protected function _truncate($table)
+ {
+ return 'DELETE FROM '.$table;
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Close DB Connection
+ *
+ * @return void
+ */
+ protected function _close()
+ {
+ sqlite_close($this->conn_id);
+ }
+
+}
diff --git a/system/database/drivers/sqlite/sqlite_forge.php b/system/database/drivers/sqlite/sqlite_forge.php
new file mode 100644
index 00000000000..6aa9c61c473
--- /dev/null
+++ b/system/database/drivers/sqlite/sqlite_forge.php
@@ -0,0 +1,205 @@
+db->database) OR ! @unlink($this->db->database))
+ {
+ return ($this->db->db_debug) ? $this->db->display_error('db_unable_to_drop') : FALSE;
+ }
+ elseif ( ! empty($this->db->data_cache['db_names']))
+ {
+ $key = array_search(strtolower($this->db->database), array_map('strtolower', $this->db->data_cache['db_names']), TRUE);
+ if ($key !== FALSE)
+ {
+ unset($this->db->data_cache['db_names'][$key]);
+ }
+ }
+
+ return TRUE;
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * ALTER TABLE
+ *
+ * @todo implement drop_column(), modify_column()
+ * @param string $alter_type ALTER type
+ * @param string $table Table name
+ * @param mixed $field Column definition
+ * @return string|string[]
+ */
+ protected function _alter_table($alter_type, $table, $field)
+ {
+ if ($alter_type === 'DROP' OR $alter_type === 'CHANGE')
+ {
+ // drop_column():
+ // BEGIN TRANSACTION;
+ // CREATE TEMPORARY TABLE t1_backup(a,b);
+ // INSERT INTO t1_backup SELECT a,b FROM t1;
+ // DROP TABLE t1;
+ // CREATE TABLE t1(a,b);
+ // INSERT INTO t1 SELECT a,b FROM t1_backup;
+ // DROP TABLE t1_backup;
+ // COMMIT;
+
+ return FALSE;
+ }
+
+ return parent::_alter_table($alter_type, $table, $field);
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Process column
+ *
+ * @param array $field
+ * @return string
+ */
+ protected function _process_column($field)
+ {
+ return $this->db->escape_identifiers($field['name'])
+ .' '.$field['type']
+ .$field['auto_increment']
+ .$field['null']
+ .$field['unique']
+ .$field['default'];
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Field attribute TYPE
+ *
+ * Performs a data type mapping between different databases.
+ *
+ * @param array &$attributes
+ * @return void
+ */
+ protected function _attr_type(&$attributes)
+ {
+ switch (strtoupper($attributes['TYPE']))
+ {
+ case 'ENUM':
+ case 'SET':
+ $attributes['TYPE'] = 'TEXT';
+ return;
+ default: return;
+ }
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Field attribute AUTO_INCREMENT
+ *
+ * @param array &$attributes
+ * @param array &$field
+ * @return void
+ */
+ protected function _attr_auto_increment(&$attributes, &$field)
+ {
+ if ( ! empty($attributes['AUTO_INCREMENT']) && $attributes['AUTO_INCREMENT'] === TRUE && stripos($field['type'], 'int') !== FALSE)
+ {
+ $field['type'] = 'INTEGER PRIMARY KEY';
+ $field['default'] = '';
+ $field['null'] = '';
+ $field['unique'] = '';
+ $field['auto_increment'] = ' AUTOINCREMENT';
+
+ $this->primary_keys = array();
+ }
+ }
+
+}
diff --git a/system/database/drivers/sqlite/sqlite_result.php b/system/database/drivers/sqlite/sqlite_result.php
new file mode 100644
index 00000000000..30c93a26fa0
--- /dev/null
+++ b/system/database/drivers/sqlite/sqlite_result.php
@@ -0,0 +1,164 @@
+num_rows)
+ ? $this->num_rows
+ : $this->num_rows = @sqlite_num_rows($this->result_id);
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Number of fields in the result set
+ *
+ * @return int
+ */
+ public function num_fields()
+ {
+ return @sqlite_num_fields($this->result_id);
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Fetch Field Names
+ *
+ * Generates an array of column names
+ *
+ * @return array
+ */
+ public function list_fields()
+ {
+ $field_names = array();
+ for ($i = 0, $c = $this->num_fields(); $i < $c; $i++)
+ {
+ $field_names[$i] = sqlite_field_name($this->result_id, $i);
+ }
+
+ return $field_names;
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Field data
+ *
+ * Generates an array of objects containing field meta-data
+ *
+ * @return array
+ */
+ public function field_data()
+ {
+ $retval = array();
+ for ($i = 0, $c = $this->num_fields(); $i < $c; $i++)
+ {
+ $retval[$i] = new stdClass();
+ $retval[$i]->name = sqlite_field_name($this->result_id, $i);
+ $retval[$i]->type = NULL;
+ $retval[$i]->max_length = NULL;
+ }
+
+ return $retval;
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Data Seek
+ *
+ * Moves the internal pointer to the desired offset. We call
+ * this internally before fetching results to make sure the
+ * result set starts at zero.
+ *
+ * @param int $n
+ * @return bool
+ */
+ public function data_seek($n = 0)
+ {
+ return sqlite_seek($this->result_id, $n);
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Result - associative array
+ *
+ * Returns the result set as an array
+ *
+ * @return array
+ */
+ protected function _fetch_assoc()
+ {
+ return sqlite_fetch_array($this->result_id);
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Result - object
+ *
+ * Returns the result set as an object
+ *
+ * @param string $class_name
+ * @return object
+ */
+ protected function _fetch_object($class_name = 'stdClass')
+ {
+ return sqlite_fetch_object($this->result_id, $class_name);
+ }
+
+}
diff --git a/system/database/drivers/sqlite/sqlite_utility.php b/system/database/drivers/sqlite/sqlite_utility.php
new file mode 100644
index 00000000000..2c7f8099ecf
--- /dev/null
+++ b/system/database/drivers/sqlite/sqlite_utility.php
@@ -0,0 +1,61 @@
+db->display_error('db_unsupported_feature');
+ }
+
+}
diff --git a/system/helpers/email_helper.php b/system/helpers/email_helper.php
new file mode 100644
index 00000000000..b25875974d3
--- /dev/null
+++ b/system/helpers/email_helper.php
@@ -0,0 +1,84 @@
+field_id pairs
+ * @param string field_id if alias name was passed in
+ * @param bool
+ * @return array
+ */
+ function smiley_js($alias = '', $field_id = '', $inline = TRUE)
+ {
+ static $do_setup = TRUE;
+ $r = '';
+
+ if ($alias !== '' && ! is_array($alias))
+ {
+ $alias = array($alias => $field_id);
+ }
+
+ if ($do_setup === TRUE)
+ {
+ $do_setup = FALSE;
+ $m = array();
+
+ if (is_array($alias))
+ {
+ foreach ($alias as $name => $id)
+ {
+ $m[] = '"'.$name.'" : "'.$id.'"';
+ }
+ }
+
+ $m = '{'.implode(',', $m).'}';
+
+ $r .= << $id)
+ {
+ $r .= 'smiley_map["'.$name.'"] = "'.$id."\";\n";
+ }
+ }
+
+ return ($inline)
+ ? ''
+ : $r;
+ }
+}
+
+// ------------------------------------------------------------------------
+
+if ( ! function_exists('get_clickable_smileys'))
+{
+ /**
+ * Get Clickable Smileys
+ *
+ * Returns an array of image tag links that can be clicked to be inserted
+ * into a form field.
+ *
+ * @param string the URL to the folder containing the smiley images
+ * @param array
+ * @return array
+ */
+ function get_clickable_smileys($image_url, $alias = '')
+ {
+ // For backward compatibility with js_insert_smiley
+ if (is_array($alias))
+ {
+ $smileys = $alias;
+ }
+ elseif (FALSE === ($smileys = _get_smiley_array()))
+ {
+ return FALSE;
+ }
+
+ // Add a trailing slash to the file path if needed
+ $image_url = rtrim($image_url, '/').'/';
+
+ $used = array();
+ foreach ($smileys as $key => $val)
+ {
+ // Keep duplicates from being used, which can happen if the
+ // mapping array contains multiple identical replacements. For example:
+ // :-) and :) might be replaced with the same image so both smileys
+ // will be in the array.
+ if (isset($used[$smileys[$key][0]]))
+ {
+ continue;
+ }
+
+ $link[] = '';
+ $used[$smileys[$key][0]] = TRUE;
+ }
+
+ return $link;
+ }
+}
+
+// ------------------------------------------------------------------------
+
+if ( ! function_exists('parse_smileys'))
+{
+ /**
+ * Parse Smileys
+ *
+ * Takes a string as input and swaps any contained smileys for the actual image
+ *
+ * @param string the text to be parsed
+ * @param string the URL to the folder containing the smiley images
+ * @param array
+ * @return string
+ */
+ function parse_smileys($str = '', $image_url = '', $smileys = NULL)
+ {
+ if ($image_url === '' OR ( ! is_array($smileys) && FALSE === ($smileys = _get_smiley_array())))
+ {
+ return $str;
+ }
+
+ // Add a trailing slash to the file path if needed
+ $image_url = rtrim($image_url, '/').'/';
+
+ foreach ($smileys as $key => $val)
+ {
+ $str = str_replace($key, '', $str);
+ }
+
+ return $str;
+ }
+}
+
+// ------------------------------------------------------------------------
+
+if ( ! function_exists('_get_smiley_array'))
+{
+ /**
+ * Get Smiley Array
+ *
+ * Fetches the config/smiley.php file
+ *
+ * @return mixed
+ */
+ function _get_smiley_array()
+ {
+ static $_smileys;
+
+ if ( ! is_array($_smileys))
+ {
+ if (file_exists(APPPATH.'config/smileys.php'))
+ {
+ include(APPPATH.'config/smileys.php');
+ }
+
+ if (file_exists(APPPATH.'config/'.ENVIRONMENT.'/smileys.php'))
+ {
+ include(APPPATH.'config/'.ENVIRONMENT.'/smileys.php');
+ }
+
+ if (empty($smileys) OR ! is_array($smileys))
+ {
+ $_smileys = array();
+ return FALSE;
+ }
+
+ $_smileys = $smileys;
+ }
+
+ return $_smileys;
+ }
+}
diff --git a/system/libraries/Cart.php b/system/libraries/Cart.php
new file mode 100644
index 00000000000..6a107752caf
--- /dev/null
+++ b/system/libraries/Cart.php
@@ -0,0 +1,567 @@
+CI =& get_instance();
+
+ // Are any config settings being passed manually? If so, set them
+ $config = is_array($params) ? $params : array();
+
+ // Load the Sessions class
+ $this->CI->load->driver('session', $config);
+
+ // Grab the shopping cart array from the session table
+ $this->_cart_contents = $this->CI->session->userdata('cart_contents');
+ if ($this->_cart_contents === NULL)
+ {
+ // No cart exists so we'll set some base values
+ $this->_cart_contents = array('cart_total' => 0, 'total_items' => 0);
+ }
+
+ log_message('info', 'Cart Class Initialized');
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Insert items into the cart and save it to the session table
+ *
+ * @param array
+ * @return bool
+ */
+ public function insert($items = array())
+ {
+ // Was any cart data passed? No? Bah...
+ if ( ! is_array($items) OR count($items) === 0)
+ {
+ log_message('error', 'The insert method must be passed an array containing data.');
+ return FALSE;
+ }
+
+ // You can either insert a single product using a one-dimensional array,
+ // or multiple products using a multi-dimensional one. The way we
+ // determine the array type is by looking for a required array key named "id"
+ // at the top level. If it's not found, we will assume it's a multi-dimensional array.
+
+ $save_cart = FALSE;
+ if (isset($items['id']))
+ {
+ if (($rowid = $this->_insert($items)))
+ {
+ $save_cart = TRUE;
+ }
+ }
+ else
+ {
+ foreach ($items as $val)
+ {
+ if (is_array($val) && isset($val['id']))
+ {
+ if ($this->_insert($val))
+ {
+ $save_cart = TRUE;
+ }
+ }
+ }
+ }
+
+ // Save the cart data if the insert was successful
+ if ($save_cart === TRUE)
+ {
+ $this->_save_cart();
+ return isset($rowid) ? $rowid : TRUE;
+ }
+
+ return FALSE;
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Insert
+ *
+ * @param array
+ * @return bool
+ */
+ protected function _insert($items = array())
+ {
+ // Was any cart data passed? No? Bah...
+ if ( ! is_array($items) OR count($items) === 0)
+ {
+ log_message('error', 'The insert method must be passed an array containing data.');
+ return FALSE;
+ }
+
+ // --------------------------------------------------------------------
+
+ // Does the $items array contain an id, quantity, price, and name? These are required
+ if ( ! isset($items['id'], $items['qty'], $items['price'], $items['name']))
+ {
+ log_message('error', 'The cart array must contain a product ID, quantity, price, and name.');
+ return FALSE;
+ }
+
+ // --------------------------------------------------------------------
+
+ // Prep the quantity. It can only be a number. Duh... also trim any leading zeros
+ $items['qty'] = (float) $items['qty'];
+
+ // If the quantity is zero or blank there's nothing for us to do
+ if ($items['qty'] == 0)
+ {
+ return FALSE;
+ }
+
+ // --------------------------------------------------------------------
+
+ // Validate the product ID. It can only be alpha-numeric, dashes, underscores or periods
+ // Not totally sure we should impose this rule, but it seems prudent to standardize IDs.
+ // Note: These can be user-specified by setting the $this->product_id_rules variable.
+ if ( ! preg_match('/^['.$this->product_id_rules.']+$/i', $items['id']))
+ {
+ log_message('error', 'Invalid product ID. The product ID can only contain alpha-numeric characters, dashes, and underscores');
+ return FALSE;
+ }
+
+ // --------------------------------------------------------------------
+
+ // Validate the product name. It can only be alpha-numeric, dashes, underscores, colons or periods.
+ // Note: These can be user-specified by setting the $this->product_name_rules variable.
+ if ($this->product_name_safe && ! preg_match('/^['.$this->product_name_rules.']+$/i'.(UTF8_ENABLED ? 'u' : ''), $items['name']))
+ {
+ log_message('error', 'An invalid name was submitted as the product name: '.$items['name'].' The name can only contain alpha-numeric characters, dashes, underscores, colons, and spaces');
+ return FALSE;
+ }
+
+ // --------------------------------------------------------------------
+
+ // Prep the price. Remove leading zeros and anything that isn't a number or decimal point.
+ $items['price'] = (float) $items['price'];
+
+ // We now need to create a unique identifier for the item being inserted into the cart.
+ // Every time something is added to the cart it is stored in the master cart array.
+ // Each row in the cart array, however, must have a unique index that identifies not only
+ // a particular product, but makes it possible to store identical products with different options.
+ // For example, what if someone buys two identical t-shirts (same product ID), but in
+ // different sizes? The product ID (and other attributes, like the name) will be identical for
+ // both sizes because it's the same shirt. The only difference will be the size.
+ // Internally, we need to treat identical submissions, but with different options, as a unique product.
+ // Our solution is to convert the options array to a string and MD5 it along with the product ID.
+ // This becomes the unique "row ID"
+ if (isset($items['options']) && count($items['options']) > 0)
+ {
+ $rowid = md5($items['id'].serialize($items['options']));
+ }
+ else
+ {
+ // No options were submitted so we simply MD5 the product ID.
+ // Technically, we don't need to MD5 the ID in this case, but it makes
+ // sense to standardize the format of array indexes for both conditions
+ $rowid = md5($items['id']);
+ }
+
+ // --------------------------------------------------------------------
+
+ // Now that we have our unique "row ID", we'll add our cart items to the master array
+ // grab quantity if it's already there and add it on
+ $old_quantity = isset($this->_cart_contents[$rowid]['qty']) ? (int) $this->_cart_contents[$rowid]['qty'] : 0;
+
+ // Re-create the entry, just to make sure our index contains only the data from this submission
+ $items['rowid'] = $rowid;
+ $items['qty'] += $old_quantity;
+ $this->_cart_contents[$rowid] = $items;
+
+ return $rowid;
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Update the cart
+ *
+ * This function permits the quantity of a given item to be changed.
+ * Typically it is called from the "view cart" page if a user makes
+ * changes to the quantity before checkout. That array must contain the
+ * product ID and quantity for each item.
+ *
+ * @param array
+ * @return bool
+ */
+ public function update($items = array())
+ {
+ // Was any cart data passed?
+ if ( ! is_array($items) OR count($items) === 0)
+ {
+ return FALSE;
+ }
+
+ // You can either update a single product using a one-dimensional array,
+ // or multiple products using a multi-dimensional one. The way we
+ // determine the array type is by looking for a required array key named "rowid".
+ // If it's not found we assume it's a multi-dimensional array
+ $save_cart = FALSE;
+ if (isset($items['rowid']))
+ {
+ if ($this->_update($items) === TRUE)
+ {
+ $save_cart = TRUE;
+ }
+ }
+ else
+ {
+ foreach ($items as $val)
+ {
+ if (is_array($val) && isset($val['rowid']))
+ {
+ if ($this->_update($val) === TRUE)
+ {
+ $save_cart = TRUE;
+ }
+ }
+ }
+ }
+
+ // Save the cart data if the insert was successful
+ if ($save_cart === TRUE)
+ {
+ $this->_save_cart();
+ return TRUE;
+ }
+
+ return FALSE;
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Update the cart
+ *
+ * This function permits changing item properties.
+ * Typically it is called from the "view cart" page if a user makes
+ * changes to the quantity before checkout. That array must contain the
+ * rowid and quantity for each item.
+ *
+ * @param array
+ * @return bool
+ */
+ protected function _update($items = array())
+ {
+ // Without these array indexes there is nothing we can do
+ if ( ! isset($items['rowid'], $this->_cart_contents[$items['rowid']]))
+ {
+ return FALSE;
+ }
+
+ // Prep the quantity
+ if (isset($items['qty']))
+ {
+ $items['qty'] = (float) $items['qty'];
+ // Is the quantity zero? If so we will remove the item from the cart.
+ // If the quantity is greater than zero we are updating
+ if ($items['qty'] == 0)
+ {
+ unset($this->_cart_contents[$items['rowid']]);
+ return TRUE;
+ }
+ }
+
+ // find updatable keys
+ $keys = array_intersect(array_keys($this->_cart_contents[$items['rowid']]), array_keys($items));
+ // if a price was passed, make sure it contains valid data
+ if (isset($items['price']))
+ {
+ $items['price'] = (float) $items['price'];
+ }
+
+ // product id & name shouldn't be changed
+ foreach (array_diff($keys, array('id', 'name')) as $key)
+ {
+ $this->_cart_contents[$items['rowid']][$key] = $items[$key];
+ }
+
+ return TRUE;
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Save the cart array to the session DB
+ *
+ * @return bool
+ */
+ protected function _save_cart()
+ {
+ // Let's add up the individual prices and set the cart sub-total
+ $this->_cart_contents['total_items'] = $this->_cart_contents['cart_total'] = 0;
+ foreach ($this->_cart_contents as $key => $val)
+ {
+ // We make sure the array contains the proper indexes
+ if ( ! is_array($val) OR ! isset($val['price'], $val['qty']))
+ {
+ continue;
+ }
+
+ $this->_cart_contents['cart_total'] += ($val['price'] * $val['qty']);
+ $this->_cart_contents['total_items'] += $val['qty'];
+ $this->_cart_contents[$key]['subtotal'] = ($this->_cart_contents[$key]['price'] * $this->_cart_contents[$key]['qty']);
+ }
+
+ // Is our cart empty? If so we delete it from the session
+ if (count($this->_cart_contents) <= 2)
+ {
+ $this->CI->session->unset_userdata('cart_contents');
+
+ // Nothing more to do... coffee time!
+ return FALSE;
+ }
+
+ // If we made it this far it means that our cart has data.
+ // Let's pass it to the Session class so it can be stored
+ $this->CI->session->set_userdata(array('cart_contents' => $this->_cart_contents));
+
+ // Woot!
+ return TRUE;
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Cart Total
+ *
+ * @return int
+ */
+ public function total()
+ {
+ return $this->_cart_contents['cart_total'];
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Remove Item
+ *
+ * Removes an item from the cart
+ *
+ * @param int
+ * @return bool
+ */
+ public function remove($rowid)
+ {
+ // unset & save
+ unset($this->_cart_contents[$rowid]);
+ $this->_save_cart();
+ return TRUE;
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Total Items
+ *
+ * Returns the total item count
+ *
+ * @return int
+ */
+ public function total_items()
+ {
+ return $this->_cart_contents['total_items'];
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Cart Contents
+ *
+ * Returns the entire cart array
+ *
+ * @param bool
+ * @return array
+ */
+ public function contents($newest_first = FALSE)
+ {
+ // do we want the newest first?
+ $cart = ($newest_first) ? array_reverse($this->_cart_contents) : $this->_cart_contents;
+
+ // Remove these so they don't create a problem when showing the cart table
+ unset($cart['total_items']);
+ unset($cart['cart_total']);
+
+ return $cart;
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Get cart item
+ *
+ * Returns the details of a specific item in the cart
+ *
+ * @param string $row_id
+ * @return array
+ */
+ public function get_item($row_id)
+ {
+ return (in_array($row_id, array('total_items', 'cart_total'), TRUE) OR ! isset($this->_cart_contents[$row_id]))
+ ? FALSE
+ : $this->_cart_contents[$row_id];
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Has options
+ *
+ * Returns TRUE if the rowid passed to this function correlates to an item
+ * that has options associated with it.
+ *
+ * @param string $row_id = ''
+ * @return bool
+ */
+ public function has_options($row_id = '')
+ {
+ return (isset($this->_cart_contents[$row_id]['options']) && count($this->_cart_contents[$row_id]['options']) !== 0);
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Product options
+ *
+ * Returns the an array of options, for a particular product row ID
+ *
+ * @param string $row_id = ''
+ * @return array
+ */
+ public function product_options($row_id = '')
+ {
+ return isset($this->_cart_contents[$row_id]['options']) ? $this->_cart_contents[$row_id]['options'] : array();
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Format Number
+ *
+ * Returns the supplied number with commas and a decimal point.
+ *
+ * @param float
+ * @return string
+ */
+ public function format_number($n = '')
+ {
+ return ($n === '') ? '' : number_format( (float) $n, 2, '.', ',');
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Destroy the cart
+ *
+ * Empties the cart and kills the session
+ *
+ * @return void
+ */
+ public function destroy()
+ {
+ $this->_cart_contents = array('cart_total' => 0, 'total_items' => 0);
+ $this->CI->session->unset_userdata('cart_contents');
+ }
+
+}
diff --git a/system/libraries/Javascript.php b/system/libraries/Javascript.php
new file mode 100644
index 00000000000..c9103945b73
--- /dev/null
+++ b/system/libraries/Javascript.php
@@ -0,0 +1,856 @@
+ 'jquery', 'autoload' => TRUE);
+
+ foreach ($defaults as $key => $val)
+ {
+ if (isset($params[$key]) && $params[$key] !== '')
+ {
+ $defaults[$key] = $params[$key];
+ }
+ }
+
+ extract($defaults);
+
+ $this->CI =& get_instance();
+
+ // load the requested js library
+ $this->CI->load->library('Javascript/'.$js_library_driver, array('autoload' => $autoload));
+ // make js to refer to current library
+ $this->js =& $this->CI->$js_library_driver;
+
+ log_message('info', 'Javascript Class Initialized and loaded. Driver used: '.$js_library_driver);
+ }
+
+ // --------------------------------------------------------------------
+ // Event Code
+ // --------------------------------------------------------------------
+
+ /**
+ * Blur
+ *
+ * Outputs a javascript library blur event
+ *
+ * @param string The element to attach the event to
+ * @param string The code to execute
+ * @return string
+ */
+ public function blur($element = 'this', $js = '')
+ {
+ return $this->js->_blur($element, $js);
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Change
+ *
+ * Outputs a javascript library change event
+ *
+ * @param string The element to attach the event to
+ * @param string The code to execute
+ * @return string
+ */
+ public function change($element = 'this', $js = '')
+ {
+ return $this->js->_change($element, $js);
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Click
+ *
+ * Outputs a javascript library click event
+ *
+ * @param string The element to attach the event to
+ * @param string The code to execute
+ * @param bool whether or not to return false
+ * @return string
+ */
+ public function click($element = 'this', $js = '', $ret_false = TRUE)
+ {
+ return $this->js->_click($element, $js, $ret_false);
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Double Click
+ *
+ * Outputs a javascript library dblclick event
+ *
+ * @param string The element to attach the event to
+ * @param string The code to execute
+ * @return string
+ */
+ public function dblclick($element = 'this', $js = '')
+ {
+ return $this->js->_dblclick($element, $js);
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Error
+ *
+ * Outputs a javascript library error event
+ *
+ * @param string The element to attach the event to
+ * @param string The code to execute
+ * @return string
+ */
+ public function error($element = 'this', $js = '')
+ {
+ return $this->js->_error($element, $js);
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Focus
+ *
+ * Outputs a javascript library focus event
+ *
+ * @param string The element to attach the event to
+ * @param string The code to execute
+ * @return string
+ */
+ public function focus($element = 'this', $js = '')
+ {
+ return $this->js->_focus($element, $js);
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Hover
+ *
+ * Outputs a javascript library hover event
+ *
+ * @param string - element
+ * @param string - Javascript code for mouse over
+ * @param string - Javascript code for mouse out
+ * @return string
+ */
+ public function hover($element = 'this', $over = '', $out = '')
+ {
+ return $this->js->_hover($element, $over, $out);
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Keydown
+ *
+ * Outputs a javascript library keydown event
+ *
+ * @param string The element to attach the event to
+ * @param string The code to execute
+ * @return string
+ */
+ public function keydown($element = 'this', $js = '')
+ {
+ return $this->js->_keydown($element, $js);
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Keyup
+ *
+ * Outputs a javascript library keydown event
+ *
+ * @param string The element to attach the event to
+ * @param string The code to execute
+ * @return string
+ */
+ public function keyup($element = 'this', $js = '')
+ {
+ return $this->js->_keyup($element, $js);
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Load
+ *
+ * Outputs a javascript library load event
+ *
+ * @param string The element to attach the event to
+ * @param string The code to execute
+ * @return string
+ */
+ public function load($element = 'this', $js = '')
+ {
+ return $this->js->_load($element, $js);
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Mousedown
+ *
+ * Outputs a javascript library mousedown event
+ *
+ * @param string The element to attach the event to
+ * @param string The code to execute
+ * @return string
+ */
+ public function mousedown($element = 'this', $js = '')
+ {
+ return $this->js->_mousedown($element, $js);
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Mouse Out
+ *
+ * Outputs a javascript library mouseout event
+ *
+ * @param string The element to attach the event to
+ * @param string The code to execute
+ * @return string
+ */
+ public function mouseout($element = 'this', $js = '')
+ {
+ return $this->js->_mouseout($element, $js);
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Mouse Over
+ *
+ * Outputs a javascript library mouseover event
+ *
+ * @param string The element to attach the event to
+ * @param string The code to execute
+ * @return string
+ */
+ public function mouseover($element = 'this', $js = '')
+ {
+ return $this->js->_mouseover($element, $js);
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Mouseup
+ *
+ * Outputs a javascript library mouseup event
+ *
+ * @param string The element to attach the event to
+ * @param string The code to execute
+ * @return string
+ */
+ public function mouseup($element = 'this', $js = '')
+ {
+ return $this->js->_mouseup($element, $js);
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Output
+ *
+ * Outputs the called javascript to the screen
+ *
+ * @param string The code to output
+ * @return string
+ */
+ public function output($js)
+ {
+ return $this->js->_output($js);
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Ready
+ *
+ * Outputs a javascript library mouseup event
+ *
+ * @param string $js Code to execute
+ * @return string
+ */
+ public function ready($js)
+ {
+ return $this->js->_document_ready($js);
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Resize
+ *
+ * Outputs a javascript library resize event
+ *
+ * @param string The element to attach the event to
+ * @param string The code to execute
+ * @return string
+ */
+ public function resize($element = 'this', $js = '')
+ {
+ return $this->js->_resize($element, $js);
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Scroll
+ *
+ * Outputs a javascript library scroll event
+ *
+ * @param string The element to attach the event to
+ * @param string The code to execute
+ * @return string
+ */
+ public function scroll($element = 'this', $js = '')
+ {
+ return $this->js->_scroll($element, $js);
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Unload
+ *
+ * Outputs a javascript library unload event
+ *
+ * @param string The element to attach the event to
+ * @param string The code to execute
+ * @return string
+ */
+ public function unload($element = 'this', $js = '')
+ {
+ return $this->js->_unload($element, $js);
+ }
+
+ // --------------------------------------------------------------------
+ // Effects
+ // --------------------------------------------------------------------
+
+ /**
+ * Add Class
+ *
+ * Outputs a javascript library addClass event
+ *
+ * @param string - element
+ * @param string - Class to add
+ * @return string
+ */
+ public function addClass($element = 'this', $class = '')
+ {
+ return $this->js->_addClass($element, $class);
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Animate
+ *
+ * Outputs a javascript library animate event
+ *
+ * @param string $element = 'this'
+ * @param array $params = array()
+ * @param mixed $speed 'slow', 'normal', 'fast', or time in milliseconds
+ * @param string $extra
+ * @return string
+ */
+ public function animate($element = 'this', $params = array(), $speed = '', $extra = '')
+ {
+ return $this->js->_animate($element, $params, $speed, $extra);
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Fade In
+ *
+ * Outputs a javascript library hide event
+ *
+ * @param string - element
+ * @param string - One of 'slow', 'normal', 'fast', or time in milliseconds
+ * @param string - Javascript callback function
+ * @return string
+ */
+ public function fadeIn($element = 'this', $speed = '', $callback = '')
+ {
+ return $this->js->_fadeIn($element, $speed, $callback);
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Fade Out
+ *
+ * Outputs a javascript library hide event
+ *
+ * @param string - element
+ * @param string - One of 'slow', 'normal', 'fast', or time in milliseconds
+ * @param string - Javascript callback function
+ * @return string
+ */
+ public function fadeOut($element = 'this', $speed = '', $callback = '')
+ {
+ return $this->js->_fadeOut($element, $speed, $callback);
+ }
+ // --------------------------------------------------------------------
+
+ /**
+ * Slide Up
+ *
+ * Outputs a javascript library slideUp event
+ *
+ * @param string - element
+ * @param string - One of 'slow', 'normal', 'fast', or time in milliseconds
+ * @param string - Javascript callback function
+ * @return string
+ */
+ public function slideUp($element = 'this', $speed = '', $callback = '')
+ {
+ return $this->js->_slideUp($element, $speed, $callback);
+
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Remove Class
+ *
+ * Outputs a javascript library removeClass event
+ *
+ * @param string - element
+ * @param string - Class to add
+ * @return string
+ */
+ public function removeClass($element = 'this', $class = '')
+ {
+ return $this->js->_removeClass($element, $class);
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Slide Down
+ *
+ * Outputs a javascript library slideDown event
+ *
+ * @param string - element
+ * @param string - One of 'slow', 'normal', 'fast', or time in milliseconds
+ * @param string - Javascript callback function
+ * @return string
+ */
+ public function slideDown($element = 'this', $speed = '', $callback = '')
+ {
+ return $this->js->_slideDown($element, $speed, $callback);
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Slide Toggle
+ *
+ * Outputs a javascript library slideToggle event
+ *
+ * @param string - element
+ * @param string - One of 'slow', 'normal', 'fast', or time in milliseconds
+ * @param string - Javascript callback function
+ * @return string
+ */
+ public function slideToggle($element = 'this', $speed = '', $callback = '')
+ {
+ return $this->js->_slideToggle($element, $speed, $callback);
+
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Hide
+ *
+ * Outputs a javascript library hide action
+ *
+ * @param string - element
+ * @param string - One of 'slow', 'normal', 'fast', or time in milliseconds
+ * @param string - Javascript callback function
+ * @return string
+ */
+ public function hide($element = 'this', $speed = '', $callback = '')
+ {
+ return $this->js->_hide($element, $speed, $callback);
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Toggle
+ *
+ * Outputs a javascript library toggle event
+ *
+ * @param string - element
+ * @return string
+ */
+ public function toggle($element = 'this')
+ {
+ return $this->js->_toggle($element);
+
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Toggle Class
+ *
+ * Outputs a javascript library toggle class event
+ *
+ * @param string $element = 'this'
+ * @param string $class = ''
+ * @return string
+ */
+ public function toggleClass($element = 'this', $class = '')
+ {
+ return $this->js->_toggleClass($element, $class);
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Show
+ *
+ * Outputs a javascript library show event
+ *
+ * @param string - element
+ * @param string - One of 'slow', 'normal', 'fast', or time in milliseconds
+ * @param string - Javascript callback function
+ * @return string
+ */
+ public function show($element = 'this', $speed = '', $callback = '')
+ {
+ return $this->js->_show($element, $speed, $callback);
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Compile
+ *
+ * gather together all script needing to be output
+ *
+ * @param string $view_var
+ * @param bool $script_tags
+ * @return string
+ */
+ public function compile($view_var = 'script_foot', $script_tags = TRUE)
+ {
+ $this->js->_compile($view_var, $script_tags);
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Clear Compile
+ *
+ * Clears any previous javascript collected for output
+ *
+ * @return void
+ */
+ public function clear_compile()
+ {
+ $this->js->_clear_compile();
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * External
+ *
+ * Outputs a
+ *
+ * @param string
+ * @return string
+ */
+ protected function _close_script($extra = "\n")
+ {
+ return ''.$extra;
+ }
+
+ // --------------------------------------------------------------------
+ // AJAX-Y STUFF - still a testbed
+ // --------------------------------------------------------------------
+
+ /**
+ * Update
+ *
+ * Outputs a javascript library slideDown event
+ *
+ * @param string - element
+ * @param string - One of 'slow', 'normal', 'fast', or time in milliseconds
+ * @param string - Javascript callback function
+ * @return string
+ */
+ public function update($element = 'this', $speed = '', $callback = '')
+ {
+ return $this->js->_updater($element, $speed, $callback);
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Generate JSON
+ *
+ * Can be passed a database result or associative array and returns a JSON formatted string
+ *
+ * @param mixed result set or array
+ * @param bool match array types (defaults to objects)
+ * @return string a json formatted string
+ */
+ public function generate_json($result = NULL, $match_array_type = FALSE)
+ {
+ // JSON data can optionally be passed to this function
+ // either as a database result object or an array, or a user supplied array
+ if ($result !== NULL)
+ {
+ if (is_object($result))
+ {
+ $json_result = is_callable(array($result, 'result_array')) ? $result->result_array() : (array) $result;
+ }
+ elseif (is_array($result))
+ {
+ $json_result = $result;
+ }
+ else
+ {
+ return $this->_prep_args($result);
+ }
+ }
+ else
+ {
+ return 'null';
+ }
+
+ $json = array();
+ $_is_assoc = TRUE;
+
+ if ( ! is_array($json_result) && empty($json_result))
+ {
+ show_error('Generate JSON Failed - Illegal key, value pair.');
+ }
+ elseif ($match_array_type)
+ {
+ $_is_assoc = $this->_is_associative_array($json_result);
+ }
+
+ foreach ($json_result as $k => $v)
+ {
+ if ($_is_assoc)
+ {
+ $json[] = $this->_prep_args($k, TRUE).':'.$this->generate_json($v, $match_array_type);
+ }
+ else
+ {
+ $json[] = $this->generate_json($v, $match_array_type);
+ }
+ }
+
+ $json = implode(',', $json);
+
+ return $_is_assoc ? '{'.$json.'}' : '['.$json.']';
+
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Is associative array
+ *
+ * Checks for an associative array
+ *
+ * @param array
+ * @return bool
+ */
+ protected function _is_associative_array($arr)
+ {
+ foreach (array_keys($arr) as $key => $val)
+ {
+ if ($key !== $val)
+ {
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Prep Args
+ *
+ * Ensures a standard json value and escapes values
+ *
+ * @param mixed $result
+ * @param bool $is_key = FALSE
+ * @return string
+ */
+ protected function _prep_args($result, $is_key = FALSE)
+ {
+ if ($result === NULL)
+ {
+ return 'null';
+ }
+ elseif (is_bool($result))
+ {
+ return ($result === TRUE) ? 'true' : 'false';
+ }
+ elseif (is_string($result) OR $is_key)
+ {
+ return '"'.str_replace(array('\\', "\t", "\n", "\r", '"', '/'), array('\\\\', '\\t', '\\n', "\\r", '\"', '\/'), $result).'"';
+ }
+ elseif (is_scalar($result))
+ {
+ return $result;
+ }
+ }
+
+}
diff --git a/system/libraries/Javascript/Jquery.php b/system/libraries/Javascript/Jquery.php
new file mode 100644
index 00000000000..485d1dc1819
--- /dev/null
+++ b/system/libraries/Javascript/Jquery.php
@@ -0,0 +1,1076 @@
+CI =& get_instance();
+ extract($params);
+
+ if ($autoload === TRUE)
+ {
+ $this->script();
+ }
+
+ log_message('info', 'Jquery Class Initialized');
+ }
+
+ // --------------------------------------------------------------------
+ // Event Code
+ // --------------------------------------------------------------------
+
+ /**
+ * Blur
+ *
+ * Outputs a jQuery blur event
+ *
+ * @param string The element to attach the event to
+ * @param string The code to execute
+ * @return string
+ */
+ protected function _blur($element = 'this', $js = '')
+ {
+ return $this->_add_event($element, $js, 'blur');
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Change
+ *
+ * Outputs a jQuery change event
+ *
+ * @param string The element to attach the event to
+ * @param string The code to execute
+ * @return string
+ */
+ protected function _change($element = 'this', $js = '')
+ {
+ return $this->_add_event($element, $js, 'change');
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Click
+ *
+ * Outputs a jQuery click event
+ *
+ * @param string The element to attach the event to
+ * @param string The code to execute
+ * @param bool whether or not to return false
+ * @return string
+ */
+ protected function _click($element = 'this', $js = '', $ret_false = TRUE)
+ {
+ is_array($js) OR $js = array($js);
+
+ if ($ret_false)
+ {
+ $js[] = 'return false;';
+ }
+
+ return $this->_add_event($element, $js, 'click');
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Double Click
+ *
+ * Outputs a jQuery dblclick event
+ *
+ * @param string The element to attach the event to
+ * @param string The code to execute
+ * @return string
+ */
+ protected function _dblclick($element = 'this', $js = '')
+ {
+ return $this->_add_event($element, $js, 'dblclick');
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Error
+ *
+ * Outputs a jQuery error event
+ *
+ * @param string The element to attach the event to
+ * @param string The code to execute
+ * @return string
+ */
+ protected function _error($element = 'this', $js = '')
+ {
+ return $this->_add_event($element, $js, 'error');
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Focus
+ *
+ * Outputs a jQuery focus event
+ *
+ * @param string The element to attach the event to
+ * @param string The code to execute
+ * @return string
+ */
+ protected function _focus($element = 'this', $js = '')
+ {
+ return $this->_add_event($element, $js, 'focus');
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Hover
+ *
+ * Outputs a jQuery hover event
+ *
+ * @param string - element
+ * @param string - Javascript code for mouse over
+ * @param string - Javascript code for mouse out
+ * @return string
+ */
+ protected function _hover($element = 'this', $over = '', $out = '')
+ {
+ $event = "\n\t$(".$this->_prep_element($element).").hover(\n\t\tfunction()\n\t\t{\n\t\t\t{$over}\n\t\t}, \n\t\tfunction()\n\t\t{\n\t\t\t{$out}\n\t\t});\n";
+
+ $this->jquery_code_for_compile[] = $event;
+
+ return $event;
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Keydown
+ *
+ * Outputs a jQuery keydown event
+ *
+ * @param string The element to attach the event to
+ * @param string The code to execute
+ * @return string
+ */
+ protected function _keydown($element = 'this', $js = '')
+ {
+ return $this->_add_event($element, $js, 'keydown');
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Keyup
+ *
+ * Outputs a jQuery keydown event
+ *
+ * @param string The element to attach the event to
+ * @param string The code to execute
+ * @return string
+ */
+ protected function _keyup($element = 'this', $js = '')
+ {
+ return $this->_add_event($element, $js, 'keyup');
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Load
+ *
+ * Outputs a jQuery load event
+ *
+ * @param string The element to attach the event to
+ * @param string The code to execute
+ * @return string
+ */
+ protected function _load($element = 'this', $js = '')
+ {
+ return $this->_add_event($element, $js, 'load');
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Mousedown
+ *
+ * Outputs a jQuery mousedown event
+ *
+ * @param string The element to attach the event to
+ * @param string The code to execute
+ * @return string
+ */
+ protected function _mousedown($element = 'this', $js = '')
+ {
+ return $this->_add_event($element, $js, 'mousedown');
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Mouse Out
+ *
+ * Outputs a jQuery mouseout event
+ *
+ * @param string The element to attach the event to
+ * @param string The code to execute
+ * @return string
+ */
+ protected function _mouseout($element = 'this', $js = '')
+ {
+ return $this->_add_event($element, $js, 'mouseout');
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Mouse Over
+ *
+ * Outputs a jQuery mouseover event
+ *
+ * @param string The element to attach the event to
+ * @param string The code to execute
+ * @return string
+ */
+ protected function _mouseover($element = 'this', $js = '')
+ {
+ return $this->_add_event($element, $js, 'mouseover');
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Mouseup
+ *
+ * Outputs a jQuery mouseup event
+ *
+ * @param string The element to attach the event to
+ * @param string The code to execute
+ * @return string
+ */
+ protected function _mouseup($element = 'this', $js = '')
+ {
+ return $this->_add_event($element, $js, 'mouseup');
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Output
+ *
+ * Outputs script directly
+ *
+ * @param array $array_js = array()
+ * @return void
+ */
+ protected function _output($array_js = array())
+ {
+ if ( ! is_array($array_js))
+ {
+ $array_js = array($array_js);
+ }
+
+ foreach ($array_js as $js)
+ {
+ $this->jquery_code_for_compile[] = "\t".$js."\n";
+ }
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Resize
+ *
+ * Outputs a jQuery resize event
+ *
+ * @param string The element to attach the event to
+ * @param string The code to execute
+ * @return string
+ */
+ protected function _resize($element = 'this', $js = '')
+ {
+ return $this->_add_event($element, $js, 'resize');
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Scroll
+ *
+ * Outputs a jQuery scroll event
+ *
+ * @param string The element to attach the event to
+ * @param string The code to execute
+ * @return string
+ */
+ protected function _scroll($element = 'this', $js = '')
+ {
+ return $this->_add_event($element, $js, 'scroll');
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Unload
+ *
+ * Outputs a jQuery unload event
+ *
+ * @param string The element to attach the event to
+ * @param string The code to execute
+ * @return string
+ */
+ protected function _unload($element = 'this', $js = '')
+ {
+ return $this->_add_event($element, $js, 'unload');
+ }
+
+ // --------------------------------------------------------------------
+ // Effects
+ // --------------------------------------------------------------------
+
+ /**
+ * Add Class
+ *
+ * Outputs a jQuery addClass event
+ *
+ * @param string $element
+ * @param string $class
+ * @return string
+ */
+ protected function _addClass($element = 'this', $class = '')
+ {
+ $element = $this->_prep_element($element);
+ return '$('.$element.').addClass("'.$class.'");';
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Animate
+ *
+ * Outputs a jQuery animate event
+ *
+ * @param string $element
+ * @param array $params
+ * @param string $speed 'slow', 'normal', 'fast', or time in milliseconds
+ * @param string $extra
+ * @return string
+ */
+ protected function _animate($element = 'this', $params = array(), $speed = '', $extra = '')
+ {
+ $element = $this->_prep_element($element);
+ $speed = $this->_validate_speed($speed);
+
+ $animations = "\t\t\t";
+
+ foreach ($params as $param => $value)
+ {
+ $animations .= $param.": '".$value."', ";
+ }
+
+ $animations = substr($animations, 0, -2); // remove the last ", "
+
+ if ($speed !== '')
+ {
+ $speed = ', '.$speed;
+ }
+
+ if ($extra !== '')
+ {
+ $extra = ', '.$extra;
+ }
+
+ return "$({$element}).animate({\n$animations\n\t\t}".$speed.$extra.');';
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Fade In
+ *
+ * Outputs a jQuery hide event
+ *
+ * @param string - element
+ * @param string - One of 'slow', 'normal', 'fast', or time in milliseconds
+ * @param string - Javascript callback function
+ * @return string
+ */
+ protected function _fadeIn($element = 'this', $speed = '', $callback = '')
+ {
+ $element = $this->_prep_element($element);
+ $speed = $this->_validate_speed($speed);
+
+ if ($callback !== '')
+ {
+ $callback = ", function(){\n{$callback}\n}";
+ }
+
+ return "$({$element}).fadeIn({$speed}{$callback});";
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Fade Out
+ *
+ * Outputs a jQuery hide event
+ *
+ * @param string - element
+ * @param string - One of 'slow', 'normal', 'fast', or time in milliseconds
+ * @param string - Javascript callback function
+ * @return string
+ */
+ protected function _fadeOut($element = 'this', $speed = '', $callback = '')
+ {
+ $element = $this->_prep_element($element);
+ $speed = $this->_validate_speed($speed);
+
+ if ($callback !== '')
+ {
+ $callback = ", function(){\n{$callback}\n}";
+ }
+
+ return '$('.$element.').fadeOut('.$speed.$callback.');';
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Hide
+ *
+ * Outputs a jQuery hide action
+ *
+ * @param string - element
+ * @param string - One of 'slow', 'normal', 'fast', or time in milliseconds
+ * @param string - Javascript callback function
+ * @return string
+ */
+ protected function _hide($element = 'this', $speed = '', $callback = '')
+ {
+ $element = $this->_prep_element($element);
+ $speed = $this->_validate_speed($speed);
+
+ if ($callback !== '')
+ {
+ $callback = ", function(){\n{$callback}\n}";
+ }
+
+ return "$({$element}).hide({$speed}{$callback});";
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Remove Class
+ *
+ * Outputs a jQuery remove class event
+ *
+ * @param string $element
+ * @param string $class
+ * @return string
+ */
+ protected function _removeClass($element = 'this', $class = '')
+ {
+ $element = $this->_prep_element($element);
+ return '$('.$element.').removeClass("'.$class.'");';
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Slide Up
+ *
+ * Outputs a jQuery slideUp event
+ *
+ * @param string - element
+ * @param string - One of 'slow', 'normal', 'fast', or time in milliseconds
+ * @param string - Javascript callback function
+ * @return string
+ */
+ protected function _slideUp($element = 'this', $speed = '', $callback = '')
+ {
+ $element = $this->_prep_element($element);
+ $speed = $this->_validate_speed($speed);
+
+ if ($callback !== '')
+ {
+ $callback = ", function(){\n{$callback}\n}";
+ }
+
+ return '$('.$element.').slideUp('.$speed.$callback.');';
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Slide Down
+ *
+ * Outputs a jQuery slideDown event
+ *
+ * @param string - element
+ * @param string - One of 'slow', 'normal', 'fast', or time in milliseconds
+ * @param string - Javascript callback function
+ * @return string
+ */
+ protected function _slideDown($element = 'this', $speed = '', $callback = '')
+ {
+ $element = $this->_prep_element($element);
+ $speed = $this->_validate_speed($speed);
+
+ if ($callback !== '')
+ {
+ $callback = ", function(){\n{$callback}\n}";
+ }
+
+ return '$('.$element.').slideDown('.$speed.$callback.');';
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Slide Toggle
+ *
+ * Outputs a jQuery slideToggle event
+ *
+ * @param string - element
+ * @param string - One of 'slow', 'normal', 'fast', or time in milliseconds
+ * @param string - Javascript callback function
+ * @return string
+ */
+ protected function _slideToggle($element = 'this', $speed = '', $callback = '')
+ {
+ $element = $this->_prep_element($element);
+ $speed = $this->_validate_speed($speed);
+
+ if ($callback !== '')
+ {
+ $callback = ", function(){\n{$callback}\n}";
+ }
+
+ return '$('.$element.').slideToggle('.$speed.$callback.');';
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Toggle
+ *
+ * Outputs a jQuery toggle event
+ *
+ * @param string - element
+ * @return string
+ */
+ protected function _toggle($element = 'this')
+ {
+ $element = $this->_prep_element($element);
+ return '$('.$element.').toggle();';
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Toggle Class
+ *
+ * Outputs a jQuery toggle class event
+ *
+ * @param string $element
+ * @param string $class
+ * @return string
+ */
+ protected function _toggleClass($element = 'this', $class = '')
+ {
+ $element = $this->_prep_element($element);
+ return '$('.$element.').toggleClass("'.$class.'");';
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Show
+ *
+ * Outputs a jQuery show event
+ *
+ * @param string - element
+ * @param string - One of 'slow', 'normal', 'fast', or time in milliseconds
+ * @param string - Javascript callback function
+ * @return string
+ */
+ protected function _show($element = 'this', $speed = '', $callback = '')
+ {
+ $element = $this->_prep_element($element);
+ $speed = $this->_validate_speed($speed);
+
+ if ($callback !== '')
+ {
+ $callback = ", function(){\n{$callback}\n}";
+ }
+
+ return '$('.$element.').show('.$speed.$callback.');';
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Updater
+ *
+ * An Ajax call that populates the designated DOM node with
+ * returned content
+ *
+ * @param string The element to attach the event to
+ * @param string the controller to run the call against
+ * @param string optional parameters
+ * @return string
+ */
+
+ protected function _updater($container = 'this', $controller = '', $options = '')
+ {
+ $container = $this->_prep_element($container);
+ $controller = (strpos('://', $controller) === FALSE) ? $controller : $this->CI->config->site_url($controller);
+
+ // ajaxStart and ajaxStop are better choices here... but this is a stop gap
+ if ($this->CI->config->item('javascript_ajax_img') === '')
+ {
+ $loading_notifier = 'Loading...';
+ }
+ else
+ {
+ $loading_notifier = '';
+ }
+
+ $updater = '$('.$container.").empty();\n" // anything that was in... get it out
+ ."\t\t$(".$container.').prepend("'.$loading_notifier."\");\n"; // to replace with an image
+
+ $request_options = '';
+ if ($options !== '')
+ {
+ $request_options .= ', {'
+ .(is_array($options) ? "'".implode("', '", $options)."'" : "'".str_replace(':', "':'", $options)."'")
+ .'}';
+ }
+
+ return $updater."\t\t$($container).load('$controller'$request_options);";
+ }
+
+ // --------------------------------------------------------------------
+ // Pre-written handy stuff
+ // --------------------------------------------------------------------
+
+ /**
+ * Zebra tables
+ *
+ * @param string $class
+ * @param string $odd
+ * @param string $hover
+ * @return string
+ */
+ protected function _zebraTables($class = '', $odd = 'odd', $hover = '')
+ {
+ $class = ($class !== '') ? '.'.$class : '';
+ $zebra = "\t\$(\"table{$class} tbody tr:nth-child(even)\").addClass(\"{$odd}\");";
+
+ $this->jquery_code_for_compile[] = $zebra;
+
+ if ($hover !== '')
+ {
+ $hover = $this->hover("table{$class} tbody tr", "$(this).addClass('hover');", "$(this).removeClass('hover');");
+ }
+
+ return $zebra;
+ }
+
+ // --------------------------------------------------------------------
+ // Plugins
+ // --------------------------------------------------------------------
+
+ /**
+ * Corner Plugin
+ *
+ * @link http://www.malsup.com/jquery/corner/
+ * @param string $element
+ * @param string $corner_style
+ * @return string
+ */
+ public function corner($element = '', $corner_style = '')
+ {
+ // may want to make this configurable down the road
+ $corner_location = '/plugins/jquery.corner.js';
+
+ if ($corner_style !== '')
+ {
+ $corner_style = '"'.$corner_style.'"';
+ }
+
+ return '$('.$this->_prep_element($element).').corner('.$corner_style.');';
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Modal window
+ *
+ * Load a thickbox modal window
+ *
+ * @param string $src
+ * @param bool $relative
+ * @return void
+ */
+ public function modal($src, $relative = FALSE)
+ {
+ $this->jquery_code_for_load[] = $this->external($src, $relative);
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Effect
+ *
+ * Load an Effect library
+ *
+ * @param string $src
+ * @param bool $relative
+ * @return void
+ */
+ public function effect($src, $relative = FALSE)
+ {
+ $this->jquery_code_for_load[] = $this->external($src, $relative);
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Plugin
+ *
+ * Load a plugin library
+ *
+ * @param string $src
+ * @param bool $relative
+ * @return void
+ */
+ public function plugin($src, $relative = FALSE)
+ {
+ $this->jquery_code_for_load[] = $this->external($src, $relative);
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * UI
+ *
+ * Load a user interface library
+ *
+ * @param string $src
+ * @param bool $relative
+ * @return void
+ */
+ public function ui($src, $relative = FALSE)
+ {
+ $this->jquery_code_for_load[] = $this->external($src, $relative);
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Sortable
+ *
+ * Creates a jQuery sortable
+ *
+ * @param string $element
+ * @param array $options
+ * @return string
+ */
+ public function sortable($element, $options = array())
+ {
+ if (count($options) > 0)
+ {
+ $sort_options = array();
+ foreach ($options as $k=>$v)
+ {
+ $sort_options[] = "\n\t\t".$k.': '.$v;
+ }
+ $sort_options = implode(',', $sort_options);
+ }
+ else
+ {
+ $sort_options = '';
+ }
+
+ return '$('.$this->_prep_element($element).').sortable({'.$sort_options."\n\t});";
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Table Sorter Plugin
+ *
+ * @param string table name
+ * @param string plugin location
+ * @return string
+ */
+ public function tablesorter($table = '', $options = '')
+ {
+ $this->jquery_code_for_compile[] = "\t$(".$this->_prep_element($table).').tablesorter('.$options.");\n";
+ }
+
+ // --------------------------------------------------------------------
+ // Class functions
+ // --------------------------------------------------------------------
+
+ /**
+ * Add Event
+ *
+ * Constructs the syntax for an event, and adds to into the array for compilation
+ *
+ * @param string The element to attach the event to
+ * @param string The code to execute
+ * @param string The event to pass
+ * @return string
+ */
+ protected function _add_event($element, $js, $event)
+ {
+ if (is_array($js))
+ {
+ $js = implode("\n\t\t", $js);
+ }
+
+ $event = "\n\t$(".$this->_prep_element($element).').'.$event."(function(){\n\t\t{$js}\n\t});\n";
+ $this->jquery_code_for_compile[] = $event;
+ return $event;
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Compile
+ *
+ * As events are specified, they are stored in an array
+ * This function compiles them all for output on a page
+ *
+ * @param string $view_var
+ * @param bool $script_tags
+ * @return void
+ */
+ protected function _compile($view_var = 'script_foot', $script_tags = TRUE)
+ {
+ // External references
+ $external_scripts = implode('', $this->jquery_code_for_load);
+ $this->CI->load->vars(array('library_src' => $external_scripts));
+
+ if (count($this->jquery_code_for_compile) === 0)
+ {
+ // no inline references, let's just return
+ return;
+ }
+
+ // Inline references
+ $script = '$(document).ready(function() {'."\n"
+ .implode('', $this->jquery_code_for_compile)
+ .'});';
+
+ $output = ($script_tags === FALSE) ? $script : $this->inline($script);
+
+ $this->CI->load->vars(array($view_var => $output));
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Clear Compile
+ *
+ * Clears the array of script events collected for output
+ *
+ * @return void
+ */
+ protected function _clear_compile()
+ {
+ $this->jquery_code_for_compile = array();
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Document Ready
+ *
+ * A wrapper for writing document.ready()
+ *
+ * @param array $js
+ * @return void
+ */
+ protected function _document_ready($js)
+ {
+ is_array($js) OR $js = array($js);
+
+ foreach ($js as $script)
+ {
+ $this->jquery_code_for_compile[] = $script;
+ }
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Script Tag
+ *
+ * Outputs the script tag that loads the jquery.js file into an HTML document
+ *
+ * @param string $library_src
+ * @param bool $relative
+ * @return string
+ */
+ public function script($library_src = '', $relative = FALSE)
+ {
+ $library_src = $this->external($library_src, $relative);
+ $this->jquery_code_for_load[] = $library_src;
+ return $library_src;
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Prep Element
+ *
+ * Puts HTML element in quotes for use in jQuery code
+ * unless the supplied element is the Javascript 'this'
+ * object, in which case no quotes are added
+ *
+ * @param string
+ * @return string
+ */
+ protected function _prep_element($element)
+ {
+ if ($element !== 'this')
+ {
+ $element = '"'.$element.'"';
+ }
+
+ return $element;
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Validate Speed
+ *
+ * Ensures the speed parameter is valid for jQuery
+ *
+ * @param string
+ * @return string
+ */
+ protected function _validate_speed($speed)
+ {
+ if (in_array($speed, array('slow', 'normal', 'fast')))
+ {
+ return '"'.$speed.'"';
+ }
+ elseif (preg_match('/[^0-9]/', $speed))
+ {
+ return '';
+ }
+
+ return $speed;
+ }
+
+}
diff --git a/system/libraries/Javascript/index.html b/system/libraries/Javascript/index.html
new file mode 100644
index 00000000000..b702fbc3967
--- /dev/null
+++ b/system/libraries/Javascript/index.html
@@ -0,0 +1,11 @@
+
+
+
+ 403 Forbidden
+
+
+
+
Directory access is forbidden.
+
+
+
diff --git a/system/libraries/Session/SessionHandlerInterface.php b/system/libraries/Session/SessionHandlerInterface.php
new file mode 100644
index 00000000000..240c5f54e88
--- /dev/null
+++ b/system/libraries/Session/SessionHandlerInterface.php
@@ -0,0 +1,59 @@
+_allow_get_array = (config_item('allow_get_array') === TRUE);
+ $this->_enable_xss = (config_item('global_xss_filtering') === TRUE);
+ $this->_enable_csrf = (config_item('csrf_protection') === TRUE);
+
+ // Assign Security and Utf8 classes
+ $this->security = $security;
+ $this->uni = $utf8;
+
+ // Sanitize global arrays
+ $this->_sanitize_globals();
+ }
+
+ public function fetch_from_array($array, $index = '', $xss_clean = FALSE)
+ {
+ return parent::_fetch_from_array($array, $index, $xss_clean);
+ }
+
+ /**
+ * Lie about being a CLI request
+ *
+ * We take advantage of this in libraries/Session_test
+ */
+ public function is_cli_request()
+ {
+ return FALSE;
+ }
+
+ public function __set($name, $value)
+ {
+ if ($name === 'ip_address')
+ {
+ $this->ip_address = $value;
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/tests/mocks/core/utf8.php b/tests/mocks/core/utf8.php
new file mode 100644
index 00000000000..3a6282e1d9a
--- /dev/null
+++ b/tests/mocks/core/utf8.php
@@ -0,0 +1,19 @@
+`.
+
+.. important:: The Email helper is DEPRECATED and is currently
+ only kept for backwards compatibility.
+
+.. contents::
+ :local:
+
+.. raw:: html
+
+
+
+Loading this Helper
+===================
+
+This helper is loaded using the following code::
+
+ $this->load->helper('email');
+
+Available Functions
+===================
+
+The following functions are available:
+
+
+.. php:function:: valid_email($email)
+
+ :param string $email: E-mail address
+ :returns: TRUE if a valid email is supplied, FALSE otherwise
+ :rtype: bool
+
+ Checks if the input is a correctly formatted e-mail address. Note that is
+ doesn't actually prove that the address will be able recieve mail, but
+ simply that it is a validly formed address.
+
+ Example::
+
+ if (valid_email('email@somesite.com'))
+ {
+ echo 'email is valid';
+ }
+ else
+ {
+ echo 'email is not valid';
+ }
+
+ .. note:: All that this function does is to use PHP's native ``filter_var()``::
+
+ (bool) filter_var($email, FILTER_VALIDATE_EMAIL);
+
+.. php:function:: send_email($recipient, $subject, $message)
+
+ :param string $recipient: E-mail address
+ :param string $subject: Mail subject
+ :param string $message: Message body
+ :returns: TRUE if the mail was successfully sent, FALSE in case of an error
+ :rtype: bool
+
+ Sends an email using PHP's native `mail() `_
+ function.
+
+ .. note:: All that this function does is to use PHP's native ``mail``
+
+ ::
+
+ mail($recipient, $subject, $message);
+
+ For a more robust email solution, see CodeIgniter's :doc:`Email Library
+ <../libraries/email>`.
\ No newline at end of file
diff --git a/user_guide_src/source/helpers/smiley_helper.rst b/user_guide_src/source/helpers/smiley_helper.rst
new file mode 100644
index 00000000000..3e766994204
--- /dev/null
+++ b/user_guide_src/source/helpers/smiley_helper.rst
@@ -0,0 +1,169 @@
+#############
+Smiley Helper
+#############
+
+The Smiley Helper file contains functions that let you manage smileys
+(emoticons).
+
+.. important:: The Smiley helper is DEPRECATED and should not be used.
+ It is currently only kept for backwards compatibility.
+
+.. contents::
+ :local:
+
+.. raw:: html
+
+
+
+Loading this Helper
+===================
+
+This helper is loaded using the following code::
+
+ $this->load->helper('smiley');
+
+Overview
+========
+
+The Smiley helper has a renderer that takes plain text smileys, like
+:-) and turns them into a image representation, like |smile!|
+
+It also lets you display a set of smiley images that when clicked will
+be inserted into a form field. For example, if you have a blog that
+allows user commenting you can show the smileys next to the comment
+form. Your users can click a desired smiley and with the help of some
+JavaScript it will be placed into the form field.
+
+Clickable Smileys Tutorial
+==========================
+
+Here is an example demonstrating how you might create a set of clickable
+smileys next to a form field. This example requires that you first
+download and install the smiley images, then create a controller and the
+View as described.
+
+.. important:: Before you begin, please `download the smiley images
+ `_
+ and put them in a publicly accessible place on your server.
+ This helper also assumes you have the smiley replacement array
+ located at `application/config/smileys.php`
+
+The Controller
+--------------
+
+In your **application/controllers/** directory, create a file called
+Smileys.php and place the code below in it.
+
+.. important:: Change the URL in the :php:func:`get_clickable_smileys()`
+ function below so that it points to your smiley folder.
+
+You'll notice that in addition to the smiley helper, we are also using
+the :doc:`Table Class <../libraries/table>`::
+
+ load->helper('smiley');
+ $this->load->library('table');
+
+ $image_array = get_clickable_smileys('http://example.com/images/smileys/', 'comments');
+ $col_array = $this->table->make_columns($image_array, 8);
+
+ $data['smiley_table'] = $this->table->generate($col_array);
+ $this->load->view('smiley_view', $data);
+ }
+
+ }
+
+In your **application/views/** directory, create a file called **smiley_view.php**
+and place this code in it::
+
+
+
+ Smileys
+
+
+
+
+
Click to insert a smiley!
+
+ When you have created the above controller and view, load it by visiting http://www.example.com/index.php/smileys/
+