Partial fix of issue 55, addition of a simple Wiki.
Added a base wiki, it is now possible to create wiki pages and update them. Revisions are kept also not used/displayed at the moment.
This commit is contained in:
parent
b13633fed2
commit
8eb5715656
@ -36,6 +36,7 @@ class IDF_Form_TabsConf extends Pluf_Form
|
||||
$this->project = $extra['project'];
|
||||
|
||||
$ak = array('downloads_access_rights' => __('Downloads'),
|
||||
'wiki_access_rights' => __('Documentation'),
|
||||
'source_access_rights' => __('Source'),
|
||||
'issues_access_rights' => __('Issues'),);
|
||||
foreach ($ak as $key=>$label) {
|
||||
|
66
src/IDF/Form/WikiConf.php
Normal file
66
src/IDF/Form/WikiConf.php
Normal file
@ -0,0 +1,66 @@
|
||||
<?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 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 ***** */
|
||||
|
||||
|
||||
/**
|
||||
* Configuration of the labels etc. for the wiki pages.
|
||||
*/
|
||||
class IDF_Form_WikiConf extends Pluf_Form
|
||||
{
|
||||
/**
|
||||
* Defined as constants to easily access the value in the
|
||||
* form in the case nothing is in the db yet.
|
||||
*/
|
||||
const init_predefined = 'Featured = Listed on project home page
|
||||
Phase:Requirements = Project vision and requirements
|
||||
Phase:Design = Project design and key concerns
|
||||
Phase:Implementation = Developers\' guide
|
||||
Phase:QA = Testing plans and QA strategies
|
||||
Phase:Deploy = How to install and configure the program
|
||||
Phase:Support = Plans for user support and advocacy
|
||||
Deprecated = Most users should NOT reference this';
|
||||
|
||||
const init_one_max = '';
|
||||
|
||||
public function initFields($extra=array())
|
||||
{
|
||||
$this->fields['labels_wiki_predefined'] = new Pluf_Form_Field_Varchar(
|
||||
array('required' => true,
|
||||
'label' => __('Predefined documentation page labels'),
|
||||
'initial' => self::init_predefined,
|
||||
'widget_attrs' => array('rows' => 13,
|
||||
'cols' => 75),
|
||||
'widget' => 'Pluf_Form_Widget_TextareaInput',
|
||||
));
|
||||
|
||||
$this->fields['labels_wiki_one_max'] = new Pluf_Form_Field_Varchar(
|
||||
array('required' => false,
|
||||
'label' => __('Each documentation page may have at most one label with each of these classes'),
|
||||
'initial' => self::init_one_max,
|
||||
'widget_attrs' => array('size' => 60),
|
||||
));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
203
src/IDF/Form/WikiCreate.php
Normal file
203
src/IDF/Form/WikiCreate.php
Normal file
@ -0,0 +1,203 @@
|
||||
<?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 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 ***** */
|
||||
|
||||
/**
|
||||
* Create a new documentation page.
|
||||
*
|
||||
* This create a new page and the corresponding revision.
|
||||
*
|
||||
*/
|
||||
class IDF_Form_WikiCreate extends Pluf_Form
|
||||
{
|
||||
public $user = null;
|
||||
public $project = null;
|
||||
public $show_full = false;
|
||||
|
||||
public function initFields($extra=array())
|
||||
{
|
||||
$initial = __('# Introduction
|
||||
|
||||
Add your content here.
|
||||
|
||||
|
||||
# Details
|
||||
|
||||
Add your content here. Format your content with:
|
||||
|
||||
* Text in **bold** or *italic*.
|
||||
* Headings, paragraphs, and lists.
|
||||
* Links to other [[WikiPage]].
|
||||
');
|
||||
$this->user = $extra['user'];
|
||||
$this->project = $extra['project'];
|
||||
if ($this->user->hasPerm('IDF.project-owner', $this->project)
|
||||
or $this->user->hasPerm('IDF.project-member', $this->project)) {
|
||||
$this->show_full = true;
|
||||
}
|
||||
$this->fields['title'] = new Pluf_Form_Field_Varchar(
|
||||
array('required' => true,
|
||||
'label' => __('Page title'),
|
||||
'initial' => __('PageName'),
|
||||
'widget_attrs' => array(
|
||||
'maxlength' => 200,
|
||||
'size' => 67,
|
||||
),
|
||||
'help_text' => __('The page name must contains only letters, digits and the dash (-) character.'),
|
||||
));
|
||||
$this->fields['summary'] = new Pluf_Form_Field_Varchar(
|
||||
array('required' => true,
|
||||
'label' => __('Description'),
|
||||
'help_text' => __('This one line description is displayed in the list of pages.'),
|
||||
'initial' => '',
|
||||
'widget_attrs' => array(
|
||||
'maxlength' => 200,
|
||||
'size' => 67,
|
||||
),
|
||||
));
|
||||
$this->fields['content'] = new Pluf_Form_Field_Varchar(
|
||||
array('required' => true,
|
||||
'label' => __('Content'),
|
||||
'initial' => $initial,
|
||||
'widget' => 'Pluf_Form_Widget_TextareaInput',
|
||||
'widget_attrs' => array(
|
||||
'cols' => 58,
|
||||
'rows' => 26,
|
||||
),
|
||||
));
|
||||
|
||||
if ($this->show_full) {
|
||||
for ($i=1;$i<4;$i++) {
|
||||
$this->fields['label'.$i] = new Pluf_Form_Field_Varchar(
|
||||
array('required' => false,
|
||||
'label' => __('Labels'),
|
||||
'initial' => '',
|
||||
'widget_attrs' => array(
|
||||
'maxlength' => 50,
|
||||
'size' => 20,
|
||||
),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function clean_title()
|
||||
{
|
||||
$title = $this->cleaned_data['title'];
|
||||
if (preg_match('/[^a-zA-Z0-9\-]/', $title)) {
|
||||
throw new Pluf_Form_Invalid(__('The title contains invalid characters.'));
|
||||
}
|
||||
$sql = new Pluf_SQL('project=%s AND title=%s',
|
||||
array($this->project->id, $title));
|
||||
$pages = Pluf::factory('IDF_WikiPage')->getList(array('filter'=>$sql->gen()));
|
||||
if ($pages->count() > 0) {
|
||||
throw new Pluf_Form_Invalid(__('A page with this title already exists.'));
|
||||
}
|
||||
return $title;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the interconnection in the form.
|
||||
*/
|
||||
public function clean()
|
||||
{
|
||||
if (!$this->show_full) {
|
||||
return $this->cleaned_data;
|
||||
}
|
||||
$conf = new IDF_Conf();
|
||||
$conf->setProject($this->project);
|
||||
$onemax = array();
|
||||
foreach (split(',', $conf->getVal('labels_wiki_one_max', IDF_Form_WikiConf::init_one_max)) as $class) {
|
||||
if (trim($class) != '') {
|
||||
$onemax[] = mb_strtolower(trim($class));
|
||||
}
|
||||
}
|
||||
$count = array();
|
||||
for ($i=1;$i<4;$i++) {
|
||||
$this->cleaned_data['label'.$i] = trim($this->cleaned_data['label'.$i]);
|
||||
if (strpos($this->cleaned_data['label'.$i], ':') !== false) {
|
||||
list($class, $name) = explode(':', $this->cleaned_data['label'.$i], 2);
|
||||
list($class, $name) = array(mb_strtolower(trim($class)),
|
||||
trim($name));
|
||||
} else {
|
||||
$class = 'other';
|
||||
$name = $this->cleaned_data['label'.$i];
|
||||
}
|
||||
if (!isset($count[$class])) $count[$class] = 1;
|
||||
else $count[$class] += 1;
|
||||
if (in_array($class, $onemax) and $count[$class] > 1) {
|
||||
if (!isset($this->errors['label'.$i])) $this->errors['label'.$i] = array();
|
||||
$this->errors['label'.$i][] = sprintf(__('You cannot provide more than label from the %s class to a page.'), $class);
|
||||
throw new Pluf_Form_Invalid(__('You provided an invalid label.'));
|
||||
}
|
||||
}
|
||||
return $this->cleaned_data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Save the model in the database.
|
||||
*
|
||||
* @param bool Commit in the database or not. If not, the object
|
||||
* is returned but not saved in the database.
|
||||
* @return Object Model with data set from the form.
|
||||
*/
|
||||
function save($commit=true)
|
||||
{
|
||||
if (!$this->isValid()) {
|
||||
throw new Exception(__('Cannot save the model from an invalid form.'));
|
||||
}
|
||||
// Add a tag for each label
|
||||
$tags = array();
|
||||
if ($this->show_full) {
|
||||
for ($i=1;$i<4;$i++) {
|
||||
if (strlen($this->cleaned_data['label'.$i]) > 0) {
|
||||
if (strpos($this->cleaned_data['label'.$i], ':') !== false) {
|
||||
list($class, $name) = explode(':', $this->cleaned_data['label'.$i], 2);
|
||||
list($class, $name) = array(trim($class), trim($name));
|
||||
} else {
|
||||
$class = 'Other';
|
||||
$name = trim($this->cleaned_data['label'.$i]);
|
||||
}
|
||||
$tags[] = IDF_Tag::add($name, $this->project, $class);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Create the page
|
||||
$page = new IDF_WikiPage();
|
||||
$page->project = $this->project;
|
||||
$page->submitter = $this->user;
|
||||
$page->summary = trim($this->cleaned_data['summary']);
|
||||
$page->title = trim($this->cleaned_data['title']);
|
||||
$page->create();
|
||||
foreach ($tags as $tag) {
|
||||
$page->setAssoc($tag);
|
||||
}
|
||||
// add the first revision
|
||||
$rev = new IDF_WikiRevision();
|
||||
$rev->wikipage = $page;
|
||||
$rev->content = $this->cleaned_data['content'];
|
||||
$rev->submitter = $this->user;
|
||||
$rev->summary = __('Initial page creation');
|
||||
$rev->create();
|
||||
return $page;
|
||||
}
|
||||
}
|
241
src/IDF/Form/WikiUpdate.php
Normal file
241
src/IDF/Form/WikiUpdate.php
Normal file
@ -0,0 +1,241 @@
|
||||
<?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 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 ***** */
|
||||
|
||||
/**
|
||||
* Update a documentation page.
|
||||
*
|
||||
* This add a corresponding revision.
|
||||
*
|
||||
*/
|
||||
class IDF_Form_WikiUpdate extends Pluf_Form
|
||||
{
|
||||
public $user = null;
|
||||
public $project = null;
|
||||
public $page = null;
|
||||
public $show_full = false;
|
||||
|
||||
|
||||
public function initFields($extra=array())
|
||||
{
|
||||
$this->page = $extra['page'];
|
||||
$this->user = $extra['user'];
|
||||
$this->project = $extra['project'];
|
||||
if ($this->user->hasPerm('IDF.project-owner', $this->project)
|
||||
or $this->user->hasPerm('IDF.project-member', $this->project)) {
|
||||
$this->show_full = true;
|
||||
}
|
||||
if ($this->show_full) {
|
||||
$this->fields['title'] = new Pluf_Form_Field_Varchar(
|
||||
array('required' => true,
|
||||
'label' => __('Page title'),
|
||||
'initial' => $this->page->title,
|
||||
'widget_attrs' => array(
|
||||
'maxlength' => 200,
|
||||
'size' => 67,
|
||||
),
|
||||
'help_text' => __('The page name must contains only letters, digits and the dash (-) character.'),
|
||||
));
|
||||
$this->fields['summary'] = new Pluf_Form_Field_Varchar(
|
||||
array('required' => true,
|
||||
'label' => __('Description'),
|
||||
'help_text' => __('This one line description is displayed in the list of pages.'),
|
||||
'initial' => $this->page->summary,
|
||||
'widget_attrs' => array(
|
||||
'maxlength' => 200,
|
||||
'size' => 67,
|
||||
),
|
||||
));
|
||||
}
|
||||
$rev = $this->page->get_current_revision();
|
||||
$this->fields['content'] = new Pluf_Form_Field_Varchar(
|
||||
array('required' => true,
|
||||
'label' => __('Content'),
|
||||
'initial' => $rev->content,
|
||||
'widget' => 'Pluf_Form_Widget_TextareaInput',
|
||||
'widget_attrs' => array(
|
||||
'cols' => 58,
|
||||
'rows' => 26,
|
||||
),
|
||||
));
|
||||
$this->fields['comment'] = new Pluf_Form_Field_Varchar(
|
||||
array('required' => true,
|
||||
'label' => __('Comment'),
|
||||
'help_text' => __('One line to describe the changes you made.'),
|
||||
'initial' => '',
|
||||
'widget_attrs' => array(
|
||||
'maxlength' => 200,
|
||||
'size' => 67,
|
||||
),
|
||||
));
|
||||
|
||||
if ($this->show_full) {
|
||||
$tags = $this->page->get_tags_list();
|
||||
for ($i=1;$i<4;$i++) {
|
||||
$initial = '';
|
||||
if (isset($tags[$i-1])) {
|
||||
if ($tags[$i-1]->class != 'Other') {
|
||||
$initial = (string) $tags[$i-1];
|
||||
} else {
|
||||
$initial = $tags[$i-1]->name;
|
||||
}
|
||||
}
|
||||
$this->fields['label'.$i] = new Pluf_Form_Field_Varchar(
|
||||
array('required' => false,
|
||||
'label' => __('Labels'),
|
||||
'initial' => $initial,
|
||||
'widget_attrs' => array(
|
||||
'maxlength' => 50,
|
||||
'size' => 20,
|
||||
),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function clean_title()
|
||||
{
|
||||
$title = $this->cleaned_data['title'];
|
||||
if (preg_match('/[^a-zA-Z0-9\-]/', $title)) {
|
||||
throw new Pluf_Form_Invalid(__('The title contains invalid characters.'));
|
||||
}
|
||||
$sql = new Pluf_SQL('project=%s AND title=%s',
|
||||
array($this->project->id, $title));
|
||||
$pages = Pluf::factory('IDF_WikiPage')->getList(array('filter'=>$sql->gen()));
|
||||
if ($pages->count() > 0 and $pages[0]->id != $this->page->id) {
|
||||
throw new Pluf_Form_Invalid(__('A page with this title already exists.'));
|
||||
}
|
||||
return $title;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the interconnection in the form.
|
||||
*/
|
||||
public function clean()
|
||||
{
|
||||
if (!$this->show_full) {
|
||||
return $this->cleaned_data;
|
||||
}
|
||||
$conf = new IDF_Conf();
|
||||
$conf->setProject($this->project);
|
||||
$onemax = array();
|
||||
foreach (split(',', $conf->getVal('labels_wiki_one_max', IDF_Form_WikiConf::init_one_max)) as $class) {
|
||||
if (trim($class) != '') {
|
||||
$onemax[] = mb_strtolower(trim($class));
|
||||
}
|
||||
}
|
||||
$count = array();
|
||||
for ($i=1;$i<4;$i++) {
|
||||
$this->cleaned_data['label'.$i] = trim($this->cleaned_data['label'.$i]);
|
||||
if (strpos($this->cleaned_data['label'.$i], ':') !== false) {
|
||||
list($class, $name) = explode(':', $this->cleaned_data['label'.$i], 2);
|
||||
list($class, $name) = array(mb_strtolower(trim($class)),
|
||||
trim($name));
|
||||
} else {
|
||||
$class = 'other';
|
||||
$name = $this->cleaned_data['label'.$i];
|
||||
}
|
||||
if (!isset($count[$class])) $count[$class] = 1;
|
||||
else $count[$class] += 1;
|
||||
if (in_array($class, $onemax) and $count[$class] > 1) {
|
||||
if (!isset($this->errors['label'.$i])) $this->errors['label'.$i] = array();
|
||||
$this->errors['label'.$i][] = sprintf(__('You cannot provide more than label from the %s class to a page.'), $class);
|
||||
throw new Pluf_Form_Invalid(__('You provided an invalid label.'));
|
||||
}
|
||||
}
|
||||
return $this->cleaned_data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Save the model in the database.
|
||||
*
|
||||
* @param bool Commit in the database or not. If not, the object
|
||||
* is returned but not saved in the database.
|
||||
* @return Object Model with data set from the form.
|
||||
*/
|
||||
function save($commit=true)
|
||||
{
|
||||
if (!$this->isValid()) {
|
||||
throw new Exception(__('Cannot save the model from an invalid form.'));
|
||||
}
|
||||
if ($this->show_full) {
|
||||
$tagids = array();
|
||||
$tags = array();
|
||||
for ($i=1;$i<4;$i++) {
|
||||
if (strlen($this->cleaned_data['label'.$i]) > 0) {
|
||||
if (strpos($this->cleaned_data['label'.$i], ':') !== false) {
|
||||
list($class, $name) = explode(':', $this->cleaned_data['label'.$i], 2);
|
||||
list($class, $name) = array(trim($class), trim($name));
|
||||
} else {
|
||||
$class = 'Other';
|
||||
$name = trim($this->cleaned_data['label'.$i]);
|
||||
}
|
||||
$tag = IDF_Tag::add($name, $this->project, $class);
|
||||
$tags[] = $tag;
|
||||
$tagids[] = $tag->id;
|
||||
}
|
||||
}
|
||||
// Compare between the old and the new data
|
||||
$changes = array();
|
||||
$oldtags = $this->page->get_tags_list();
|
||||
foreach ($tags as $tag) {
|
||||
if (!Pluf_Model_InArray($tag, $oldtags)) {
|
||||
if (!isset($changes['lb'])) $changes['lb'] = array();
|
||||
if ($tag->class != 'Other') {
|
||||
$changes['lb'][] = (string) $tag; //new tag
|
||||
} else {
|
||||
$changes['lb'][] = (string) $tag->name;
|
||||
}
|
||||
}
|
||||
}
|
||||
foreach ($oldtags as $tag) {
|
||||
if (!Pluf_Model_InArray($tag, $tags)) {
|
||||
if (!isset($changes['lb'])) $changes['lb'] = array();
|
||||
if ($tag->class != 'Other') {
|
||||
$changes['lb'][] = '-'.(string) $tag; //new tag
|
||||
} else {
|
||||
$changes['lb'][] = '-'.(string) $tag->name;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (trim($this->page->summary) != trim($this->cleaned_data['summary'])) {
|
||||
$changes['su'] = trim($this->cleaned_data['summary']);
|
||||
}
|
||||
// Update the page
|
||||
$this->page->batchAssoc('IDF_Tag', $tagids);
|
||||
$this->page->summary = trim($this->cleaned_data['summary']);
|
||||
$this->page->title = trim($this->cleaned_data['title']);
|
||||
} else {
|
||||
$changes = array();
|
||||
}
|
||||
$this->page->update();
|
||||
// add the new revision
|
||||
$rev = new IDF_WikiRevision();
|
||||
$rev->wikipage = $this->page;
|
||||
$rev->content = $this->cleaned_data['content'];
|
||||
$rev->submitter = $this->user;
|
||||
$rev->summary = $this->cleaned_data['comment'];
|
||||
$rev->changes = $changes;
|
||||
$rev->create();
|
||||
return $this->page;
|
||||
}
|
||||
}
|
@ -53,6 +53,7 @@ class IDF_Middleware
|
||||
$request->conf = new IDF_Conf();
|
||||
$request->conf->setProject($request->project);
|
||||
$ak = array('downloads_access_rights' => 'hasDownloadsAccess',
|
||||
'wiki_access_rights' => 'hasWikiAccess',
|
||||
'source_access_rights' => 'hasSourceAccess',
|
||||
'issues_access_rights' => 'hasIssuesAccess');
|
||||
$request->rights = array();
|
||||
|
54
src/IDF/Migrations/7Wiki.php
Normal file
54
src/IDF/Migrations/7Wiki.php
Normal file
@ -0,0 +1,54 @@
|
||||
<?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 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 download of files.
|
||||
*/
|
||||
|
||||
function IDF_Migrations_7Wiki_up($params=null)
|
||||
{
|
||||
$models = array(
|
||||
'IDF_WikiPage',
|
||||
'IDF_WikiRevision',
|
||||
);
|
||||
$db = Pluf::db();
|
||||
$schema = new Pluf_DB_Schema($db);
|
||||
foreach ($models as $model) {
|
||||
$schema->model = new $model();
|
||||
$schema->createTables();
|
||||
}
|
||||
}
|
||||
|
||||
function IDF_Migrations_7Wiki_down($params=null)
|
||||
{
|
||||
$models = array(
|
||||
'IDF_WikiRevision',
|
||||
'IDF_WikiPage',
|
||||
);
|
||||
$db = Pluf::db();
|
||||
$schema = new Pluf_DB_Schema($db);
|
||||
foreach ($models as $model) {
|
||||
$schema->model = new $model();
|
||||
$schema->dropTables();
|
||||
}
|
||||
}
|
@ -40,6 +40,8 @@ function IDF_Migrations_Install_setup($params=null)
|
||||
'IDF_IssueFile',
|
||||
'IDF_Commit',
|
||||
'IDF_Timeline',
|
||||
'IDF_WikiPage',
|
||||
'IDF_WikiRevision',
|
||||
);
|
||||
$db = Pluf::db();
|
||||
$schema = new Pluf_DB_Schema($db);
|
||||
@ -69,6 +71,8 @@ function IDF_Migrations_Install_teardown($params=null)
|
||||
$perm = Pluf_Permission::getFromString('IDF.project-owner');
|
||||
if ($perm) $perm->delete();
|
||||
$models = array(
|
||||
'IDF_WikiRevision',
|
||||
'IDF_WikiPage',
|
||||
'IDF_Timeline',
|
||||
'IDF_IssueFile',
|
||||
'IDF_Search_Occ',
|
||||
|
@ -143,6 +143,15 @@ class IDF_Precondition
|
||||
return self::accessTabGeneric($request, 'downloads_access_rights');
|
||||
}
|
||||
|
||||
static public function accessWiki($request)
|
||||
{
|
||||
$res = self::baseAccess($request);
|
||||
if (true !== $res) {
|
||||
return $res;
|
||||
}
|
||||
return self::accessTabGeneric($request, 'wiki_access_rights');
|
||||
}
|
||||
|
||||
/**
|
||||
* Based on the request, it is automatically setting the user.
|
||||
*
|
||||
|
@ -283,10 +283,9 @@ class IDF_Project extends Pluf_Model
|
||||
/**
|
||||
* Generate the tag clouds.
|
||||
*
|
||||
* Return an array of tags sorted class, then name. Each tag get
|
||||
* the extra property 'nb_use' for the number of use in the
|
||||
* project. For issues, only open issues are used to generate the
|
||||
* cloud.
|
||||
* Return an array of tags sorted by class, then name. Each tag
|
||||
* get the extra property 'nb_use' for the number of use in the
|
||||
* project.
|
||||
*
|
||||
* @param string ('issues') 'closed_issues' or 'downloads'
|
||||
* @return ArrayObject of IDF_Tag
|
||||
|
@ -32,13 +32,13 @@ class IDF_Template_IssueComment extends Pluf_Template_Tag
|
||||
private $request = null;
|
||||
private $scm = null;
|
||||
|
||||
function start($text, $request, $echo=true, $wordwrap=true)
|
||||
function start($text, $request, $echo=true, $wordwrap=true, $esc=true)
|
||||
{
|
||||
$this->project = $request->project;
|
||||
$this->request = $request;
|
||||
$this->scm = IDF_Scm::get($request);
|
||||
if ($wordwrap) $text = wordwrap($text, 69, "\n", true);
|
||||
$text = Pluf_esc($text);
|
||||
if ($esc) $text = Pluf_esc($text);
|
||||
$text = ereg_replace('[[:alpha:]]+://[^<>[:space:]]+[[:alnum:]/]',
|
||||
'<a href="\\0" rel="nofollow">\\0</a>',
|
||||
$text);
|
||||
|
@ -23,80 +23,55 @@
|
||||
|
||||
Pluf::loadFunction('Pluf_Text_MarkDown_parse');
|
||||
|
||||
function IDF_Template_Markdown_filter($mdtext)
|
||||
/**
|
||||
* Make the links to issues and commits.
|
||||
*/
|
||||
class IDF_Template_Markdown extends Pluf_Template_Tag
|
||||
{
|
||||
$filter = new IDF_Template_Markdown();
|
||||
return Pluf_Template::markSafe(Pluf_Text_MarkDown_parse($filter->go($mdtext)));
|
||||
private $project = null;
|
||||
private $request = null;
|
||||
private $scm = null;
|
||||
|
||||
function start($text, $request)
|
||||
{
|
||||
$this->project = $request->project;
|
||||
$this->request = $request;
|
||||
$filter = new IDF_Template_MarkdownPrefilter();
|
||||
$text = $filter->go($text);
|
||||
// The filter has replace < and > also in the code blocks so
|
||||
// we need to revert them
|
||||
$tmp = array();
|
||||
foreach (preg_split("/\015\012|\015|\012/", $text, -1) as $s) {
|
||||
if (0 === strpos($s, ' ')) {
|
||||
$s = str_replace(array('<', '>'),
|
||||
array('<', '>'), $s);
|
||||
}
|
||||
$tmp[] = $s;
|
||||
}
|
||||
$text = implode("\n", $tmp);
|
||||
// Replace like in the issue text
|
||||
$tag = new IDF_Template_IssueComment();
|
||||
$text = $tag->start($text, $request, false, false, false);
|
||||
// Replace [[PageName]] with corresponding link to the page.
|
||||
// if not the right to see the
|
||||
$text = preg_replace_callback('#\[\[([A-Za-z0-9\-]+)\]\]#im',
|
||||
array($this, 'callbackWikiPage'),
|
||||
$text);
|
||||
echo Pluf_Text_MarkDown_parse($text);
|
||||
}
|
||||
|
||||
function callbackWikiPage($m)
|
||||
{
|
||||
$sql = new Pluf_SQL('project=%s AND title=%s',
|
||||
array($this->project->id, $m[1]));
|
||||
$pages = Pluf::factory('IDF_WikiPage')->getList(array('filter'=>$sql->gen()));
|
||||
if ($pages->count() != 1) {
|
||||
return $m[0];
|
||||
}
|
||||
if (!$this->request->rights['hasWikiAccess']) {
|
||||
return $m[1];
|
||||
}
|
||||
return '<a href="'.Pluf_HTTP_URL_urlForView('IDF_Views_Wiki::view', array($this->project->shortname, $pages[0]->title)).'" title="'.Pluf_esc($pages[0]->summary).'">'.$m[1].'</a>';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Strict class to only allow entities.
|
||||
*/
|
||||
class IDF_Template_Markdown extends Pluf_Text_HTML_Filter
|
||||
{
|
||||
public $allowed = array();
|
||||
public $always_close = array();
|
||||
public $remove_blanks = array();
|
||||
public $allowed_entities = array(
|
||||
'amp',
|
||||
'gt',
|
||||
'lt',
|
||||
'quot',
|
||||
'nbsp',
|
||||
'ndash',
|
||||
'rdquo',
|
||||
'ldquo',
|
||||
'Alpha',
|
||||
'Beta',
|
||||
'Gamma',
|
||||
'Delta',
|
||||
'Epsilon',
|
||||
'Zeta',
|
||||
'Eta',
|
||||
'Theta',
|
||||
'Iota',
|
||||
'Kappa',
|
||||
'Lambda',
|
||||
'Mu',
|
||||
'Nu',
|
||||
'Xi',
|
||||
'Omicron',
|
||||
'Pi',
|
||||
'Rho',
|
||||
'Sigma',
|
||||
'Tau',
|
||||
'Upsilon',
|
||||
'Phi',
|
||||
'Chi',
|
||||
'Psi',
|
||||
'Omega',
|
||||
'alpha',
|
||||
'beta',
|
||||
'gamma',
|
||||
'delta',
|
||||
'epsilon',
|
||||
'zeta',
|
||||
'eta',
|
||||
'theta',
|
||||
'iota',
|
||||
'kappa',
|
||||
'lambda',
|
||||
'mu',
|
||||
'nu',
|
||||
'xi',
|
||||
'omicron',
|
||||
'pi',
|
||||
'rho',
|
||||
'sigmaf',
|
||||
'sigma',
|
||||
'tau',
|
||||
'upsilon',
|
||||
'phi',
|
||||
'chi',
|
||||
'psi',
|
||||
'omega',
|
||||
'thetasym',
|
||||
'upsih',
|
||||
'piv',
|
||||
);
|
||||
}
|
||||
|
94
src/IDF/Template/MarkdownPrefilter.php
Normal file
94
src/IDF/Template/MarkdownPrefilter.php
Normal file
@ -0,0 +1,94 @@
|
||||
<?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 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 ***** */
|
||||
|
||||
/**
|
||||
* Strict class to only allow entities.
|
||||
*/
|
||||
class IDF_Template_MarkdownPrefilter extends Pluf_Text_HTML_Filter
|
||||
{
|
||||
public $allowed = array();
|
||||
public $always_close = array();
|
||||
public $remove_blanks = array();
|
||||
public $allowed_entities = array(
|
||||
'amp',
|
||||
'gt',
|
||||
'lt',
|
||||
'quot',
|
||||
'nbsp',
|
||||
'ndash',
|
||||
'rdquo',
|
||||
'ldquo',
|
||||
'Alpha',
|
||||
'Beta',
|
||||
'Gamma',
|
||||
'Delta',
|
||||
'Epsilon',
|
||||
'Zeta',
|
||||
'Eta',
|
||||
'Theta',
|
||||
'Iota',
|
||||
'Kappa',
|
||||
'Lambda',
|
||||
'Mu',
|
||||
'Nu',
|
||||
'Xi',
|
||||
'Omicron',
|
||||
'Pi',
|
||||
'Rho',
|
||||
'Sigma',
|
||||
'Tau',
|
||||
'Upsilon',
|
||||
'Phi',
|
||||
'Chi',
|
||||
'Psi',
|
||||
'Omega',
|
||||
'alpha',
|
||||
'beta',
|
||||
'gamma',
|
||||
'delta',
|
||||
'epsilon',
|
||||
'zeta',
|
||||
'eta',
|
||||
'theta',
|
||||
'iota',
|
||||
'kappa',
|
||||
'lambda',
|
||||
'mu',
|
||||
'nu',
|
||||
'xi',
|
||||
'omicron',
|
||||
'pi',
|
||||
'rho',
|
||||
'sigmaf',
|
||||
'sigma',
|
||||
'tau',
|
||||
'upsilon',
|
||||
'phi',
|
||||
'chi',
|
||||
'psi',
|
||||
'omega',
|
||||
'thetasym',
|
||||
'upsih',
|
||||
'piv',
|
||||
);
|
||||
}
|
@ -81,6 +81,10 @@ class IDF_Views_Project
|
||||
if (true === IDF_Precondition::accessDownloads($request)) {
|
||||
$rights[] = '\'IDF_Upload\'';
|
||||
}
|
||||
if (true === IDF_Precondition::accessWiki($request)) {
|
||||
$rights[] = '\'IDF_WikiPage\'';
|
||||
$rights[] = '\'IDF_WikiRevision\'';
|
||||
}
|
||||
if (count($rights) == 0) {
|
||||
$rights[] = '\'IDF_Dummy\'';
|
||||
}
|
||||
@ -233,6 +237,49 @@ class IDF_Views_Project
|
||||
$request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Administrate the information pages of a project.
|
||||
*/
|
||||
public $adminWiki_precond = array('IDF_Precondition::projectOwner');
|
||||
public function adminWiki($request, $match)
|
||||
{
|
||||
$prj = $request->project;
|
||||
$title = sprintf(__('%s Documentation Configuration'), (string) $prj);
|
||||
$conf = new IDF_Conf();
|
||||
$conf->setProject($prj);
|
||||
if ($request->method == 'POST') {
|
||||
$form = new IDF_Form_WikiConf($request->POST);
|
||||
if ($form->isValid()) {
|
||||
foreach ($form->cleaned_data as $key=>$val) {
|
||||
$conf->setVal($key, $val);
|
||||
}
|
||||
$request->user->setMessage(__('The documentation configuration has been saved.'));
|
||||
$url = Pluf_HTTP_URL_urlForView('IDF_Views_Project::adminDownloads',
|
||||
array($prj->shortname));
|
||||
return new Pluf_HTTP_Response_Redirect($url);
|
||||
}
|
||||
} else {
|
||||
$params = array();
|
||||
$keys = array('labels_wiki_predefined', 'labels_wiki_one_max');
|
||||
foreach ($keys as $key) {
|
||||
$_val = $conf->getVal($key, false);
|
||||
if ($_val !== false) {
|
||||
$params[$key] = $_val;
|
||||
}
|
||||
}
|
||||
if (count($params) == 0) {
|
||||
$params = null; //Nothing in the db, so new form.
|
||||
}
|
||||
$form = new IDF_Form_WikiConf($params);
|
||||
}
|
||||
return Pluf_Shortcuts_RenderToResponse('idf/admin/wiki.html',
|
||||
array(
|
||||
'page_title' => $title,
|
||||
'form' => $form,
|
||||
),
|
||||
$request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Administrate the members of a project.
|
||||
*/
|
||||
@ -292,7 +339,8 @@ class IDF_Views_Project
|
||||
} else {
|
||||
$params = array();
|
||||
$keys = array('downloads_access_rights', 'source_access_rights',
|
||||
'issues_access_rights', 'private_project');
|
||||
'issues_access_rights', 'private_project',
|
||||
'wiki_access_rights');
|
||||
foreach ($keys as $key) {
|
||||
$_val = $request->conf->getVal($key, false);
|
||||
if ($_val !== false) {
|
||||
|
279
src/IDF/Views/Wiki.php
Normal file
279
src/IDF/Views/Wiki.php
Normal file
@ -0,0 +1,279 @@
|
||||
<?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 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 ***** */
|
||||
|
||||
Pluf::loadFunction('Pluf_HTTP_URL_urlForView');
|
||||
Pluf::loadFunction('Pluf_Shortcuts_RenderToResponse');
|
||||
Pluf::loadFunction('Pluf_Shortcuts_GetObjectOr404');
|
||||
Pluf::loadFunction('Pluf_Shortcuts_GetFormForModel');
|
||||
|
||||
/**
|
||||
* Documentation pages views.
|
||||
*/
|
||||
class IDF_Views_Wiki
|
||||
{
|
||||
/**
|
||||
* View list of issues for a given project.
|
||||
*/
|
||||
public $index_precond = array('IDF_Precondition::accessWiki');
|
||||
public function index($request, $match, $api=false)
|
||||
{
|
||||
$prj = $request->project;
|
||||
$title = sprintf(__('%s Documentation'), (string) $prj);
|
||||
// Paginator to paginate the pages
|
||||
$pag = new Pluf_Paginator(new IDF_WikiPage());
|
||||
$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 documentation pages.');
|
||||
$pag->action = array('IDF_Views_Wiki::index', array($prj->shortname));
|
||||
$pag->edit_action = array('IDF_Views_Wiki::view', 'shortname', 'title');
|
||||
$sql = 'project=%s';
|
||||
$ptags = self::getWikiTags($prj);
|
||||
$dtag = array_pop($ptags); // The last tag is the deprecated tag.
|
||||
$ids = self::getDeprecatedPagesIds($prj, $dtag);
|
||||
if (count($ids)) {
|
||||
$sql .= ' AND id NOT IN ('.implode(',', $ids).')';
|
||||
}
|
||||
$pag->forced_where = new Pluf_SQL($sql, array($prj->id));
|
||||
$list_display = array(
|
||||
'title' => __('Page Title'),
|
||||
array('summary', 'IDF_Views_Wiki_SummaryAndLabels', __('Summary')),
|
||||
array('modif_dtime', 'Pluf_Paginator_DateYMD', __('Updated')),
|
||||
);
|
||||
$pag->configure($list_display, array(), array('title', 'modif_dtime'));
|
||||
$pag->items_per_page = 25;
|
||||
$pag->no_results_text = __('No documentation pages were found.');
|
||||
$pag->sort_order = array('title', 'ASC');
|
||||
$pag->setFromRequest($request);
|
||||
//$tags = $prj->getTagCloud('downloads');
|
||||
return Pluf_Shortcuts_RenderToResponse('idf/wiki/index.html',
|
||||
array(
|
||||
'page_title' => $title,
|
||||
'pages' => $pag,
|
||||
//'tags' => $tags,
|
||||
'deprecated' => count($ids),
|
||||
'dlabel' => $dtag,
|
||||
),
|
||||
$request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new documentation page.
|
||||
*/
|
||||
public $create_precond = array('IDF_Precondition::accessWiki',
|
||||
'Pluf_Precondition::loginRequired');
|
||||
public function create($request, $match)
|
||||
{
|
||||
$prj = $request->project;
|
||||
$title = __('New Page');
|
||||
$preview = false;
|
||||
if ($request->method == 'POST') {
|
||||
$form = new IDF_Form_WikiCreate($request->POST,
|
||||
array('project' => $prj,
|
||||
'user' => $request->user
|
||||
));
|
||||
if ($form->isValid() and !isset($request->POST['preview'])) {
|
||||
$page = $form->save();
|
||||
$urlpage = Pluf_HTTP_URL_urlForView('IDF_Views_Wiki::view',
|
||||
array($prj->shortname, $page->title));
|
||||
$request->user->setMessage(sprintf(__('The page <a href="%s">%s</a> has been created.'), $urlpage, Pluf_esc($page->title)));
|
||||
$url = Pluf_HTTP_URL_urlForView('IDF_Views_Wiki::index',
|
||||
array($prj->shortname));
|
||||
return new Pluf_HTTP_Response_Redirect($url);
|
||||
} elseif (isset($request->POST['preview'])) {
|
||||
$preview = $request->POST['content'];
|
||||
}
|
||||
} else {
|
||||
$form = new IDF_Form_WikiCreate(null,
|
||||
array('project' => $prj,
|
||||
'user' => $request->user));
|
||||
}
|
||||
return Pluf_Shortcuts_RenderToResponse('idf/wiki/create.html',
|
||||
array(
|
||||
'auto_labels' => self::autoCompleteArrays($prj),
|
||||
'page_title' => $title,
|
||||
'form' => $form,
|
||||
'preview' => $preview,
|
||||
),
|
||||
$request);
|
||||
}
|
||||
|
||||
/**
|
||||
* View a documentation page.
|
||||
*/
|
||||
public $view_precond = array('IDF_Precondition::accessWiki');
|
||||
public function view($request, $match)
|
||||
{
|
||||
$prj = $request->project;
|
||||
// Find the page
|
||||
$sql = new Pluf_SQL('project=%s AND title=%s',
|
||||
array($prj->id, $match[2]));
|
||||
$pages = Pluf::factory('IDF_WikiPage')->getList(array('filter'=>$sql->gen()));
|
||||
if ($pages->count() != 1) {
|
||||
throw new Pluf_HTTP_Error404($request);
|
||||
}
|
||||
$page = $pages[0];
|
||||
$title = $page->title;
|
||||
$revision = $page->get_current_revision();
|
||||
return Pluf_Shortcuts_RenderToResponse('idf/wiki/view.html',
|
||||
array(
|
||||
'page_title' => $title,
|
||||
'page' => $page,
|
||||
'rev' => $revision,
|
||||
'tags' => $page->get_tags_list(),
|
||||
),
|
||||
$request);
|
||||
}
|
||||
|
||||
/**
|
||||
* View a documentation page.
|
||||
*/
|
||||
public $update_precond = array('IDF_Precondition::accessWiki',
|
||||
'Pluf_Precondition::loginRequired');
|
||||
public function update($request, $match)
|
||||
{
|
||||
$prj = $request->project;
|
||||
// Find the page
|
||||
$sql = new Pluf_SQL('project=%s AND title=%s',
|
||||
array($prj->id, $match[2]));
|
||||
$pages = Pluf::factory('IDF_WikiPage')->getList(array('filter'=>$sql->gen()));
|
||||
if ($pages->count() != 1) {
|
||||
throw new Pluf_HTTP_Error404($request);
|
||||
}
|
||||
$page = $pages[0];
|
||||
$title = sprintf(__('Update %s'), $page->title);
|
||||
$revision = $page->get_current_revision();
|
||||
$preview = false;
|
||||
$params = array('project' => $prj,
|
||||
'user' => $request->user,
|
||||
'page' => $page);
|
||||
if ($request->method == 'POST') {
|
||||
$form = new IDF_Form_WikiUpdate($request->POST, $params);
|
||||
if ($form->isValid() and !isset($request->POST['preview'])) {
|
||||
$page = $form->save();
|
||||
$urlpage = Pluf_HTTP_URL_urlForView('IDF_Views_Wiki::view',
|
||||
array($prj->shortname, $page->title));
|
||||
$request->user->setMessage(sprintf(__('The page <a href="%s">%s</a> has been updated.'), $urlpage, Pluf_esc($page->title)));
|
||||
$url = Pluf_HTTP_URL_urlForView('IDF_Views_Wiki::index',
|
||||
array($prj->shortname));
|
||||
return new Pluf_HTTP_Response_Redirect($url);
|
||||
} elseif (isset($request->POST['preview'])) {
|
||||
$preview = $request->POST['content'];
|
||||
}
|
||||
} else {
|
||||
|
||||
$form = new IDF_Form_WikiUpdate(null, $params);
|
||||
}
|
||||
return Pluf_Shortcuts_RenderToResponse('idf/wiki/update.html',
|
||||
array(
|
||||
'auto_labels' => self::autoCompleteArrays($prj),
|
||||
'page_title' => $title,
|
||||
'page' => $page,
|
||||
'rev' => $revision,
|
||||
'form' => $form,
|
||||
'preview' => $preview,
|
||||
),
|
||||
$request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the wiki tags.
|
||||
*
|
||||
* @param IDF_Project
|
||||
* @return ArrayObject The tags
|
||||
*/
|
||||
public static function getWikiTags($project)
|
||||
{
|
||||
return $project->getTagsFromConfig('labels_wiki_predefined',
|
||||
IDF_Form_WikiConf::init_predefined);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Get deprecated page ids.
|
||||
*
|
||||
* @param IDF_Project
|
||||
* @param IDF_Tag Deprecated tag (null)
|
||||
* @return array Ids of the deprecated pages.
|
||||
*/
|
||||
public static function getDeprecatedPagesIds($project, $dtag=null)
|
||||
{
|
||||
if (is_null($dtag)) {
|
||||
$ptags = self::getDownloadTags($project);
|
||||
$dtag = array_pop($ptags); // The last tag is the deprecated tag
|
||||
}
|
||||
$sql = new Pluf_SQL('project=%s AND idf_tag_id=%s', array($project->id,
|
||||
$dtag->id));
|
||||
$ids = array();
|
||||
foreach (Pluf::factory('IDF_WikiPage')->getList(array('filter' => $sql->gen(), 'view' => 'join_tags'))
|
||||
as $file) {
|
||||
$ids[] = (int) $file->id;
|
||||
}
|
||||
return $ids;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the autocomplete arrays for the little AJAX stuff.
|
||||
*/
|
||||
public static function autoCompleteArrays($project)
|
||||
{
|
||||
$conf = new IDF_Conf();
|
||||
$conf->setProject($project);
|
||||
$st = preg_split("/\015\012|\015|\012/",
|
||||
$conf->getVal('labels_wiki_predefined', IDF_Form_UploadConf::init_predefined), -1, PREG_SPLIT_NO_EMPTY);
|
||||
$auto = '';
|
||||
foreach ($st as $s) {
|
||||
$v = '';
|
||||
$d = '';
|
||||
$_s = split('=', $s, 2);
|
||||
if (count($_s) > 1) {
|
||||
$v = trim($_s[0]);
|
||||
$d = trim($_s[1]);
|
||||
} else {
|
||||
$v = trim($_s[0]);
|
||||
}
|
||||
$auto .= sprintf('{ name: "%s", to: "%s" }, ',
|
||||
Pluf_esc($d), Pluf_esc($v));
|
||||
}
|
||||
return substr($auto, 0, -1);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the summary of a page, then on a new line, display the
|
||||
* list of labels.
|
||||
*/
|
||||
function IDF_Views_Wiki_SummaryAndLabels($field, $page, $extra='')
|
||||
{
|
||||
$tags = array();
|
||||
foreach ($page->get_tags_list() as $tag) {
|
||||
$tags[] = Pluf_esc((string) $tag);
|
||||
}
|
||||
$out = '';
|
||||
if (count($tags)) {
|
||||
$out = '<br /><span class="note label">'.implode(', ', $tags).'</span>';
|
||||
}
|
||||
return Pluf_esc($page->summary).$out;
|
||||
}
|
192
src/IDF/WikiPage.php
Normal file
192
src/IDF/WikiPage.php
Normal file
@ -0,0 +1,192 @@
|
||||
<?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 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 ***** */
|
||||
|
||||
Pluf::loadFunction('Pluf_HTTP_URL_urlForView');
|
||||
Pluf::loadFunction('Pluf_Template_dateAgo');
|
||||
|
||||
/**
|
||||
* Base definition of a wiki page.
|
||||
*
|
||||
* A wiki page can have tags and be starred by the users. The real
|
||||
* content of the page is stored in the IDF_WikiRevision
|
||||
* object. Several revisions are associated to a given page.
|
||||
*/
|
||||
class IDF_WikiPage extends Pluf_Model
|
||||
{
|
||||
public $_model = __CLASS__;
|
||||
|
||||
function init()
|
||||
{
|
||||
$this->_a['table'] = 'idf_wikipages';
|
||||
$this->_a['model'] = __CLASS__;
|
||||
$this->_a['cols'] = array(
|
||||
// It is mandatory to have an "id" column.
|
||||
'id' =>
|
||||
array(
|
||||
'type' => 'Pluf_DB_Field_Sequence',
|
||||
'blank' => true,
|
||||
),
|
||||
'project' =>
|
||||
array(
|
||||
'type' => 'Pluf_DB_Field_Foreignkey',
|
||||
'model' => 'IDF_Project',
|
||||
'blank' => false,
|
||||
'verbose' => __('project'),
|
||||
'relate_name' => 'wikipages',
|
||||
),
|
||||
'title' =>
|
||||
array(
|
||||
'type' => 'Pluf_DB_Field_Varchar',
|
||||
'blank' => false,
|
||||
'size' => 250,
|
||||
'verbose' => __('title'),
|
||||
'help_text' => __('The title of the page must only contain letters, digits or the dash character. For example: My-new-Wiki-Page.'),
|
||||
),
|
||||
'summary' =>
|
||||
array(
|
||||
'type' => 'Pluf_DB_Field_Varchar',
|
||||
'blank' => false,
|
||||
'size' => 250,
|
||||
'verbose' => __('summary'),
|
||||
'help_text' => __('A one line description of the page content.'),
|
||||
),
|
||||
'submitter' =>
|
||||
array(
|
||||
'type' => 'Pluf_DB_Field_Foreignkey',
|
||||
'model' => 'Pluf_User',
|
||||
'blank' => false,
|
||||
'verbose' => __('submitter'),
|
||||
'relate_name' => 'submitted_wikipages',
|
||||
),
|
||||
'interested' =>
|
||||
array(
|
||||
'type' => 'Pluf_DB_Field_Manytomany',
|
||||
'model' => 'Pluf_User',
|
||||
'blank' => true,
|
||||
'verbose' => __('interested users'),
|
||||
'help_text' => 'Interested users will get an email notification when the wiki page is changed.',
|
||||
),
|
||||
'tags' =>
|
||||
array(
|
||||
'type' => 'Pluf_DB_Field_Manytomany',
|
||||
'blank' => true,
|
||||
'model' => 'IDF_Tag',
|
||||
'verbose' => __('labels'),
|
||||
),
|
||||
'creation_dtime' =>
|
||||
array(
|
||||
'type' => 'Pluf_DB_Field_Datetime',
|
||||
'blank' => true,
|
||||
'verbose' => __('creation date'),
|
||||
),
|
||||
'modif_dtime' =>
|
||||
array(
|
||||
'type' => 'Pluf_DB_Field_Datetime',
|
||||
'blank' => true,
|
||||
'verbose' => __('modification date'),
|
||||
),
|
||||
);
|
||||
$this->_a['idx'] = array(
|
||||
'modif_dtime_idx' =>
|
||||
array(
|
||||
'col' => 'modif_dtime',
|
||||
'type' => 'normal',
|
||||
),
|
||||
);
|
||||
$table = $this->_con->pfx.'idf_tag_idf_wikipage_assoc';
|
||||
$this->_a['views'] = array(
|
||||
'join_tags' =>
|
||||
array(
|
||||
'join' => 'LEFT JOIN '.$table
|
||||
.' ON idf_wikipage_id=id',
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
function __toString()
|
||||
{
|
||||
return $this->title.' - '.$this->summary;
|
||||
}
|
||||
|
||||
function _toIndex()
|
||||
{
|
||||
$rev = $this->get_current_revision()->_toIndex();
|
||||
$str = str_repeat($this->summary.' ', 4).' '.$rev;
|
||||
return Pluf_Text::cleanString(html_entity_decode($str, ENT_QUOTES, 'UTF-8'));
|
||||
}
|
||||
|
||||
function get_current_revision()
|
||||
{
|
||||
$db = $this->getDbConnection();
|
||||
$true = Pluf_DB_BooleanToDb(true, $db);
|
||||
$rev = $this->get_revisions_list(array('filter' => 'is_head='.$true,
|
||||
'nb' => 1));
|
||||
return ($rev->count() == 1) ? $rev[0] : null;
|
||||
}
|
||||
|
||||
function preSave($create=false)
|
||||
{
|
||||
if ($this->id == '') {
|
||||
$this->creation_dtime = gmdate('Y-m-d H:i:s');
|
||||
}
|
||||
$this->modif_dtime = gmdate('Y-m-d H:i:s');
|
||||
}
|
||||
|
||||
function postSave($create=false)
|
||||
{
|
||||
// Note: No indexing is performed here. The indexing is
|
||||
// triggered in the postSave step of the revision to ensure
|
||||
// that the page as a given revision in the database when
|
||||
// doing the indexing.
|
||||
if ($create) {
|
||||
IDF_Timeline::insert($this, $this->get_project(),
|
||||
$this->get_submitter());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an HTML fragment used to display this wikipage in the
|
||||
* timeline.
|
||||
*
|
||||
* The request object is given to be able to check the rights and
|
||||
* as such create links to other items etc. You can consider that
|
||||
* if displayed, you can create a link to it.
|
||||
*
|
||||
* @param Pluf_HTTP_Request
|
||||
* @return Pluf_Template_SafeString
|
||||
*/
|
||||
public function timelineFragment($request)
|
||||
{
|
||||
$url = Pluf_HTTP_URL_urlForView('IDF_Views_Wiki::view',
|
||||
array($request->project->shortname,
|
||||
$this->title));
|
||||
$out = '<tr class="log"><td><a href="'.$url.'">'.
|
||||
Pluf_esc(Pluf_Template_dateAgo($this->creation_dtime, 'without')).
|
||||
'</a></td><td>';
|
||||
$submitter = $this->get_submitter();
|
||||
$out .= sprintf(__('<a href="%1$s" title="View page">%2$s</a>, %3$s'), $url, Pluf_esc($this->title), Pluf_esc($this->summary)).'</td>';
|
||||
$out .= "\n".'<tr class="extra"><td colspan="2">
|
||||
<div class="helptext right">'.sprintf(__('Creation of <a href="%s">page %s</a>'), $url, Pluf_esc($this->title)).', '.__('by').' '.Pluf_esc($submitter).'</div></td></tr>';
|
||||
return Pluf_Template::markSafe($out);
|
||||
}
|
||||
}
|
183
src/IDF/WikiRevision.php
Normal file
183
src/IDF/WikiRevision.php
Normal file
@ -0,0 +1,183 @@
|
||||
<?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 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 ***** */
|
||||
|
||||
/**
|
||||
* A revision of a wiki page.
|
||||
*
|
||||
*/
|
||||
class IDF_WikiRevision extends Pluf_Model
|
||||
{
|
||||
public $_model = __CLASS__;
|
||||
|
||||
function init()
|
||||
{
|
||||
$this->_a['table'] = 'idf_wikirevisions';
|
||||
$this->_a['model'] = __CLASS__;
|
||||
$this->_a['cols'] = array(
|
||||
// It is mandatory to have an "id" column.
|
||||
'id' =>
|
||||
array(
|
||||
'type' => 'Pluf_DB_Field_Sequence',
|
||||
'blank' => true,
|
||||
),
|
||||
'wikipage' =>
|
||||
array(
|
||||
'type' => 'Pluf_DB_Field_Foreignkey',
|
||||
'model' => 'IDF_WikiPage',
|
||||
'blank' => false,
|
||||
'verbose' => __('page'),
|
||||
'relate_name' => 'revisions',
|
||||
),
|
||||
'is_head' =>
|
||||
array(
|
||||
'type' => 'Pluf_DB_Field_Boolean',
|
||||
'blank' => false,
|
||||
'default' => false,
|
||||
'help_text' => 'If this revision is the latest, we mark it as being the head revision.',
|
||||
'index' => true,
|
||||
|
||||
),
|
||||
'summary' =>
|
||||
array(
|
||||
'type' => 'Pluf_DB_Field_Varchar',
|
||||
'blank' => false,
|
||||
'size' => 250,
|
||||
'verbose' => __('summary'),
|
||||
'help_text' => __('A one line description of the changes.'),
|
||||
),
|
||||
'content' =>
|
||||
array(
|
||||
'type' => 'Pluf_DB_Field_Compressed',
|
||||
'blank' => false,
|
||||
'verbose' => __('content'),
|
||||
),
|
||||
'submitter' =>
|
||||
array(
|
||||
'type' => 'Pluf_DB_Field_Foreignkey',
|
||||
'model' => 'Pluf_User',
|
||||
'blank' => false,
|
||||
'verbose' => __('submitter'),
|
||||
),
|
||||
'changes' =>
|
||||
array(
|
||||
'type' => 'Pluf_DB_Field_Serialized',
|
||||
'blank' => true,
|
||||
'verbose' => __('changes'),
|
||||
'help_text' => 'Serialized array of the changes in the issue.',
|
||||
),
|
||||
'creation_dtime' =>
|
||||
array(
|
||||
'type' => 'Pluf_DB_Field_Datetime',
|
||||
'blank' => true,
|
||||
'verbose' => __('creation date'),
|
||||
),
|
||||
);
|
||||
$this->_a['idx'] = array(
|
||||
'creation_dtime_idx' =>
|
||||
array(
|
||||
'col' => 'creation_dtime',
|
||||
'type' => 'normal',
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
function changedRevision()
|
||||
{
|
||||
return (is_array($this->changes) and count($this->changes) > 0);
|
||||
}
|
||||
|
||||
function _toIndex()
|
||||
{
|
||||
return $this->content;
|
||||
}
|
||||
|
||||
function preSave($create=false)
|
||||
{
|
||||
if ($this->id == '') {
|
||||
$this->creation_dtime = gmdate('Y-m-d H:i:s');
|
||||
$this->is_head = true;
|
||||
}
|
||||
}
|
||||
|
||||
function postSave($create=false)
|
||||
{
|
||||
if ($create) {
|
||||
// Check if more than one revision for this page. We do
|
||||
// not want to insert the first revision in the timeline
|
||||
// as the page itself is inserted. We do not insert on
|
||||
// update as update is performed to change the is_head
|
||||
// flag.
|
||||
$sql = new Pluf_SQL('wikipage=%s', array($this->wikipage));
|
||||
$rev = Pluf::factory('IDF_WikiRevision')->getList(array('filter'=>$sql->gen()));
|
||||
if ($rev->count() > 1) {
|
||||
IDF_Timeline::insert($this, $this->get_wikipage()->get_project(),
|
||||
$this->get_submitter());
|
||||
foreach ($rev as $r) {
|
||||
if ($r->id != $this->id and $r->is_head) {
|
||||
$r->is_head = false;
|
||||
$r->update();
|
||||
}
|
||||
}
|
||||
}
|
||||
$page = $this->get_wikipage();
|
||||
$page->update(); // Will update the modification timestamp.
|
||||
IDF_Search::index($page);
|
||||
}
|
||||
}
|
||||
|
||||
public function timelineFragment($request)
|
||||
{
|
||||
$page = $this->get_wikipage();
|
||||
$url = Pluf_HTTP_URL_urlForView('IDF_Views_Wiki::view',
|
||||
array($request->project->shortname,
|
||||
$page->title));
|
||||
$out = "\n".'<tr class="log"><td><a href="'.$url.'">'.
|
||||
Pluf_esc(Pluf_Template_dateAgo($this->creation_dtime, 'without')).
|
||||
'</a></td><td>';
|
||||
$submitter = $this->get_submitter();
|
||||
$out .= sprintf(__('<a href="%1$s" title="View page">%2$s</a>, %3$s'), $url, Pluf_esc($page->title), Pluf_esc($this->summary));
|
||||
//$out .= '<strong>'.__('Summary:').'</strong> '.Pluf_esc($this->summary).' ';
|
||||
if ($this->changedRevision()) {
|
||||
$out .= '<div class="issue-changes-timeline">';
|
||||
foreach ($this->changes as $w => $v) {
|
||||
$out .= '<strong>';
|
||||
switch ($w) {
|
||||
case 'lb':
|
||||
$out .= __('Labels:'); break;
|
||||
}
|
||||
$out .= '</strong> ';
|
||||
if ($w == 'lb') {
|
||||
$out .= Pluf_esc(implode(', ', $v));
|
||||
} else {
|
||||
$out .= Pluf_esc($v);
|
||||
}
|
||||
$out .= ' ';
|
||||
}
|
||||
$out .= '</div>';
|
||||
}
|
||||
$out .= '</td></tr>';
|
||||
$out .= "\n".'<tr class="extra"><td colspan="2">
|
||||
<div class="helptext right">'.sprintf(__('Change of <a href="%s">%s</a>'), $url, Pluf_esc($page->title)).', '.__('by').' '.Pluf_esc($submitter).'</div></td></tr>';
|
||||
return Pluf_Template::markSafe($out);
|
||||
}
|
||||
}
|
@ -161,10 +161,10 @@ $cfg['template_tags'] = array(
|
||||
'hotkey' => 'IDF_Template_HotKey',
|
||||
'issuetext' => 'IDF_Template_IssueComment',
|
||||
'timeline' => 'IDF_Template_TimelineFragment',
|
||||
'markdown' => 'IDF_Template_Markdown',
|
||||
);
|
||||
$cfg['template_modifiers'] = array(
|
||||
'size' => 'IDF_Views_Source_PrettySize',
|
||||
'markdown' => 'IDF_Template_Markdown_filter',
|
||||
);
|
||||
|
||||
// available languages
|
||||
|
@ -147,37 +147,37 @@ $ctl[] = array('regex' => '#^/p/([\-\w]+)/issues/attachment/(\d+)/(.*)$#',
|
||||
|
||||
// ---------- SCM ----------------------------------------
|
||||
|
||||
$ctl[] = array('regex' => '#^/p/([\-\w]+)/source/tree/(\w+)/$#',
|
||||
$ctl[] = array('regex' => '#^/p/([\-\w]+)/source/tree/([\S^/]+)/$#',
|
||||
'base' => $base,
|
||||
'priority' => 4,
|
||||
'model' => 'IDF_Views_Source',
|
||||
'method' => 'treeBase');
|
||||
|
||||
$ctl[] = array('regex' => '#^/p/([\-\w]+)/source/tree/(\w+)/(.*)$#',
|
||||
$ctl[] = array('regex' => '#^/p/([\-\w]+)/source/tree/([\S^/]+)/(.*)$#',
|
||||
'base' => $base,
|
||||
'priority' => 4,
|
||||
'model' => 'IDF_Views_Source',
|
||||
'method' => 'tree');
|
||||
|
||||
$ctl[] = array('regex' => '#^/p/([\-\w]+)/source/changes/(\w+)/$#',
|
||||
$ctl[] = array('regex' => '#^/p/([\-\w]+)/source/changes/([\S^/]+)/$#',
|
||||
'base' => $base,
|
||||
'priority' => 4,
|
||||
'model' => 'IDF_Views_Source',
|
||||
'method' => 'changeLog');
|
||||
|
||||
$ctl[] = array('regex' => '#^/p/([\-\w]+)/source/commit/(\w+)/$#',
|
||||
$ctl[] = array('regex' => '#^/p/([\-\w]+)/source/commit/([\S^/]+)/$#',
|
||||
'base' => $base,
|
||||
'priority' => 4,
|
||||
'model' => 'IDF_Views_Source',
|
||||
'method' => 'commit');
|
||||
|
||||
$ctl[] = array('regex' => '#^/p/([\-\w]+)/source/download/(\w+)/$#',
|
||||
$ctl[] = array('regex' => '#^/p/([\-\w]+)/source/download/([\S^/]+)/$#',
|
||||
'base' => $base,
|
||||
'priority' => 4,
|
||||
'model' => 'IDF_Views_Source',
|
||||
'method' => 'download');
|
||||
|
||||
$ctl[] = array('regex' => '#^/p/([\-\w]+)/source/file/(\w+)/(.*)$#',
|
||||
$ctl[] = array('regex' => '#^/p/([\-\w]+)/source/file/([\S^/]+)/(.*)$#',
|
||||
'base' => $base,
|
||||
'priority' => 4,
|
||||
'model' => 'IDF_Views_Source',
|
||||
@ -195,6 +195,32 @@ $ctl[] = array('regex' => '#^/p/([\-\w]+)/source/changesrev/$#',
|
||||
'model' => 'IDF_Views_Source_Svn',
|
||||
'method' => 'changelogRev');
|
||||
|
||||
// ---------- WIKI -----------------------------------------
|
||||
|
||||
$ctl[] = array('regex' => '#^/p/([\-\w]+)/doc/$#',
|
||||
'base' => $base,
|
||||
'priority' => 4,
|
||||
'model' => 'IDF_Views_Wiki',
|
||||
'method' => 'index');
|
||||
|
||||
$ctl[] = array('regex' => '#^/p/([\-\w]+)/doc/create/$#',
|
||||
'base' => $base,
|
||||
'priority' => 4,
|
||||
'model' => 'IDF_Views_Wiki',
|
||||
'method' => 'create');
|
||||
|
||||
$ctl[] = array('regex' => '#^/p/([\-\w]+)/doc/update/(.*)/$#',
|
||||
'base' => $base,
|
||||
'priority' => 4,
|
||||
'model' => 'IDF_Views_Wiki',
|
||||
'method' => 'update');
|
||||
|
||||
$ctl[] = array('regex' => '#^/p/([\-\w]+)/page/(.*)/$#',
|
||||
'base' => $base,
|
||||
'priority' => 4,
|
||||
'model' => 'IDF_Views_Wiki',
|
||||
'method' => 'view');
|
||||
|
||||
// ---------- Downloads ------------------------------------
|
||||
|
||||
$ctl[] = array('regex' => '#^/p/([\-\w]+)/downloads/$#',
|
||||
@ -254,6 +280,12 @@ $ctl[] = array('regex' => '#^/p/([\-\w]+)/admin/downloads/$#',
|
||||
'model' => 'IDF_Views_Project',
|
||||
'method' => 'adminDownloads');
|
||||
|
||||
$ctl[] = array('regex' => '#^/p/([\-\w]+)/admin/wiki/$#',
|
||||
'base' => $base,
|
||||
'priority' => 4,
|
||||
'model' => 'IDF_Views_Project',
|
||||
'method' => 'adminWiki');
|
||||
|
||||
$ctl[] = array('regex' => '#^/p/([\-\w]+)/admin/source/$#',
|
||||
'base' => $base,
|
||||
'priority' => 4,
|
||||
|
@ -30,5 +30,8 @@ $m['IDF_IssueFile'] = array('relate_to' => array('IDF_IssueComment', 'Pluf_User'
|
||||
$m['IDF_Upload'] = array('relate_to' => array('IDF_Project', 'Pluf_User'),
|
||||
'relate_to_many' => array('IDF_Tag'));
|
||||
$m['IDF_Search_Occ'] = array('relate_to' => array('IDF_Project'),);
|
||||
$m['IDF_WikiPage'] = array('relate_to' => array('IDF_Project', 'Pluf_User'),
|
||||
'relate_to_many' => array('IDF_Tag', 'Pluf_User'));
|
||||
$m['IDF_WikiRevision'] = array('relate_to' => array('IDF_WikiPage', 'Pluf_User'));
|
||||
|
||||
return $m;
|
||||
|
@ -3,8 +3,9 @@
|
||||
{block subtabs}
|
||||
<div id="sub-tabs">
|
||||
<a {if $inSummary}class="active" {/if}href="{url 'IDF_Views_Project::admin', array($project.shortname)}">{trans 'Project Summary'}</a> |
|
||||
<a {if $inIssueTracking}class="active" {/if}href="{url 'IDF_Views_Project::adminIssues', array($project.shortname)}">{trans 'Issue Tracking'}</a> |
|
||||
<a {if $inDownloads}class="active" {/if}href="{url 'IDF_Views_Project::adminDownloads', array($project.shortname)}">{trans 'Downloads'}</a> |
|
||||
<a {if $inWiki}class="active" {/if}href="{url 'IDF_Views_Project::adminWiki', array($project.shortname)}">{trans 'Documentation'}</a> |
|
||||
<a {if $inIssueTracking}class="active" {/if}href="{url 'IDF_Views_Project::adminIssues', array($project.shortname)}">{trans 'Issue Tracking'}</a> |
|
||||
<a {if $inSource}class="active" {/if}href="{url 'IDF_Views_Project::adminSource', array($project.shortname)}">{trans 'Source'}</a> |
|
||||
<a {if $inMembers}class="active" {/if}href="{url 'IDF_Views_Project::adminMembers', array($project.shortname)}">{trans 'Project Members'}</a> |
|
||||
<a {if $inTabs}class="active" {/if}href="{url 'IDF_Views_Project::adminTabs', array($project.shortname)}">{trans 'Tabs Access'}</a>
|
||||
|
@ -18,6 +18,12 @@
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><strong>{$form.f.wiki_access_rights.labelTag}:</strong></th>
|
||||
<td>{if $form.f.wiki_access_rights.errors}{$form.f.wiki_access_rights.fieldErrors}{/if}
|
||||
{$form.f.wiki_access_rights|unsafe}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><strong>{$form.f.issues_access_rights.labelTag}:</strong></th>
|
||||
<td>{if $form.f.issues_access_rights.errors}{$form.f.issues_access_rights.fieldErrors}{/if}
|
||||
{$form.f.issues_access_rights|unsafe}
|
||||
|
34
src/IDF/templates/idf/admin/wiki.html
Normal file
34
src/IDF/templates/idf/admin/wiki.html
Normal file
@ -0,0 +1,34 @@
|
||||
{extends "idf/admin/base.html"}
|
||||
{block docclass}yui-t1{assign $inWiki = true}{/block}
|
||||
{block body}
|
||||
<form method="post" action=".">
|
||||
<table class="form" summary="">
|
||||
<tr>
|
||||
<td colspan="2"><strong>{$form.f.labels_wiki_predefined.labelTag}:</strong><br />
|
||||
{if $form.f.labels_wiki_predefined.errors}{$form.f.labels_wiki_predefined.fieldErrors}{/if}
|
||||
{$form.f.labels_wiki_predefined|unsafe}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2">{$form.f.labels_wiki_one_max.labelTag}:<br />
|
||||
{if $form.f.labels_wiki_one_max.errors}{$form.f.labels_wiki_one_max.fieldErrors}{/if}
|
||||
{$form.f.labels_wiki_one_max|unsafe}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2">
|
||||
<input type="submit" value="{trans 'Save Changes'}" name="submit" />
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</form>
|
||||
{/block}
|
||||
{block context}
|
||||
<div class="issue-submit-info">
|
||||
{blocktrans}
|
||||
<p><strong>Instructions:</strong></p>
|
||||
<p>List one status value per line in desired sort-order.</p>
|
||||
<p>Optionally, use an equals-sign to document the meaning of each status value.</p>
|
||||
{/blocktrans}
|
||||
</div>
|
||||
{/block}
|
@ -43,8 +43,9 @@
|
||||
<div id="main-tabs">
|
||||
{if $project}
|
||||
<a accesskey="1" href="{url 'IDF_Views_Project::home', array($project.shortname)}"{block tabhome}{/block}>{trans 'Project Home'}</a>
|
||||
{if $hasIssuesAccess} <a href="{url 'IDF_Views_Issue::index', array($project.shortname)}"{block tabissues}{/block}>{trans 'Issues'}</a>{/if}
|
||||
{if $hasDownloadsAccess} <a href="{url 'IDF_Views_Download::index', array($project.shortname)}"{block tabdownloads}{/block}>{trans 'Downloads'}</a>{/if}
|
||||
{if $hasWikiAccess} <a href="{url 'IDF_Views_Wiki::index', array($project.shortname)}"{block tabwiki}{/block}>{trans 'Documentation'}</a>{/if}
|
||||
{if $hasIssuesAccess} <a href="{url 'IDF_Views_Issue::index', array($project.shortname)}"{block tabissues}{/block}>{trans 'Issues'}</a>{/if}
|
||||
{if $hasSourceAccess} <a href="{url 'IDF_Views_Source::treeBase', array($project.shortname, $project.getScmRoot())}"{block tabsource}{/block}>{trans 'Source'}</a>{/if}
|
||||
{if $isOwner}
|
||||
<a href="{url 'IDF_Views_Project::admin', array($project.shortname)}"{block tabadmin}{/block}>{trans 'Administer'}</a>{/if}{/if}
|
||||
|
@ -7,7 +7,7 @@
|
||||
</div>
|
||||
{/block}
|
||||
{block body}
|
||||
{$project.description|markdown}
|
||||
{markdown $project.description, $request}
|
||||
{/block}
|
||||
{block context}
|
||||
{if count($downloads) > 0}
|
||||
|
10
src/IDF/templates/idf/wiki/base.html
Normal file
10
src/IDF/templates/idf/wiki/base.html
Normal file
@ -0,0 +1,10 @@
|
||||
{extends "idf/base.html"}
|
||||
{block tabwiki} class="active"{/block}
|
||||
{block subtabs}
|
||||
<div id="sub-tabs">
|
||||
<a {if $inWiki}class="active" {/if}href="{url 'IDF_Views_Wiki::index', array($project.shortname)}">{trans 'List Pages'}</a>
|
||||
{if !$user.isAnonymous()} | <a {if $inCreate}class="active" {/if}href="{url 'IDF_Views_Wiki::create', array($project.shortname)}">{trans 'New Page'}</a> {/if}
|
||||
{if !$user.isAnonymous() and $inView} | <a href="{url 'IDF_Views_Wiki::update', array($project.shortname, $page.title)}">{trans 'Update This Page'}</a> {/if}
|
||||
{superblock}
|
||||
</div>
|
||||
{/block}
|
68
src/IDF/templates/idf/wiki/create.html
Normal file
68
src/IDF/templates/idf/wiki/create.html
Normal file
@ -0,0 +1,68 @@
|
||||
{extends "idf/wiki/base.html"}
|
||||
{block docclass}yui-t1{assign $inCreate = true}{/block}
|
||||
{block body}
|
||||
|
||||
{if $preview}
|
||||
<h2 class="top">{trans 'Preview of the Page'}</h2>
|
||||
|
||||
{markdown $preview, $request}
|
||||
{/if}
|
||||
|
||||
{if $form.errors}
|
||||
<div class="px-message-error">
|
||||
<p>{trans 'The form contains some errors. Please correct them to create the page.'}</p>
|
||||
{if $form.get_top_errors}
|
||||
{$form.render_top_errors|unsafe}
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<form method="post" enctype="multipart/form-data" action="." >
|
||||
<table class="form" summary="">
|
||||
<tr>
|
||||
<th><strong>{$form.f.title.labelTag}:</strong></th>
|
||||
<td>{if $form.f.title.errors}{$form.f.title.fieldErrors}{/if}
|
||||
{$form.f.title|unsafe}<br />
|
||||
<span class="helptext">{$form.f.title.help_text}</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><strong>{$form.f.summary.labelTag}:</strong></th>
|
||||
<td>{if $form.f.summary.errors}{$form.f.summary.fieldErrors}{/if}
|
||||
{$form.f.summary|unsafe}<br />
|
||||
<span class="helptext">{$form.f.summary.help_text}</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><strong>{$form.f.content.labelTag}:</strong></th>
|
||||
<td>{if $form.f.content.errors}{$form.f.content.fieldErrors}{/if}
|
||||
{$form.f.content|unsafe}
|
||||
</td>
|
||||
</tr>{if $isOwner or $isMember}
|
||||
<tr>
|
||||
<th>{$form.f.label1.labelTag}:</th>
|
||||
<td>
|
||||
{if $form.f.label1.errors}{$form.f.label1.fieldErrors}{/if}{$form.f.label1|unsafe}
|
||||
{if $form.f.label2.errors}{$form.f.label2.fieldErrors}{/if}{$form.f.label2|unsafe}
|
||||
{if $form.f.label3.errors}{$form.f.label3.fieldErrors}{/if}{$form.f.label3|unsafe}
|
||||
</td>
|
||||
</tr>{/if}
|
||||
<tr>
|
||||
<td> </td>
|
||||
<td><input type="submit" value="{trans 'Preview'}" name="preview" /> <input type="submit" value="{trans 'Create Page'}" name="submit" /> | <a href="{url 'IDF_Views_Wiki::index', array($project.shortname)}">{trans 'Cancel'}</a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</form>
|
||||
{/block}
|
||||
{block context}
|
||||
<div class="issue-submit-info">
|
||||
{include 'idf/wiki/edit-info.html'}
|
||||
</div>
|
||||
{/block}
|
||||
{block javascript}
|
||||
<script type="text/javascript">
|
||||
document.getElementById('id_title').focus()
|
||||
</script>
|
||||
{include 'idf/wiki/js-autocomplete.html'}{/block}
|
||||
|
6
src/IDF/templates/idf/wiki/edit-info.html
Normal file
6
src/IDF/templates/idf/wiki/edit-info.html
Normal file
@ -0,0 +1,6 @@
|
||||
{assign $url = 'http://daringfireball.net/projects/markdown/syntax'}
|
||||
{blocktrans}
|
||||
<p><strong>Instructions:</strong></p>
|
||||
<p>The content of the page can use the <a href="{$url}">Markdown syntax</a>.</p>
|
||||
<p>Website addresses are automatically linked and you can link to another page in the documentation using double square brackets like that [[AnotherPage]].</p>
|
||||
{/blocktrans}
|
13
src/IDF/templates/idf/wiki/index.html
Normal file
13
src/IDF/templates/idf/wiki/index.html
Normal file
@ -0,0 +1,13 @@
|
||||
{extends "idf/wiki/base.html"}
|
||||
{block docclass}yui-t1{assign $inWiki=true}{/block}
|
||||
{block body}
|
||||
{$pages.render}
|
||||
{if !$user.isAnonymous()}
|
||||
{aurl 'url', 'IDF_Views_Wiki::create', array($project.shortname)}
|
||||
<p><a href="{$url}"><img style="vertical-align: text-bottom;" src="{media '/idf/img/add.png'}" alt="+" align="bottom" /></a> <a href="{$url}">{trans 'New Page'}</a></p>{/if}
|
||||
|
||||
{/block}
|
||||
{block context}
|
||||
<p><strong>{trans 'Number of pages:'}</strong> {$pages.nb_items}</p>
|
||||
{/block}
|
||||
|
27
src/IDF/templates/idf/wiki/js-autocomplete.html
Normal file
27
src/IDF/templates/idf/wiki/js-autocomplete.html
Normal file
@ -0,0 +1,27 @@
|
||||
{if $isOwner or $isMember}
|
||||
<script type="text/javascript" src="{media '/idf/js/jquery.bgiframe.min.js'}"></script>
|
||||
<script type="text/javascript" src="{media '/idf/js/jquery.autocomplete.min.js'}"></script>
|
||||
<script type="text/javascript" charset="utf-8">
|
||||
// <!-- {literal}
|
||||
$(document).ready(function(){
|
||||
var auto_labels = [{/literal}{$auto_labels|safe}{literal}];
|
||||
var j=0;
|
||||
for (j=1;j<4;j=j+1) {
|
||||
$("#id_label"+j).autocomplete(auto_labels, {
|
||||
minChars: 0,
|
||||
width: 310,
|
||||
matchContains: true,
|
||||
max: 50,
|
||||
highlightItem: false,
|
||||
formatItem: function(row, i, max, term) {
|
||||
return row.to.replace(new RegExp("(" + term + ")", "gi"), "<strong>$1</strong>") + " <span style='font-size: 80%;'>" + row.name + "</span>";
|
||||
},
|
||||
formatResult: function(row) {
|
||||
return row.to;
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
{/literal} //-->
|
||||
</script>
|
||||
{/if}
|
72
src/IDF/templates/idf/wiki/update.html
Normal file
72
src/IDF/templates/idf/wiki/update.html
Normal file
@ -0,0 +1,72 @@
|
||||
{extends "idf/wiki/base.html"}
|
||||
{block docclass}yui-t2{/block}
|
||||
{block body}
|
||||
|
||||
{if $preview}
|
||||
<h2 class="top">{trans 'Preview of the Page'}</h2>
|
||||
|
||||
{markdown $preview, $request}
|
||||
{/if}
|
||||
|
||||
{if $form.errors}
|
||||
<div class="px-message-error">
|
||||
<p>{trans 'The form contains some errors. Please correct them to update the page.'}</p>
|
||||
{if $form.get_top_errors}
|
||||
{$form.render_top_errors|unsafe}
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<form method="post" enctype="multipart/form-data" action="." >
|
||||
<table class="form" summary="">{if $isOwner or $isMember}
|
||||
<tr>
|
||||
<th><strong>{$form.f.title.labelTag}:</strong></th>
|
||||
<td>{if $form.f.title.errors}{$form.f.title.fieldErrors}{/if}
|
||||
{$form.f.title|unsafe}<br />
|
||||
<span class="helptext">{$form.f.title.help_text}</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><strong>{$form.f.summary.labelTag}:</strong></th>
|
||||
<td>{if $form.f.summary.errors}{$form.f.summary.fieldErrors}{/if}
|
||||
{$form.f.summary|unsafe}<br />
|
||||
<span class="helptext">{$form.f.summary.help_text}</span>
|
||||
</td>
|
||||
</tr>{/if}
|
||||
<tr>
|
||||
<th><strong>{$form.f.content.labelTag}:</strong></th>
|
||||
<td>{if $form.f.content.errors}{$form.f.content.fieldErrors}{/if}
|
||||
{$form.f.content|unsafe}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><strong>{$form.f.comment.labelTag}:</strong></th>
|
||||
<td>{if $form.f.comment.errors}{$form.f.comment.fieldErrors}{/if}
|
||||
{$form.f.comment|unsafe}<br />
|
||||
<span class="helptext">{$form.f.comment.help_text}</span>
|
||||
</td>
|
||||
</tr>{if $isOwner or $isMember}
|
||||
<tr>
|
||||
<th>{$form.f.label1.labelTag}:</th>
|
||||
<td>
|
||||
{if $form.f.label1.errors}{$form.f.label1.fieldErrors}{/if}{$form.f.label1|unsafe}
|
||||
{if $form.f.label2.errors}{$form.f.label2.fieldErrors}{/if}{$form.f.label2|unsafe}
|
||||
{if $form.f.label3.errors}{$form.f.label3.fieldErrors}{/if}{$form.f.label3|unsafe}
|
||||
</td>
|
||||
</tr>{/if}
|
||||
<tr>
|
||||
<td> </td>
|
||||
<td><input type="submit" value="{trans 'Preview'}" name="preview" /> <input type="submit" value="{trans 'Update Page'}" name="submit" /> | <a href="{url 'IDF_Views_Wiki::index', array($project.shortname)}">{trans 'Cancel'}</a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</form>
|
||||
{/block}
|
||||
{block context}
|
||||
<div class="issue-submit-info">
|
||||
{include 'idf/wiki/edit-info.html'}
|
||||
</div>
|
||||
{/block}
|
||||
{block javascript}
|
||||
{include 'idf/wiki/js-autocomplete.html'}{/block}
|
||||
|
22
src/IDF/templates/idf/wiki/view.html
Normal file
22
src/IDF/templates/idf/wiki/view.html
Normal file
@ -0,0 +1,22 @@
|
||||
{extends "idf/wiki/base.html"}
|
||||
{block docclass}yui-t3{assign $inView=true}{/block}
|
||||
{block body}
|
||||
|
||||
<p class="desc">{$page.summary}</p>
|
||||
|
||||
{markdown $rev.content, $request}
|
||||
|
||||
{/block}
|
||||
{block context}
|
||||
{assign $submitter = $page.get_submitter()}
|
||||
<p><strong>{trans 'Created:'}</strong> <span class="nobrk">{$page.creation_dtime|dateago}</span><br /><span class="nobrk">{blocktrans}by {$submitter}{/blocktrans}</span></p>
|
||||
{if $rev.creation_dtime != $page.creation_dtime}<p>{assign $submitter = $rev.get_submitter()}
|
||||
<strong>{trans 'Updated:'}</strong> <span class="nobrk">{$rev.creation_dtime|dateago}</span><br /><span class="nobrk">{blocktrans}by {$submitter}{/blocktrans}</span></p>{/if}
|
||||
{if $tags.count()}
|
||||
<p>
|
||||
<strong>{trans 'Labels:'}</strong><br />
|
||||
{foreach $tags as $tag}
|
||||
<span class="label"><strong>{$tag.class}:</strong>{$tag.name}</span><br />
|
||||
{/foreach}
|
||||
</p>{/if}
|
||||
{/block}
|
@ -578,3 +578,14 @@ div.download-file {
|
||||
-moz-border-radius: 5px;
|
||||
-webkit-border-radius: 5px;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wiki
|
||||
*/
|
||||
p.desc {
|
||||
background-color: #eeeeec;
|
||||
-moz-border-radius: 3px;
|
||||
-webkit-border-radius: 3px;
|
||||
padding: 4px;
|
||||
width: 60%;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user