96 Commits

Author SHA1 Message Date
Thomas Keller
3cc14ef6a0 Merge branch 'release-1.3' into develop 2012-11-19 00:17:29 +01:00
Thomas Keller
02613203c9 Ease the creation of tarballs a bit. 2012-11-19 00:16:02 +01:00
Thomas Keller
6f4af6b68d Start 1.3.4 development 2012-11-18 23:58:18 +01:00
Thomas Keller
ebb8d46420 Release 1.3.3 2012-11-18 23:55:17 +01:00
Thomas Keller
6c5406dd99 Fix a problem in jquery.hotkeys that triggered global hotkeys when one was
in a password text field. Upstream should know of this problem for a long
time already, but hasn't released a fixed version yet, so we're applying
our own patch here (fixes issue 821).
2012-11-18 00:58:27 +01:00
Thomas Keller
4aa4100532 Update French translation from Transifex. 2012-11-18 00:28:30 +01:00
Thomas Keller
d90c1a2c23 $prj wasn't defined, so use the project reference that the page has instead (fixes issue 808) 2012-07-20 15:03:57 +02:00
Thomas Keller
22c1f92b2b Use git's "find copies harder" algorithm to - well - find copies in changesets
and render them as such.
2012-07-11 00:17:23 +02:00
Thomas Keller
d17098e703 Ensure that PHP doesn't interpret read ini file values and therefor
scrambles the output of hgrc files (issue 523).
2012-06-05 20:55:21 +02:00
Thomas Keller
64c6674762 Copy over all project properties, except a few scm settings and very
project-specific ones, when a new project is based on another one.
2012-05-21 23:33:38 +02:00
Thomas Keller
01febe1411 Merge branch 'release-1.3' into develop 2012-05-15 22:48:56 +02:00
Thomas Keller
839444cc8a Use Pluf's new migration capabilities to prevent problems with the
circular dependency between project and project activity during
new db installations (issue 800).
ATTENTION: IDF now needs Pluf a45dc195 or newer!
2012-05-15 22:43:15 +02:00
Thomas Keller
831439120c Make the current_activity field in IDF_Project nullable and fix
a problem in the migration 25's down method (issue 800)
2012-05-15 22:38:27 +02:00
Thomas Keller
6bb886b92a If ssh public key data contain forward slashes, the SyncGit cron job
did not properly find and update the region which it should have
under its control (thanks to Simon Gareste for the fix!)
2012-05-14 19:38:07 +02:00
Thomas Keller
dd3474c06c Add two more targets to dump and restore application backups. 2012-05-12 02:25:33 +02:00
Thomas Keller
bcd515eed5 Do not display all project to a user if he has no rights for
_any_ project of the forge, but actually hide all... thanks
to René Klomp for this finding!
2012-05-11 23:26:42 +02:00
Thomas Keller
231dfaa8a6 Merge branch 'release-1.3' of projects.ceondo.com:indefero into develop 2012-05-09 22:21:32 +02:00
Thomas Keller
0826dab575 Start 1.3.3 development. 2012-05-09 22:10:24 +02:00
Thomas Keller
1c037f81a0 Release 1.3.2. 2012-05-09 22:09:13 +02:00
Thomas Keller
71c41fe940 Of course $ids should have been initialized beforehand... 2012-05-07 23:26:23 +02:00
Thomas Keller
8ad0707509 Fix the project display when no projects are available or visible. 2012-05-07 23:12:55 +02:00
Thomas Keller
e0dec2278c Merge branch 'feature.issue-due-date' of https://github.com/treffynnon/Indefero into develop 2012-05-06 23:12:52 +02:00
Thomas Keller
7221135849 Merge branch 'release-1.3' into develop 2012-05-06 22:49:48 +02:00
Thomas Keller
a2d5b14a2c Start with 1.3.2 development. 2012-05-06 22:49:04 +02:00
Thomas Keller
16de6a0d77 Enter a release date and pin the current version. 2012-05-06 22:34:56 +02:00
Thomas Keller
03404adf64 - move getProjectsWithLabelCounts to IDF_Views (where the other functions
reside as well) and make it static
- refactor out the code from getProjects that determines which projects
  are visible by a user and use the same code to restrict the count that
  we calculate for all available project tags
- calculating the project stats is now no longer O(5n) but simply O(5)
  when it comes to SQL queries (where n is the number of filtered projects);
  remove the member statistic since it makes no sense in this context
2012-05-04 23:31:07 +02:00
Thomas Keller
dd2fa6f902 Remove OS9 line ending support again, this was left out for a reason.
Fix tests after issue 804 was fixed.
2012-05-04 01:01:33 +02:00
Thomas Keller
b6acf4c0e2 Replace the implementation of splitIntoLines by a new one that does
not need PHP's array_shift which tends to be very slow for arrays
with many thousand entries (fixes issue 804).
2012-05-04 00:48:53 +02:00
Simon Holywell
cf1a7e8852 fix migration number after merging in the changes to the develop branch 2012-05-02 12:32:14 +01:00
Simon Holywell
c0035061b0 Merge branch 'develop' into feature.issue-due-date 2012-05-02 12:21:44 +01:00
Simon Holywell
6c130cd3ca Fix error where a due date of 0000-00-00 00:00:00 was not equated to empty by forcing to null in model restore() method 2012-05-02 12:18:53 +01:00
Thomas Keller
8db3c45763 Revamp this a little and make it jQuery 1.7 compatible (fixes issue 803) 2012-04-29 00:24:09 +02:00
Simon Holywell
696f2d06d6 Attempt to clean up any code inconsistencies and remove an erroneously committed file 2012-04-27 18:34:34 +01:00
Simon Holywell
158f9288d3 Try to avoid anchors with '#' as target and use
'javascript:void(0);' instead
2012-04-27 14:57:18 +01:00
Simon Holywell
e883f22790 Make date shortcut names and titles translatable 2012-04-27 14:54:08 +01:00
Simon Holywell
2b5bf490a5 The {aurl} must be outside the {blocktrans} 2012-04-27 09:36:22 +01:00
Simon Holywell
014d8ca6af Change route to remove ability to pass through due status 2012-04-27 09:31:07 +01:00
Simon Holywell
02a99e2f9c The overdue marker in list views is now translatable 2012-04-27 09:22:36 +01:00
Simon Holywell
23253fc40e Fix the duplication of the date shortcut codes 2012-04-26 17:24:06 +01:00
Simon Holywell
d348c45c56 simplify the code in IDF_Views_Issue a little 2012-04-26 17:18:35 +01:00
Simon Holywell
53f6133899 Refactor getIssueCountByDueDate slightly 2012-04-26 17:01:10 +01:00
Simon Holywell
c3bbddb1ff Repair the issue due date migration for Postgresql 2012-04-26 16:29:26 +01:00
Simon Holywell
a608d7ea0a add an explanatory comment to the Issue model preSave hack 2012-04-26 16:24:35 +01:00
Simon Holywell
fde3a0a949 Date validation in the Issue model 2012-04-26 16:22:11 +01:00
Simon Holywell
2bd2b3a463 Repair borked conflicted merge :( 2012-04-26 16:19:11 +01:00
Simon Holywell
7207cdcd46 Merge branch 'feature.issue-due-date' of github.com:treffynnon/Indefero into feature.issue-due-date
Conflicts:
	src/IDF/Form/IssueUpdate.php
2012-04-26 16:16:45 +01:00
Simon Holywell
85f247909e Remove local Date field types and use Pluf newly added ones instead 2012-04-26 16:14:41 +01:00
Thomas Keller
e8882292b5 Improve the error we throw at the user if no configuration is found
to calculate the project activities.
2012-04-24 20:37:23 +02:00
Thomas Keller
bca3eb332e Reference the issue in which the Postgres issues have been tracked. 2012-04-22 23:11:48 +02:00
Thomas Keller
307c35ff42 Pulled updated French translation from Transifex (thanks to
Jonathan Aillet, again!)
2012-04-22 00:52:33 +02:00
Thomas Keller
786e9f81c0 Added Jonathan's email. 2012-04-21 19:03:25 +02:00
Thomas Keller
8cd19c0f53 Escape the xml file path arg. 2012-04-20 00:50:24 +02:00
Thomas Keller
d5394265ba Formatting fix. 2012-04-20 00:12:45 +02:00
Thomas Keller
0919cb83d8 Properly mark 1.3.1 dev version. 2012-04-19 23:40:50 +02:00
Thomas Keller
b356625268 Merge branch 'release-1.3' into develop 2012-04-19 23:39:47 +02:00
Thomas Keller
4e8ca58a2e Start 1.4 development 2012-04-19 23:37:53 +02:00
Simon Holywell
6996e1185f Issue #13: Due time handling (local time / UTC)
- Move time strip into the formInit method and out of the model
- Improve the validation of the issue due date on the preSave method of the model
2012-04-19 21:20:51 +01:00
Thomas Keller
b7ad4bf47a Apparently the default project for tags is still 0, so make it explicit. 2012-04-19 00:37:09 +02:00
Thomas Keller
75f62663a9 Make the project field in the tags table nullable so it is (hopefully)
optional on setups with enabled foreign key constraints.
2012-04-19 00:14:10 +02:00
Thomas Keller
169fbe6216 Another Postgres issue fixed. 2012-04-18 23:22:32 +02:00
Thomas Keller
84d80af1ce Postgres seems to need every column in the group by, not only the PK. 2012-04-18 23:00:37 +02:00
Thomas Keller
d1542c9c00 Another Postgres issue (hopefully fixes issue 800). 2012-04-18 22:09:53 +02:00
Thomas Keller
4da01b2732 Another Postgres nuisance. 2012-04-18 22:05:17 +02:00
Thomas Keller
b44ad48fd5 Another PostgreSQL issue (hopefully) fixed. 2012-04-18 07:17:35 +02:00
Thomas Keller
3ae92627bc French translation pulled from transifex. 2012-04-18 00:59:41 +02:00
Thomas Keller
d46df5c129 Fix PostgreSQL compatibility issues. 2012-04-18 00:55:29 +02:00
Simon Holywell
11b3811e17 Issue #8 Misleading label in issue form (minor) - improve styling 2012-04-13 16:59:09 +01:00
Simon Holywell
3e78376be3 Issue #13 Due time handling (local time / UTC) 2012-04-13 14:07:18 +01:00
Simon Holywell
cf2f9d419e Issue #8 Misleading label in issue form (minor) 2012-04-13 13:05:58 +01:00
Simon Holywell
a9630cea0d Issue #16 Make the date format uniform with the rest of Indefero 2012-04-13 13:00:40 +01:00
Simon Holywell
4323edcf0c Issue #14 The Atom feed is missing a section label for Due date changes 2012-04-13 11:52:04 +01:00
Simon Holywell
120101c4df Issue #11 Filtering by tickets that are not overdue not possible from the list views 2012-04-13 11:47:39 +01:00
Simon Holywell
b9c3ee1a09 Issue #16 Make the date format uniform with the rest of Indefero 2012-04-13 11:27:32 +01:00
Simon Holywell
60cdd2224f Issue #9 No display of due date for anonymous users 2012-04-13 11:27:01 +01:00
Simon Holywell
e7643e97e4 Issue #7 Undefined variable duedateStatistics for empty project 2012-04-13 10:55:49 +01:00
Simon Holywell
10e5f350f7 Add in helpful shortcuts menu to issue due dates 2012-04-10 21:46:58 +01:00
Simon Holywell
1690fa8416 Move the default due date time to be configurable in the IDF config file 2012-04-10 12:17:22 +01:00
Simon Holywell
9168a26a72 Merge branch 'develop' into feature.issue-due-date 2012-04-10 11:50:22 +01:00
Simon Holywell
3bf4977460 Closes issue 3: Issues list left hand navigation - controls for issue due date 2012-03-30 15:20:05 +01:00
Simon Holywell
315e06da1b Merge branch 'develop' into feature.issue-due-date
Conflicts:
	src/IDF/templates/idf/base-full.html
	src/IDF/templates/idf/base-simple.html
	src/IDF/templates/idf/base.html
2012-03-30 12:20:07 +01:00
Simon Holywell
3a71d71ef8 Setup the overdue summary graph and issue list view 2012-03-23 17:03:17 +00:00
Simon Holywell
1d15d53eaa Add in the beginings of overdue issue display 2012-03-23 00:29:15 +00:00
Simon Holywell
1b363e4b6d Hide overdue tag on issues that are now complete 2012-03-22 22:19:43 +00:00
Simon Holywell
f7d75f1b94 Move the issue due date migration to position 25 to 19 to avoid collision with the latest updates to the develop branch 2012-03-22 11:36:26 +00:00
Simon Holywell
fa95cbd934 Merge branch 'develop' into feature.issue-due-date 2012-03-22 11:01:34 +00:00
Simon Holywell
47da6adebb Tweak JS to allow multiple date formats 2012-03-11 01:43:45 +00:00
Simon Holywell
69949b2941 Add in a due date column to issue lists and a red overdue flag after the issue summary 2012-03-11 01:15:29 +00:00
Simon Holywell
d676727c1e Allow for non-mandantory date time fields 2012-03-10 23:16:12 +00:00
Simon Holywell
e0da21cbf8 Normalize case of the due date title across the code 2012-03-08 16:50:40 +00:00
Simon Holywell
214d035d12 Add in support for issue notification emails to include due dates 2012-03-08 15:57:42 +00:00
Simon Holywell
f005bc1ddd Improve the issue due date field with JS helpers
- Add jQuery UI datepicker widget to the field
- Duplicate changes on the create an issue template
2012-03-08 15:03:02 +00:00
Simon Holywell
9beffaae7e Merge remote branch 'origin/develop' into feature.issue-due-date 2012-03-08 14:47:01 +00:00
Simon Holywell
0e52a2e673 Setup a simple JS shortcut to insert todays date for the due date 2012-03-05 23:05:12 +00:00
Simon Holywell
c2d61083a7 Fix the due date display 2012-03-05 22:34:30 +00:00
Simon Holywell
f8a1d26b28 Add in the the migration for the due date field for issues 2012-03-05 21:28:58 +00:00
Simon Holywell
f697d97b6a Issue 584: Ability to add a due date to a ticket - beginnings thereof 2012-03-04 22:57:26 +00:00
66 changed files with 2465 additions and 599 deletions

1
.gitignore vendored
View File

@@ -5,6 +5,7 @@
.settings .settings
.tx/config .tx/config
attachments attachments
backups
indefero-*.zip indefero-*.zip
src/IDF/conf/idf.php src/IDF/conf/idf.php
src/IDF/conf/idf.test.php src/IDF/conf/idf.test.php

View File

@@ -7,6 +7,7 @@ Much appreciated contributors (in alphabetical order):
Andrew Nguyen <andrew-git-indefero@na-consulting.net> Andrew Nguyen <andrew-git-indefero@na-consulting.net>
Baptiste Durand-Bret <bathizte@ozazar.org> Baptiste Durand-Bret <bathizte@ozazar.org>
Baptiste Michaud <bactisme@gmail.com> - Subversion sync Baptiste Michaud <bactisme@gmail.com> - Subversion sync
Benjamin Danon <benjamin@sphax3d.org> - French translation
Benjamin Jorand <benjamin.jorand@gmail.com> - Mercurial support Benjamin Jorand <benjamin.jorand@gmail.com> - Mercurial support
Brenda Wallace <shiny@cpan.org> Brenda Wallace <shiny@cpan.org>
Brian Armstrong <brianar> Brian Armstrong <brianar>
@@ -22,6 +23,7 @@ Much appreciated contributors (in alphabetical order):
Janez Troha <http://www.dz0ny.info> - Slovenian translation Janez Troha <http://www.dz0ny.info> - Slovenian translation
Jean-Philippe Fleury <jpfleury> Jean-Philippe Fleury <jpfleury>
Jerry <lxb429@gmail.com> - Chinese translation Jerry <lxb429@gmail.com> - Chinese translation
Jonathan Aillet <jonathan.aillet@gmail.com> - French translation
Julien Issler <julien@issler.net> Julien Issler <julien@issler.net>
Litew <litew9@gmail.com> - Russian translation Litew <litew9@gmail.com> - Russian translation
Ludovic Bellière <xrogaan> Ludovic Bellière <xrogaan>

View File

@@ -37,10 +37,11 @@ help:
@printf "\tpo-push - Send the all PO files to the transifex server.\n" @printf "\tpo-push - Send the all PO files to the transifex server.\n"
@printf "\tpo-pull - Get all PO files from the transifex server.\n" @printf "\tpo-pull - Get all PO files from the transifex server.\n"
@printf "\tpo-stats - Show translation statistics of all PO files.\n" @printf "\tpo-stats - Show translation statistics of all PO files.\n"
@printf "\nMisc Rules :\n"; @printf "\nRules for managing the database :\n";
@printf "\tdb-install - Install the database schema.\n" @printf "\tdb-install - Install the database schema.\n"
@printf "\tdb-update - Update the database schema.\n" @printf "\tdb-update - Update the database schema.\n"
@printf "\tdb-backup-foo - Create a named backup 'foo' with data from the current database.\n"
@printf "\tdb-restore-foo - Restore schema and the data from a named backup 'foo' to an empty database.\n"
# #
# Internationalization rule, POT & PO file manipulation # Internationalization rule, POT & PO file manipulation
@@ -139,12 +140,27 @@ po-stats:
# make develop_zipfile # make develop_zipfile
# #
%-zipfile: %-zipfile:
@git archive --format=zip --prefix="indefero/" $(@:-zipfile=) \ @git archive --format=zip --prefix="indefero/" $* \
> indefero-$(@:-zipfile=)-`git log $(@:-zipfile=) -n 1 \ > indefero-$*-`git log $* -n 1 \
--pretty=format:%h`.zip --pretty=format:%h`.zip
%-tarfile:
@git archive --format=tar --prefix="indefero/" $* \
> indefero-$*-`git log $* -n 1 \
--pretty=format:%h`.tar
db-install: db-install:
@cd src && php "$(PLUF_PATH)/migrate.php" --conf=IDF/conf/idf.php -a -d -i @cd src && php "$(PLUF_PATH)/migrate.php" --conf=IDF/conf/idf.php -a -d -i
db-update: db-update:
@cd src && php "$(PLUF_PATH)/migrate.php" --conf=IDF/conf/idf.php -a -d @cd src && php "$(PLUF_PATH)/migrate.php" --conf=IDF/conf/idf.php -a -d
db-backup-%:
@[ -e backups ] || mkdir backups
@cd src && php "$(PLUF_PATH)/migrate.php" --conf=IDF/conf/idf.php -a -b ../backups $*
@echo Files for named backup $* have been saved into backups/ directory.
db-restore-%:
@cd src && php "$(PLUF_PATH)/migrate.php" --conf=IDF/conf/idf.php -a -r ../backups $*
@echo Files for named backup $* have been restored from the backups/ directory.

View File

@@ -1,4 +1,72 @@
# InDefero 1.3 - Sun Apr 15 21:10 2011 UTC # InDefero 1.4 - xxx xxx xx xx:xx 2012 UTC
## New Features
- Indefero can now record the due date of an issue and lets
you filter and search by overdue issues (fixes issue 584,
thanks to Simon Holywell!)
# InDefero 1.3.3 - Sun Nov 18 22:54:00 UTC 2012
**ATTENTION**: InDefero needs Pluf [a45dc195](http://projects.ceondo.com/p/pluf/source/commit/a45dc195)
or newer to run properly!
## Bugfixes
- A long standing bug in the Mercurial plugin that lead to corruption
of boolean configuration values in the `hgrc` of the served repository
has been fixed (issue 523).
- If an anonymous or authenticated user had no access to any project in a
forge, all projects were listed for him (but still no one was actually
accessible). This has been fixed.
- Fixed a problem where the SyncGit plugin doesn't properly updates the
authorized_keys file when the public key data contained slashes (thanks
to Simon Gareste for the fix!)
- Under PostgreSQL indefero could not be set up because of a circular
foreign key dependency. This has been fixed (issue 800).
- Under PostgreSQL new projects could not be created due to a failing
foreign key relation. Adding project tags was not possible for a similar
reason. This has been fixed (issue 800, continued).
- If a project was created based on the settings of an existing project,
not all settings, like for example the new notification settings, have
been copied. This has been changed insofar that now all properties except
the project's URL, logo and individual SCM settings are copied by default.
- Wiki pages couldn't be properly saved with E_NOTICE enabled because
of a syntax error (fixes issue 808).
- Indefero now shows detected copies in git changesets.
- A user is no longer redirected to the Help page if he enters 'H' in the
password text field on the login page (fixes issue 821).
# InDefero 1.3.2 - Wed May 09 20:05 2012 UTC
## Bugfixes
- Fix two bugs in the project list view if no project
is visible to the user or available in the forge (issue 805)
# InDefero 1.3.1 - Sun May 06 20:32 2012 UTC
## Bugfixes
- Compatiblity fixes for PostgreSQL (issue 800)
- Fix TOC generation in wiki (issue 803)
- Make the display of large files and diffs faster (issue 804)
- Make the project list faster and its tag list more accurate by not
counting projects that are invisible to the current user
## Language and Translations
- French translation updated (thanks to Jonathan Aillet!)
# InDefero 1.3 - Sun Apr 15 21:10 2012 UTC
This new major release of Indefero is possible thanks to the sponsor of This new major release of Indefero is possible thanks to the sponsor of
[Scilab Enterprises](http://www.scilab-enterprises.com/). [Scilab Enterprises](http://www.scilab-enterprises.com/).
@@ -34,7 +102,7 @@ or newer to properly run this version of Indefero!
emails for one object are uniquely identifyable to support a grouped view emails for one object are uniquely identifyable to support a grouped view
in email clients that support that. (fixes issues 334, 452, 480, and 791) in email clients that support that. (fixes issues 334, 452, 480, and 791)
- Indefero can now be configured to record activity metrics for all projects - Indefero can now be configured to record activity metrics for all projects
in a forge. This needs a special cron job named 'activitycron.php` in a forge. This needs a special cron job named `activitycron.php`
(under `scripts`) that is run on a regular basis. The metrics can be (under `scripts`) that is run on a regular basis. The metrics can be
fine-tuned via `activity_section_weights` and `activity_lookback` in fine-tuned via `activity_section_weights` and `activity_lookback` in
`idf.php` and the result is visible as green bar in the project list view. `idf.php` and the result is visible as green bar in the project list view.

View File

@@ -2,7 +2,7 @@
<?php <?php
$xmlfile = dirname(__FILE__) .'/test/report.xml'; $xmlfile = dirname(__FILE__) .'/test/report.xml';
passthru('phpunit --coverage-clover='.$xmlfile); passthru('phpunit --coverage-clover='.escapeshellarg($xmlfile));
$xml = simplexml_load_string(file_get_contents($xmlfile)); $xml = simplexml_load_string(file_get_contents($xmlfile));
unlink($xmlfile); unlink($xmlfile);
printf( printf(

View File

@@ -44,10 +44,15 @@ class IDF_ActivityTaxonomy
{ {
public static function recalculateTaxnomies(DateTime $date) public static function recalculateTaxnomies(DateTime $date)
{ {
$sectionWeights = Pluf::f('activity_section_weights', null);
$lookback = Pluf::f('activity_lookback', null);
if ($sectionWeights === null || $lookback === null) {
throw new LogicException('activity configuration is missing in idf.php');
}
// //
// query and normalize the section weights // query and normalize the section weights
// //
$sectionWeights = Pluf::f('activity_section_weights', array());
$allWeights = array_sum($sectionWeights); $allWeights = array_sum($sectionWeights);
if ($allWeights == 0) { if ($allWeights == 0) {
throw new LogicException('the sum of all "activity_section_weights" must not be 0'); throw new LogicException('the sum of all "activity_section_weights" must not be 0');
@@ -59,7 +64,6 @@ class IDF_ActivityTaxonomy
// //
// determine the date boundaries // determine the date boundaries
// //
$lookback = Pluf::f('activity_lookback', 0);
if ($lookback < 1) { if ($lookback < 1) {
throw new LogicException('lookback must be greater or equal to 1'); throw new LogicException('lookback must be greater or equal to 1');
} }
@@ -141,7 +145,12 @@ class IDF_ActivityTaxonomy
$cache[$argIdent] = 0; $cache[$argIdent] = 0;
list($higher, $lower) = $dateBoundaries; list($higher, $lower) = $dateBoundaries;
$sql = new Pluf_SQL('model_class IN ("'.implode('","', $classes).'") '. $db = Pluf::db();
$classes_esc = array();
foreach ($classes as $class) {
$classes_esc[] = $db->esc($class);
}
$sql = new Pluf_SQL('model_class IN ('.implode(',', $classes_esc).') '.
'AND creation_dtime >= %s AND creation_dtime <= %s', 'AND creation_dtime >= %s AND creation_dtime <= %s',
array($lower, $higher)); array($lower, $higher));

View File

@@ -44,9 +44,9 @@ class IDF_Conf extends Pluf_Model
array( array(
'type' => 'Pluf_DB_Field_Sequence', 'type' => 'Pluf_DB_Field_Sequence',
//It is automatically added. //It is automatically added.
'blank' => true, 'blank' => true,
), ),
'project' => 'project' =>
array( array(
'type' => 'Pluf_DB_Field_Foreignkey', 'type' => 'Pluf_DB_Field_Foreignkey',
'model' => 'IDF_Project', 'model' => 'IDF_Project',
@@ -84,7 +84,7 @@ class IDF_Conf extends Pluf_Model
function initCache() function initCache()
{ {
$this->datacache = new ArrayObject(); $this->datacache = array();
$sql = new Pluf_SQL('project=%s', $this->_project->id); $sql = new Pluf_SQL('project=%s', $this->_project->id);
foreach ($this->getList(array('filter' => $sql->gen())) as $val) { foreach ($this->getList(array('filter' => $sql->gen())) as $val) {
$this->datacache[$val->vkey] = $val->vdesc; $this->datacache[$val->vkey] = $val->vdesc;
@@ -97,7 +97,7 @@ class IDF_Conf extends Pluf_Model
*/ */
function setVal($key, $value) function setVal($key, $value)
{ {
if (!is_null($this->getVal($key, null)) if (!is_null($this->getVal($key, null))
and $value == $this->getVal($key)) { and $value == $this->getVal($key)) {
return; return;
} }
@@ -129,4 +129,12 @@ class IDF_Conf extends Pluf_Model
$this->initCache(); $this->initCache();
} }
} }
function getKeys()
{
if ($this->datacache === null) {
$this->initCache();
}
return array_keys($this->datacache);
}
} }

View File

@@ -147,7 +147,7 @@ class IDF_FileUtil
* Splits a string into separate lines while retaining the individual * Splits a string into separate lines while retaining the individual
* line ending character for every line. * line ending character for every line.
* *
* OS9 line endings are not supported. * OS 9 line endings are not supported.
* *
* @param string content * @param string content
* @param boolean if true, skip completely empty lines * @param boolean if true, skip completely empty lines
@@ -155,19 +155,16 @@ class IDF_FileUtil
*/ */
public static function splitIntoLines($content, $skipEmpty = false) public static function splitIntoLines($content, $skipEmpty = false)
{ {
$flags = PREG_SPLIT_OFFSET_CAPTURE; $last_off = 0;
if ($skipEmpty) $flags |= PREG_SPLIT_NO_EMPTY;
$splitted = preg_split("/\r\n|\n/", $content, -1, $flags);
$last_off = -1;
$lines = array(); $lines = array();
while (($split = array_shift($splitted)) !== null) { while (preg_match("/\r\n|\n/", $content, $m, PREG_OFFSET_CAPTURE, $last_off)) {
if ($last_off != -1) { $next_off = strlen($m[0][0]) + $m[0][1];
$lines[] .= substr($content, $last_off, $split[1] - $last_off); $line = substr($content, $last_off, $next_off - $last_off);
} $last_off = $next_off;
$last_off = $split[1]; if ($line !== $m[0][0] || !$skipEmpty) $lines[] = $line;
} }
$lines[] = substr($content, $last_off); $line = substr($content, $last_off);
if ($line !== false && strlen($line) > 0) $lines[] = $line;
return $lines; return $lines;
} }

View File

@@ -52,31 +52,6 @@ class IDF_Forge
$this->conf->setVal('project_labels', $labels); $this->conf->setVal('project_labels', $labels);
} }
public function getProjectLabelsWithCounts() {
$sql = new Pluf_SQL('project=0');
$tagList = Pluf::factory('IDF_Tag')->getList(array(
'filter' => $sql->gen(),
'view' => 'join_projects',
'order' => 'class ASC, lcname ASC'
));
$maxProjectCount = 0;
foreach ($tagList as $tag) {
$maxProjectCount = max($maxProjectCount, $tag->project_count);
}
$tags = array();
foreach ($tagList as $tag) {
// group by class
if (!array_key_exists($tag->class, $tags)) {
$tags[$tag->class] = array();
}
$tag->rel_project_count = $tag->project_count / (double) $maxProjectCount;
$tags[$tag->class][] = $tag;
}
return $tags;
}
public function setCustomForgePageEnabled($enabled) { public function setCustomForgePageEnabled($enabled) {
$this->conf->setVal('custom_forge_page_enabled', $enabled); $this->conf->setVal('custom_forge_page_enabled', $enabled);
} }
@@ -92,4 +67,4 @@ class IDF_Forge
public function setCustomForgePageContent($content) { public function setCustomForgePageContent($content) {
$this->conf->setVal('custom_forge_page_content', $content); $this->conf->setVal('custom_forge_page_content', $content);
} }
} }

View File

@@ -360,45 +360,35 @@ class IDF_Form_Admin_ProjectCreate extends Pluf_Form
$conf = new IDF_Conf(); $conf = new IDF_Conf();
$conf->setProject($project); $conf->setProject($project);
$keys = array('scm', 'svn_remote_url', 'svn_username',
'svn_password', 'mtn_master_branch', 'external_project_url');
foreach ($keys as $key) {
$this->cleaned_data[$key] = (!empty($this->cleaned_data[$key])) ?
$this->cleaned_data[$key] : '';
$conf->setVal($key, $this->cleaned_data[$key]);
}
if ($this->cleaned_data['template'] != '--') { if ($this->cleaned_data['template'] != '--') {
$tmplconf = new IDF_Conf(); $tmplconf = new IDF_Conf();
$tmplconf->setProject($tmpl); $tmplconf->setProject($tmpl);
// We need to get all the configuration variables we want from
// the old project and put them into the new project. $allKeys = $tmplconf->getKeys();
$props = array( $scm = $this->cleaned_data['scm'];
'labels_download_predefined' => IDF_Form_UploadConf::init_predefined, $ignoreKeys = array('scm', 'external_project_url', 'logo');
'labels_download_one_max' => IDF_Form_UploadConf::init_one_max,
'labels_wiki_predefined' => IDF_Form_WikiConf::init_predefined, // copy over all existing variables, except scm-related data and
'labels_wiki_one_max' => IDF_Form_WikiConf::init_one_max, // the project url / logo
'labels_issue_template' => IDF_Form_IssueTrackingConf::init_template, foreach ($allKeys as $key) {
'labels_issue_open' => IDF_Form_IssueTrackingConf::init_open, if (in_array($key, $ignoreKeys) || strpos($key, $scm.'_') === 0) {
'labels_issue_closed' => IDF_Form_IssueTrackingConf::init_closed, continue;
'labels_issue_predefined' => IDF_Form_IssueTrackingConf::init_predefined, }
'labels_issue_one_max' => IDF_Form_IssueTrackingConf::init_one_max, $conf->setVal($key, $tmplconf->getVal($key));
'issue_relations' => IDF_Form_IssueTrackingConf::init_relations,
'webhook_url' => '',
'downloads_access_rights' => 'all',
'review_access_rights' => 'all',
'wiki_access_rights' => 'all',
'source_access_rights' => 'all',
'issues_access_rights' => 'all',
'downloads_notification_email' => '',
'review_notification_email' => '',
'wiki_notification_email' => '',
'source_notification_email' => '',
'issues_notification_email' => '',
);
foreach ($props as $prop => $def) {
$conf->setVal($prop, $tmplconf->getVal($prop, $def));
} }
} }
$keys = array(
'scm', 'svn_remote_url', 'svn_username',
'svn_password', 'mtn_master_branch',
'external_project_url'
);
foreach ($keys as $key) {
$this->cleaned_data[$key] = !empty($this->cleaned_data[$key]) ?
$this->cleaned_data[$key] : '';
$conf->setVal($key, $this->cleaned_data[$key]);
}
$project->created(); $project->created();
if ($this->cleaned_data['template'] == '--') { if ($this->cleaned_data['template'] == '--') {

View File

@@ -112,6 +112,12 @@ class IDF_Form_IssueCreate extends Pluf_Form
'size' => 15, 'size' => 15,
), ),
)); ));
$this->fields['due_dtime'] = new Pluf_Form_Field_Date(
array('required' => false,
'label' => __('Due date'),
'initial' => '',
'widget_attrs' => array('size' => 15,),
));
$this->fields['relation_type0'] = new Pluf_Form_Field_Varchar( $this->fields['relation_type0'] = new Pluf_Form_Field_Varchar(
array('required' => false, array('required' => false,
@@ -368,6 +374,7 @@ class IDF_Form_IssueCreate extends Pluf_Form
$issue->status = new IDF_Tag($_t[0]); // first one is the default $issue->status = new IDF_Tag($_t[0]); // first one is the default
$issue->owner = null; $issue->owner = null;
} }
$issue->due_dtime = $this->cleaned_data['due_dtime'];
$issue->summary = trim($this->cleaned_data['summary']); $issue->summary = trim($this->cleaned_data['summary']);
$issue->create(); $issue->create();
foreach ($tags as $tag) { foreach ($tags as $tag) {

View File

@@ -103,6 +103,13 @@ class IDF_Form_IssueUpdate extends IDF_Form_IssueCreate
'size' => 15, 'size' => 15,
), ),
)); ));
$due_dtime = substr($this->issue->due_dtime, 0, 10);
$this->fields['due_dtime'] = new Pluf_Form_Field_Date(
array('required' => false,
'label' => __('Due date'),
'initial' => $due_dtime,
'widget_attrs' => array('size' => 15,),
));
$idx = 0; $idx = 0;
// note: clean_relation_type0 and clean_relation_issue0 already // note: clean_relation_type0 and clean_relation_issue0 already
@@ -266,6 +273,9 @@ class IDF_Form_IssueUpdate extends IDF_Form_IssueCreate
or ((!is_null($owner) and !is_null($this->issue->get_owner())) and $owner->id != $this->issue->get_owner()->id)) { or ((!is_null($owner) and !is_null($this->issue->get_owner())) and $owner->id != $this->issue->get_owner()->id)) {
return $this->cleaned_data; return $this->cleaned_data;
} }
if (trim($this->issue->due_dtime) != trim($this->cleaned_data['due_dtime'])) {
return $this->cleaned_data;
}
$tags = array(); $tags = array();
for ($i=1;$i<7;$i++) { for ($i=1;$i<7;$i++) {
if (strlen($this->cleaned_data['label'.$i]) > 0) { if (strlen($this->cleaned_data['label'.$i]) > 0) {
@@ -385,6 +395,9 @@ class IDF_Form_IssueUpdate extends IDF_Form_IssueCreate
or ((!is_null($owner) and !is_null($this->issue->get_owner())) and $owner->id != $this->issue->get_owner()->id)) { or ((!is_null($owner) and !is_null($this->issue->get_owner())) and $owner->id != $this->issue->get_owner()->id)) {
$changes['ow'] = (is_null($owner)) ? '---' : $owner->login; $changes['ow'] = (is_null($owner)) ? '---' : $owner->login;
} }
if (trim($this->issue->due_dtime) != trim($this->cleaned_data['due_dtime'])) {
$changes['du'] = Pluf_Template_dateFormat($this->cleaned_data['due_dtime']);
}
// Issue relations - additions // Issue relations - additions
foreach ($this->cleaned_data['_added_issue_relations'] as $verb => $ids) { foreach ($this->cleaned_data['_added_issue_relations'] as $verb => $ids) {
$other_verb = $this->relation_types[$verb]; $other_verb = $this->relation_types[$verb];
@@ -431,6 +444,7 @@ class IDF_Form_IssueUpdate extends IDF_Form_IssueCreate
$this->issue->summary = trim($this->cleaned_data['summary']); $this->issue->summary = trim($this->cleaned_data['summary']);
$this->issue->status = $status; $this->issue->status = $status;
$this->issue->owner = $owner; $this->issue->owner = $owner;
$this->issue->due_dtime = $this->cleaned_data['due_dtime'];
} }
// Create the comment // Create the comment
$comment = new IDF_IssueComment(); $comment = new IDF_IssueComment();

View File

@@ -91,6 +91,13 @@ class IDF_Issue extends Pluf_Model
'model' => 'IDF_Tag', 'model' => 'IDF_Tag',
'verbose' => __('labels'), 'verbose' => __('labels'),
), ),
'due_dtime' =>
array(
'type' => 'Pluf_DB_Field_Datetime',
'blank' => true,
'is_null' => true,
'verbose' => __('due date'),
),
'status' => 'status' =>
array( array(
'type' => 'Pluf_DB_Field_Foreignkey', 'type' => 'Pluf_DB_Field_Foreignkey',
@@ -149,11 +156,28 @@ class IDF_Issue extends Pluf_Model
IDF_Search::remove($this); IDF_Search::remove($this);
} }
function restore()
{
// Note: If a due date has not been set then it should
// be set to null and not a useless/confusing date so...
if ('0000-00-00 00:00:00' === $this->due_dtime) {
$this->due_dtime = null;
}
}
function preSave($create=false) function preSave($create=false)
{ {
if ($this->id == '') { if ($this->id == '') {
$this->creation_dtime = gmdate('Y-m-d H:i:s'); $this->creation_dtime = gmdate('Y-m-d H:i:s');
} }
// Note: If a due date is supplied then it must have
// a time appended to it so that calculations of when
// an issue falls overdue are accurate. In this case
// 23:59:59 is added to signify the end of the day.
if ($this->due_dtime and !empty($this->due_dtime)) {
$this->due_dtime = date('Y-m-d 23:59:59',
strtotime($this->due_dtime));
}
$this->modif_dtime = gmdate('Y-m-d H:i:s'); $this->modif_dtime = gmdate('Y-m-d H:i:s');
} }

View File

@@ -153,6 +153,8 @@ class IDF_IssueComment extends Pluf_Model
$out .= __('Status:'); break; $out .= __('Status:'); break;
case 'ow': case 'ow':
$out .= __('Owner:'); break; $out .= __('Owner:'); break;
case 'du':
$out .= __('Due date:'); break;
case 'lb': case 'lb':
$out .= __('Labels:'); break; $out .= __('Labels:'); break;
case 'rel': case 'rel':

View File

@@ -0,0 +1,47 @@
<?php
/* -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
# ***** BEGIN LICENSE BLOCK *****
# This file is part of InDefero, an open source project management application.
# Copyright (C) 2008-2011 Céondo Ltd and contributors.
#
# InDefero is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# InDefero is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
# ***** END LICENSE BLOCK ***** */
function IDF_Migrations_25NullableProjectInTag_up($params=null)
{
$engine = Pluf::f('db_engine');
$db = Pluf::db();
if ($engine === 'PostgreSQL') {
$db->execute('ALTER TABLE '.$db->pfx.'idf_tags ALTER COLUMN project DROP NOT NULL');
} else if ($engine === 'MySQL') {
$db->execute('ALTER TABLE '.$db->pfx.'idf_tags MODIFY project MEDIUMINT NULL');
// this is only needed for non-transactional setups where MySQL set 0 as default value
$db->execute('UPDATE '.$db->pfx.'idf_tags SET project=NULL WHERE project=0');
}
}
function IDF_Migrations_25NullableProjectInTag_down($params=null)
{
$engine = Pluf::f('db_engine');
$db = Pluf::db();
if ($engine === 'PostgreSQL') {
$db->execute('ALTER TABLE '.$db->pfx.'idf_tags ALTER COLUMN project SET NOT NULL');
} else if ($engine === 'MySQL') {
$db->execute('ALTER TABLE '.$db->pfx.'idf_tags MODIFY project MEDIUMINT NOT NULL');
}
}

View File

@@ -0,0 +1,46 @@
<?php
/* -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
# ***** BEGIN LICENSE BLOCK *****
# This file is part of InDefero, an open source project management application.
# Copyright (C) 2008-2012 Céondo Ltd and contributors.
#
# InDefero is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# InDefero is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
# ***** END LICENSE BLOCK ***** */
function IDF_Migrations_26NullableActivityInProject_up($params=null)
{
$engine = Pluf::f('db_engine');
$db = Pluf::db();
if ($engine === 'PostgreSQL') {
$db->execute('ALTER TABLE '.$db->pfx.'idf_projects ALTER COLUMN current_activity DROP NOT NULL');
} else if ($engine === 'MySQL') {
$db->execute('ALTER TABLE '.$db->pfx.'idf_projects MODIFY current_activity MEDIUMINT NULL');
// this is only needed for non-transactional setups where MySQL set 0 as default value
$db->execute('UPDATE '.$db->pfx.'idf_projects SET current_activity=NULL WHERE current_activity=0');
}
}
function IDF_Migrations_26NullableActivityInProject_down($params=null)
{
$engine = Pluf::f('db_engine');
$db = Pluf::db();
if ($engine === 'PostgreSQL') {
$db->execute('ALTER TABLE '.$db->pfx.'idf_projects ALTER COLUMN current_activity SET NOT NULL');
} else if ($engine === 'MySQL') {
$db->execute('ALTER TABLE '.$db->pfx.'idf_projects MODIFY current_activity MEDIUMINT NOT NULL');
}
}

View File

@@ -0,0 +1,55 @@
<?php
/* -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
# ***** BEGIN LICENSE BLOCK *****
# This file is part of InDefero, an open source project management application.
# Copyright (C) 2008-2011 Céondo Ltd and contributors.
#
# InDefero is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# InDefero is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
# ***** END LICENSE BLOCK ***** */
/**
* Add the private column for the project.
*/
function IDF_Migrations_27IssueDueDate_up($params=null)
{
$table = Pluf::factory('IDF_Issue')->getSqlTable();
$sql = array();
$sql['PostgreSQL'] = 'ALTER TABLE '.$table.' ADD COLUMN "due_dtime" TIMESTAMP';
$sql['MySQL'] = 'ALTER TABLE '.$table.' ADD COLUMN `due_dtime` DATETIME';
$db = Pluf::db();
$engine = Pluf::f('db_engine');
if (!isset($sql[$engine])) {
throw new Exception('SQLite complex migration not supported.');
}
$db->execute($sql[$engine]);
}
function IDF_Migrations_27IssueDueDate_down($params=null)
{
$table = Pluf::factory('IDF_Issue')->getSqlTable();
$sql = array();
$sql['PostgreSQL'] = 'ALTER TABLE '.$table.' DROP COLUMN "due_dtime"';
$sql['MySQL'] = 'ALTER TABLE '.$table.' DROP COLUMN `due_dtime`';
$db = Pluf::db();
$engine = Pluf::f('db_engine');
if (!isset($sql[$engine])) {
throw new Exception('SQLite complex migration not supported.');
}
$db->execute($sql[$engine]);
}

View File

@@ -119,5 +119,9 @@ function IDF_Migrations_Backup_restore($folder, $name)
foreach ($full_data as $model => $data) { foreach ($full_data as $model => $data) {
Pluf_Test_Fixture::load($data, false); Pluf_Test_Fixture::load($data, false);
} }
foreach ($models as $model) {
$schema->model = new $model();
$schema->createConstraints();
}
return true; return true;
} }

View File

@@ -62,6 +62,10 @@ function IDF_Migrations_Install_setup($params=null)
$schema->model = new $model(); $schema->model = new $model();
$schema->createTables(); $schema->createTables();
} }
foreach ($models as $model) {
$schema->model = new $model();
$schema->createConstraints();
}
// Install the permissions // Install the permissions
$perm = new Pluf_Permission(); $perm = new Pluf_Permission();
$perm->name = 'Project membership'; $perm->name = 'Project membership';
@@ -120,6 +124,10 @@ function IDF_Migrations_Install_teardown($params=null)
); );
$db = Pluf::db(); $db = Pluf::db();
$schema = new Pluf_DB_Schema($db); $schema = new Pluf_DB_Schema($db);
foreach ($models as $model) {
$schema->model = new $model();
$schema->dropConstraints();
}
foreach ($models as $model) { foreach ($models as $model) {
$schema->model = new $model(); $schema->model = new $model();
$schema->dropTables(); $schema->dropTables();

View File

@@ -64,7 +64,7 @@ class IDF_Plugin_SyncGit_Cron
// We update only the part of the file between IDF_START / IDF_END comment // We update only the part of the file between IDF_START / IDF_END comment
$original_keys = file_get_contents($authorized_keys); $original_keys = file_get_contents($authorized_keys);
if (strstr($original_keys, "# indefero start") && strstr($original_keys, "# indefero end")) { if (strstr($original_keys, "# indefero start") && strstr($original_keys, "# indefero end")) {
$out = preg_replace('/(#\sindefero\sstart).+(#\sindefero\send\s\s?)/isU', $out = preg_replace('%(#\sindefero\sstart).+(#\sindefero\send\s\s?)%isU',
$out, $original_keys); $out, $original_keys);
} else { } else {
$out .= $original_keys; $out .= $original_keys;

View File

@@ -178,7 +178,10 @@ class IDF_Plugin_SyncMercurial
// Generate hgrc content // Generate hgrc content
if (is_file($hgrc_file)) { if (is_file($hgrc_file)) {
$tmp_content = parse_ini_file($hgrc_file, true); $tmp_content = @parse_ini_file($hgrc_file, true, INI_SCANNER_RAW);
if ($tmp_content === false) {
throw new Exception('could not parse "'.$hgrc_file.'" because of syntax problems');
}
$tmp_content['web']['allow_push'] = $allow_push; $tmp_content['web']['allow_push'] = $allow_push;
} }
else { else {

View File

@@ -105,6 +105,8 @@ class IDF_Project extends Pluf_Model
'type' => 'Pluf_DB_Field_Foreignkey', 'type' => 'Pluf_DB_Field_Foreignkey',
'model' => 'IDF_ProjectActivity', 'model' => 'IDF_ProjectActivity',
'blank' => true, 'blank' => true,
'is_null' => true,
'default' => null,
'verbose' => __('current project activity'), 'verbose' => __('current project activity'),
), ),
); );
@@ -115,8 +117,7 @@ class IDF_Project extends Pluf_Model
array( array(
'join' => 'LEFT JOIN '.$activityTable.' ON current_activity='.$activityTable.'.id ' 'join' => 'LEFT JOIN '.$activityTable.' ON current_activity='.$activityTable.'.id '
.'LEFT JOIN '.$tagTable.' ON idf_project_id='.$this->getSqlTable().'.id', .'LEFT JOIN '.$tagTable.' ON idf_project_id='.$this->getSqlTable().'.id',
'select' => $this->getSelect().', date, value', 'select' => 'DISTINCT '.$this->getSelect().', date, value',
'group' => $this->getSqlTable().'.id',
'props' => array( 'props' => array(
'date' => 'current_activity_date', 'date' => 'current_activity_date',
'value' => 'current_activity_value' 'value' => 'current_activity_value'
@@ -202,6 +203,39 @@ GROUP BY uid";
return $ownerStatistics; return $ownerStatistics;
} }
/**
* Returns the number of overdue issues.
*
* @return int Count
*/
public function getIssueCountByDueDate($due='overdue', $label=null, $ids=array())
{
$tags = array();
foreach ($this->getTagsFromConfig('labels_issue_open', IDF_Form_IssueTrackingConf::init_open, 'Status') as $tag) {
$tags[] = (int)$tag->id;
}
if (count($tags) == 0) return array();
$sql = new Pluf_SQL(sprintf('project=%%s AND status IN (%s)', implode(', ', $tags)), array($this->id));
if (!is_null($label)) {
$sql2 = new Pluf_SQL('idf_tag_id=%s', array($label->id));
$sql->SAnd($sql2);
}
if (count($ids) > 0) {
$sql2 = new Pluf_SQL(sprintf('id IN (%s)', implode(', ', $ids)));
$sql->SAnd($sql2);
}
if('overdue' === $due) {
$sql3 = new Pluf_SQL('due_dtime < NOW()');
} else {
$sql3 = new Pluf_SQL('due_dtime >= NOW()');
}
$sql->SAnd($sql3);
$params = array('filter' => $sql->gen());
if (!is_null($label)) { $params['view'] = 'join_tags'; }
$gissue = new IDF_Issue();
return $gissue->getCount($params);
}
/** /**
* Returns the number of open/closed issues. * Returns the number of open/closed issues.
* *

View File

@@ -52,11 +52,11 @@ class IDF_Scm_Git extends IDF_Scm
* A doc/Guide utilisateur/images/ftp-nautilus.png * A doc/Guide utilisateur/images/ftp-nautilus.png
* M doc/Guide utilisateur/textes/log_boot_PEGASE.txt * M doc/Guide utilisateur/textes/log_boot_PEGASE.txt
* *
* Status letters mean : Added (A), Deleted (D), Modified (M), Renamed (R) * Status letters mean : Added (A), Copied (C), Deleted (D), Modified (M), Renamed (R)
*/ */
public function getChanges($commit) public function getChanges($commit)
{ {
$cmd = sprintf('GIT_DIR=%s '.Pluf::f('git_path', 'git').' show %s --name-status --pretty="format:" --diff-filter="[A|D|M|R]" -M', $cmd = sprintf('GIT_DIR=%s '.Pluf::f('git_path', 'git').' show %s --name-status --pretty="format:" --diff-filter="[A|C|D|M|R]" -C -C',
escapeshellarg($this->repo), escapeshellarg($this->repo),
escapeshellarg($commit)); escapeshellarg($commit));
$out = array(); $out = array();
@@ -89,6 +89,9 @@ class IDF_Scm_Git extends IDF_Scm
} else if ($action == 'R') { } else if ($action == 'R') {
$matches = preg_split("/\t/", $line); $matches = preg_split("/\t/", $line);
$return->renames[$matches[1]] = $matches[2]; $return->renames[$matches[1]] = $matches[2];
} else if ($action == 'C') {
$matches = preg_split("/\t/", $line);
$return->copies[$matches[1]] = $matches[2];
} }
} }
} }

View File

@@ -48,7 +48,9 @@ class IDF_Tag extends Pluf_Model
array( array(
'type' => 'Pluf_DB_Field_Foreignkey', 'type' => 'Pluf_DB_Field_Foreignkey',
'model' => 'IDF_Project', 'model' => 'IDF_Project',
'blank' => false, 'blank' => true,
'is_null' => true,
'default' => null,
'verbose' => __('project'), 'verbose' => __('project'),
), ),
'class' => 'class' =>
@@ -76,13 +78,14 @@ class IDF_Tag extends Pluf_Model
); );
$table = $this->_con->pfx.'idf_project_idf_tag_assoc'; $table = $this->_con->pfx.'idf_project_idf_tag_assoc';
$cols = implode(', ', array_keys($this->_a['cols']));
$this->_a['views'] = array( $this->_a['views'] = array(
'join_projects' => 'join_projects' =>
array( array(
'join' => 'LEFT JOIN '.$table 'join' => 'LEFT JOIN '.$table
.' ON idf_tag_id=id', .' ON idf_tag_id=id',
'select' => $this->getSelect().',COUNT(idf_project_id) as project_count', 'select' => $this->getSelect().',COUNT(idf_project_id) as project_count',
'group' => 'idf_tag_id', 'group' => $cols,
'props' => array('project_count' => 'project_count'), 'props' => array('project_count' => 'project_count'),
), ),
); );
@@ -146,7 +149,7 @@ class IDF_Tag extends Pluf_Model
$class = trim($class); $class = trim($class);
$name = trim($name); $name = trim($name);
$gtag = new IDF_Tag(); $gtag = new IDF_Tag();
$sql = new Pluf_SQL('class=%s AND lcname=%s AND project=0', $sql = new Pluf_SQL('class=%s AND lcname=%s AND project IS NULL',
array($class, mb_strtolower($name))); array($class, mb_strtolower($name)));
$tags = $gtag->getList(array('filter' => $sql->gen())); $tags = $gtag->getList(array('filter' => $sql->gen()));
if ($tags->count() < 1) { if ($tags->count() < 1) {
@@ -154,6 +157,7 @@ class IDF_Tag extends Pluf_Model
$tag = new IDF_Tag(); $tag = new IDF_Tag();
$tag->name = $name; $tag->name = $name;
$tag->class = $class; $tag->class = $class;
$tag->project = null;
$tag->create(); $tag->create();
return $tag; return $tag;
} }

View File

@@ -83,7 +83,7 @@ class IDF_Template_MarkdownForge extends Pluf_Template_Tag
$name = $class; $name = $class;
$class = IDF_TAG_DEFAULT_CLASS; $class = IDF_TAG_DEFAULT_CLASS;
} }
$sql = new Pluf_SQL('class=%s AND lcname=%s AND project=0', $sql = new Pluf_SQL('class=%s AND lcname=%s AND project IS NULL',
array(strtolower($class), mb_strtolower($name))); array(strtolower($class), mb_strtolower($name)));
$tag = Pluf::factory('IDF_Tag')->getOne(array('filter' => $sql->gen())); $tag = Pluf::factory('IDF_Tag')->getOne(array('filter' => $sql->gen()));
} }

View File

@@ -85,7 +85,7 @@ class IDF_Views
$projects = self::getProjects($request->user, $tag, $order); $projects = self::getProjects($request->user, $tag, $order);
$stats = self::getProjectsStatistics($projects); $stats = self::getProjectsStatistics($projects);
$projectLabels = IDF_Forge::instance()->getProjectLabelsWithCounts(); $projectLabels = self::getProjectLabelsWithCounts($request->user);
return Pluf_Shortcuts_RenderToResponse('idf/listProjects.html', return Pluf_Shortcuts_RenderToResponse('idf/listProjects.html',
array('page_title' => __('Projects'), array('page_title' => __('Projects'),
@@ -371,6 +371,62 @@ class IDF_Views
} }
/**
* Returns a list of ids of projects that are visible for the given user
*
* @param Pluf_User $user
*/
private static function getUserVisibleProjectIds($user)
{
$db =& Pluf::db();
// the administrator can see all projects
if ($user->administrator) {
$ids = array();
$sql_results = $db->select(
'SELECT id FROM '.Pluf::f('db_table_prefix', '').'idf_projects'
);
foreach ($sql_results as $id) {
$ids[] = $id['id'];
}
return $ids;
}
// anonymous users can only see non-private projects
$false = Pluf_DB_BooleanToDb(false, $db);
$sql_results = $db->select(
'SELECT id FROM '.$db->pfx.'idf_projects '.
'WHERE '.$db->qn('private').'='.$false
);
$ids = array();
foreach ($sql_results as $id) {
$ids[] = $id['id'];
}
// registered users may additionally see private projects with which
// they're somehow affiliated
if (!$user->isAnonymous()) {
$perms = array(
Pluf_Permission::getFromString('IDF.project-member'),
Pluf_Permission::getFromString('IDF.project-owner'),
Pluf_Permission::getFromString('IDF.project-authorized-user')
);
$permSql = new Pluf_SQL(
"model_class='IDF_Project' AND owner_class='Pluf_User' ".
"AND owner_id=%s AND negative=".$false, $user->id
);
$rows = Pluf::factory('Pluf_RowPermission')->getList(array('filter' => $permSql->gen()));
if ($rows->count() > 0) {
foreach ($rows as $row) {
if (in_array($row->model_id, $ids))
continue;
$ids[] = $row->model_id;
}
}
}
return $ids;
}
/** /**
* Returns a list of projects accessible for the user and optionally filtered by tag. * Returns a list of projects accessible for the user and optionally filtered by tag.
* *
@@ -381,39 +437,18 @@ class IDF_Views
public static function getProjects($user, $tag = false, $order = 'name') public static function getProjects($user, $tag = false, $order = 'name')
{ {
$db =& Pluf::db(); $db =& Pluf::db();
$false = Pluf_DB_BooleanToDb(false, $db); $sql = new Pluf_SQL('1=1');
$sql = new Pluf_SQL(1);
if ($tag !== false) { if ($tag !== false) {
$sql->SAnd(new Pluf_SQL('idf_tag_id=%s', $tag->id)); $sql->SAnd(new Pluf_SQL('idf_tag_id=%s', $tag->id));
} }
if ($user->isAnonymous()) $projectIds = self::getUserVisibleProjectIds($user);
{ if (count($projectIds) == 0) {
$authSql = new Pluf_SQL('private=%s', $false); return new ArrayObject();
$sql->SAnd($authSql);
} else
if (!$user->administrator) {
// grab the list of projects where the user is admin,
// member or authorized
$perms = array(
Pluf_Permission::getFromString('IDF.project-member'),
Pluf_Permission::getFromString('IDF.project-owner'),
Pluf_Permission::getFromString('IDF.project-authorized-user')
);
$permSql = new Pluf_SQL("model_class='IDF_Project' AND owner_class='Pluf_User' AND owner_id=%s AND negative=".$false, $user->id);
$rows = Pluf::factory('Pluf_RowPermission')->getList(array('filter' => $permSql->gen()));
$authSql = new Pluf_SQL('private=%s', $false);
if ($rows->count() > 0) {
$ids = array();
foreach ($rows as $row) {
$ids[] = $row->model_id;
}
$authSql->SOr(new Pluf_SQL(sprintf($db->pfx.'idf_projects.id IN (%s)', implode(', ', $ids))));
}
$sql->SAnd($authSql);
} }
$sql->SAnd(new Pluf_SQL(sprintf($db->pfx.'idf_projects.id IN (%s)', implode(', ', $projectIds))));
$orderTypes = array( $orderTypes = array(
'name' => 'name ASC', 'name' => 'name ASC',
'activity' => 'value DESC, name ASC', 'activity' => 'value DESC, name ASC',
@@ -425,6 +460,48 @@ class IDF_Views
)); ));
} }
/**
* Returns a list of global tags each carrying the number of projects that have the
* particular tag set
*
* @param Pluf_User $user
* @return array
*/
public static function getProjectLabelsWithCounts($user) {
$sql = new Pluf_SQL('project IS NULL');
$projectIds = self::getUserVisibleProjectIds($user);
if (count($projectIds) == 0) {
return new ArrayObject();
}
$sql->SAnd(new Pluf_SQL(sprintf('idf_project_id IN (%s)', implode(', ', $projectIds))));
$tagList = Pluf::factory('IDF_Tag')->getList(array(
'filter' => $sql->gen(),
'view' => 'join_projects',
'order' => 'class ASC, lcname ASC'
));
$maxProjectCount = 0;
foreach ($tagList as $tag) {
$maxProjectCount = max($maxProjectCount, $tag->project_count);
}
$tags = array();
foreach ($tagList as $tag) {
// group by class
if (!array_key_exists($tag->class, $tags)) {
$tags[$tag->class] = array();
}
$tag->rel_project_count = $tag->project_count / (double) $maxProjectCount;
$tags[$tag->class][] = $tag;
}
return $tags;
}
/** /**
* Returns statistics on a list of projects. * Returns statistics on a list of projects.
* *
@@ -433,27 +510,30 @@ class IDF_Views
*/ */
public static function getProjectsStatistics($projects) public static function getProjectsStatistics($projects)
{ {
// Init the return var $projectIds = array(0);
$forgestats = array('downloads' => 0, foreach ($projects as $project) {
'reviews' => 0, $projectIds[] = $project->id;
'issues' => 0,
'docpages' => 0,
'commits' => 0);
// Count for each projects
foreach ($projects as $p) {
$pstats = $p->getStats();
$forgestats['downloads'] += $pstats['downloads'];
$forgestats['reviews'] += $pstats['reviews'];
$forgestats['issues'] += $pstats['issues'];
$forgestats['docpages'] += $pstats['docpages'];
$forgestats['commits'] += $pstats['commits'];
} }
// Count members $forgestats = array();
$sql = new Pluf_SQL('first_name != %s', array('---'));
$forgestats['members'] = Pluf::factory('Pluf_User') // count overall project stats
->getCount(array('filter' => $sql->gen())); $forgestats['total'] = 0;
$what = array(
'downloads' => 'IDF_Upload',
'reviews' => 'IDF_Review',
'issues' => 'IDF_Issue',
'docpages' => 'IDF_Wiki_Page',
'commits' => 'IDF_Commit',
);
foreach ($what as $key => $model) {
$count = Pluf::factory($model)->getCount(array(
'filter' => sprintf('project IN (%s)', implode(', ', $projectIds))
));
$forgestats[$key] = $count;
$forgestats['total'] += $count;
}
return $forgestats; return $forgestats;
} }

View File

@@ -42,6 +42,7 @@ class IDF_Views_Issue
// Get stats about the issues // Get stats about the issues
$open = $prj->getIssueCountByStatus('open'); $open = $prj->getIssueCountByStatus('open');
$closed = $prj->getIssueCountByStatus('closed'); $closed = $prj->getIssueCountByStatus('closed');
$overdue = $prj->getIssueCountByDueDate();
// Paginator to paginate the issues // Paginator to paginate the issues
$pag = new Pluf_Paginator(new IDF_Issue()); $pag = new Pluf_Paginator(new IDF_Issue());
$pag->class = 'recent-issues'; $pag->class = 'recent-issues';
@@ -61,9 +62,10 @@ class IDF_Views_Issue
'id' => __('Id'), 'id' => __('Id'),
array('summary', 'IDF_Views_Issue_SummaryAndLabels', __('Summary')), array('summary', 'IDF_Views_Issue_SummaryAndLabels', __('Summary')),
array('status', 'IDF_Views_Issue_ShowStatus', __('Status')), array('status', 'IDF_Views_Issue_ShowStatus', __('Status')),
array('due_dtime', 'IDF_Views_Issue_DueDate', __('Due Date')),
array('modif_dtime', 'Pluf_Paginator_DateAgo', __('Last Updated')), array('modif_dtime', 'Pluf_Paginator_DateAgo', __('Last Updated')),
); );
$pag->configure($list_display, array(), array('id', 'status', 'modif_dtime')); $pag->configure($list_display, array(), array('id', 'status', 'due_dtime', 'modif_dtime'));
$pag->items_per_page = 10; $pag->items_per_page = 10;
$pag->no_results_text = __('No issues were found.'); $pag->no_results_text = __('No issues were found.');
$pag->setFromRequest($request); $pag->setFromRequest($request);
@@ -71,6 +73,7 @@ class IDF_Views_Issue
'page_title' => $title, 'page_title' => $title,
'open' => $open, 'open' => $open,
'closed' => $closed, 'closed' => $closed,
'overdue' => $overdue,
'issues' => $pag, 'issues' => $pag,
'cloud' => 'issues', 'cloud' => 'issues',
); );
@@ -88,6 +91,7 @@ class IDF_Views_Issue
{ {
$tagStatistics = array(); $tagStatistics = array();
$ownerStatistics = array(); $ownerStatistics = array();
$duedateStatistics = array();
$status = array(); $status = array();
$isTrackerEmpty = false; $isTrackerEmpty = false;
@@ -121,6 +125,14 @@ class IDF_Views_Issue
} }
arsort($ownerStatistics); arsort($ownerStatistics);
// Issue due date statistics
$overdue = $prj->getIssueCountByDueDate();
$combined_opened = $overdue + $opened;
$duedateStatistics = array();
if ($combined_opened > 0) {
$duedateStatistics = array($overdue, (int)(100 * $overdue / $combined_opened));
}
// Issue class tag statistics // Issue class tag statistics
$grouped_tags = $prj->getTagCloud(); $grouped_tags = $prj->getTagCloud();
foreach ($grouped_tags as $class => $tags) { foreach ($grouped_tags as $class => $tags) {
@@ -154,6 +166,7 @@ class IDF_Views_Issue
'project' => $prj, 'project' => $prj,
'tagStatistics' => $tagStatistics, 'tagStatistics' => $tagStatistics,
'ownerStatistics' => $ownerStatistics, 'ownerStatistics' => $ownerStatistics,
'duedateStatistics' => $duedateStatistics,
'status' => $status, 'status' => $status,
), ),
$request); $request);
@@ -187,9 +200,16 @@ class IDF_Views_Issue
$nb_open = Pluf::factory('IDF_Issue')->getCount(array('filter'=>$sql->gen())); $nb_open = Pluf::factory('IDF_Issue')->getCount(array('filter'=>$sql->gen()));
$sql = new Pluf_SQL('project=%s AND id IN ('.$issue_ids.') AND status IN ('.implode(', ', $ctags).')', array($prj->id)); $sql = new Pluf_SQL('project=%s AND id IN ('.$issue_ids.') AND status IN ('.implode(', ', $ctags).')', array($prj->id));
$nb_closed = Pluf::factory('IDF_Issue')->getCount(array('filter'=>$sql->gen())); $nb_closed = Pluf::factory('IDF_Issue')->getCount(array('filter'=>$sql->gen()));
$sql = new Pluf_SQL('project=%s AND id IN ('.$issue_ids.') AND status IN ('.implode(', ', $otags).') AND due_dtime < NOW()', array($prj->id));
$nb_overdue = Pluf::factory('IDF_Issue')->getCount(array('filter'=>$sql->gen()));
// Generate a filter for the paginator // Generate a filter for the paginator
switch ($match[2]) { switch ($match[2]) {
case 'overdue':
$title = sprintf(__('Watch List: Overdue Issues for %s'), (string) $prj);
$summary = __('This table shows the overdue issues in your watch list for %s project.', (string) $prj);
$f_sql = new Pluf_SQL('project=%s AND id IN ('.$issue_ids.') AND status IN ('.implode(', ', $otags).') AND due_dtime < NOW()', array($prj->id));
break;
case 'closed': case 'closed':
$title = sprintf(__('Watch List: Closed Issues for %s'), (string) $prj); $title = sprintf(__('Watch List: Closed Issues for %s'), (string) $prj);
$summary = __('This table shows the closed issues in your watch list for %s project.', (string) $prj); $summary = __('This table shows the closed issues in your watch list for %s project.', (string) $prj);
@@ -220,9 +240,10 @@ class IDF_Views_Issue
'id' => __('Id'), 'id' => __('Id'),
array('summary', 'IDF_Views_Issue_SummaryAndLabels', __('Summary')), array('summary', 'IDF_Views_Issue_SummaryAndLabels', __('Summary')),
array('status', 'IDF_Views_Issue_ShowStatus', __('Status')), array('status', 'IDF_Views_Issue_ShowStatus', __('Status')),
array('due_dtime', 'IDF_Views_Issue_DueDate', __('Due Date')),
array('modif_dtime', 'Pluf_Paginator_DateAgo', __('Last Updated')), array('modif_dtime', 'Pluf_Paginator_DateAgo', __('Last Updated')),
); );
$pag->configure($list_display, array(), array('id', 'status', 'modif_dtime')); $pag->configure($list_display, array(), array('id', 'status', 'due_dtime', 'modif_dtime'));
$pag->items_per_page = 10; $pag->items_per_page = 10;
$pag->no_results_text = __('No issues were found.'); $pag->no_results_text = __('No issues were found.');
$pag->setFromRequest($request); $pag->setFromRequest($request);
@@ -231,6 +252,7 @@ class IDF_Views_Issue
'page_title' => $title, 'page_title' => $title,
'open' => $nb_open, 'open' => $nb_open,
'closed' => $nb_closed, 'closed' => $nb_closed,
'overdue' => $nb_overdue,
'issues' => $pag, 'issues' => $pag,
), ),
$request); $request);
@@ -270,9 +292,16 @@ class IDF_Views_Issue
$nb_open = Pluf::factory('IDF_Issue')->getCount(array('filter'=>$sql->gen())); $nb_open = Pluf::factory('IDF_Issue')->getCount(array('filter'=>$sql->gen()));
$sql = new Pluf_SQL('id IN ('.$issue_ids.') AND status IN ('.implode(', ', $ctags).')', array()); $sql = new Pluf_SQL('id IN ('.$issue_ids.') AND status IN ('.implode(', ', $ctags).')', array());
$nb_closed = Pluf::factory('IDF_Issue')->getCount(array('filter'=>$sql->gen())); $nb_closed = Pluf::factory('IDF_Issue')->getCount(array('filter'=>$sql->gen()));
$sql = new Pluf_SQL('id IN ('.$issue_ids.') AND status IN ('.implode(', ', $otags).') AND due_dtime < NOW()', array());
$nb_overdue = Pluf::factory('IDF_Issue')->getCount(array('filter'=>$sql->gen()));
// Generate a filter for the paginator // Generate a filter for the paginator
switch ($match[1]) { switch ($match[1]) {
case 'overdue':
$title = sprintf(__('Watch List: Overdue Issues'));
$summary = __('This table shows the overdue issues in your watch list.');
$f_sql = new Pluf_SQL('id IN ('.$issue_ids.') AND status IN ('.implode(', ', $otags).') AND due_dtime < NOW()', array());
break;
case 'closed': case 'closed':
$title = sprintf(__('Watch List: Closed Issues')); $title = sprintf(__('Watch List: Closed Issues'));
$summary = __('This table shows the closed issues in your watch list.'); $summary = __('This table shows the closed issues in your watch list.');
@@ -302,9 +331,10 @@ class IDF_Views_Issue
array('summary', 'IDF_Views_Issue_SummaryAndLabelsUnknownProject', __('Summary')), array('summary', 'IDF_Views_Issue_SummaryAndLabelsUnknownProject', __('Summary')),
array('project', 'Pluf_Paginator_FkToString', __('Project')), array('project', 'Pluf_Paginator_FkToString', __('Project')),
array('status', 'IDF_Views_Issue_ShowStatus', __('Status')), array('status', 'IDF_Views_Issue_ShowStatus', __('Status')),
array('due_dtime', 'IDF_Views_Issue_DueDate', __('Due Date')),
array('modif_dtime', 'Pluf_Paginator_DateAgo', __('Last Updated')), array('modif_dtime', 'Pluf_Paginator_DateAgo', __('Last Updated')),
); );
$pag->configure($list_display, array(), array('id', 'project', 'status', 'modif_dtime')); $pag->configure($list_display, array(), array('id', 'project', 'status', 'due_dtime', 'modif_dtime'));
$pag->items_per_page = 10; $pag->items_per_page = 10;
$pag->no_results_text = __('No issues were found.'); $pag->no_results_text = __('No issues were found.');
$pag->setFromRequest($request); $pag->setFromRequest($request);
@@ -312,6 +342,7 @@ class IDF_Views_Issue
array('page_title' => $title, array('page_title' => $title,
'open' => $nb_open, 'open' => $nb_open,
'closed' => $nb_closed, 'closed' => $nb_closed,
'overdue' => $nb_overdue,
'issues' => $pag, 'issues' => $pag,
), ),
$request); $request);
@@ -390,9 +421,10 @@ class IDF_Views_Issue
'id' => __('Id'), 'id' => __('Id'),
array('summary', 'IDF_Views_Issue_SummaryAndLabels', __('Summary')), array('summary', 'IDF_Views_Issue_SummaryAndLabels', __('Summary')),
array('status', 'IDF_Views_Issue_ShowStatus', __('Status')), array('status', 'IDF_Views_Issue_ShowStatus', __('Status')),
array('due_dtime', 'IDF_Views_Issue_DueDate', __('Due Date')),
array('modif_dtime', 'Pluf_Paginator_DateAgo', __('Last Updated')), array('modif_dtime', 'Pluf_Paginator_DateAgo', __('Last Updated')),
); );
$pag->configure($list_display, array(), array('id', 'status', 'modif_dtime')); $pag->configure($list_display, array(), array('id', 'status', 'due_dtime', 'modif_dtime'));
$pag->items_per_page = 10; $pag->items_per_page = 10;
$pag->no_results_text = __('No issues were found.'); $pag->no_results_text = __('No issues were found.');
$pag->setFromRequest($request); $pag->setFromRequest($request);
@@ -443,6 +475,7 @@ class IDF_Views_Issue
'preview' => $preview, 'preview' => $preview,
'issue' => new IDF_Issue(), 'issue' => new IDF_Issue(),
), ),
self::getDateShortcuts(),
self::autoCompleteArrays($prj) self::autoCompleteArrays($prj)
); );
if ($api == true) return $params; if ($api == true) return $params;
@@ -461,7 +494,7 @@ class IDF_Views_Issue
public function searchStatus($request, $match) public function searchStatus($request, $match)
{ {
$query = !isset($request->REQUEST['q']) ? '' : $request->REQUEST['q']; $query = !isset($request->REQUEST['q']) ? '' : $request->REQUEST['q'];
$status = in_array($match[2], array('open', 'closed')) ? $match[2] : 'open'; $status = in_array($match[2], array('open', 'closed', 'overdue')) ? $match[2] : 'open';
return $this->doSearch($request, $query, $status); return $this->doSearch($request, $query, $status);
} }
@@ -470,7 +503,7 @@ class IDF_Views_Issue
{ {
$query = !isset($request->REQUEST['q']) ? '' : $request->REQUEST['q']; $query = !isset($request->REQUEST['q']) ? '' : $request->REQUEST['q'];
$tag_id = intval($match[2]); $tag_id = intval($match[2]);
$status = in_array($match[3], array('open', 'closed')) ? $match[3] : 'open'; $status = in_array($match[3], array('open', 'closed', 'overdue')) ? $match[3] : 'open';
return $this->doSearch($request, $query, $status, $tag_id); return $this->doSearch($request, $query, $status, $tag_id);
} }
@@ -490,6 +523,10 @@ class IDF_Views_Issue
$title = sprintf(__('Search issues - %s'), $query); $title = sprintf(__('Search issues - %s'), $query);
if ($status === 'closed') { if ($status === 'closed') {
$title = sprintf(__('Search closed issues - %s'), $query); $title = sprintf(__('Search closed issues - %s'), $query);
} elseif ($status === 'overdue') {
$title = sprintf(__('Search overdue issues - %s'), $query);
$status = 'open';
$overdue_status = true;
} }
// using Plufs ResultSet implementation here is inefficient, because // using Plufs ResultSet implementation here is inefficient, because
@@ -510,6 +547,10 @@ class IDF_Views_Issue
'AND status IN ('.implode(', ', $otags).') '. 'AND status IN ('.implode(', ', $otags).') '.
($tag_id !== null ? 'AND idf_tag_id='.$tag_id.' ' : '') ($tag_id !== null ? 'AND idf_tag_id='.$tag_id.' ' : '')
); );
if (isset($overdue_status)) {
$sql2 = new Pluf_SQL('due_dtime < NOW()');
$sql->SAnd($sql2);
}
$model = new IDF_Issue(); $model = new IDF_Issue();
$issues = $model->getList(array('filter' => $sql->gen(), 'view' => 'join_tags')); $issues = $model->getList(array('filter' => $sql->gen(), 'view' => 'join_tags'));
@@ -542,6 +583,7 @@ class IDF_Views_Issue
'id' => __('Id'), 'id' => __('Id'),
array('summary', 'IDF_Views_Issue_SummaryAndLabels', __('Summary')), array('summary', 'IDF_Views_Issue_SummaryAndLabels', __('Summary')),
array('status', 'IDF_Views_Issue_ShowStatus', __('Status')), array('status', 'IDF_Views_Issue_ShowStatus', __('Status')),
array('due_dtime', 'IDF_Views_Issue_DueDate', __('Due Date')),
array('modif_dtime', 'Pluf_Paginator_DateAgo', __('Last Updated')), array('modif_dtime', 'Pluf_Paginator_DateAgo', __('Last Updated')),
)); ));
// disable paginating // disable paginating
@@ -562,6 +604,7 @@ class IDF_Views_Issue
} }
// get stats about the issues // get stats about the issues
$overdue = $prj->getIssueCountByDueDate('overdue', $tag, $issue_ids);
$open = $prj->getIssueCountByStatus('open', $tag, $issue_ids); $open = $prj->getIssueCountByStatus('open', $tag, $issue_ids);
$closed = $prj->getIssueCountByStatus('closed', $tag, $issue_ids); $closed = $prj->getIssueCountByStatus('closed', $tag, $issue_ids);
@@ -583,6 +626,7 @@ class IDF_Views_Issue
'status' => $status, 'status' => $status,
'open' => $open, 'open' => $open,
'closed' => $closed, 'closed' => $closed,
'overdue' => $overdue,
'tag' => $tag, 'tag' => $tag,
'all_tags' => $grouped_tags, 'all_tags' => $grouped_tags,
); );
@@ -669,6 +713,7 @@ class IDF_Views_Issue
'next_issue_id' => $next_issue_id, 'next_issue_id' => $next_issue_id,
'related_issues' => $related_issues, 'related_issues' => $related_issues,
), ),
self::getDateShortcuts(),
$arrays), $arrays),
$request); $request);
} }
@@ -746,6 +791,7 @@ class IDF_Views_Issue
// Get stats about the issues // Get stats about the issues
$open = $prj->getIssueCountByStatus('open'); $open = $prj->getIssueCountByStatus('open');
$closed = $prj->getIssueCountByStatus('closed'); $closed = $prj->getIssueCountByStatus('closed');
$overdue = $prj->getIssueCountByDueDate();
// Paginator to paginate the issues // Paginator to paginate the issues
$pag = new Pluf_Paginator(new IDF_Issue()); $pag = new Pluf_Paginator(new IDF_Issue());
$pag->class = 'recent-issues'; $pag->class = 'recent-issues';
@@ -765,9 +811,10 @@ class IDF_Views_Issue
'id' => __('Id'), 'id' => __('Id'),
array('summary', 'IDF_Views_Issue_SummaryAndLabels', __('Summary')), array('summary', 'IDF_Views_Issue_SummaryAndLabels', __('Summary')),
array('status', 'IDF_Views_Issue_ShowStatus', __('Status')), array('status', 'IDF_Views_Issue_ShowStatus', __('Status')),
array('due_dtime', 'IDF_Views_Issue_DueDate', __('Due Date')),
array('modif_dtime', 'Pluf_Paginator_DateAgo', __('Last Updated')), array('modif_dtime', 'Pluf_Paginator_DateAgo', __('Last Updated')),
); );
$pag->configure($list_display, array(), array('id', 'status', 'modif_dtime')); $pag->configure($list_display, array(), array('id', 'status', 'due_dtime', 'modif_dtime'));
$pag->items_per_page = 10; $pag->items_per_page = 10;
$pag->no_results_text = __('No issues were found.'); $pag->no_results_text = __('No issues were found.');
$pag->setFromRequest($request); $pag->setFromRequest($request);
@@ -776,6 +823,59 @@ class IDF_Views_Issue
'page_title' => $title, 'page_title' => $title,
'open' => $open, 'open' => $open,
'closed' => $closed, 'closed' => $closed,
'overdue' => $overdue,
'issues' => $pag,
'cloud' => 'closed_issues',
),
$request);
}
/**
* View list of issues for a given project with a given status.
*/
public $listOverdue_precond = array('IDF_Precondition::accessIssues');
public function listOverdue($request, $match)
{
$prj = $request->project;
$status = __('Overdue');
$title = sprintf(__('%s %s Issues'), (string) $prj, (string) $status);
// Get stats about the issues
$open = $prj->getIssueCountByStatus('open');
$closed = $prj->getIssueCountByStatus('closed');
$overdue = $prj->getIssueCountByDueDate();
// Paginator to paginate the issues
$pag = new Pluf_Paginator(new IDF_Issue());
$pag->class = 'recent-issues';
$pag->item_extra_props = array('project_m' => $prj,
'shortname' => $prj->shortname,
'current_user' => $request->user);
$pag->summary = __('This table shows the overdue issues.');
$otags = $prj->getTagIdsByStatus('open');
if (count($otags) == 0) $otags[] = 0;
$pag->forced_where = new Pluf_SQL('project=%s AND due_dtime < NOW() AND status IN ('.implode(', ', $otags).')', array($prj->id));
$pag->action = array('IDF_Views_Issue::listOverdue', array($prj->shortname, $status));
$pag->sort_order = array('due_dtime', 'DESC'); // will be reverted
$pag->sort_reverse_order = array('due_dtime');
$pag->sort_link_title = true;
$pag->extra_classes = array('a-c', '', 'a-c', '');
$list_display = array(
'id' => __('Id'),
array('summary', 'IDF_Views_Issue_SummaryAndLabels', __('Summary')),
array('status', 'IDF_Views_Issue_ShowStatus', __('Status')),
array('due_dtime', 'IDF_Views_Issue_DueDate', __('Due Date')),
array('modif_dtime', 'Pluf_Paginator_DateAgo', __('Last Updated')),
);
$pag->configure($list_display, array(), array('id', 'status', 'due_dtime', 'modif_dtime'));
$pag->items_per_page = 10;
$pag->no_results_text = __('No issues were found.');
$pag->setFromRequest($request);
return Pluf_Shortcuts_RenderToResponse('idf/issues/index.html',
array('project' => $prj,
'page_title' => $title,
'open' => $open,
'closed' => $closed,
'overdue' => $overdue,
'issues' => $pag, 'issues' => $pag,
'cloud' => 'closed_issues', 'cloud' => 'closed_issues',
), ),
@@ -791,12 +891,17 @@ class IDF_Views_Issue
$prj = $request->project; $prj = $request->project;
$tag = Pluf_Shortcuts_GetObjectOr404('IDF_Tag', $match[2]); $tag = Pluf_Shortcuts_GetObjectOr404('IDF_Tag', $match[2]);
$status = $match[3]; $status = $match[3];
if ($tag->project != $prj->id or !in_array($status, array('open', 'closed'))) { if ($tag->project != $prj->id or !in_array($status, array('open', 'closed', 'overdue'))) {
throw new Pluf_HTTP_Error404(); throw new Pluf_HTTP_Error404();
} }
if ($status == 'open') { if ($status == 'open') {
$title = sprintf(__('%1$s Issues with Label %2$s'), (string) $prj, $title = sprintf(__('%1$s Issues with Label %2$s'), (string) $prj,
(string) $tag); (string) $tag);
} elseif ($status == 'overdue') {
$title = sprintf(__('%1$s Overdue Issues with Label %2$s'), (string) $prj,
(string) $tag);
$overdue_status = true;
$status = 'open';
} else { } else {
$title = sprintf(__('%1$s Closed Issues with Label %2$s'), $title = sprintf(__('%1$s Closed Issues with Label %2$s'),
(string) $prj, (string) $tag); (string) $prj, (string) $tag);
@@ -804,6 +909,7 @@ class IDF_Views_Issue
// Get stats about the open/closed issues having this tag. // Get stats about the open/closed issues having this tag.
$open = $prj->getIssueCountByStatus('open', $tag); $open = $prj->getIssueCountByStatus('open', $tag);
$closed = $prj->getIssueCountByStatus('closed', $tag); $closed = $prj->getIssueCountByStatus('closed', $tag);
$overdue = $prj->getIssueCountByDueDate('overdue', $tag);
// Paginator to paginate the issues // Paginator to paginate the issues
$pag = new Pluf_Paginator(new IDF_Issue()); $pag = new Pluf_Paginator(new IDF_Issue());
$pag->model_view = 'join_tags'; $pag->model_view = 'join_tags';
@@ -815,6 +921,9 @@ class IDF_Views_Issue
$otags = $prj->getTagIdsByStatus($status); $otags = $prj->getTagIdsByStatus($status);
if (count($otags) == 0) $otags[] = 0; if (count($otags) == 0) $otags[] = 0;
$pag->forced_where = new Pluf_SQL('project=%s AND idf_tag_id=%s AND status IN ('.implode(', ', $otags).')', array($prj->id, $tag->id)); $pag->forced_where = new Pluf_SQL('project=%s AND idf_tag_id=%s AND status IN ('.implode(', ', $otags).')', array($prj->id, $tag->id));
if (isset($overdue_status)) {
$pag->forced_where->SAnd(new Pluf_SQL('due_dtime < NOW()'));
}
$pag->action = array('IDF_Views_Issue::listLabel', array($prj->shortname, $tag->id, $status)); $pag->action = array('IDF_Views_Issue::listLabel', array($prj->shortname, $tag->id, $status));
$pag->sort_order = array('modif_dtime', 'ASC'); // will be reverted $pag->sort_order = array('modif_dtime', 'ASC'); // will be reverted
$pag->sort_reverse_order = array('modif_dtime'); $pag->sort_reverse_order = array('modif_dtime');
@@ -824,9 +933,10 @@ class IDF_Views_Issue
'id' => __('Id'), 'id' => __('Id'),
array('summary', 'IDF_Views_Issue_SummaryAndLabels', __('Summary')), array('summary', 'IDF_Views_Issue_SummaryAndLabels', __('Summary')),
array('status', 'IDF_Views_Issue_ShowStatus', __('Status')), array('status', 'IDF_Views_Issue_ShowStatus', __('Status')),
array('due_dtime', 'IDF_Views_Issue_DueDate', __('Due Date')),
array('modif_dtime', 'Pluf_Paginator_DateAgo', __('Last Updated')), array('modif_dtime', 'Pluf_Paginator_DateAgo', __('Last Updated')),
); );
$pag->configure($list_display, array(), array('id', 'status', 'modif_dtime')); $pag->configure($list_display, array(), array('id', 'status', 'due_dtime', 'modif_dtime'));
$pag->items_per_page = 10; $pag->items_per_page = 10;
$pag->no_results_text = __('No issues were found.'); $pag->no_results_text = __('No issues were found.');
$pag->setFromRequest($request); $pag->setFromRequest($request);
@@ -842,6 +952,7 @@ class IDF_Views_Issue
'open' => $open, 'open' => $open,
'label' => $tag, 'label' => $tag,
'closed' => $closed, 'closed' => $closed,
'overdue' => $overdue,
'issues' => $pag, 'issues' => $pag,
), ),
$request); $request);
@@ -1002,6 +1113,28 @@ class IDF_Views_Issue
$auto['auto_relation_types'] = substr($auto['auto_relation_types'], 0, -2); $auto['auto_relation_types'] = substr($auto['auto_relation_types'], 0, -2);
return $auto; return $auto;
} }
public static function getDateShortcuts()
{
return array(
'date_shortcuts' => array(
__('Soon') => array(
__('Today') => date('Y-m-d'),
__('Tomorrow') => date('Y-m-d', strtotime('tomorrow')),
__('2 Days') => date('Y-m-d', strtotime('+2 days')),
),
__('Midterm') => array(
__('Friday') => date('Y-m-d', strtotime('next friday')),
__('1 Week') => date('Y-m-d', strtotime('+1 week')),
__('A Fortnight') => date('Y-m-d', strtotime('+2 week')),
),
__('Longterm') => array(
__('End of the Month') => date('Y-m-d', strtotime('last day of this month')),
__('1 Month') => date('Y-m-d', strtotime('+1 month')),
),
),
);
}
} }
/** /**
@@ -1015,6 +1148,16 @@ function IDF_Views_Issue_SummaryAndLabelsUnknownProject($field, $issue, $extra='
return IDF_Views_Issue_SummaryAndLabels ($field, $issue, $extra); return IDF_Views_Issue_SummaryAndLabels ($field, $issue, $extra);
} }
/**
* Get the date value for the Due Date table column
*/
function IDF_Views_Issue_DueDate($field, $issue, $extra='')
{
if($issue->$field) {
return Pluf_Template_dateFormat($issue->$field);
}
}
/** /**
* Display the summary of an issue, then on a new line, display the * Display the summary of an issue, then on a new line, display the
* list of labels with a link to a view "by label only". * list of labels with a link to a view "by label only".
@@ -1037,8 +1180,12 @@ function IDF_Views_Issue_SummaryAndLabels($field, $issue, $extra='')
$s = '<img style="vertical-align: text-bottom;" src="'.Pluf_Template_Tag_MediaUrl::url('/idf/img/star.png').'" alt="'.__('On your watch list.').'" /> '; $s = '<img style="vertical-align: text-bottom;" src="'.Pluf_Template_Tag_MediaUrl::url('/idf/img/star.png').'" alt="'.__('On your watch list.').'" /> ';
} }
$out = ''; $out = '';
if ('' != $issue->due_dtime and (time() >= strtotime($issue->due_dtime)) and
in_array($issue->status, $issue->get_project()->getTagIdsByStatus('open'))) {
$out = ' <span class="overdue">' . __('overdue') . '</span>';
}
if (count($tags)) { if (count($tags)) {
$out = '<br /><span class="note">'.implode(', ', $tags).'</span>'; $out .= '<br /><span class="note">'.implode(', ', $tags).'</span>';
} }
return $s.sprintf('<a href="%s">%s</a>', $edit, Pluf_esc($issue->summary)).$out; return $s.sprintf('<a href="%s">%s</a>', $edit, Pluf_esc($issue->summary)).$out;
} }

View File

@@ -167,7 +167,7 @@ class IDF_Wiki_PageRevision extends Pluf_Model
if (count($matches) > 1 && count($matches[1]) > 0) { if (count($matches) > 1 && count($matches[1]) > 0) {
foreach ($matches[1] as $resourceName) { foreach ($matches[1] as $resourceName) {
$sql = new Pluf_SQL('project=%s AND title=%s', $sql = new Pluf_SQL('project=%s AND title=%s',
array($prj->id, $resourceName)); array($page->get_project()->id, $resourceName));
$resources = Pluf::factory('IDF_Wiki_Resource')->getList(array('filter'=>$sql->gen())); $resources = Pluf::factory('IDF_Wiki_Resource')->getList(array('filter'=>$sql->gen()));
if ($resources->count() == 0) if ($resources->count() == 0)
continue; continue;

View File

@@ -506,7 +506,7 @@ $cfg['idf_strong_key_check'] = false;
# submitted as value of the HTTP header 'Post-Commit-Hook-Hmac' during # submitted as value of the HTTP header 'Post-Commit-Hook-Hmac' during
# such a request. Since newer versions of Indefero use the same authentication # such a request. Since newer versions of Indefero use the same authentication
# mechanism (based on the same secret key) for other web hooks of the same # mechanism (based on the same secret key) for other web hooks of the same
# project as well, the name of this HTTP header was no longer appropriate # project as well, the name of this HTTP header was no longer appropriate
# and as such changed to simply 'Web-Hook-Hmac'. # and as such changed to simply 'Web-Hook-Hmac'.
# #
# Setting the following configuration option to 'compat' now restores the # Setting the following configuration option to 'compat' now restores the
@@ -533,7 +533,7 @@ $cfg['activity_section_weights'] = array(
'wiki' => 2, 'wiki' => 2,
'downloads' => 1, 'downloads' => 1,
'review' => 1, 'review' => 1,
); );
# Here you can define the timespan in days how long the activity calculation # Here you can define the timespan in days how long the activity calculation
# process should look into the history to get meaningful activity values for # process should look into the history to get meaningful activity values for
@@ -544,5 +544,4 @@ $cfg['activity_section_weights'] = array(
# high enough to show a proper activity index for those projects as well. # high enough to show a proper activity index for those projects as well.
$cfg['activity_lookback'] = 7; $cfg['activity_lookback'] = 7;
return $cfg; return $cfg;

View File

@@ -163,6 +163,11 @@ $ctl[] = array('regex' => '#^/p/([\-\w]+)/issues/status/(\w+)/$#',
'model' => 'IDF_Views_Issue', 'model' => 'IDF_Views_Issue',
'method' => 'listStatus'); 'method' => 'listStatus');
$ctl[] = array('regex' => '#^/p/([\-\w]+)/issues/due/overdue/$#',
'base' => $base,
'model' => 'IDF_Views_Issue',
'method' => 'listOverdue');
$ctl[] = array('regex' => '#^/p/([\-\w]+)/issues/label/(\d+)/(\w+)/$#', $ctl[] = array('regex' => '#^/p/([\-\w]+)/issues/label/(\d+)/(\w+)/$#',
'base' => $base, 'base' => $base,
'model' => 'IDF_Views_Issue', 'model' => 'IDF_Views_Issue',

File diff suppressed because it is too large Load Diff

View File

@@ -25,6 +25,7 @@
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<link rel="stylesheet" type="text/css" href="{media '/idf/css/yui.css'}" /> <link rel="stylesheet" type="text/css" href="{media '/idf/css/yui.css'}" />
<link rel="stylesheet" type="text/css" href="{media '/idf/css/style.css'}" /> <link rel="stylesheet" type="text/css" href="{media '/idf/css/style.css'}" />
<link rel="stylesheet" type="text/css" href="{media '/idf/css/jquery-ui-1.8.18.custom.css'}" />
<link rel="icon" type="image/png" href="{media '/idf/img/favicon.png'}" /> <link rel="icon" type="image/png" href="{media '/idf/img/favicon.png'}" />
<!--[if lt IE 7]> <!--[if lt IE 7]>
<link rel="stylesheet" type="text/css" href="{media '/idf/css/ie6.css'}" /> <link rel="stylesheet" type="text/css" href="{media '/idf/css/ie6.css'}" />
@@ -32,6 +33,7 @@
{block extraheader}{/block} {block extraheader}{/block}
<title>{block pagetitle}{$page_title|strip_tags}{/block}{if $project} - {$project.shortdesc}{/if}</title> <title>{block pagetitle}{$page_title|strip_tags}{/block}{if $project} - {$project.shortdesc}{/if}</title>
<script type="text/javascript" src="{media '/idf/js/jquery-1.7.2.min.js'}"></script> <script type="text/javascript" src="{media '/idf/js/jquery-1.7.2.min.js'}"></script>
<script type="text/javascript" src="{media '/idf/js/jquery-ui-1.8.18.custom.min.js'}"></script>
{appversion} {appversion}
</head> </head>
<body> <body>

View File

@@ -25,6 +25,7 @@
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<link rel="stylesheet" type="text/css" href="{media '/idf/css/yui.css'}" /> <link rel="stylesheet" type="text/css" href="{media '/idf/css/yui.css'}" />
<link rel="stylesheet" type="text/css" href="{media '/idf/css/style.css'}" /> <link rel="stylesheet" type="text/css" href="{media '/idf/css/style.css'}" />
<link rel="stylesheet" type="text/css" href="{media '/idf/css/jquery-ui-1.8.18.custom.css'}" />
<link rel="icon" type="image/png" href="{media '/idf/img/favicon.png'}" /> <link rel="icon" type="image/png" href="{media '/idf/img/favicon.png'}" />
<!--[if lt IE 7]> <!--[if lt IE 7]>
<link rel="stylesheet" type="text/css" href="{media '/idf/css/ie6.css'}" /> <link rel="stylesheet" type="text/css" href="{media '/idf/css/ie6.css'}" />
@@ -32,6 +33,7 @@
{block extraheader}{/block} {block extraheader}{/block}
<title>{block pagetitle}{$page_title|strip_tags}{/block}</title> <title>{block pagetitle}{$page_title|strip_tags}{/block}</title>
<script type="text/javascript" src="{media '/idf/js/jquery-1.7.2.min.js'}"></script> <script type="text/javascript" src="{media '/idf/js/jquery-1.7.2.min.js'}"></script>
<script type="text/javascript" src="{media '/idf/js/jquery-ui-1.8.18.custom.min.js'}"></script>
{appversion} {appversion}
</head> </head>
<body> <body>

View File

@@ -25,6 +25,7 @@
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<link rel="stylesheet" type="text/css" href="{media '/idf/css/yui.css'}" /> <link rel="stylesheet" type="text/css" href="{media '/idf/css/yui.css'}" />
<link rel="stylesheet" type="text/css" href="{media '/idf/css/style.css'}" /> <link rel="stylesheet" type="text/css" href="{media '/idf/css/style.css'}" />
<link rel="stylesheet" type="text/css" href="{media '/idf/css/jquery-ui-1.8.18.custom.css'}" />
<link rel="icon" type="image/png" href="{media '/idf/img/favicon.png'}" /> <link rel="icon" type="image/png" href="{media '/idf/img/favicon.png'}" />
<!--[if lt IE 7]> <!--[if lt IE 7]>
<link rel="stylesheet" type="text/css" href="{media '/idf/css/ie6.css'}" /> <link rel="stylesheet" type="text/css" href="{media '/idf/css/ie6.css'}" />
@@ -32,6 +33,7 @@
{block extraheader}{/block} {block extraheader}{/block}
<title>{block pagetitle}{$page_title|strip_tags}{/block}{if $project} - {$project.shortdesc}{/if}</title> <title>{block pagetitle}{$page_title|strip_tags}{/block}{if $project} - {$project.shortdesc}{/if}</title>
<script type="text/javascript" src="{media '/idf/js/jquery-1.7.2.min.js'}"></script> <script type="text/javascript" src="{media '/idf/js/jquery-1.7.2.min.js'}"></script>
<script type="text/javascript" src="{media '/idf/js/jquery-ui-1.8.18.custom.min.js'}"></script>
{appversion} {appversion}
</head> </head>
<body> <body>

View File

@@ -10,8 +10,10 @@
{block context} {block context}
{aurl 'open_url', 'IDF_Views_Issue::listLabel', array($project.shortname, $label.id, 'open')} {aurl 'open_url', 'IDF_Views_Issue::listLabel', array($project.shortname, $label.id, 'open')}
{aurl 'closed_url', 'IDF_Views_Issue::listLabel', array($project.shortname, $label.id, 'closed')} {aurl 'closed_url', 'IDF_Views_Issue::listLabel', array($project.shortname, $label.id, 'closed')}
{aurl 'overdue_url', 'IDF_Views_Issue::listLabel', array($project.shortname, $label.id, 'overdue')}
{blocktrans}<p><strong>Open issues:</strong> <a href="{$open_url}">{$open}</a></p> {blocktrans}<p><strong>Open issues:</strong> <a href="{$open_url}">{$open}</a></p>
<p><strong>Closed issues:</strong> <a href="{$closed_url}">{$closed}</a></p> <p><strong>Closed issues:</strong> <a href="{$closed_url}">{$closed}</a></p>
<p><span>Overdue:</span> <a href="{$overdue_url}">{$overdue}</a></p>
{/blocktrans} {/blocktrans}
<p><strong>{trans 'Label:'}</strong> <p><strong>{trans 'Label:'}</strong>
{aurl 'url', 'IDF_Views_Issue::listLabel', array($project.shortname, $label.id, 'open')} {aurl 'url', 'IDF_Views_Issue::listLabel', array($project.shortname, $label.id, 'open')}

View File

@@ -63,6 +63,24 @@
</td> </td>
</tr> </tr>
<tr> <tr>
<th>{$form.f.due_dtime.labelTag}:</th>
<td>{if $form.f.due_dtime.errors}{$form.f.due_dtime.fieldErrors}{/if}
{$form.f.due_dtime|unsafe}
<div id="due_dtime_wrapper">
<a href="#" id="due_dtime_shortcut_link">Date shortcuts&hellip;</a>
{if $date_shortcuts}
<dl id="due_dtime_more_shortcuts" style="display: none">
{foreach $date_shortcuts as $time_span => $shortcuts}
<dt>{$time_span}</dt>
{foreach $shortcuts as $title => $date}
<dd><a href="javascript:void(0);" rel="{$date}" class="due_dtime_shortcut">{$title}</a></dd>
{/foreach}
{/foreach}
</dl>
{/if}
</div>
</td>
<tr>
<th>{$form.f.relation_type0.labelTag}:</th> <th>{$form.f.relation_type0.labelTag}:</th>
<td> <td>
{if $form.f.relation_type0.errors}{$form.f.relation_type0.fieldErrors}{/if} {if $form.f.relation_type0.errors}{$form.f.relation_type0.fieldErrors}{/if}
@@ -108,7 +126,21 @@
<script type="text/javascript"> <script type="text/javascript">
document.getElementById('id_summary').focus();{literal} document.getElementById('id_summary').focus();{literal}
$(document).ready(function(){ $(document).ready(function(){
$("#id_due_dtime").datepicker({
changeYear: true,
changeMonth: true,
yearRange: '-0:+5',
constrainInput: false,
dateFormat: 'yy-mm-dd'
});
$('#due_dtime_wrapper').mouseover(function(){
$('#due_dtime_more_shortcuts').show();
}).mouseout(function(){
$('#due_dtime_more_shortcuts').hide();
});
$(".due_dtime_shortcut").click(function(){
$('#id_due_dtime').val($(this).attr('rel'));
});
// Hide the upload forms, we insert before the first attach file // Hide the upload forms, we insert before the first attach file
// row an "Attach File" little link. // row an "Attach File" little link.
// We hide all the rows. // We hide all the rows.

View File

@@ -14,7 +14,7 @@
</ul>{/if} </ul>{/if}
{if $c.changes} {if $c.changes}
{foreach $c.changes as $w => $v} {foreach $c.changes as $w => $v}
<strong>{if $w == 'su'}{trans 'Summary:'}{/if}{if $w == 'st'}{trans 'Status:'}{/if}{if $w == 'ow'}{trans 'Owner:'}{/if}{if $w == 'lb'}{trans 'Labels:'}{/if}{if $w == 'rel'}{trans 'Relations:'}{/if}</strong> <strong>{if $w == 'su'}{trans 'Summary:'}{/if}{if $w == 'st'}{trans 'Status:'}{/if}{if $w == 'ow'}{trans 'Owner:'}{/if}{if $w == 'lb'}{trans 'Labels:'}{/if}{if $w == 'rel'}{trans 'Relations:'}{/if}{if $w == 'du'}{trans 'Due date:'}{/if}</strong>
{if $w == 'lb' or $w == 'rel'} {if $w == 'lb' or $w == 'rel'}
{foreach $v as $t => $ls} {foreach $v as $t => $ls}
{foreach $ls as $l} {foreach $ls as $l}

View File

@@ -7,6 +7,8 @@
{block context} {block context}
{aurl 'open_url', 'IDF_Views_Issue::forgeWatchList', array('open')} {aurl 'open_url', 'IDF_Views_Issue::forgeWatchList', array('open')}
{aurl 'closed_url', 'IDF_Views_Issue::forgeWatchList', array('closed')} {aurl 'closed_url', 'IDF_Views_Issue::forgeWatchList', array('closed')}
{aurl 'overdue_url', 'IDF_Views_Issue::forgeWatchList', array('overdue')}
{blocktrans}<p><strong>Open issues:</strong> <a href="{$open_url}">{$open}</a></p> {blocktrans}<p><strong>Open issues:</strong> <a href="{$open_url}">{$open}</a></p>
<p><strong>Closed issues:</strong> <a href="{$closed_url}">{$closed}</a></p>{/blocktrans} <p><strong>Closed issues:</strong> <a href="{$closed_url}">{$closed}</a></p>
{/block} <p><span>Overdue:</span> <a href="{$overdue_url}">{$overdue}</a></p>{/blocktrans}
{/block}

View File

@@ -10,8 +10,10 @@
{block context} {block context}
{aurl 'open_url', 'IDF_Views_Issue::index', array($project.shortname)} {aurl 'open_url', 'IDF_Views_Issue::index', array($project.shortname)}
{aurl 'closed_url', 'IDF_Views_Issue::listStatus', array($project.shortname, 'closed')} {aurl 'closed_url', 'IDF_Views_Issue::listStatus', array($project.shortname, 'closed')}
{aurl 'overdue_url', 'IDF_Views_Issue::listOverdue', array($project.shortname, 'Overdue', 'overdue')}
{blocktrans}<p><strong>Open issues:</strong> <a href="{$open_url}">{$open}</a></p> {blocktrans}<p><strong>Open issues:</strong> <a href="{$open_url}">{$open}</a></p>
<p><strong>Closed issues:</strong> <a href="{$closed_url}">{$closed}</a></p>{/blocktrans} <p><strong>Closed issues:</strong> <a href="{$closed_url}">{$closed}</a></p>
<p><span>Overdue:</span> <a href="{$overdue_url}">{$overdue}</a></p>{/blocktrans}
{assign $cloud_url = 'IDF_Views_Issue::listLabel'} {assign $cloud_url = 'IDF_Views_Issue::listLabel'}
{include 'idf/tags-cloud.html'} {include 'idf/tags-cloud.html'}
{/block} {/block}

View File

@@ -6,6 +6,7 @@
{trans 'Project:'} {$project.name|safe} {trans 'Project:'} {$project.name|safe}
{trans 'Status:'} {$issue.get_status.name|safe} {trans 'Status:'} {$issue.get_status.name|safe}
{trans 'Reported by:'} {$issue.get_submitter|safe} {trans 'Reported by:'} {$issue.get_submitter|safe}
{if $issue.due_dtime}{trans 'Due date:'} {$issue.due_dtime|date|safe}{/if}
{assign $tags = $issue.get_tags_list()}{if $tags.count()}{trans 'Labels:'} {assign $tags = $issue.get_tags_list()}{if $tags.count()}{trans 'Labels:'}
{foreach $tags as $tag} {$tag.class|safe}:{$tag.name|safe} {foreach $tags as $tag} {$tag.class|safe}:{$tag.name|safe}
{/foreach}{/if} {/foreach}{/if}

View File

@@ -6,6 +6,7 @@
{trans 'Project:'} {$project.name|safe} {trans 'Project:'} {$project.name|safe}
{trans 'Status:'} {$issue.get_status.name} {trans 'Status:'} {$issue.get_status.name}
{trans 'Reported by:'} {$issue.get_submitter|safe} {trans 'Reported by:'} {$issue.get_submitter|safe}
{if $issue.due_dtime}{trans 'Due date:'} {$issue.due_dtime|date|safe}{/if}
{trans 'URL:'} {$url_base}{url 'IDF_Views_Issue::view', array($project.shortname, $issue.id)} {trans 'URL:'} {$url_base}{url 'IDF_Views_Issue::view', array($project.shortname, $issue.id)}
{assign $tags = $issue.get_tags_list()}{if $tags.count()}{trans 'Labels:'} {assign $tags = $issue.get_tags_list()}{if $tags.count()}{trans 'Labels:'}
{foreach $tags as $tag} {$tag.class|safe}:{$tag.name|safe} {foreach $tags as $tag} {$tag.class|safe}:{$tag.name|safe}
@@ -16,7 +17,7 @@
{if strlen($c.content) > 0}{$c.content|safe}{/if}{if $c.changedIssue()} {if strlen($c.content) > 0}{$c.content|safe}{/if}{if $c.changedIssue()}
{foreach $c.changes as $w => $v} {foreach $c.changes as $w => $v}
{if $w == 'su'}{trans 'Summary:'}{/if}{if $w == 'st'}{trans 'Status:'}{/if}{if $w == 'ow'}{trans 'Owner:'}{/if}{if $w == 'lb'}{trans 'Labels:'}{/if}{if $w == 'rel'}{trans 'Relations:'}{/if} {if $w == 'lb' or $w == 'rel'}{foreach $v as $t => $ls}{foreach $ls as $l}{if $t == 'rem'}-{/if}{$l} {/foreach}{/foreach}{else}{$v}{/if}{/foreach}{/if}{assign $attachments = $c.get_attachment_list()}{if $attachments.count() > 0} {if $w == 'su'}{trans 'Summary:'}{/if}{if $w == 'st'}{trans 'Status:'}{/if}{if $w == 'ow'}{trans 'Owner:'}{/if}{if $w == 'du'}{trans 'Due date:'}{/if}{if $w == 'lb'}{trans 'Labels:'}{/if}{if $w == 'rel'}{trans 'Relations:'}{/if} {if $w == 'lb' or $w == 'rel'}{foreach $v as $t => $ls}{foreach $ls as $l}{if $t == 'rem'}-{/if}{$l} {/foreach}{/foreach}{else}{$v}{/if}{/foreach}{/if}{assign $attachments = $c.get_attachment_list()}{if $attachments.count() > 0}
{trans 'Attachments:'}{foreach $attachments as $a} {trans 'Attachments:'}{foreach $attachments as $a}
- {$a.filename|safe} - {$a.filesize|ssize} - {$a.filename|safe} - {$a.filesize|ssize}

View File

@@ -12,6 +12,8 @@
{block context} {block context}
{aurl 'open_url', 'IDF_Views_Issue::watchList', array($project.shortname, 'open')} {aurl 'open_url', 'IDF_Views_Issue::watchList', array($project.shortname, 'open')}
{aurl 'closed_url', 'IDF_Views_Issue::watchList', array($project.shortname, 'closed')} {aurl 'closed_url', 'IDF_Views_Issue::watchList', array($project.shortname, 'closed')}
{aurl 'overdue_url', 'IDF_Views_Issue::watchList', array($project.shortname, 'overdue')}
{blocktrans}<p><strong>Open issues:</strong> <a href="{$open_url}">{$open}</a></p> {blocktrans}<p><strong>Open issues:</strong> <a href="{$open_url}">{$open}</a></p>
<p><strong>Closed issues:</strong> <a href="{$closed_url}">{$closed}</a></p>{/blocktrans} <p><strong>Closed issues:</strong> <a href="{$closed_url}">{$closed}</a></p>
{/block} <p><span>Overdue:</span> <a href="{$overdue_url}">{$overdue}</a></p>{/blocktrans}
{/block}

View File

@@ -10,13 +10,16 @@
{block context} {block context}
{aurl 'open_url', 'IDF_Views_Issue::searchStatus', array($project.shortname, 'open'), array('q' => $query)} {aurl 'open_url', 'IDF_Views_Issue::searchStatus', array($project.shortname, 'open'), array('q' => $query)}
{aurl 'closed_url', 'IDF_Views_Issue::searchStatus', array($project.shortname, 'closed'), array('q' => $query)} {aurl 'closed_url', 'IDF_Views_Issue::searchStatus', array($project.shortname, 'closed'), array('q' => $query)}
{aurl 'overdue_url', 'IDF_Views_Issue::searchStatus', array($project.shortname, 'overdue'), array('q' => $query)}
{if $tag != null} {if $tag != null}
{aurl 'open_url', 'IDF_Views_Issue::searchLabel', array($project.shortname, $tag.id, 'open'), array('q' => $query)} {aurl 'open_url', 'IDF_Views_Issue::searchLabel', array($project.shortname, $tag.id, 'open'), array('q' => $query)}
{aurl 'closed_url', 'IDF_Views_Issue::searchLabel', array($project.shortname, $tag.id, 'closed'), array('q' => $query)} {aurl 'closed_url', 'IDF_Views_Issue::searchLabel', array($project.shortname, $tag.id, 'closed'), array('q' => $query)}
{aurl 'overdue_url', 'IDF_Views_Issue::searchLabel', array($project.shortname, $tag.id, 'overdue'), array('q' => $query)}
{/if} {/if}
{blocktrans} {blocktrans}
<p><strong>Found open issues:</strong> <a href="{$open_url}">{$open}</a></p> <p><strong>Found open issues:</strong> <a href="{$open_url}">{$open}</a></p>
<p><strong>Found closed issues:</strong> <a href="{$closed_url}">{$closed}</a></p>{/blocktrans} <p><strong>Found closed issues:</strong> <a href="{$closed_url}">{$closed}</a></p>
<p>Found overdue issues: <a href="{$overdue_url}">{$overdue}</a></p>{/blocktrans}
{if $tag !== null} {if $tag !== null}
{blocktrans}<p><strong>Label:</strong> {blocktrans}<p><strong>Label:</strong>
<a href="{$open_url}" class="label"><strong>{$tag.class}:</strong>{$tag.name}</a></p>{/blocktrans} <a href="{$open_url}" class="label"><strong>{$tag.class}:</strong>{$tag.name}</a></p>{/blocktrans}

View File

@@ -103,6 +103,34 @@
</table> </table>
</div> </div>
{/if} {/if}
{if $duedateStatistics}
<div>
<h2>{blocktrans}Unresolved: By Due Date{/blocktrans}</h2>
<table class='issue-summary'>
<tbody>
<tr>
<td class="name">
{aurl 'url', 'IDF_Views_Issue::listOverdue', array($project.shortname, 'overdue', 'due')}
<a href="{$url}">{blocktrans}Overdue{/blocktrans}</a>
</td>
<td class="count">{$duedateStatistics[0]}</td>
<td class="graph">
<table class='graph'>
<tbody><tr>
<td style="width:{$duedateStatistics[1] * 0.8 + 1}%" class="graph-color" valign="center">
<div class="colour-bar"></div>
</td>
<td class="graph-percent">{$duedateStatistics[1]}%</td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
</div>
{/if}
</div> </div>
{/if} {/if}
{/block} {/block}

View File

@@ -40,7 +40,7 @@
{if $i> 0 and $c.changedIssue()} {if $i> 0 and $c.changedIssue()}
<div class="issue-changes"> <div class="issue-changes">
{foreach $c.changes as $w => $v} {foreach $c.changes as $w => $v}
<strong>{if $w == 'su'}{trans 'Summary:'}{/if}{if $w == 'st'}{trans 'Status:'}{/if}{if $w == 'ow'}{trans 'Owner:'}{/if}{if $w == 'lb'}{trans 'Labels:'}{/if}{if $w == 'rel'}{trans 'Relations:'}{/if}</strong> <strong>{if $w == 'su'}{trans 'Summary:'}{/if}{if $w == 'st'}{trans 'Status:'}{/if}{if $w == 'ow'}{trans 'Owner:'}{/if}{if $w == 'du'}{trans 'Due date:'}{/if}{if $w == 'lb'}{trans 'Labels:'}{/if}{if $w == 'rel'}{trans 'Relations:'}{/if}</strong>
{if $w == 'lb' or $w == 'rel'} {if $w == 'lb' or $w == 'rel'}
{foreach $v as $t => $ls} {foreach $v as $t => $ls}
{foreach $ls as $l} {foreach $ls as $l}
@@ -128,6 +128,24 @@
{$form.f.owner|unsafe} {$form.f.owner|unsafe}
</td> </td>
</tr> </tr>
<th>{$form.f.due_dtime.labelTag}:</th>
<td>{if $form.f.due_dtime.errors}{$form.f.due_dtime.fieldErrors}{/if}
{$form.f.due_dtime|unsafe}
<div id="due_dtime_wrapper">
<a href="#" id="due_dtime_shortcut_link">Date shortcuts&hellip;</a>
{if $date_shortcuts}
<dl id="due_dtime_more_shortcuts" style="display: none">
{foreach $date_shortcuts as $time_span => $shortcuts}
<dt>{$time_span}</dt>
{foreach $shortcuts as $title => $date}
<dd><a href="javascript:void(0);" rel="{$date}" class="due_dtime_shortcut">{$title}</a></dd>
{/foreach}
{/foreach}
</dl>
{/if}
</div>
</td>
<tr>
<tr> <tr>
<th>{$form.f.relation_type0.labelTag}:</th> <th>{$form.f.relation_type0.labelTag}:</th>
<td> <td>
@@ -180,6 +198,9 @@
<strong>{trans 'Owner:'}</strong> {showuser $issue.get_owner(), $request} <strong>{trans 'Owner:'}</strong> {showuser $issue.get_owner(), $request}
</p>{/if} </p>{/if}
{if $interested > 0}<p><strong>{trans 'Followed by:'}</strong> {blocktrans $interested}{$interested} person{plural}{$interested} persons{/blocktrans}</p>{/if} {if $interested > 0}<p><strong>{trans 'Followed by:'}</strong> {blocktrans $interested}{$interested} person{plural}{$interested} persons{/blocktrans}</p>{/if}
{if $issue.due_dtime}
<p><strong>{trans 'Due Date:'}</strong> {$issue.due_dtime|date}</p>
{/if}
{assign $tags = $issue.get_tags_list()}{if $tags.count()} {assign $tags = $issue.get_tags_list()}{if $tags.count()}
<p> <p>
<strong>{trans 'Labels:'}</strong><br /> <strong>{trans 'Labels:'}</strong><br />
@@ -209,7 +230,21 @@
<script type="text/javascript"> <script type="text/javascript">
{literal} {literal}
$(document).ready(function(){ $(document).ready(function(){
$("#id_due_dtime").datepicker({
changeYear: true,
changeMonth: true,
yearRange: '-0:+5',
constrainInput: false,
dateFormat: 'yy-mm-dd'
});
$('#due_dtime_wrapper').mouseover(function(){
$('#due_dtime_more_shortcuts').show();
}).mouseout(function(){
$('#due_dtime_more_shortcuts').hide();
});
$(".due_dtime_shortcut").click(function(){
$('#id_due_dtime').val($(this).attr('rel'));
});
// Hide the upload forms, we insert before the first attach file // Hide the upload forms, we insert before the first attach file
// row an "Attach File" little link. // row an "Attach File" little link.
// We hide all the rows. // We hide all the rows.

View File

@@ -48,7 +48,6 @@
<strong>{trans 'Filtered project stats'}</strong> <strong>{trans 'Filtered project stats'}</strong>
<dl class="statistics smaller"> <dl class="statistics smaller">
<dt>{trans 'Members:'}</dt><dd>{$stats.members}</dd>
<dt>{trans 'Issues:'}</dt><dd>{$stats.issues}</dd> <dt>{trans 'Issues:'}</dt><dd>{$stats.issues}</dd>
<dt>{trans 'Commits:'}</dt><dd>{$stats.commits}</dd> <dt>{trans 'Commits:'}</dt><dd>{$stats.commits}</dd>
<dt>{trans 'Documentations:'}</dt><dd>{$stats.docpages}</dd> <dt>{trans 'Documentations:'}</dt><dd>{$stats.docpages}</dd>

View File

@@ -1,5 +1,5 @@
<?php <?php
return array( return array(
'version' => '1.3-dev', 'version' => '1.4-dev',
'revision' => '$Format:%H$', 'revision' => '$Format:%H$',
); );

View File

@@ -80,7 +80,6 @@
0 => '', 0 => '',
1 => 11, 1 => 11,
2 => ' 2 => '
', ',
), ),
), ),
@@ -102,4 +101,4 @@
), ),
), ),
), ),
); );

View File

@@ -0,0 +1,354 @@
/*
* jQuery UI CSS Framework 1.8.18
*
* Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
* Dual licensed under the MIT or GPL Version 2 licenses.
* http://jquery.org/license
*
* http://docs.jquery.com/UI/Theming/API
*/
/* Layout helpers
----------------------------------*/
.ui-helper-hidden { display: none; }
.ui-helper-hidden-accessible { position: absolute !important; clip: rect(1px 1px 1px 1px); clip: rect(1px,1px,1px,1px); }
.ui-helper-reset { margin: 0; padding: 0; border: 0; outline: 0; line-height: 1.3; text-decoration: none; font-size: 100%; list-style: none; }
.ui-helper-clearfix:before, .ui-helper-clearfix:after { content: ""; display: table; }
.ui-helper-clearfix:after { clear: both; }
.ui-helper-clearfix { zoom: 1; }
.ui-helper-zfix { width: 100%; height: 100%; top: 0; left: 0; position: absolute; opacity: 0; filter:Alpha(Opacity=0); }
/* Interaction Cues
----------------------------------*/
.ui-state-disabled { cursor: default !important; }
/* Icons
----------------------------------*/
/* states and images */
.ui-icon { display: block; text-indent: -99999px; overflow: hidden; background-repeat: no-repeat; }
/* Misc visuals
----------------------------------*/
/* Overlays */
.ui-widget-overlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; }
/*
* jQuery UI CSS Framework 1.8.18
*
* Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
* Dual licensed under the MIT or GPL Version 2 licenses.
* http://jquery.org/license
*
* http://docs.jquery.com/UI/Theming/API
*
* To view and modify this theme, visit http://jqueryui.com/themeroller/?ffDefault=Verdana,Arial,sans-serif&fwDefault=normal&fsDefault=1.1em&cornerRadius=4px&bgColorHeader=cccccc&bgTextureHeader=03_highlight_soft.png&bgImgOpacityHeader=75&borderColorHeader=aaaaaa&fcHeader=222222&iconColorHeader=222222&bgColorContent=ffffff&bgTextureContent=01_flat.png&bgImgOpacityContent=75&borderColorContent=aaaaaa&fcContent=222222&iconColorContent=222222&bgColorDefault=e6e6e6&bgTextureDefault=02_glass.png&bgImgOpacityDefault=75&borderColorDefault=d3d3d3&fcDefault=555555&iconColorDefault=888888&bgColorHover=dadada&bgTextureHover=02_glass.png&bgImgOpacityHover=75&borderColorHover=999999&fcHover=212121&iconColorHover=454545&bgColorActive=ffffff&bgTextureActive=02_glass.png&bgImgOpacityActive=65&borderColorActive=aaaaaa&fcActive=212121&iconColorActive=454545&bgColorHighlight=fbf9ee&bgTextureHighlight=02_glass.png&bgImgOpacityHighlight=55&borderColorHighlight=fcefa1&fcHighlight=363636&iconColorHighlight=2e83ff&bgColorError=fef1ec&bgTextureError=02_glass.png&bgImgOpacityError=95&borderColorError=cd0a0a&fcError=cd0a0a&iconColorError=cd0a0a&bgColorOverlay=aaaaaa&bgTextureOverlay=01_flat.png&bgImgOpacityOverlay=0&opacityOverlay=30&bgColorShadow=aaaaaa&bgTextureShadow=01_flat.png&bgImgOpacityShadow=0&opacityShadow=30&thicknessShadow=8px&offsetTopShadow=-8px&offsetLeftShadow=-8px&cornerRadiusShadow=8px
*/
/* Component containers
----------------------------------*/
.ui-widget { font-family: Verdana,Arial,sans-serif; font-size: 1.1em; }
.ui-widget .ui-widget { font-size: 1em; }
.ui-widget input, .ui-widget select, .ui-widget textarea, .ui-widget button { font-family: Verdana,Arial,sans-serif; font-size: 1em; }
.ui-widget-content { border: 1px solid #aaaaaa; background: #ffffff url(/media/idf/img/jquery-ui/ui-bg_flat_75_ffffff_40x100.png) 50% 50% repeat-x; color: #222222; }
.ui-widget-content a { color: #222222; }
.ui-widget-header { border: 1px solid #aaaaaa; background: #cccccc url(/media/idf/img/jquery-ui/ui-bg_highlight-soft_75_cccccc_1x100.png) 50% 50% repeat-x; color: #222222; font-weight: bold; }
.ui-widget-header a { color: #222222; }
/* Interaction states
----------------------------------*/
.ui-state-default, .ui-widget-content .ui-state-default, .ui-widget-header .ui-state-default { border: 1px solid #d3d3d3; background: #e6e6e6 url(/media/idf/img/jquery-ui/ui-bg_glass_75_e6e6e6_1x400.png) 50% 50% repeat-x; font-weight: normal; color: #555555; }
.ui-state-default a, .ui-state-default a:link, .ui-state-default a:visited { color: #555555; text-decoration: none; }
.ui-state-hover, .ui-widget-content .ui-state-hover, .ui-widget-header .ui-state-hover, .ui-state-focus, .ui-widget-content .ui-state-focus, .ui-widget-header .ui-state-focus { border: 1px solid #999999; background: #dadada url(/media/idf/img/jquery-ui/ui-bg_glass_75_dadada_1x400.png) 50% 50% repeat-x; font-weight: normal; color: #212121; }
.ui-state-hover a, .ui-state-hover a:hover { color: #212121; text-decoration: none; }
.ui-state-active, .ui-widget-content .ui-state-active, .ui-widget-header .ui-state-active { border: 1px solid #aaaaaa; background: #ffffff url(/media/idf/img/jquery-ui/ui-bg_glass_65_ffffff_1x400.png) 50% 50% repeat-x; font-weight: normal; color: #212121; }
.ui-state-active a, .ui-state-active a:link, .ui-state-active a:visited { color: #212121; text-decoration: none; }
.ui-widget :active { outline: none; }
/* Interaction Cues
----------------------------------*/
.ui-state-highlight, .ui-widget-content .ui-state-highlight, .ui-widget-header .ui-state-highlight {border: 1px solid #fcefa1; background: #fbf9ee url(/media/idf/img/jquery-ui/ui-bg_glass_55_fbf9ee_1x400.png) 50% 50% repeat-x; color: #363636; }
.ui-state-highlight a, .ui-widget-content .ui-state-highlight a,.ui-widget-header .ui-state-highlight a { color: #363636; }
.ui-state-error, .ui-widget-content .ui-state-error, .ui-widget-header .ui-state-error {border: 1px solid #cd0a0a; background: #fef1ec url(/media/idf/img/jquery-ui/ui-bg_glass_95_fef1ec_1x400.png) 50% 50% repeat-x; color: #cd0a0a; }
.ui-state-error a, .ui-widget-content .ui-state-error a, .ui-widget-header .ui-state-error a { color: #cd0a0a; }
.ui-state-error-text, .ui-widget-content .ui-state-error-text, .ui-widget-header .ui-state-error-text { color: #cd0a0a; }
.ui-priority-primary, .ui-widget-content .ui-priority-primary, .ui-widget-header .ui-priority-primary { font-weight: bold; }
.ui-priority-secondary, .ui-widget-content .ui-priority-secondary, .ui-widget-header .ui-priority-secondary { opacity: .7; filter:Alpha(Opacity=70); font-weight: normal; }
.ui-state-disabled, .ui-widget-content .ui-state-disabled, .ui-widget-header .ui-state-disabled { opacity: .35; filter:Alpha(Opacity=35); background-image: none; }
/* Icons
----------------------------------*/
/* states and images */
.ui-icon { width: 16px; height: 16px; background-image: url(/media/idf/img/jquery-ui/ui-icons_222222_256x240.png); }
.ui-widget-content .ui-icon {background-image: url(/media/idf/img/jquery-ui/ui-icons_222222_256x240.png); }
.ui-widget-header .ui-icon {background-image: url(/media/idf/img/jquery-ui/ui-icons_222222_256x240.png); }
.ui-state-default .ui-icon { background-image: url(/media/idf/img/jquery-ui/ui-icons_888888_256x240.png); }
.ui-state-hover .ui-icon, .ui-state-focus .ui-icon {background-image: url(/media/idf/img/jquery-ui/ui-icons_454545_256x240.png); }
.ui-state-active .ui-icon {background-image: url(/media/idf/img/jquery-ui/ui-icons_454545_256x240.png); }
.ui-state-highlight .ui-icon {background-image: url(/media/idf/img/jquery-ui/ui-icons_2e83ff_256x240.png); }
.ui-state-error .ui-icon, .ui-state-error-text .ui-icon {background-image: url(/media/idf/img/jquery-ui/ui-icons_cd0a0a_256x240.png); }
/* positioning */
.ui-icon-carat-1-n { background-position: 0 0; }
.ui-icon-carat-1-ne { background-position: -16px 0; }
.ui-icon-carat-1-e { background-position: -32px 0; }
.ui-icon-carat-1-se { background-position: -48px 0; }
.ui-icon-carat-1-s { background-position: -64px 0; }
.ui-icon-carat-1-sw { background-position: -80px 0; }
.ui-icon-carat-1-w { background-position: -96px 0; }
.ui-icon-carat-1-nw { background-position: -112px 0; }
.ui-icon-carat-2-n-s { background-position: -128px 0; }
.ui-icon-carat-2-e-w { background-position: -144px 0; }
.ui-icon-triangle-1-n { background-position: 0 -16px; }
.ui-icon-triangle-1-ne { background-position: -16px -16px; }
.ui-icon-triangle-1-e { background-position: -32px -16px; }
.ui-icon-triangle-1-se { background-position: -48px -16px; }
.ui-icon-triangle-1-s { background-position: -64px -16px; }
.ui-icon-triangle-1-sw { background-position: -80px -16px; }
.ui-icon-triangle-1-w { background-position: -96px -16px; }
.ui-icon-triangle-1-nw { background-position: -112px -16px; }
.ui-icon-triangle-2-n-s { background-position: -128px -16px; }
.ui-icon-triangle-2-e-w { background-position: -144px -16px; }
.ui-icon-arrow-1-n { background-position: 0 -32px; }
.ui-icon-arrow-1-ne { background-position: -16px -32px; }
.ui-icon-arrow-1-e { background-position: -32px -32px; }
.ui-icon-arrow-1-se { background-position: -48px -32px; }
.ui-icon-arrow-1-s { background-position: -64px -32px; }
.ui-icon-arrow-1-sw { background-position: -80px -32px; }
.ui-icon-arrow-1-w { background-position: -96px -32px; }
.ui-icon-arrow-1-nw { background-position: -112px -32px; }
.ui-icon-arrow-2-n-s { background-position: -128px -32px; }
.ui-icon-arrow-2-ne-sw { background-position: -144px -32px; }
.ui-icon-arrow-2-e-w { background-position: -160px -32px; }
.ui-icon-arrow-2-se-nw { background-position: -176px -32px; }
.ui-icon-arrowstop-1-n { background-position: -192px -32px; }
.ui-icon-arrowstop-1-e { background-position: -208px -32px; }
.ui-icon-arrowstop-1-s { background-position: -224px -32px; }
.ui-icon-arrowstop-1-w { background-position: -240px -32px; }
.ui-icon-arrowthick-1-n { background-position: 0 -48px; }
.ui-icon-arrowthick-1-ne { background-position: -16px -48px; }
.ui-icon-arrowthick-1-e { background-position: -32px -48px; }
.ui-icon-arrowthick-1-se { background-position: -48px -48px; }
.ui-icon-arrowthick-1-s { background-position: -64px -48px; }
.ui-icon-arrowthick-1-sw { background-position: -80px -48px; }
.ui-icon-arrowthick-1-w { background-position: -96px -48px; }
.ui-icon-arrowthick-1-nw { background-position: -112px -48px; }
.ui-icon-arrowthick-2-n-s { background-position: -128px -48px; }
.ui-icon-arrowthick-2-ne-sw { background-position: -144px -48px; }
.ui-icon-arrowthick-2-e-w { background-position: -160px -48px; }
.ui-icon-arrowthick-2-se-nw { background-position: -176px -48px; }
.ui-icon-arrowthickstop-1-n { background-position: -192px -48px; }
.ui-icon-arrowthickstop-1-e { background-position: -208px -48px; }
.ui-icon-arrowthickstop-1-s { background-position: -224px -48px; }
.ui-icon-arrowthickstop-1-w { background-position: -240px -48px; }
.ui-icon-arrowreturnthick-1-w { background-position: 0 -64px; }
.ui-icon-arrowreturnthick-1-n { background-position: -16px -64px; }
.ui-icon-arrowreturnthick-1-e { background-position: -32px -64px; }
.ui-icon-arrowreturnthick-1-s { background-position: -48px -64px; }
.ui-icon-arrowreturn-1-w { background-position: -64px -64px; }
.ui-icon-arrowreturn-1-n { background-position: -80px -64px; }
.ui-icon-arrowreturn-1-e { background-position: -96px -64px; }
.ui-icon-arrowreturn-1-s { background-position: -112px -64px; }
.ui-icon-arrowrefresh-1-w { background-position: -128px -64px; }
.ui-icon-arrowrefresh-1-n { background-position: -144px -64px; }
.ui-icon-arrowrefresh-1-e { background-position: -160px -64px; }
.ui-icon-arrowrefresh-1-s { background-position: -176px -64px; }
.ui-icon-arrow-4 { background-position: 0 -80px; }
.ui-icon-arrow-4-diag { background-position: -16px -80px; }
.ui-icon-extlink { background-position: -32px -80px; }
.ui-icon-newwin { background-position: -48px -80px; }
.ui-icon-refresh { background-position: -64px -80px; }
.ui-icon-shuffle { background-position: -80px -80px; }
.ui-icon-transfer-e-w { background-position: -96px -80px; }
.ui-icon-transferthick-e-w { background-position: -112px -80px; }
.ui-icon-folder-collapsed { background-position: 0 -96px; }
.ui-icon-folder-open { background-position: -16px -96px; }
.ui-icon-document { background-position: -32px -96px; }
.ui-icon-document-b { background-position: -48px -96px; }
.ui-icon-note { background-position: -64px -96px; }
.ui-icon-mail-closed { background-position: -80px -96px; }
.ui-icon-mail-open { background-position: -96px -96px; }
.ui-icon-suitcase { background-position: -112px -96px; }
.ui-icon-comment { background-position: -128px -96px; }
.ui-icon-person { background-position: -144px -96px; }
.ui-icon-print { background-position: -160px -96px; }
.ui-icon-trash { background-position: -176px -96px; }
.ui-icon-locked { background-position: -192px -96px; }
.ui-icon-unlocked { background-position: -208px -96px; }
.ui-icon-bookmark { background-position: -224px -96px; }
.ui-icon-tag { background-position: -240px -96px; }
.ui-icon-home { background-position: 0 -112px; }
.ui-icon-flag { background-position: -16px -112px; }
.ui-icon-calendar { background-position: -32px -112px; }
.ui-icon-cart { background-position: -48px -112px; }
.ui-icon-pencil { background-position: -64px -112px; }
.ui-icon-clock { background-position: -80px -112px; }
.ui-icon-disk { background-position: -96px -112px; }
.ui-icon-calculator { background-position: -112px -112px; }
.ui-icon-zoomin { background-position: -128px -112px; }
.ui-icon-zoomout { background-position: -144px -112px; }
.ui-icon-search { background-position: -160px -112px; }
.ui-icon-wrench { background-position: -176px -112px; }
.ui-icon-gear { background-position: -192px -112px; }
.ui-icon-heart { background-position: -208px -112px; }
.ui-icon-star { background-position: -224px -112px; }
.ui-icon-link { background-position: -240px -112px; }
.ui-icon-cancel { background-position: 0 -128px; }
.ui-icon-plus { background-position: -16px -128px; }
.ui-icon-plusthick { background-position: -32px -128px; }
.ui-icon-minus { background-position: -48px -128px; }
.ui-icon-minusthick { background-position: -64px -128px; }
.ui-icon-close { background-position: -80px -128px; }
.ui-icon-closethick { background-position: -96px -128px; }
.ui-icon-key { background-position: -112px -128px; }
.ui-icon-lightbulb { background-position: -128px -128px; }
.ui-icon-scissors { background-position: -144px -128px; }
.ui-icon-clipboard { background-position: -160px -128px; }
.ui-icon-copy { background-position: -176px -128px; }
.ui-icon-contact { background-position: -192px -128px; }
.ui-icon-image { background-position: -208px -128px; }
.ui-icon-video { background-position: -224px -128px; }
.ui-icon-script { background-position: -240px -128px; }
.ui-icon-alert { background-position: 0 -144px; }
.ui-icon-info { background-position: -16px -144px; }
.ui-icon-notice { background-position: -32px -144px; }
.ui-icon-help { background-position: -48px -144px; }
.ui-icon-check { background-position: -64px -144px; }
.ui-icon-bullet { background-position: -80px -144px; }
.ui-icon-radio-off { background-position: -96px -144px; }
.ui-icon-radio-on { background-position: -112px -144px; }
.ui-icon-pin-w { background-position: -128px -144px; }
.ui-icon-pin-s { background-position: -144px -144px; }
.ui-icon-play { background-position: 0 -160px; }
.ui-icon-pause { background-position: -16px -160px; }
.ui-icon-seek-next { background-position: -32px -160px; }
.ui-icon-seek-prev { background-position: -48px -160px; }
.ui-icon-seek-end { background-position: -64px -160px; }
.ui-icon-seek-start { background-position: -80px -160px; }
/* ui-icon-seek-first is deprecated, use ui-icon-seek-start instead */
.ui-icon-seek-first { background-position: -80px -160px; }
.ui-icon-stop { background-position: -96px -160px; }
.ui-icon-eject { background-position: -112px -160px; }
.ui-icon-volume-off { background-position: -128px -160px; }
.ui-icon-volume-on { background-position: -144px -160px; }
.ui-icon-power { background-position: 0 -176px; }
.ui-icon-signal-diag { background-position: -16px -176px; }
.ui-icon-signal { background-position: -32px -176px; }
.ui-icon-battery-0 { background-position: -48px -176px; }
.ui-icon-battery-1 { background-position: -64px -176px; }
.ui-icon-battery-2 { background-position: -80px -176px; }
.ui-icon-battery-3 { background-position: -96px -176px; }
.ui-icon-circle-plus { background-position: 0 -192px; }
.ui-icon-circle-minus { background-position: -16px -192px; }
.ui-icon-circle-close { background-position: -32px -192px; }
.ui-icon-circle-triangle-e { background-position: -48px -192px; }
.ui-icon-circle-triangle-s { background-position: -64px -192px; }
.ui-icon-circle-triangle-w { background-position: -80px -192px; }
.ui-icon-circle-triangle-n { background-position: -96px -192px; }
.ui-icon-circle-arrow-e { background-position: -112px -192px; }
.ui-icon-circle-arrow-s { background-position: -128px -192px; }
.ui-icon-circle-arrow-w { background-position: -144px -192px; }
.ui-icon-circle-arrow-n { background-position: -160px -192px; }
.ui-icon-circle-zoomin { background-position: -176px -192px; }
.ui-icon-circle-zoomout { background-position: -192px -192px; }
.ui-icon-circle-check { background-position: -208px -192px; }
.ui-icon-circlesmall-plus { background-position: 0 -208px; }
.ui-icon-circlesmall-minus { background-position: -16px -208px; }
.ui-icon-circlesmall-close { background-position: -32px -208px; }
.ui-icon-squaresmall-plus { background-position: -48px -208px; }
.ui-icon-squaresmall-minus { background-position: -64px -208px; }
.ui-icon-squaresmall-close { background-position: -80px -208px; }
.ui-icon-grip-dotted-vertical { background-position: 0 -224px; }
.ui-icon-grip-dotted-horizontal { background-position: -16px -224px; }
.ui-icon-grip-solid-vertical { background-position: -32px -224px; }
.ui-icon-grip-solid-horizontal { background-position: -48px -224px; }
.ui-icon-gripsmall-diagonal-se { background-position: -64px -224px; }
.ui-icon-grip-diagonal-se { background-position: -80px -224px; }
/* Misc visuals
----------------------------------*/
/* Corner radius */
.ui-corner-all, .ui-corner-top, .ui-corner-left, .ui-corner-tl { -moz-border-radius-topleft: 4px; -webkit-border-top-left-radius: 4px; -khtml-border-top-left-radius: 4px; border-top-left-radius: 4px; }
.ui-corner-all, .ui-corner-top, .ui-corner-right, .ui-corner-tr { -moz-border-radius-topright: 4px; -webkit-border-top-right-radius: 4px; -khtml-border-top-right-radius: 4px; border-top-right-radius: 4px; }
.ui-corner-all, .ui-corner-bottom, .ui-corner-left, .ui-corner-bl { -moz-border-radius-bottomleft: 4px; -webkit-border-bottom-left-radius: 4px; -khtml-border-bottom-left-radius: 4px; border-bottom-left-radius: 4px; }
.ui-corner-all, .ui-corner-bottom, .ui-corner-right, .ui-corner-br { -moz-border-radius-bottomright: 4px; -webkit-border-bottom-right-radius: 4px; -khtml-border-bottom-right-radius: 4px; border-bottom-right-radius: 4px; }
/* Overlays */
.ui-widget-overlay { background: #aaaaaa url(/media/idf/img/jquery-ui/ui-bg_flat_0_aaaaaa_40x100.png) 50% 50% repeat-x; opacity: .30;filter:Alpha(Opacity=30); }
.ui-widget-shadow { margin: -8px 0 0 -8px; padding: 8px; background: #aaaaaa url(/media/idf/img/jquery-ui/ui-bg_flat_0_aaaaaa_40x100.png) 50% 50% repeat-x; opacity: .30;filter:Alpha(Opacity=30); -moz-border-radius: 8px; -khtml-border-radius: 8px; -webkit-border-radius: 8px; border-radius: 8px; }/*
* jQuery UI Datepicker 1.8.18
*
* Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
* Dual licensed under the MIT or GPL Version 2 licenses.
* http://jquery.org/license
*
* http://docs.jquery.com/UI/Datepicker#theming
*/
.ui-datepicker { width: 17em; padding: .2em .2em 0; display: none; }
.ui-datepicker .ui-datepicker-header { position:relative; padding:.2em 0; }
.ui-datepicker .ui-datepicker-prev, .ui-datepicker .ui-datepicker-next { position:absolute; top: 2px; width: 1.8em; height: 1.8em; }
.ui-datepicker .ui-datepicker-prev-hover, .ui-datepicker .ui-datepicker-next-hover { top: 1px; }
.ui-datepicker .ui-datepicker-prev { left:2px; }
.ui-datepicker .ui-datepicker-next { right:2px; }
.ui-datepicker .ui-datepicker-prev-hover { left:1px; }
.ui-datepicker .ui-datepicker-next-hover { right:1px; }
.ui-datepicker .ui-datepicker-prev span, .ui-datepicker .ui-datepicker-next span { display: block; position: absolute; left: 50%; margin-left: -8px; top: 50%; margin-top: -8px; }
.ui-datepicker .ui-datepicker-title { margin: 0 2.3em; line-height: 1.8em; text-align: center; }
.ui-datepicker .ui-datepicker-title select { font-size:1em; margin:1px 0; }
.ui-datepicker select.ui-datepicker-month-year {width: 100%;}
.ui-datepicker select.ui-datepicker-month,
.ui-datepicker select.ui-datepicker-year { width: 49%;}
.ui-datepicker table {width: 100%; font-size: .9em; border-collapse: collapse; margin:0 0 .4em; }
.ui-datepicker th { padding: .7em .3em; text-align: center; font-weight: bold; border: 0; }
.ui-datepicker td { border: 0; padding: 1px; }
.ui-datepicker td span, .ui-datepicker td a { display: block; padding: .2em; text-align: right; text-decoration: none; }
.ui-datepicker .ui-datepicker-buttonpane { background-image: none; margin: .7em 0 0 0; padding:0 .2em; border-left: 0; border-right: 0; border-bottom: 0; }
.ui-datepicker .ui-datepicker-buttonpane button { float: right; margin: .5em .2em .4em; cursor: pointer; padding: .2em .6em .3em .6em; width:auto; overflow:visible; }
.ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current { float:left; }
/* with multiple calendars */
.ui-datepicker.ui-datepicker-multi { width:auto; }
.ui-datepicker-multi .ui-datepicker-group { float:left; }
.ui-datepicker-multi .ui-datepicker-group table { width:95%; margin:0 auto .4em; }
.ui-datepicker-multi-2 .ui-datepicker-group { width:50%; }
.ui-datepicker-multi-3 .ui-datepicker-group { width:33.3%; }
.ui-datepicker-multi-4 .ui-datepicker-group { width:25%; }
.ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header { border-left-width:0; }
.ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header { border-left-width:0; }
.ui-datepicker-multi .ui-datepicker-buttonpane { clear:left; }
.ui-datepicker-row-break { clear:both; width:100%; font-size:0em; }
/* RTL support */
.ui-datepicker-rtl { direction: rtl; }
.ui-datepicker-rtl .ui-datepicker-prev { right: 2px; left: auto; }
.ui-datepicker-rtl .ui-datepicker-next { left: 2px; right: auto; }
.ui-datepicker-rtl .ui-datepicker-prev:hover { right: 1px; left: auto; }
.ui-datepicker-rtl .ui-datepicker-next:hover { left: 1px; right: auto; }
.ui-datepicker-rtl .ui-datepicker-buttonpane { clear:right; }
.ui-datepicker-rtl .ui-datepicker-buttonpane button { float: left; }
.ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current { float:right; }
.ui-datepicker-rtl .ui-datepicker-group { float:right; }
.ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header { border-right-width:0; border-left-width:1px; }
.ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header { border-right-width:0; border-left-width:1px; }
/* IE6 IFRAME FIX (taken from datepicker 1.5.3 */
.ui-datepicker-cover {
display: none; /*sorry for IE5*/
display/**/: block; /*sorry for IE5*/
position: absolute; /*must have*/
z-index: -1; /*must have*/
filter: mask(); /*must have*/
top: -4px; /*must have*/
left: -4px; /*must have*/
width: 200px; /*must have*/
height: 200px; /*must have*/
}

View File

@@ -184,6 +184,14 @@ table.recent-issues td {
vertical-align: top; vertical-align: top;
} }
table.recent-issues td span.overdue {
font-weight: bold;
background-color: #c00;
color: #fff;
padding: 0 2px;
margin-left: 5px;
}
table.recent-issues tfoot th { table.recent-issues tfoot th {
text-align: right; text-align: right;
} }
@@ -317,6 +325,72 @@ div.issue-submit-info h2 {
margin-top: 0; margin-top: 0;
} }
#due_dtime_wrapper {
float: right;
width: 350px;
position: relative;
padding-left: 0 !important;
}
#due_dtime_shortcut_link {
text-decoration: none;
color: #000;
}
#due_dtime_wrapper > a {
padding-left: 5px;
padding-right: 5px;
margin-top: -3px;
padding-top: 3px;
}
#due_dtime_more_shortcuts {
display: none;
background: #A5E26A;
border-top: 0;
position: absolute;
margin: 1px 0 0;
z-index: 1000;
top: 1.1em;
-moz-border-radius: 0 0 3px 3px;
border-radius: 0 0 3px 3px;
-moz-box-shadow: 0 10px 20px #333;
-webkit-box-shadow: 0 10px 20px #333;
box-shadow: 0 10px 20px #333;
max-height: 400px;
min-width: 145px;
overflow-x: hidden;
overflow-y: auto;
padding: 0 5px 5px;
}
#due_dtime_more_shortcuts dt {
font-weight: bold;
margin-top: 2px;
}
#due_dtime_more_shortcuts dd {
margin-left: 6px;
}
#due_dtime_more_shortcuts a {
text-decoration: none;
padding: 0 2px;
}
#due_dtime_more_shortcuts a:hover {
background: #fff;
}
#due_dtime_wrapper:hover > a {
background: #A5E26A;
text-decoration: none;
}
#due_dtime_wrapper:hover a {
color: #2E3436;
}
span.label { span.label {
color: #204a87; color: #204a87;
padding-left: 0.5em; padding-left: 0.5em;
@@ -610,7 +684,7 @@ span.ctrl-char {
cursor: default; cursor: default;
} }
/* special formatting for the TAB character: make it wider, so it is rendered more properly */ /* special formatting for the TAB character: make it wider, so it is rendered more properly */
span.ctrl-char[title="0x09"] { span.ctrl-char[title="0x09"] {
width: 24px; width: 24px;
} }
@@ -701,7 +775,7 @@ table.diff-linecounts.right-hidden tr > td + td {
table.diff-contents td { table.diff-contents td {
line-height: 12px; line-height: 12px;
padding: 2px; padding: 2px;
font-size: 90%; font-size: 90%;
border: none; border: none;
white-space: pre; white-space: pre;
} }
@@ -723,7 +797,7 @@ table.diff-contents td:hover > span.ctrl-char {
} }
table.diff-contents td.added > span.ctrl-char { table.diff-contents td.added > span.ctrl-char {
background: #0A0; background: #0A0;
} }
table.diff-contents td.removed > span.ctrl-char { table.diff-contents td.removed > span.ctrl-char {
@@ -857,7 +931,7 @@ div.deprecated-page {
} }
li.old-rev { li.old-rev {
font-style: italic; font-style: italic;
} }
.delp { .delp {

Binary file not shown.

After

Width:  |  Height:  |  Size: 180 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 178 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 120 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 105 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 111 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 110 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 119 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 101 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

File diff suppressed because one or more lines are too long

View File

@@ -44,7 +44,7 @@
handleObj.handler = function( event ) { handleObj.handler = function( event ) {
// Don't fire in text-accepting inputs that we didn't directly bind to // Don't fire in text-accepting inputs that we didn't directly bind to
if ( this !== event.target && (/textarea|select/i.test( event.target.nodeName ) || if ( this !== event.target && (/textarea|select|input/i.test( event.target.nodeName ) ||
event.target.type === "text" || $(event.target).prop('contenteditable') == 'true' )) { event.target.type === "text" || $(event.target).prop('contenteditable') == 'true' )) {
return; return;
} }

View File

@@ -1,9 +1,12 @@
$(document).ready(function() { $(document).ready(function() {
$(":header", "#wiki-content").map(function(index) { $(":header", "#wiki-content").map(function(index) {
this.id = "wikititle_" + index; var $header = $(this);
$("<a href='#" + this.id + "'>" + jQuery.fn.text([this]) + "</a>") var $toc = $('#wiki-toc-content');
.addClass("wiki-" + this.tagName.toLowerCase()) $header.attr('id', 'wikititle_' + index);
.appendTo('#wiki-toc-content'); $('<a />').attr('href', '#' + $header.attr('id'))
.text($header.text())
.addClass("wiki-" + $header[0].tagName.toLowerCase())
.appendTo($toc);
}); });
if ($('#wiki-toc-content *').size() < 2) if ($('#wiki-toc-content *').size() < 2)
$('#wiki-toc').hide(); $('#wiki-toc').hide();