From 2116f9f591674d19825143f528d8a3a8072ac732 Mon Sep 17 00:00:00 2001 From: Serge Rey Date: Fri, 21 Jul 2006 04:26:13 +0000 Subject: [PATCH] new directory structure additions. --- COPYING | 25 + HISTORY | 67 ++ MANIFEST | 71 ++ README | 65 ++ about.php | 54 ++ calendar-setup.js | 200 ++++ calendar-win2k-cold-1.css | 265 ++++++ calendar.js | 1806 ++++++++++++++++++++++++++++++++++++ checklistReport.php | 70 ++ config.sample.php | 8 + credits.php | 30 + editCategory.php | 53 ++ editChecklist.php | 47 + editChecklistItem.php | 62 ++ editContext.php | 55 ++ editGoal.php | 85 ++ editList.php | 46 + editListItem.php | 66 ++ editTimeContext.php | 55 ++ footer.php | 11 + gtdfuncs.php | 188 ++++ header.php | 119 +++ img.gif | Bin 0 -> 223 bytes index.php | 7 + install.php | 503 ++++++++++ item.php | 226 +++++ lang/calendar-en.js | 127 +++ listChecklist.php | 72 ++ listGoals.php | 96 ++ listItems.php | 207 +++++ listList.php | 79 ++ listProjects.php | 147 +++ listReport.php | 94 ++ makegtd.sql | 149 +++ newCategory.php | 39 + newChecklist.php | 64 ++ newChecklistItem.php | 55 ++ newContext.php | 35 + newGoal.php | 72 ++ newList.php | 64 ++ newListItem.php | 54 ++ newTimeContext.php | 35 + note.php | 49 + phpSettings.php | 4 + processChecklistItem.php | 29 + processChecklistUpdate.php | 41 + processGoal.php | 32 + processItem.php | 55 ++ processItemUpdate.php | 111 +++ processListItem.php | 25 + processListUpdate.php | 36 + processNote.php | 32 + processProject.php | 54 ++ processProjectUpdate.php | 89 ++ project.php | 134 +++ projectReport.php | 194 ++++ reportContext.php | 196 ++++ style.css | 198 ++++ style_screen.css | 47 + summary.php | 177 ++++ summaryAlone.php | 7 + tickler.php | 208 +++++ updateCategory.php | 33 + updateChecklist.php | 46 + updateChecklistItem.php | 45 + updateContext.php | 33 + updateGoal.php | 61 ++ updateItem.php | 87 ++ updateList.php | 47 + updateListItem.php | 40 + updateNote.php | 37 + updateProject.php | 78 ++ updateTimeContext.php | 33 + weekly.php | 63 ++ 74 files changed, 7894 insertions(+) create mode 100644 COPYING create mode 100644 HISTORY create mode 100644 MANIFEST create mode 100644 README create mode 100644 about.php create mode 100644 calendar-setup.js create mode 100644 calendar-win2k-cold-1.css create mode 100644 calendar.js create mode 100644 checklistReport.php create mode 100644 config.sample.php create mode 100644 credits.php create mode 100644 editCategory.php create mode 100644 editChecklist.php create mode 100644 editChecklistItem.php create mode 100644 editContext.php create mode 100644 editGoal.php create mode 100644 editList.php create mode 100644 editListItem.php create mode 100644 editTimeContext.php create mode 100644 footer.php create mode 100644 gtdfuncs.php create mode 100644 header.php create mode 100644 img.gif create mode 100644 index.php create mode 100644 install.php create mode 100644 item.php create mode 100644 lang/calendar-en.js create mode 100644 listChecklist.php create mode 100644 listGoals.php create mode 100644 listItems.php create mode 100644 listList.php create mode 100644 listProjects.php create mode 100644 listReport.php create mode 100644 makegtd.sql create mode 100644 newCategory.php create mode 100644 newChecklist.php create mode 100644 newChecklistItem.php create mode 100644 newContext.php create mode 100644 newGoal.php create mode 100644 newList.php create mode 100644 newListItem.php create mode 100644 newTimeContext.php create mode 100644 note.php create mode 100644 phpSettings.php create mode 100644 processChecklistItem.php create mode 100644 processChecklistUpdate.php create mode 100644 processGoal.php create mode 100644 processItem.php create mode 100644 processItemUpdate.php create mode 100644 processListItem.php create mode 100644 processListUpdate.php create mode 100644 processNote.php create mode 100644 processProject.php create mode 100644 processProjectUpdate.php create mode 100644 project.php create mode 100644 projectReport.php create mode 100644 reportContext.php create mode 100644 style.css create mode 100644 style_screen.css create mode 100644 summary.php create mode 100644 summaryAlone.php create mode 100644 tickler.php create mode 100644 updateCategory.php create mode 100644 updateChecklist.php create mode 100644 updateChecklistItem.php create mode 100644 updateContext.php create mode 100644 updateGoal.php create mode 100644 updateItem.php create mode 100644 updateList.php create mode 100644 updateListItem.php create mode 100644 updateNote.php create mode 100644 updateProject.php create mode 100644 updateTimeContext.php create mode 100644 weekly.php diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..670c9b6 --- /dev/null +++ b/COPYING @@ -0,0 +1,25 @@ +Copyright (c) 2005,2006, Sergio J. Rey +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the gtd-php team nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/HISTORY b/HISTORY new file mode 100644 index 0000000..ecdd4f1 --- /dev/null +++ b/HISTORY @@ -0,0 +1,67 @@ +(In progress) Version 0.6.1 + - Calendar for date selector (Serge Rey) + - MySQL 5. and PhP 5. support (Serge Rey) + - Title option (Serge Rey) + - Horizontal drop down menus (Serge Rey) + - Previous and Next links on Project Reports (Serge Rey) + +2006-06-11 Version 0.6 + - Weekly review now has links (Scott Jason Korvek) + - Install script streamlined (Serge Rey) + - New database backend and php code redesign (Scott Jason Korvek) + - Any item can be freely converted between an action, waiting, or reference type (Scott Jason Korvek) + - Tickler file added- notes, projects, and items (Scott Jason Korvek) + - Repeating projects (Scott Jason Korvek) + - Added Time Context Creation (Serge Rey) + - Ablility to list items filtered by context and categories (Scott Jason Korvek) + - Ability to mark an action as the next action -- denoted as * on the report (Scott Jason Korvek) + - Added next action report (Scott Jason Korvek) + - Due dates matching today are colored green, past due dates colored red (Scott Jason Korvek) + - Context reports only shows next actions (not all actions) (Serge Rey) + - In-place (via hyperlink) editing of contexts and categories (Scott Jason Korvek) + - Can add/delete/modify space and time contexts (Scott Jason Korvek) + - New default categories, contexts, and project (Serge Rey) + - Tooltips/context-sensitive help (Scott Jason Korvek) + - Date header (Scott Jason Korvek) + - Formatted dates (Scott Jason Korvek) + - Adjusted table sorting and listed columns (Scott Jason Korvek) + - Adjusted page refresh times and targets (Scott Jason Korvek) + - Standardized appearance of forms (Scott Jason Korvek) + - Input sanitization and removal of error reporting to minimize hacking potential and enforce defaults (Scott Jason Korvek) + - Character escaping and text formatting (Scott Jason Korvek) + - Links to our wiki and frapper map (Serge Rey) + - Many more updates, enhancements, and bugfixes... + +2006-03-18 Version 0.5 + - Added repeating next actions (Scott Jason Korvek) + - Added Someday/Maybe list (Scott Jason Korvek) + - Added List (Scott Jason Korvek) + - Added CheckLists (Scott Jason Korvek) + - Added Categories (Scott Jason Korvek) + - Fixed project title reporting bug after project update (Serge Rey) + - Next Actions Deadline option (Scott Jason Korvek) + - Date selector (Serge Rey) + - Install (update) script (Serge Rey) + +2006-02-04 Version 0.4 + - Fixed IE layout bug (Mike Kober) + - Added Contexts summary table (Serge Rey) + +2006-01-28 Version 0.3 + - Fixed count of completed/non-completed nextActions (Serge Rey) + - Fixed plural useage on summary.php (Serge Rey) + - Fixed showing table headings when there are no NAs in project report (Serge Rey) + - Fixed showing table headings when there are no WOs in project report (Serge Rey) + - Fixed showing table headings when there are no Nas in context report (Serge Rey) + - Added delete checkbox on editNextAction form (Serge Rey) + - Added complete checkbox on editNextAction form (Serge Rey) + - Added complete checkbox on next actions report form (Serge Rey) + - Added complete checkbox on context report form (Serge Rey) + - Changed tarball and zip archive to include gtd directory (Thanks to Vicki Brown) + +2006-01-21 Version 0.2 + - css and layout redesign (Jason Brown) + - refresh on update and new nextActions (Serge Rey) + - meta links on side bar (Serge Rey) + +2006-01-15 Version 0.1 (Windy) diff --git a/MANIFEST b/MANIFEST new file mode 100644 index 0000000..63316f8 --- /dev/null +++ b/MANIFEST @@ -0,0 +1,71 @@ +COPYING +HISTORY +MANIFEST +README +about.php +calendar.js +calender-setup.js +calendar-win2k-cold-1.css +checklistReport.php +config.sample.php +credits.php +editCategory.php +editChecklist.php +editChecklistItem.php +editContext.php +editGoal.php +editList.php +editListItem.php +editTimeContext.php +footer.php +gtdfuncs.php +header.php +img.gif +index.php +install.php +item.php +lang/calender-en.js +listChecklist.php +listGoals.php +listItems.php +listList.php +listProjects.php +listReport.php +newCategory.php +newChecklist.php +newChecklistItem.php +newContext.php +newGoal.php +newList.php +newListItem.php +newTimeContext.php +note.php +processChecklistItem.php +processChecklistUpdate.php +processGoal.php +processItem.php +processItemUpdate.php +processListItem.php +processListUpdate.php +processNote.php +processProject.php +processProjectUpdate.php +project.php +projectReport.php +reportContext.php +style.css +style_screen.css +summary.php +summaryAlone.php +tickler.php +updateCategory.php +updateChecklist.php +updateChecklistItem.php +updateContext.php +updateGoal.php +updateItem.php +updateList.php +updateListItem.php +updateProject.php +updateTimeContext.php +weekly.php diff --git a/README b/README new file mode 100644 index 0000000..93a1e6f --- /dev/null +++ b/README @@ -0,0 +1,65 @@ +gtd-php +Version 0.6.1 (2006-07-08) +A web-based implementation of the Getting Things Done system for personal +organization. + +Requirements: + mysql + php + apache with php enabled + +This version does not support installations using table prefixes in the +database. We plan on adding that support in the next release. + +UPGRADING + +1. You should backup your gtd database with: + mysqldump gtd > gtdbackup.sql + (use this in case you need to restore) + +2. Extract the tarball into the same directory you originally + installed gtd-php in. + +3. Then proceed to step 8 under NEW INSTALLATION. This will add new tables as + well as add new columns to your existing tables. Your original data will + be upgraded to use the new functionality in version 0.5. You do not need + to recreate your original database (i.e., step 1 is simply a precaution). + + +NEW INSTALLATION +Installation (Mac OS X-specific. For an other OS, adjust accordingly): + +1. Set up mysql and php + +2. cd ~/Sites + +3. tar -xzvf pathtotarball + +4. cd ~/Sites/gtd-php + +5. cp config.sample.php config.php + +6. Edit config.php and change $pass and $user to values for local machine. + +7. In mysql create a database called gtd: + create database gtd; + + Note that you should also set proper mysql permissions for the mysql user. + This user should NOT have access to other databases, nor grant privileges; + this should NOT be the root user. + +8. Make sure the name of the database and user that you created in step 7, + match those in your config file from step 6. + +9. Point your browser to http://localhost/~username/gtd-php/install.php + + If you encounter a mysql error "Error connecting to database" + then connect to mysql from a shell and issue: + set password for 'user'@'localhost' = old_password('password'); + + being sure to change user to the user in config.php and password to + the value of pass in config.php + +10. Explore, enjoy, and send us comments, suggestions, gripes, donations at + http://toae.org/boards + diff --git a/about.php b/about.php new file mode 100644 index 0000000..4d6e044 --- /dev/null +++ b/about.php @@ -0,0 +1,54 @@ +gtd-php "; + echo ''; + echo ' + + + + + +
+Copyright (c) 2005,2006, Sergio J. Rey. +All rights reserved. +
+Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: +
+ * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. +
+ * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. +
+ * Neither the name of the gtd-php team nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. +
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +
+'; + + + include_once('footer.php'); +?> diff --git a/calendar-setup.js b/calendar-setup.js new file mode 100644 index 0000000..a94c340 --- /dev/null +++ b/calendar-setup.js @@ -0,0 +1,200 @@ +/* Copyright Mihai Bazon, 2002, 2003 | http://dynarch.com/mishoo/ + * --------------------------------------------------------------------------- + * + * The DHTML Calendar + * + * Details and latest version at: + * http://dynarch.com/mishoo/calendar.epl + * + * This script is distributed under the GNU Lesser General Public License. + * Read the entire license text here: http://www.gnu.org/licenses/lgpl.html + * + * This file defines helper functions for setting up the calendar. They are + * intended to help non-programmers get a working calendar on their site + * quickly. This script should not be seen as part of the calendar. It just + * shows you what one can do with the calendar, while in the same time + * providing a quick and simple method for setting it up. If you need + * exhaustive customization of the calendar creation process feel free to + * modify this code to suit your needs (this is recommended and much better + * than modifying calendar.js itself). + */ + +// $Id: calendar-setup.js,v 1.2 2006/07/08 19:20:34 serge Exp $ + +/** + * This function "patches" an input field (or other element) to use a calendar + * widget for date selection. + * + * The "params" is a single object that can have the following properties: + * + * prop. name | description + * ------------------------------------------------------------------------------------------------- + * inputField | the ID of an input field to store the date + * displayArea | the ID of a DIV or other element to show the date + * button | ID of a button or other element that will trigger the calendar + * eventName | event that will trigger the calendar, without the "on" prefix (default: "click") + * ifFormat | date format that will be stored in the input field + * daFormat | the date format that will be used to display the date in displayArea + * singleClick | (true/false) wether the calendar is in single click mode or not (default: true) + * firstDay | numeric: 0 to 6. "0" means display Sunday first, "1" means display Monday first, etc. + * align | alignment (default: "Br"); if you don't know what's this see the calendar documentation + * range | array with 2 elements. Default: [1900, 2999] -- the range of years available + * weekNumbers | (true/false) if it's true (default) the calendar will display week numbers + * flat | null or element ID; if not null the calendar will be a flat calendar having the parent with the given ID + * flatCallback | function that receives a JS Date object and returns an URL to point the browser to (for flat calendar) + * disableFunc | function that receives a JS Date object and should return true if that date has to be disabled in the calendar + * onSelect | function that gets called when a date is selected. You don't _have_ to supply this (the default is generally okay) + * onClose | function that gets called when the calendar is closed. [default] + * onUpdate | function that gets called after the date is updated in the input field. Receives a reference to the calendar. + * date | the date that the calendar will be initially displayed to + * showsTime | default: false; if true the calendar will include a time selector + * timeFormat | the time format; can be "12" or "24", default is "12" + * electric | if true (default) then given fields/date areas are updated for each move; otherwise they're updated only on close + * step | configures the step of the years in drop-down boxes; default: 2 + * position | configures the calendar absolute position; default: null + * cache | if "true" (but default: "false") it will reuse the same calendar object, where possible + * showOthers | if "true" (but default: "false") it will show days from other months too + * + * None of them is required, they all have default values. However, if you + * pass none of "inputField", "displayArea" or "button" you'll get a warning + * saying "nothing to setup". + */ +Calendar.setup = function (params) { + function param_default(pname, def) { if (typeof params[pname] == "undefined") { params[pname] = def; } }; + + param_default("inputField", null); + param_default("displayArea", null); + param_default("button", null); + param_default("eventName", "click"); + param_default("ifFormat", "%Y/%m/%d"); + param_default("daFormat", "%Y/%m/%d"); + param_default("singleClick", true); + param_default("disableFunc", null); + param_default("dateStatusFunc", params["disableFunc"]); // takes precedence if both are defined + param_default("dateText", null); + param_default("firstDay", null); + param_default("align", "Br"); + param_default("range", [1900, 2999]); + param_default("weekNumbers", true); + param_default("flat", null); + param_default("flatCallback", null); + param_default("onSelect", null); + param_default("onClose", null); + param_default("onUpdate", null); + param_default("date", null); + param_default("showsTime", false); + param_default("timeFormat", "24"); + param_default("electric", true); + param_default("step", 2); + param_default("position", null); + param_default("cache", false); + param_default("showOthers", false); + param_default("multiple", null); + + var tmp = ["inputField", "displayArea", "button"]; + for (var i in tmp) { + if (typeof params[tmp[i]] == "string") { + params[tmp[i]] = document.getElementById(params[tmp[i]]); + } + } + if (!(params.flat || params.multiple || params.inputField || params.displayArea || params.button)) { + alert("Calendar.setup:\n Nothing to setup (no fields found). Please check your code"); + return false; + } + + function onSelect(cal) { + var p = cal.params; + var update = (cal.dateClicked || p.electric); + if (update && p.inputField) { + p.inputField.value = cal.date.print(p.ifFormat); + if (typeof p.inputField.onchange == "function") + p.inputField.onchange(); + } + if (update && p.displayArea) + p.displayArea.innerHTML = cal.date.print(p.daFormat); + if (update && typeof p.onUpdate == "function") + p.onUpdate(cal); + if (update && p.flat) { + if (typeof p.flatCallback == "function") + p.flatCallback(cal); + } + if (update && p.singleClick && cal.dateClicked) + cal.callCloseHandler(); + }; + + if (params.flat != null) { + if (typeof params.flat == "string") + params.flat = document.getElementById(params.flat); + if (!params.flat) { + alert("Calendar.setup:\n Flat specified but can't find parent."); + return false; + } + var cal = new Calendar(params.firstDay, params.date, params.onSelect || onSelect); + cal.showsOtherMonths = params.showOthers; + cal.showsTime = params.showsTime; + cal.time24 = (params.timeFormat == "24"); + cal.params = params; + cal.weekNumbers = params.weekNumbers; + cal.setRange(params.range[0], params.range[1]); + cal.setDateStatusHandler(params.dateStatusFunc); + cal.getDateText = params.dateText; + if (params.ifFormat) { + cal.setDateFormat(params.ifFormat); + } + if (params.inputField && typeof params.inputField.value == "string") { + cal.parseDate(params.inputField.value); + } + cal.create(params.flat); + cal.show(); + return false; + } + + var triggerEl = params.button || params.displayArea || params.inputField; + triggerEl["on" + params.eventName] = function() { + var dateEl = params.inputField || params.displayArea; + var dateFmt = params.inputField ? params.ifFormat : params.daFormat; + var mustCreate = false; + var cal = window.calendar; + if (dateEl) + params.date = Date.parseDate(dateEl.value || dateEl.innerHTML, dateFmt); + if (!(cal && params.cache)) { + window.calendar = cal = new Calendar(params.firstDay, + params.date, + params.onSelect || onSelect, + params.onClose || function(cal) { cal.hide(); }); + cal.showsTime = params.showsTime; + cal.time24 = (params.timeFormat == "24"); + cal.weekNumbers = params.weekNumbers; + mustCreate = true; + } else { + if (params.date) + cal.setDate(params.date); + cal.hide(); + } + if (params.multiple) { + cal.multiple = {}; + for (var i = params.multiple.length; --i >= 0;) { + var d = params.multiple[i]; + var ds = d.print("%Y%m%d"); + cal.multiple[ds] = d; + } + } + cal.showsOtherMonths = params.showOthers; + cal.yearStep = params.step; + cal.setRange(params.range[0], params.range[1]); + cal.params = params; + cal.setDateStatusHandler(params.dateStatusFunc); + cal.getDateText = params.dateText; + cal.setDateFormat(dateFmt); + if (mustCreate) + cal.create(); + cal.refresh(); + if (!params.position) + cal.showAtElement(params.button || params.displayArea || params.inputField, params.align); + else + cal.showAt(params.position[0], params.position[1]); + return false; + }; + + return cal; +}; diff --git a/calendar-win2k-cold-1.css b/calendar-win2k-cold-1.css new file mode 100644 index 0000000..fa5c093 --- /dev/null +++ b/calendar-win2k-cold-1.css @@ -0,0 +1,265 @@ +/* The main calendar widget. DIV containing a table. */ + +.calendar { + position: relative; + display: none; + border-top: 2px solid #fff; + border-right: 2px solid #000; + border-bottom: 2px solid #000; + border-left: 2px solid #fff; + font-size: 11px; + color: #000; + cursor: default; + background: #c8d0d4; + font-family: tahoma,verdana,sans-serif; +} + +.calendar table { + border-top: 1px solid #000; + border-right: 1px solid #fff; + border-bottom: 1px solid #fff; + border-left: 1px solid #000; + font-size: 11px; + color: #000; + cursor: default; + background: #c8d0d4; + font-family: tahoma,verdana,sans-serif; +} + +/* Header part -- contains navigation buttons and day names. */ + +.calendar .button { /* "<<", "<", ">", ">>" buttons have this class */ + text-align: center; + padding: 1px; + border-top: 1px solid #fff; + border-right: 1px solid #000; + border-bottom: 1px solid #000; + border-left: 1px solid #fff; +} + +.calendar .nav { + background: transparent url(menuarrow.gif) no-repeat 100% 100%; +} + +.calendar thead .title { /* This holds the current "month, year" */ + font-weight: bold; + padding: 1px; + border: 1px solid #000; + background: #788084; + color: #fff; + text-align: center; +} + +.calendar thead .headrow { /* Row containing navigation buttons */ +} + +.calendar thead .daynames { /* Row containing the day names */ +} + +.calendar thead .name { /* Cells containing the day names */ + border-bottom: 1px solid #000; + padding: 2px; + text-align: center; + background: #e8f0f4; +} + +.calendar thead .weekend { /* How a weekend day name shows in header */ + color: #f00; +} + +.calendar thead .hilite { /* How do the buttons in header appear when hover */ + border-top: 2px solid #fff; + border-right: 2px solid #000; + border-bottom: 2px solid #000; + border-left: 2px solid #fff; + padding: 0px; + background-color: #d8e0e4; +} + +.calendar thead .active { /* Active (pressed) buttons in header */ + padding: 2px 0px 0px 2px; + border-top: 1px solid #000; + border-right: 1px solid #fff; + border-bottom: 1px solid #fff; + border-left: 1px solid #000; + background-color: #b8c0c4; +} + +/* The body part -- contains all the days in month. */ + +.calendar tbody .day { /* Cells containing month days dates */ + width: 2em; + text-align: right; + padding: 2px 4px 2px 2px; +} +.calendar tbody .day.othermonth { + font-size: 80%; + color: #aaa; +} +.calendar tbody .day.othermonth.oweekend { + color: #faa; +} + +.calendar table .wn { + padding: 2px 3px 2px 2px; + border-right: 1px solid #000; + background: #e8f4f0; +} + +.calendar tbody .rowhilite td { + background: #d8e4e0; +} + +.calendar tbody .rowhilite td.wn { + background: #c8d4d0; +} + +.calendar tbody td.hilite { /* Hovered cells */ + padding: 1px 3px 1px 1px; + border: 1px solid; + border-color: #fff #000 #000 #fff; +} + +.calendar tbody td.active { /* Active (pressed) cells */ + padding: 2px 2px 0px 2px; + border: 1px solid; + border-color: #000 #fff #fff #000; +} + +.calendar tbody td.selected { /* Cell showing selected date */ + font-weight: bold; + padding: 2px 2px 0px 2px; + border: 1px solid; + border-color: #000 #fff #fff #000; + background: #d8e0e4; +} + +.calendar tbody td.weekend { /* Cells showing weekend days */ + color: #f00; +} + +.calendar tbody td.today { /* Cell showing today date */ + font-weight: bold; + color: #00f; +} + +.calendar tbody .disabled { color: #999; } + +.calendar tbody .emptycell { /* Empty cells (the best is to hide them) */ + visibility: hidden; +} + +.calendar tbody .emptyrow { /* Empty row (some months need less than 6 rows) */ + display: none; +} + +/* The footer part -- status bar and "Close" button */ + +.calendar tfoot .footrow { /* The in footer (only one right now) */ +} + +.calendar tfoot .ttip { /* Tooltip (status bar) cell */ + background: #e8f0f4; + padding: 1px; + border: 1px solid #000; + background: #788084; + color: #fff; + text-align: center; +} + +.calendar tfoot .hilite { /* Hover style for buttons in footer */ + border-top: 1px solid #fff; + border-right: 1px solid #000; + border-bottom: 1px solid #000; + border-left: 1px solid #fff; + padding: 1px; + background: #d8e0e4; +} + +.calendar tfoot .active { /* Active (pressed) style for buttons in footer */ + padding: 2px 0px 0px 2px; + border-top: 1px solid #000; + border-right: 1px solid #fff; + border-bottom: 1px solid #fff; + border-left: 1px solid #000; +} + +/* Combo boxes (menus that display months/years for direct selection) */ + +.calendar .combo { + position: absolute; + display: none; + width: 4em; + top: 0px; + left: 0px; + cursor: default; + border-top: 1px solid #fff; + border-right: 1px solid #000; + border-bottom: 1px solid #000; + border-left: 1px solid #fff; + background: #d8e0e4; + font-size: 90%; + padding: 1px; + z-index: 100; +} + +.calendar .combo .label, +.calendar .combo .label-IEfix { + text-align: center; + padding: 1px; +} + +.calendar .combo .label-IEfix { + width: 4em; +} + +.calendar .combo .active { + background: #c8d0d4; + padding: 0px; + border-top: 1px solid #000; + border-right: 1px solid #fff; + border-bottom: 1px solid #fff; + border-left: 1px solid #000; +} + +.calendar .combo .hilite { + background: #048; + color: #aef; +} + +.calendar td.time { + border-top: 1px solid #000; + padding: 1px 0px; + text-align: center; + background-color: #e8f0f4; +} + +.calendar td.time .hour, +.calendar td.time .minute, +.calendar td.time .ampm { + padding: 0px 3px 0px 4px; + border: 1px solid #889; + font-weight: bold; + background-color: #fff; +} + +.calendar td.time .ampm { + text-align: center; +} + +.calendar td.time .colon { + padding: 0px 2px 0px 3px; + font-weight: bold; +} + +.calendar td.time span.hilite { + border-color: #000; + background-color: #667; + color: #fff; +} + +.calendar td.time span.active { + border-color: #f00; + background-color: #000; + color: #0f0; +} diff --git a/calendar.js b/calendar.js new file mode 100644 index 0000000..7136b5b --- /dev/null +++ b/calendar.js @@ -0,0 +1,1806 @@ +/* Copyright Mihai Bazon, 2002-2005 | www.bazon.net/mishoo + * ----------------------------------------------------------- + * + * The DHTML Calendar, version 1.0 "It is happening again" + * + * Details and latest version at: + * www.dynarch.com/projects/calendar + * + * This script is developed by Dynarch.com. Visit us at www.dynarch.com. + * + * This script is distributed under the GNU Lesser General Public License. + * Read the entire license text here: http://www.gnu.org/licenses/lgpl.html + */ + +// $Id: calendar.js,v 1.2 2006/07/08 19:20:34 serge Exp $ + +/** The Calendar object constructor. */ +Calendar = function (firstDayOfWeek, dateStr, onSelected, onClose) { + // member variables + this.activeDiv = null; + this.currentDateEl = null; + this.getDateStatus = null; + this.getDateToolTip = null; + this.getDateText = null; + this.timeout = null; + this.onSelected = onSelected || null; + this.onClose = onClose || null; + this.dragging = false; + this.hidden = false; + this.minYear = 1970; + this.maxYear = 2050; + this.dateFormat = Calendar._TT["DEF_DATE_FORMAT"]; + this.ttDateFormat = Calendar._TT["TT_DATE_FORMAT"]; + this.isPopup = true; + this.weekNumbers = true; + this.firstDayOfWeek = typeof firstDayOfWeek == "number" ? firstDayOfWeek : Calendar._FD; // 0 for Sunday, 1 for Monday, etc. + this.showsOtherMonths = false; + this.dateStr = dateStr; + this.ar_days = null; + this.showsTime = false; + this.time24 = true; + this.yearStep = 2; + this.hiliteToday = true; + this.multiple = null; + // HTML elements + this.table = null; + this.element = null; + this.tbody = null; + this.firstdayname = null; + // Combo boxes + this.monthsCombo = null; + this.yearsCombo = null; + this.hilitedMonth = null; + this.activeMonth = null; + this.hilitedYear = null; + this.activeYear = null; + // Information + this.dateClicked = false; + + // one-time initializations + if (typeof Calendar._SDN == "undefined") { + // table of short day names + if (typeof Calendar._SDN_len == "undefined") + Calendar._SDN_len = 3; + var ar = new Array(); + for (var i = 8; i > 0;) { + ar[--i] = Calendar._DN[i].substr(0, Calendar._SDN_len); + } + Calendar._SDN = ar; + // table of short month names + if (typeof Calendar._SMN_len == "undefined") + Calendar._SMN_len = 3; + ar = new Array(); + for (var i = 12; i > 0;) { + ar[--i] = Calendar._MN[i].substr(0, Calendar._SMN_len); + } + Calendar._SMN = ar; + } +}; + +// ** constants + +/// "static", needed for event handlers. +Calendar._C = null; + +/// detect a special case of "web browser" +Calendar.is_ie = ( /msie/i.test(navigator.userAgent) && + !/opera/i.test(navigator.userAgent) ); + +Calendar.is_ie5 = ( Calendar.is_ie && /msie 5\.0/i.test(navigator.userAgent) ); + +/// detect Opera browser +Calendar.is_opera = /opera/i.test(navigator.userAgent); + +/// detect KHTML-based browsers +Calendar.is_khtml = /Konqueror|Safari|KHTML/i.test(navigator.userAgent); + +// BEGIN: UTILITY FUNCTIONS; beware that these might be moved into a separate +// library, at some point. + +Calendar.getAbsolutePos = function(el) { + var SL = 0, ST = 0; + var is_div = /^div$/i.test(el.tagName); + if (is_div && el.scrollLeft) + SL = el.scrollLeft; + if (is_div && el.scrollTop) + ST = el.scrollTop; + var r = { x: el.offsetLeft - SL, y: el.offsetTop - ST }; + if (el.offsetParent) { + var tmp = this.getAbsolutePos(el.offsetParent); + r.x += tmp.x; + r.y += tmp.y; + } + return r; +}; + +Calendar.isRelated = function (el, evt) { + var related = evt.relatedTarget; + if (!related) { + var type = evt.type; + if (type == "mouseover") { + related = evt.fromElement; + } else if (type == "mouseout") { + related = evt.toElement; + } + } + while (related) { + if (related == el) { + return true; + } + related = related.parentNode; + } + return false; +}; + +Calendar.removeClass = function(el, className) { + if (!(el && el.className)) { + return; + } + var cls = el.className.split(" "); + var ar = new Array(); + for (var i = cls.length; i > 0;) { + if (cls[--i] != className) { + ar[ar.length] = cls[i]; + } + } + el.className = ar.join(" "); +}; + +Calendar.addClass = function(el, className) { + Calendar.removeClass(el, className); + el.className += " " + className; +}; + +// FIXME: the following 2 functions totally suck, are useless and should be replaced immediately. +Calendar.getElement = function(ev) { + var f = Calendar.is_ie ? window.event.srcElement : ev.currentTarget; + while (f.nodeType != 1 || /^div$/i.test(f.tagName)) + f = f.parentNode; + return f; +}; + +Calendar.getTargetElement = function(ev) { + var f = Calendar.is_ie ? window.event.srcElement : ev.target; + while (f.nodeType != 1) + f = f.parentNode; + return f; +}; + +Calendar.stopEvent = function(ev) { + ev || (ev = window.event); + if (Calendar.is_ie) { + ev.cancelBubble = true; + ev.returnValue = false; + } else { + ev.preventDefault(); + ev.stopPropagation(); + } + return false; +}; + +Calendar.addEvent = function(el, evname, func) { + if (el.attachEvent) { // IE + el.attachEvent("on" + evname, func); + } else if (el.addEventListener) { // Gecko / W3C + el.addEventListener(evname, func, true); + } else { + el["on" + evname] = func; + } +}; + +Calendar.removeEvent = function(el, evname, func) { + if (el.detachEvent) { // IE + el.detachEvent("on" + evname, func); + } else if (el.removeEventListener) { // Gecko / W3C + el.removeEventListener(evname, func, true); + } else { + el["on" + evname] = null; + } +}; + +Calendar.createElement = function(type, parent) { + var el = null; + if (document.createElementNS) { + // use the XHTML namespace; IE won't normally get here unless + // _they_ "fix" the DOM2 implementation. + el = document.createElementNS("http://www.w3.org/1999/xhtml", type); + } else { + el = document.createElement(type); + } + if (typeof parent != "undefined") { + parent.appendChild(el); + } + return el; +}; + +// END: UTILITY FUNCTIONS + +// BEGIN: CALENDAR STATIC FUNCTIONS + +/** Internal -- adds a set of events to make some element behave like a button. */ +Calendar._add_evs = function(el) { + with (Calendar) { + addEvent(el, "mouseover", dayMouseOver); + addEvent(el, "mousedown", dayMouseDown); + addEvent(el, "mouseout", dayMouseOut); + if (is_ie) { + addEvent(el, "dblclick", dayMouseDblClick); + el.setAttribute("unselectable", true); + } + } +}; + +Calendar.findMonth = function(el) { + if (typeof el.month != "undefined") { + return el; + } else if (typeof el.parentNode.month != "undefined") { + return el.parentNode; + } + return null; +}; + +Calendar.findYear = function(el) { + if (typeof el.year != "undefined") { + return el; + } else if (typeof el.parentNode.year != "undefined") { + return el.parentNode; + } + return null; +}; + +Calendar.showMonthsCombo = function () { + var cal = Calendar._C; + if (!cal) { + return false; + } + var cal = cal; + var cd = cal.activeDiv; + var mc = cal.monthsCombo; + if (cal.hilitedMonth) { + Calendar.removeClass(cal.hilitedMonth, "hilite"); + } + if (cal.activeMonth) { + Calendar.removeClass(cal.activeMonth, "active"); + } + var mon = cal.monthsCombo.getElementsByTagName("div")[cal.date.getMonth()]; + Calendar.addClass(mon, "active"); + cal.activeMonth = mon; + var s = mc.style; + s.display = "block"; + if (cd.navtype < 0) + s.left = cd.offsetLeft + "px"; + else { + var mcw = mc.offsetWidth; + if (typeof mcw == "undefined") + // Konqueror brain-dead techniques + mcw = 50; + s.left = (cd.offsetLeft + cd.offsetWidth - mcw) + "px"; + } + s.top = (cd.offsetTop + cd.offsetHeight) + "px"; +}; + +Calendar.showYearsCombo = function (fwd) { + var cal = Calendar._C; + if (!cal) { + return false; + } + var cal = cal; + var cd = cal.activeDiv; + var yc = cal.yearsCombo; + if (cal.hilitedYear) { + Calendar.removeClass(cal.hilitedYear, "hilite"); + } + if (cal.activeYear) { + Calendar.removeClass(cal.activeYear, "active"); + } + cal.activeYear = null; + var Y = cal.date.getFullYear() + (fwd ? 1 : -1); + var yr = yc.firstChild; + var show = false; + for (var i = 12; i > 0; --i) { + if (Y >= cal.minYear && Y <= cal.maxYear) { + yr.innerHTML = Y; + yr.year = Y; + yr.style.display = "block"; + show = true; + } else { + yr.style.display = "none"; + } + yr = yr.nextSibling; + Y += fwd ? cal.yearStep : -cal.yearStep; + } + if (show) { + var s = yc.style; + s.display = "block"; + if (cd.navtype < 0) + s.left = cd.offsetLeft + "px"; + else { + var ycw = yc.offsetWidth; + if (typeof ycw == "undefined") + // Konqueror brain-dead techniques + ycw = 50; + s.left = (cd.offsetLeft + cd.offsetWidth - ycw) + "px"; + } + s.top = (cd.offsetTop + cd.offsetHeight) + "px"; + } +}; + +// event handlers + +Calendar.tableMouseUp = function(ev) { + var cal = Calendar._C; + if (!cal) { + return false; + } + if (cal.timeout) { + clearTimeout(cal.timeout); + } + var el = cal.activeDiv; + if (!el) { + return false; + } + var target = Calendar.getTargetElement(ev); + ev || (ev = window.event); + Calendar.removeClass(el, "active"); + if (target == el || target.parentNode == el) { + Calendar.cellClick(el, ev); + } + var mon = Calendar.findMonth(target); + var date = null; + if (mon) { + date = new Date(cal.date); + if (mon.month != date.getMonth()) { + date.setMonth(mon.month); + cal.setDate(date); + cal.dateClicked = false; + cal.callHandler(); + } + } else { + var year = Calendar.findYear(target); + if (year) { + date = new Date(cal.date); + if (year.year != date.getFullYear()) { + date.setFullYear(year.year); + cal.setDate(date); + cal.dateClicked = false; + cal.callHandler(); + } + } + } + with (Calendar) { + removeEvent(document, "mouseup", tableMouseUp); + removeEvent(document, "mouseover", tableMouseOver); + removeEvent(document, "mousemove", tableMouseOver); + cal._hideCombos(); + _C = null; + return stopEvent(ev); + } +}; + +Calendar.tableMouseOver = function (ev) { + var cal = Calendar._C; + if (!cal) { + return; + } + var el = cal.activeDiv; + var target = Calendar.getTargetElement(ev); + if (target == el || target.parentNode == el) { + Calendar.addClass(el, "hilite active"); + Calendar.addClass(el.parentNode, "rowhilite"); + } else { + if (typeof el.navtype == "undefined" || (el.navtype != 50 && (el.navtype == 0 || Math.abs(el.navtype) > 2))) + Calendar.removeClass(el, "active"); + Calendar.removeClass(el, "hilite"); + Calendar.removeClass(el.parentNode, "rowhilite"); + } + ev || (ev = window.event); + if (el.navtype == 50 && target != el) { + var pos = Calendar.getAbsolutePos(el); + var w = el.offsetWidth; + var x = ev.clientX; + var dx; + var decrease = true; + if (x > pos.x + w) { + dx = x - pos.x - w; + decrease = false; + } else + dx = pos.x - x; + + if (dx < 0) dx = 0; + var range = el._range; + var current = el._current; + var count = Math.floor(dx / 10) % range.length; + for (var i = range.length; --i >= 0;) + if (range[i] == current) + break; + while (count-- > 0) + if (decrease) { + if (--i < 0) + i = range.length - 1; + } else if ( ++i >= range.length ) + i = 0; + var newval = range[i]; + el.innerHTML = newval; + + cal.onUpdateTime(); + } + var mon = Calendar.findMonth(target); + if (mon) { + if (mon.month != cal.date.getMonth()) { + if (cal.hilitedMonth) { + Calendar.removeClass(cal.hilitedMonth, "hilite"); + } + Calendar.addClass(mon, "hilite"); + cal.hilitedMonth = mon; + } else if (cal.hilitedMonth) { + Calendar.removeClass(cal.hilitedMonth, "hilite"); + } + } else { + if (cal.hilitedMonth) { + Calendar.removeClass(cal.hilitedMonth, "hilite"); + } + var year = Calendar.findYear(target); + if (year) { + if (year.year != cal.date.getFullYear()) { + if (cal.hilitedYear) { + Calendar.removeClass(cal.hilitedYear, "hilite"); + } + Calendar.addClass(year, "hilite"); + cal.hilitedYear = year; + } else if (cal.hilitedYear) { + Calendar.removeClass(cal.hilitedYear, "hilite"); + } + } else if (cal.hilitedYear) { + Calendar.removeClass(cal.hilitedYear, "hilite"); + } + } + return Calendar.stopEvent(ev); +}; + +Calendar.tableMouseDown = function (ev) { + if (Calendar.getTargetElement(ev) == Calendar.getElement(ev)) { + return Calendar.stopEvent(ev); + } +}; + +Calendar.calDragIt = function (ev) { + var cal = Calendar._C; + if (!(cal && cal.dragging)) { + return false; + } + var posX; + var posY; + if (Calendar.is_ie) { + posY = window.event.clientY + document.body.scrollTop; + posX = window.event.clientX + document.body.scrollLeft; + } else { + posX = ev.pageX; + posY = ev.pageY; + } + cal.hideShowCovered(); + var st = cal.element.style; + st.left = (posX - cal.xOffs) + "px"; + st.top = (posY - cal.yOffs) + "px"; + return Calendar.stopEvent(ev); +}; + +Calendar.calDragEnd = function (ev) { + var cal = Calendar._C; + if (!cal) { + return false; + } + cal.dragging = false; + with (Calendar) { + removeEvent(document, "mousemove", calDragIt); + removeEvent(document, "mouseup", calDragEnd); + tableMouseUp(ev); + } + cal.hideShowCovered(); +}; + +Calendar.dayMouseDown = function(ev) { + var el = Calendar.getElement(ev); + if (el.disabled) { + return false; + } + var cal = el.calendar; + cal.activeDiv = el; + Calendar._C = cal; + if (el.navtype != 300) with (Calendar) { + if (el.navtype == 50) { + el._current = el.innerHTML; + addEvent(document, "mousemove", tableMouseOver); + } else + addEvent(document, Calendar.is_ie5 ? "mousemove" : "mouseover", tableMouseOver); + addClass(el, "hilite active"); + addEvent(document, "mouseup", tableMouseUp); + } else if (cal.isPopup) { + cal._dragStart(ev); + } + if (el.navtype == -1 || el.navtype == 1) { + if (cal.timeout) clearTimeout(cal.timeout); + cal.timeout = setTimeout("Calendar.showMonthsCombo()", 250); + } else if (el.navtype == -2 || el.navtype == 2) { + if (cal.timeout) clearTimeout(cal.timeout); + cal.timeout = setTimeout((el.navtype > 0) ? "Calendar.showYearsCombo(true)" : "Calendar.showYearsCombo(false)", 250); + } else { + cal.timeout = null; + } + return Calendar.stopEvent(ev); +}; + +Calendar.dayMouseDblClick = function(ev) { + Calendar.cellClick(Calendar.getElement(ev), ev || window.event); + if (Calendar.is_ie) { + document.selection.empty(); + } +}; + +Calendar.dayMouseOver = function(ev) { + var el = Calendar.getElement(ev); + if (Calendar.isRelated(el, ev) || Calendar._C || el.disabled) { + return false; + } + if (el.ttip) { + if (el.ttip.substr(0, 1) == "_") { + el.ttip = el.caldate.print(el.calendar.ttDateFormat) + el.ttip.substr(1); + } + el.calendar.tooltips.innerHTML = el.ttip; + } + if (el.navtype != 300) { + Calendar.addClass(el, "hilite"); + if (el.caldate) { + Calendar.addClass(el.parentNode, "rowhilite"); + } + } + return Calendar.stopEvent(ev); +}; + +Calendar.dayMouseOut = function(ev) { + with (Calendar) { + var el = getElement(ev); + if (isRelated(el, ev) || _C || el.disabled) + return false; + removeClass(el, "hilite"); + if (el.caldate) + removeClass(el.parentNode, "rowhilite"); + if (el.calendar) + el.calendar.tooltips.innerHTML = _TT["SEL_DATE"]; + return stopEvent(ev); + } +}; + +/** + * A generic "click" handler :) handles all types of buttons defined in this + * calendar. + */ +Calendar.cellClick = function(el, ev) { + var cal = el.calendar; + var closing = false; + var newdate = false; + var date = null; + if (typeof el.navtype == "undefined") { + if (cal.currentDateEl) { + Calendar.removeClass(cal.currentDateEl, "selected"); + Calendar.addClass(el, "selected"); + closing = (cal.currentDateEl == el); + if (!closing) { + cal.currentDateEl = el; + } + } + cal.date.setDateOnly(el.caldate); + date = cal.date; + var other_month = !(cal.dateClicked = !el.otherMonth); + if (!other_month && !cal.currentDateEl) + cal._toggleMultipleDate(new Date(date)); + else + newdate = !el.disabled; + // a date was clicked + if (other_month) + cal._init(cal.firstDayOfWeek, date); + } else { + if (el.navtype == 200) { + Calendar.removeClass(el, "hilite"); + cal.callCloseHandler(); + return; + } + date = new Date(cal.date); + if (el.navtype == 0) + date.setDateOnly(new Date()); // TODAY + // unless "today" was clicked, we assume no date was clicked so + // the selected handler will know not to close the calenar when + // in single-click mode. + // cal.dateClicked = (el.navtype == 0); + cal.dateClicked = false; + var year = date.getFullYear(); + var mon = date.getMonth(); + function setMonth(m) { + var day = date.getDate(); + var max = date.getMonthDays(m); + if (day > max) { + date.setDate(max); + } + date.setMonth(m); + }; + switch (el.navtype) { + case 400: + Calendar.removeClass(el, "hilite"); + var text = Calendar._TT["ABOUT"]; + if (typeof text != "undefined") { + text += cal.showsTime ? Calendar._TT["ABOUT_TIME"] : ""; + } else { + // FIXME: this should be removed as soon as lang files get updated! + text = "Help and about box text is not translated into this language.\n" + + "If you know this language and you feel generous please update\n" + + "the corresponding file in \"lang\" subdir to match calendar-en.js\n" + + "and send it back to to get it into the distribution ;-)\n\n" + + "Thank you!\n" + + "http://dynarch.com/mishoo/calendar.epl\n"; + } + alert(text); + return; + case -2: + if (year > cal.minYear) { + date.setFullYear(year - 1); + } + break; + case -1: + if (mon > 0) { + setMonth(mon - 1); + } else if (year-- > cal.minYear) { + date.setFullYear(year); + setMonth(11); + } + break; + case 1: + if (mon < 11) { + setMonth(mon + 1); + } else if (year < cal.maxYear) { + date.setFullYear(year + 1); + setMonth(0); + } + break; + case 2: + if (year < cal.maxYear) { + date.setFullYear(year + 1); + } + break; + case 100: + cal.setFirstDayOfWeek(el.fdow); + return; + case 50: + var range = el._range; + var current = el.innerHTML; + for (var i = range.length; --i >= 0;) + if (range[i] == current) + break; + if (ev && ev.shiftKey) { + if (--i < 0) + i = range.length - 1; + } else if ( ++i >= range.length ) + i = 0; + var newval = range[i]; + el.innerHTML = newval; + cal.onUpdateTime(); + return; + case 0: + // TODAY will bring us here + if ((typeof cal.getDateStatus == "function") && + cal.getDateStatus(date, date.getFullYear(), date.getMonth(), date.getDate())) { + return false; + } + break; + } + if (!date.equalsTo(cal.date)) { + cal.setDate(date); + newdate = true; + } else if (el.navtype == 0) + newdate = closing = true; + } + if (newdate) { + ev && cal.callHandler(); + } + if (closing) { + Calendar.removeClass(el, "hilite"); + ev && cal.callCloseHandler(); + } +}; + +// END: CALENDAR STATIC FUNCTIONS + +// BEGIN: CALENDAR OBJECT FUNCTIONS + +/** + * This function creates the calendar inside the given parent. If _par is + * null than it creates a popup calendar inside the BODY element. If _par is + * an element, be it BODY, then it creates a non-popup calendar (still + * hidden). Some properties need to be set before calling this function. + */ +Calendar.prototype.create = function (_par) { + var parent = null; + if (! _par) { + // default parent is the document body, in which case we create + // a popup calendar. + parent = document.getElementsByTagName("body")[0]; + this.isPopup = true; + } else { + parent = _par; + this.isPopup = false; + } + this.date = this.dateStr ? new Date(this.dateStr) : new Date(); + + var table = Calendar.createElement("table"); + this.table = table; + table.cellSpacing = 0; + table.cellPadding = 0; + table.calendar = this; + Calendar.addEvent(table, "mousedown", Calendar.tableMouseDown); + + var div = Calendar.createElement("div"); + this.element = div; + div.className = "calendar"; + if (this.isPopup) { + div.style.position = "absolute"; + div.style.display = "none"; + } + div.appendChild(table); + + var thead = Calendar.createElement("thead", table); + var cell = null; + var row = null; + + var cal = this; + var hh = function (text, cs, navtype) { + cell = Calendar.createElement("td", row); + cell.colSpan = cs; + cell.className = "button"; + if (navtype != 0 && Math.abs(navtype) <= 2) + cell.className += " nav"; + Calendar._add_evs(cell); + cell.calendar = cal; + cell.navtype = navtype; + cell.innerHTML = "
" + text + "
"; + return cell; + }; + + row = Calendar.createElement("tr", thead); + var title_length = 6; + (this.isPopup) && --title_length; + (this.weekNumbers) && ++title_length; + + hh("?", 1, 400).ttip = Calendar._TT["INFO"]; + this.title = hh("", title_length, 300); + this.title.className = "title"; + if (this.isPopup) { + this.title.ttip = Calendar._TT["DRAG_TO_MOVE"]; + this.title.style.cursor = "move"; + hh("×", 1, 200).ttip = Calendar._TT["CLOSE"]; + } + + row = Calendar.createElement("tr", thead); + row.className = "headrow"; + + this._nav_py = hh("«", 1, -2); + this._nav_py.ttip = Calendar._TT["PREV_YEAR"]; + + this._nav_pm = hh("‹", 1, -1); + this._nav_pm.ttip = Calendar._TT["PREV_MONTH"]; + + this._nav_now = hh(Calendar._TT["TODAY"], this.weekNumbers ? 4 : 3, 0); + this._nav_now.ttip = Calendar._TT["GO_TODAY"]; + + this._nav_nm = hh("›", 1, 1); + this._nav_nm.ttip = Calendar._TT["NEXT_MONTH"]; + + this._nav_ny = hh("»", 1, 2); + this._nav_ny.ttip = Calendar._TT["NEXT_YEAR"]; + + // day names + row = Calendar.createElement("tr", thead); + row.className = "daynames"; + if (this.weekNumbers) { + cell = Calendar.createElement("td", row); + cell.className = "name wn"; + cell.innerHTML = Calendar._TT["WK"]; + } + for (var i = 7; i > 0; --i) { + cell = Calendar.createElement("td", row); + if (!i) { + cell.navtype = 100; + cell.calendar = this; + Calendar._add_evs(cell); + } + } + this.firstdayname = (this.weekNumbers) ? row.firstChild.nextSibling : row.firstChild; + this._displayWeekdays(); + + var tbody = Calendar.createElement("tbody", table); + this.tbody = tbody; + + for (i = 6; i > 0; --i) { + row = Calendar.createElement("tr", tbody); + if (this.weekNumbers) { + cell = Calendar.createElement("td", row); + } + for (var j = 7; j > 0; --j) { + cell = Calendar.createElement("td", row); + cell.calendar = this; + Calendar._add_evs(cell); + } + } + + if (this.showsTime) { + row = Calendar.createElement("tr", tbody); + row.className = "time"; + + cell = Calendar.createElement("td", row); + cell.className = "time"; + cell.colSpan = 2; + cell.innerHTML = Calendar._TT["TIME"] || " "; + + cell = Calendar.createElement("td", row); + cell.className = "time"; + cell.colSpan = this.weekNumbers ? 4 : 3; + + (function(){ + function makeTimePart(className, init, range_start, range_end) { + var part = Calendar.createElement("span", cell); + part.className = className; + part.innerHTML = init; + part.calendar = cal; + part.ttip = Calendar._TT["TIME_PART"]; + part.navtype = 50; + part._range = []; + if (typeof range_start != "number") + part._range = range_start; + else { + for (var i = range_start; i <= range_end; ++i) { + var txt; + if (i < 10 && range_end >= 10) txt = '0' + i; + else txt = '' + i; + part._range[part._range.length] = txt; + } + } + Calendar._add_evs(part); + return part; + }; + var hrs = cal.date.getHours(); + var mins = cal.date.getMinutes(); + var t12 = !cal.time24; + var pm = (hrs > 12); + if (t12 && pm) hrs -= 12; + var H = makeTimePart("hour", hrs, t12 ? 1 : 0, t12 ? 12 : 23); + var span = Calendar.createElement("span", cell); + span.innerHTML = ":"; + span.className = "colon"; + var M = makeTimePart("minute", mins, 0, 59); + var AP = null; + cell = Calendar.createElement("td", row); + cell.className = "time"; + cell.colSpan = 2; + if (t12) + AP = makeTimePart("ampm", pm ? "pm" : "am", ["am", "pm"]); + else + cell.innerHTML = " "; + + cal.onSetTime = function() { + var pm, hrs = this.date.getHours(), + mins = this.date.getMinutes(); + if (t12) { + pm = (hrs >= 12); + if (pm) hrs -= 12; + if (hrs == 0) hrs = 12; + AP.innerHTML = pm ? "pm" : "am"; + } + H.innerHTML = (hrs < 10) ? ("0" + hrs) : hrs; + M.innerHTML = (mins < 10) ? ("0" + mins) : mins; + }; + + cal.onUpdateTime = function() { + var date = this.date; + var h = parseInt(H.innerHTML, 10); + if (t12) { + if (/pm/i.test(AP.innerHTML) && h < 12) + h += 12; + else if (/am/i.test(AP.innerHTML) && h == 12) + h = 0; + } + var d = date.getDate(); + var m = date.getMonth(); + var y = date.getFullYear(); + date.setHours(h); + date.setMinutes(parseInt(M.innerHTML, 10)); + date.setFullYear(y); + date.setMonth(m); + date.setDate(d); + this.dateClicked = false; + this.callHandler(); + }; + })(); + } else { + this.onSetTime = this.onUpdateTime = function() {}; + } + + var tfoot = Calendar.createElement("tfoot", table); + + row = Calendar.createElement("tr", tfoot); + row.className = "footrow"; + + cell = hh(Calendar._TT["SEL_DATE"], this.weekNumbers ? 8 : 7, 300); + cell.className = "ttip"; + if (this.isPopup) { + cell.ttip = Calendar._TT["DRAG_TO_MOVE"]; + cell.style.cursor = "move"; + } + this.tooltips = cell; + + div = Calendar.createElement("div", this.element); + this.monthsCombo = div; + div.className = "combo"; + for (i = 0; i < Calendar._MN.length; ++i) { + var mn = Calendar.createElement("div"); + mn.className = Calendar.is_ie ? "label-IEfix" : "label"; + mn.month = i; + mn.innerHTML = Calendar._SMN[i]; + div.appendChild(mn); + } + + div = Calendar.createElement("div", this.element); + this.yearsCombo = div; + div.className = "combo"; + for (i = 12; i > 0; --i) { + var yr = Calendar.createElement("div"); + yr.className = Calendar.is_ie ? "label-IEfix" : "label"; + div.appendChild(yr); + } + + this._init(this.firstDayOfWeek, this.date); + parent.appendChild(this.element); +}; + +/** keyboard navigation, only for popup calendars */ +Calendar._keyEvent = function(ev) { + var cal = window._dynarch_popupCalendar; + if (!cal || cal.multiple) + return false; + (Calendar.is_ie) && (ev = window.event); + var act = (Calendar.is_ie || ev.type == "keypress"), + K = ev.keyCode; + if (ev.ctrlKey) { + switch (K) { + case 37: // KEY left + act && Calendar.cellClick(cal._nav_pm); + break; + case 38: // KEY up + act && Calendar.cellClick(cal._nav_py); + break; + case 39: // KEY right + act && Calendar.cellClick(cal._nav_nm); + break; + case 40: // KEY down + act && Calendar.cellClick(cal._nav_ny); + break; + default: + return false; + } + } else switch (K) { + case 32: // KEY space (now) + Calendar.cellClick(cal._nav_now); + break; + case 27: // KEY esc + act && cal.callCloseHandler(); + break; + case 37: // KEY left + case 38: // KEY up + case 39: // KEY right + case 40: // KEY down + if (act) { + var prev, x, y, ne, el, step; + prev = K == 37 || K == 38; + step = (K == 37 || K == 39) ? 1 : 7; + function setVars() { + el = cal.currentDateEl; + var p = el.pos; + x = p & 15; + y = p >> 4; + ne = cal.ar_days[y][x]; + };setVars(); + function prevMonth() { + var date = new Date(cal.date); + date.setDate(date.getDate() - step); + cal.setDate(date); + }; + function nextMonth() { + var date = new Date(cal.date); + date.setDate(date.getDate() + step); + cal.setDate(date); + }; + while (1) { + switch (K) { + case 37: // KEY left + if (--x >= 0) + ne = cal.ar_days[y][x]; + else { + x = 6; + K = 38; + continue; + } + break; + case 38: // KEY up + if (--y >= 0) + ne = cal.ar_days[y][x]; + else { + prevMonth(); + setVars(); + } + break; + case 39: // KEY right + if (++x < 7) + ne = cal.ar_days[y][x]; + else { + x = 0; + K = 40; + continue; + } + break; + case 40: // KEY down + if (++y < cal.ar_days.length) + ne = cal.ar_days[y][x]; + else { + nextMonth(); + setVars(); + } + break; + } + break; + } + if (ne) { + if (!ne.disabled) + Calendar.cellClick(ne); + else if (prev) + prevMonth(); + else + nextMonth(); + } + } + break; + case 13: // KEY enter + if (act) + Calendar.cellClick(cal.currentDateEl, ev); + break; + default: + return false; + } + return Calendar.stopEvent(ev); +}; + +/** + * (RE)Initializes the calendar to the given date and firstDayOfWeek + */ +Calendar.prototype._init = function (firstDayOfWeek, date) { + var today = new Date(), + TY = today.getFullYear(), + TM = today.getMonth(), + TD = today.getDate(); + this.table.style.visibility = "hidden"; + var year = date.getFullYear(); + if (year < this.minYear) { + year = this.minYear; + date.setFullYear(year); + } else if (year > this.maxYear) { + year = this.maxYear; + date.setFullYear(year); + } + this.firstDayOfWeek = firstDayOfWeek; + this.date = new Date(date); + var month = date.getMonth(); + var mday = date.getDate(); + var no_days = date.getMonthDays(); + + // calendar voodoo for computing the first day that would actually be + // displayed in the calendar, even if it's from the previous month. + // WARNING: this is magic. ;-) + date.setDate(1); + var day1 = (date.getDay() - this.firstDayOfWeek) % 7; + if (day1 < 0) + day1 += 7; + date.setDate(-day1); + date.setDate(date.getDate() + 1); + + var row = this.tbody.firstChild; + var MN = Calendar._SMN[month]; + var ar_days = this.ar_days = new Array(); + var weekend = Calendar._TT["WEEKEND"]; + var dates = this.multiple ? (this.datesCells = {}) : null; + for (var i = 0; i < 6; ++i, row = row.nextSibling) { + var cell = row.firstChild; + if (this.weekNumbers) { + cell.className = "day wn"; + cell.innerHTML = date.getWeekNumber(); + cell = cell.nextSibling; + } + row.className = "daysrow"; + var hasdays = false, iday, dpos = ar_days[i] = []; + for (var j = 0; j < 7; ++j, cell = cell.nextSibling, date.setDate(iday + 1)) { + iday = date.getDate(); + var wday = date.getDay(); + cell.className = "day"; + cell.pos = i << 4 | j; + dpos[j] = cell; + var current_month = (date.getMonth() == month); + if (!current_month) { + if (this.showsOtherMonths) { + cell.className += " othermonth"; + cell.otherMonth = true; + } else { + cell.className = "emptycell"; + cell.innerHTML = " "; + cell.disabled = true; + continue; + } + } else { + cell.otherMonth = false; + hasdays = true; + } + cell.disabled = false; + cell.innerHTML = this.getDateText ? this.getDateText(date, iday) : iday; + if (dates) + dates[date.print("%Y%m%d")] = cell; + if (this.getDateStatus) { + var status = this.getDateStatus(date, year, month, iday); + if (this.getDateToolTip) { + var toolTip = this.getDateToolTip(date, year, month, iday); + if (toolTip) + cell.title = toolTip; + } + if (status === true) { + cell.className += " disabled"; + cell.disabled = true; + } else { + if (/disabled/i.test(status)) + cell.disabled = true; + cell.className += " " + status; + } + } + if (!cell.disabled) { + cell.caldate = new Date(date); + cell.ttip = "_"; + if (!this.multiple && current_month + && iday == mday && this.hiliteToday) { + cell.className += " selected"; + this.currentDateEl = cell; + } + if (date.getFullYear() == TY && + date.getMonth() == TM && + iday == TD) { + cell.className += " today"; + cell.ttip += Calendar._TT["PART_TODAY"]; + } + if (weekend.indexOf(wday.toString()) != -1) + cell.className += cell.otherMonth ? " oweekend" : " weekend"; + } + } + if (!(hasdays || this.showsOtherMonths)) + row.className = "emptyrow"; + } + this.title.innerHTML = Calendar._MN[month] + ", " + year; + this.onSetTime(); + this.table.style.visibility = "visible"; + this._initMultipleDates(); + // PROFILE + // this.tooltips.innerHTML = "Generated in " + ((new Date()) - today) + " ms"; +}; + +Calendar.prototype._initMultipleDates = function() { + if (this.multiple) { + for (var i in this.multiple) { + var cell = this.datesCells[i]; + var d = this.multiple[i]; + if (!d) + continue; + if (cell) + cell.className += " selected"; + } + } +}; + +Calendar.prototype._toggleMultipleDate = function(date) { + if (this.multiple) { + var ds = date.print("%Y%m%d"); + var cell = this.datesCells[ds]; + if (cell) { + var d = this.multiple[ds]; + if (!d) { + Calendar.addClass(cell, "selected"); + this.multiple[ds] = date; + } else { + Calendar.removeClass(cell, "selected"); + delete this.multiple[ds]; + } + } + } +}; + +Calendar.prototype.setDateToolTipHandler = function (unaryFunction) { + this.getDateToolTip = unaryFunction; +}; + +/** + * Calls _init function above for going to a certain date (but only if the + * date is different than the currently selected one). + */ +Calendar.prototype.setDate = function (date) { + if (!date.equalsTo(this.date)) { + this._init(this.firstDayOfWeek, date); + } +}; + +/** + * Refreshes the calendar. Useful if the "disabledHandler" function is + * dynamic, meaning that the list of disabled date can change at runtime. + * Just * call this function if you think that the list of disabled dates + * should * change. + */ +Calendar.prototype.refresh = function () { + this._init(this.firstDayOfWeek, this.date); +}; + +/** Modifies the "firstDayOfWeek" parameter (pass 0 for Synday, 1 for Monday, etc.). */ +Calendar.prototype.setFirstDayOfWeek = function (firstDayOfWeek) { + this._init(firstDayOfWeek, this.date); + this._displayWeekdays(); +}; + +/** + * Allows customization of what dates are enabled. The "unaryFunction" + * parameter must be a function object that receives the date (as a JS Date + * object) and returns a boolean value. If the returned value is true then + * the passed date will be marked as disabled. + */ +Calendar.prototype.setDateStatusHandler = Calendar.prototype.setDisabledHandler = function (unaryFunction) { + this.getDateStatus = unaryFunction; +}; + +/** Customization of allowed year range for the calendar. */ +Calendar.prototype.setRange = function (a, z) { + this.minYear = a; + this.maxYear = z; +}; + +/** Calls the first user handler (selectedHandler). */ +Calendar.prototype.callHandler = function () { + if (this.onSelected) { + this.onSelected(this, this.date.print(this.dateFormat)); + } +}; + +/** Calls the second user handler (closeHandler). */ +Calendar.prototype.callCloseHandler = function () { + if (this.onClose) { + this.onClose(this); + } + this.hideShowCovered(); +}; + +/** Removes the calendar object from the DOM tree and destroys it. */ +Calendar.prototype.destroy = function () { + var el = this.element.parentNode; + el.removeChild(this.element); + Calendar._C = null; + window._dynarch_popupCalendar = null; +}; + +/** + * Moves the calendar element to a different section in the DOM tree (changes + * its parent). + */ +Calendar.prototype.reparent = function (new_parent) { + var el = this.element; + el.parentNode.removeChild(el); + new_parent.appendChild(el); +}; + +// This gets called when the user presses a mouse button anywhere in the +// document, if the calendar is shown. If the click was outside the open +// calendar this function closes it. +Calendar._checkCalendar = function(ev) { + var calendar = window._dynarch_popupCalendar; + if (!calendar) { + return false; + } + var el = Calendar.is_ie ? Calendar.getElement(ev) : Calendar.getTargetElement(ev); + for (; el != null && el != calendar.element; el = el.parentNode); + if (el == null) { + // calls closeHandler which should hide the calendar. + window._dynarch_popupCalendar.callCloseHandler(); + return Calendar.stopEvent(ev); + } +}; + +/** Shows the calendar. */ +Calendar.prototype.show = function () { + var rows = this.table.getElementsByTagName("tr"); + for (var i = rows.length; i > 0;) { + var row = rows[--i]; + Calendar.removeClass(row, "rowhilite"); + var cells = row.getElementsByTagName("td"); + for (var j = cells.length; j > 0;) { + var cell = cells[--j]; + Calendar.removeClass(cell, "hilite"); + Calendar.removeClass(cell, "active"); + } + } + this.element.style.display = "block"; + this.hidden = false; + if (this.isPopup) { + window._dynarch_popupCalendar = this; + Calendar.addEvent(document, "keydown", Calendar._keyEvent); + Calendar.addEvent(document, "keypress", Calendar._keyEvent); + Calendar.addEvent(document, "mousedown", Calendar._checkCalendar); + } + this.hideShowCovered(); +}; + +/** + * Hides the calendar. Also removes any "hilite" from the class of any TD + * element. + */ +Calendar.prototype.hide = function () { + if (this.isPopup) { + Calendar.removeEvent(document, "keydown", Calendar._keyEvent); + Calendar.removeEvent(document, "keypress", Calendar._keyEvent); + Calendar.removeEvent(document, "mousedown", Calendar._checkCalendar); + } + this.element.style.display = "none"; + this.hidden = true; + this.hideShowCovered(); +}; + +/** + * Shows the calendar at a given absolute position (beware that, depending on + * the calendar element style -- position property -- this might be relative + * to the parent's containing rectangle). + */ +Calendar.prototype.showAt = function (x, y) { + var s = this.element.style; + s.left = x + "px"; + s.top = y + "px"; + this.show(); +}; + +/** Shows the calendar near a given element. */ +Calendar.prototype.showAtElement = function (el, opts) { + var self = this; + var p = Calendar.getAbsolutePos(el); + if (!opts || typeof opts != "string") { + this.showAt(p.x, p.y + el.offsetHeight); + return true; + } + function fixPosition(box) { + if (box.x < 0) + box.x = 0; + if (box.y < 0) + box.y = 0; + var cp = document.createElement("div"); + var s = cp.style; + s.position = "absolute"; + s.right = s.bottom = s.width = s.height = "0px"; + document.body.appendChild(cp); + var br = Calendar.getAbsolutePos(cp); + document.body.removeChild(cp); + if (Calendar.is_ie) { + br.y += document.body.scrollTop; + br.x += document.body.scrollLeft; + } else { + br.y += window.scrollY; + br.x += window.scrollX; + } + var tmp = box.x + box.width - br.x; + if (tmp > 0) box.x -= tmp; + tmp = box.y + box.height - br.y; + if (tmp > 0) box.y -= tmp; + }; + this.element.style.display = "block"; + Calendar.continuation_for_the_fucking_khtml_browser = function() { + var w = self.element.offsetWidth; + var h = self.element.offsetHeight; + self.element.style.display = "none"; + var valign = opts.substr(0, 1); + var halign = "l"; + if (opts.length > 1) { + halign = opts.substr(1, 1); + } + // vertical alignment + switch (valign) { + case "T": p.y -= h; break; + case "B": p.y += el.offsetHeight; break; + case "C": p.y += (el.offsetHeight - h) / 2; break; + case "t": p.y += el.offsetHeight - h; break; + case "b": break; // already there + } + // horizontal alignment + switch (halign) { + case "L": p.x -= w; break; + case "R": p.x += el.offsetWidth; break; + case "C": p.x += (el.offsetWidth - w) / 2; break; + case "l": p.x += el.offsetWidth - w; break; + case "r": break; // already there + } + p.width = w; + p.height = h + 40; + self.monthsCombo.style.display = "none"; + fixPosition(p); + self.showAt(p.x, p.y); + }; + if (Calendar.is_khtml) + setTimeout("Calendar.continuation_for_the_fucking_khtml_browser()", 10); + else + Calendar.continuation_for_the_fucking_khtml_browser(); +}; + +/** Customizes the date format. */ +Calendar.prototype.setDateFormat = function (str) { + this.dateFormat = str; +}; + +/** Customizes the tooltip date format. */ +Calendar.prototype.setTtDateFormat = function (str) { + this.ttDateFormat = str; +}; + +/** + * Tries to identify the date represented in a string. If successful it also + * calls this.setDate which moves the calendar to the given date. + */ +Calendar.prototype.parseDate = function(str, fmt) { + if (!fmt) + fmt = this.dateFormat; + this.setDate(Date.parseDate(str, fmt)); +}; + +Calendar.prototype.hideShowCovered = function () { + if (!Calendar.is_ie && !Calendar.is_opera) + return; + function getVisib(obj){ + var value = obj.style.visibility; + if (!value) { + if (document.defaultView && typeof (document.defaultView.getComputedStyle) == "function") { // Gecko, W3C + if (!Calendar.is_khtml) + value = document.defaultView. + getComputedStyle(obj, "").getPropertyValue("visibility"); + else + value = ''; + } else if (obj.currentStyle) { // IE + value = obj.currentStyle.visibility; + } else + value = ''; + } + return value; + }; + + var tags = new Array("applet", "iframe", "select"); + var el = this.element; + + var p = Calendar.getAbsolutePos(el); + var EX1 = p.x; + var EX2 = el.offsetWidth + EX1; + var EY1 = p.y; + var EY2 = el.offsetHeight + EY1; + + for (var k = tags.length; k > 0; ) { + var ar = document.getElementsByTagName(tags[--k]); + var cc = null; + + for (var i = ar.length; i > 0;) { + cc = ar[--i]; + + p = Calendar.getAbsolutePos(cc); + var CX1 = p.x; + var CX2 = cc.offsetWidth + CX1; + var CY1 = p.y; + var CY2 = cc.offsetHeight + CY1; + + if (this.hidden || (CX1 > EX2) || (CX2 < EX1) || (CY1 > EY2) || (CY2 < EY1)) { + if (!cc.__msh_save_visibility) { + cc.__msh_save_visibility = getVisib(cc); + } + cc.style.visibility = cc.__msh_save_visibility; + } else { + if (!cc.__msh_save_visibility) { + cc.__msh_save_visibility = getVisib(cc); + } + cc.style.visibility = "hidden"; + } + } + } +}; + +/** Internal function; it displays the bar with the names of the weekday. */ +Calendar.prototype._displayWeekdays = function () { + var fdow = this.firstDayOfWeek; + var cell = this.firstdayname; + var weekend = Calendar._TT["WEEKEND"]; + for (var i = 0; i < 7; ++i) { + cell.className = "day name"; + var realday = (i + fdow) % 7; + if (i) { + cell.ttip = Calendar._TT["DAY_FIRST"].replace("%s", Calendar._DN[realday]); + cell.navtype = 100; + cell.calendar = this; + cell.fdow = realday; + Calendar._add_evs(cell); + } + if (weekend.indexOf(realday.toString()) != -1) { + Calendar.addClass(cell, "weekend"); + } + cell.innerHTML = Calendar._SDN[(i + fdow) % 7]; + cell = cell.nextSibling; + } +}; + +/** Internal function. Hides all combo boxes that might be displayed. */ +Calendar.prototype._hideCombos = function () { + this.monthsCombo.style.display = "none"; + this.yearsCombo.style.display = "none"; +}; + +/** Internal function. Starts dragging the element. */ +Calendar.prototype._dragStart = function (ev) { + if (this.dragging) { + return; + } + this.dragging = true; + var posX; + var posY; + if (Calendar.is_ie) { + posY = window.event.clientY + document.body.scrollTop; + posX = window.event.clientX + document.body.scrollLeft; + } else { + posY = ev.clientY + window.scrollY; + posX = ev.clientX + window.scrollX; + } + var st = this.element.style; + this.xOffs = posX - parseInt(st.left); + this.yOffs = posY - parseInt(st.top); + with (Calendar) { + addEvent(document, "mousemove", calDragIt); + addEvent(document, "mouseup", calDragEnd); + } +}; + +// BEGIN: DATE OBJECT PATCHES + +/** Adds the number of days array to the Date object. */ +Date._MD = new Array(31,28,31,30,31,30,31,31,30,31,30,31); + +/** Constants used for time computations */ +Date.SECOND = 1000 /* milliseconds */; +Date.MINUTE = 60 * Date.SECOND; +Date.HOUR = 60 * Date.MINUTE; +Date.DAY = 24 * Date.HOUR; +Date.WEEK = 7 * Date.DAY; + +Date.parseDate = function(str, fmt) { + var today = new Date(); + var y = 0; + var m = -1; + var d = 0; + var a = str.split(/\W+/); + var b = fmt.match(/%./g); + var i = 0, j = 0; + var hr = 0; + var min = 0; + for (i = 0; i < a.length; ++i) { + if (!a[i]) + continue; + switch (b[i]) { + case "%d": + case "%e": + d = parseInt(a[i], 10); + break; + + case "%m": + m = parseInt(a[i], 10) - 1; + break; + + case "%Y": + case "%y": + y = parseInt(a[i], 10); + (y < 100) && (y += (y > 29) ? 1900 : 2000); + break; + + case "%b": + case "%B": + for (j = 0; j < 12; ++j) { + if (Calendar._MN[j].substr(0, a[i].length).toLowerCase() == a[i].toLowerCase()) { m = j; break; } + } + break; + + case "%H": + case "%I": + case "%k": + case "%l": + hr = parseInt(a[i], 10); + break; + + case "%P": + case "%p": + if (/pm/i.test(a[i]) && hr < 12) + hr += 12; + else if (/am/i.test(a[i]) && hr >= 12) + hr -= 12; + break; + + case "%M": + min = parseInt(a[i], 10); + break; + } + } + if (isNaN(y)) y = today.getFullYear(); + if (isNaN(m)) m = today.getMonth(); + if (isNaN(d)) d = today.getDate(); + if (isNaN(hr)) hr = today.getHours(); + if (isNaN(min)) min = today.getMinutes(); + if (y != 0 && m != -1 && d != 0) + return new Date(y, m, d, hr, min, 0); + y = 0; m = -1; d = 0; + for (i = 0; i < a.length; ++i) { + if (a[i].search(/[a-zA-Z]+/) != -1) { + var t = -1; + for (j = 0; j < 12; ++j) { + if (Calendar._MN[j].substr(0, a[i].length).toLowerCase() == a[i].toLowerCase()) { t = j; break; } + } + if (t != -1) { + if (m != -1) { + d = m+1; + } + m = t; + } + } else if (parseInt(a[i], 10) <= 12 && m == -1) { + m = a[i]-1; + } else if (parseInt(a[i], 10) > 31 && y == 0) { + y = parseInt(a[i], 10); + (y < 100) && (y += (y > 29) ? 1900 : 2000); + } else if (d == 0) { + d = a[i]; + } + } + if (y == 0) + y = today.getFullYear(); + if (m != -1 && d != 0) + return new Date(y, m, d, hr, min, 0); + return today; +}; + +/** Returns the number of days in the current month */ +Date.prototype.getMonthDays = function(month) { + var year = this.getFullYear(); + if (typeof month == "undefined") { + month = this.getMonth(); + } + if (((0 == (year%4)) && ( (0 != (year%100)) || (0 == (year%400)))) && month == 1) { + return 29; + } else { + return Date._MD[month]; + } +}; + +/** Returns the number of day in the year. */ +Date.prototype.getDayOfYear = function() { + var now = new Date(this.getFullYear(), this.getMonth(), this.getDate(), 0, 0, 0); + var then = new Date(this.getFullYear(), 0, 0, 0, 0, 0); + var time = now - then; + return Math.floor(time / Date.DAY); +}; + +/** Returns the number of the week in year, as defined in ISO 8601. */ +Date.prototype.getWeekNumber = function() { + var d = new Date(this.getFullYear(), this.getMonth(), this.getDate(), 0, 0, 0); + var DoW = d.getDay(); + d.setDate(d.getDate() - (DoW + 6) % 7 + 3); // Nearest Thu + var ms = d.valueOf(); // GMT + d.setMonth(0); + d.setDate(4); // Thu in Week 1 + return Math.round((ms - d.valueOf()) / (7 * 864e5)) + 1; +}; + +/** Checks date and time equality */ +Date.prototype.equalsTo = function(date) { + return ((this.getFullYear() == date.getFullYear()) && + (this.getMonth() == date.getMonth()) && + (this.getDate() == date.getDate()) && + (this.getHours() == date.getHours()) && + (this.getMinutes() == date.getMinutes())); +}; + +/** Set only the year, month, date parts (keep existing time) */ +Date.prototype.setDateOnly = function(date) { + var tmp = new Date(date); + this.setDate(1); + this.setFullYear(tmp.getFullYear()); + this.setMonth(tmp.getMonth()); + this.setDate(tmp.getDate()); +}; + +/** Prints the date in a string according to the given format. */ +Date.prototype.print = function (str) { + var m = this.getMonth(); + var d = this.getDate(); + var y = this.getFullYear(); + var wn = this.getWeekNumber(); + var w = this.getDay(); + var s = {}; + var hr = this.getHours(); + var pm = (hr >= 12); + var ir = (pm) ? (hr - 12) : hr; + var dy = this.getDayOfYear(); + if (ir == 0) + ir = 12; + var min = this.getMinutes(); + var sec = this.getSeconds(); + s["%a"] = Calendar._SDN[w]; // abbreviated weekday name [FIXME: I18N] + s["%A"] = Calendar._DN[w]; // full weekday name + s["%b"] = Calendar._SMN[m]; // abbreviated month name [FIXME: I18N] + s["%B"] = Calendar._MN[m]; // full month name + // FIXME: %c : preferred date and time representation for the current locale + s["%C"] = 1 + Math.floor(y / 100); // the century number + s["%d"] = (d < 10) ? ("0" + d) : d; // the day of the month (range 01 to 31) + s["%e"] = d; // the day of the month (range 1 to 31) + // FIXME: %D : american date style: %m/%d/%y + // FIXME: %E, %F, %G, %g, %h (man strftime) + s["%H"] = (hr < 10) ? ("0" + hr) : hr; // hour, range 00 to 23 (24h format) + s["%I"] = (ir < 10) ? ("0" + ir) : ir; // hour, range 01 to 12 (12h format) + s["%j"] = (dy < 100) ? ((dy < 10) ? ("00" + dy) : ("0" + dy)) : dy; // day of the year (range 001 to 366) + s["%k"] = hr; // hour, range 0 to 23 (24h format) + s["%l"] = ir; // hour, range 1 to 12 (12h format) + s["%m"] = (m < 9) ? ("0" + (1+m)) : (1+m); // month, range 01 to 12 + s["%M"] = (min < 10) ? ("0" + min) : min; // minute, range 00 to 59 + s["%n"] = "\n"; // a newline character + s["%p"] = pm ? "PM" : "AM"; + s["%P"] = pm ? "pm" : "am"; + // FIXME: %r : the time in am/pm notation %I:%M:%S %p + // FIXME: %R : the time in 24-hour notation %H:%M + s["%s"] = Math.floor(this.getTime() / 1000); + s["%S"] = (sec < 10) ? ("0" + sec) : sec; // seconds, range 00 to 59 + s["%t"] = "\t"; // a tab character + // FIXME: %T : the time in 24-hour notation (%H:%M:%S) + s["%U"] = s["%W"] = s["%V"] = (wn < 10) ? ("0" + wn) : wn; + s["%u"] = w + 1; // the day of the week (range 1 to 7, 1 = MON) + s["%w"] = w; // the day of the week (range 0 to 6, 0 = SUN) + // FIXME: %x : preferred date representation for the current locale without the time + // FIXME: %X : preferred time representation for the current locale without the date + s["%y"] = ('' + y).substr(2, 2); // year without the century (range 00 to 99) + s["%Y"] = y; // year with the century + s["%%"] = "%"; // a literal '%' character + + var re = /%./g; + if (!Calendar.is_ie5 && !Calendar.is_khtml) + return str.replace(re, function (par) { return s[par] || par; }); + + var a = str.match(re); + for (var i = 0; i < a.length; i++) { + var tmp = s[a[i]]; + if (tmp) { + re = new RegExp(a[i], 'g'); + str = str.replace(re, tmp); + } + } + + return str; +}; + +Date.prototype.__msh_oldSetFullYear = Date.prototype.setFullYear; +Date.prototype.setFullYear = function(y) { + var d = new Date(this); + d.__msh_oldSetFullYear(y); + if (d.getMonth() != this.getMonth()) + this.setDate(28); + this.__msh_oldSetFullYear(y); +}; + +// END: DATE OBJECT PATCHES + + +// global object that remembers the calendar +window._dynarch_popupCalendar = null; diff --git a/checklistReport.php b/checklistReport.php new file mode 100644 index 0000000..40603f9 --- /dev/null +++ b/checklistReport.php @@ -0,0 +1,70 @@ +'."\n"; + echo "

Checklist Report: $checklistTitle

\n"; + + echo '[ Edit Checklist ]'."\n"; + echo "
\n"; + + echo '

Checklist Items

'."\n"; + + $query = "SELECT checklistItems.checklistitemId, checklistItems.item, checklistItems.notes, checklistItems.checklistId, checklistItems.checked + FROM checklistItems + LEFT JOIN checklist on checklistItems.checklistId = checklist.checklistId + WHERE checklist.checklistId = '$checklistId' ORDER BY checklistItems.checked DESC, checklistItems.item ASC"; + $result = mysql_query($query) or die ("Error in query"); + + if (mysql_num_rows($result) > 0){ + $counter=0; + + echo "\n"; + echo " \n"; + echo " \n"; + echo " \n"; + echo " \n"; + echo " \n"; + + while($row = mysql_fetch_row($result)){ + echo " \n"; + $checklistItemId = $row[0]; + echo ' \n"; + echo " \n"; + echo ' \n"; + echo " \n"; + $counter = $counter+1; + } + echo "
ItemNotesChecked
'.$row[1]."".$row[2]."
\n"; + + echo '

  Clear Checklist 

'."\n"; + + echo '

'."\n"; + echo '

'."\n"; + if($counter==0){ + echo "No checklist items\n"; + } + } + + + + mysql_free_result($result); + mysql_close($connection); + include_once('footer.php'); +?> diff --git a/config.sample.php b/config.sample.php new file mode 100644 index 0000000..6eba558 --- /dev/null +++ b/config.sample.php @@ -0,0 +1,8 @@ +'; + $pass = ''; + $title = 'GTD'; +?> + diff --git a/credits.php b/credits.php new file mode 100644 index 0000000..d0daf39 --- /dev/null +++ b/credits.php @@ -0,0 +1,30 @@ + + +

gtd-php Credits

+Development Team + + + + + + + +
WhoWhat
Serge ReyProject Founder and Director
Scott Jason KorvekGTD Enhancements
+ +Contributors + + + + + + + + +
WhoWhat
Jason BrownCSS and design
Josh BurnettCSS
Mike KoberCSS (IE Savior)
+ + diff --git a/editCategory.php b/editCategory.php new file mode 100644 index 0000000..42bfc26 --- /dev/null +++ b/editCategory.php @@ -0,0 +1,53 @@ +'.stripslashes($row['category']).'\n'; + } + mysql_free_result($result); + + //Select category to edit + $query = "SELECT categoryId, category, description FROM categories WHERE categoryId = '$categoryId'"; + $result = mysql_query($query) or die ("Error in query"); + $row = mysql_fetch_assoc($result); + +//PAGE DISPLAY CODE + echo "

Edit Category

\n"; + echo '
'; + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + echo '
Category Name
'; + echo '
Description
'; + echo '
Delete categoryReassign all items to category:'; + echo ' '; + echo '
'; + echo '
'; + echo ''; + echo '
'; + + include_once('footer.php'); +?> diff --git a/editChecklist.php b/editChecklist.php new file mode 100644 index 0000000..7c2d682 --- /dev/null +++ b/editChecklist.php @@ -0,0 +1,47 @@ +Edit Checklist: $checklistTitle"; + echo '
'; + echo ''; + echo ''; + echo ''; + + $catquery = "select * from categories"; + $catresult = mysql_query($catquery) or die("error in query: $catquery. ".mysql_error()); + + echo ''; + + echo ''; + echo ''; + + echo ''; + + echo '
Checklist TitleCategory
'; + echo '
Description
'; + echo '
Delete Checklist '; + echo 'Clear Checklist 
'; + echo '
'; + echo ''; + echo ''; + + include_once('footer.php'); +?> diff --git a/editChecklistItem.php b/editChecklistItem.php new file mode 100644 index 0000000..240bdd4 --- /dev/null +++ b/editChecklistItem.php @@ -0,0 +1,62 @@ +Edit checklist Item\n"; + +//SELECT checklistId, title, categoryId, description from checklist ORDER BY title + + $query = "SELECT * from checklist ORDER BY title"; + $result = mysql_query($query) or die ("Error in query: $query. ".mysql_error()); + echo ''."\n"; + echo ''."\n"; + echo " \n"; + echo " \n"; + echo ' \n"; + mysql_free_result($result); + echo " \n"; + echo ' '."\n"; + + echo " \n"; + echo "
checklistCompleted:
\n"; + + echo "\n"; + echo " \n"; + echo ' '."\n"; + echo " \n"; + echo ' '."\n"; + echo ' '."\n"; + echo "
Item
Notes
Delete checklist Item 
\n"; + echo "
\n"; + echo ''."\n"; + echo ''."\n"; + include_once('footer.php'); +?> diff --git a/editContext.php b/editContext.php new file mode 100644 index 0000000..6dd814d --- /dev/null +++ b/editContext.php @@ -0,0 +1,55 @@ +" . stripslashes($row['name']) . "\n"; + } else { + $cshtml .= "\n"; + } + } + mysql_free_result($result); + + //Select context to edit + $query = "SELECT contextId, name, description FROM context WHERE contextId = '$contextId'"; + $result = mysql_query($query) or die ("Error in query"); + $row = mysql_fetch_assoc($result); + +//PAGE DISPLAY CODE + echo "

Edit Context

\n"; + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + echo '
Context Name
'; + echo '
Description
'; + echo '
Delete ContextReassign all items to context:'; + echo ' '; + echo '
'; + echo '
'; + echo ''; + echo '
'; + + include_once('footer.php'); +?> diff --git a/editGoal.php b/editGoal.php new file mode 100644 index 0000000..2c8d9c3 --- /dev/null +++ b/editGoal.php @@ -0,0 +1,85 @@ +Edit Goal"; + $query = "SELECT * from projects order by name"; + $result = mysql_query($query) or die ("Error in query: $query. ".mysql_error()); + echo '
'; + echo ''; + echo ''; + echo ''; + mysql_free_result($result); + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + + echo ''; + echo "
ProjectTypeDate Added:DeadlineCompleted
"; + echo ""; + echo ''; + echo ''; + echo ''; + echo ''; + echo '
Goal
Description
'; + echo '
'; + echo ''; + echo ''; + include_once('footer.php'); +?> diff --git a/editList.php b/editList.php new file mode 100644 index 0000000..e6e73f9 --- /dev/null +++ b/editList.php @@ -0,0 +1,46 @@ +Edit List: $listTitle"; + echo ''; + echo ''; + echo ''; + echo ''; + +//SELECT categoryId, category, description from categories + + $catquery = "select * from categories"; + $catresult = mysql_query($catquery) or die("Error in query"); + + echo ''; + + echo ''; + echo ''; + echo ''; + echo '
List TitleCategory
'; + echo '
Description
'; + echo '
Delete List 
'; + echo '
'; + echo ''; + echo ''; + + include_once('footer.php'); +?> diff --git a/editListItem.php b/editListItem.php new file mode 100644 index 0000000..7ea9e54 --- /dev/null +++ b/editListItem.php @@ -0,0 +1,66 @@ +Edit List Item"; + +//SELECT listId, title, categoryId, description from list ORDER BY title + + $query = "SELECT * from list ORDER BY title"; + $result = mysql_query($query) or die ("Error in query"); + echo ''; + echo ''; + echo ''; + echo ''; + mysql_free_result($result); + + echo ''; + echo ''; + echo ''; + echo "
ListDate Completed:
"; + + echo ""; + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + echo '
Title
Description
Delete List Item 
'; + echo '
'; + echo ''; + echo ''; + include_once('footer.php'); +?> diff --git a/editTimeContext.php b/editTimeContext.php new file mode 100644 index 0000000..b711cff --- /dev/null +++ b/editTimeContext.php @@ -0,0 +1,55 @@ +" . stripslashes($row['timeframe']) . "\n"; + } else { + $cshtml .= "\n"; + } + } + mysql_free_result($result); + + //Select timeframe to edit + $query = "SELECT timeframeId, timeframe, description FROM timeitems WHERE timeframeId = '$tcId'"; + $result = mysql_query($query) or die ("Error in query"); + $row = mysql_fetch_assoc($result); + +//PAGE DISPLAY CODE + echo "

Edit Timeframe

\n"; + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + echo '
Timeframe Name
'; + echo '
Description
'; + echo '
Delete TimeframeReassign Items to timeframe:'; + echo ' '; + echo '
'; + echo '
'; + echo ''; + echo '
'; + + include_once('footer.php'); +?> diff --git a/footer.php b/footer.php new file mode 100644 index 0000000..e5a253a --- /dev/null +++ b/footer.php @@ -0,0 +1,11 @@ + + + + + + + + + diff --git a/gtdfuncs.php b/gtdfuncs.php new file mode 100644 index 0000000..6adfade --- /dev/null +++ b/gtdfuncs.php @@ -0,0 +1,188 @@ + +\n"; + echo "\n"; + for ($i = 0; $i <= $size; $i++) { + $theday = mktime (0,0,0,date("m") ,date("d")+$i ,date("Y")); + $option=date("D M j, Y",$theday); + //$value=date("m:d:Y",$theday); + $value=date("Y-m-d",$theday); + $dow=date("D",$theday); + if ($dow=="Mon") { + echo "\n"; + } + if ($value == $default) { + $selected="SELECTED"; + } else { + $selected=""; + } + if (($dow!="Sun" and $dow!="Sat") or !$skip) { + echo ''; + } + } + echo "\n"; + } + + function getNextActions(){ + // Get all next actions, distinguishing between regular actions and + // next actions. + // Argument: + // none + // Return: + // list: associative array with two elements + // n: count of next actions + // result: mysql result object + // + $query = "SELECT nextaction FROM nextactions"; + $result = mysql_query($query) or die ("Error in query"); + $nr=mysql_numrows($result); + $list['n']=$nr; + $list['result']=$result; + return $list; + } + + function getActions(){ + // Get all (completed and pending) of the next actions + // Argument: + // none + // Return: + // list: associative array with two elements + // n: count of next actions + // result: mysql result object + $query = "SELECT itemattributes.itemid FROM itemattributes WHERE type = 'a'"; + $result = mysql_query($query) or die ("Error in query"); + $nr=mysql_numrows($result); + $list['n']=$nr; + $list['result']=$result; + return $list; + } + + function getCompletedNextActions(){ + // Get completed next actions + // Argument: + // none + // Return: + // list: associative array with two elements + // n: count of next actions + // result: mysql result object + $result = mysql_query("SELECT itemstatus.itemId FROM itemstatus, itemattributes + WHERE itemattributes.itemId=itemstatus.itemId AND itemattributes.type='a' AND dateCompleted >0"); + $nr=mysql_numrows($result); + $list['n']=$nr; + $list['result']=$result; + return $list; + } + + + function getNumberOfAllNextActions(){ + // Get the number of all next actions (completed and pending) + // Argument: + // none + // Return: + // n: integer + $result=getAllNextActions(); + return $result['n']; + } + + function getNumberOfNextActions(){ + // Get the number of pending next actions + // Argument: + // none + // Return: + // n: integer + $result=getNextActions(); + return $result['n']; + } + + function getNumberOfActions(){ + // Get the number of pending actions + // Argument: + // none + // Return: + // n: integer count of all actions (next and regular) that are + // pending. + $result=getActions(); + $ntotal=$result['n']; + $result=getCompletedNextActions(); + $ncomp=$result['n']; + $npending = $ntotal-$ncomp; + return $npending; + } + + function getProjectTitle($projectId){ + // Get the title of a project + // Argument: + // projectId: int project id + // Return: + // projectTitle: string + $query="select name from projects where projectId='$projectId'"; + $result=mysql_query($query) or die ("Error in query"); + $row=mysql_fetch_row($result); + $projectTitle=stripslashes($row[0]); + return $projectTitle; + } + + function projectName($projectId){ + // Get project name + // Argument: + // projectId: int + // Return: + // name: string + // -1: if projectId not in result set not found + $projectRes = mysql_query("select * from projects"); + $names = array(); + $flag=1; + while($row = mysql_fetch_array($projectRes,MYSQL_ASSOC)){ + $id = $row['projectId']; + $name = stripslashes($row['name']); + if($id==$projectId){ + $flag = 0; + return $name; + } + } + return -1; + } + + function nonext($projectId) { + $query = "SELECT projectId, nextaction FROM nextactions WHERE projectId='$projectId'"; + $result = mysql_query($query) or die ("Error in query: $query. ".mysql_error()); + if (mysql_num_rows($result)>0) $nonext="false"; + else $nonext="true"; + return $nonext; + } + + function doquery($query){ + $result = mysql_query($query); + if ($result) return $result; + else{ + die ("Error in query: $query. MySQL Error: ".mysql_error()); + } + } + +?> diff --git a/header.php b/header.php new file mode 100644 index 0000000..f43a4b1 --- /dev/null +++ b/header.php @@ -0,0 +1,119 @@ + + + + + +'.$title.''; +?> + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + +
+ + diff --git a/img.gif b/img.gif new file mode 100644 index 0000000000000000000000000000000000000000..cd2c4a521774c70473f11c88642543751a812d6f GIT binary patch literal 223 zcmY+8F$w}P5Jmsu1X2mY7Pj^lfoWE3A`H5AX$H3SCIQzYcmogOL2?Q^tGEd(=x;uM z{$plN=VQ0Kv{>RraL#2QrIhnCSD|Y2rlx_xwxq&h@fcKZs#?v!0&(grG%|C?d}R)U zD^^qZLqwz(8AZb2F@n7Ht1*~)C_QN;j~*1;!-N#FcEOM(A3fUjg#2vzUPlb`OU3Tk Fe*i=yIHv#r literal 0 HcmV?d00001 diff --git a/index.php b/index.php new file mode 100644 index 0000000..1277c58 --- /dev/null +++ b/index.php @@ -0,0 +1,7 @@ + diff --git a/install.php b/install.php new file mode 100644 index 0000000..7904c91 --- /dev/null +++ b/install.php @@ -0,0 +1,503 @@ +gtd-php installation/upgrade"; + echo "

Upgrade check

"; + + //connect + $connection = mysql_connect($host, $user, $pass) or die ("unable to connect"); + + //check if gtd db has been created + $msg="Unable to select gtd database.
Please create the gtd mysql database and rerun this script."; + mysql_select_db($db) or die ($msg); + + //check if we are doing a new install, an upgrade, or are we current + $tprojects=0; + $titemstatus=0; + //echo $db; + //checking for table itemstatus (new in 0.6) + $tables = mysql_list_tables($db); + while (list($temp) = mysql_fetch_array($tables)){ + //echo "
"; + //echo $temp; + if($temp == 'itemstatus'){ + $titemstatus=1; + } + if($temp == 'projects'){ + $tprojects=1; + } + } + //echo $tprojects; + //echo $titemstatus; + //upgrade, 0 = current, 1 = new install, 2 = upgrade + if ($tprojects==$titemstatus){ + if($tprojects==1){ + $upgrade=0; + }else{ + $upgrade=1; + } + }else{ + $upgrade=2; + } + echo "
"; + if ($upgrade==0){ + echo "No upgrade necessary."; + }elseif($upgrade==1){ + echo "New installation."; + + //Using heredoc to create tables. last TEST cannot be indented. + $query = << 30 Minutes'); +TEST; + $result = mysql_query($query); + }elseif($upgrade=2){ + echo "Upgrading to version 0.6"; + echo "
"; + //create three new tables from old nextActions table + // items first + echo "Creating table items
"; + $query = "select nextActionId, title, description from nextActions"; + $result = mysql_query($query); + $query="create table items (itemId int(10) unsigned not null auto_increment, title text not null, description longtext, primary key (itemId))"; + $result = mysql_query($query); + $query="insert into items(title, description) select title,description from nextActions"; + $result = mysql_query($query); + $query="select max(itemId) from items"; + $result=mysql_query($query); + $tmp=mysql_fetch_row($result); + $nacount=$tmp[0]; + //echo $nacount; + // add reference items + $query="insert into items(title, description) select title, description from reference"; + $result = mysql_query($query); + echo "Creating table itemstatus
"; + $query="create table itemstatus(itemId int unsigned not null auto_increment, dateCreated date not null, lastModified timestamp, dateCompleted date, completed int(10) unsigned, primary key(itemId))"; + $result = mysql_query($query); + + $query="insert into itemstatus(dateCreated, dateCompleted, completed) select dateCreated, dateCompleted, completed from nextActions"; + $result = mysql_query($query); + //now add any references + $query="insert into itemstatus(dateCreated) select dateCreated from reference"; + $result = mysql_query($query); + + echo "Creating table itemattributes
"; + $query="create table itemattributes (itemId int unsigned not null auto_increment, type enum('a','r','w') not null default 'a', + projectId int(10) unsigned not null default 0, + contextId int(10) unsigned not null default 1, + timeframeId int(10) unsigned not null default 1, + deadline date, + `repeat` int(10) unsigned not null default 0, + suppress enum('y','n') not null default 'n', + suppressUntil int(10) unsigned default NULL, + primary key(itemId))"; + $result = mysql_query($query); + $query="insert into itemattributes(projectId, contextId, timeframeId, deadline, `repeat`) select projectId, contextId, timeId, deadline, repeat from nextActions"; + $result = mysql_query($query); + // add references + $query="insert into itemattributes(projectId) select projectId from reference"; + $result = mysql_query($query); + //update reference type + $query="update itemattributes set type='r' where itemId > '$nacount'"; + $result = mysql_query($query); + + // add waiting ons + $query="select max(itemId) from items"; + $result = mysql_query($query); + $tmp=mysql_fetch_row($result); + $nacount=$tmp[0]; + $query="insert into items(title, description) select title, description from waitingOn"; + $result = mysql_query($query); + $query="insert into itemstatus(dateCreated, dateCompleted) select dateCreated, dateCompleted from waitingOn"; + $result = mysql_query($query); + $query="insert into itemattributes(projectId) select projectId from waitingOn"; + $result = mysql_query($query); + $query="update itemattributes set type='w' where itemId > '$nacount'"; + $result = mysql_query($query); + + //get rid of 0 offset for timeId + $query="update itemattributes set timeframeId = timeframeId+1"; + $result = mysql_query($query); + + //modify nextActions table + echo "Modifying nextActions table
"; + $query =<<"; + + $query = <<"; + $query = << diff --git a/item.php b/item.php new file mode 100644 index 0000000..d0f1e34 --- /dev/null +++ b/item.php @@ -0,0 +1,226 @@ +0) { + $query= "SELECT items.itemId, itemattributes.projectId, itemattributes.contextId, itemattributes.type, itemattributes.timeframeId, items.title, + items.description, itemstatus.dateCreated, itemattributes.deadline, itemstatus.dateCompleted, itemstatus.lastModified, + itemattributes.repeat, itemattributes.suppress, itemattributes.suppressUntil FROM items, itemattributes, itemstatus + WHERE itemstatus.itemId=items.itemId and itemattributes.itemId=items.itemId and items.itemId = '$itemId'"; + $result = mysql_query($query) or die ("Error in query"); + $currentrow = mysql_fetch_assoc($result); + mysql_free_result($result); + $type=$currentrow['type']; + } + + //Test to see if nextaction + $query = "SELECT projectId, nextaction FROM nextactions where nextaction='$itemId'"; + $result = mysql_query($query) or die ("Error in query"); + while ($nextactiontest = mysql_fetch_assoc($result)) { + if ($nextactiontest['nextaction']==$itemId) $nextactioncheck='true'; + } + mysql_free_result($result); + + + //select active or someday projects for selectbox (would make good function!) + $query="SELECT projects.projectId, projects.name, projects.description + FROM projects, projectattributes, projectstatus + WHERE projectattributes.projectId = projects.projectId + AND projectstatus.projectId=projects.projectId + AND (projectstatus.dateCompleted IS NULL OR projectstatus.dateCompleted = '0000-00-00') + AND projectattributes.isSomeday ='".$isSomeday."' ORDER BY projects.name"; + $result = mysql_query($query) or die ("Error in query"); + $pshtml=""; + while($row = mysql_fetch_assoc($result)){ + $pshtml .= '