Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/matomo-org/matomo.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormattab <matthieu.aubry@gmail.com>2013-03-28 03:42:39 +0400
committermattab <matthieu.aubry@gmail.com>2013-03-28 03:42:40 +0400
commitae4b03163792f0b6e933933e5d37df87dc3fd566 (patch)
treed1d7510a9728f587d3d63ebd03e4ecf3d904838b /plugins/Annotations
parent158c2150f5f2e13ece459b8d131244c11b763997 (diff)
Mass conversion of all files to the newly agreed coding standard: PSR 1/2
Converting Piwik core source files, PHP, JS, TPL, CSS More info: http://piwik.org/participate/coding-standards/
Diffstat (limited to 'plugins/Annotations')
-rwxr-xr-xplugins/Annotations/API.php691
-rwxr-xr-xplugins/Annotations/AnnotationList.php824
-rwxr-xr-xplugins/Annotations/Annotations.php96
-rwxr-xr-xplugins/Annotations/Controller.php406
-rwxr-xr-xplugins/Annotations/templates/annotation.tpl83
-rwxr-xr-xplugins/Annotations/templates/annotationManager.tpl36
-rwxr-xr-xplugins/Annotations/templates/annotations.js1194
-rwxr-xr-xplugins/Annotations/templates/annotations.tpl47
-rwxr-xr-xplugins/Annotations/templates/evolutionAnnotations.tpl18
-rwxr-xr-xplugins/Annotations/templates/styles.css216
10 files changed, 1764 insertions, 1847 deletions
diff --git a/plugins/Annotations/API.php b/plugins/Annotations/API.php
index e03f5f5dba..7750c816e3 100755
--- a/plugins/Annotations/API.php
+++ b/plugins/Annotations/API.php
@@ -12,365 +12,350 @@
/**
* @see plugins/Annotations/AnnotationList.php
*/
-require_once PIWIK_INCLUDE_PATH.'/plugins/Annotations/AnnotationList.php';
+require_once PIWIK_INCLUDE_PATH . '/plugins/Annotations/AnnotationList.php';
/**
* API for annotations plugin. Provides methods to create, modify, delete & query
* annotations.
- *
+ *
* @package Piwik_Annotations
*/
class Piwik_Annotations_API
{
- static private $instance = null;
-
- /**
- * Returns this API's singleton instance.
- *
- * @return Piwik_Annotations_API
- */
- static public function getInstance()
- {
- if (self::$instance == null)
- {
- self::$instance = new self;
- }
- return self::$instance;
- }
-
- /**
- * Create a new annotation for a site.
- *
- * @param string $idSite The site ID to add the annotation to.
- * @param string $date The date the annotation is attached to.
- * @param string $note The text of the annotation.
- * @param string $starred Either 0 or 1. Whether the annotation should be starred.
- * @return array Returns an array of two elements. The first element (indexed by
- * 'annotation') is the new annotation. The second element (indexed
- * by 'idNote' is the new note's ID).
- */
- public function add( $idSite, $date, $note, $starred = 0 )
- {
- $this->checkSingleIdSite($idSite, $extraMessage = "Note: Cannot add one note to multiple sites.");
- $this->checkDateIsValid($date);
- $this->checkUserCanAddNotesFor($idSite);
-
- // add, save & return a new annotation
- $annotations = new Piwik_Annotations_AnnotationList($idSite);
-
- $newAnnotation = $annotations->add($idSite, $date, $note, $starred);
- $annotations->save($idSite);
-
- return $newAnnotation;
- }
-
- /**
- * Modifies an annotation for a site and returns the modified annotation
- * and its ID.
- *
- * If the current user is not allowed to modify an annotation, an exception
- * will be thrown. A user can modify a note if:
- * - the user has admin access for the site, OR
- * - the user has view access, is not the anonymous user and is the user that
- * created the note
- *
- * @param string $idSite The site ID to add the annotation to.
- * @param string $idNote The ID of the note.
- * @param string|null $date The date the annotation is attached to. If null, the annotation's
- * date is not modified.
- * @param string|null $note The text of the annotation. If null, the annotation's text
- * is not modified.
- * @param string|null $starred Either 0 or 1. Whether the annotation should be starred.
- * If null, the annotation is not starred/un-starred.
- * @return array Returns an array of two elements. The first element (indexed by
- * 'annotation') is the new annotation. The second element (indexed
- * by 'idNote' is the new note's ID).
- */
- public function save( $idSite, $idNote, $date = null, $note = null, $starred = null )
- {
- $this->checkSingleIdSite($idSite, $extraMessage = "Note: Cannot modify more than one note at a time.");
- $this->checkDateIsValid($date, $canBeNull = true);
-
- // get the annotations for the site
- $annotations = new Piwik_Annotations_AnnotationList($idSite);
-
- // check permissions
- $this->checkUserCanModifyOrDelete($idSite, $annotations->get($idSite, $idNote));
-
- // modify the annotation, and save the whole list
- $annotations->update($idSite, $idNote, $date, $note, $starred);
- $annotations->save($idSite);
-
- return $annotations->get($idSite, $idNote);
- }
-
- /**
- * Removes an annotation from a site's list of annotations.
- *
- * If the current user is not allowed to delete the annotation, an exception
- * will be thrown. A user can delete a note if:
- * - the user has admin access for the site, OR
- * - the user has view access, is not the anonymous user and is the user that
- * created the note
- *
- * @param string $idSite The site ID to add the annotation to.
- * @param string $idNote The ID of the note to delete.
- */
- public function delete( $idSite, $idNote )
- {
- $this->checkSingleIdSite($idSite, $extraMessage = "Note: Cannot delete multiple notes.");
-
- $annotations = new Piwik_Annotations_AnnotationList($idSite);
-
- // check permissions
- $this->checkUserCanModifyOrDelete($idSite, $annotations->get($idSite, $idNote));
-
- // remove the note & save the list
- $annotations->remove($idSite, $idNote);
- $annotations->save($idSite);
- }
-
- /**
- * Returns a single note for one site.
- *
- * @param string $idSite The site ID to add the annotation to.
- * @param string $idNote The ID of the note to get.
- * @return array The annotation. It will contain the following properties:
- * - date: The date the annotation was recorded for.
- * - note: The note text.
- * - starred: Whether the note is starred or not.
- * - user: The user that created the note.
- * - canEditOrDelete: Whether the user that called this method can edit or
- * delete the annotation returned.
- */
- public function get( $idSite, $idNote )
- {
- $this->checkSingleIdSite($idSite, $extraMessage = "Note: Specify only one site ID when getting ONE note.");
- Piwik::checkUserHasViewAccess($idSite);
-
- // get single annotation
- $annotations = new Piwik_Annotations_AnnotationList($idSite);
- return $annotations->get($idSite, $idNote);
- }
-
- /**
- * Returns every annotation for a specific site within a specific date range.
- * The date range is specified by a date, the period type (day/week/month/year)
- * and an optional number of N periods in the past to include.
- *
- * @param string $idSite The site ID to add the annotation to. Can be one ID or
- * a list of site IDs.
- * @param string|false $date The date of the period.
- * @param string $period The period type.
- * @param int|false $lastN Whether to include the last N number of periods in the
- * date range or not.
- * @return array An array that indexes arrays of annotations by site ID. ie,
- * array(
- * 5 => array(
- * array(...), // annotation #1
- * array(...), // annotation #2
- * ),
- * 8 => array(...)
- * )
- */
- public function getAll( $idSite, $date = false, $period = 'day', $lastN = false )
- {
- Piwik::checkUserHasViewAccess($idSite);
-
- $annotations = new Piwik_Annotations_AnnotationList($idSite);
-
- // if date/period are supplied, determine start/end date for search
- list($startDate, $endDate) = self::getDateRangeForPeriod($date, $period, $lastN);
-
- return $annotations->search($startDate, $endDate);
- }
-
- /**
- * Returns the count of annotations for a list of periods, including the count of
- * starred annotations.
- *
- * @param string $idSite The site ID to add the annotation to.
- * @param string|false $date The date of the period.
- * @param string $period The period type.
- * @param int|false $lastN Whether to get counts for the last N number of periods or not.
- * @return array An array mapping site IDs to arrays holding dates & the count of
- * annotations made for those dates. eg,
- * array(
- * 5 => array(
- * array('2012-01-02', array('count' => 4, 'starred' => 2)),
- * array('2012-01-03', array('count' => 0, 'starred' => 0)),
- * array('2012-01-04', array('count' => 2, 'starred' => 0)),
- * ),
- * 6 => array(
- * array('2012-01-02', array('count' => 1, 'starred' => 0)),
- * array('2012-01-03', array('count' => 4, 'starred' => 3)),
- * array('2012-01-04', array('count' => 2, 'starred' => 0)),
- * ),
- * ...
- * )
- */
- public function getAnnotationCountForDates( $idSite, $date, $period, $lastN = false, $getAnnotationText = false )
- {
- Piwik::checkUserHasViewAccess($idSite);
-
- // get start & end date for request. lastN is ignored if $period == 'range'
- list($startDate, $endDate) = self::getDateRangeForPeriod($date, $period, $lastN);
- if ($period == 'range')
- {
- $period = 'day';
- }
-
- // create list of dates
- $dates = array();
- for (; $startDate->getTimestamp() <= $endDate->getTimestamp(); $startDate = $startDate->addPeriod(1, $period))
- {
- $dates[] = $startDate;
- }
- // we add one for the end of the last period (used in for loop below to bound annotation dates)
- $dates[] = $startDate;
-
- // get annotations for the site
- $annotations = new Piwik_Annotations_AnnotationList($idSite);
-
- // create result w/ 0-counts
- $result = array();
- for ($i = 0; $i != count($dates) - 1; ++$i)
- {
- $date = $dates[$i];
- $nextDate = $dates[$i + 1];
- $strDate = $date->toString();
-
- foreach ($annotations->getIdSites() as $idSite)
- {
- $result[$idSite][$strDate] = $annotations->count($idSite, $date, $nextDate);
-
- // if only one annotation, return the one annotation's text w/ the counts
- if ($getAnnotationText
- && $result[$idSite][$strDate]['count'] == 1)
- {
- $annotationsForSite = $annotations->search(
- $date, Piwik_Date::factory($nextDate->getTimestamp() - 1), $idSite);
- $annotation = reset($annotationsForSite[$idSite]);
-
- $result[$idSite][$strDate]['note'] = $annotation['note'];
- }
- }
- }
-
- // convert associative array into array of pairs (so it can be traversed by index)
- $pairResult = array();
- foreach ($result as $idSite => $counts)
- {
- foreach ($counts as $date => $count)
- {
- $pairResult[$idSite][] = array($date, $count);
- }
- }
- return $pairResult;
- }
-
- /**
- * Throws if the current user is not allowed to modify or delete an annotation.
- *
- * @param int $idSite The site ID the annotation belongs to.
- * @param array $annotation The annotation.
- * @throws Exception if the current user is not allowed to modify/delete $annotation.
- */
- private function checkUserCanModifyOrDelete( $idSite, $annotation )
- {
- if (!$annotation['canEditOrDelete'])
- {
- throw new Exception(Piwik_Translate('Annotations_YouCannotModifyThisNote'));
- }
- }
-
- /**
- * Throws if the current user is not allowed to create annotations for a site.
- *
- * @param int $idSite The site ID.
- * @throws Exception if the current user is anonymous or does not have view access
- * for site w/ id=$idSite.
- */
- private static function checkUserCanAddNotesFor( $idSite )
- {
- if (!Piwik_Annotations_AnnotationList::canUserAddNotesFor($idSite))
- {
- throw new Exception("The current user is not allowed to add notes for site #$idSite.");
- }
- }
-
- /**
- * Returns start & end dates for the range described by a period and optional lastN
- * argument.
- *
- * @param string $date|false The start date of the period (or the date range of a range
- * period).
- * @param string $period The period type ('day', 'week', 'month', 'year' or 'range').
- * @param int|false $lastN Whether to include the last N periods in the range or not.
- * Ignored if period == range.
- *
- * @ignore
- */
- public static function getDateRangeForPeriod( $date, $period, $lastN = false )
- {
- if ($date === false)
- {
- return array(false, false);
- }
-
- // if the range is just a normal period (or the period is a range in which case lastN is ignored)
- if ($lastN === false
- || $period == 'range')
- {
- if ($period == 'range')
- {
- $oPeriod = new Piwik_Period_Range('day', $date);
- }
- else
- {
- $oPeriod = Piwik_Period::factory($period, Piwik_Date::factory($date));
- }
-
- $startDate = $oPeriod->getDateStart();
- $endDate = $oPeriod->getDateEnd();
- }
- else // if the range includes the last N periods
- {
- list($date, $lastN) =
- Piwik_ViewDataTable_GenerateGraphHTML_ChartEvolution::getDateRangeAndLastN($period, $date, $lastN);
- list($startDate, $endDate) = explode(',', $date);
-
- $startDate = Piwik_Date::factory($startDate);
- $endDate = Piwik_Date::factory($endDate);
- }
- return array($startDate, $endDate);
- }
-
- /**
- * Utility function, makes sure idSite string has only one site ID and throws if
- * otherwise.
- */
- private function checkSingleIdSite( $idSite, $extraMessage )
- {
- // can only add a note to one site
- if (!is_numeric($idSite))
- {
- throw new Exception("Invalid idSite: '$idSite'. $extraMessage");
- }
- }
-
- /**
- * Utility function, makes sure date string is valid date, and throws if
- * otherwise.
- */
- private function checkDateIsValid( $date, $canBeNull = false )
- {
- if ($date === null
- && $canBeNull)
- {
- return;
- }
-
- Piwik_Date::factory($date);
- }
+ static private $instance = null;
+
+ /**
+ * Returns this API's singleton instance.
+ *
+ * @return Piwik_Annotations_API
+ */
+ static public function getInstance()
+ {
+ if (self::$instance == null) {
+ self::$instance = new self;
+ }
+ return self::$instance;
+ }
+
+ /**
+ * Create a new annotation for a site.
+ *
+ * @param string $idSite The site ID to add the annotation to.
+ * @param string $date The date the annotation is attached to.
+ * @param string $note The text of the annotation.
+ * @param string $starred Either 0 or 1. Whether the annotation should be starred.
+ * @return array Returns an array of two elements. The first element (indexed by
+ * 'annotation') is the new annotation. The second element (indexed
+ * by 'idNote' is the new note's ID).
+ */
+ public function add($idSite, $date, $note, $starred = 0)
+ {
+ $this->checkSingleIdSite($idSite, $extraMessage = "Note: Cannot add one note to multiple sites.");
+ $this->checkDateIsValid($date);
+ $this->checkUserCanAddNotesFor($idSite);
+
+ // add, save & return a new annotation
+ $annotations = new Piwik_Annotations_AnnotationList($idSite);
+
+ $newAnnotation = $annotations->add($idSite, $date, $note, $starred);
+ $annotations->save($idSite);
+
+ return $newAnnotation;
+ }
+
+ /**
+ * Modifies an annotation for a site and returns the modified annotation
+ * and its ID.
+ *
+ * If the current user is not allowed to modify an annotation, an exception
+ * will be thrown. A user can modify a note if:
+ * - the user has admin access for the site, OR
+ * - the user has view access, is not the anonymous user and is the user that
+ * created the note
+ *
+ * @param string $idSite The site ID to add the annotation to.
+ * @param string $idNote The ID of the note.
+ * @param string|null $date The date the annotation is attached to. If null, the annotation's
+ * date is not modified.
+ * @param string|null $note The text of the annotation. If null, the annotation's text
+ * is not modified.
+ * @param string|null $starred Either 0 or 1. Whether the annotation should be starred.
+ * If null, the annotation is not starred/un-starred.
+ * @return array Returns an array of two elements. The first element (indexed by
+ * 'annotation') is the new annotation. The second element (indexed
+ * by 'idNote' is the new note's ID).
+ */
+ public function save($idSite, $idNote, $date = null, $note = null, $starred = null)
+ {
+ $this->checkSingleIdSite($idSite, $extraMessage = "Note: Cannot modify more than one note at a time.");
+ $this->checkDateIsValid($date, $canBeNull = true);
+
+ // get the annotations for the site
+ $annotations = new Piwik_Annotations_AnnotationList($idSite);
+
+ // check permissions
+ $this->checkUserCanModifyOrDelete($idSite, $annotations->get($idSite, $idNote));
+
+ // modify the annotation, and save the whole list
+ $annotations->update($idSite, $idNote, $date, $note, $starred);
+ $annotations->save($idSite);
+
+ return $annotations->get($idSite, $idNote);
+ }
+
+ /**
+ * Removes an annotation from a site's list of annotations.
+ *
+ * If the current user is not allowed to delete the annotation, an exception
+ * will be thrown. A user can delete a note if:
+ * - the user has admin access for the site, OR
+ * - the user has view access, is not the anonymous user and is the user that
+ * created the note
+ *
+ * @param string $idSite The site ID to add the annotation to.
+ * @param string $idNote The ID of the note to delete.
+ */
+ public function delete($idSite, $idNote)
+ {
+ $this->checkSingleIdSite($idSite, $extraMessage = "Note: Cannot delete multiple notes.");
+
+ $annotations = new Piwik_Annotations_AnnotationList($idSite);
+
+ // check permissions
+ $this->checkUserCanModifyOrDelete($idSite, $annotations->get($idSite, $idNote));
+
+ // remove the note & save the list
+ $annotations->remove($idSite, $idNote);
+ $annotations->save($idSite);
+ }
+
+ /**
+ * Returns a single note for one site.
+ *
+ * @param string $idSite The site ID to add the annotation to.
+ * @param string $idNote The ID of the note to get.
+ * @return array The annotation. It will contain the following properties:
+ * - date: The date the annotation was recorded for.
+ * - note: The note text.
+ * - starred: Whether the note is starred or not.
+ * - user: The user that created the note.
+ * - canEditOrDelete: Whether the user that called this method can edit or
+ * delete the annotation returned.
+ */
+ public function get($idSite, $idNote)
+ {
+ $this->checkSingleIdSite($idSite, $extraMessage = "Note: Specify only one site ID when getting ONE note.");
+ Piwik::checkUserHasViewAccess($idSite);
+
+ // get single annotation
+ $annotations = new Piwik_Annotations_AnnotationList($idSite);
+ return $annotations->get($idSite, $idNote);
+ }
+
+ /**
+ * Returns every annotation for a specific site within a specific date range.
+ * The date range is specified by a date, the period type (day/week/month/year)
+ * and an optional number of N periods in the past to include.
+ *
+ * @param string $idSite The site ID to add the annotation to. Can be one ID or
+ * a list of site IDs.
+ * @param string|false $date The date of the period.
+ * @param string $period The period type.
+ * @param int|false $lastN Whether to include the last N number of periods in the
+ * date range or not.
+ * @return array An array that indexes arrays of annotations by site ID. ie,
+ * array(
+ * 5 => array(
+ * array(...), // annotation #1
+ * array(...), // annotation #2
+ * ),
+ * 8 => array(...)
+ * )
+ */
+ public function getAll($idSite, $date = false, $period = 'day', $lastN = false)
+ {
+ Piwik::checkUserHasViewAccess($idSite);
+
+ $annotations = new Piwik_Annotations_AnnotationList($idSite);
+
+ // if date/period are supplied, determine start/end date for search
+ list($startDate, $endDate) = self::getDateRangeForPeriod($date, $period, $lastN);
+
+ return $annotations->search($startDate, $endDate);
+ }
+
+ /**
+ * Returns the count of annotations for a list of periods, including the count of
+ * starred annotations.
+ *
+ * @param string $idSite The site ID to add the annotation to.
+ * @param string|false $date The date of the period.
+ * @param string $period The period type.
+ * @param int|false $lastN Whether to get counts for the last N number of periods or not.
+ * @return array An array mapping site IDs to arrays holding dates & the count of
+ * annotations made for those dates. eg,
+ * array(
+ * 5 => array(
+ * array('2012-01-02', array('count' => 4, 'starred' => 2)),
+ * array('2012-01-03', array('count' => 0, 'starred' => 0)),
+ * array('2012-01-04', array('count' => 2, 'starred' => 0)),
+ * ),
+ * 6 => array(
+ * array('2012-01-02', array('count' => 1, 'starred' => 0)),
+ * array('2012-01-03', array('count' => 4, 'starred' => 3)),
+ * array('2012-01-04', array('count' => 2, 'starred' => 0)),
+ * ),
+ * ...
+ * )
+ */
+ public function getAnnotationCountForDates($idSite, $date, $period, $lastN = false, $getAnnotationText = false)
+ {
+ Piwik::checkUserHasViewAccess($idSite);
+
+ // get start & end date for request. lastN is ignored if $period == 'range'
+ list($startDate, $endDate) = self::getDateRangeForPeriod($date, $period, $lastN);
+ if ($period == 'range') {
+ $period = 'day';
+ }
+
+ // create list of dates
+ $dates = array();
+ for (; $startDate->getTimestamp() <= $endDate->getTimestamp(); $startDate = $startDate->addPeriod(1, $period)) {
+ $dates[] = $startDate;
+ }
+ // we add one for the end of the last period (used in for loop below to bound annotation dates)
+ $dates[] = $startDate;
+
+ // get annotations for the site
+ $annotations = new Piwik_Annotations_AnnotationList($idSite);
+
+ // create result w/ 0-counts
+ $result = array();
+ for ($i = 0; $i != count($dates) - 1; ++$i) {
+ $date = $dates[$i];
+ $nextDate = $dates[$i + 1];
+ $strDate = $date->toString();
+
+ foreach ($annotations->getIdSites() as $idSite) {
+ $result[$idSite][$strDate] = $annotations->count($idSite, $date, $nextDate);
+
+ // if only one annotation, return the one annotation's text w/ the counts
+ if ($getAnnotationText
+ && $result[$idSite][$strDate]['count'] == 1
+ ) {
+ $annotationsForSite = $annotations->search(
+ $date, Piwik_Date::factory($nextDate->getTimestamp() - 1), $idSite);
+ $annotation = reset($annotationsForSite[$idSite]);
+
+ $result[$idSite][$strDate]['note'] = $annotation['note'];
+ }
+ }
+ }
+
+ // convert associative array into array of pairs (so it can be traversed by index)
+ $pairResult = array();
+ foreach ($result as $idSite => $counts) {
+ foreach ($counts as $date => $count) {
+ $pairResult[$idSite][] = array($date, $count);
+ }
+ }
+ return $pairResult;
+ }
+
+ /**
+ * Throws if the current user is not allowed to modify or delete an annotation.
+ *
+ * @param int $idSite The site ID the annotation belongs to.
+ * @param array $annotation The annotation.
+ * @throws Exception if the current user is not allowed to modify/delete $annotation.
+ */
+ private function checkUserCanModifyOrDelete($idSite, $annotation)
+ {
+ if (!$annotation['canEditOrDelete']) {
+ throw new Exception(Piwik_Translate('Annotations_YouCannotModifyThisNote'));
+ }
+ }
+
+ /**
+ * Throws if the current user is not allowed to create annotations for a site.
+ *
+ * @param int $idSite The site ID.
+ * @throws Exception if the current user is anonymous or does not have view access
+ * for site w/ id=$idSite.
+ */
+ private static function checkUserCanAddNotesFor($idSite)
+ {
+ if (!Piwik_Annotations_AnnotationList::canUserAddNotesFor($idSite)) {
+ throw new Exception("The current user is not allowed to add notes for site #$idSite.");
+ }
+ }
+
+ /**
+ * Returns start & end dates for the range described by a period and optional lastN
+ * argument.
+ *
+ * @param string $date|false The start date of the period (or the date range of a range
+ * period).
+ * @param string $period The period type ('day', 'week', 'month', 'year' or 'range').
+ * @param int|false $lastN Whether to include the last N periods in the range or not.
+ * Ignored if period == range.
+ *
+ * @ignore
+ */
+ public static function getDateRangeForPeriod($date, $period, $lastN = false)
+ {
+ if ($date === false) {
+ return array(false, false);
+ }
+
+ // if the range is just a normal period (or the period is a range in which case lastN is ignored)
+ if ($lastN === false
+ || $period == 'range'
+ ) {
+ if ($period == 'range') {
+ $oPeriod = new Piwik_Period_Range('day', $date);
+ } else {
+ $oPeriod = Piwik_Period::factory($period, Piwik_Date::factory($date));
+ }
+
+ $startDate = $oPeriod->getDateStart();
+ $endDate = $oPeriod->getDateEnd();
+ } else // if the range includes the last N periods
+ {
+ list($date, $lastN) =
+ Piwik_ViewDataTable_GenerateGraphHTML_ChartEvolution::getDateRangeAndLastN($period, $date, $lastN);
+ list($startDate, $endDate) = explode(',', $date);
+
+ $startDate = Piwik_Date::factory($startDate);
+ $endDate = Piwik_Date::factory($endDate);
+ }
+ return array($startDate, $endDate);
+ }
+
+ /**
+ * Utility function, makes sure idSite string has only one site ID and throws if
+ * otherwise.
+ */
+ private function checkSingleIdSite($idSite, $extraMessage)
+ {
+ // can only add a note to one site
+ if (!is_numeric($idSite)) {
+ throw new Exception("Invalid idSite: '$idSite'. $extraMessage");
+ }
+ }
+
+ /**
+ * Utility function, makes sure date string is valid date, and throws if
+ * otherwise.
+ */
+ private function checkDateIsValid($date, $canBeNull = false)
+ {
+ if ($date === null
+ && $canBeNull
+ ) {
+ return;
+ }
+
+ Piwik_Date::factory($date);
+ }
}
diff --git a/plugins/Annotations/AnnotationList.php b/plugins/Annotations/AnnotationList.php
index 47d897f2dc..daed59a554 100755
--- a/plugins/Annotations/AnnotationList.php
+++ b/plugins/Annotations/AnnotationList.php
@@ -12,440 +12,418 @@
/**
* This class can be used to query & modify annotations for multiple sites
* at once.
- *
+ *
* Example use:
* $annotations = new Piwik_Annotations_AnnotationList($idSites = "1,2,5");
* $annotation = $annotations->get($idSite = 1, $idNote = 4);
* // do stuff w/ annotation
* $annotations->update($idSite = 2, $idNote = 4, $note = "This is the new text.");
* $annotations->save($idSite);
- *
+ *
* Note: There is a concurrency issue w/ this code. If two users try to save
* an annotation for the same site, it's possible one of their changes will
* never get made (as it will be overwritten by the other's).
- *
+ *
* @package Piwik_Annotations
*/
class Piwik_Annotations_AnnotationList
{
- const ANNOTATION_COLLECTION_OPTION_SUFFIX = '_annotations';
-
- /**
- * List of site IDs this instance holds annotations for.
- *
- * @var array
- */
- private $idSites;
-
- /**
- * Array that associates lists of annotations with site IDs.
- *
- * @var array
- */
- private $annotations;
-
- /**
- * Constructor. Loads annotations from the database.
- *
- * @param string|int $idSites The list of site IDs to load annotations for.
- */
- public function __construct( $idSites )
- {
- $this->idSites = Piwik_Site::getIdSitesFromIdSitesString($idSites);
- $this->annotations = $this->getAnnotationsForSite();
- }
-
- /**
- * Returns the list of site IDs this list contains annotations for.
- *
- * @return array
- */
- public function getIdSites()
- {
- return $this->idSites;
- }
-
- /**
- * Creates a new annotation for a site. This method does not perist the result.
- * To save the new annotation in the database, call $this->save.
- *
- * @param int $idSite The ID of the site to add an annotation to.
- * @param string $date The date the annotation is in reference to.
- * @param string $note The text of the new annotation.
- * @param int $starred Either 1 or 0. If 1, the new annotation has been starred,
- * otherwise it will start out unstarred.
- * @return array The added annotation.
- * @throws Exception if $idSite is not an ID that was supplied upon construction.
- */
- public function add($idSite, $date, $note, $starred = 0)
- {
- $this->checkIdSiteIsLoaded($idSite);
-
- $this->annotations[$idSite][] = self::makeAnnotation($date, $note, $starred);
-
- // get the id of the new annotation
- end($this->annotations[$idSite]);
- $newNoteId = key($this->annotations[$idSite]);
-
- return $this->get($idSite, $newNoteId);
- }
-
- /**
- * Persists the annotations list for a site, overwriting whatever exists.
- *
- * @param int $idSite The ID of the site to save annotations for.
- * @throws Exception if $idSite is not an ID that was supplied upon construction.
- */
- public function save($idSite)
- {
- $this->checkIdSiteIsLoaded($idSite);
-
- $optionName = self::getAnnotationCollectionOptionName($idSite);
- Piwik_SetOption($optionName, serialize($this->annotations[$idSite]));
- }
-
- /**
- * Modifies an annotation in this instance's collection of annotations.
- *
- * Note: This method does not perist the change in the DB. The save method must
- * be called for that.
- *
- * @param int $idSite The ID of the site whose annotation will be updated.
- * @param int $idNote The ID of the note.
- * @param string|null $date The new date of the annotation, eg '2012-01-01'. If
- * null, no change is made.
- * @param string|null $note The new text of the annotation. If null, no change
- * is made.
- * @param int|null $starred Either 1 or 0, whether the annotation should be
- * starred or not. If null, no change is made.
- * @throws Exception if $idSite is not an ID that was supplied upon construction.
- * @throws Exception if $idNote does not refer to valid note for the site.
- */
- public function update( $idSite, $idNote, $date = null, $note = null, $starred = null )
- {
- $this->checkIdSiteIsLoaded($idSite);
- $this->checkNoteExists($idSite, $idNote);
-
- $annotation =& $this->annotations[$idSite][$idNote];
- if ($date !== null)
- {
- $annotation['date'] = $date;
- }
- if ($note !== null)
- {
- $annotation['note'] = $note;
- }
- if ($starred !== null)
- {
- $annotation['starred'] = $starred;
- }
- }
-
- /**
- * Removes a note from a site's collection of annotations.
- *
- * Note: This method does not perist the change in the DB. The save method must
- * be called for that.
- *
- * @param int $idSite The ID of the site whose annotation will be updated.
- * @param int $idNote The ID of the note.
- * @throws Exception if $idSite is not an ID that was supplied upon construction.
- * @throws Exception if $idNote does not refer to valid note for the site.
- */
- public function remove( $idSite, $idNote )
- {
- $this->checkIdSiteIsLoaded($idSite);
- $this->checkNoteExists($idSite, $idNote);
-
- unset($this->annotations[$idSite][$idNote]);
- }
-
- /**
- * Retrieves an annotation by ID.
- *
- * This function returns an array with the following elements:
- * - idNote: The ID of the annotation.
- * - date: The date of the annotation.
- * - note: The text of the annotation.
- * - starred: 1 or 0, whether the annotation is stared;
- * - user: (unless current user is anonymous) The user that created the annotation.
- * - canEditOrDelete: True if the user can edit/delete the annotation.
- *
- * @param int $idSite The ID of the site to get an annotation for.
- * @param int $idNote The ID of the note to get.
- * @param array The annotation.
- * @throws Exception if $idSite is not an ID that was supplied upon construction.
- * @throws Exception if $idNote does not refer to valid note for the site.
- */
- public function get( $idSite, $idNote )
- {
- $this->checkIdSiteIsLoaded($idSite);
- $this->checkNoteExists($idSite, $idNote);
-
- $annotation = $this->annotations[$idSite][$idNote];
- $this->augmentAnnotationData($idSite, $idNote, $annotation);
- return $annotation;
- }
-
- /**
- * Returns all annotations within a specific date range. The result is
- * an array that maps site IDs with arrays of annotations within the range.
- *
- * Note: The date range is inclusive.
- *
- * @see self::get for info on what attributes stored within annotations.
- *
- * @param Piwik_Date|false $startDate The start of the date range.
- * @param Piwik_Date|false $endDate The end of the date range.
- * @param string|int|array|false $idSite IDs of the sites whose annotations to
- * search through.
- * @return array Array mapping site IDs with arrays of annotations, eg:
- * array(
- * '5' => array(
- * array(...), // annotation
- * array(...), // annotation
- * ...
- * ),
- * '6' => array(
- * array(...), // annotation
- * array(...), // annotation
- * ...
- * ),
- * )
- */
- public function search( $startDate, $endDate, $idSite = false )
- {
- if ($idSite)
- {
- $idSites = Piwik_Site::getIdSitesFromIdSitesString($idSite);
- }
- else
- {
- $idSites = array_keys($this->annotations);
- }
-
- // collect annotations that are within the right date range & belong to the right
- // site
- $result = array();
- foreach ($idSites as $idSite)
- {
- if (!isset($this->annotations[$idSite]))
- {
- continue;
- }
-
- foreach ($this->annotations[$idSite] as $idNote => $annotation)
- {
- if ($startDate !== false)
- {
- $annotationDate = Piwik_Date::factory($annotation['date']);
- if ($annotationDate->getTimestamp() < $startDate->getTimestamp()
- || $annotationDate->getTimestamp() > $endDate->getTimestamp())
- {
- continue;
- }
- }
-
- $this->augmentAnnotationData($idSite, $idNote, $annotation);
- $result[$idSite][] = $annotation;
- }
-
- // sort by annotation date
- if (!empty($result[$idSite]))
- {
- uasort($result[$idSite], array($this, 'compareAnnotationDate'));
- }
- }
- return $result;
- }
-
- /**
- * Counts annotations & starred annotations within a date range and returns
- * the counts. The date range includes the start date, but not the end date.
- *
- * @param int $idSite The ID of the site to count annotations for.
- * @param string|false $startDate The start date of the range or false if no
- * range check is desired.
- * @param string|false $endDate The end date of the range or false if no
- * range check is desired.
- * @return array eg, array('count' => 5, 'starred' => 2)
- */
- public function count( $idSite, $startDate, $endDate )
- {
- $this->checkIdSiteIsLoaded($idSite);
-
- // search includes end date, and count should not, so subtract one from the timestamp
- $annotations = $this->search($startDate, Piwik_Date::factory($endDate->getTimestamp() - 1));
-
- // count the annotations
- $count = $starred = 0;
- if (!empty($annotations[$idSite]))
- {
- $count = count($annotations[$idSite]);
- foreach ($annotations[$idSite] as $annotation)
- {
- if ($annotation['starred'])
- {
- ++$starred;
- }
- }
- }
-
- return array('count' => $count, 'starred' => $starred);
- }
-
- /**
- * Utility function. Creates a new annotation.
- *
- * @param string $date
- * @param string $note
- * @param int $starred
- */
- private function makeAnnotation( $date, $note, $starred = 0 )
- {
- return array('date' => $date,
- 'note' => $note,
- 'starred' => (int)$starred,
- 'user' => Piwik::getCurrentUserLogin());
- }
-
- /**
- * Retrieves annotations from the database for the sites supplied to the
- * constructor.
- *
- * @return array Lists of annotations mapped by site ID.
- */
- private function getAnnotationsForSite()
- {
- $result = array();
- foreach ($this->idSites as $id)
- {
- $optionName = self::getAnnotationCollectionOptionName($id);
- $serialized = Piwik_GetOption($optionName);
-
- if ($serialized !== false)
- {
- $result[$id] = unserialize($serialized);
- }
- else
- {
- $result[$id] = array();
- }
- }
- return $result;
- }
-
- /**
- * Utility function that checks if a site ID was supplied and if not,
- * throws an exception.
- *
- * We can only modify/read annotations for sites that we've actually
- * loaded the annotations for.
- *
- * @param int $idSite
- * @throws Exception
- */
- private function checkIdSiteIsLoaded( $idSite )
- {
- if (!in_array($idSite, $this->idSites))
- {
- throw new Exception("This AnnotationList was not initialized with idSite '$idSite'.");
- }
- }
-
- /**
- * Utility function that checks if a note exists for a site, and if not,
- * throws an exception.
- *
- * @param int $idSite
- * @param int $idNote
- * @throws Exception
- */
- private function checkNoteExists( $idSite, $idNote )
- {
- if (empty($this->annotations[$idSite][$idNote]))
- {
- throw new Exception("There is no note with id '$idNote' for site with id '$idSite'.");
- }
- }
-
- /**
- * Returns true if the current user can modify or delete a specific annotation.
- *
- * A user can modify/delete a note if the user has admin access for the site OR
- * the user has view access, is not the anonymous user and is the user that
- * created the note in question.
- *
- * @param int $idSite The site ID the annotation belongs to.
- * @param array $annotation The annotation.
- * @return bool
- */
- public static function canUserModifyOrDelete( $idSite, $annotation )
- {
- // user can save if user is admin or if has view access, is not anonymous & is user who wrote note
- $canEdit = Piwik::isUserHasAdminAccess($idSite)
- || (!Piwik::isUserIsAnonymous()
- && Piwik::getCurrentUserLogin() == $annotation['user']);
- return $canEdit;
- }
-
- /**
- * Adds extra data to an annotation, including the annotation's ID and whether
- * the current user can edit or delete it.
- *
- * Also, if the current user is anonymous, the user attribute is removed.
- *
- * @param int $idSite
- * @param int $idNote
- * @param array $annotation
- */
- private function augmentAnnotationData( $idSite, $idNote, &$annotation )
- {
- $annotation['idNote'] = $idNote;
- $annotation['canEditOrDelete'] = self::canUserModifyOrDelete($idSite, $annotation);
-
- // we don't supply user info if the current user is anonymous
- if (Piwik::isUserIsAnonymous())
- {
- unset($annotation['user']);
- }
- }
-
- /**
- * Utility function that compares two annotations.
- *
- * @param array $lhs An annotation.
- * @param array $rhs An annotation.
- * @return int -1, 0 or 1
- */
- public function compareAnnotationDate( $lhs, $rhs )
- {
- if ($lhs['date'] == $rhs['date'])
- {
- return $lhs['idNote'] <= $rhs['idNote'] ? -1 : 1;
- }
-
- return $lhs['date'] < $rhs['date'] ? -1 : 1; // string comparison works because date format should be YYYY-MM-DD
- }
-
- /**
- * Returns true if the current user can add notes for a specific site.
- *
- * @param int $idSite The site to add notes to.
- */
- public static function canUserAddNotesFor( $idSite )
- {
- return Piwik::isUserHasViewAccess($idSite)
- && !Piwik::isUserIsAnonymous($idSite);
- }
-
- /**
- * Returns the option name used to store annotations for a site.
- *
- * @param int $idSite The site ID.
- */
- public static function getAnnotationCollectionOptionName( $idSite )
- {
- return $idSite.self::ANNOTATION_COLLECTION_OPTION_SUFFIX;
- }
+ const ANNOTATION_COLLECTION_OPTION_SUFFIX = '_annotations';
+
+ /**
+ * List of site IDs this instance holds annotations for.
+ *
+ * @var array
+ */
+ private $idSites;
+
+ /**
+ * Array that associates lists of annotations with site IDs.
+ *
+ * @var array
+ */
+ private $annotations;
+
+ /**
+ * Constructor. Loads annotations from the database.
+ *
+ * @param string|int $idSites The list of site IDs to load annotations for.
+ */
+ public function __construct($idSites)
+ {
+ $this->idSites = Piwik_Site::getIdSitesFromIdSitesString($idSites);
+ $this->annotations = $this->getAnnotationsForSite();
+ }
+
+ /**
+ * Returns the list of site IDs this list contains annotations for.
+ *
+ * @return array
+ */
+ public function getIdSites()
+ {
+ return $this->idSites;
+ }
+
+ /**
+ * Creates a new annotation for a site. This method does not perist the result.
+ * To save the new annotation in the database, call $this->save.
+ *
+ * @param int $idSite The ID of the site to add an annotation to.
+ * @param string $date The date the annotation is in reference to.
+ * @param string $note The text of the new annotation.
+ * @param int $starred Either 1 or 0. If 1, the new annotation has been starred,
+ * otherwise it will start out unstarred.
+ * @return array The added annotation.
+ * @throws Exception if $idSite is not an ID that was supplied upon construction.
+ */
+ public function add($idSite, $date, $note, $starred = 0)
+ {
+ $this->checkIdSiteIsLoaded($idSite);
+
+ $this->annotations[$idSite][] = self::makeAnnotation($date, $note, $starred);
+
+ // get the id of the new annotation
+ end($this->annotations[$idSite]);
+ $newNoteId = key($this->annotations[$idSite]);
+
+ return $this->get($idSite, $newNoteId);
+ }
+
+ /**
+ * Persists the annotations list for a site, overwriting whatever exists.
+ *
+ * @param int $idSite The ID of the site to save annotations for.
+ * @throws Exception if $idSite is not an ID that was supplied upon construction.
+ */
+ public function save($idSite)
+ {
+ $this->checkIdSiteIsLoaded($idSite);
+
+ $optionName = self::getAnnotationCollectionOptionName($idSite);
+ Piwik_SetOption($optionName, serialize($this->annotations[$idSite]));
+ }
+
+ /**
+ * Modifies an annotation in this instance's collection of annotations.
+ *
+ * Note: This method does not perist the change in the DB. The save method must
+ * be called for that.
+ *
+ * @param int $idSite The ID of the site whose annotation will be updated.
+ * @param int $idNote The ID of the note.
+ * @param string|null $date The new date of the annotation, eg '2012-01-01'. If
+ * null, no change is made.
+ * @param string|null $note The new text of the annotation. If null, no change
+ * is made.
+ * @param int|null $starred Either 1 or 0, whether the annotation should be
+ * starred or not. If null, no change is made.
+ * @throws Exception if $idSite is not an ID that was supplied upon construction.
+ * @throws Exception if $idNote does not refer to valid note for the site.
+ */
+ public function update($idSite, $idNote, $date = null, $note = null, $starred = null)
+ {
+ $this->checkIdSiteIsLoaded($idSite);
+ $this->checkNoteExists($idSite, $idNote);
+
+ $annotation =& $this->annotations[$idSite][$idNote];
+ if ($date !== null) {
+ $annotation['date'] = $date;
+ }
+ if ($note !== null) {
+ $annotation['note'] = $note;
+ }
+ if ($starred !== null) {
+ $annotation['starred'] = $starred;
+ }
+ }
+
+ /**
+ * Removes a note from a site's collection of annotations.
+ *
+ * Note: This method does not perist the change in the DB. The save method must
+ * be called for that.
+ *
+ * @param int $idSite The ID of the site whose annotation will be updated.
+ * @param int $idNote The ID of the note.
+ * @throws Exception if $idSite is not an ID that was supplied upon construction.
+ * @throws Exception if $idNote does not refer to valid note for the site.
+ */
+ public function remove($idSite, $idNote)
+ {
+ $this->checkIdSiteIsLoaded($idSite);
+ $this->checkNoteExists($idSite, $idNote);
+
+ unset($this->annotations[$idSite][$idNote]);
+ }
+
+ /**
+ * Retrieves an annotation by ID.
+ *
+ * This function returns an array with the following elements:
+ * - idNote: The ID of the annotation.
+ * - date: The date of the annotation.
+ * - note: The text of the annotation.
+ * - starred: 1 or 0, whether the annotation is stared;
+ * - user: (unless current user is anonymous) The user that created the annotation.
+ * - canEditOrDelete: True if the user can edit/delete the annotation.
+ *
+ * @param int $idSite The ID of the site to get an annotation for.
+ * @param int $idNote The ID of the note to get.
+ * @param array The annotation.
+ * @throws Exception if $idSite is not an ID that was supplied upon construction.
+ * @throws Exception if $idNote does not refer to valid note for the site.
+ */
+ public function get($idSite, $idNote)
+ {
+ $this->checkIdSiteIsLoaded($idSite);
+ $this->checkNoteExists($idSite, $idNote);
+
+ $annotation = $this->annotations[$idSite][$idNote];
+ $this->augmentAnnotationData($idSite, $idNote, $annotation);
+ return $annotation;
+ }
+
+ /**
+ * Returns all annotations within a specific date range. The result is
+ * an array that maps site IDs with arrays of annotations within the range.
+ *
+ * Note: The date range is inclusive.
+ *
+ * @see self::get for info on what attributes stored within annotations.
+ *
+ * @param Piwik_Date|false $startDate The start of the date range.
+ * @param Piwik_Date|false $endDate The end of the date range.
+ * @param string|int|array|false $idSite IDs of the sites whose annotations to
+ * search through.
+ * @return array Array mapping site IDs with arrays of annotations, eg:
+ * array(
+ * '5' => array(
+ * array(...), // annotation
+ * array(...), // annotation
+ * ...
+ * ),
+ * '6' => array(
+ * array(...), // annotation
+ * array(...), // annotation
+ * ...
+ * ),
+ * )
+ */
+ public function search($startDate, $endDate, $idSite = false)
+ {
+ if ($idSite) {
+ $idSites = Piwik_Site::getIdSitesFromIdSitesString($idSite);
+ } else {
+ $idSites = array_keys($this->annotations);
+ }
+
+ // collect annotations that are within the right date range & belong to the right
+ // site
+ $result = array();
+ foreach ($idSites as $idSite) {
+ if (!isset($this->annotations[$idSite])) {
+ continue;
+ }
+
+ foreach ($this->annotations[$idSite] as $idNote => $annotation) {
+ if ($startDate !== false) {
+ $annotationDate = Piwik_Date::factory($annotation['date']);
+ if ($annotationDate->getTimestamp() < $startDate->getTimestamp()
+ || $annotationDate->getTimestamp() > $endDate->getTimestamp()
+ ) {
+ continue;
+ }
+ }
+
+ $this->augmentAnnotationData($idSite, $idNote, $annotation);
+ $result[$idSite][] = $annotation;
+ }
+
+ // sort by annotation date
+ if (!empty($result[$idSite])) {
+ uasort($result[$idSite], array($this, 'compareAnnotationDate'));
+ }
+ }
+ return $result;
+ }
+
+ /**
+ * Counts annotations & starred annotations within a date range and returns
+ * the counts. The date range includes the start date, but not the end date.
+ *
+ * @param int $idSite The ID of the site to count annotations for.
+ * @param string|false $startDate The start date of the range or false if no
+ * range check is desired.
+ * @param string|false $endDate The end date of the range or false if no
+ * range check is desired.
+ * @return array eg, array('count' => 5, 'starred' => 2)
+ */
+ public function count($idSite, $startDate, $endDate)
+ {
+ $this->checkIdSiteIsLoaded($idSite);
+
+ // search includes end date, and count should not, so subtract one from the timestamp
+ $annotations = $this->search($startDate, Piwik_Date::factory($endDate->getTimestamp() - 1));
+
+ // count the annotations
+ $count = $starred = 0;
+ if (!empty($annotations[$idSite])) {
+ $count = count($annotations[$idSite]);
+ foreach ($annotations[$idSite] as $annotation) {
+ if ($annotation['starred']) {
+ ++$starred;
+ }
+ }
+ }
+
+ return array('count' => $count, 'starred' => $starred);
+ }
+
+ /**
+ * Utility function. Creates a new annotation.
+ *
+ * @param string $date
+ * @param string $note
+ * @param int $starred
+ */
+ private function makeAnnotation($date, $note, $starred = 0)
+ {
+ return array('date' => $date,
+ 'note' => $note,
+ 'starred' => (int)$starred,
+ 'user' => Piwik::getCurrentUserLogin());
+ }
+
+ /**
+ * Retrieves annotations from the database for the sites supplied to the
+ * constructor.
+ *
+ * @return array Lists of annotations mapped by site ID.
+ */
+ private function getAnnotationsForSite()
+ {
+ $result = array();
+ foreach ($this->idSites as $id) {
+ $optionName = self::getAnnotationCollectionOptionName($id);
+ $serialized = Piwik_GetOption($optionName);
+
+ if ($serialized !== false) {
+ $result[$id] = unserialize($serialized);
+ } else {
+ $result[$id] = array();
+ }
+ }
+ return $result;
+ }
+
+ /**
+ * Utility function that checks if a site ID was supplied and if not,
+ * throws an exception.
+ *
+ * We can only modify/read annotations for sites that we've actually
+ * loaded the annotations for.
+ *
+ * @param int $idSite
+ * @throws Exception
+ */
+ private function checkIdSiteIsLoaded($idSite)
+ {
+ if (!in_array($idSite, $this->idSites)) {
+ throw new Exception("This AnnotationList was not initialized with idSite '$idSite'.");
+ }
+ }
+
+ /**
+ * Utility function that checks if a note exists for a site, and if not,
+ * throws an exception.
+ *
+ * @param int $idSite
+ * @param int $idNote
+ * @throws Exception
+ */
+ private function checkNoteExists($idSite, $idNote)
+ {
+ if (empty($this->annotations[$idSite][$idNote])) {
+ throw new Exception("There is no note with id '$idNote' for site with id '$idSite'.");
+ }
+ }
+
+ /**
+ * Returns true if the current user can modify or delete a specific annotation.
+ *
+ * A user can modify/delete a note if the user has admin access for the site OR
+ * the user has view access, is not the anonymous user and is the user that
+ * created the note in question.
+ *
+ * @param int $idSite The site ID the annotation belongs to.
+ * @param array $annotation The annotation.
+ * @return bool
+ */
+ public static function canUserModifyOrDelete($idSite, $annotation)
+ {
+ // user can save if user is admin or if has view access, is not anonymous & is user who wrote note
+ $canEdit = Piwik::isUserHasAdminAccess($idSite)
+ || (!Piwik::isUserIsAnonymous()
+ && Piwik::getCurrentUserLogin() == $annotation['user']);
+ return $canEdit;
+ }
+
+ /**
+ * Adds extra data to an annotation, including the annotation's ID and whether
+ * the current user can edit or delete it.
+ *
+ * Also, if the current user is anonymous, the user attribute is removed.
+ *
+ * @param int $idSite
+ * @param int $idNote
+ * @param array $annotation
+ */
+ private function augmentAnnotationData($idSite, $idNote, &$annotation)
+ {
+ $annotation['idNote'] = $idNote;
+ $annotation['canEditOrDelete'] = self::canUserModifyOrDelete($idSite, $annotation);
+
+ // we don't supply user info if the current user is anonymous
+ if (Piwik::isUserIsAnonymous()) {
+ unset($annotation['user']);
+ }
+ }
+
+ /**
+ * Utility function that compares two annotations.
+ *
+ * @param array $lhs An annotation.
+ * @param array $rhs An annotation.
+ * @return int -1, 0 or 1
+ */
+ public function compareAnnotationDate($lhs, $rhs)
+ {
+ if ($lhs['date'] == $rhs['date']) {
+ return $lhs['idNote'] <= $rhs['idNote'] ? -1 : 1;
+ }
+
+ return $lhs['date'] < $rhs['date'] ? -1 : 1; // string comparison works because date format should be YYYY-MM-DD
+ }
+
+ /**
+ * Returns true if the current user can add notes for a specific site.
+ *
+ * @param int $idSite The site to add notes to.
+ */
+ public static function canUserAddNotesFor($idSite)
+ {
+ return Piwik::isUserHasViewAccess($idSite)
+ && !Piwik::isUserIsAnonymous($idSite);
+ }
+
+ /**
+ * Returns the option name used to store annotations for a site.
+ *
+ * @param int $idSite The site ID.
+ */
+ public static function getAnnotationCollectionOptionName($idSite)
+ {
+ return $idSite . self::ANNOTATION_COLLECTION_OPTION_SUFFIX;
+ }
}
diff --git a/plugins/Annotations/Annotations.php b/plugins/Annotations/Annotations.php
index 1b0503862a..937500053a 100755
--- a/plugins/Annotations/Annotations.php
+++ b/plugins/Annotations/Annotations.php
@@ -12,58 +12,58 @@
/**
* Annotations plugins. Provides the ability to attach text notes to
* dates for each sites. Notes can be viewed, modified, deleted or starred.
- *
+ *
* @package Piwik_Annotations
*/
class Piwik_Annotations extends Piwik_Plugin
{
- /**
- * Returns information about this plugin.
- *
- * @return array
- */
- public function getInformation()
- {
- return array(
- 'description' => Piwik_Translate('Annotations_PluginDescription'),
- 'author' => 'Piwik',
- 'author_homepage' => 'http://piwik.org/',
- 'version' => Piwik_Version::VERSION,
- );
- }
-
- /**
- * Returns list of event hooks.
- *
- * @return array
- */
- public function getListHooksRegistered()
- {
- return array(
- 'AssetManager.getCssFiles' => 'getCssFiles',
- 'AssetManager.getJsFiles' => 'getJsFiles'
- );
- }
+ /**
+ * Returns information about this plugin.
+ *
+ * @return array
+ */
+ public function getInformation()
+ {
+ return array(
+ 'description' => Piwik_Translate('Annotations_PluginDescription'),
+ 'author' => 'Piwik',
+ 'author_homepage' => 'http://piwik.org/',
+ 'version' => Piwik_Version::VERSION,
+ );
+ }
+
+ /**
+ * Returns list of event hooks.
+ *
+ * @return array
+ */
+ public function getListHooksRegistered()
+ {
+ return array(
+ 'AssetManager.getCssFiles' => 'getCssFiles',
+ 'AssetManager.getJsFiles' => 'getJsFiles'
+ );
+ }
- /**
- * Adds css files for this plugin to the list in the event notification.
- *
- * @param Piwik_Event_Notification $notification notification object
- */
- function getCssFiles( $notification )
- {
- $cssFiles = &$notification->getNotificationObject();
- $cssFiles[] = "plugins/Annotations/templates/styles.css";
- }
+ /**
+ * Adds css files for this plugin to the list in the event notification.
+ *
+ * @param Piwik_Event_Notification $notification notification object
+ */
+ function getCssFiles($notification)
+ {
+ $cssFiles = & $notification->getNotificationObject();
+ $cssFiles[] = "plugins/Annotations/templates/styles.css";
+ }
- /**
- * Adds js files for this plugin to the list in the event notification.
- *
- * @param Piwik_Event_Notification $notification notification object
- */
- function getJsFiles( $notification )
- {
- $jsFiles = &$notification->getNotificationObject();
- $jsFiles[] = "plugins/Annotations/templates/annotations.js";
- }
+ /**
+ * Adds js files for this plugin to the list in the event notification.
+ *
+ * @param Piwik_Event_Notification $notification notification object
+ */
+ function getJsFiles($notification)
+ {
+ $jsFiles = & $notification->getNotificationObject();
+ $jsFiles[] = "plugins/Annotations/templates/annotations.js";
+ }
}
diff --git a/plugins/Annotations/Controller.php b/plugins/Annotations/Controller.php
index 0a235a2200..9b9f9e352c 100755
--- a/plugins/Annotations/Controller.php
+++ b/plugins/Annotations/Controller.php
@@ -11,216 +11,206 @@
/**
* Controller for the Annotations plugin.
- *
+ *
* @package Piwik_Annotations
*/
class Piwik_Annotations_Controller extends Piwik_Controller
{
- /**
- * Controller action that returns HTML displaying annotations for a site and
- * specific date range.
- *
- * Query Param Input:
- * - idSite: The ID of the site to get annotations for. Only one allowed.
- * - date: The date to get annotations for. If lastN is not supplied, this is the start date,
- * otherwise the start date in the last period.
- * - period: The period type.
- * - lastN: If supplied, the last N # of periods will be included w/ the range specified
- * by date + period.
- *
- * Output:
- * - HTML displaying annotations for a specific range.
- *
- * @param bool $fetch True if the annotation manager should be returned as a string,
- * false if it should be echo-ed.
- * @param string $date Override for 'date' query parameter.
- * @param string $period Override for 'period' query parameter.
- * @param string $lastN Override for 'lastN' query parameter.
- * @return string|void
- */
- public function getAnnotationManager( $fetch = false, $date = false, $period = false, $lastN = false )
- {
- $idSite = Piwik_Common::getRequestVar('idSite');
-
- if ($date === false)
- {
- $date = Piwik_Common::getRequestVar('date', false);
- }
-
- if ($period === false)
- {
- $period = Piwik_Common::getRequestVar('period', 'day');
- }
-
- if ($lastN === false)
- {
- $lastN = Piwik_Common::getRequestVar('lastN', false);
- }
-
- // create & render the view
- $view = Piwik_View::factory('annotationManager');
-
- $allAnnotations = Piwik_API_Request::processRequest(
- 'Annotations.getAll', array('date' => $date, 'period' => $period, 'lastN' => $lastN));
- $view->annotations = empty($allAnnotations[$idSite]) ? array() : $allAnnotations[$idSite];
-
- $view->period = $period;
- $view->lastN = $lastN;
-
- list($startDate, $endDate) = Piwik_Annotations_API::getDateRangeForPeriod($date, $period, $lastN);
- $view->startDate = $startDate->toString();
- $view->endDate = $endDate->toString();
-
- $dateFormat = Piwik_Translate('CoreHome_ShortDateFormatWithYear');
- $view->startDatePretty = $startDate->getLocalized($dateFormat);
- $view->endDatePretty = $endDate->getLocalized($dateFormat);
-
- $view->canUserAddNotes = Piwik_Annotations_AnnotationList::canUserAddNotesFor($idSite);
-
- if ($fetch)
- {
- return $view->render();
- }
- else
- {
- echo $view->render();
- }
- }
-
- /**
- * Controller action that modifies an annotation and returns HTML displaying
- * the modified annotation.
- *
- * Query Param Input:
- * - idSite: The ID of the site the annotation belongs to. Only one ID is allowed.
- * - idNote: The ID of the annotation.
- * - date: The new date value for the annotation. (optional)
- * - note: The new text for the annotation. (optional)
- * - starred: Either 1 or 0. Whether the note should be starred or not. (optional)
- *
- * Output:
- * - HTML displaying modified annotation.
- *
- * If an optional query param is not supplied, that part of the annotation is
- * not modified.
- */
- public function saveAnnotation()
- {
- if ($_SERVER["REQUEST_METHOD"] == "POST")
- {
- $this->checkTokenInUrl();
-
- $view = Piwik_View::factory('annotation');
-
- // NOTE: permissions checked in API method
- // save the annotation
- $view->annotation = Piwik_API_Request::processRequest("Annotations.save");
-
- echo $view->render();
- }
- }
-
- /**
- * Controller action that adds a new annotation for a site and returns new
- * annotation manager HTML for the site and date range.
- *
- * Query Param Input:
- * - idSite: The ID of the site to add an annotation to.
- * - date: The date for the new annotation.
- * - note: The text of the annotation.
- * - starred: Either 1 or 0, whether the annotation should be starred or not.
- * Defaults to 0.
- * - managerDate: The date for the annotation manager. If a range is given, the start
- * date is used for the new annotation.
- * - managerPeriod: For rendering the annotation manager. @see self::getAnnotationManager
- * for more info.
- * - lastN: For rendering the annotation manager. @see self::getAnnotationManager
- * for more info.
- * Output:
- * - @see self::getAnnotationManager
- */
- public function addAnnotation()
- {
- if ($_SERVER["REQUEST_METHOD"] == "POST")
- {
- $this->checkTokenInUrl();
-
- // the date used is for the annotation manager HTML that gets echo'd. we
- // use this date for the new annotation, unless it is a date range, in
- // which case we use the first date of the range.
- $date = Piwik_Common::getRequestVar('date');
- if (strpos($date, ',') !== false)
- {
- $date = reset(explode(',', $date));
- }
-
- // add the annotation. NOTE: permissions checked in API method
- Piwik_API_Request::processRequest("Annotations.add", array('date' => $date));
-
- $managerDate = Piwik_Common::getRequestVar('managerDate', false);
- $managerPeriod = Piwik_Common::getRequestVar('managerPeriod', false);
- echo $this->getAnnotationManager($fetch = true, $managerDate, $managerPeriod);
- }
- }
-
- /**
- * Controller action that deletes an annotation and returns new annotation
- * manager HTML for the site & date range.
- *
- * Query Param Input:
- * - idSite: The ID of the site this annotation belongs to.
- * - idNote: The ID of the annotation to delete.
- * - date: For rendering the annotation manager. @see self::getAnnotationManager
- * for more info.
- * - period: For rendering the annotation manager. @see self::getAnnotationManager
- * for more info.
- * - lastN: For rendering the annotation manager. @see self::getAnnotationManager
- * for more info.
- *
- * Output:
- * - @see self::getAnnotationManager
- */
- public function deleteAnnotation()
- {
- if ($_SERVER["REQUEST_METHOD"] == "POST")
- {
- $this->checkTokenInUrl();
-
- // delete annotation. NOTE: permissions checked in API method
- Piwik_API_Request::processRequest("Annotations.delete");
-
- echo $this->getAnnotationManager($fetch = true);
- }
- }
-
- /**
- * Controller action that echo's HTML that displays marker icons for an
- * evolution graph's x-axis. The marker icons still need to be positioned
- * by the JavaScript.
- *
- * Query Param Input:
- * - idSite: The ID of the site this annotation belongs to. Only one is allowed.
- * - date: The date to check for annotations. If lastN is not supplied, this is
- * the start of the date range used to check for annotations. If supplied,
- * this is the start of the last period in the date range.
- * - period: The period type.
- * - lastN: If supplied, the last N # of periods are included in the date range
- * used to check for annotations.
- *
- * Output:
- * - HTML that displays marker icons for an evolution graph based on the
- * number of annotations & starred annotations in the graph's date range.
- */
- public function getEvolutionIcons()
- {
- // get annotation the count
- $annotationCounts = Piwik_API_Request::processRequest(
- "Annotations.getAnnotationCountForDates", array('getAnnotationText' => 1));
-
- // create & render the view
- $view = Piwik_View::factory('evolutionAnnotations');
- $view->annotationCounts = reset($annotationCounts); // only one idSite allowed for this action
-
- echo $view->render();
- }
+ /**
+ * Controller action that returns HTML displaying annotations for a site and
+ * specific date range.
+ *
+ * Query Param Input:
+ * - idSite: The ID of the site to get annotations for. Only one allowed.
+ * - date: The date to get annotations for. If lastN is not supplied, this is the start date,
+ * otherwise the start date in the last period.
+ * - period: The period type.
+ * - lastN: If supplied, the last N # of periods will be included w/ the range specified
+ * by date + period.
+ *
+ * Output:
+ * - HTML displaying annotations for a specific range.
+ *
+ * @param bool $fetch True if the annotation manager should be returned as a string,
+ * false if it should be echo-ed.
+ * @param string $date Override for 'date' query parameter.
+ * @param string $period Override for 'period' query parameter.
+ * @param string $lastN Override for 'lastN' query parameter.
+ * @return string|void
+ */
+ public function getAnnotationManager($fetch = false, $date = false, $period = false, $lastN = false)
+ {
+ $idSite = Piwik_Common::getRequestVar('idSite');
+
+ if ($date === false) {
+ $date = Piwik_Common::getRequestVar('date', false);
+ }
+
+ if ($period === false) {
+ $period = Piwik_Common::getRequestVar('period', 'day');
+ }
+
+ if ($lastN === false) {
+ $lastN = Piwik_Common::getRequestVar('lastN', false);
+ }
+
+ // create & render the view
+ $view = Piwik_View::factory('annotationManager');
+
+ $allAnnotations = Piwik_API_Request::processRequest(
+ 'Annotations.getAll', array('date' => $date, 'period' => $period, 'lastN' => $lastN));
+ $view->annotations = empty($allAnnotations[$idSite]) ? array() : $allAnnotations[$idSite];
+
+ $view->period = $period;
+ $view->lastN = $lastN;
+
+ list($startDate, $endDate) = Piwik_Annotations_API::getDateRangeForPeriod($date, $period, $lastN);
+ $view->startDate = $startDate->toString();
+ $view->endDate = $endDate->toString();
+
+ $dateFormat = Piwik_Translate('CoreHome_ShortDateFormatWithYear');
+ $view->startDatePretty = $startDate->getLocalized($dateFormat);
+ $view->endDatePretty = $endDate->getLocalized($dateFormat);
+
+ $view->canUserAddNotes = Piwik_Annotations_AnnotationList::canUserAddNotesFor($idSite);
+
+ if ($fetch) {
+ return $view->render();
+ } else {
+ echo $view->render();
+ }
+ }
+
+ /**
+ * Controller action that modifies an annotation and returns HTML displaying
+ * the modified annotation.
+ *
+ * Query Param Input:
+ * - idSite: The ID of the site the annotation belongs to. Only one ID is allowed.
+ * - idNote: The ID of the annotation.
+ * - date: The new date value for the annotation. (optional)
+ * - note: The new text for the annotation. (optional)
+ * - starred: Either 1 or 0. Whether the note should be starred or not. (optional)
+ *
+ * Output:
+ * - HTML displaying modified annotation.
+ *
+ * If an optional query param is not supplied, that part of the annotation is
+ * not modified.
+ */
+ public function saveAnnotation()
+ {
+ if ($_SERVER["REQUEST_METHOD"] == "POST") {
+ $this->checkTokenInUrl();
+
+ $view = Piwik_View::factory('annotation');
+
+ // NOTE: permissions checked in API method
+ // save the annotation
+ $view->annotation = Piwik_API_Request::processRequest("Annotations.save");
+
+ echo $view->render();
+ }
+ }
+
+ /**
+ * Controller action that adds a new annotation for a site and returns new
+ * annotation manager HTML for the site and date range.
+ *
+ * Query Param Input:
+ * - idSite: The ID of the site to add an annotation to.
+ * - date: The date for the new annotation.
+ * - note: The text of the annotation.
+ * - starred: Either 1 or 0, whether the annotation should be starred or not.
+ * Defaults to 0.
+ * - managerDate: The date for the annotation manager. If a range is given, the start
+ * date is used for the new annotation.
+ * - managerPeriod: For rendering the annotation manager. @see self::getAnnotationManager
+ * for more info.
+ * - lastN: For rendering the annotation manager. @see self::getAnnotationManager
+ * for more info.
+ * Output:
+ * - @see self::getAnnotationManager
+ */
+ public function addAnnotation()
+ {
+ if ($_SERVER["REQUEST_METHOD"] == "POST") {
+ $this->checkTokenInUrl();
+
+ // the date used is for the annotation manager HTML that gets echo'd. we
+ // use this date for the new annotation, unless it is a date range, in
+ // which case we use the first date of the range.
+ $date = Piwik_Common::getRequestVar('date');
+ if (strpos($date, ',') !== false) {
+ $date = reset(explode(',', $date));
+ }
+
+ // add the annotation. NOTE: permissions checked in API method
+ Piwik_API_Request::processRequest("Annotations.add", array('date' => $date));
+
+ $managerDate = Piwik_Common::getRequestVar('managerDate', false);
+ $managerPeriod = Piwik_Common::getRequestVar('managerPeriod', false);
+ echo $this->getAnnotationManager($fetch = true, $managerDate, $managerPeriod);
+ }
+ }
+
+ /**
+ * Controller action that deletes an annotation and returns new annotation
+ * manager HTML for the site & date range.
+ *
+ * Query Param Input:
+ * - idSite: The ID of the site this annotation belongs to.
+ * - idNote: The ID of the annotation to delete.
+ * - date: For rendering the annotation manager. @see self::getAnnotationManager
+ * for more info.
+ * - period: For rendering the annotation manager. @see self::getAnnotationManager
+ * for more info.
+ * - lastN: For rendering the annotation manager. @see self::getAnnotationManager
+ * for more info.
+ *
+ * Output:
+ * - @see self::getAnnotationManager
+ */
+ public function deleteAnnotation()
+ {
+ if ($_SERVER["REQUEST_METHOD"] == "POST") {
+ $this->checkTokenInUrl();
+
+ // delete annotation. NOTE: permissions checked in API method
+ Piwik_API_Request::processRequest("Annotations.delete");
+
+ echo $this->getAnnotationManager($fetch = true);
+ }
+ }
+
+ /**
+ * Controller action that echo's HTML that displays marker icons for an
+ * evolution graph's x-axis. The marker icons still need to be positioned
+ * by the JavaScript.
+ *
+ * Query Param Input:
+ * - idSite: The ID of the site this annotation belongs to. Only one is allowed.
+ * - date: The date to check for annotations. If lastN is not supplied, this is
+ * the start of the date range used to check for annotations. If supplied,
+ * this is the start of the last period in the date range.
+ * - period: The period type.
+ * - lastN: If supplied, the last N # of periods are included in the date range
+ * used to check for annotations.
+ *
+ * Output:
+ * - HTML that displays marker icons for an evolution graph based on the
+ * number of annotations & starred annotations in the graph's date range.
+ */
+ public function getEvolutionIcons()
+ {
+ // get annotation the count
+ $annotationCounts = Piwik_API_Request::processRequest(
+ "Annotations.getAnnotationCountForDates", array('getAnnotationText' => 1));
+
+ // create & render the view
+ $view = Piwik_View::factory('evolutionAnnotations');
+ $view->annotationCounts = reset($annotationCounts); // only one idSite allowed for this action
+
+ echo $view->render();
+ }
}
diff --git a/plugins/Annotations/templates/annotation.tpl b/plugins/Annotations/templates/annotation.tpl
index e1cd5f6013..cc0d909a3b 100755
--- a/plugins/Annotations/templates/annotation.tpl
+++ b/plugins/Annotations/templates/annotation.tpl
@@ -1,43 +1,46 @@
<tr class="annotation" data-id="{$annotation.idNote}" data-date="{$annotation.date}">
- <td class="annotation-meta">
- <div class="annotation-star{if $annotation.canEditOrDelete} annotation-star-changeable{/if}" data-starred="{$annotation.starred}" {if $annotation.canEditOrDelete}title="{'Annotations_ClickToStarOrUnstar'|translate}"{/if}>
- {if $annotation.starred}
- <img src="themes/default/images/star.png"/>
- {else}
- <img src="themes/default/images/star_empty.png"/>
- {/if}
- </div>
- <div class="annotation-period {if $annotation.canEditOrDelete}annotation-enter-edit-mode{/if}">({$annotation.date})</div>
- {if $annotation.canEditOrDelete}
- <div class="annotation-period-edit" style="display:none">
- <a href="#">{$annotation.date}</a>
- <div class="datepicker" style="display:none"/>
- </div>
- {/if}
- </td>
- <td class="annotation-value">
- <div class="annotation-view-mode">
- <span {if $annotation.canEditOrDelete}title="{'Annotations_ClickToEdit'|translate}" class="annotation-enter-edit-mode"{/if}>{$annotation.note|unescape|escape:'html'}</span>
- {if $annotation.canEditOrDelete}
- <a href="#" class="edit-annotation annotation-enter-edit-mode" title="{'Annotations_ClickToEdit'|translate}">{'General_Edit'|translate}...</a>
- {/if}
- </div>
- {if $annotation.canEditOrDelete}
- <div class="annotation-edit-mode" style="display:none">
- <input class="annotation-edit" type="text" value="{$annotation.note|unescape|escape:'html'}"/>
- <br/>
- <input class="annotation-save submit" type="button" value="{'General_Save'|translate}"/>
- <input class="annotation-cancel submit" type="button" value="{'General_Cancel'|translate}"/>
- </div>
- {/if}
- </td>
- {if isset($annotation.user) && $userLogin != 'anonymous'}
- <td class="annotation-user-cell">
- <span class="annotation-user">{$annotation.user|unescape|escape:'html'}</span><br/>
- {if $annotation.canEditOrDelete}
- <a href="#" class="delete-annotation" style="display:none" title="{'Annotations_ClickToDelete'|translate}">{'General_Delete'|translate}</a>
- {/if}
- </td>
- {/if}
+ <td class="annotation-meta">
+ <div class="annotation-star{if $annotation.canEditOrDelete} annotation-star-changeable{/if}" data-starred="{$annotation.starred}"
+ {if $annotation.canEditOrDelete}title="{'Annotations_ClickToStarOrUnstar'|translate}"{/if}>
+ {if $annotation.starred}
+ <img src="themes/default/images/star.png"/>
+ {else}
+ <img src="themes/default/images/star_empty.png"/>
+ {/if}
+ </div>
+ <div class="annotation-period {if $annotation.canEditOrDelete}annotation-enter-edit-mode{/if}">({$annotation.date})</div>
+ {if $annotation.canEditOrDelete}
+ <div class="annotation-period-edit" style="display:none">
+ <a href="#">{$annotation.date}</a>
+
+ <div class="datepicker" style="display:none"/>
+ </div>
+ {/if}
+ </td>
+ <td class="annotation-value">
+ <div class="annotation-view-mode">
+ <span {if $annotation.canEditOrDelete}title="{'Annotations_ClickToEdit'|translate}"
+ class="annotation-enter-edit-mode"{/if}>{$annotation.note|unescape|escape:'html'}</span>
+ {if $annotation.canEditOrDelete}
+ <a href="#" class="edit-annotation annotation-enter-edit-mode" title="{'Annotations_ClickToEdit'|translate}">{'General_Edit'|translate}...</a>
+ {/if}
+ </div>
+ {if $annotation.canEditOrDelete}
+ <div class="annotation-edit-mode" style="display:none">
+ <input class="annotation-edit" type="text" value="{$annotation.note|unescape|escape:'html'}"/>
+ <br/>
+ <input class="annotation-save submit" type="button" value="{'General_Save'|translate}"/>
+ <input class="annotation-cancel submit" type="button" value="{'General_Cancel'|translate}"/>
+ </div>
+ {/if}
+ </td>
+ {if isset($annotation.user) && $userLogin != 'anonymous'}
+ <td class="annotation-user-cell">
+ <span class="annotation-user">{$annotation.user|unescape|escape:'html'}</span><br/>
+ {if $annotation.canEditOrDelete}
+ <a href="#" class="delete-annotation" style="display:none" title="{'Annotations_ClickToDelete'|translate}">{'General_Delete'|translate}</a>
+ {/if}
+ </td>
+ {/if}
</tr>
diff --git a/plugins/Annotations/templates/annotationManager.tpl b/plugins/Annotations/templates/annotationManager.tpl
index 852c09bbc4..401c2458c9 100755
--- a/plugins/Annotations/templates/annotationManager.tpl
+++ b/plugins/Annotations/templates/annotationManager.tpl
@@ -1,27 +1,27 @@
<div class="annotation-manager"
- {if $startDate neq $endDate}data-date="{$startDate},{$endDate}" data-period="range"
- {else}data-date="{$startDate}" data-period="{$period}"
- {/if}>
+ {if $startDate neq $endDate}data-date="{$startDate},{$endDate}" data-period="range"
+ {else}data-date="{$startDate}" data-period="{$period}"
+ {/if}>
-<div class="annotations-header">
- <span>{'Annotations_Annotations'|translate}</span>
-</div>
+ <div class="annotations-header">
+ <span>{'Annotations_Annotations'|translate}</span>
+ </div>
-<div class="annotation-list-range">{$startDatePretty}{if $startDate neq $endDate} &mdash; {$endDatePretty}{/if}</div>
+ <div class="annotation-list-range">{$startDatePretty}{if $startDate neq $endDate} &mdash; {$endDatePretty}{/if}</div>
-<div class="annotation-list">
-{include file="Annotations/templates/annotations.tpl"}
+ <div class="annotation-list">
+ {include file="Annotations/templates/annotations.tpl"}
-<span class="loadingPiwik" style="display:none"><img src="themes/default/images/loading-blue.gif"/>{'General_Loading_js'|translate}</span>
+ <span class="loadingPiwik" style="display:none"><img src="themes/default/images/loading-blue.gif"/>{'General_Loading_js'|translate}</span>
-</div>
+ </div>
-<div class="annotation-controls">
- {if $canUserAddNotes}
- <a href="#" class="add-annotation" title="{'Annotations_CreateNewAnnotation'|translate}">{'Annotations_CreateNewAnnotation'|translate}</a>
- {elseif $userLogin eq 'anonymous'}
- <a href="index.php?module=Login">{'Annotations_LoginToAnnotate'|translate}</a>
- {/if}
-</div>
+ <div class="annotation-controls">
+ {if $canUserAddNotes}
+ <a href="#" class="add-annotation" title="{'Annotations_CreateNewAnnotation'|translate}">{'Annotations_CreateNewAnnotation'|translate}</a>
+ {elseif $userLogin eq 'anonymous'}
+ <a href="index.php?module=Login">{'Annotations_LoginToAnnotate'|translate}</a>
+ {/if}
+ </div>
</div>
diff --git a/plugins/Annotations/templates/annotations.js b/plugins/Annotations/templates/annotations.js
index 62f63a59aa..85097ad1d6 100755
--- a/plugins/Annotations/templates/annotations.js
+++ b/plugins/Annotations/templates/annotations.js
@@ -5,628 +5,586 @@
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
*/
-(function($, piwik) {
-
-var annotationsApi = {
-
- // calls Annotations.getAnnotationManager
- getAnnotationManager: function(idSite, date, period, lastN, callback)
- {
- var ajaxParams =
- {
- module: 'Annotations',
- action: 'getAnnotationManager',
- idSite: idSite,
- date: date,
- period: period
- };
- if (lastN)
- {
- ajaxParams.lastN = lastN;
- }
-
- var ajaxRequest = new ajaxHelper();
- ajaxRequest.addParams(ajaxParams, 'get');
- ajaxRequest.setCallback(callback);
- ajaxRequest.setFormat('html');
- ajaxRequest.send(false);
- },
-
- // calls Annotations.addAnnotation
- addAnnotation: function(idSite, managerDate, managerPeriod, date, note, callback)
- {
- var ajaxParams =
- {
- module: 'Annotations',
- action: 'addAnnotation',
- idSite: idSite,
- date: date,
- managerDate: managerDate,
- managerPeriod: managerPeriod,
- note: note
- };
-
- var ajaxRequest = new ajaxHelper();
- ajaxRequest.addParams(ajaxParams, 'get');
- ajaxRequest.addParams({token_auth: piwik.token_auth}, 'post');
- ajaxRequest.setCallback(callback);
- ajaxRequest.setFormat('html');
- ajaxRequest.send(false);
- },
-
- // calls Annotations.saveAnnotation
- saveAnnotation: function(idSite, idNote, date, noteData, callback)
- {
- var ajaxParams =
- {
- module: 'Annotations',
- action: 'saveAnnotation',
- idSite: idSite,
- idNote: idNote,
- date: date
- };
-
- for (var key in noteData)
- {
- ajaxParams[key] = noteData[key];
- }
-
- var ajaxRequest = new ajaxHelper();
- ajaxRequest.addParams(ajaxParams, 'get');
- ajaxRequest.addParams({token_auth: piwik.token_auth}, 'post');
- ajaxRequest.setCallback(callback);
- ajaxRequest.setFormat('html');
- ajaxRequest.send(false);
- },
-
- // calls Annotations.deleteAnnotation
- deleteAnnotation: function(idSite, idNote, managerDate, managerPeriod, callback)
- {
- var ajaxParams =
- {
- module: 'Annotations',
- action: 'deleteAnnotation',
- idSite: idSite,
- idNote: idNote,
- date: managerDate,
- period: managerPeriod
- };
-
- var ajaxRequest = new ajaxHelper();
- ajaxRequest.addParams(ajaxParams, 'get');
- ajaxRequest.addParams({token_auth: piwik.token_auth}, 'post');
- ajaxRequest.setCallback(callback);
- ajaxRequest.setFormat('html');
- ajaxRequest.send(false);
- },
-
- // calls Annotations.getEvolutionIcons
- getEvolutionIcons: function(idSite, date, period, lastN, callback)
- {
- var ajaxParams =
- {
- module: 'Annotations',
- action: 'getEvolutionIcons',
- idSite: idSite,
- date: date,
- period: period
- };
- if (lastN)
- {
- ajaxParams.lastN = lastN;
- }
-
- var ajaxRequest = new ajaxHelper();
- ajaxRequest.addParams(ajaxParams, 'get');
- ajaxRequest.setFormat('html');
- ajaxRequest.setCallback(callback);
- ajaxRequest.send(false);
- }
-};
-
-var today = new Date();
-
-/**
- * Returns options to configure an annotation's datepicker shown in edit mode.
- *
- * @param {Element} annotation The annotation element.
- */
-var getDatePickerOptions = function(annotation)
-{
- var annotationDateStr = annotation.attr('data-date'),
- parts = annotationDateStr.split('-'),
- annotationDate = new Date(parts[0], parts[1] - 1, parts[2]);
-
- var result = piwik.getBaseDatePickerOptions(annotationDate);
-
- // make sure days before site start & after today cannot be selected
- var piwikMinDate = result.minDate;
- result.beforeShowDay = function (date)
- {
- var valid = true;
-
- // if date is after today or before date of site creation, it cannot be selected
- if (date > today
- || date < piwikMinDate)
- {
- valid = false;
- }
-
- return [valid, ''];
- };
-
- // on select a date, change the text of the edit date link
- result.onSelect = function (dateText)
- {
- $('.annotation-period-edit>a', annotation).text(dateText);
- $('.datepicker', annotation).hide();
- };
-
- return result;
-};
-
-/**
- * Switches the current mode of an annotation between the view/edit modes.
- *
- * @param {Element} inAnnotationElement An element within the annotation to toggle the mode of.
- * Should be two levels nested in the .annotation-value
- * element.
- * @return {Element} The .annotation-value element.
- */
-var toggleAnnotationMode = function(inAnnotationElement)
-{
- var annotation = $(inAnnotationElement).closest('.annotation');
- $('.annotation-period,.annotation-period-edit,.delete-annotation,' +
- '.annotation-edit-mode,.annotation-view-mode', annotation).toggle();
-
- return $(inAnnotationElement).find('.annotation-value');
-};
-
-/**
- * Creates the datepicker for an annotation element.
- *
- * @param {Element} annotation The annotation element.
- */
-var createDatePicker = function ( annotation )
-{
- $('.datepicker', annotation).datepicker(getDatePickerOptions(annotation)).hide();
-};
-
-/**
- * Creates datepickers for every period edit in an annotation manager.
- *
- * @param {Element} manager The annotation manager element.
- */
-var createDatePickers = function ( manager )
-{
- $('.annotation-period-edit', manager).each(function() {
- createDatePicker($(this).parent().parent());
- });
-}
-
-/**
- * Replaces the HTML of an annotation manager element, and resets date/period
- * attributes.
- *
- * @param {Element} manager The annotation manager.
- * @param {string} tml The HTML of the new annotation manager.
- */
-var replaceAnnotationManager = function(manager, html)
-{
- var newManager = $(html);
- manager.html(newManager.html())
- .attr('data-date', newManager.attr('data-date'))
- .attr('data-period', newManager.attr('data-period'));
- createDatePickers(manager);
-};
-
-/**
- * Returns true if an annotation element is starred, false if otherwise.
- *
- * @param {Element} annotation The annotation element.
- * @return {bool}
- */
-var isAnnotationStarred = function(annotation)
-{
- return +$('.annotation-star', annotation).attr('data-starred') == 1 ? true : false;
-};
-
-/**
- * Replaces the HTML of an annotation element with HTML returned from Piwik, and
- * makes sure the data attributes are correct.
- *
- * @param {Element} annotation The annotation element.
- * @param {string} html The replacement HTML (or alternatively, the replacement
- * element/jQuery object).
- */
-var replaceAnnotationHtml = function ( annotation, html )
-{
- var newHtml = $(html);
- annotation.html(newHtml.html()).attr('data-date', newHtml.attr('data-date'));
- createDatePicker(annotation);
-}
-
-/**
- * Binds events to an annotation manager element.
- *
- * @param {Element} manager The annotation manager.
- * @param {int} idSite The site ID the manager is showing annotations for.
- * @param {function} onAnnotationCountChange Callback that is called when there is a change
- * in the number of annotations and/or starred annotations,
- * eg, when a user adds a new one or deletes an existing one.
- */
-var bindAnnotationManagerEvents = function(manager, idSite, onAnnotationCountChange)
-{
- if (!onAnnotationCountChange)
- {
- onAnnotationCountChange = function() {};
- }
-
- // show new annotation row if create new annotation link is clicked
- manager.on('click', '.add-annotation', function(e) {
- e.preventDefault();
-
- $('.new-annotation-row', manager).show();
- $(this).hide();
-
- return false;
- });
-
- // hide new annotation row if cancel button clicked
- manager.on('click', '.new-annotation-cancel', function() {
- var newAnnotationRow = $(this).parent().parent();
- newAnnotationRow.hide();
-
- $('.add-annotation', newAnnotationRow.closest('.annotation-manager')).show();
- });
-
- // save new annotation when new annotation row save is clicked
- manager.on('click', '.new-annotation-save', function() {
- var addRow = $(this).parent().parent(),
- addNoteInput = addRow.find('.new-annotation-edit'),
- noteDate = addRow.find('.annotation-period-edit>a').text();
-
- // do nothing if input is empty
- if (!addNoteInput.val())
- {
- return;
- }
-
- // disable input & link
- addNoteInput.attr('disabled', 'disabled');
- $(this).attr('disabled', 'disabled');
-
- // add a new annotation for the site, date & period
- annotationsApi.addAnnotation(
- idSite,
- manager.attr('data-date'),
- manager.attr('data-period'),
- noteDate,
- addNoteInput.val(),
- function(response) {
- replaceAnnotationManager(manager, response);
-
- // increment annotation count for this date
- onAnnotationCountChange(noteDate, 1, 0);
- }
- );
- });
-
- // add new annotation when enter key pressed on new annotation input
- manager.on('keypress', '.new-annotation-edit', function(e) {
- if (e.which == 13)
- {
- $(this).parent().find('.new-annotation-save').click();
- }
- });
-
- // show annotation editor if edit link, annotation text or period text is clicked
- manager.on('click', '.annotation-enter-edit-mode', function(e) {
- e.preventDefault();
-
- var annotationContent = toggleAnnotationMode(this);
- annotationContent.find('.annotation-edit').focus();
-
- return false;
- });
-
- // hide annotation editor if cancel button is clicked
- manager.on('click', '.annotation-cancel', function() {
- toggleAnnotationMode(this);
- });
-
- // save annotation if save button clicked
- manager.on('click', '.annotation-edit-mode .annotation-save', function() {
- var annotation = $(this).parent().parent().parent(),
- input = $('.annotation-edit', annotation),
- dateEditText = $('.annotation-period-edit>a', annotation).text();
-
- // if annotation value/date has not changed, just show the view mode instead of edit
- if (input[0].defaultValue == input.val()
- && dateEditText == annotation.attr('data-date'))
- {
- toggleAnnotationMode(this);
- return;
- }
-
- // disable input while ajax is happening
- input.attr('disabled', 'disabled');
- $(this).attr('disabled', 'disabled');
-
- // save the note w/ the new note text & date
- annotationsApi.saveAnnotation(
- idSite,
- annotation.attr('data-id'),
- dateEditText,
- {
- note: input.val()
- },
- function(response) {
- response = $(response);
-
- var newDate = response.attr('data-date'),
- isStarred = isAnnotationStarred(response),
- originalDate = annotation.attr('data-date');
-
- replaceAnnotationHtml(annotation, response);
-
- // if the date has been changed, update the evolution icon counts to reflect the change
- if (originalDate != newDate)
- {
- // reduce count for original date
- onAnnotationCountChange(originalDate, -1, isStarred ? -1 : 0);
-
- // increase count for new date
- onAnnotationCountChange(newDate, 1, isStarred ? 1 : 0);
- }
- }
- );
- });
-
- // save annotation if 'enter' pressed on input
- manager.on('keypress', '.annotation-value input', function(e) {
- if (e.which == 13)
- {
- $(this).parent().find('.annotation-save').click();
- }
- });
-
- // delete annotation if delete link clicked
- manager.on('click', '.delete-annotation', function(e) {
- e.preventDefault();
-
- var annotation = $(this).parent().parent();
- $(this).attr('disabled', 'disabled');
-
- // delete annotation by ajax
- annotationsApi.deleteAnnotation(
- idSite,
- annotation.attr('data-id'),
- manager.attr('data-date'),
- manager.attr('data-period'),
- function (response) {
- replaceAnnotationManager(manager, response);
-
- // update evolution icons
- var isStarred = isAnnotationStarred(annotation);
- onAnnotationCountChange(annotation.attr('data-date'), -1, isStarred ? -1 : 0);
- }
- );
-
- return false;
- });
-
- // star/unstar annotation if star clicked
- manager.on('click', '.annotation-star-changeable', function(e) {
- var annotation = $(this).parent().parent(),
- newStarredVal = $(this).attr('data-starred') == 0 ? 1 : 0 // flip existing 'starred' value
- ;
-
- // perform ajax request to star annotation
- annotationsApi.saveAnnotation(
- idSite,
- annotation.attr('data-id'),
- annotation.attr('data-date'),
- {
- starred: newStarredVal
- },
- function (response) {
- replaceAnnotationHtml(annotation, response);
-
- // change starred count for this annotation in evolution graph based on what we're
- // changing the starred value to
- onAnnotationCountChange(annotation.attr('data-date'), 0, newStarredVal == 0 ? -1 : 1);
- }
- );
- });
-
- // when period edit is clicked, show datepicker
- manager.on('click', '.annotation-period-edit>a', function(e) {
- e.preventDefault();
- $('.datepicker', $(this).parent()).toggle();
- return false;
- });
-
- // make sure datepicker popups are closed if someone clicks elsewhere
- $('body').on('mouseup', function(e) {
- var container = $('.annotation-period-edit>.datepicker:visible').parent();
-
- if (!container.has(e.target).length)
- {
- container.find('.datepicker').hide();
- }
- });
-};
+(function ($, piwik) {
+
+ var annotationsApi = {
+
+ // calls Annotations.getAnnotationManager
+ getAnnotationManager: function (idSite, date, period, lastN, callback) {
+ var ajaxParams =
+ {
+ module: 'Annotations',
+ action: 'getAnnotationManager',
+ idSite: idSite,
+ date: date,
+ period: period
+ };
+ if (lastN) {
+ ajaxParams.lastN = lastN;
+ }
+
+ var ajaxRequest = new ajaxHelper();
+ ajaxRequest.addParams(ajaxParams, 'get');
+ ajaxRequest.setCallback(callback);
+ ajaxRequest.setFormat('html');
+ ajaxRequest.send(false);
+ },
+
+ // calls Annotations.addAnnotation
+ addAnnotation: function (idSite, managerDate, managerPeriod, date, note, callback) {
+ var ajaxParams =
+ {
+ module: 'Annotations',
+ action: 'addAnnotation',
+ idSite: idSite,
+ date: date,
+ managerDate: managerDate,
+ managerPeriod: managerPeriod,
+ note: note
+ };
+
+ var ajaxRequest = new ajaxHelper();
+ ajaxRequest.addParams(ajaxParams, 'get');
+ ajaxRequest.addParams({token_auth: piwik.token_auth}, 'post');
+ ajaxRequest.setCallback(callback);
+ ajaxRequest.setFormat('html');
+ ajaxRequest.send(false);
+ },
+
+ // calls Annotations.saveAnnotation
+ saveAnnotation: function (idSite, idNote, date, noteData, callback) {
+ var ajaxParams =
+ {
+ module: 'Annotations',
+ action: 'saveAnnotation',
+ idSite: idSite,
+ idNote: idNote,
+ date: date
+ };
+
+ for (var key in noteData) {
+ ajaxParams[key] = noteData[key];
+ }
+
+ var ajaxRequest = new ajaxHelper();
+ ajaxRequest.addParams(ajaxParams, 'get');
+ ajaxRequest.addParams({token_auth: piwik.token_auth}, 'post');
+ ajaxRequest.setCallback(callback);
+ ajaxRequest.setFormat('html');
+ ajaxRequest.send(false);
+ },
+
+ // calls Annotations.deleteAnnotation
+ deleteAnnotation: function (idSite, idNote, managerDate, managerPeriod, callback) {
+ var ajaxParams =
+ {
+ module: 'Annotations',
+ action: 'deleteAnnotation',
+ idSite: idSite,
+ idNote: idNote,
+ date: managerDate,
+ period: managerPeriod
+ };
+
+ var ajaxRequest = new ajaxHelper();
+ ajaxRequest.addParams(ajaxParams, 'get');
+ ajaxRequest.addParams({token_auth: piwik.token_auth}, 'post');
+ ajaxRequest.setCallback(callback);
+ ajaxRequest.setFormat('html');
+ ajaxRequest.send(false);
+ },
+
+ // calls Annotations.getEvolutionIcons
+ getEvolutionIcons: function (idSite, date, period, lastN, callback) {
+ var ajaxParams =
+ {
+ module: 'Annotations',
+ action: 'getEvolutionIcons',
+ idSite: idSite,
+ date: date,
+ period: period
+ };
+ if (lastN) {
+ ajaxParams.lastN = lastN;
+ }
+
+ var ajaxRequest = new ajaxHelper();
+ ajaxRequest.addParams(ajaxParams, 'get');
+ ajaxRequest.setFormat('html');
+ ajaxRequest.setCallback(callback);
+ ajaxRequest.send(false);
+ }
+ };
+
+ var today = new Date();
+
+ /**
+ * Returns options to configure an annotation's datepicker shown in edit mode.
+ *
+ * @param {Element} annotation The annotation element.
+ */
+ var getDatePickerOptions = function (annotation) {
+ var annotationDateStr = annotation.attr('data-date'),
+ parts = annotationDateStr.split('-'),
+ annotationDate = new Date(parts[0], parts[1] - 1, parts[2]);
+
+ var result = piwik.getBaseDatePickerOptions(annotationDate);
+
+ // make sure days before site start & after today cannot be selected
+ var piwikMinDate = result.minDate;
+ result.beforeShowDay = function (date) {
+ var valid = true;
+
+ // if date is after today or before date of site creation, it cannot be selected
+ if (date > today
+ || date < piwikMinDate) {
+ valid = false;
+ }
+
+ return [valid, ''];
+ };
+
+ // on select a date, change the text of the edit date link
+ result.onSelect = function (dateText) {
+ $('.annotation-period-edit>a', annotation).text(dateText);
+ $('.datepicker', annotation).hide();
+ };
+
+ return result;
+ };
+
+ /**
+ * Switches the current mode of an annotation between the view/edit modes.
+ *
+ * @param {Element} inAnnotationElement An element within the annotation to toggle the mode of.
+ * Should be two levels nested in the .annotation-value
+ * element.
+ * @return {Element} The .annotation-value element.
+ */
+ var toggleAnnotationMode = function (inAnnotationElement) {
+ var annotation = $(inAnnotationElement).closest('.annotation');
+ $('.annotation-period,.annotation-period-edit,.delete-annotation,' +
+ '.annotation-edit-mode,.annotation-view-mode', annotation).toggle();
+
+ return $(inAnnotationElement).find('.annotation-value');
+ };
+
+ /**
+ * Creates the datepicker for an annotation element.
+ *
+ * @param {Element} annotation The annotation element.
+ */
+ var createDatePicker = function (annotation) {
+ $('.datepicker', annotation).datepicker(getDatePickerOptions(annotation)).hide();
+ };
+
+ /**
+ * Creates datepickers for every period edit in an annotation manager.
+ *
+ * @param {Element} manager The annotation manager element.
+ */
+ var createDatePickers = function (manager) {
+ $('.annotation-period-edit', manager).each(function () {
+ createDatePicker($(this).parent().parent());
+ });
+ }
+
+ /**
+ * Replaces the HTML of an annotation manager element, and resets date/period
+ * attributes.
+ *
+ * @param {Element} manager The annotation manager.
+ * @param {string} tml The HTML of the new annotation manager.
+ */
+ var replaceAnnotationManager = function (manager, html) {
+ var newManager = $(html);
+ manager.html(newManager.html())
+ .attr('data-date', newManager.attr('data-date'))
+ .attr('data-period', newManager.attr('data-period'));
+ createDatePickers(manager);
+ };
+
+ /**
+ * Returns true if an annotation element is starred, false if otherwise.
+ *
+ * @param {Element} annotation The annotation element.
+ * @return {bool}
+ */
+ var isAnnotationStarred = function (annotation) {
+ return +$('.annotation-star', annotation).attr('data-starred') == 1 ? true : false;
+ };
+
+ /**
+ * Replaces the HTML of an annotation element with HTML returned from Piwik, and
+ * makes sure the data attributes are correct.
+ *
+ * @param {Element} annotation The annotation element.
+ * @param {string} html The replacement HTML (or alternatively, the replacement
+ * element/jQuery object).
+ */
+ var replaceAnnotationHtml = function (annotation, html) {
+ var newHtml = $(html);
+ annotation.html(newHtml.html()).attr('data-date', newHtml.attr('data-date'));
+ createDatePicker(annotation);
+ }
+
+ /**
+ * Binds events to an annotation manager element.
+ *
+ * @param {Element} manager The annotation manager.
+ * @param {int} idSite The site ID the manager is showing annotations for.
+ * @param {function} onAnnotationCountChange Callback that is called when there is a change
+ * in the number of annotations and/or starred annotations,
+ * eg, when a user adds a new one or deletes an existing one.
+ */
+ var bindAnnotationManagerEvents = function (manager, idSite, onAnnotationCountChange) {
+ if (!onAnnotationCountChange) {
+ onAnnotationCountChange = function () {};
+ }
+
+ // show new annotation row if create new annotation link is clicked
+ manager.on('click', '.add-annotation', function (e) {
+ e.preventDefault();
+
+ $('.new-annotation-row', manager).show();
+ $(this).hide();
+
+ return false;
+ });
+
+ // hide new annotation row if cancel button clicked
+ manager.on('click', '.new-annotation-cancel', function () {
+ var newAnnotationRow = $(this).parent().parent();
+ newAnnotationRow.hide();
+
+ $('.add-annotation', newAnnotationRow.closest('.annotation-manager')).show();
+ });
+
+ // save new annotation when new annotation row save is clicked
+ manager.on('click', '.new-annotation-save', function () {
+ var addRow = $(this).parent().parent(),
+ addNoteInput = addRow.find('.new-annotation-edit'),
+ noteDate = addRow.find('.annotation-period-edit>a').text();
+
+ // do nothing if input is empty
+ if (!addNoteInput.val()) {
+ return;
+ }
+
+ // disable input & link
+ addNoteInput.attr('disabled', 'disabled');
+ $(this).attr('disabled', 'disabled');
+
+ // add a new annotation for the site, date & period
+ annotationsApi.addAnnotation(
+ idSite,
+ manager.attr('data-date'),
+ manager.attr('data-period'),
+ noteDate,
+ addNoteInput.val(),
+ function (response) {
+ replaceAnnotationManager(manager, response);
+
+ // increment annotation count for this date
+ onAnnotationCountChange(noteDate, 1, 0);
+ }
+ );
+ });
+
+ // add new annotation when enter key pressed on new annotation input
+ manager.on('keypress', '.new-annotation-edit', function (e) {
+ if (e.which == 13) {
+ $(this).parent().find('.new-annotation-save').click();
+ }
+ });
+
+ // show annotation editor if edit link, annotation text or period text is clicked
+ manager.on('click', '.annotation-enter-edit-mode', function (e) {
+ e.preventDefault();
+
+ var annotationContent = toggleAnnotationMode(this);
+ annotationContent.find('.annotation-edit').focus();
+
+ return false;
+ });
+
+ // hide annotation editor if cancel button is clicked
+ manager.on('click', '.annotation-cancel', function () {
+ toggleAnnotationMode(this);
+ });
+
+ // save annotation if save button clicked
+ manager.on('click', '.annotation-edit-mode .annotation-save', function () {
+ var annotation = $(this).parent().parent().parent(),
+ input = $('.annotation-edit', annotation),
+ dateEditText = $('.annotation-period-edit>a', annotation).text();
+
+ // if annotation value/date has not changed, just show the view mode instead of edit
+ if (input[0].defaultValue == input.val()
+ && dateEditText == annotation.attr('data-date')) {
+ toggleAnnotationMode(this);
+ return;
+ }
+
+ // disable input while ajax is happening
+ input.attr('disabled', 'disabled');
+ $(this).attr('disabled', 'disabled');
+
+ // save the note w/ the new note text & date
+ annotationsApi.saveAnnotation(
+ idSite,
+ annotation.attr('data-id'),
+ dateEditText,
+ {
+ note: input.val()
+ },
+ function (response) {
+ response = $(response);
+
+ var newDate = response.attr('data-date'),
+ isStarred = isAnnotationStarred(response),
+ originalDate = annotation.attr('data-date');
+
+ replaceAnnotationHtml(annotation, response);
+
+ // if the date has been changed, update the evolution icon counts to reflect the change
+ if (originalDate != newDate) {
+ // reduce count for original date
+ onAnnotationCountChange(originalDate, -1, isStarred ? -1 : 0);
+
+ // increase count for new date
+ onAnnotationCountChange(newDate, 1, isStarred ? 1 : 0);
+ }
+ }
+ );
+ });
+
+ // save annotation if 'enter' pressed on input
+ manager.on('keypress', '.annotation-value input', function (e) {
+ if (e.which == 13) {
+ $(this).parent().find('.annotation-save').click();
+ }
+ });
+
+ // delete annotation if delete link clicked
+ manager.on('click', '.delete-annotation', function (e) {
+ e.preventDefault();
+
+ var annotation = $(this).parent().parent();
+ $(this).attr('disabled', 'disabled');
+
+ // delete annotation by ajax
+ annotationsApi.deleteAnnotation(
+ idSite,
+ annotation.attr('data-id'),
+ manager.attr('data-date'),
+ manager.attr('data-period'),
+ function (response) {
+ replaceAnnotationManager(manager, response);
+
+ // update evolution icons
+ var isStarred = isAnnotationStarred(annotation);
+ onAnnotationCountChange(annotation.attr('data-date'), -1, isStarred ? -1 : 0);
+ }
+ );
+
+ return false;
+ });
+
+ // star/unstar annotation if star clicked
+ manager.on('click', '.annotation-star-changeable', function (e) {
+ var annotation = $(this).parent().parent(),
+ newStarredVal = $(this).attr('data-starred') == 0 ? 1 : 0 // flip existing 'starred' value
+ ;
+
+ // perform ajax request to star annotation
+ annotationsApi.saveAnnotation(
+ idSite,
+ annotation.attr('data-id'),
+ annotation.attr('data-date'),
+ {
+ starred: newStarredVal
+ },
+ function (response) {
+ replaceAnnotationHtml(annotation, response);
+
+ // change starred count for this annotation in evolution graph based on what we're
+ // changing the starred value to
+ onAnnotationCountChange(annotation.attr('data-date'), 0, newStarredVal == 0 ? -1 : 1);
+ }
+ );
+ });
+
+ // when period edit is clicked, show datepicker
+ manager.on('click', '.annotation-period-edit>a', function (e) {
+ e.preventDefault();
+ $('.datepicker', $(this).parent()).toggle();
+ return false;
+ });
+
+ // make sure datepicker popups are closed if someone clicks elsewhere
+ $('body').on('mouseup', function (e) {
+ var container = $('.annotation-period-edit>.datepicker:visible').parent();
+
+ if (!container.has(e.target).length) {
+ container.find('.datepicker').hide();
+ }
+ });
+ };
// used in below function
-var loadingAnnotationManager = false;
-
-/**
- * Shows an annotation manager under a report for a specific site & date range.
- *
- * @param {Element} domElem The element of the report to show the annotation manger
- * under.
- * @param {int} idSite The ID of the site to show the annotations of.
- * @param {string} date The start date of the period.
- * @param {string} period The period type.
- * @param {int} Whether to include the last N periods in the date range or not. Can
- * be undefined.
- */
-var showAnnotationViewer = function(domElem, idSite, date, period, lastN, callback)
-{
- var addToAnnotationCount = function(date, amt, starAmt)
- {
- if (date.indexOf(',') != -1)
- {
- date = date.split(',')[0];
- }
-
- $('.evolution-annotations>span', domElem).each(function() {
- if ($(this).attr('data-date') == date)
- {
- // get counts from attributes (and convert them to ints)
- var starredCount = +$(this).attr('data-starred'),
- annotationCount = +$(this).attr('data-count');
-
- // modify the starred count & make sure the correct image is used
- var newStarCount = starredCount + starAmt;
- if(newStarCount > 0) {
- var newImg = 'themes/default/images/yellow_marker.png';
- } else {
- var newImg = 'themes/default/images/grey_marker.png';
+ var loadingAnnotationManager = false;
+
+ /**
+ * Shows an annotation manager under a report for a specific site & date range.
+ *
+ * @param {Element} domElem The element of the report to show the annotation manger
+ * under.
+ * @param {int} idSite The ID of the site to show the annotations of.
+ * @param {string} date The start date of the period.
+ * @param {string} period The period type.
+ * @param {int} Whether to include the last N periods in the date range or not. Can
+ * be undefined.
+ */
+ var showAnnotationViewer = function (domElem, idSite, date, period, lastN, callback) {
+ var addToAnnotationCount = function (date, amt, starAmt) {
+ if (date.indexOf(',') != -1) {
+ date = date.split(',')[0];
+ }
+
+ $('.evolution-annotations>span', domElem).each(function () {
+ if ($(this).attr('data-date') == date) {
+ // get counts from attributes (and convert them to ints)
+ var starredCount = +$(this).attr('data-starred'),
+ annotationCount = +$(this).attr('data-count');
+
+ // modify the starred count & make sure the correct image is used
+ var newStarCount = starredCount + starAmt;
+ if (newStarCount > 0) {
+ var newImg = 'themes/default/images/yellow_marker.png';
+ } else {
+ var newImg = 'themes/default/images/grey_marker.png';
+ }
+ $(this).attr('data-starred', newStarCount).find('img').attr('src', newImg);
+
+ // modify the annotation count & hide/show based on new count
+ var newCount = annotationCount + amt;
+ $(this).attr('data-count', newCount).css('opacity', newCount > 0 ? 1 : 0);
+
+ return false;
+ }
+ });
+ };
+
+ var manager = $('.annotation-manager', domElem);
+ if (manager.length) {
+ // if annotations for the requested date + period are already loaded, then just toggle the
+ // visibility of the annotation viewer. otherwise, we reload the annotations.
+ if (manager.attr('data-date') == date
+ && manager.attr('data-period') == period) {
+ // toggle manager view
+ if (manager.is(':hidden')) {
+ manager.slideDown('slow', function () { if (callback) callback(manager) });
+ }
+ else {
+ manager.slideUp('slow', function () { if (callback) callback(manager) });
+ }
+ }
+ else {
+ // show nothing but the loading gif
+ $('.annotations', manager).html('');
+ $('.loadingPiwik', manager).show();
+
+ // reload annotation manager for new date/period
+ annotationsApi.getAnnotationManager(idSite, date, period, lastN, function (response) {
+ replaceAnnotationManager(manager, response);
+
+ createDatePickers(manager);
+
+ // show if hidden
+ if (manager.is(':hidden')) {
+ manager.slideDown('slow', function () { if (callback) callback(manager) });
+ }
+ else {
+ if (callback) {
+ callback(manager);
+ }
+ }
+ });
+ }
}
- $(this).attr('data-starred', newStarCount).find('img').attr('src', newImg);
-
- // modify the annotation count & hide/show based on new count
- var newCount = annotationCount + amt;
- $(this).attr('data-count', newCount).css('opacity', newCount > 0 ? 1 : 0);
-
- return false;
- }
- });
- };
-
- var manager = $('.annotation-manager', domElem);
- if (manager.length)
- {
- // if annotations for the requested date + period are already loaded, then just toggle the
- // visibility of the annotation viewer. otherwise, we reload the annotations.
- if (manager.attr('data-date') == date
- && manager.attr('data-period') == period)
- {
- // toggle manager view
- if (manager.is(':hidden'))
- {
- manager.slideDown('slow', function () { if (callback) callback(manager) });
- }
- else
- {
- manager.slideUp('slow', function () { if (callback) callback(manager) });
- }
- }
- else
- {
- // show nothing but the loading gif
- $('.annotations', manager).html('');
- $('.loadingPiwik', manager).show();
-
- // reload annotation manager for new date/period
- annotationsApi.getAnnotationManager(idSite, date, period, lastN, function(response) {
- replaceAnnotationManager(manager, response);
-
- createDatePickers(manager);
-
- // show if hidden
- if (manager.is(':hidden'))
- {
- manager.slideDown('slow', function () { if (callback) callback(manager) });
- }
- else
- {
- if (callback)
- {
- callback(manager);
- }
- }
- });
- }
- }
- else
- {
- // if we are already loading the annotation manager, don't load it again
- if (loadingAnnotationManager)
- {
- return;
- }
-
- loadingAnnotationManager = true;
-
- var loading = $('.loadingPiwikBelow', domElem).css({display: 'block'});
-
- // the annotations for this report have not been retrieved yet, so do an ajax request
- // & show the result
- annotationsApi.getAnnotationManager(idSite, date, period, lastN, function(response) {
- var manager = $(response).hide();
-
- // if an error occurred (and response does not contain the annotation manager), do nothing
- if (!manager.hasClass('annotation-manager'))
- {
- return;
- }
-
- // create datepickers for each shown annotation
- createDatePickers(manager);
-
- bindAnnotationManagerEvents(manager, idSite, addToAnnotationCount);
-
- loading.css('visibility', 'hidden');
-
- // add & show annotation manager
- $('.dataTableFeatures', domElem).append(manager);
- manager.slideDown('slow', function() {
- loading.hide().css('visibility', 'visible');
- loadingAnnotationManager = false;
-
- if (callback) callback(manager)
- });
- });
- }
-};
-
-/**
- * Determines the x-coordinates of a set of evolution annotation icons.
- *
- * @param {Element} annotations The '.evolution-annotations' element.
- * @param {Element} graphElem The evolution graph's datatable element.
- */
-var placeEvolutionIcons = function (annotations, graphElem)
-{
- var canvases = $('.piwik-graph .jqplot-xaxis canvas', graphElem),
- noteSize = 16;
-
- // if no graph available, hide all icons
- if (!canvases || canvases.length == 0) {
- $('span', annotations).hide();
- return true;
- }
-
- // set position of each individual icon
- $('span', annotations).each(function(i) {
- var canvas = $(canvases[i]),
- canvasCenterX = canvas.position().left + (canvas.width() / 2);
- $(this).css({
- left: canvasCenterX - noteSize / 2,
- // show if there are annotations for this x-axis tick
- opacity: +$(this).attr('data-count') > 0 ? 1 : 0
- });
- });
-};
+ else {
+ // if we are already loading the annotation manager, don't load it again
+ if (loadingAnnotationManager) {
+ return;
+ }
+
+ loadingAnnotationManager = true;
+
+ var loading = $('.loadingPiwikBelow', domElem).css({display: 'block'});
+
+ // the annotations for this report have not been retrieved yet, so do an ajax request
+ // & show the result
+ annotationsApi.getAnnotationManager(idSite, date, period, lastN, function (response) {
+ var manager = $(response).hide();
+
+ // if an error occurred (and response does not contain the annotation manager), do nothing
+ if (!manager.hasClass('annotation-manager')) {
+ return;
+ }
+
+ // create datepickers for each shown annotation
+ createDatePickers(manager);
+
+ bindAnnotationManagerEvents(manager, idSite, addToAnnotationCount);
+
+ loading.css('visibility', 'hidden');
+
+ // add & show annotation manager
+ $('.dataTableFeatures', domElem).append(manager);
+ manager.slideDown('slow', function () {
+ loading.hide().css('visibility', 'visible');
+ loadingAnnotationManager = false;
+
+ if (callback) callback(manager)
+ });
+ });
+ }
+ };
+
+ /**
+ * Determines the x-coordinates of a set of evolution annotation icons.
+ *
+ * @param {Element} annotations The '.evolution-annotations' element.
+ * @param {Element} graphElem The evolution graph's datatable element.
+ */
+ var placeEvolutionIcons = function (annotations, graphElem) {
+ var canvases = $('.piwik-graph .jqplot-xaxis canvas', graphElem),
+ noteSize = 16;
+
+ // if no graph available, hide all icons
+ if (!canvases || canvases.length == 0) {
+ $('span', annotations).hide();
+ return true;
+ }
+
+ // set position of each individual icon
+ $('span', annotations).each(function (i) {
+ var canvas = $(canvases[i]),
+ canvasCenterX = canvas.position().left + (canvas.width() / 2);
+ $(this).css({
+ left: canvasCenterX - noteSize / 2,
+ // show if there are annotations for this x-axis tick
+ opacity: +$(this).attr('data-count') > 0 ? 1 : 0
+ });
+ });
+ };
// make showAnnotationViewer, placeEvolutionIcons & annotationsApi globally accessible
-piwik.annotations = {
- showAnnotationViewer: showAnnotationViewer,
- placeEvolutionIcons: placeEvolutionIcons,
- api: annotationsApi
-};
+ piwik.annotations = {
+ showAnnotationViewer: showAnnotationViewer,
+ placeEvolutionIcons: placeEvolutionIcons,
+ api: annotationsApi
+ };
}(jQuery, piwik));
diff --git a/plugins/Annotations/templates/annotations.tpl b/plugins/Annotations/templates/annotations.tpl
index f15750e548..26c1f708f1 100755
--- a/plugins/Annotations/templates/annotations.tpl
+++ b/plugins/Annotations/templates/annotations.tpl
@@ -1,30 +1,29 @@
<div class="annotations">
-{if empty($annotations)}
+ {if empty($annotations)}
+ <div class="empty-annotation-list">{'Annotations_NoAnnotations'|translate}</div>
+ {/if}
-<div class="empty-annotation-list">{'Annotations_NoAnnotations'|translate}</div>
+ <table>
+ {foreach from=$annotations item=annotation}
+ {include file="Annotations/templates/annotation.tpl"}
+ {/foreach}
+ <tr class="new-annotation-row" style="display:none" data-date="{$startDate}">
+ <td class="annotation-meta">
+ <div class="annotation-star">&nbsp;</div>
+ <div class="annotation-period-edit">
+ <a href="#">{$startDate}</a>
-{/if}
-
-<table>
-{foreach from=$annotations item=annotation}
-{include file="Annotations/templates/annotation.tpl"}
-{/foreach}
-<tr class="new-annotation-row" style="display:none" data-date="{$startDate}">
- <td class="annotation-meta">
- <div class="annotation-star">&nbsp;</div>
- <div class="annotation-period-edit">
- <a href="#">{$startDate}</a>
- <div class="datepicker" style="display:none"/>
- </div>
- </td>
- <td class="annotation-value">
- <input type="text" value="" class="new-annotation-edit" placeholder="{'Annotations_EnterAnnotationText'|translate}"/><br/>
- <input type="button" class="submit new-annotation-save" value="{'General_Save'|translate}"/>
- <input type="button" class="submit new-annotation-cancel" value="{'General_Cancel'|translate}"/>
- </td>
- <td class="annotation-user-cell"><span class="annotation-user">{$userLogin}</span></td>
-</tr>
-</table>
+ <div class="datepicker" style="display:none"/>
+ </div>
+ </td>
+ <td class="annotation-value">
+ <input type="text" value="" class="new-annotation-edit" placeholder="{'Annotations_EnterAnnotationText'|translate}"/><br/>
+ <input type="button" class="submit new-annotation-save" value="{'General_Save'|translate}"/>
+ <input type="button" class="submit new-annotation-cancel" value="{'General_Cancel'|translate}"/>
+ </td>
+ <td class="annotation-user-cell"><span class="annotation-user">{$userLogin}</span></td>
+ </tr>
+ </table>
</div>
diff --git a/plugins/Annotations/templates/evolutionAnnotations.tpl b/plugins/Annotations/templates/evolutionAnnotations.tpl
index 8da13d35f0..eaf6f9d9d3 100755
--- a/plugins/Annotations/templates/evolutionAnnotations.tpl
+++ b/plugins/Annotations/templates/evolutionAnnotations.tpl
@@ -1,15 +1,15 @@
<div class="evolution-annotations">
-{foreach from=$annotationCounts item=dateCountPair}
- {assign var=date value=$dateCountPair[0]}
- {assign var=counts value=$dateCountPair[1]}
- <span data-date="{$date}" data-count="{$counts.count}" data-starred="{$counts.starred}"
- {if $counts.count eq 0}title="{'Annotations_AddAnnotationsFor_js'|translate:$date}"
- {elseif $counts.count eq 1}title="{'Annotations_AnnotationOnDate'|translate:$date:$counts.note}
+ {foreach from=$annotationCounts item=dateCountPair}
+ {assign var=date value=$dateCountPair[0]}
+ {assign var=counts value=$dateCountPair[1]}
+ <span data-date="{$date}" data-count="{$counts.count}" data-starred="{$counts.starred}"
+ {if $counts.count eq 0}title="{'Annotations_AddAnnotationsFor_js'|translate:$date}"
+ {elseif $counts.count eq 1}title="{'Annotations_AnnotationOnDate'|translate:$date:$counts.note}
{'Annotations_ClickToEditOrAdd'|translate}"
- {else}title="{'Annotations_ViewAndAddAnnotations_js'|translate:$date}"
- {/if}>
+ {else}title="{'Annotations_ViewAndAddAnnotations_js'|translate:$date}"
+ {/if}>
<img src="themes/default/images/{if $counts.starred > 0}yellow_marker.png{else}grey_marker.png{/if}" width="16" height="16"/>
</span>
-{/foreach}
+ {/foreach}
</div>
diff --git a/plugins/Annotations/templates/styles.css b/plugins/Annotations/templates/styles.css
index 4831bafcb1..089a8ef6c3 100755
--- a/plugins/Annotations/templates/styles.css
+++ b/plugins/Annotations/templates/styles.css
@@ -1,194 +1,198 @@
.evolution-annotations {
- position: relative;
- height: 16px;
- width: 100%;
- margin-top: 12px;
- margin-bottom: -28px;
- cursor: pointer;
+ position: relative;
+ height: 16px;
+ width: 100%;
+ margin-top: 12px;
+ margin-bottom: -28px;
+ cursor: pointer;
}
.evolution-annotations > span {
- position: absolute;
+ position: absolute;
}
.annotation-manager {
- text-align: left;
- margin-top: -18px;
+ text-align: left;
+ margin-top: -18px;
}
.annotations-header {
- display: inline-block;
- width: 128px;
- text-align: right;
- font-size: 12px;
- font-style: italic;
- margin-bottom: 8px;
- vertical-align: top;
- color: #666;
+ display: inline-block;
+ width: 128px;
+ text-align: right;
+ font-size: 12px;
+ font-style: italic;
+ margin-bottom: 8px;
+ vertical-align: top;
+ color: #666;
}
.annotation-controls {
- display:inline-block;
- margin-left: 132px;
+ display: inline-block;
+ margin-left: 132px;
}
.annotation-controls>a {
- font-size: 11px;
- font-style: italic;
- color: #666;
- cursor:pointer;
- padding:3px 0 6px 0;
- display:inline-block;
+ font-size: 11px;
+ font-style: italic;
+ color: #666;
+ cursor: pointer;
+ padding: 3px 0 6px 0;
+ display: inline-block;
}
.annotation-controls>a:hover {
- text-decoration:none;
+ text-decoration: none;
}
.annotation-list {
- margin-left: 8px;
+ margin-left: 8px;
}
.annotation-list table {
- width: 100%;
+ width: 100%;
}
.annotation-list-range {
- display: inline-block;
- font-size: 12px;
- font-style: italic;
- color: #666;
- vertical-align: top;
- margin: 0 0 8px 8px;
+ display: inline-block;
+ font-size: 12px;
+ font-style: italic;
+ color: #666;
+ vertical-align: top;
+ margin: 0 0 8px 8px;
}
-.empty-annotation-list,.annotation-list .loadingPiwik {
- display: block;
-
- font-style: italic;
- color: #666;
- margin: 0 0 12px 140px;
+.empty-annotation-list, .annotation-list .loadingPiwik {
+ display: block;
+
+ font-style: italic;
+ color: #666;
+ margin: 0 0 12px 140px;
}
.annotation-meta {
- width: 128px;
- text-align: right;
- vertical-align: top;
- font-size:14px;
+ width: 128px;
+ text-align: right;
+ vertical-align: top;
+ font-size: 14px;
}
.annotation-user {
- font-style: italic;
- font-size: 11px;
- color:#444;
+ font-style: italic;
+ font-size: 11px;
+ color: #444;
}
.annotation-user-cell {
- vertical-align: top;
- width: 92px;
+ vertical-align: top;
+ width: 92px;
}
.annotation-period {
- display:inline-block;
- font-style: italic;
- margin: 0 8px 8px 8px;
- vertical-align: top;
+ display: inline-block;
+ font-style: italic;
+ margin: 0 8px 8px 8px;
+ vertical-align: top;
}
.annotation-value {
- margin: 0 12px 12px 8px;
- vertical-align: top;
- position: relative;
- font-size:14px;
+ margin: 0 12px 12px 8px;
+ vertical-align: top;
+ position: relative;
+ font-size: 14px;
}
.annotation-enter-edit-mode {
- cursor: pointer;
+ cursor: pointer;
}
-.annotation-edit,.new-annotation-edit {
- -webkit-box-sizing: border-box;
- -moz-box-sizing: border-box;
- box-sizing: border-box;
- width:98%;
+.annotation-edit, .new-annotation-edit {
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+ width: 98%;
}
.annotation-star {
- display: inline-block;
- margin: 0 8px 8px 0;
- width: 16px;
+ display: inline-block;
+ margin: 0 8px 8px 0;
+ width: 16px;
}
.annotation-star-changeable {
- cursor: pointer;
+ cursor: pointer;
}
.delete-annotation {
- font-size:12px;
- font-style: italic;
- color: red;
- text-decoration: none;
- display: inline-block;
+ font-size: 12px;
+ font-style: italic;
+ color: red;
+ text-decoration: none;
+ display: inline-block;
}
.delete-annotation:hover {
- text-decoration: underline;
+ text-decoration: underline;
}
.annotation-manager .submit {
- float:none;
+ float: none;
}
.edit-annotation {
- font-size:10px;
- color:#666;
- font-style:italic;
+ font-size: 10px;
+ color: #666;
+ font-style: italic;
}
+
.edit-annotation:hover {
- text-decoration:none;
+ text-decoration: none;
}
.annotationView {
- float: right;
+ float: right;
margin-left: 5px;
position: relative;
- cursor:pointer;
+ cursor: pointer;
}
.annotationView > span {
- font-style: italic;
- display: inline-block;
- margin: 4px 4px 0 4px;
+ font-style: italic;
+ display: inline-block;
+ margin: 4px 4px 0 4px;
}
.annotation-period-edit {
- display:inline-block;
- background:white;
- color:#444;
- font-size:12px;
- border: 1px solid #e4e5e4;
- padding:5px 5px 6px 3px;
- border-radius:4px;
- -moz-border-radius:4px;
- -webkit-border-radius:4px;
+ display: inline-block;
+ background: white;
+ color: #444;
+ font-size: 12px;
+ border: 1px solid #e4e5e4;
+ padding: 5px 5px 6px 3px;
+ border-radius: 4px;
+ -moz-border-radius: 4px;
+ -webkit-border-radius: 4px;
}
+
.annotation-period-edit:hover {
- background:#f1f0eb;
- border-color:#a9a399;
+ background: #f1f0eb;
+ border-color: #a9a399;
}
+
.annotation-period-edit>a {
- text-decoration:none;
- cursor:pointer;
- display:block;
+ text-decoration: none;
+ cursor: pointer;
+ display: block;
}
+
.annotation-period-edit>.datepicker {
- position:absolute;
- margin-top:6px;
- margin-left:-5px;
- z-index:15;
- background:white;
- border: 1px solid #e4e5e4;
- border-radius:4px;
- -moz-border-radius:4px;
- -webkit-border-radius:4px;
+ position: absolute;
+ margin-top: 6px;
+ margin-left: -5px;
+ z-index: 15;
+ background: white;
+ border: 1px solid #e4e5e4;
+ border-radius: 4px;
+ -moz-border-radius: 4px;
+ -webkit-border-radius: 4px;
}