Add screenshot support for tasks (copy/paste images directly)
This commit is contained in:
@@ -80,6 +80,7 @@ Documentation
|
|||||||
#### Working with tasks
|
#### Working with tasks
|
||||||
|
|
||||||
- [Creating tasks](docs/creating-tasks.markdown)
|
- [Creating tasks](docs/creating-tasks.markdown)
|
||||||
|
- [Adding screenshots](docs/screenshots.markdown)
|
||||||
- [Task links](docs/task-links.markdown)
|
- [Task links](docs/task-links.markdown)
|
||||||
- [Transitions](docs/transitions.markdown)
|
- [Transitions](docs/transitions.markdown)
|
||||||
- [Time tracking](docs/time-tracking.markdown)
|
- [Time tracking](docs/time-tracking.markdown)
|
||||||
|
|||||||
@@ -335,4 +335,19 @@ class Board extends Base
|
|||||||
|
|
||||||
$this->response->redirect($this->helper->url('board', 'show', array('project_id' => $values['project_id'])));
|
$this->response->redirect($this->helper->url('board', 'show', array('project_id' => $values['project_id'])));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Screenshot popover
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
*/
|
||||||
|
public function screenshot()
|
||||||
|
{
|
||||||
|
$task = $this->getTask();
|
||||||
|
|
||||||
|
$this->response->html($this->template->render('file/screenshot', array(
|
||||||
|
'task' => $task,
|
||||||
|
'redirect' => 'board',
|
||||||
|
)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,32 @@ namespace Controller;
|
|||||||
*/
|
*/
|
||||||
class File extends Base
|
class File extends Base
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* Screenshot
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
*/
|
||||||
|
public function screenshot()
|
||||||
|
{
|
||||||
|
$task = $this->getTask();
|
||||||
|
|
||||||
|
if ($this->request->isPost() && $this->file->uploadScreenshot($task['project_id'], $task['id'], $this->request->getValue('screenshot'))) {
|
||||||
|
|
||||||
|
$this->session->flash(t('Screenshot uploaded successfully.'));
|
||||||
|
|
||||||
|
if ($this->request->getStringParam('redirect') === 'board') {
|
||||||
|
$this->response->redirect($this->helper->url('board', 'show', array('project_id' => $task['project_id'])));
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->response->redirect($this->helper->url('task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id'])));
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->response->html($this->taskLayout('file/screenshot', array(
|
||||||
|
'task' => $task,
|
||||||
|
'redirect' => 'task',
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* File upload form
|
* File upload form
|
||||||
*
|
*
|
||||||
@@ -34,13 +60,11 @@ class File extends Base
|
|||||||
{
|
{
|
||||||
$task = $this->getTask();
|
$task = $this->getTask();
|
||||||
|
|
||||||
if ($this->file->upload($task['project_id'], $task['id'], 'files') === true) {
|
if (! $this->file->upload($task['project_id'], $task['id'], 'files')) {
|
||||||
$this->response->redirect('?controller=task&action=show&task_id='.$task['id'].'&project_id='.$task['project_id'].'#attachments');
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
$this->session->flashError(t('Unable to upload the file.'));
|
$this->session->flashError(t('Unable to upload the file.'));
|
||||||
$this->response->redirect('?controller=file&action=create&task_id='.$task['id'].'&project_id='.$task['project_id']);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$this->response->redirect($this->helper->url('task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id'])));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -59,7 +83,7 @@ class File extends Base
|
|||||||
$this->response->binary(file_get_contents($filename));
|
$this->response->binary(file_get_contents($filename));
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->response->redirect('?controller=task&action=show&task_id='.$task['id'].'&project_id='.$task['project_id']);
|
$this->response->redirect($this->helper->url('task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id'])));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -140,7 +164,7 @@ class File extends Base
|
|||||||
$this->session->flashError(t('Unable to remove this file.'));
|
$this->session->flashError(t('Unable to remove this file.'));
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->response->redirect('?controller=task&action=show&task_id='.$task['id'].'&project_id='.$task['project_id']);
|
$this->response->redirect($this->helper->url('task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id'])));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -853,4 +853,10 @@ return array(
|
|||||||
// 'Burndown chart for "%s"' => '',
|
// 'Burndown chart for "%s"' => '',
|
||||||
// 'Burndown chart' => '',
|
// 'Burndown chart' => '',
|
||||||
// 'This chart show the task complexity over the time (Work Remaining).' => '',
|
// 'This chart show the task complexity over the time (Work Remaining).' => '',
|
||||||
|
// 'Screenshot taken %s' => '',
|
||||||
|
// 'Add a screenshot' => '',
|
||||||
|
// 'Copy and paste images are only supported with Mozilla Firefox and Google Chrome.' => '',
|
||||||
|
// 'Take a screenshot and press CTRL+V or ⌘+V to paste here.' => '',
|
||||||
|
// 'Screenshot uploaded successfully.' => '',
|
||||||
|
// 'SEK - Swedish Krona' => '',
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -853,4 +853,10 @@ return array(
|
|||||||
// 'Burndown chart for "%s"' => '',
|
// 'Burndown chart for "%s"' => '',
|
||||||
// 'Burndown chart' => '',
|
// 'Burndown chart' => '',
|
||||||
// 'This chart show the task complexity over the time (Work Remaining).' => '',
|
// 'This chart show the task complexity over the time (Work Remaining).' => '',
|
||||||
|
// 'Screenshot taken %s' => '',
|
||||||
|
// 'Add a screenshot' => '',
|
||||||
|
// 'Copy and paste images are only supported with Mozilla Firefox and Google Chrome.' => '',
|
||||||
|
// 'Take a screenshot and press CTRL+V or ⌘+V to paste here.' => '',
|
||||||
|
// 'Screenshot uploaded successfully.' => '',
|
||||||
|
// 'SEK - Swedish Krona' => '',
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -853,4 +853,10 @@ return array(
|
|||||||
// 'Burndown chart for "%s"' => '',
|
// 'Burndown chart for "%s"' => '',
|
||||||
// 'Burndown chart' => '',
|
// 'Burndown chart' => '',
|
||||||
// 'This chart show the task complexity over the time (Work Remaining).' => '',
|
// 'This chart show the task complexity over the time (Work Remaining).' => '',
|
||||||
|
// 'Screenshot taken %s' => '',
|
||||||
|
// 'Add a screenshot' => '',
|
||||||
|
// 'Copy and paste images are only supported with Mozilla Firefox and Google Chrome.' => '',
|
||||||
|
// 'Take a screenshot and press CTRL+V or ⌘+V to paste here.' => '',
|
||||||
|
// 'Screenshot uploaded successfully.' => '',
|
||||||
|
// 'SEK - Swedish Krona' => '',
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -853,4 +853,10 @@ return array(
|
|||||||
// 'Burndown chart for "%s"' => '',
|
// 'Burndown chart for "%s"' => '',
|
||||||
// 'Burndown chart' => '',
|
// 'Burndown chart' => '',
|
||||||
// 'This chart show the task complexity over the time (Work Remaining).' => '',
|
// 'This chart show the task complexity over the time (Work Remaining).' => '',
|
||||||
|
// 'Screenshot taken %s' => '',
|
||||||
|
// 'Add a screenshot' => '',
|
||||||
|
// 'Copy and paste images are only supported with Mozilla Firefox and Google Chrome.' => '',
|
||||||
|
// 'Take a screenshot and press CTRL+V or ⌘+V to paste here.' => '',
|
||||||
|
// 'Screenshot uploaded successfully.' => '',
|
||||||
|
// 'SEK - Swedish Krona' => '',
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -849,10 +849,16 @@ return array(
|
|||||||
'Test your device' => 'Testez votre appareil',
|
'Test your device' => 'Testez votre appareil',
|
||||||
'Assign a color when the task is moved to a specific column' => 'Assigner une couleur lorsque la tâche est déplacée dans une colonne spécifique',
|
'Assign a color when the task is moved to a specific column' => 'Assigner une couleur lorsque la tâche est déplacée dans une colonne spécifique',
|
||||||
'%s via Kanboard' => '%s via Kanboard',
|
'%s via Kanboard' => '%s via Kanboard',
|
||||||
'uploaded by: %s' => 'Télécharger par : %s',
|
'uploaded by: %s' => 'Téléchargé par %s',
|
||||||
'uploaded on: %s' => 'Télécharger le : %s',
|
'uploaded on: %s' => 'Téléchargé le %s',
|
||||||
'size: %s' => 'Taille : %s',
|
'size: %s' => 'Taille : %s',
|
||||||
'Burndown chart for "%s"' => 'Graphique d\'avancement pour « %s »',
|
'Burndown chart for "%s"' => 'Graphique d\'avancement pour « %s »',
|
||||||
'Burndown chart' => 'Graphique d\'avancement',
|
'Burndown chart' => 'Graphique d\'avancement',
|
||||||
'This chart show the task complexity over the time (Work Remaining).' => 'Ce graphique représente la complexité des tâches en fonction du temps (travail restant).',
|
'This chart show the task complexity over the time (Work Remaining).' => 'Ce graphique représente la complexité des tâches en fonction du temps (travail restant).',
|
||||||
|
'Screenshot taken %s' => 'Capture d\'écran prise le %s',
|
||||||
|
'Add a screenshot' => 'Ajouter une capture d\'écran',
|
||||||
|
'Copy and paste images are only supported with Mozilla Firefox and Google Chrome.' => 'Copier/coller des images est uniquement supporté par Mozilla Firefox et Google Chrome.',
|
||||||
|
'Take a screenshot and press CTRL+V or ⌘+V to paste here.' => 'Prenez une capture d\'écran et appuyez sur CTRL+V ou ⌘+V pour coller ici.',
|
||||||
|
'Screenshot uploaded successfully.' => 'Capture d\'écran téléchargée avec succès.',
|
||||||
|
'SEK - Swedish Krona' => 'SEK - Couronne suédoise',
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -853,4 +853,10 @@ return array(
|
|||||||
// 'Burndown chart for "%s"' => '',
|
// 'Burndown chart for "%s"' => '',
|
||||||
// 'Burndown chart' => '',
|
// 'Burndown chart' => '',
|
||||||
// 'This chart show the task complexity over the time (Work Remaining).' => '',
|
// 'This chart show the task complexity over the time (Work Remaining).' => '',
|
||||||
|
// 'Screenshot taken %s' => '',
|
||||||
|
// 'Add a screenshot' => '',
|
||||||
|
// 'Copy and paste images are only supported with Mozilla Firefox and Google Chrome.' => '',
|
||||||
|
// 'Take a screenshot and press CTRL+V or ⌘+V to paste here.' => '',
|
||||||
|
// 'Screenshot uploaded successfully.' => '',
|
||||||
|
// 'SEK - Swedish Krona' => '',
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -853,4 +853,10 @@ return array(
|
|||||||
// 'Burndown chart for "%s"' => '',
|
// 'Burndown chart for "%s"' => '',
|
||||||
// 'Burndown chart' => '',
|
// 'Burndown chart' => '',
|
||||||
// 'This chart show the task complexity over the time (Work Remaining).' => '',
|
// 'This chart show the task complexity over the time (Work Remaining).' => '',
|
||||||
|
// 'Screenshot taken %s' => '',
|
||||||
|
// 'Add a screenshot' => '',
|
||||||
|
// 'Copy and paste images are only supported with Mozilla Firefox and Google Chrome.' => '',
|
||||||
|
// 'Take a screenshot and press CTRL+V or ⌘+V to paste here.' => '',
|
||||||
|
// 'Screenshot uploaded successfully.' => '',
|
||||||
|
// 'SEK - Swedish Krona' => '',
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -853,4 +853,10 @@ return array(
|
|||||||
// 'Burndown chart for "%s"' => '',
|
// 'Burndown chart for "%s"' => '',
|
||||||
// 'Burndown chart' => '',
|
// 'Burndown chart' => '',
|
||||||
// 'This chart show the task complexity over the time (Work Remaining).' => '',
|
// 'This chart show the task complexity over the time (Work Remaining).' => '',
|
||||||
|
// 'Screenshot taken %s' => '',
|
||||||
|
// 'Add a screenshot' => '',
|
||||||
|
// 'Copy and paste images are only supported with Mozilla Firefox and Google Chrome.' => '',
|
||||||
|
// 'Take a screenshot and press CTRL+V or ⌘+V to paste here.' => '',
|
||||||
|
// 'Screenshot uploaded successfully.' => '',
|
||||||
|
// 'SEK - Swedish Krona' => '',
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -853,4 +853,10 @@ return array(
|
|||||||
// 'Burndown chart for "%s"' => '',
|
// 'Burndown chart for "%s"' => '',
|
||||||
// 'Burndown chart' => '',
|
// 'Burndown chart' => '',
|
||||||
// 'This chart show the task complexity over the time (Work Remaining).' => '',
|
// 'This chart show the task complexity over the time (Work Remaining).' => '',
|
||||||
|
// 'Screenshot taken %s' => '',
|
||||||
|
// 'Add a screenshot' => '',
|
||||||
|
// 'Copy and paste images are only supported with Mozilla Firefox and Google Chrome.' => '',
|
||||||
|
// 'Take a screenshot and press CTRL+V or ⌘+V to paste here.' => '',
|
||||||
|
// 'Screenshot uploaded successfully.' => '',
|
||||||
|
// 'SEK - Swedish Krona' => '',
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -853,4 +853,10 @@ return array(
|
|||||||
// 'Burndown chart for "%s"' => '',
|
// 'Burndown chart for "%s"' => '',
|
||||||
// 'Burndown chart' => '',
|
// 'Burndown chart' => '',
|
||||||
// 'This chart show the task complexity over the time (Work Remaining).' => '',
|
// 'This chart show the task complexity over the time (Work Remaining).' => '',
|
||||||
|
// 'Screenshot taken %s' => '',
|
||||||
|
// 'Add a screenshot' => '',
|
||||||
|
// 'Copy and paste images are only supported with Mozilla Firefox and Google Chrome.' => '',
|
||||||
|
// 'Take a screenshot and press CTRL+V or ⌘+V to paste here.' => '',
|
||||||
|
// 'Screenshot uploaded successfully.' => '',
|
||||||
|
// 'SEK - Swedish Krona' => '',
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -853,4 +853,10 @@ return array(
|
|||||||
// 'Burndown chart for "%s"' => '',
|
// 'Burndown chart for "%s"' => '',
|
||||||
// 'Burndown chart' => '',
|
// 'Burndown chart' => '',
|
||||||
// 'This chart show the task complexity over the time (Work Remaining).' => '',
|
// 'This chart show the task complexity over the time (Work Remaining).' => '',
|
||||||
|
// 'Screenshot taken %s' => '',
|
||||||
|
// 'Add a screenshot' => '',
|
||||||
|
// 'Copy and paste images are only supported with Mozilla Firefox and Google Chrome.' => '',
|
||||||
|
// 'Take a screenshot and press CTRL+V or ⌘+V to paste here.' => '',
|
||||||
|
// 'Screenshot uploaded successfully.' => '',
|
||||||
|
// 'SEK - Swedish Krona' => '',
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -853,4 +853,10 @@ return array(
|
|||||||
// 'Burndown chart for "%s"' => '',
|
// 'Burndown chart for "%s"' => '',
|
||||||
// 'Burndown chart' => '',
|
// 'Burndown chart' => '',
|
||||||
// 'This chart show the task complexity over the time (Work Remaining).' => '',
|
// 'This chart show the task complexity over the time (Work Remaining).' => '',
|
||||||
|
// 'Screenshot taken %s' => '',
|
||||||
|
// 'Add a screenshot' => '',
|
||||||
|
// 'Copy and paste images are only supported with Mozilla Firefox and Google Chrome.' => '',
|
||||||
|
// 'Take a screenshot and press CTRL+V or ⌘+V to paste here.' => '',
|
||||||
|
// 'Screenshot uploaded successfully.' => '',
|
||||||
|
// 'SEK - Swedish Krona' => '',
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -853,4 +853,10 @@ return array(
|
|||||||
// 'Burndown chart for "%s"' => '',
|
// 'Burndown chart for "%s"' => '',
|
||||||
// 'Burndown chart' => '',
|
// 'Burndown chart' => '',
|
||||||
// 'This chart show the task complexity over the time (Work Remaining).' => '',
|
// 'This chart show the task complexity over the time (Work Remaining).' => '',
|
||||||
|
// 'Screenshot taken %s' => '',
|
||||||
|
// 'Add a screenshot' => '',
|
||||||
|
// 'Copy and paste images are only supported with Mozilla Firefox and Google Chrome.' => '',
|
||||||
|
// 'Take a screenshot and press CTRL+V or ⌘+V to paste here.' => '',
|
||||||
|
// 'Screenshot uploaded successfully.' => '',
|
||||||
|
// 'SEK - Swedish Krona' => '',
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -802,7 +802,6 @@ return array(
|
|||||||
'The budget line have been created successfully.' => 'Budgetlinjen har skapats.',
|
'The budget line have been created successfully.' => 'Budgetlinjen har skapats.',
|
||||||
'Unable to create the budget line.' => 'Kunde inte skapa budgetlinjen.',
|
'Unable to create the budget line.' => 'Kunde inte skapa budgetlinjen.',
|
||||||
'Unable to remove this budget line.' => 'Kunde inte ta bort budgetlinjen.',
|
'Unable to remove this budget line.' => 'Kunde inte ta bort budgetlinjen.',
|
||||||
'SEK - Swedish Krona' => 'SEK - Svensk Krona',
|
|
||||||
'USD - US Dollar' => 'USD - Amerikanska Dollar',
|
'USD - US Dollar' => 'USD - Amerikanska Dollar',
|
||||||
'Remaining' => 'Återstående',
|
'Remaining' => 'Återstående',
|
||||||
'Destination column' => 'Målkolumn',
|
'Destination column' => 'Målkolumn',
|
||||||
@@ -854,4 +853,10 @@ return array(
|
|||||||
'Burndown chart for "%s"' => 'Burndown diagram för "%s"',
|
'Burndown chart for "%s"' => 'Burndown diagram för "%s"',
|
||||||
'Burndown chart' => 'Burndown diagram',
|
'Burndown chart' => 'Burndown diagram',
|
||||||
'This chart show the task complexity over the time (Work Remaining).' => 'Diagrammet visar uppgiftens svårighet över tid (återstående arbete).',
|
'This chart show the task complexity over the time (Work Remaining).' => 'Diagrammet visar uppgiftens svårighet över tid (återstående arbete).',
|
||||||
|
// 'Screenshot taken %s' => '',
|
||||||
|
// 'Add a screenshot' => '',
|
||||||
|
// 'Copy and paste images are only supported with Mozilla Firefox and Google Chrome.' => '',
|
||||||
|
// 'Take a screenshot and press CTRL+V or ⌘+V to paste here.' => '',
|
||||||
|
// 'Screenshot uploaded successfully.' => '',
|
||||||
|
'SEK - Swedish Krona' => 'SEK - Svensk Krona',
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -853,4 +853,10 @@ return array(
|
|||||||
// 'Burndown chart for "%s"' => '',
|
// 'Burndown chart for "%s"' => '',
|
||||||
// 'Burndown chart' => '',
|
// 'Burndown chart' => '',
|
||||||
// 'This chart show the task complexity over the time (Work Remaining).' => '',
|
// 'This chart show the task complexity over the time (Work Remaining).' => '',
|
||||||
|
// 'Screenshot taken %s' => '',
|
||||||
|
// 'Add a screenshot' => '',
|
||||||
|
// 'Copy and paste images are only supported with Mozilla Firefox and Google Chrome.' => '',
|
||||||
|
// 'Take a screenshot and press CTRL+V or ⌘+V to paste here.' => '',
|
||||||
|
// 'Screenshot uploaded successfully.' => '',
|
||||||
|
// 'SEK - Swedish Krona' => '',
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -853,4 +853,10 @@ return array(
|
|||||||
// 'Burndown chart for "%s"' => '',
|
// 'Burndown chart for "%s"' => '',
|
||||||
// 'Burndown chart' => '',
|
// 'Burndown chart' => '',
|
||||||
// 'This chart show the task complexity over the time (Work Remaining).' => '',
|
// 'This chart show the task complexity over the time (Work Remaining).' => '',
|
||||||
|
// 'Screenshot taken %s' => '',
|
||||||
|
// 'Add a screenshot' => '',
|
||||||
|
// 'Copy and paste images are only supported with Mozilla Firefox and Google Chrome.' => '',
|
||||||
|
// 'Take a screenshot and press CTRL+V or ⌘+V to paste here.' => '',
|
||||||
|
// 'Screenshot uploaded successfully.' => '',
|
||||||
|
// 'SEK - Swedish Krona' => '',
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -853,4 +853,10 @@ return array(
|
|||||||
// 'Burndown chart for "%s"' => '',
|
// 'Burndown chart for "%s"' => '',
|
||||||
// 'Burndown chart' => '',
|
// 'Burndown chart' => '',
|
||||||
// 'This chart show the task complexity over the time (Work Remaining).' => '',
|
// 'This chart show the task complexity over the time (Work Remaining).' => '',
|
||||||
|
// 'Screenshot taken %s' => '',
|
||||||
|
// 'Add a screenshot' => '',
|
||||||
|
// 'Copy and paste images are only supported with Mozilla Firefox and Google Chrome.' => '',
|
||||||
|
// 'Take a screenshot and press CTRL+V or ⌘+V to paste here.' => '',
|
||||||
|
// 'Screenshot uploaded successfully.' => '',
|
||||||
|
// 'SEK - Swedish Krona' => '',
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ class Config extends Base
|
|||||||
'INR' => t('INR - Indian Rupee'),
|
'INR' => t('INR - Indian Rupee'),
|
||||||
'JPY' => t('JPY - Japanese Yen'),
|
'JPY' => t('JPY - Japanese Yen'),
|
||||||
'RSD' => t('RSD - Serbian dinar'),
|
'RSD' => t('RSD - Serbian dinar'),
|
||||||
|
'SEK' => t('SEK - Swedish Krona'),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -248,9 +248,9 @@ class File extends Base
|
|||||||
* Handle file upload
|
* Handle file upload
|
||||||
*
|
*
|
||||||
* @access public
|
* @access public
|
||||||
* @param integer $project_id Project id
|
* @param integer $project_id Project id
|
||||||
* @param integer $task_id Task id
|
* @param integer $task_id Task id
|
||||||
* @param string $form_name File form name
|
* @param string $form_name File form name
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
public function upload($project_id, $task_id, $form_name)
|
public function upload($project_id, $task_id, $form_name)
|
||||||
@@ -287,6 +287,38 @@ class File extends Base
|
|||||||
return count(array_unique($result)) === 1;
|
return count(array_unique($result)) === 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle screenshot upload
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param integer $project_id Project id
|
||||||
|
* @param integer $task_id Task id
|
||||||
|
* @param string $blob Base64 encoded image
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function uploadScreenshot($project_id, $task_id, $blob)
|
||||||
|
{
|
||||||
|
$data = base64_decode($blob);
|
||||||
|
|
||||||
|
if (empty($data)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$original_filename = e('Screenshot taken %s', dt('%B %e, %Y at %k:%M %p', time()));
|
||||||
|
$destination_filename = $this->generatePath($project_id, $task_id, $original_filename);
|
||||||
|
|
||||||
|
@mkdir(FILES_DIR.dirname($destination_filename), 0755, true);
|
||||||
|
@file_put_contents(FILES_DIR.$destination_filename, $data);
|
||||||
|
|
||||||
|
return $this->create(
|
||||||
|
$task_id,
|
||||||
|
$original_filename,
|
||||||
|
$destination_filename,
|
||||||
|
true,
|
||||||
|
strlen($data)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate a jpeg thumbnail from an image (output directly the image)
|
* Generate a jpeg thumbnail from an image (output directly the image)
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
<li><i class="fa fa-comment-o"></i> <?= $this->a(t('Add a comment'), 'comment', 'create', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'task-board-popover') ?></li>
|
<li><i class="fa fa-comment-o"></i> <?= $this->a(t('Add a comment'), 'comment', 'create', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'task-board-popover') ?></li>
|
||||||
<li><i class="fa fa-code-fork"></i> <?= $this->a(t('Add a link'), 'tasklink', 'create', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'task-board-popover') ?></li>
|
<li><i class="fa fa-code-fork"></i> <?= $this->a(t('Add a link'), 'tasklink', 'create', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'task-board-popover') ?></li>
|
||||||
<li><i class="fa fa-pencil-square-o"></i> <?= $this->a(t('Edit this task'), 'task', 'edit', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'task-board-popover') ?></li>
|
<li><i class="fa fa-pencil-square-o"></i> <?= $this->a(t('Edit this task'), 'task', 'edit', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'task-board-popover') ?></li>
|
||||||
|
<li><i class="fa fa-camera"></i> <?= $this->a(t('Add a screenshot'), 'board', 'screenshot', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'task-board-popover') ?></li>
|
||||||
<li><i class="fa fa-close"></i> <?= $this->a(t('Close this task'), 'task', 'close', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'redirect' => 'board'), false, 'task-board-popover') ?></li>
|
<li><i class="fa fa-close"></i> <?= $this->a(t('Close this task'), 'task', 'close', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'redirect' => 'board'), false, 'task-board-popover') ?></li>
|
||||||
</ul>
|
</ul>
|
||||||
</span>
|
</span>
|
||||||
|
|||||||
19
app/Template/file/screenshot.php
Normal file
19
app/Template/file/screenshot.php
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
<div class="page-header">
|
||||||
|
<h2><?= t('Add a screenshot') ?></h2>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="screenshot-zone">
|
||||||
|
<p id="screenshot-inner"><?= t('Take a screenshot and press CTRL+V or ⌘+V to paste here.') ?></p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<form action="<?= $this->u('file', 'screenshot', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'redirect' => $redirect)) ?>" method="post">
|
||||||
|
<input type="hidden" name="screenshot"/>
|
||||||
|
<?= $this->formCsrf() ?>
|
||||||
|
<div class="form-actions">
|
||||||
|
<input type="submit" value="<?= t('Save') ?>" class="btn btn-blue"/>
|
||||||
|
<?= t('or') ?>
|
||||||
|
<?= $this->a(t('cancel'), 'task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'close-popover') ?>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<p class="alert alert-info"><?= t('Copy and paste images are only supported with Mozilla Firefox and Google Chrome.') ?></p>
|
||||||
@@ -36,6 +36,9 @@
|
|||||||
<li>
|
<li>
|
||||||
<?= $this->a(t('Attach a document'), 'file', 'create', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>
|
<?= $this->a(t('Attach a document'), 'file', 'create', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>
|
||||||
</li>
|
</li>
|
||||||
|
<li>
|
||||||
|
<?= $this->a(t('Add a screenshot'), 'file', 'screenshot', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>
|
||||||
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<?= $this->a(t('Duplicate'), 'task', 'duplicate', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>
|
<?= $this->a(t('Duplicate'), 'task', 'duplicate', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>
|
||||||
</li>
|
</li>
|
||||||
|
|||||||
@@ -769,7 +769,7 @@ nav .active a {
|
|||||||
|
|
||||||
/* board table */
|
/* board table */
|
||||||
#board-container {
|
#board-container {
|
||||||
padding-bottom: 180px; /* Space to avoid dropdown menu truncated */
|
padding-bottom: 200px; /* Space to avoid dropdown menu truncated */
|
||||||
overflow-x: scroll;
|
overflow-x: scroll;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1083,17 +1083,21 @@ span.task-board-date-overdue {
|
|||||||
.task-link-closed {
|
.task-link-closed {
|
||||||
text-decoration: line-through;
|
text-decoration: line-through;
|
||||||
}
|
}
|
||||||
|
|
||||||
.task-show-images {
|
.task-show-images {
|
||||||
list-style-type: none;
|
list-style-type: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.task-show-images li img {
|
.task-show-images li img {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.task-show-images li .img_container {
|
.task-show-images li .img_container {
|
||||||
width: 250px;
|
width: 250px;
|
||||||
height: 100px;
|
height: 100px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
.task-show-images li {
|
.task-show-images li {
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
@@ -1102,20 +1106,44 @@ span.task-board-date-overdue {
|
|||||||
display: inline-block;
|
display: inline-block;
|
||||||
vertical-align: top;
|
vertical-align: top;
|
||||||
}
|
}
|
||||||
|
|
||||||
.task-show-images li p{
|
.task-show-images li p{
|
||||||
padding: 5px;
|
padding: 5px;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
.task-show-images li:hover {
|
.task-show-images li:hover {
|
||||||
background: #eee;
|
background: #eee;
|
||||||
}
|
}
|
||||||
|
|
||||||
.task-show-image-actions {
|
.task-show-image-actions {
|
||||||
margin-left: 5px;
|
margin-left: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.task-show-file-table {
|
.task-show-file-table {
|
||||||
width: auto;
|
width: auto;
|
||||||
}
|
}
|
||||||
/* comments */
|
|
||||||
|
/* screenshots */
|
||||||
|
#screenshot-zone {
|
||||||
|
position: relative;
|
||||||
|
border: 2px dashed #ccc;
|
||||||
|
width: 90%;
|
||||||
|
height: 250px;
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
#screenshot-inner {
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
bottom: 48%;
|
||||||
|
width: 100%;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
#screenshot-zone.screenshot-pasted {
|
||||||
|
border: 2px solid #333;
|
||||||
|
}/* comments */
|
||||||
.comment {
|
.comment {
|
||||||
margin-bottom: 20px;
|
margin-bottom: 20px;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,7 +20,7 @@
|
|||||||
|
|
||||||
/* board table */
|
/* board table */
|
||||||
#board-container {
|
#board-container {
|
||||||
padding-bottom: 180px; /* Space to avoid dropdown menu truncated */
|
padding-bottom: 200px; /* Space to avoid dropdown menu truncated */
|
||||||
overflow-x: scroll;
|
overflow-x: scroll;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -243,17 +243,21 @@ span.task-board-date-overdue {
|
|||||||
.task-link-closed {
|
.task-link-closed {
|
||||||
text-decoration: line-through;
|
text-decoration: line-through;
|
||||||
}
|
}
|
||||||
|
|
||||||
.task-show-images {
|
.task-show-images {
|
||||||
list-style-type: none;
|
list-style-type: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.task-show-images li img {
|
.task-show-images li img {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.task-show-images li .img_container {
|
.task-show-images li .img_container {
|
||||||
width: 250px;
|
width: 250px;
|
||||||
height: 100px;
|
height: 100px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
.task-show-images li {
|
.task-show-images li {
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
@@ -262,16 +266,41 @@ span.task-board-date-overdue {
|
|||||||
display: inline-block;
|
display: inline-block;
|
||||||
vertical-align: top;
|
vertical-align: top;
|
||||||
}
|
}
|
||||||
|
|
||||||
.task-show-images li p{
|
.task-show-images li p{
|
||||||
padding: 5px;
|
padding: 5px;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
.task-show-images li:hover {
|
.task-show-images li:hover {
|
||||||
background: #eee;
|
background: #eee;
|
||||||
}
|
}
|
||||||
|
|
||||||
.task-show-image-actions {
|
.task-show-image-actions {
|
||||||
margin-left: 5px;
|
margin-left: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.task-show-file-table {
|
.task-show-file-table {
|
||||||
width: auto;
|
width: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* screenshots */
|
||||||
|
#screenshot-zone {
|
||||||
|
position: relative;
|
||||||
|
border: 2px dashed #ccc;
|
||||||
|
width: 90%;
|
||||||
|
height: 250px;
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
#screenshot-inner {
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
bottom: 48%;
|
||||||
|
width: 100%;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
#screenshot-zone.screenshot-pasted {
|
||||||
|
border: 2px solid #333;
|
||||||
|
}
|
||||||
File diff suppressed because one or more lines are too long
@@ -263,6 +263,11 @@ var Kanboard = (function() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Screenshot
|
||||||
|
if (Kanboard.Exists("screenshot-zone")) {
|
||||||
|
Kanboard.Screenshot.Init();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
102
assets/js/src/screenshot.js
Normal file
102
assets/js/src/screenshot.js
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
Kanboard.Screenshot = (function() {
|
||||||
|
|
||||||
|
var pasteCatcher = null;
|
||||||
|
|
||||||
|
// Setup event listener and workarounds
|
||||||
|
function init()
|
||||||
|
{
|
||||||
|
if (! window.Clipboard) {
|
||||||
|
|
||||||
|
// Create a contenteditable element
|
||||||
|
pasteCatcher = document.createElement("div");
|
||||||
|
pasteCatcher.setAttribute("contenteditable", "");
|
||||||
|
pasteCatcher.style.opacity = 0;
|
||||||
|
document.body.appendChild(pasteCatcher);
|
||||||
|
|
||||||
|
// Make sure it is always in focus
|
||||||
|
pasteCatcher.focus();
|
||||||
|
document.addEventListener("click", function() { pasteCatcher.focus(); });
|
||||||
|
}
|
||||||
|
|
||||||
|
window.addEventListener("paste", pasteHandler);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Paste event callback
|
||||||
|
function pasteHandler(e)
|
||||||
|
{
|
||||||
|
// Firefox doesn't have the property e.clipboardData.items (only Chrome)
|
||||||
|
if (e.clipboardData && e.clipboardData.items) {
|
||||||
|
|
||||||
|
var items = e.clipboardData.items;
|
||||||
|
|
||||||
|
if (items) {
|
||||||
|
|
||||||
|
for (var i = 0; i < items.length; i++) {
|
||||||
|
|
||||||
|
// Find an image in pasted elements
|
||||||
|
if (items[i].type.indexOf("image") !== -1) {
|
||||||
|
|
||||||
|
var blob = items[i].getAsFile();
|
||||||
|
|
||||||
|
// Get the image as base64 data
|
||||||
|
var reader = new FileReader();
|
||||||
|
reader.onload = function(event) {
|
||||||
|
createImage(event.target.result);
|
||||||
|
};
|
||||||
|
|
||||||
|
reader.readAsDataURL(blob);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
|
||||||
|
// Handle Firefox
|
||||||
|
setTimeout(checkInput, 100);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse the input in the paste catcher element
|
||||||
|
function checkInput()
|
||||||
|
{
|
||||||
|
var child = pasteCatcher.childNodes[0];
|
||||||
|
pasteCatcher.innerHTML = "";
|
||||||
|
|
||||||
|
if (child) {
|
||||||
|
// If the user pastes an image, the src attribute
|
||||||
|
// will represent the image as a base64 encoded string.
|
||||||
|
if (child.tagName === "IMG") {
|
||||||
|
createImage(child.src);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Creates a new image from a given source
|
||||||
|
function createImage(blob)
|
||||||
|
{
|
||||||
|
var pastedImage = new Image();
|
||||||
|
pastedImage.src = blob;
|
||||||
|
|
||||||
|
// Send the image content to the form variable
|
||||||
|
pastedImage.onload = function() {
|
||||||
|
var sourceSplit = blob.split("base64,");
|
||||||
|
var sourceString = sourceSplit[1];
|
||||||
|
$("input[name=screenshot]").val(sourceString);
|
||||||
|
};
|
||||||
|
|
||||||
|
document.getElementById("screenshot-inner").style.display = "none";
|
||||||
|
document.getElementById("screenshot-zone").className = "screenshot-pasted";
|
||||||
|
document.getElementById("screenshot-zone").appendChild(pastedImage);
|
||||||
|
}
|
||||||
|
|
||||||
|
jQuery(document).ready(function() {
|
||||||
|
|
||||||
|
if (Kanboard.Exists("screenshot-zone")) {
|
||||||
|
init();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
Init: init
|
||||||
|
};
|
||||||
|
})();
|
||||||
26
docs/screenshots.markdown
Normal file
26
docs/screenshots.markdown
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
Adding screenshots
|
||||||
|
==================
|
||||||
|
|
||||||
|
You can copy and paste images directly in Kanboard to save time.
|
||||||
|
These images are uploaded as attachments to the task.
|
||||||
|
|
||||||
|
This is especially useful for taking screenshots to describe an issue by example.
|
||||||
|
|
||||||
|
You can add screenshots directly from the board by clicking on the dropdown menu or in the task view page.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
To add a new image, take your screenshot and paste with CTRL+V or Command+V:
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
On Mac OS X, you can use those shortcuts to take screenshots:
|
||||||
|
|
||||||
|
- Command-Control-Shift-3: Take a screenshot of the screen, and save it to the clipboard
|
||||||
|
- Command-Control-Shift-4, then select an area: Take a screenshot of an area and save it to the clipboard
|
||||||
|
- Command-Control-Shift-4, then space, then click a window: Take a screenshot of a window and save it to the clipboard
|
||||||
|
|
||||||
|
There are also several third-party applications that can be used to take screenshots with annotations and shapes.
|
||||||
|
|
||||||
|
Note: this feature **works only with Mozilla Firefox and Google Chrome**.
|
||||||
|
If you use another browser, you have to upload an attachment manually.
|
||||||
@@ -3,9 +3,9 @@
|
|||||||
app_css="base links title table form button alert tooltip header board task comment subtask markdown listing activity dashboard pagination popover confirm sidebar responsive dropdown"
|
app_css="base links title table form button alert tooltip header board task comment subtask markdown listing activity dashboard pagination popover confirm sidebar responsive dropdown"
|
||||||
vendor_css="jquery-ui.min chosen.min fullcalendar.min font-awesome.min"
|
vendor_css="jquery-ui.min chosen.min fullcalendar.min font-awesome.min"
|
||||||
|
|
||||||
app_js="base board calendar analytic swimlane dashboard budget"
|
app_js="base board calendar analytic swimlane dashboard budget screenshot"
|
||||||
vendor_js="jquery-1.11.1.min jquery-ui.min jquery.ui.touch-punch.min chosen.jquery.min dropit.min moment.min fullcalendar.min mousetrap.min mousetrap-global-bind.min app.min"
|
vendor_js="jquery-1.11.1.min jquery-ui.min jquery.ui.touch-punch.min chosen.jquery.min dropit.min moment.min fullcalendar.min mousetrap.min mousetrap-global-bind.min app.min"
|
||||||
lang_js="da de es fi fr hu it ja pl pt-br ru sv th zh-cn tr"
|
lang_js="da de es fi fr hu it ja nl pl pt-br ru sv th tr zh-cn"
|
||||||
|
|
||||||
function merge_css {
|
function merge_css {
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user