add icons for Character groups

This commit is contained in:
coderkun 2014-04-29 14:18:04 +02:00
commit 2d9a41a5fe
3461 changed files with 594457 additions and 0 deletions

View file

@ -0,0 +1,329 @@
<?php
/**
* Piwik - Open source web analytics
*
* @link http://piwik.org
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
*
*/
namespace Piwik\Plugins\SegmentEditor;
use Exception;
use Piwik\Common;
use Piwik\Date;
use Piwik\Db;
use Piwik\Piwik;
use Piwik\Segment;
/**
* The SegmentEditor API lets you add, update, delete custom Segments, and list saved segments.a
*
* @method static \Piwik\Plugins\SegmentEditor\API getInstance()
*/
class API extends \Piwik\Plugin\API
{
const DEACTIVATE_SEGMENT_EVENT = 'SegmentEditor.deactivate';
protected function checkSegmentValue($definition, $idSite)
{
// unsanitize so we don't record the HTML entitied segment
$definition = Common::unsanitizeInputValue($definition);
$definition = str_replace("#", '%23', $definition); // hash delimiter
$definition = str_replace("'", '%27', $definition); // not encoded in JS
$definition = str_replace("&", '%26', $definition);
try {
$segment = new Segment($definition, $idSite);
$segment->getHash();
} catch (Exception $e) {
throw new Exception("The specified segment is invalid: " . $e->getMessage());
}
return $definition;
}
protected function checkSegmentName($name)
{
if (empty($name)) {
throw new Exception("Invalid name for this custom segment.");
}
}
protected function checkEnabledAllUsers($enabledAllUsers)
{
$enabledAllUsers = (int)$enabledAllUsers;
if ($enabledAllUsers
&& !Piwik::hasUserSuperUserAccess()
) {
throw new Exception("enabledAllUsers=1 requires Super User access");
}
return $enabledAllUsers;
}
protected function checkIdSite($idSite)
{
if (empty($idSite)) {
if (!Piwik::hasUserSuperUserAccess()) {
throw new Exception($this->getMessageCannotEditSegmentCreatedBySuperUser());
}
} else {
if (!is_numeric($idSite)) {
throw new Exception("idSite should be a numeric value");
}
Piwik::checkUserHasViewAccess($idSite);
}
$idSite = (int)$idSite;
return $idSite;
}
protected function checkAutoArchive($autoArchive, $idSite)
{
$autoArchive = (int)$autoArchive;
if ($autoArchive) {
$exception = new Exception("To prevent abuse, autoArchive=1 requires Super User or ControllerAdmin access.");
if (empty($idSite)) {
if (!Piwik::hasUserSuperUserAccess()) {
throw $exception;
}
} else {
if (!Piwik::isUserHasAdminAccess($idSite)) {
throw $exception;
}
}
}
return $autoArchive;
}
protected function getSegmentOrFail($idSegment)
{
$segment = $this->get($idSegment);
if (empty($segment)) {
throw new Exception("Requested segment not found");
}
return $segment;
}
protected function checkUserIsNotAnonymous()
{
if (Piwik::isUserIsAnonymous()) {
throw new Exception("To create, edit or delete Custom Segments, please sign in first.");
}
}
protected function checkUserCanModifySegment($segment)
{
if(Piwik::hasUserSuperUserAccess()) {
return;
}
if($segment['login'] != Piwik::getCurrentUserLogin()) {
throw new Exception($this->getMessageCannotEditSegmentCreatedBySuperUser());
}
}
/**
* Deletes a stored segment.
*
* @param $idSegment
* @return bool
*/
public function delete($idSegment)
{
$this->checkUserIsNotAnonymous();
$segment = $this->getSegmentOrFail($idSegment);
$this->checkUserCanModifySegment($segment);
$this->sendSegmentDeactivationEvent($idSegment);
$db = Db::get();
$db->delete(Common::prefixTable('segment'), 'idsegment = ' . $idSegment);
return true;
}
/**
* Modifies an existing stored segment.
*
* @param int $idSegment The ID of the stored segment to modify.
* @param string $name The new name of the segment.
* @param string $definition The new definition of the segment.
* @param bool $idSite If supplied, associates the stored segment with as single site.
* @param bool $autoArchive Whether to automatically archive data with the segment or not.
* @param bool $enabledAllUsers Whether the stored segment is viewable by all users or just the one that created it.
*
* @return bool
*/
public function update($idSegment, $name, $definition, $idSite = false, $autoArchive = false, $enabledAllUsers = false)
{
$this->checkUserIsNotAnonymous();
$segment = $this->getSegmentOrFail($idSegment);
$this->checkUserCanModifySegment($segment);
$idSite = $this->checkIdSite($idSite);
$this->checkSegmentName($name);
$definition = $this->checkSegmentValue($definition, $idSite);
$enabledAllUsers = $this->checkEnabledAllUsers($enabledAllUsers);
$autoArchive = $this->checkAutoArchive($autoArchive, $idSite);
if ($this->segmentVisibilityIsReduced($idSite, $enabledAllUsers, $segment)) {
$this->sendSegmentDeactivationEvent($idSegment);
}
$bind = array(
'name' => $name,
'definition' => $definition,
'enable_all_users' => $enabledAllUsers,
'enable_only_idsite' => $idSite,
'auto_archive' => $autoArchive,
'ts_last_edit' => Date::now()->getDatetime(),
);
$db = Db::get();
$db->update(Common::prefixTable("segment"),
$bind,
"idsegment = $idSegment"
);
return true;
}
/**
* Adds a new stored segment.
*
* @param string $name The new name of the segment.
* @param string $definition The new definition of the segment.
* @param bool $idSite If supplied, associates the stored segment with as single site.
* @param bool $autoArchive Whether to automatically archive data with the segment or not.
* @param bool $enabledAllUsers Whether the stored segment is viewable by all users or just the one that created it.
*
* @return int The newly created segment Id
*/
public function add($name, $definition, $idSite = false, $autoArchive = false, $enabledAllUsers = false)
{
$this->checkUserIsNotAnonymous();
$idSite = $this->checkIdSite($idSite);
$this->checkSegmentName($name);
$definition = $this->checkSegmentValue($definition, $idSite);
$enabledAllUsers = $this->checkEnabledAllUsers($enabledAllUsers);
$autoArchive = $this->checkAutoArchive($autoArchive, $idSite);
$db = Db::get();
$bind = array(
'name' => $name,
'definition' => $definition,
'login' => Piwik::getCurrentUserLogin(),
'enable_all_users' => $enabledAllUsers,
'enable_only_idsite' => $idSite,
'auto_archive' => $autoArchive,
'ts_created' => Date::now()->getDatetime(),
'deleted' => 0,
);
$db->insert(Common::prefixTable("segment"), $bind);
return $db->lastInsertId();
}
/**
* Returns a stored segment by ID
*
* @param $idSegment
* @throws Exception
* @return bool
*/
public function get($idSegment)
{
Piwik::checkUserHasSomeViewAccess();
if (!is_numeric($idSegment)) {
throw new Exception("idSegment should be numeric.");
}
$segment = Db::get()->fetchRow("SELECT * " .
" FROM " . Common::prefixTable("segment") .
" WHERE idsegment = ?", $idSegment);
if (empty($segment)) {
return false;
}
try {
if (!$segment['enable_all_users']) {
Piwik::checkUserHasSuperUserAccessOrIsTheUser($segment['login']);
}
} catch (Exception $e) {
throw new Exception($this->getMessageCannotEditSegmentCreatedBySuperUser());
}
if ($segment['deleted']) {
throw new Exception("This segment is marked as deleted. ");
}
return $segment;
}
/**
* Returns all stored segments.
*
* @param bool|int $idSite Whether to return stored segments for a specific idSite, or all of them. If supplied, must be a valid site ID.
* @return array
*/
public function getAll($idSite = false)
{
if (!empty($idSite)) {
Piwik::checkUserHasViewAccess($idSite);
} else {
Piwik::checkUserHasSomeViewAccess();
}
$userLogin = Piwik::getCurrentUserLogin();
$model = new Model();
if (empty($idSite)) {
$segments = $model->getAllSegments($userLogin);
} else {
$segments = $model->getAllSegmentsForSite($idSite, $userLogin);
}
return $segments;
}
/**
* When deleting or making a segment invisible, allow plugins to throw an exception or propagate the action
*
* @param $idSegment
*/
private function sendSegmentDeactivationEvent($idSegment)
{
/**
* Triggered before a segment is deleted or made invisible.
*
* This event can be used by plugins to throw an exception
* or do something else.
*
* @param int $idSegment The ID of the segment being deleted.
*/
Piwik::postEvent(self::DEACTIVATE_SEGMENT_EVENT, array($idSegment));
}
/**
* @param $idSiteNewValue
* @param $enableAllUserNewValue
* @param $segment
* @return bool
*/
private function segmentVisibilityIsReduced($idSiteNewValue, $enableAllUserNewValue, $segment)
{
$allUserVisibilityIsDropped = $segment['enable_all_users'] && !$enableAllUserNewValue;
$allWebsiteVisibilityIsDropped = !isset($segment['idSite']) && $idSiteNewValue;
return $allUserVisibilityIsDropped || $allWebsiteVisibilityIsDropped;
}
/**
* @return string
*/
private function getMessageCannotEditSegmentCreatedBySuperUser()
{
$message = "You can only edit and delete custom segments that you have created yourself. This segment was created and 'shared with you' by the Super User. " .
"To modify this segment, you can first create a new one by clicking on 'Add new segment'. Then you can customize the segment's definition.";
return $message;
}
}

View file

@ -0,0 +1,20 @@
<?php
/**
* Piwik - Open source web analytics
*
* @link http://piwik.org
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
*
*/
namespace Piwik\Plugins\SegmentEditor;
/**
*/
class Controller extends \Piwik\Plugin\Controller
{
public function getSelector()
{
$selector = new SegmentSelectorControl();
return $selector->render();
}
}

View file

@ -0,0 +1,89 @@
<?php
/**
* Piwik - Open source web analytics
*
* @link http://piwik.org
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
*
*/
namespace Piwik\Plugins\SegmentEditor;
use Exception;
use Piwik\Common;
use Piwik\Date;
use Piwik\Db;
use Piwik\Piwik;
use Piwik\Segment;
/**
* The SegmentEditor Model lets you persist and read custom Segments from the backend without handling any logic.
*/
class Model
{
/**
* Returns all stored segments.
*
* @param bool|int $idSite Whether to return stored segments for a specific idSite, or segments that are available
* for all sites. If supplied, must be a valid site ID.
* @return array
*/
public function getSegmentsToAutoArchive($idSite = false)
{
$bind = array();
$whereIdSite = '';
if (!empty($idSite)) {
$whereIdSite = 'enable_only_idsite = ? OR ';
$bind[] = $idSite;
}
$sql = $this->buildQuerySortedByName("($whereIdSite enable_only_idsite = 0)
AND deleted = 0 AND auto_archive = 1");
$segments = Db::get()->fetchAll($sql, $bind);
return $segments;
}
/**
* Returns all stored segments that are available to the given login.
*
* @param string $userLogin
* @return array
*/
public function getAllSegments($userLogin)
{
$bind = array($userLogin);
$sql = $this->buildQuerySortedByName('deleted = 0 AND (enable_all_users = 1 OR login = ?)');
$segments = Db::get()->fetchAll($sql, $bind);
return $segments;
}
/**
* Returns all stored segments that are available for the given site and login.
*
* @param string $userLogin
* @param int $idSite Whether to return stored segments for a specific idSite, or all of them. If supplied, must be a valid site ID.
* @return array
*/
public function getAllSegmentsForSite($idSite, $userLogin)
{
$bind = array($idSite, $userLogin);
$sql = $this->buildQuerySortedByName('(enable_only_idsite = ? OR enable_only_idsite = 0)
AND deleted = 0
AND (enable_all_users = 1 OR login = ?)');
$segments = Db::get()->fetchAll($sql, $bind);
return $segments;
}
private function buildQuerySortedByName($where)
{
$sql = "SELECT * FROM " . Common::prefixTable("segment") .
" WHERE $where ORDER BY name ASC";
return $sql;
}
}

View file

@ -0,0 +1,104 @@
<?php
/**
* Piwik - Open source web analytics
*
* @link http://piwik.org
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
*
*/
namespace Piwik\Plugins\SegmentEditor;
use Exception;
use Piwik\Common;
use Piwik\Db;
use Piwik\DbHelper;
use Piwik\Piwik;
use Piwik\Version;
/**
*/
class SegmentEditor extends \Piwik\Plugin
{
/**
* @see Piwik\Plugin::getInformation
*/
public function getInformation()
{
return array(
'description' => 'Create and reuse custom visitor Segments with the Segment Editor.',
'authors' => array(array('name' => 'Piwik', 'homepage' => 'http://piwik.org/')),
'version' => Version::VERSION,
'license' => 'GPL v3+',
'license_homepage' => 'http://www.gnu.org/licenses/gpl.html'
);
}
/**
* @see Piwik\Plugin::getListHooksRegistered
*/
public function getListHooksRegistered()
{
return array(
'Segments.getKnownSegmentsToArchiveForSite' => 'getKnownSegmentsToArchiveForSite',
'Segments.getKnownSegmentsToArchiveAllSites' => 'getKnownSegmentsToArchiveAllSites',
'AssetManager.getJavaScriptFiles' => 'getJsFiles',
'AssetManager.getStylesheetFiles' => 'getStylesheetFiles',
'Template.nextToCalendar' => 'getSegmentEditorHtml',
);
}
function getSegmentEditorHtml(&$out)
{
$controller = new Controller();
$out .= $controller->getSelector();
}
public function getKnownSegmentsToArchiveAllSites(&$segments)
{
$this->getKnownSegmentsToArchiveForSite($segments, $idSite = false);
}
/**
* Adds the pre-processed segments to the list of Segments.
* Used by CronArchive, ArchiveProcessor\Rules, etc.
*
* @param $segments
* @param $idSite
*/
public function getKnownSegmentsToArchiveForSite(&$segments, $idSite)
{
$model = new Model();
$segmentToAutoArchive = $model->getSegmentsToAutoArchive($idSite);
foreach ($segmentToAutoArchive as $segmentInfo) {
$segments[] = $segmentInfo['definition'];
}
$segments = array_unique($segments);
}
public function install()
{
$segmentTable = "`idsegment` INT(11) NOT NULL AUTO_INCREMENT,
`name` VARCHAR(255) NOT NULL,
`definition` TEXT NOT NULL,
`login` VARCHAR(100) NOT NULL,
`enable_all_users` tinyint(4) NOT NULL default 0,
`enable_only_idsite` INTEGER(11) NULL,
`auto_archive` tinyint(4) NOT NULL default 0,
`ts_created` TIMESTAMP NULL,
`ts_last_edit` TIMESTAMP NULL,
`deleted` tinyint(4) NOT NULL default 0,
PRIMARY KEY (`idsegment`)";
DbHelper::createTable('segment', $segmentTable);
}
public function getJsFiles(&$jsFiles)
{
$jsFiles[] = "plugins/SegmentEditor/javascripts/Segmentation.js";
}
public function getStylesheetFiles(&$stylesheets)
{
$stylesheets[] = "plugins/SegmentEditor/stylesheets/segmentation.less";
}
}

View file

@ -0,0 +1,130 @@
<?php
/**
* Piwik - Open source web analytics
*
* @link http://piwik.org
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
*
*/
namespace Piwik\Plugins\SegmentEditor;
use Piwik\Common;
use Piwik\Config;
use Piwik\Piwik;
use Piwik\Plugins\API\API as APIMetadata;
use Piwik\View\UIControl;
/**
* Generates the HTML for the segment selector control (which includes the segment editor).
*/
class SegmentSelectorControl extends UIControl
{
const TEMPLATE = "@SegmentEditor/_segmentSelector";
/**
* Constructor.
*/
public function __construct($idSite = false)
{
parent::__construct();
$this->jsClass = "SegmentSelectorControl";
$this->cssIdentifier = "segmentEditorPanel";
$this->cssClass = "piwikTopControl";
$this->idSite = $idSite ?: Common::getRequestVar('idSite', false, 'int');
$this->selectedSegment = Common::getRequestVar('segment', false, 'string');
$segments = APIMetadata::getInstance()->getSegmentsMetadata($this->idSite);
$segmentsByCategory = $customVariablesSegments = array();
foreach ($segments as $segment) {
if ($segment['category'] == Piwik::translate('General_Visit')
&& ($segment['type'] == 'metric' && $segment['segment'] != 'visitIp')
) {
$metricsLabel = Piwik::translate('General_Metrics');
$metricsLabel[0] = strtolower($metricsLabel[0]);
$segment['category'] .= ' (' . $metricsLabel . ')';
}
$segmentsByCategory[$segment['category']][] = $segment;
}
uksort($segmentsByCategory, array($this, 'sortSegmentCategories'));
$this->createRealTimeSegmentsIsEnabled = Config::getInstance()->General['enable_create_realtime_segments'];
$this->segmentsByCategory = $segmentsByCategory;
$this->nameOfCurrentSegment = '';
$this->isSegmentNotAppliedBecauseBrowserArchivingIsDisabled = 0;
$this->availableSegments = API::getInstance()->getAll($this->idSite);
foreach ($this->availableSegments as &$savedSegment) {
$savedSegment['name'] = Common::sanitizeInputValue($savedSegment['name']);
if (!empty($this->selectedSegment) && $this->selectedSegment == $savedSegment['definition']) {
$this->nameOfCurrentSegment = $savedSegment['name'];
$this->isSegmentNotAppliedBecauseBrowserArchivingIsDisabled =
$this->wouldApplySegment($savedSegment) ? 0 : 1;
}
}
$this->authorizedToCreateSegments = !Piwik::isUserIsAnonymous();
$this->segmentTranslations = $this->getTranslations();
}
public function getClientSideProperties()
{
return array('availableSegments',
'segmentTranslations',
'isSegmentNotAppliedBecauseBrowserArchivingIsDisabled',
'selectedSegment');
}
private function wouldApplySegment($savedSegment)
{
$isBrowserArchivingDisabled = Config::getInstance()->General['browser_archiving_disabled_enforce'];
if (!$isBrowserArchivingDisabled) {
return true;
}
return (bool) $savedSegment['auto_archive'];
}
public function sortSegmentCategories($a, $b)
{
// Custom Variables last
if ($a == Piwik::translate('CustomVariables_CustomVariables')) {
return 1;
}
return 0;
}
private function getTranslations()
{
$translationKeys = array(
'General_OperationEquals',
'General_OperationNotEquals',
'General_OperationAtMost',
'General_OperationAtLeast',
'General_OperationLessThan',
'General_OperationGreaterThan',
'General_OperationContains',
'General_OperationDoesNotContain',
'General_OperationIs',
'General_OperationIsNot',
'General_OperationContains',
'General_OperationDoesNotContain',
'SegmentEditor_DefaultAllVisits',
'General_DefaultAppended',
'SegmentEditor_AddNewSegment',
'General_Edit',
'General_Search',
'General_SearchNoResults',
);
$translations = array();
foreach ($translationKeys as $key) {
$translations[$key] = Piwik::translate($key);
}
return $translations;
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 847 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 968 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 288 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 928 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 378 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1,021 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,705 @@
/* ADDITIONAL STYLES*/
.youMustBeLoggedIn {
font-size: 8pt;
font-style: italic;
}
.segment-footer .segmentFooterNote {
display: none;
float: left;
padding-top: 9px;
}
.segment-footer .segmentFooterNote, .segment-element .segment-footer .segmentFooterNote a {
font-size: 8pt;
color: #888172;
}
.segment-element .segment-footer .segmentFooterNote a {
padding: 0;
margin: 0;
text-decoration: underline;
}
.searchFound {
border: 0px solid red;
}
.others {
border: 0px solid green;
}
.clear {
clear: both;
}
.segment-row-inputs {
margin-bottom: 5px;
}
.hovered {
border-radius: 4px;
border: 2px dashed #000 !important;
padding: 0px;
}
.metricListBlock {
border-radius: 4px;
width: 292px;
margin-right: 11px;
border: 2px dashed #EFEFEB;
}
.metricListBlock > select {
margin: 0 !important;
width: 98% !important;
margin-left: 2px !important;
}
.metricMatchBlock {
width: 120px;
margin-right: 11px;
}
.metricValueBlock {
width: 352px;
}
div.scrollable {
height: 100%;
overflow: hidden;
overflow-y: auto;
}
.no_results {
position: absolute;
margin: -225px 0 0 10px;
}
.segment-element {
border: 1px solid #a9a399;
background-color: #f1f0eb;
padding: 6px 4px;
border-radius: 3px;
position: absolute;
left: -1px;
top: -1px;
}
.segment-element .custom_select_search {
width: 146px;
height: 21px;
background: url(plugins/SegmentEditor/images/bg-segment-search.png) 0 10px no-repeat;
padding: 10px 0 0 0;
margin: 10px 0 10px 15px;
border-top: 1px solid #dcdacf;
position: relative;
}
.segment-element .custom_select_search input[type="text"] {
font: 11px Arial;
color: #454545;
width: 125px;
padding: 4px 0 3px 7px;
border: none;
background: none;
}
.segment-element .custom_select_search a {
position: absolute;
width: 13px;
height: 13px;
right: 5px;
top: 14px;
background: url(plugins/SegmentEditor/images/reset_search.png);
}
.segment-element .segment-nav {
position: absolute;
top: 7px;
left: 5px;
bottom: 135px;
float: left;
width: 170px;
}
.segment-element .segment-nav h4 {
font: bold 14px Arial;
padding: 0 0 8px 0;
}
.segment-element .segment-nav h4.visits {
padding-left: 28px;
background: url(plugins/SegmentEditor/images/icon-users.png) 0 0 no-repeat;
}
.segment-element .segment-nav h4 a {
color: #255792;
text-decoration: none;
}
.segment-element .segment-nav div > ul {
padding: 0 0 0 15px;
}
.segment-element .segment-nav div > ul > li {
padding: 2px 0;
line-height: 14px;
}
.segment-element .segment-nav div > ul > li li {
padding: 1px;
border-radius: 3px 3px 3px 3px;
}
.segment-element .segment-nav div > ul > li li:hover {
padding: 0;
border: 1px solid #cfccbd;
border-bottom: 1px solid #7c7a72;
}
.segment-element .segment-nav div > ul > li li:hover a {
cursor: move;
padding: 1px 0 2px 8px;
border-top: 1px solid #fff;
background: #eae8e3 url(plugins/SegmentEditor/images/segment-move.png) 100% 50% no-repeat;
}
.segment-element .segment-nav div > ul > li li a {
padding: 2px 0 2px 8px;
font-weight: normal;
display: block;
}
.segment-element .segment-nav div > ul > li ul {
margin: 2px 0 -3px 10px;
}
.segment-element .segment-nav div > ul > li a {
color: #5d5342;
font: bold 11px Arial;
text-decoration: none;
text-shadow: 0 1px 0 #fff;
}
.segment-element .segment-content {
min-height: 300px;
padding: 0 0 20px 203px;
}
.segment-element .segment-content h3 {
font: bold 16px Arial;
color: #505050;
margin: 11px 0 0 0;
text-shadow: 0 1px 0 #fff;
}
.segment-element .segment-content h3 a {
font-size: 11px;
text-decoration: none;
margin: -1px 0 0 0;
}
.segment-element .segment-content .segment-rows {
padding: 4px;
margin: 0 3px 0 0;
background: #fff;
border: 1px solid #a9a399;
border-radius: 3px 3px 3px 3px;
position: relative;
box-shadow: 0 12px 6px -10px rgba(0, 0, 0, 0.42);
}
.segment-element .segment-content .segment-add-row,
.segment-element .segment-content .segment-add-or {
font: bold 14px Arial;
background: #fff;
color: #b9b9b9;
text-align: center;
position: relative;
}
.segment-element .segment-content .segment-add-row > div,
.segment-element .segment-content .segment-add-or > div {
border-radius: 4px;
border: 2px dashed #fff;
padding: 10px 0;
}
.segment-element .segment-content .segment-add-row > div a,
.segment-element .segment-content .segment-add-or > div a {
color: #b9b9b9;
text-decoration: none;
}
.segment-element .segment-content .segment-add-row > div a span,
.segment-element .segment-content .segment-add-or > div a span {
color: #255792;
}
.segment-element .segment-content .segment-add-row {
margin: 0 3px 0 0;
padding: 0 12px;
border: 1px solid #a9a399;
border-radius: 3px 3px 3px 3px;
box-shadow: 0 12px 6px -10px rgba(0, 0, 0, 0.42);
}
.segment-element .segment-content .segment-add-or {
text-shadow: 0 1px 0 #fff;
display: inline-block;
width: 98%;
padding: 0 1%;
background: #efefeb;
border-radius: 3px 3px 3px 3px;
}
.segment-element .segment-content .segment-add-or > div {
border: 2px dashed #EFEFEB;
}
.segment-element .segment-content .segment-row {
border-radius: 3px;
display: inline-block;
position: relative;
width: 811px;
padding: 12px 1%;
background: #efefeb;
padding: 7px 5px 0 5px;
}
.segment-element .segment-content .segment-row .segment-close {
top: 15px;
right: 6px;
position: absolute;
width: 15px;
height: 15px;
background: url(plugins/SegmentEditor/images/segment-close.png) 0 0 no-repeat;
}
.segment-element .segment-content .segment-row .segment-loading {
display: none;
top: 25px;
right: 30px;
position: absolute;
width: 15px;
height: 15px;
background: url(plugins/MultiSites/images/loading-blue.gif) 0 0 no-repeat;
}
.segment-element .segment-content .segment-or {
display: inline-block;
margin: 0 0 0 6%;
position: relative;
background: #efefeb;
padding: 5px 28px;
color: #4f4f4f;
font: bold 14px Arial;
text-shadow: 0 1px 0 #fff;
}
.segment-element .segment-content .segment-or:before,
.segment-element .segment-content .segment-or:after {
content: '';
position: absolute;
background: #fff;
border: 1px solid #efefeb;
width: 10px;
top: -1px;
bottom: -1px;
}
.segment-element .segment-content .segment-or:before {
border-left: none;
left: 0px;
border-radius: 0 5px 5px 0;
}
.segment-element .segment-content .segment-or:after {
border-right: none;
right: 0px;
border-radius: 5px 0 0 5px;
}
.segment-element .segment-content .segment-and {
display: inline-block;
margin: -1px 0 -1px 6%;
z-index: 1;
position: relative;
background: #fff;
padding: 5px 35px;
color: #4f4f4f;
font: bold 14px Arial;
text-shadow: 0 1px 0 #fff;
}
.segment-element .segment-content .segment-and:before,
.segment-element .segment-content .segment-and:after {
content: '';
position: absolute;
background: url(plugins/SegmentEditor/images/bg-inverted-corners.png);
border: 1px solid #a9a399;
width: 10px;
top: 0px;
bottom: 0px;
}
.segment-element .segment-content .segment-and:before {
border-left: none;
left: 0px;
border-radius: 0 5px 5px 0;
}
.segment-element .segment-content .segment-and:after {
border-right: none;
right: 0px;
border-radius: 5px 0 0 5px;
}
.segment-element .segment-content .segment-input {
float: left;
padding: 6px 0 5px 3px;
border: 2px dashed #EFEFEB;
margin-right: 3px;
}
.segment-element .segment-content .segment-input label {
display: block;
margin: 0 0 5px 0;
font: 11px Arial;
color: #505050;
}
.segment-element .segment-content .segment-input select,
.segment-element .segment-content .segment-input input {
display: block;
font: 16px Arial;
color: #255792;
width: 96%;
padding: 7px 2%;
border-radius: 2px 2px 2px 2px;
}
.segment-element .segment-content .segment-input input {
padding: 8px 2%;
}
.segment-element .segment-top {
font: 11px Arial;
color: #505050;
text-align: right;
padding: 3px 7px 0 0;
}
.segment-element .segment-top a {
text-decoration: none;
}
.segment-element .segment-top a.dropdown {
padding: 0 17px 0 0;
background: url(plugins/Zeitgeist/images/sort_subtable_desc.png) 100% -2px no-repeat;
}
.segment-element .segment-footer {
background: #eae8e3;
border-top: 1px solid #a9a399;
text-align: right;
padding: 7px 10px;
margin: 0 -4px -6px -4px;
}
.segment-element .segment-footer a.delete {
color: red;
}
.segment-element .segment-footer a {
font: 14px Arial;
color: #255792;
margin: 0 5px;
text-decoration: none;
}
.segment-element .segment-footer button {
min-width: 178px;
height: 30px;
background-image: url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiA/Pgo8c3ZnIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgdmlld0JveD0iMCAwIDE3OCAzMCIgcHJlc2VydmVBc3BlY3RSYXRpbz0ibm9uZSI+PGxpbmVhckdyYWRpZW50IGlkPSJoYXQwIiBncmFkaWVudFVuaXRzPSJvYmplY3RCb3VuZGluZ0JveCIgeDE9IjUwJSIgeTE9IjEwMCUiIHgyPSI1MCUiIHkyPSItMS40MjEwODU0NzE1MjAyZS0xNCUiPgo8c3RvcCBvZmZzZXQ9IjAlIiBzdG9wLWNvbG9yPSIjODM3OTZiIiBzdG9wLW9wYWNpdHk9IjEiLz4KPHN0b3Agb2Zmc2V0PSIxMDAlIiBzdG9wLWNvbG9yPSIjYWJhMzkzIiBzdG9wLW9wYWNpdHk9IjEiLz4KICAgPC9saW5lYXJHcmFkaWVudD4KCjxyZWN0IHg9IjAiIHk9IjAiIHdpZHRoPSIxNzgiIGhlaWdodD0iMzAiIGZpbGw9InVybCgjaGF0MCkiIC8+Cjwvc3ZnPg==);
background-image: -moz-linear-gradient(bottom, #83796b 0%, #aba393 100%);
background-image: -o-linear-gradient(bottom, #83796b 0%, #aba393 100%);
background-image: -webkit-linear-gradient(bottom, #83796b 0%, #aba393 100%);
background-image: linear-gradient(bottom, #83796b 0%, #aba393 100%);
color: #fff;
font-family: "Arial";
font-size: 16px;
font-weight: bold;
border-radius: 4px 4px 4px 4px;
border: none;
margin: 0 0 0 15px;
}
.segmentEditorPanel {
display:inline-block;
position:relative;
z-index: 121; /* Should be bigger than 'Dashboard widget selector' (z-index: 120) */
background: #f7f7f7;
border: 1px solid #e4e5e4;
padding: 5px 10px 6px 10px;
margin-right: 10px;
border-radius: 4px;
color: #444;
font-size: 14px;
}
.top_controls .segmentEditorPanel {
position:absolute;
}
.segmentEditorPanel:hover {
background: #f1f0eb;
border-color: #a9a399;
}
.segmentationContainer > span > strong {
color: #255792;
}
.segmentationContainer .submenu {
font-size: 13px;
min-width: 200px;
}
.segmentationContainer .submenu ul {
color: #5D5342;
float: none;
font-size: 11px;
font-weight: normal;
line-height: 20px;
list-style: none outside none;
margin-left: 5px;
margin-right: 0;
padding-top: 10px;
}
.segmentationContainer .submenu ul li {
padding: 2px 0px 1px 6px;
margin: 3px 0 0 0;
cursor: pointer;
}
.segmentationContainer .submenu ul li:hover {
color: #255792;
margin: 0;
margin-left: -3px;
border: 1px solid #d5d2c6;
border-bottom: 2px solid #918f88;
border-radius: 4px;
background: #eae8e3;
}
.segmentationContainer ul.submenu {
padding-top: 5px;
display: none;
float: left;
}
.segmentationContainer ul.submenu > li span.editSegment {
display: block;
float: right;
text-align: center;
margin-right:4px;
font-weight: normal;
}
.segmentEditorPanel.visible .segmentationContainer {
width: 200px;
border-bottom-left-radius: 0;
border-bottom-right-radius: 0;
}
.segmentEditorPanel.visible ul.submenu {
display: block;
list-style: none;
}
.segmentEditorPanel.visible .add_new_segment {
display: block;
background: url("plugins/SegmentEditor/images/dashboard_h_bg_hover.png") repeat-x scroll 0 0 #847b6d;
border: 0 none;
border-radius: 4px 4px 4px 4px;
clear: both;
color: #FFFFFF;
float: right;
margin: 12px 0 10px;
padding: 3px 10px;
text-decoration: none;
width: 130px;
}
.segmentationContainer > ul.submenu > li {
padding: 5px 0;
clear: both;
cursor: pointer;
}
span.segmentationTitle {
background: url(plugins/Zeitgeist/images/sort_subtable_desc.png) no-repeat right 0;
padding-right: 20px;
width: 160px;
display: block;
cursor: pointer;
}
.add_new_segment {
display: none;
}
.segmentListContainer {
overflow: hidden; /* Create a BFC */
}
.jspVerticalBar {
background: transparent !important;
}
/* ADDITIONAL STYLES*/
body > a.ddmetric {
display: block;
cursor: move;
padding: 1px 0 2px 18px;
background: #eae8e3 url(plugins/SegmentEditor/images/segment-move.png) 100% 50% no-repeat;
color: #5d5342;
font: normal 11px Arial;
text-decoration: none;
text-shadow: 0 1px 0 #fff;
border: 1px solid #cfccbd;
border-top: 1px solid #fff;
border-bottom: 1px solid #7c7a72;
}
.segment-element .segment-nav div > ul > li ul {
margin-left: 0;
}
.segment-element .segment-nav div > ul > li li a,
.segment-element .segment-nav div > ul > li li a:hover {
padding-right: 18px;
}
.hovered {
border-color: #a0a0a0 !important;
}
a.metric_category {
display: block;
width: 100%;
}
.segment-content > h3 {
padding-bottom: 7px;
}
.no_results {
margin: 0;
position: relative;
}
.no_results a {
cursor: default;
}
.ui-widget-segmentation {
border: 1px solid #D4D4D4 !important;
}
.clearfix {
zoom: 1;
}
.clearfix:after {
display: block;
visibility: hidden;
height: 0;
clear: both;
content: ".";
}
.available_segments a.dropdown {
background: url("plugins/Zeitgeist/images/sort_subtable_desc.png") no-repeat scroll 100% -2px transparent !important;
padding: 0 17px 0 0 !important;
}
.notification {
float: left;
}
.metricValueBlock input {
padding: 8px !important;
}
.segmentationContainer {
z-index: 120;
}
.segment-element {
z-index: 999;
width: 1040px;
}
.segmentationSelectorContainer {
margin: 8px;
}
.segmentSelected, .segmentSelected:hover {
font-weight: bold;
}
.ui-autocomplete {
position: absolute;
cursor: default;
z-index: 1000 !important;
}
@media all and (max-width: 749px) {
span.segmentationTitle,
.segmentEditorPanel.visible .segmentationContainer {
width: auto;
}
.segmentEditorPanel.visible .add_new_segment {
float: left;
}
}
.dropdown-body {
position:absolute;
top:100%;
left:-1px;
background-color:#f7f7f7;
padding:0px 10px;
border: 1px solid #e4e5e4;
border-top-width:0px;
display:none;
border-bottom-left-radius: 4px;
border-bottom-right-radius: 4px;
}
.segmentEditorPanel.visible .dropdown-body {
display:block;
border-top-left-radius: 0;
border-top-right-radius: 0;
}
.segmentEditorPanel:hover .dropdown-body {
border-color: #a9a399;
background: #f1f0eb
}
.segmentEditorPanel.visible {
border-bottom-left-radius: 0;
border-bottom-right-radius: 0;
}
.segment-element.anchorRight {
right:-1px;
left:auto;
}

View file

@ -0,0 +1,161 @@
<div class="SegmentEditor" style="display:none;">
<div class="segmentationContainer listHtml">
<span class="segmentationTitle"></span>
<div class="dropdown-body">
<ul class="submenu">
<li>{{ 'SegmentEditor_SelectSegmentOfVisitors'|translate }}
<div class="segmentList">
<ul>
</ul>
</div>
</li>
</ul>
{% if authorizedToCreateSegments %}
<a class="add_new_segment">{{ 'SegmentEditor_AddNewSegment'|translate }}</a>
{% else %}
<ul class="submenu">
<li> <span class='youMustBeLoggedIn'>{{ 'SegmentEditor_YouMustBeLoggedInToCreateSegments'|translate }}
<br/>&rsaquo; <a href='index.php?module={{ loginModule }}'>{{ 'Login_LogIn'|translate }}</a> </span>
</li>
</ul>
{% endif %}
</div>
</div>
<div class="initial-state-rows">{# no space here important for jquery #}<div class="segment-add-row initial"><div>
<span>+ {{ 'SegmentEditor_DragDropCondition'|translate|raw }}</span>
</div></div>
<div class="segment-and">{{ 'SegmentEditor_OperatorAND'|translate|raw }}</div>
<div class="segment-add-row initial"><div>
<span>+ {{ 'SegmentEditor_DragDropCondition'|translate|raw }}</span>
</div></div>
</div>
<div class="segment-row-inputs">
<div class="segment-input metricListBlock">
<select title="{{ 'SegmentEditor_ChooseASegment'|translate }}" class="metricList">
{% for category,segmentsInCategory in segmentsByCategory %}
<optgroup label="{{ category }}">
{% for segmentInCategory in segmentsInCategory %}
<option data-type="{{ segmentInCategory.type }}" value="{{ segmentInCategory.segment }}">{{ segmentInCategory.name }}</option>
{% endfor %}
</optgroup>
{% endfor %}
</select>
</div>
<div class="segment-input metricMatchBlock">
<select title="{{ 'General_Matches'|translate }}">
<option value="==">{{ 'General_OperationEquals'|translate }}</option>
<option value="!=">{{ 'General_OperationNotEquals'|translate }}</option>
<option value="<=">{{ 'General_OperationAtMost'|translate }}</option>
<option value=">=">{{ 'General_OperationAtLeast'|translate }}</option>
<option value="<">{{ 'General_OperationLessThan'|translate }}</option>
<option value=">">{{ 'General_OperationGreaterThan'|translate }}</option>
<option value="=@">{{ 'General_OperationContains'|translate }}</option>
<option value="!@">{{ 'General_OperationDoesNotContain'|translate }}</option>
</select>
</div>
<div class="segment-input metricValueBlock">
<input type="text" title="{{ 'General_Value'|translate }}">
</div>
<div class="clear"></div>
</div>
<div class="segment-rows">
<div class="segment-row">
<a href="#" class="segment-close"></a>
<a href="#" class="segment-loading"></a>
</div>
</div>
<div class="segment-or">{{ 'SegmentEditor_OperatorOR'|translate }}</div>
<div class="segment-add-or"><div>
{% set orCondition %}<span>{{ 'SegmentEditor_OperatorOR'|translate }}</span>{% endset %}
<a href="#"> + {{ 'SegmentEditor_AddANDorORCondition'|translate(orCondition)|raw }} </a>
</div>
</div>
<div class="segment-and">{{ 'SegmentEditor_OperatorAND'|translate }}</div>
<div class="segment-add-row"><div>
{% set andCondition %}<span>{{ 'SegmentEditor_OperatorAND'|translate }}</span>{% endset %}
<a href="#">+ {{ 'SegmentEditor_AddANDorORCondition'|translate(andCondition)|raw }}</a>
</div>
</div>
<div class="segment-element">
<div class="segment-nav">
<h4 class="visits"><span class="available_segments"><strong>
<select class="available_segments_select"></select>
</strong></span></h4>
<div class="scrollable">
<ul>
{% for category,segmentsInCategory in segmentsByCategory %}
<li data="visit">
<a class="metric_category" href="#">{{ category }}</a>
<ul style="display:none;">
{% for segmentInCategory in segmentsInCategory %}
<li data-metric="{{ segmentInCategory.segment }}"><a class="ddmetric" href="#">{{ segmentInCategory.name }}</a></li>
{% endfor %}
</ul>
</li>
{% endfor %}
</ul>
</div>
<div class="custom_select_search">
<a href="#"></a>
<input type="text" aria-haspopup="true" aria-autocomplete="list" role="textbox" autocomplete="off" class="inp ui-autocomplete-input segmentSearch" value="{{ 'General_Search'|translate }}" length="15">
</div>
</div>
<div class="segment-content">
<div class="segment-top" {% if not isSuperUser %}style="display:none"{% endif %}>
{{ 'SegmentEditor_ThisSegmentIsVisibleTo'|translate }} <span class="enable_all_users"><strong>
<select class="enable_all_users_select">
<option selected="1" value="0">{{ 'SegmentEditor_VisibleToMe'|translate }}</option>
<option value="1">{{ 'SegmentEditor_VisibleToAllUsers'|translate }}</option>
</select>
</strong></span>
{{ 'SegmentEditor_SegmentIsDisplayedForWebsite'|translate }}<span class="visible_to_website"><strong>
<select class="visible_to_website_select">
<option selected="" value="{{ idSite }}">{{ 'SegmentEditor_SegmentDisplayedThisWebsiteOnly'|translate }}</option>
<option value="0">{{ 'SegmentEditor_SegmentDisplayedAllWebsites'|translate }}</option>
</select>
</strong></span>
{{ 'General_And'|translate }} <span class="auto_archive"><strong>
<select class="auto_archive_select">
{% if createRealTimeSegmentsIsEnabled %}
<option selected="1" value="0">{{ 'SegmentEditor_AutoArchiveRealTime'|translate }} {{ 'General_DefaultAppended'|translate }}</option>
{% endif %}
<option {% if not createRealTimeSegmentsIsEnabled %}selected="1"{% endif %} value="1">{{ 'SegmentEditor_AutoArchivePreProcessed'|translate }} </option>
</select>
</strong></span>
</div>
<h3>{{ 'General_Name'|translate }}: <span class="segmentName"></span> <a class="editSegmentName" href="#">{{ 'General_Edit'|translate|lower }}</a></h3>
</div>
<div class="segment-footer">
<div piwik-rate-feature title="Segment Editor" style="display:inline-block;float: left;margin-top: 2px;margin-right: 10px;"></div>
<span class="segmentFooterNote">The Segment Editor was <a class='crowdfundingLink' href='http://crowdfunding.piwik.org/custom-segments-editor/' target='_blank'>crowdfunded</a> with the awesome support of 80 companies and Piwik users worldwide!</span>
<a class="delete" href="#">{{ 'General_Delete'|translate }}</a>
<a class="close" href="#">{{ 'General_Close'|translate }}</a>
<button class="saveAndApply">{{ 'SegmentEditor_SaveAndApply'|translate }}</button>
</div>
</div>
</div>
<div class="segmentListContainer">
<div class="ui-confirm segment-delete-confirm">
<h2>{{ 'SegmentEditor_AreYouSureDeleteSegment'|translate }}</h2>
<input role="yes" type="button" value="{{ 'General_Yes'|translate }}"/>
<input role="no" type="button" value="{{ 'General_No'|translate }}"/>
</div>
<div class="ui-confirm pleaseChangeBrowserAchivingDisabledSetting">
<h2>{{ 'SegmentEditor_SegmentNotApplied'|translate(nameOfCurrentSegment)|raw }}</h2>
{% set segmentSetting %}{{ 'SegmentEditor_AutoArchivePreProcessed'|translate }}{% endset %}
<input role="yes" type="button" value="{{ 'General_Ok'|translate }}"/>
<p class="description">
{{ 'SegmentEditor_SegmentNotAppliedMessage'|translate(nameOfCurrentSegment)|raw }}
<br/>
{{ 'SegmentEditor_DataAvailableAtLaterDate'|translate }}
{% if isSuperUser %}
<br/> <br/> {{ 'SegmentEditor_YouMayChangeSetting'|translate('browser_archiving_disabled_enforce', segmentSetting) }}
{% endif %}
</p>
</div>
</div>