Merge remote-tracking branch 'upstream/develop' into no-term2
This commit is contained in:
commit
59675c4f0b
52 changed files with 5302 additions and 240 deletions
|
@ -50,7 +50,6 @@
|
||||||
"bower-asset/base64": "^1.0",
|
"bower-asset/base64": "^1.0",
|
||||||
"bower-asset/chart-js": "^2.8",
|
"bower-asset/chart-js": "^2.8",
|
||||||
"bower-asset/dompurify": "^1.0",
|
"bower-asset/dompurify": "^1.0",
|
||||||
"bower-asset/perfect-scrollbar": "^0.6",
|
|
||||||
"bower-asset/vue": "^2.6",
|
"bower-asset/vue": "^2.6",
|
||||||
"npm-asset/es-jquery-sortable": "^0.9.13",
|
"npm-asset/es-jquery-sortable": "^0.9.13",
|
||||||
"npm-asset/jquery": "^2.0",
|
"npm-asset/jquery": "^2.0",
|
||||||
|
|
31
composer.lock
generated
31
composer.lock
generated
|
@ -237,37 +237,6 @@
|
||||||
],
|
],
|
||||||
"time": "2019-02-28T15:21:34+00:00"
|
"time": "2019-02-28T15:21:34+00:00"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "bower-asset/perfect-scrollbar",
|
|
||||||
"version": "0.6.16",
|
|
||||||
"source": {
|
|
||||||
"type": "git",
|
|
||||||
"url": "https://github.com/utatti/perfect-scrollbar-bower.git",
|
|
||||||
"reference": "3049129e5dbb403295ce8507a461cdd0f200938c"
|
|
||||||
},
|
|
||||||
"dist": {
|
|
||||||
"type": "zip",
|
|
||||||
"url": "https://api.github.com/repos/utatti/perfect-scrollbar-bower/zipball/3049129e5dbb403295ce8507a461cdd0f200938c",
|
|
||||||
"reference": "3049129e5dbb403295ce8507a461cdd0f200938c",
|
|
||||||
"shasum": ""
|
|
||||||
},
|
|
||||||
"type": "bower-asset-library",
|
|
||||||
"extra": {
|
|
||||||
"bower-asset-main": [
|
|
||||||
"css/perfect-scrollbar.css",
|
|
||||||
"js/perfect-scrollbar.js"
|
|
||||||
],
|
|
||||||
"bower-asset-ignore": [
|
|
||||||
"**/.*",
|
|
||||||
"bower_components"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"license": [
|
|
||||||
"MIT"
|
|
||||||
],
|
|
||||||
"description": "Minimalistic but perfect custom scrollbar plugin",
|
|
||||||
"time": "2017-01-10T01:04:09+00:00"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "bower-asset/vue",
|
"name": "bower-asset/vue",
|
||||||
"version": "v2.6.10",
|
"version": "v2.6.10",
|
||||||
|
|
52
database.sql
52
database.sql
|
@ -715,24 +715,6 @@ CREATE TABLE IF NOT EXISTS `item-content` (
|
||||||
INDEX `uri-id` (`uri-id`)
|
INDEX `uri-id` (`uri-id`)
|
||||||
) DEFAULT COLLATE utf8mb4_general_ci COMMENT='Content for all posts';
|
) DEFAULT COLLATE utf8mb4_general_ci COMMENT='Content for all posts';
|
||||||
|
|
||||||
--
|
|
||||||
-- TABLE item-delivery-data
|
|
||||||
--
|
|
||||||
CREATE TABLE IF NOT EXISTS `item-delivery-data` (
|
|
||||||
`iid` int unsigned NOT NULL COMMENT 'Item id',
|
|
||||||
`postopts` text COMMENT 'External post connectors add their network name to this comma-separated string to identify that they should be delivered to these networks during delivery',
|
|
||||||
`inform` mediumtext COMMENT 'Additional receivers of the linked item',
|
|
||||||
`queue_count` mediumint NOT NULL DEFAULT 0 COMMENT 'Initial number of delivery recipients, used as item.delivery_queue_count',
|
|
||||||
`queue_done` mediumint NOT NULL DEFAULT 0 COMMENT 'Number of successful deliveries, used as item.delivery_queue_done',
|
|
||||||
`queue_failed` mediumint NOT NULL DEFAULT 0 COMMENT 'Number of unsuccessful deliveries, used as item.delivery_queue_failed',
|
|
||||||
`activitypub` mediumint NOT NULL DEFAULT 0 COMMENT 'Number of successful deliveries via ActivityPub',
|
|
||||||
`dfrn` mediumint NOT NULL DEFAULT 0 COMMENT 'Number of successful deliveries via DFRN',
|
|
||||||
`legacy_dfrn` mediumint NOT NULL DEFAULT 0 COMMENT 'Number of successful deliveries via legacy DFRN',
|
|
||||||
`diaspora` mediumint NOT NULL DEFAULT 0 COMMENT 'Number of successful deliveries via Diaspora',
|
|
||||||
`ostatus` mediumint NOT NULL DEFAULT 0 COMMENT 'Number of successful deliveries via OStatus',
|
|
||||||
PRIMARY KEY(`iid`)
|
|
||||||
) DEFAULT COLLATE utf8mb4_general_ci COMMENT='Delivery data for items';
|
|
||||||
|
|
||||||
--
|
--
|
||||||
-- TABLE item-uri
|
-- TABLE item-uri
|
||||||
--
|
--
|
||||||
|
@ -1200,6 +1182,24 @@ CREATE TABLE IF NOT EXISTS `post-category` (
|
||||||
INDEX `uri-id` (`tid`)
|
INDEX `uri-id` (`tid`)
|
||||||
) DEFAULT COLLATE utf8mb4_general_ci COMMENT='post relation to categories';
|
) DEFAULT COLLATE utf8mb4_general_ci COMMENT='post relation to categories';
|
||||||
|
|
||||||
|
--
|
||||||
|
-- TABLE post-delivery-data
|
||||||
|
--
|
||||||
|
CREATE TABLE IF NOT EXISTS `post-delivery-data` (
|
||||||
|
`uri-id` int unsigned NOT NULL COMMENT 'Id of the item-uri table entry that contains the item uri',
|
||||||
|
`postopts` text COMMENT 'External post connectors add their network name to this comma-separated string to identify that they should be delivered to these networks during delivery',
|
||||||
|
`inform` mediumtext COMMENT 'Additional receivers of the linked item',
|
||||||
|
`queue_count` mediumint NOT NULL DEFAULT 0 COMMENT 'Initial number of delivery recipients, used as item.delivery_queue_count',
|
||||||
|
`queue_done` mediumint NOT NULL DEFAULT 0 COMMENT 'Number of successful deliveries, used as item.delivery_queue_done',
|
||||||
|
`queue_failed` mediumint NOT NULL DEFAULT 0 COMMENT 'Number of unsuccessful deliveries, used as item.delivery_queue_failed',
|
||||||
|
`activitypub` mediumint NOT NULL DEFAULT 0 COMMENT 'Number of successful deliveries via ActivityPub',
|
||||||
|
`dfrn` mediumint NOT NULL DEFAULT 0 COMMENT 'Number of successful deliveries via DFRN',
|
||||||
|
`legacy_dfrn` mediumint NOT NULL DEFAULT 0 COMMENT 'Number of successful deliveries via legacy DFRN',
|
||||||
|
`diaspora` mediumint NOT NULL DEFAULT 0 COMMENT 'Number of successful deliveries via Diaspora',
|
||||||
|
`ostatus` mediumint NOT NULL DEFAULT 0 COMMENT 'Number of successful deliveries via OStatus',
|
||||||
|
PRIMARY KEY(`uri-id`)
|
||||||
|
) DEFAULT COLLATE utf8mb4_general_ci COMMENT='Delivery data for items';
|
||||||
|
|
||||||
--
|
--
|
||||||
-- TABLE post-tag
|
-- TABLE post-tag
|
||||||
--
|
--
|
||||||
|
@ -1569,22 +1569,6 @@ CREATE VIEW `owner-view` AS SELECT
|
||||||
INNER JOIN `contact` ON `contact`.`uid` = `user`.`uid` AND `contact`.`self`
|
INNER JOIN `contact` ON `contact`.`uid` = `user`.`uid` AND `contact`.`self`
|
||||||
INNER JOIN `profile` ON `profile`.`uid` = `user`.`uid`;
|
INNER JOIN `profile` ON `profile`.`uid` = `user`.`uid`;
|
||||||
|
|
||||||
--
|
|
||||||
-- VIEW participation-view
|
|
||||||
--
|
|
||||||
DROP VIEW IF EXISTS `participation-view`;
|
|
||||||
CREATE VIEW `participation-view` AS SELECT
|
|
||||||
`participation`.`iid` AS `iid`,
|
|
||||||
`contact`.`id` AS `id`,
|
|
||||||
`contact`.`url` AS `url`,
|
|
||||||
`contact`.`name` AS `name`,
|
|
||||||
`contact`.`protocol` AS `protocol`,
|
|
||||||
CASE `contact`.`batch` WHEN '' THEN `fcontact`.`batch` ELSE `contact`.`batch` END AS `batch`,
|
|
||||||
CASE `fcontact`.`network` WHEN '' THEN `contact`.`network` ELSE `fcontact`.`network` END AS `network`
|
|
||||||
FROM `participation`
|
|
||||||
INNER JOIN `contact` ON `contact`.`id` = `participation`.`cid` AND NOT `contact`.`archive`
|
|
||||||
INNER JOIN `fcontact` ON `fcontact`.`id` = `participation`.`fid`;
|
|
||||||
|
|
||||||
--
|
--
|
||||||
-- VIEW pending-view
|
-- VIEW pending-view
|
||||||
--
|
--
|
||||||
|
|
|
@ -107,12 +107,24 @@ function notification($params)
|
||||||
$item_id = 0;
|
$item_id = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isset($params['item']['uri-id'])) {
|
||||||
|
$uri_id = $params['item']['uri-id'];
|
||||||
|
} else {
|
||||||
|
$uri_id = 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (isset($params['parent'])) {
|
if (isset($params['parent'])) {
|
||||||
$parent_id = $params['parent'];
|
$parent_id = $params['parent'];
|
||||||
} else {
|
} else {
|
||||||
$parent_id = 0;
|
$parent_id = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isset($params['item']['parent-uri-id'])) {
|
||||||
|
$parent_uri_id = $params['item']['parent-uri-id'];
|
||||||
|
} else {
|
||||||
|
$parent_uri_id = 0;
|
||||||
|
}
|
||||||
|
|
||||||
$epreamble = '';
|
$epreamble = '';
|
||||||
$preamble = '';
|
$preamble = '';
|
||||||
$subject = '';
|
$subject = '';
|
||||||
|
@ -458,8 +470,10 @@ function notification($params)
|
||||||
'photo' => $params['source_photo'] ?? '',
|
'photo' => $params['source_photo'] ?? '',
|
||||||
'link' => $itemlink ?? '',
|
'link' => $itemlink ?? '',
|
||||||
'uid' => $params['uid'] ?? 0,
|
'uid' => $params['uid'] ?? 0,
|
||||||
'iid' => $item_id ?? 0,
|
'iid' => $item_id,
|
||||||
'parent' => $parent_id ?? 0,
|
'uri-id' => $uri_id,
|
||||||
|
'parent' => $parent_id,
|
||||||
|
'parent-uri-id' => $parent_uri_id,
|
||||||
'type' => $params['type'] ?? '',
|
'type' => $params['type'] ?? '',
|
||||||
'verb' => $params['verb'] ?? '',
|
'verb' => $params['verb'] ?? '',
|
||||||
'otype' => $params['otype'] ?? '',
|
'otype' => $params['otype'] ?? '',
|
||||||
|
@ -487,6 +501,7 @@ function notification($params)
|
||||||
Logger::log("notify_id:" . intval($notify_id) . ", parent: " . intval($params['parent']) . "uid: " . intval($params['uid']), Logger::DEBUG);
|
Logger::log("notify_id:" . intval($notify_id) . ", parent: " . intval($params['parent']) . "uid: " . intval($params['uid']), Logger::DEBUG);
|
||||||
|
|
||||||
$fields = ['notify-id' => $notify_id, 'master-parent-item' => $params['parent'],
|
$fields = ['notify-id' => $notify_id, 'master-parent-item' => $params['parent'],
|
||||||
|
'master-parent-uri-id' => $parent_uri_id,
|
||||||
'receiver-uid' => $params['uid'], 'parent-item' => 0];
|
'receiver-uid' => $params['uid'], 'parent-item' => 0];
|
||||||
DBA::insert('notify-threads', $fields);
|
DBA::insert('notify-threads', $fields);
|
||||||
|
|
||||||
|
@ -574,7 +589,7 @@ function check_user_notification($itemid) {
|
||||||
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
|
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
|
||||||
*/
|
*/
|
||||||
function check_item_notification($itemid, $uid, $notification_type) {
|
function check_item_notification($itemid, $uid, $notification_type) {
|
||||||
$fields = ['id', 'mention', 'parent', 'title', 'body',
|
$fields = ['id', 'uri-id', 'mention', 'parent', 'parent-uri-id', 'title', 'body',
|
||||||
'author-link', 'author-name', 'author-avatar', 'author-id',
|
'author-link', 'author-name', 'author-avatar', 'author-id',
|
||||||
'guid', 'parent-uri', 'uri', 'contact-id', 'network'];
|
'guid', 'parent-uri', 'uri', 'contact-id', 'network'];
|
||||||
$condition = ['id' => $itemid, 'gravity' => [GRAVITY_PARENT, GRAVITY_COMMENT], 'deleted' => false];
|
$condition = ['id' => $itemid, 'gravity' => [GRAVITY_PARENT, GRAVITY_COMMENT], 'deleted' => false];
|
||||||
|
|
|
@ -74,6 +74,9 @@ class PostUpdate
|
||||||
if (!self::update1342()) {
|
if (!self::update1342()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (!self::update1345()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
if (!self::update1346()) {
|
if (!self::update1346()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -564,7 +567,6 @@ class PostUpdate
|
||||||
|
|
||||||
Logger::info('Start', ['item' => $id]);
|
Logger::info('Start', ['item' => $id]);
|
||||||
|
|
||||||
$start_id = $id;
|
|
||||||
$rows = 0;
|
$rows = 0;
|
||||||
|
|
||||||
$items = DBA::p("SELECT `uri-id`,`body` FROM `item-content` WHERE
|
$items = DBA::p("SELECT `uri-id`,`body` FROM `item-content` WHERE
|
||||||
|
@ -618,7 +620,6 @@ class PostUpdate
|
||||||
|
|
||||||
Logger::info('Start', ['item' => $id]);
|
Logger::info('Start', ['item' => $id]);
|
||||||
|
|
||||||
$start_id = $id;
|
|
||||||
$rows = 0;
|
$rows = 0;
|
||||||
|
|
||||||
$terms = DBA::p("SELECT `term`.`tid`, `item`.`uri-id`, `term`.`type`, `term`.`term`, `term`.`url`, `item-content`.`body`
|
$terms = DBA::p("SELECT `term`.`tid`, `item`.`uri-id`, `term`.`type`, `term`.`term`, `term`.`url`, `item-content`.`body`
|
||||||
|
@ -673,6 +674,60 @@ class PostUpdate
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fill the "post-delivery-data" table with data from the "item-delivery-data" table
|
||||||
|
*
|
||||||
|
* @return bool "true" when the job is done
|
||||||
|
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
|
||||||
|
*/
|
||||||
|
private static function update1345()
|
||||||
|
{
|
||||||
|
// Was the script completed?
|
||||||
|
if (DI::config()->get('system', 'post_update_version') >= 1345) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
$id = DI::config()->get('system', 'post_update_version_1345_id', 0);
|
||||||
|
Logger::info('Start', ['item' => $id]);
|
||||||
|
|
||||||
|
$rows = 0;
|
||||||
|
|
||||||
|
$deliveries = DBA::p("SELECT `uri-id`, `iid`, `item-delivery-data`.`postopts`, `item-delivery-data`.`inform`,
|
||||||
|
`queue_count`, `queue_done`, `activitypub`, `dfrn`, `diaspora`, `ostatus`, `legacy_dfrn`, `queue_failed`
|
||||||
|
FROM `item-delivery-data`
|
||||||
|
INNER JOIN `item` ON `item`.`id` = `item-delivery-data`.`iid`
|
||||||
|
WHERE `iid` >= ? ORDER BY `iid` LIMIT 10000", $id);
|
||||||
|
|
||||||
|
if (DBA::errorNo() != 0) {
|
||||||
|
Logger::error('Database error', ['no' => DBA::errorNo(), 'message' => DBA::errorMessage()]);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
while ($delivery = DBA::fetch($deliveries)) {
|
||||||
|
$id = $delivery['iid'];
|
||||||
|
unset($delivery['iid']);
|
||||||
|
DBA::insert('post-delivery-data', $delivery);
|
||||||
|
++$rows;
|
||||||
|
}
|
||||||
|
DBA::close($deliveries);
|
||||||
|
|
||||||
|
DI::config()->set('system', 'post_update_version_1345_id', $id);
|
||||||
|
|
||||||
|
Logger::info('Processed', ['rows' => $rows, 'last' => $id]);
|
||||||
|
|
||||||
|
// When there are less than 100 items processed this means that we reached the end
|
||||||
|
// The other entries will then be processed with the regular functionality
|
||||||
|
if ($rows < 100) {
|
||||||
|
DI::config()->set('system', 'post_update_version', 1345);
|
||||||
|
Logger::info('Done');
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fill the "tag" table with tags and mentions from the "term" table
|
* Fill the "tag" table with tags and mentions from the "term" table
|
||||||
*
|
*
|
||||||
|
|
|
@ -284,7 +284,7 @@ class Item
|
||||||
|
|
||||||
// Fetch data from the item-content table whenever there is content there
|
// Fetch data from the item-content table whenever there is content there
|
||||||
if (self::isLegacyMode()) {
|
if (self::isLegacyMode()) {
|
||||||
$legacy_fields = array_merge(ItemDeliveryData::LEGACY_FIELD_LIST, self::MIXED_CONTENT_FIELDLIST);
|
$legacy_fields = array_merge(Post\DeliveryData::LEGACY_FIELD_LIST, self::MIXED_CONTENT_FIELDLIST);
|
||||||
foreach ($legacy_fields as $field) {
|
foreach ($legacy_fields as $field) {
|
||||||
if (empty($row[$field]) && !empty($row['internal-item-' . $field])) {
|
if (empty($row[$field]) && !empty($row['internal-item-' . $field])) {
|
||||||
$row[$field] = $row['internal-item-' . $field];
|
$row[$field] = $row['internal-item-' . $field];
|
||||||
|
@ -685,7 +685,7 @@ class Item
|
||||||
|
|
||||||
$fields['item-content'] = array_merge(self::CONTENT_FIELDLIST, self::MIXED_CONTENT_FIELDLIST);
|
$fields['item-content'] = array_merge(self::CONTENT_FIELDLIST, self::MIXED_CONTENT_FIELDLIST);
|
||||||
|
|
||||||
$fields['item-delivery-data'] = array_merge(ItemDeliveryData::LEGACY_FIELD_LIST, ItemDeliveryData::FIELD_LIST);
|
$fields['post-delivery-data'] = array_merge(Post\DeliveryData::LEGACY_FIELD_LIST, Post\DeliveryData::FIELD_LIST);
|
||||||
|
|
||||||
$fields['permissionset'] = ['allow_cid', 'allow_gid', 'deny_cid', 'deny_gid'];
|
$fields['permissionset'] = ['allow_cid', 'allow_gid', 'deny_cid', 'deny_gid'];
|
||||||
|
|
||||||
|
@ -807,8 +807,8 @@ class Item
|
||||||
$joins .= " LEFT JOIN `item-content` ON `item-content`.`uri-id` = `item`.`uri-id`";
|
$joins .= " LEFT JOIN `item-content` ON `item-content`.`uri-id` = `item`.`uri-id`";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strpos($sql_commands, "`item-delivery-data`.") !== false) {
|
if (strpos($sql_commands, "`post-delivery-data`.") !== false) {
|
||||||
$joins .= " LEFT JOIN `item-delivery-data` ON `item-delivery-data`.`iid` = `item`.`id`";
|
$joins .= " LEFT JOIN `post-delivery-data` ON `post-delivery-data`.`uri-id` = `item`.`uri-id` AND `item`.`origin`";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strpos($sql_commands, "`permissionset`.") !== false) {
|
if (strpos($sql_commands, "`permissionset`.") !== false) {
|
||||||
|
@ -848,7 +848,7 @@ class Item
|
||||||
$selected[] = 'internal-user-ignored';
|
$selected[] = 'internal-user-ignored';
|
||||||
}
|
}
|
||||||
|
|
||||||
$legacy_fields = array_merge(ItemDeliveryData::LEGACY_FIELD_LIST, self::MIXED_CONTENT_FIELDLIST);
|
$legacy_fields = array_merge(Post\DeliveryData::LEGACY_FIELD_LIST, self::MIXED_CONTENT_FIELDLIST);
|
||||||
|
|
||||||
$selection = [];
|
$selection = [];
|
||||||
foreach ($fields as $table => $table_fields) {
|
foreach ($fields as $table => $table_fields) {
|
||||||
|
@ -934,7 +934,7 @@ class Item
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$delivery_data = ItemDeliveryData::extractFields($fields);
|
$delivery_data = Post\DeliveryData::extractFields($fields);
|
||||||
|
|
||||||
$clear_fields = ['bookmark', 'type', 'author-name', 'author-avatar', 'author-link', 'owner-name', 'owner-avatar', 'owner-link', 'postopts', 'inform'];
|
$clear_fields = ['bookmark', 'type', 'author-name', 'author-avatar', 'author-link', 'owner-name', 'owner-avatar', 'owner-link', 'postopts', 'inform'];
|
||||||
foreach ($clear_fields as $field) {
|
foreach ($clear_fields as $field) {
|
||||||
|
@ -1022,7 +1022,7 @@ class Item
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ItemDeliveryData::update($item['id'], $delivery_data);
|
Post\DeliveryData::update($item['uri-id'], $delivery_data);
|
||||||
|
|
||||||
self::updateThread($item['id']);
|
self::updateThread($item['id']);
|
||||||
|
|
||||||
|
@ -1182,7 +1182,7 @@ class Item
|
||||||
self::markForDeletion(['uri' => $item['uri'], 'uid' => 0, 'deleted' => false], $priority);
|
self::markForDeletion(['uri' => $item['uri'], 'uid' => 0, 'deleted' => false], $priority);
|
||||||
}
|
}
|
||||||
|
|
||||||
ItemDeliveryData::delete($item['id']);
|
Post\DeliveryData::delete($item['uri-id']);
|
||||||
|
|
||||||
// We don't delete the item-activity here, since we need some of the data for ActivityPub
|
// We don't delete the item-activity here, since we need some of the data for ActivityPub
|
||||||
|
|
||||||
|
@ -1838,7 +1838,7 @@ class Item
|
||||||
self::insertContent($item);
|
self::insertContent($item);
|
||||||
}
|
}
|
||||||
|
|
||||||
$delivery_data = ItemDeliveryData::extractFields($item);
|
$delivery_data = Post\DeliveryData::extractFields($item);
|
||||||
|
|
||||||
unset($item['postopts']);
|
unset($item['postopts']);
|
||||||
unset($item['inform']);
|
unset($item['inform']);
|
||||||
|
@ -1942,7 +1942,7 @@ class Item
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!empty($item['origin']) || !empty($item['wall']) || !empty($delivery_data['postopts']) || !empty($delivery_data['inform'])) {
|
if (!empty($item['origin']) || !empty($item['wall']) || !empty($delivery_data['postopts']) || !empty($delivery_data['inform'])) {
|
||||||
ItemDeliveryData::insert($current_post, $delivery_data);
|
Post\DeliveryData::insert($item['uri-id'], $delivery_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
DBA::commit();
|
DBA::commit();
|
||||||
|
|
|
@ -19,12 +19,12 @@
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Friendica\Model;
|
namespace Friendica\Model\Post;
|
||||||
|
|
||||||
use Friendica\Database\DBA;
|
use Friendica\Database\DBA;
|
||||||
use \BadMethodCallException;
|
use \BadMethodCallException;
|
||||||
|
|
||||||
class ItemDeliveryData
|
class DeliveryData
|
||||||
{
|
{
|
||||||
const LEGACY_FIELD_LIST = [
|
const LEGACY_FIELD_LIST = [
|
||||||
// Legacy fields moved from item table
|
// Legacy fields moved from item table
|
||||||
|
@ -55,7 +55,7 @@ class ItemDeliveryData
|
||||||
public static function extractFields(array &$fields)
|
public static function extractFields(array &$fields)
|
||||||
{
|
{
|
||||||
$delivery_data = [];
|
$delivery_data = [];
|
||||||
foreach (array_merge(ItemDeliveryData::FIELD_LIST, ItemDeliveryData::LEGACY_FIELD_LIST) as $key => $field) {
|
foreach (array_merge(self::FIELD_LIST, self::LEGACY_FIELD_LIST) as $key => $field) {
|
||||||
if (is_int($key) && isset($fields[$field])) {
|
if (is_int($key) && isset($fields[$field])) {
|
||||||
// Legacy field moved from item table
|
// Legacy field moved from item table
|
||||||
$delivery_data[$field] = $fields[$field];
|
$delivery_data[$field] = $fields[$field];
|
||||||
|
@ -71,16 +71,16 @@ class ItemDeliveryData
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Increments the queue_done for the given item ID.
|
* Increments the queue_done for the given URI ID.
|
||||||
*
|
*
|
||||||
* Avoids racing condition between multiple delivery threads.
|
* Avoids racing condition between multiple delivery threads.
|
||||||
*
|
*
|
||||||
* @param integer $item_id
|
* @param integer $uri_id
|
||||||
* @param integer $protocol
|
* @param integer $protocol
|
||||||
* @return bool
|
* @return bool
|
||||||
* @throws \Exception
|
* @throws \Exception
|
||||||
*/
|
*/
|
||||||
public static function incrementQueueDone($item_id, $protocol = 0)
|
public static function incrementQueueDone(int $uri_id, int $protocol = 0)
|
||||||
{
|
{
|
||||||
$sql = '';
|
$sql = '';
|
||||||
|
|
||||||
|
@ -102,69 +102,69 @@ class ItemDeliveryData
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return DBA::e('UPDATE `item-delivery-data` SET `queue_done` = `queue_done` + 1' . $sql . ' WHERE `iid` = ?', $item_id);
|
return DBA::e('UPDATE `post-delivery-data` SET `queue_done` = `queue_done` + 1' . $sql . ' WHERE `uri-id` = ?', $uri_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Increments the queue_failed for the given item ID.
|
* Increments the queue_failed for the given URI ID.
|
||||||
*
|
*
|
||||||
* Avoids racing condition between multiple delivery threads.
|
* Avoids racing condition between multiple delivery threads.
|
||||||
*
|
*
|
||||||
* @param integer $item_id
|
* @param integer $uri_id
|
||||||
* @return bool
|
* @return bool
|
||||||
* @throws \Exception
|
* @throws \Exception
|
||||||
*/
|
*/
|
||||||
public static function incrementQueueFailed($item_id)
|
public static function incrementQueueFailed(int $uri_id)
|
||||||
{
|
{
|
||||||
return DBA::e('UPDATE `item-delivery-data` SET `queue_failed` = `queue_failed` + 1 WHERE `iid` = ?', $item_id);
|
return DBA::e('UPDATE `post-delivery-data` SET `queue_failed` = `queue_failed` + 1 WHERE `uri-id` = ?', $uri_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Increments the queue_count for the given item ID.
|
* Increments the queue_count for the given URI ID.
|
||||||
*
|
*
|
||||||
* @param integer $item_id
|
* @param integer $uri_id
|
||||||
* @param integer $increment
|
* @param integer $increment
|
||||||
* @return bool
|
* @return bool
|
||||||
* @throws \Exception
|
* @throws \Exception
|
||||||
*/
|
*/
|
||||||
public static function incrementQueueCount(int $item_id, int $increment = 1)
|
public static function incrementQueueCount(int $uri_id, int $increment = 1)
|
||||||
{
|
{
|
||||||
return DBA::e('UPDATE `item-delivery-data` SET `queue_count` = `queue_count` + ? WHERE `iid` = ?', $increment, $item_id);
|
return DBA::e('UPDATE `post-delivery-data` SET `queue_count` = `queue_count` + ? WHERE `uri-id` = ?', $increment, $uri_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Insert a new item delivery data entry
|
* Insert a new URI delivery data entry
|
||||||
*
|
*
|
||||||
* @param integer $item_id
|
* @param integer $uri_id
|
||||||
* @param array $fields
|
* @param array $fields
|
||||||
* @return bool
|
* @return bool
|
||||||
* @throws \Exception
|
* @throws \Exception
|
||||||
*/
|
*/
|
||||||
public static function insert($item_id, array $fields)
|
public static function insert(int $uri_id, array $fields)
|
||||||
{
|
{
|
||||||
if (empty($item_id)) {
|
if (empty($uri_id)) {
|
||||||
throw new BadMethodCallException('Empty item_id');
|
throw new BadMethodCallException('Empty URI_id');
|
||||||
}
|
}
|
||||||
|
|
||||||
$fields['iid'] = $item_id;
|
$fields['uri-id'] = $uri_id;
|
||||||
|
|
||||||
return DBA::insert('item-delivery-data', $fields);
|
return DBA::insert('post-delivery-data', $fields);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update/Insert item delivery data
|
* Update/Insert URI delivery data
|
||||||
*
|
*
|
||||||
* If you want to update queue_done, please use incrementQueueDone instead.
|
* If you want to update queue_done, please use incrementQueueDone instead.
|
||||||
*
|
*
|
||||||
* @param integer $item_id
|
* @param integer $uri_id
|
||||||
* @param array $fields
|
* @param array $fields
|
||||||
* @return bool
|
* @return bool
|
||||||
* @throws \Exception
|
* @throws \Exception
|
||||||
*/
|
*/
|
||||||
public static function update($item_id, array $fields)
|
public static function update(int $uri_id, array $fields)
|
||||||
{
|
{
|
||||||
if (empty($item_id)) {
|
if (empty($uri_id)) {
|
||||||
throw new BadMethodCallException('Empty item_id');
|
throw new BadMethodCallException('Empty URI_id');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (empty($fields)) {
|
if (empty($fields)) {
|
||||||
|
@ -172,22 +172,22 @@ class ItemDeliveryData
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return DBA::update('item-delivery-data', $fields, ['iid' => $item_id], true);
|
return DBA::update('post-delivery-data', $fields, ['uri-id' => $uri_id], true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Delete item delivery data
|
* Delete URI delivery data
|
||||||
*
|
*
|
||||||
* @param integer $item_id
|
* @param integer $uri_id
|
||||||
* @return bool
|
* @return bool
|
||||||
* @throws \Exception
|
* @throws \Exception
|
||||||
*/
|
*/
|
||||||
public static function delete($item_id)
|
public static function delete(int $uri_id)
|
||||||
{
|
{
|
||||||
if (empty($item_id)) {
|
if (empty($uri_id)) {
|
||||||
throw new BadMethodCallException('Empty item_id');
|
throw new BadMethodCallException('Empty URI_id');
|
||||||
}
|
}
|
||||||
|
|
||||||
return DBA::delete('item-delivery-data', ['iid' => $item_id]);
|
return DBA::delete('post-delivery-data', ['uri-id' => $uri_id]);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -36,8 +36,8 @@ use Friendica\Model\Conversation;
|
||||||
use Friendica\Model\GContact;
|
use Friendica\Model\GContact;
|
||||||
use Friendica\Model\Item;
|
use Friendica\Model\Item;
|
||||||
use Friendica\Model\ItemURI;
|
use Friendica\Model\ItemURI;
|
||||||
use Friendica\Model\ItemDeliveryData;
|
|
||||||
use Friendica\Model\Mail;
|
use Friendica\Model\Mail;
|
||||||
|
use Friendica\Model\Post;
|
||||||
use Friendica\Model\Tag;
|
use Friendica\Model\Tag;
|
||||||
use Friendica\Model\User;
|
use Friendica\Model\User;
|
||||||
use Friendica\Network\Probe;
|
use Friendica\Network\Probe;
|
||||||
|
@ -252,19 +252,25 @@ class Diaspora
|
||||||
* One of the parameters is a contact array.
|
* One of the parameters is a contact array.
|
||||||
* This is done to avoid duplicates.
|
* This is done to avoid duplicates.
|
||||||
*
|
*
|
||||||
* @param integer $thread The id of the thread
|
* @param array $parent The parent post
|
||||||
* @param array $contacts The previously fetched contacts
|
* @param array $contacts The previously fetched contacts
|
||||||
*
|
*
|
||||||
* @return array of relay servers
|
* @return array of relay servers
|
||||||
* @throws \Exception
|
* @throws \Exception
|
||||||
*/
|
*/
|
||||||
public static function participantsForThread($thread, array $contacts)
|
public static function participantsForThread(array $parent, array $contacts)
|
||||||
{
|
{
|
||||||
$participation = DBA::select('participation-view', [], ['iid' => $thread]);
|
if (!in_array($parent['private'], [Item::PUBLIC, Item::UNLISTED])) {
|
||||||
|
return $contacts;
|
||||||
|
}
|
||||||
|
|
||||||
while ($contact = DBA::fetch($participation)) {
|
$items = Item::select(['author-id'], ['parent' => $parent['id']], ['group_by' => ['author-id']]);
|
||||||
if (empty($contact['protocol'])) {
|
while ($item = DBA::fetch($items)) {
|
||||||
$contact['protocol'] = $contact['network'];
|
$contact = DBA::selectFirst('contact', ['id', 'url', 'name', 'protocol', 'batch', 'network'],
|
||||||
|
['id' => $item['author-id']]);
|
||||||
|
if (!DBA::isResult($contact)) {
|
||||||
|
// Shouldn't happen
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
$exists = false;
|
$exists = false;
|
||||||
|
@ -275,11 +281,11 @@ class Diaspora
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!$exists) {
|
if (!$exists) {
|
||||||
|
Logger::info('Add participant to receiver list', ['item' => $parent['guid'], 'participant' => $contact['url']]);
|
||||||
$contacts[] = $contact;
|
$contacts[] = $contact;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
DBA::close($items);
|
||||||
DBA::close($participation);
|
|
||||||
|
|
||||||
return $contacts;
|
return $contacts;
|
||||||
}
|
}
|
||||||
|
@ -2251,18 +2257,32 @@ class Diaspora
|
||||||
* @param array $importer Array of the importer user
|
* @param array $importer Array of the importer user
|
||||||
* @param object $data The message object
|
* @param object $data The message object
|
||||||
*
|
*
|
||||||
* @return bool always true
|
* @return bool success
|
||||||
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
|
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
|
||||||
* @throws \ImagickException
|
* @throws \ImagickException
|
||||||
*/
|
*/
|
||||||
private static function receiveParticipation(array $importer, $data)
|
private static function receiveParticipation(array $importer, $data)
|
||||||
{
|
{
|
||||||
$author = strtolower(Strings::escapeTags(XML::unescape($data->author)));
|
$author = strtolower(Strings::escapeTags(XML::unescape($data->author)));
|
||||||
|
$guid = Strings::escapeTags(XML::unescape($data->guid));
|
||||||
$parent_guid = Strings::escapeTags(XML::unescape($data->parent_guid));
|
$parent_guid = Strings::escapeTags(XML::unescape($data->parent_guid));
|
||||||
|
|
||||||
$contact_id = Contact::getIdForURL($author);
|
$contact = self::allowedContactByHandle($importer, $author, true);
|
||||||
if (!$contact_id) {
|
if (!$contact) {
|
||||||
Logger::log('Contact not found: '.$author);
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (self::messageExists($importer["uid"], $guid)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
$parent_item = self::parentItem($importer["uid"], $parent_guid, $author, $contact);
|
||||||
|
if (!$parent_item) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!in_array($parent_item['private'], [Item::PUBLIC, Item::UNLISTED])) {
|
||||||
|
Logger::info('Item is not public, participation is ignored', ['parent_guid' => $parent_guid, 'guid' => $guid, 'author' => $author]);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2272,36 +2292,48 @@ class Diaspora
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
$item = Item::selectFirst(['id'], ['guid' => $parent_guid, 'origin' => true, 'private' => [Item::PUBLIC, Item::UNLISTED]]);
|
$author_contact = self::authorContactByUrl($contact, $person, $importer["uid"]);
|
||||||
if (!DBA::isResult($item)) {
|
|
||||||
Logger::log('Item not found, no origin or private: '.$parent_guid);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
$author_parts = explode('@', $author);
|
// Store participation
|
||||||
if (isset($author_parts[1])) {
|
$datarray = [];
|
||||||
$server = $author_parts[1];
|
|
||||||
} else {
|
|
||||||
// Should never happen
|
|
||||||
$server = $author;
|
|
||||||
}
|
|
||||||
|
|
||||||
Logger::log('Received participation for ID: '.$item['id'].' - Contact: '.$contact_id.' - Server: '.$server, Logger::DEBUG);
|
$datarray["protocol"] = Conversation::PARCEL_DIASPORA;
|
||||||
|
|
||||||
if (!DBA::exists('participation', ['iid' => $item['id'], 'server' => $server])) {
|
$datarray["uid"] = $importer["uid"];
|
||||||
DBA::insert('participation', ['iid' => $item['id'], 'cid' => $contact_id, 'fid' => $person['id'], 'server' => $server]);
|
$datarray["contact-id"] = $author_contact["cid"];
|
||||||
}
|
$datarray["network"] = $author_contact["network"];
|
||||||
|
|
||||||
|
$datarray["owner-link"] = $datarray["author-link"] = $person["url"];
|
||||||
|
$datarray["owner-id"] = $datarray["author-id"] = Contact::getIdForURL($person["url"], 0);
|
||||||
|
|
||||||
|
$datarray["guid"] = $guid;
|
||||||
|
$datarray["uri"] = self::getUriFromGuid($author, $guid);
|
||||||
|
|
||||||
|
$datarray["verb"] = Activity::FOLLOW;
|
||||||
|
$datarray["gravity"] = GRAVITY_ACTIVITY;
|
||||||
|
$datarray["parent-uri"] = $parent_item["uri"];
|
||||||
|
|
||||||
|
$datarray["object-type"] = Activity\ObjectType::NOTE;
|
||||||
|
|
||||||
|
$datarray["body"] = Activity::FOLLOW;
|
||||||
|
|
||||||
|
// Diaspora doesn't provide a date for a participation
|
||||||
|
$datarray["changed"] = $datarray["created"] = $datarray["edited"] = DateTimeFormat::utcNow();
|
||||||
|
|
||||||
|
$message_id = Item::insert($datarray);
|
||||||
|
|
||||||
|
Logger::info('Participation stored', ['id' => $message_id, 'guid' => $guid, 'parent_guid' => $parent_guid, 'author' => $author]);
|
||||||
|
|
||||||
// Send all existing comments and likes to the requesting server
|
// Send all existing comments and likes to the requesting server
|
||||||
$comments = Item::select(['id', 'parent', 'verb', 'self'], ['parent' => $item['id']]);
|
$comments = Item::select(['id', 'uri-id', 'parent'], ['parent' => $parent_item['id']]);
|
||||||
while ($comment = Item::fetch($comments)) {
|
while ($comment = Item::fetch($comments)) {
|
||||||
if ($comment['id'] == $comment['parent']) {
|
if ($comment['id'] == $comment['parent']) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
Logger::info('Deliver participation', ['item' => $comment['id'], 'contact' => $contact_id]);
|
Logger::info('Deliver participation', ['item' => $comment['id'], 'contact' => $author_contact["cid"]]);
|
||||||
if (Worker::add(PRIORITY_HIGH, 'Delivery', Delivery::POST, $comment['id'], $contact_id)) {
|
if (Worker::add(PRIORITY_HIGH, 'Delivery', Delivery::POST, $comment['id'], $author_contact["cid"])) {
|
||||||
ItemDeliveryData::incrementQueueCount($comment['id'], 1);
|
Post\DeliveryData::incrementQueueCount($comment['uri-id'], 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
DBA::close($comments);
|
DBA::close($comments);
|
||||||
|
|
|
@ -2081,12 +2081,10 @@ class OStatus
|
||||||
XML::addElement($doc, $entry, "ostatus:conversation", $conversation_uri, $attributes);
|
XML::addElement($doc, $entry, "ostatus:conversation", $conversation_uri, $attributes);
|
||||||
}
|
}
|
||||||
|
|
||||||
$tags = Tag::getByURIId($item['uri-id']);
|
// uri-id isn't present for follow entry pseudo-items
|
||||||
if (count($tags)) {
|
foreach (Tag::getByURIId($item['uri-id'] ?? 0) as $tag) {
|
||||||
foreach ($tags as $tag) {
|
|
||||||
$mentioned[$tag['url']] = $tag['url'];
|
$mentioned[$tag['url']] = $tag['url'];
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Make sure that mentions are accepted (GNU Social has problems with mixing HTTP and HTTPS)
|
// Make sure that mentions are accepted (GNU Social has problems with mixing HTTP and HTTPS)
|
||||||
$newmentions = [];
|
$newmentions = [];
|
||||||
|
|
|
@ -23,7 +23,8 @@ namespace Friendica\Worker;
|
||||||
|
|
||||||
use Friendica\Core\Logger;
|
use Friendica\Core\Logger;
|
||||||
use Friendica\Core\Worker;
|
use Friendica\Core\Worker;
|
||||||
use Friendica\Model\ItemDeliveryData;
|
use Friendica\Model\Item;
|
||||||
|
use Friendica\Model\Post;
|
||||||
use Friendica\Protocol\ActivityPub;
|
use Friendica\Protocol\ActivityPub;
|
||||||
use Friendica\Util\HTTPSignature;
|
use Friendica\Util\HTTPSignature;
|
||||||
|
|
||||||
|
@ -67,10 +68,13 @@ class APDelivery
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This should never fail and is temporariy (until the move to )
|
||||||
|
$item = Item::selectFirst(['uri-id'], ['id' => $target_id]);
|
||||||
|
|
||||||
if (!$success && !Worker::defer() && in_array($cmd, [Delivery::POST])) {
|
if (!$success && !Worker::defer() && in_array($cmd, [Delivery::POST])) {
|
||||||
ItemDeliveryData::incrementQueueFailed($target_id);
|
Post\DeliveryData::incrementQueueFailed($item['uri-id']);
|
||||||
} elseif ($success && in_array($cmd, [Delivery::POST])) {
|
} elseif ($success && in_array($cmd, [Delivery::POST])) {
|
||||||
ItemDeliveryData::incrementQueueDone($target_id, ItemDeliveryData::ACTIVITYPUB);
|
Post\DeliveryData::incrementQueueDone($item['uri-id'], Post\DeliveryData::ACTIVITYPUB);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -58,14 +58,14 @@ class Delivery
|
||||||
if ($cmd == self::MAIL) {
|
if ($cmd == self::MAIL) {
|
||||||
$target_item = DBA::selectFirst('mail', [], ['id' => $target_id]);
|
$target_item = DBA::selectFirst('mail', [], ['id' => $target_id]);
|
||||||
if (!DBA::isResult($target_item)) {
|
if (!DBA::isResult($target_item)) {
|
||||||
self::setFailedQueue($cmd, $target_id);
|
self::setFailedQueue($cmd, $target_item);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
$uid = $target_item['uid'];
|
$uid = $target_item['uid'];
|
||||||
} elseif ($cmd == self::SUGGESTION) {
|
} elseif ($cmd == self::SUGGESTION) {
|
||||||
$target_item = DBA::selectFirst('fsuggest', [], ['id' => $target_id]);
|
$target_item = DBA::selectFirst('fsuggest', [], ['id' => $target_id]);
|
||||||
if (!DBA::isResult($target_item)) {
|
if (!DBA::isResult($target_item)) {
|
||||||
self::setFailedQueue($cmd, $target_id);
|
self::setFailedQueue($cmd, $target_item);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
$uid = $target_item['uid'];
|
$uid = $target_item['uid'];
|
||||||
|
@ -75,7 +75,7 @@ class Delivery
|
||||||
} else {
|
} else {
|
||||||
$item = Model\Item::selectFirst(['parent'], ['id' => $target_id]);
|
$item = Model\Item::selectFirst(['parent'], ['id' => $target_id]);
|
||||||
if (!DBA::isResult($item) || empty($item['parent'])) {
|
if (!DBA::isResult($item) || empty($item['parent'])) {
|
||||||
self::setFailedQueue($cmd, $target_id);
|
self::setFailedQueue($cmd, $target_item);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
$parent_id = intval($item['parent']);
|
$parent_id = intval($item['parent']);
|
||||||
|
@ -97,13 +97,13 @@ class Delivery
|
||||||
|
|
||||||
if (empty($target_item)) {
|
if (empty($target_item)) {
|
||||||
Logger::log('Item ' . $target_id . "wasn't found. Quitting here.");
|
Logger::log('Item ' . $target_id . "wasn't found. Quitting here.");
|
||||||
self::setFailedQueue($cmd, $target_id);
|
self::setFailedQueue($cmd, $target_item);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (empty($parent)) {
|
if (empty($parent)) {
|
||||||
Logger::log('Parent ' . $parent_id . ' for item ' . $target_id . "wasn't found. Quitting here.");
|
Logger::log('Parent ' . $parent_id . ' for item ' . $target_id . "wasn't found. Quitting here.");
|
||||||
self::setFailedQueue($cmd, $target_id);
|
self::setFailedQueue($cmd, $target_item);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -113,7 +113,7 @@ class Delivery
|
||||||
$uid = $target_item['uid'];
|
$uid = $target_item['uid'];
|
||||||
} else {
|
} else {
|
||||||
Logger::log('Only public users for item ' . $target_id, Logger::DEBUG);
|
Logger::log('Only public users for item ' . $target_id, Logger::DEBUG);
|
||||||
self::setFailedQueue($cmd, $target_id);
|
self::setFailedQueue($cmd, $target_item);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -127,7 +127,7 @@ class Delivery
|
||||||
|
|
||||||
if (!empty($contact_id) && Model\Contact::isArchived($contact_id)) {
|
if (!empty($contact_id) && Model\Contact::isArchived($contact_id)) {
|
||||||
Logger::info('Contact is archived', ['id' => $contact_id, 'cmd' => $cmd, 'item' => $target_item['id']]);
|
Logger::info('Contact is archived', ['id' => $contact_id, 'cmd' => $cmd, 'item' => $target_item['id']]);
|
||||||
self::setFailedQueue($cmd, $target_id);
|
self::setFailedQueue($cmd, $target_item);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -187,7 +187,7 @@ class Delivery
|
||||||
|
|
||||||
$owner = Model\User::getOwnerDataById($uid);
|
$owner = Model\User::getOwnerDataById($uid);
|
||||||
if (!DBA::isResult($owner)) {
|
if (!DBA::isResult($owner)) {
|
||||||
self::setFailedQueue($cmd, $target_id);
|
self::setFailedQueue($cmd, $target_item);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -196,12 +196,12 @@ class Delivery
|
||||||
['id' => $contact_id, 'blocked' => false, 'pending' => false, 'self' => false]
|
['id' => $contact_id, 'blocked' => false, 'pending' => false, 'self' => false]
|
||||||
);
|
);
|
||||||
if (!DBA::isResult($contact)) {
|
if (!DBA::isResult($contact)) {
|
||||||
self::setFailedQueue($cmd, $target_id);
|
self::setFailedQueue($cmd, $target_item);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Network::isUrlBlocked($contact['url'])) {
|
if (Network::isUrlBlocked($contact['url'])) {
|
||||||
self::setFailedQueue($cmd, $target_id);
|
self::setFailedQueue($cmd, $target_item);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -243,15 +243,15 @@ class Delivery
|
||||||
* Increased the "failed" counter in the item delivery data
|
* Increased the "failed" counter in the item delivery data
|
||||||
*
|
*
|
||||||
* @param string $cmd Command
|
* @param string $cmd Command
|
||||||
* @param integer $id Item id
|
* @param array $item Item array
|
||||||
*/
|
*/
|
||||||
private static function setFailedQueue(string $cmd, int $id)
|
private static function setFailedQueue(string $cmd, array $item)
|
||||||
{
|
{
|
||||||
if (!in_array($cmd, [Delivery::POST, Delivery::POKE])) {
|
if (!in_array($cmd, [Delivery::POST, Delivery::POKE])) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Model\ItemDeliveryData::incrementQueueFailed($id);
|
Model\Post\DeliveryData::incrementQueueFailed($item['uri-id'] ?? $item['id']);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -335,13 +335,13 @@ class Delivery
|
||||||
DFRN::import($atom, $target_importer);
|
DFRN::import($atom, $target_importer);
|
||||||
|
|
||||||
if (in_array($cmd, [Delivery::POST, Delivery::POKE])) {
|
if (in_array($cmd, [Delivery::POST, Delivery::POKE])) {
|
||||||
Model\ItemDeliveryData::incrementQueueDone($target_item['id'], Model\ItemDeliveryData::DFRN);
|
Model\Post\DeliveryData::incrementQueueDone($target_item['uri-id'], Model\Post\DeliveryData::DFRN);
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$protocol = Model\ItemDeliveryData::DFRN;
|
$protocol = Model\Post\DeliveryData::DFRN;
|
||||||
|
|
||||||
// We don't have a relationship with contacts on a public post.
|
// We don't have a relationship with contacts on a public post.
|
||||||
// Se we transmit with the new method and via Diaspora as a fallback
|
// Se we transmit with the new method and via Diaspora as a fallback
|
||||||
|
@ -357,9 +357,9 @@ class Delivery
|
||||||
|
|
||||||
if (in_array($cmd, [Delivery::POST, Delivery::POKE])) {
|
if (in_array($cmd, [Delivery::POST, Delivery::POKE])) {
|
||||||
if (($deliver_status >= 200) && ($deliver_status <= 299)) {
|
if (($deliver_status >= 200) && ($deliver_status <= 299)) {
|
||||||
Model\ItemDeliveryData::incrementQueueDone($target_item['id'], $protocol);
|
Model\Post\DeliveryData::incrementQueueDone($target_item['uri-id'], $protocol);
|
||||||
} else {
|
} else {
|
||||||
Model\ItemDeliveryData::incrementQueueFailed($target_item['id']);
|
Model\Post\DeliveryData::incrementQueueFailed($target_item['uri-id']);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
|
@ -376,11 +376,11 @@ class Delivery
|
||||||
if ($deliver_status < 200) {
|
if ($deliver_status < 200) {
|
||||||
// Legacy DFRN
|
// Legacy DFRN
|
||||||
$deliver_status = DFRN::deliver($owner, $contact, $atom);
|
$deliver_status = DFRN::deliver($owner, $contact, $atom);
|
||||||
$protocol = Model\ItemDeliveryData::LEGACY_DFRN;
|
$protocol = Model\Post\DeliveryData::LEGACY_DFRN;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
$deliver_status = DFRN::deliver($owner, $contact, $atom);
|
$deliver_status = DFRN::deliver($owner, $contact, $atom);
|
||||||
$protocol = Model\ItemDeliveryData::LEGACY_DFRN;
|
$protocol = Model\Post\DeliveryData::LEGACY_DFRN;
|
||||||
}
|
}
|
||||||
|
|
||||||
Logger::info('DFRN Delivery', ['cmd' => $cmd, 'url' => $contact['url'], 'guid' => ($target_item['guid'] ?? '') ?: $target_item['id'], 'return' => $deliver_status]);
|
Logger::info('DFRN Delivery', ['cmd' => $cmd, 'url' => $contact['url'], 'guid' => ($target_item['guid'] ?? '') ?: $target_item['id'], 'return' => $deliver_status]);
|
||||||
|
@ -390,7 +390,7 @@ class Delivery
|
||||||
Model\Contact::unmarkForArchival($contact);
|
Model\Contact::unmarkForArchival($contact);
|
||||||
|
|
||||||
if (in_array($cmd, [Delivery::POST, Delivery::POKE])) {
|
if (in_array($cmd, [Delivery::POST, Delivery::POKE])) {
|
||||||
Model\ItemDeliveryData::incrementQueueDone($target_item['id'], $protocol);
|
Model\Post\DeliveryData::incrementQueueDone($target_item['uri-id'], $protocol);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// The message could not be delivered. We mark the contact as "dead"
|
// The message could not be delivered. We mark the contact as "dead"
|
||||||
|
@ -398,7 +398,7 @@ class Delivery
|
||||||
|
|
||||||
Logger::info('Delivery failed: defer message', ['id' => ($target_item['guid'] ?? '') ?: $target_item['id']]);
|
Logger::info('Delivery failed: defer message', ['id' => ($target_item['guid'] ?? '') ?: $target_item['id']]);
|
||||||
if (!Worker::defer() && in_array($cmd, [Delivery::POST, Delivery::POKE])) {
|
if (!Worker::defer() && in_array($cmd, [Delivery::POST, Delivery::POKE])) {
|
||||||
Model\ItemDeliveryData::incrementQueueFailed($target_item['id']);
|
Model\Post\DeliveryData::incrementQueueFailed($target_item['uri-id']);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -475,7 +475,7 @@ class Delivery
|
||||||
Model\Contact::unmarkForArchival($contact);
|
Model\Contact::unmarkForArchival($contact);
|
||||||
|
|
||||||
if (in_array($cmd, [Delivery::POST, Delivery::POKE])) {
|
if (in_array($cmd, [Delivery::POST, Delivery::POKE])) {
|
||||||
Model\ItemDeliveryData::incrementQueueDone($target_item['id'], Model\ItemDeliveryData::DIASPORA);
|
Model\Post\DeliveryData::incrementQueueDone($target_item['uri-id'], Model\Post\DeliveryData::DIASPORA);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// The message could not be delivered. We mark the contact as "dead"
|
// The message could not be delivered. We mark the contact as "dead"
|
||||||
|
@ -490,10 +490,10 @@ class Delivery
|
||||||
Logger::info('Delivery failed: defer message', ['id' => ($target_item['guid'] ?? '') ?: $target_item['id']]);
|
Logger::info('Delivery failed: defer message', ['id' => ($target_item['guid'] ?? '') ?: $target_item['id']]);
|
||||||
// defer message for redelivery
|
// defer message for redelivery
|
||||||
if (!Worker::defer() && in_array($cmd, [Delivery::POST, Delivery::POKE])) {
|
if (!Worker::defer() && in_array($cmd, [Delivery::POST, Delivery::POKE])) {
|
||||||
Model\ItemDeliveryData::incrementQueueFailed($target_item['id']);
|
Model\Post\DeliveryData::incrementQueueFailed($target_item['uri-id']);
|
||||||
}
|
}
|
||||||
} elseif (in_array($cmd, [Delivery::POST, Delivery::POKE])) {
|
} elseif (in_array($cmd, [Delivery::POST, Delivery::POKE])) {
|
||||||
Model\ItemDeliveryData::incrementQueueFailed($target_item['id']);
|
Model\Post\DeliveryData::incrementQueueFailed($target_item['uri-id']);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -603,7 +603,7 @@ class Delivery
|
||||||
|
|
||||||
Email::send($addr, $subject, $headers, $target_item);
|
Email::send($addr, $subject, $headers, $target_item);
|
||||||
|
|
||||||
Model\ItemDeliveryData::incrementQueueDone($target_item['id'], Model\ItemDeliveryData::MAIL);
|
Model\Post\DeliveryData::incrementQueueDone($target_item['uri-id'], Model\Post\DeliveryData::MAIL);
|
||||||
|
|
||||||
Logger::info('Delivered via mail', ['guid' => $target_item['guid'], 'to' => $addr, 'subject' => $subject]);
|
Logger::info('Delivered via mail', ['guid' => $target_item['guid'], 'to' => $addr, 'subject' => $subject]);
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,7 +32,7 @@ use Friendica\Model\Contact;
|
||||||
use Friendica\Model\Conversation;
|
use Friendica\Model\Conversation;
|
||||||
use Friendica\Model\Group;
|
use Friendica\Model\Group;
|
||||||
use Friendica\Model\Item;
|
use Friendica\Model\Item;
|
||||||
use Friendica\Model\ItemDeliveryData;
|
use Friendica\Model\Post;
|
||||||
use Friendica\Model\PushSubscriber;
|
use Friendica\Model\PushSubscriber;
|
||||||
use Friendica\Model\User;
|
use Friendica\Model\User;
|
||||||
use Friendica\Network\Probe;
|
use Friendica\Network\Probe;
|
||||||
|
@ -441,7 +441,7 @@ class Notifier
|
||||||
|
|
||||||
// Fetch the participation list
|
// Fetch the participation list
|
||||||
// The function will ensure that there are no duplicates
|
// The function will ensure that there are no duplicates
|
||||||
$relay_list = Diaspora::participantsForThread($target_id, $relay_list);
|
$relay_list = Diaspora::participantsForThread($parent, $relay_list);
|
||||||
|
|
||||||
// Add the relay to the list, avoid duplicates.
|
// Add the relay to the list, avoid duplicates.
|
||||||
// Don't send community posts to the relay. Forum posts via the Diaspora protocol are looking ugly.
|
// Don't send community posts to the relay. Forum posts via the Diaspora protocol are looking ugly.
|
||||||
|
@ -573,7 +573,7 @@ class Notifier
|
||||||
/// @TODO Redeliver/queue these items on failure, though there is no contact record
|
/// @TODO Redeliver/queue these items on failure, though there is no contact record
|
||||||
$delivery_queue_count++;
|
$delivery_queue_count++;
|
||||||
Salmon::slapper($owner, $url, $slap);
|
Salmon::slapper($owner, $url, $slap);
|
||||||
ItemDeliveryData::incrementQueueDone($target_id, ItemDeliveryData::OSTATUS);
|
Post\DeliveryData::incrementQueueDone($target_item['uri-id'], Post\DeliveryData::OSTATUS);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -595,11 +595,11 @@ class Notifier
|
||||||
// Workaround for pure connector posts
|
// Workaround for pure connector posts
|
||||||
if (in_array($cmd, [Delivery::POST, Delivery::POKE])) {
|
if (in_array($cmd, [Delivery::POST, Delivery::POKE])) {
|
||||||
if ($delivery_queue_count == 0) {
|
if ($delivery_queue_count == 0) {
|
||||||
ItemDeliveryData::incrementQueueDone($target_item['id']);
|
Post\DeliveryData::incrementQueueDone($target_item['uri-id']);
|
||||||
$delivery_queue_count = 1;
|
$delivery_queue_count = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
ItemDeliveryData::incrementQueueCount($target_item['id'], $delivery_queue_count);
|
Post\DeliveryData::incrementQueueCount($target_item['uri-id'], $delivery_queue_count);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -804,25 +804,6 @@ return [
|
||||||
"uri-id" => ["uri-id"]
|
"uri-id" => ["uri-id"]
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
"item-delivery-data" => [
|
|
||||||
"comment" => "Delivery data for items",
|
|
||||||
"fields" => [
|
|
||||||
"iid" => ["type" => "int unsigned", "not null" => "1", "primary" => "1", "relation" => ["item" => "id"], "comment" => "Item id"],
|
|
||||||
"postopts" => ["type" => "text", "comment" => "External post connectors add their network name to this comma-separated string to identify that they should be delivered to these networks during delivery"],
|
|
||||||
"inform" => ["type" => "mediumtext", "comment" => "Additional receivers of the linked item"],
|
|
||||||
"queue_count" => ["type" => "mediumint", "not null" => "1", "default" => "0", "comment" => "Initial number of delivery recipients, used as item.delivery_queue_count"],
|
|
||||||
"queue_done" => ["type" => "mediumint", "not null" => "1", "default" => "0", "comment" => "Number of successful deliveries, used as item.delivery_queue_done"],
|
|
||||||
"queue_failed" => ["type" => "mediumint", "not null" => "1", "default" => "0", "comment" => "Number of unsuccessful deliveries, used as item.delivery_queue_failed"],
|
|
||||||
"activitypub" => ["type" => "mediumint", "not null" => "1", "default" => "0", "comment" => "Number of successful deliveries via ActivityPub"],
|
|
||||||
"dfrn" => ["type" => "mediumint", "not null" => "1", "default" => "0", "comment" => "Number of successful deliveries via DFRN"],
|
|
||||||
"legacy_dfrn" => ["type" => "mediumint", "not null" => "1", "default" => "0", "comment" => "Number of successful deliveries via legacy DFRN"],
|
|
||||||
"diaspora" => ["type" => "mediumint", "not null" => "1", "default" => "0", "comment" => "Number of successful deliveries via Diaspora"],
|
|
||||||
"ostatus" => ["type" => "mediumint", "not null" => "1", "default" => "0", "comment" => "Number of successful deliveries via OStatus"],
|
|
||||||
],
|
|
||||||
"indexes" => [
|
|
||||||
"PRIMARY" => ["iid"],
|
|
||||||
]
|
|
||||||
],
|
|
||||||
"item-uri" => [
|
"item-uri" => [
|
||||||
"comment" => "URI and GUID for items",
|
"comment" => "URI and GUID for items",
|
||||||
"fields" => [
|
"fields" => [
|
||||||
|
@ -927,6 +908,8 @@ return [
|
||||||
"link" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""],
|
"link" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""],
|
||||||
"iid" => ["type" => "int unsigned", "not null" => "1", "default" => "0", "relation" => ["item" => "id"], "comment" => "item.id"],
|
"iid" => ["type" => "int unsigned", "not null" => "1", "default" => "0", "relation" => ["item" => "id"], "comment" => "item.id"],
|
||||||
"parent" => ["type" => "int unsigned", "not null" => "1", "default" => "0", "relation" => ["item" => "id"], "comment" => ""],
|
"parent" => ["type" => "int unsigned", "not null" => "1", "default" => "0", "relation" => ["item" => "id"], "comment" => ""],
|
||||||
|
"uri-id" => ["type" => "int unsigned", "relation" => ["item-uri" => "id"], "comment" => "Item-uri id of the related post"],
|
||||||
|
"parent-uri-id" => ["type" => "int unsigned", "relation" => ["item-uri" => "id"], "comment" => "Item-uri id of the parent of the related post"],
|
||||||
"seen" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => ""],
|
"seen" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => ""],
|
||||||
"verb" => ["type" => "varchar(100)", "not null" => "1", "default" => "", "comment" => ""],
|
"verb" => ["type" => "varchar(100)", "not null" => "1", "default" => "", "comment" => ""],
|
||||||
"otype" => ["type" => "varchar(10)", "not null" => "1", "default" => "", "comment" => ""],
|
"otype" => ["type" => "varchar(10)", "not null" => "1", "default" => "", "comment" => ""],
|
||||||
|
@ -945,8 +928,8 @@ return [
|
||||||
"fields" => [
|
"fields" => [
|
||||||
"id" => ["type" => "int unsigned", "not null" => "1", "extra" => "auto_increment", "primary" => "1", "comment" => "sequential ID"],
|
"id" => ["type" => "int unsigned", "not null" => "1", "extra" => "auto_increment", "primary" => "1", "comment" => "sequential ID"],
|
||||||
"notify-id" => ["type" => "int unsigned", "not null" => "1", "default" => "0", "relation" => ["notify" => "id"], "comment" => ""],
|
"notify-id" => ["type" => "int unsigned", "not null" => "1", "default" => "0", "relation" => ["notify" => "id"], "comment" => ""],
|
||||||
"master-parent-item" => ["type" => "int unsigned", "not null" => "1", "default" => "0", "relation" => ["item" => "id"],
|
"master-parent-item" => ["type" => "int unsigned", "not null" => "1", "default" => "0", "relation" => ["item" => "id"], "comment" => ""],
|
||||||
"comment" => ""],
|
"master-parent-uri-id" => ["type" => "int unsigned", "relation" => ["item-uri" => "id"], "comment" => "Item-uri id of the parent of the related post"],
|
||||||
"parent-item" => ["type" => "int unsigned", "not null" => "1", "default" => "0", "comment" => ""],
|
"parent-item" => ["type" => "int unsigned", "not null" => "1", "default" => "0", "comment" => ""],
|
||||||
"receiver-uid" => ["type" => "mediumint unsigned", "not null" => "1", "default" => "0", "relation" => ["user" => "uid"],
|
"receiver-uid" => ["type" => "mediumint unsigned", "not null" => "1", "default" => "0", "relation" => ["user" => "uid"],
|
||||||
"comment" => "User id"],
|
"comment" => "User id"],
|
||||||
|
@ -1319,6 +1302,25 @@ return [
|
||||||
"uri-id" => ["tid"]
|
"uri-id" => ["tid"]
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
|
"post-delivery-data" => [
|
||||||
|
"comment" => "Delivery data for items",
|
||||||
|
"fields" => [
|
||||||
|
"uri-id" => ["type" => "int unsigned", "not null" => "1", "primary" => "1", "relation" => ["item-uri" => "id"], "comment" => "Id of the item-uri table entry that contains the item uri"],
|
||||||
|
"postopts" => ["type" => "text", "comment" => "External post connectors add their network name to this comma-separated string to identify that they should be delivered to these networks during delivery"],
|
||||||
|
"inform" => ["type" => "mediumtext", "comment" => "Additional receivers of the linked item"],
|
||||||
|
"queue_count" => ["type" => "mediumint", "not null" => "1", "default" => "0", "comment" => "Initial number of delivery recipients, used as item.delivery_queue_count"],
|
||||||
|
"queue_done" => ["type" => "mediumint", "not null" => "1", "default" => "0", "comment" => "Number of successful deliveries, used as item.delivery_queue_done"],
|
||||||
|
"queue_failed" => ["type" => "mediumint", "not null" => "1", "default" => "0", "comment" => "Number of unsuccessful deliveries, used as item.delivery_queue_failed"],
|
||||||
|
"activitypub" => ["type" => "mediumint", "not null" => "1", "default" => "0", "comment" => "Number of successful deliveries via ActivityPub"],
|
||||||
|
"dfrn" => ["type" => "mediumint", "not null" => "1", "default" => "0", "comment" => "Number of successful deliveries via DFRN"],
|
||||||
|
"legacy_dfrn" => ["type" => "mediumint", "not null" => "1", "default" => "0", "comment" => "Number of successful deliveries via legacy DFRN"],
|
||||||
|
"diaspora" => ["type" => "mediumint", "not null" => "1", "default" => "0", "comment" => "Number of successful deliveries via Diaspora"],
|
||||||
|
"ostatus" => ["type" => "mediumint", "not null" => "1", "default" => "0", "comment" => "Number of successful deliveries via OStatus"],
|
||||||
|
],
|
||||||
|
"indexes" => [
|
||||||
|
"PRIMARY" => ["uri-id"],
|
||||||
|
]
|
||||||
|
],
|
||||||
"post-tag" => [
|
"post-tag" => [
|
||||||
"comment" => "post relation to tags",
|
"comment" => "post relation to tags",
|
||||||
"fields" => [
|
"fields" => [
|
||||||
|
|
|
@ -201,20 +201,6 @@ return [
|
||||||
INNER JOIN `contact` ON `contact`.`uid` = `user`.`uid` AND `contact`.`self`
|
INNER JOIN `contact` ON `contact`.`uid` = `user`.`uid` AND `contact`.`self`
|
||||||
INNER JOIN `profile` ON `profile`.`uid` = `user`.`uid`"
|
INNER JOIN `profile` ON `profile`.`uid` = `user`.`uid`"
|
||||||
],
|
],
|
||||||
"participation-view" => [
|
|
||||||
"fields" => [
|
|
||||||
"iid" => ["participation", "iid"],
|
|
||||||
"id" => ["contact", "id"],
|
|
||||||
"url" => ["contact", "url"],
|
|
||||||
"name" => ["contact", "name"],
|
|
||||||
"protocol" => ["contact", "protocol"],
|
|
||||||
"batch" => "CASE `contact`.`batch` WHEN '' THEN `fcontact`.`batch` ELSE `contact`.`batch` END",
|
|
||||||
"network" => "CASE `fcontact`.`network` WHEN '' THEN `contact`.`network` ELSE `fcontact`.`network` END",
|
|
||||||
],
|
|
||||||
"query" => "FROM `participation`
|
|
||||||
INNER JOIN `contact` ON `contact`.`id` = `participation`.`cid` AND NOT `contact`.`archive`
|
|
||||||
INNER JOIN `fcontact` ON `fcontact`.`id` = `participation`.`fid`"
|
|
||||||
],
|
|
||||||
"pending-view" => [
|
"pending-view" => [
|
||||||
"fields" => [
|
"fields" => [
|
||||||
"id" => ["register", "id"],
|
"id" => ["register", "id"],
|
||||||
|
|
|
@ -27,7 +27,7 @@ return [
|
||||||
'photo',
|
'photo',
|
||||||
'workerqueue',
|
'workerqueue',
|
||||||
'mail',
|
'mail',
|
||||||
'item-delivery-data',
|
'post-delivery-data',
|
||||||
// Base test config to avoid notice messages
|
// Base test config to avoid notice messages
|
||||||
'config' => [
|
'config' => [
|
||||||
[
|
[
|
||||||
|
|
22
view/js/perfect-scrollbar/LICENSE
Normal file
22
view/js/perfect-scrollbar/LICENSE
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright (c) 2016 Hyunje Alex Jun
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
|
5
view/js/perfect-scrollbar/README.md
Normal file
5
view/js/perfect-scrollbar/README.md
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
# Bower Package of perfect-scrollbar
|
||||||
|
|
||||||
|
This is the [Bower](https://bower.io/) package of perfect-scrollbar.
|
||||||
|
|
||||||
|
For details and usage please read more on [https://github.com/noraesae/perfect-scrollbar](https://github.com/noraesae/perfect-scrollbar).
|
18
view/js/perfect-scrollbar/bower.json
Normal file
18
view/js/perfect-scrollbar/bower.json
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
{
|
||||||
|
"name": "perfect-scrollbar",
|
||||||
|
"version": "0.6.16",
|
||||||
|
"homepage": "http://noraesae.github.io/perfect-scrollbar/",
|
||||||
|
"authors": [
|
||||||
|
"Hyunje Jun <me@noraesae.net>"
|
||||||
|
],
|
||||||
|
"description": "Minimalistic but perfect custom scrollbar plugin",
|
||||||
|
"main": [
|
||||||
|
"css/perfect-scrollbar.css",
|
||||||
|
"js/perfect-scrollbar.js"
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"ignore": [
|
||||||
|
"**/.*",
|
||||||
|
"bower_components"
|
||||||
|
]
|
||||||
|
}
|
113
view/js/perfect-scrollbar/css/perfect-scrollbar.css
Normal file
113
view/js/perfect-scrollbar/css/perfect-scrollbar.css
Normal file
|
@ -0,0 +1,113 @@
|
||||||
|
/* perfect-scrollbar v0.6.16 */
|
||||||
|
.ps-container {
|
||||||
|
-ms-touch-action: auto;
|
||||||
|
touch-action: auto;
|
||||||
|
overflow: hidden !important;
|
||||||
|
-ms-overflow-style: none; }
|
||||||
|
@supports (-ms-overflow-style: none) {
|
||||||
|
.ps-container {
|
||||||
|
overflow: auto !important; } }
|
||||||
|
@media screen and (-ms-high-contrast: active), (-ms-high-contrast: none) {
|
||||||
|
.ps-container {
|
||||||
|
overflow: auto !important; } }
|
||||||
|
.ps-container.ps-active-x > .ps-scrollbar-x-rail,
|
||||||
|
.ps-container.ps-active-y > .ps-scrollbar-y-rail {
|
||||||
|
display: block;
|
||||||
|
background-color: transparent; }
|
||||||
|
.ps-container.ps-in-scrolling.ps-x > .ps-scrollbar-x-rail {
|
||||||
|
background-color: #eee;
|
||||||
|
opacity: 0.9; }
|
||||||
|
.ps-container.ps-in-scrolling.ps-x > .ps-scrollbar-x-rail > .ps-scrollbar-x {
|
||||||
|
background-color: #999;
|
||||||
|
height: 11px; }
|
||||||
|
.ps-container.ps-in-scrolling.ps-y > .ps-scrollbar-y-rail {
|
||||||
|
background-color: #eee;
|
||||||
|
opacity: 0.9; }
|
||||||
|
.ps-container.ps-in-scrolling.ps-y > .ps-scrollbar-y-rail > .ps-scrollbar-y {
|
||||||
|
background-color: #999;
|
||||||
|
width: 11px; }
|
||||||
|
.ps-container > .ps-scrollbar-x-rail {
|
||||||
|
display: none;
|
||||||
|
position: absolute;
|
||||||
|
/* please don't change 'position' */
|
||||||
|
opacity: 0;
|
||||||
|
-webkit-transition: background-color .2s linear, opacity .2s linear;
|
||||||
|
-o-transition: background-color .2s linear, opacity .2s linear;
|
||||||
|
-moz-transition: background-color .2s linear, opacity .2s linear;
|
||||||
|
transition: background-color .2s linear, opacity .2s linear;
|
||||||
|
bottom: 0px;
|
||||||
|
/* there must be 'bottom' for ps-scrollbar-x-rail */
|
||||||
|
height: 15px; }
|
||||||
|
.ps-container > .ps-scrollbar-x-rail > .ps-scrollbar-x {
|
||||||
|
position: absolute;
|
||||||
|
/* please don't change 'position' */
|
||||||
|
background-color: #aaa;
|
||||||
|
-webkit-border-radius: 6px;
|
||||||
|
-moz-border-radius: 6px;
|
||||||
|
border-radius: 6px;
|
||||||
|
-webkit-transition: background-color .2s linear, height .2s linear, width .2s ease-in-out, -webkit-border-radius .2s ease-in-out;
|
||||||
|
transition: background-color .2s linear, height .2s linear, width .2s ease-in-out, -webkit-border-radius .2s ease-in-out;
|
||||||
|
-o-transition: background-color .2s linear, height .2s linear, width .2s ease-in-out, border-radius .2s ease-in-out;
|
||||||
|
-moz-transition: background-color .2s linear, height .2s linear, width .2s ease-in-out, border-radius .2s ease-in-out, -moz-border-radius .2s ease-in-out;
|
||||||
|
transition: background-color .2s linear, height .2s linear, width .2s ease-in-out, border-radius .2s ease-in-out;
|
||||||
|
transition: background-color .2s linear, height .2s linear, width .2s ease-in-out, border-radius .2s ease-in-out, -webkit-border-radius .2s ease-in-out, -moz-border-radius .2s ease-in-out;
|
||||||
|
bottom: 2px;
|
||||||
|
/* there must be 'bottom' for ps-scrollbar-x */
|
||||||
|
height: 6px; }
|
||||||
|
.ps-container > .ps-scrollbar-x-rail:hover > .ps-scrollbar-x, .ps-container > .ps-scrollbar-x-rail:active > .ps-scrollbar-x {
|
||||||
|
height: 11px; }
|
||||||
|
.ps-container > .ps-scrollbar-y-rail {
|
||||||
|
display: none;
|
||||||
|
position: absolute;
|
||||||
|
/* please don't change 'position' */
|
||||||
|
opacity: 0;
|
||||||
|
-webkit-transition: background-color .2s linear, opacity .2s linear;
|
||||||
|
-o-transition: background-color .2s linear, opacity .2s linear;
|
||||||
|
-moz-transition: background-color .2s linear, opacity .2s linear;
|
||||||
|
transition: background-color .2s linear, opacity .2s linear;
|
||||||
|
right: 0;
|
||||||
|
/* there must be 'right' for ps-scrollbar-y-rail */
|
||||||
|
width: 15px; }
|
||||||
|
.ps-container > .ps-scrollbar-y-rail > .ps-scrollbar-y {
|
||||||
|
position: absolute;
|
||||||
|
/* please don't change 'position' */
|
||||||
|
background-color: #aaa;
|
||||||
|
-webkit-border-radius: 6px;
|
||||||
|
-moz-border-radius: 6px;
|
||||||
|
border-radius: 6px;
|
||||||
|
-webkit-transition: background-color .2s linear, height .2s linear, width .2s ease-in-out, -webkit-border-radius .2s ease-in-out;
|
||||||
|
transition: background-color .2s linear, height .2s linear, width .2s ease-in-out, -webkit-border-radius .2s ease-in-out;
|
||||||
|
-o-transition: background-color .2s linear, height .2s linear, width .2s ease-in-out, border-radius .2s ease-in-out;
|
||||||
|
-moz-transition: background-color .2s linear, height .2s linear, width .2s ease-in-out, border-radius .2s ease-in-out, -moz-border-radius .2s ease-in-out;
|
||||||
|
transition: background-color .2s linear, height .2s linear, width .2s ease-in-out, border-radius .2s ease-in-out;
|
||||||
|
transition: background-color .2s linear, height .2s linear, width .2s ease-in-out, border-radius .2s ease-in-out, -webkit-border-radius .2s ease-in-out, -moz-border-radius .2s ease-in-out;
|
||||||
|
right: 2px;
|
||||||
|
/* there must be 'right' for ps-scrollbar-y */
|
||||||
|
width: 6px; }
|
||||||
|
.ps-container > .ps-scrollbar-y-rail:hover > .ps-scrollbar-y, .ps-container > .ps-scrollbar-y-rail:active > .ps-scrollbar-y {
|
||||||
|
width: 11px; }
|
||||||
|
.ps-container:hover.ps-in-scrolling.ps-x > .ps-scrollbar-x-rail {
|
||||||
|
background-color: #eee;
|
||||||
|
opacity: 0.9; }
|
||||||
|
.ps-container:hover.ps-in-scrolling.ps-x > .ps-scrollbar-x-rail > .ps-scrollbar-x {
|
||||||
|
background-color: #999;
|
||||||
|
height: 11px; }
|
||||||
|
.ps-container:hover.ps-in-scrolling.ps-y > .ps-scrollbar-y-rail {
|
||||||
|
background-color: #eee;
|
||||||
|
opacity: 0.9; }
|
||||||
|
.ps-container:hover.ps-in-scrolling.ps-y > .ps-scrollbar-y-rail > .ps-scrollbar-y {
|
||||||
|
background-color: #999;
|
||||||
|
width: 11px; }
|
||||||
|
.ps-container:hover > .ps-scrollbar-x-rail,
|
||||||
|
.ps-container:hover > .ps-scrollbar-y-rail {
|
||||||
|
opacity: 0.6; }
|
||||||
|
.ps-container:hover > .ps-scrollbar-x-rail:hover {
|
||||||
|
background-color: #eee;
|
||||||
|
opacity: 0.9; }
|
||||||
|
.ps-container:hover > .ps-scrollbar-x-rail:hover > .ps-scrollbar-x {
|
||||||
|
background-color: #999; }
|
||||||
|
.ps-container:hover > .ps-scrollbar-y-rail:hover {
|
||||||
|
background-color: #eee;
|
||||||
|
opacity: 0.9; }
|
||||||
|
.ps-container:hover > .ps-scrollbar-y-rail:hover > .ps-scrollbar-y {
|
||||||
|
background-color: #999; }
|
2
view/js/perfect-scrollbar/css/perfect-scrollbar.min.css
vendored
Normal file
2
view/js/perfect-scrollbar/css/perfect-scrollbar.min.css
vendored
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
/* perfect-scrollbar v0.6.16 */
|
||||||
|
.ps-container{-ms-touch-action:auto;touch-action:auto;overflow:hidden !important;-ms-overflow-style:none}@supports (-ms-overflow-style: none){.ps-container{overflow:auto !important}}@media screen and (-ms-high-contrast: active), (-ms-high-contrast: none){.ps-container{overflow:auto !important}}.ps-container.ps-active-x>.ps-scrollbar-x-rail,.ps-container.ps-active-y>.ps-scrollbar-y-rail{display:block;background-color:transparent}.ps-container.ps-in-scrolling.ps-x>.ps-scrollbar-x-rail{background-color:#eee;opacity:.9}.ps-container.ps-in-scrolling.ps-x>.ps-scrollbar-x-rail>.ps-scrollbar-x{background-color:#999;height:11px}.ps-container.ps-in-scrolling.ps-y>.ps-scrollbar-y-rail{background-color:#eee;opacity:.9}.ps-container.ps-in-scrolling.ps-y>.ps-scrollbar-y-rail>.ps-scrollbar-y{background-color:#999;width:11px}.ps-container>.ps-scrollbar-x-rail{display:none;position:absolute;opacity:0;-webkit-transition:background-color .2s linear, opacity .2s linear;-o-transition:background-color .2s linear, opacity .2s linear;-moz-transition:background-color .2s linear, opacity .2s linear;transition:background-color .2s linear, opacity .2s linear;bottom:0px;height:15px}.ps-container>.ps-scrollbar-x-rail>.ps-scrollbar-x{position:absolute;background-color:#aaa;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-transition:background-color .2s linear, height .2s linear, width .2s ease-in-out, -webkit-border-radius .2s ease-in-out;transition:background-color .2s linear, height .2s linear, width .2s ease-in-out, -webkit-border-radius .2s ease-in-out;-o-transition:background-color .2s linear, height .2s linear, width .2s ease-in-out, border-radius .2s ease-in-out;-moz-transition:background-color .2s linear, height .2s linear, width .2s ease-in-out, border-radius .2s ease-in-out, -moz-border-radius .2s ease-in-out;transition:background-color .2s linear, height .2s linear, width .2s ease-in-out, border-radius .2s ease-in-out;transition:background-color .2s linear, height .2s linear, width .2s ease-in-out, border-radius .2s ease-in-out, -webkit-border-radius .2s ease-in-out, -moz-border-radius .2s ease-in-out;bottom:2px;height:6px}.ps-container>.ps-scrollbar-x-rail:hover>.ps-scrollbar-x,.ps-container>.ps-scrollbar-x-rail:active>.ps-scrollbar-x{height:11px}.ps-container>.ps-scrollbar-y-rail{display:none;position:absolute;opacity:0;-webkit-transition:background-color .2s linear, opacity .2s linear;-o-transition:background-color .2s linear, opacity .2s linear;-moz-transition:background-color .2s linear, opacity .2s linear;transition:background-color .2s linear, opacity .2s linear;right:0;width:15px}.ps-container>.ps-scrollbar-y-rail>.ps-scrollbar-y{position:absolute;background-color:#aaa;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-transition:background-color .2s linear, height .2s linear, width .2s ease-in-out, -webkit-border-radius .2s ease-in-out;transition:background-color .2s linear, height .2s linear, width .2s ease-in-out, -webkit-border-radius .2s ease-in-out;-o-transition:background-color .2s linear, height .2s linear, width .2s ease-in-out, border-radius .2s ease-in-out;-moz-transition:background-color .2s linear, height .2s linear, width .2s ease-in-out, border-radius .2s ease-in-out, -moz-border-radius .2s ease-in-out;transition:background-color .2s linear, height .2s linear, width .2s ease-in-out, border-radius .2s ease-in-out;transition:background-color .2s linear, height .2s linear, width .2s ease-in-out, border-radius .2s ease-in-out, -webkit-border-radius .2s ease-in-out, -moz-border-radius .2s ease-in-out;right:2px;width:6px}.ps-container>.ps-scrollbar-y-rail:hover>.ps-scrollbar-y,.ps-container>.ps-scrollbar-y-rail:active>.ps-scrollbar-y{width:11px}.ps-container:hover.ps-in-scrolling.ps-x>.ps-scrollbar-x-rail{background-color:#eee;opacity:.9}.ps-container:hover.ps-in-scrolling.ps-x>.ps-scrollbar-x-rail>.ps-scrollbar-x{background-color:#999;height:11px}.ps-container:hover.ps-in-scrolling.ps-y>.ps-scrollbar-y-rail{background-color:#eee;opacity:.9}.ps-container:hover.ps-in-scrolling.ps-y>.ps-scrollbar-y-rail>.ps-scrollbar-y{background-color:#999;width:11px}.ps-container:hover>.ps-scrollbar-x-rail,.ps-container:hover>.ps-scrollbar-y-rail{opacity:.6}.ps-container:hover>.ps-scrollbar-x-rail:hover{background-color:#eee;opacity:.9}.ps-container:hover>.ps-scrollbar-x-rail:hover>.ps-scrollbar-x{background-color:#999}.ps-container:hover>.ps-scrollbar-y-rail:hover{background-color:#eee;opacity:.9}.ps-container:hover>.ps-scrollbar-y-rail:hover>.ps-scrollbar-y{background-color:#999}
|
1577
view/js/perfect-scrollbar/js/perfect-scrollbar.jquery.js
Normal file
1577
view/js/perfect-scrollbar/js/perfect-scrollbar.jquery.js
Normal file
File diff suppressed because it is too large
Load diff
2
view/js/perfect-scrollbar/js/perfect-scrollbar.jquery.min.js
vendored
Normal file
2
view/js/perfect-scrollbar/js/perfect-scrollbar.jquery.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1550
view/js/perfect-scrollbar/js/perfect-scrollbar.js
Normal file
1550
view/js/perfect-scrollbar/js/perfect-scrollbar.js
Normal file
File diff suppressed because it is too large
Load diff
2
view/js/perfect-scrollbar/js/perfect-scrollbar.min.js
vendored
Normal file
2
view/js/perfect-scrollbar/js/perfect-scrollbar.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
3
view/js/perfect-scrollbar/src/css/main.scss
Normal file
3
view/js/perfect-scrollbar/src/css/main.scss
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
@import 'variables';
|
||||||
|
@import 'mixins';
|
||||||
|
@import 'themes';
|
128
view/js/perfect-scrollbar/src/css/mixins.scss
Normal file
128
view/js/perfect-scrollbar/src/css/mixins.scss
Normal file
|
@ -0,0 +1,128 @@
|
||||||
|
@mixin scrollbar-rail-default($theme) {
|
||||||
|
display: none;
|
||||||
|
position: absolute; /* please don't change 'position' */
|
||||||
|
opacity: map_get($theme, rail-default-opacity);
|
||||||
|
transition: background-color .2s linear, opacity .2s linear;
|
||||||
|
}
|
||||||
|
|
||||||
|
@mixin scrollbar-rail-hover($theme) {
|
||||||
|
background-color: map_get($theme, rail-hover-bg);
|
||||||
|
opacity: map_get($theme, rail-hover-opacity);
|
||||||
|
}
|
||||||
|
|
||||||
|
@mixin scrollbar-default($theme) {
|
||||||
|
position: absolute; /* please don't change 'position' */
|
||||||
|
background-color: map_get($theme, bar-container-hover-bg);
|
||||||
|
border-radius: map_get($theme, border-radius);
|
||||||
|
transition: background-color .2s linear, height .2s linear, width .2s ease-in-out,
|
||||||
|
border-radius .2s ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
@mixin scrollbar-hover($theme) {
|
||||||
|
background-color: map_get($theme, bar-hover-bg);
|
||||||
|
}
|
||||||
|
|
||||||
|
@mixin in-scrolling($theme) {
|
||||||
|
&.ps-in-scrolling {
|
||||||
|
&.ps-x > .ps-scrollbar-x-rail {
|
||||||
|
@include scrollbar-rail-hover($theme);
|
||||||
|
> .ps-scrollbar-x {
|
||||||
|
@include scrollbar-hover($theme);
|
||||||
|
height: map_get($theme, scrollbar-x-hover-height);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&.ps-y > .ps-scrollbar-y-rail {
|
||||||
|
@include scrollbar-rail-hover($theme);
|
||||||
|
> .ps-scrollbar-y {
|
||||||
|
@include scrollbar-hover($theme);
|
||||||
|
width: map_get($theme, scrollbar-y-hover-width);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Layout and theme mixin
|
||||||
|
@mixin ps-container($theme) {
|
||||||
|
-ms-touch-action: auto;
|
||||||
|
touch-action: auto;
|
||||||
|
overflow: hidden !important;
|
||||||
|
-ms-overflow-style: none;
|
||||||
|
|
||||||
|
// Edge
|
||||||
|
@supports (-ms-overflow-style: none) {
|
||||||
|
overflow: auto !important;
|
||||||
|
}
|
||||||
|
// IE10+
|
||||||
|
@media screen and (-ms-high-contrast: active), (-ms-high-contrast: none) {
|
||||||
|
overflow: auto !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.ps-active-x > .ps-scrollbar-x-rail,
|
||||||
|
&.ps-active-y > .ps-scrollbar-y-rail {
|
||||||
|
display: block;
|
||||||
|
background-color: map_get($theme, bar-bg);
|
||||||
|
}
|
||||||
|
|
||||||
|
@include in-scrolling($theme);
|
||||||
|
|
||||||
|
> .ps-scrollbar-x-rail {
|
||||||
|
@include scrollbar-rail-default($theme);
|
||||||
|
bottom: map_get($theme, scrollbar-x-rail-bottom); /* there must be 'bottom' for ps-scrollbar-x-rail */
|
||||||
|
height: map_get($theme, scrollbar-x-rail-height);
|
||||||
|
|
||||||
|
> .ps-scrollbar-x {
|
||||||
|
@include scrollbar-default($theme);
|
||||||
|
bottom: map_get($theme, scrollbar-x-bottom); /* there must be 'bottom' for ps-scrollbar-x */
|
||||||
|
height: map_get($theme, scrollbar-x-height);
|
||||||
|
}
|
||||||
|
&:hover,
|
||||||
|
&:active {
|
||||||
|
> .ps-scrollbar-x {
|
||||||
|
height: map_get($theme, scrollbar-x-hover-height);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
> .ps-scrollbar-y-rail {
|
||||||
|
@include scrollbar-rail-default($theme);
|
||||||
|
right: map_get($theme, scrollbar-y-rail-right); /* there must be 'right' for ps-scrollbar-y-rail */
|
||||||
|
width: map_get($theme, scrollbar-y-rail-width);
|
||||||
|
|
||||||
|
> .ps-scrollbar-y {
|
||||||
|
@include scrollbar-default($theme);
|
||||||
|
right: map_get($theme, scrollbar-y-right); /* there must be 'right' for ps-scrollbar-y */
|
||||||
|
width: map_get($theme, scrollbar-y-width);
|
||||||
|
}
|
||||||
|
&:hover,
|
||||||
|
&:active {
|
||||||
|
> .ps-scrollbar-y {
|
||||||
|
width: map_get($theme, scrollbar-y-hover-width);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
@include in-scrolling($theme);
|
||||||
|
|
||||||
|
> .ps-scrollbar-x-rail,
|
||||||
|
> .ps-scrollbar-y-rail {
|
||||||
|
opacity: map_get($theme, rail-container-hover-opacity);
|
||||||
|
}
|
||||||
|
|
||||||
|
> .ps-scrollbar-x-rail:hover {
|
||||||
|
@include scrollbar-rail-hover($theme);
|
||||||
|
|
||||||
|
> .ps-scrollbar-x {
|
||||||
|
@include scrollbar-hover($theme);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
> .ps-scrollbar-y-rail:hover {
|
||||||
|
@include scrollbar-rail-hover($theme);
|
||||||
|
|
||||||
|
> .ps-scrollbar-y {
|
||||||
|
@include scrollbar-hover($theme);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
25
view/js/perfect-scrollbar/src/css/themes.scss
Normal file
25
view/js/perfect-scrollbar/src/css/themes.scss
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
$ps-theme-default: (
|
||||||
|
border-radius: $ps-border-radius,
|
||||||
|
rail-default-opacity: $ps-rail-default-opacity,
|
||||||
|
rail-container-hover-opacity: $ps-rail-container-hover-opacity,
|
||||||
|
rail-hover-opacity: $ps-rail-hover-opacity,
|
||||||
|
bar-bg: $ps-bar-bg,
|
||||||
|
bar-container-hover-bg: $ps-bar-container-hover-bg,
|
||||||
|
bar-hover-bg: $ps-bar-hover-bg,
|
||||||
|
rail-hover-bg: $ps-rail-hover-bg,
|
||||||
|
scrollbar-x-rail-bottom: $ps-scrollbar-x-rail-bottom,
|
||||||
|
scrollbar-x-rail-height: $ps-scrollbar-x-rail-height,
|
||||||
|
scrollbar-x-bottom: $ps-scrollbar-x-bottom,
|
||||||
|
scrollbar-x-height: $ps-scrollbar-x-height,
|
||||||
|
scrollbar-x-hover-height: $ps-scrollbar-x-hover-height,
|
||||||
|
scrollbar-y-rail-right: $ps-scrollbar-y-rail-right,
|
||||||
|
scrollbar-y-rail-width: $ps-scrollbar-y-rail-width,
|
||||||
|
scrollbar-y-right: $ps-scrollbar-y-right,
|
||||||
|
scrollbar-y-width: $ps-scrollbar-y-width,
|
||||||
|
scrollbar-y-hover-width: $ps-scrollbar-y-hover-width,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Default theme
|
||||||
|
.ps-container {
|
||||||
|
@include ps-container($ps-theme-default);
|
||||||
|
}
|
24
view/js/perfect-scrollbar/src/css/variables.scss
Normal file
24
view/js/perfect-scrollbar/src/css/variables.scss
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
// Colors
|
||||||
|
$ps-border-radius: 6px !default;
|
||||||
|
|
||||||
|
$ps-rail-default-opacity: 0 !default;
|
||||||
|
$ps-rail-container-hover-opacity: 0.6 !default;
|
||||||
|
$ps-rail-hover-opacity: 0.9 !default;
|
||||||
|
|
||||||
|
$ps-bar-bg: transparent !default;
|
||||||
|
$ps-bar-container-hover-bg: #aaa !default;
|
||||||
|
$ps-bar-hover-bg: #999 !default;
|
||||||
|
$ps-rail-hover-bg: #eee !default;
|
||||||
|
|
||||||
|
// Sizes
|
||||||
|
$ps-scrollbar-x-rail-bottom: 0px !default;
|
||||||
|
$ps-scrollbar-x-rail-height: 15px !default;
|
||||||
|
$ps-scrollbar-x-bottom: 2px !default;
|
||||||
|
$ps-scrollbar-x-height: 6px !default;
|
||||||
|
$ps-scrollbar-x-hover-height: 11px !default;
|
||||||
|
|
||||||
|
$ps-scrollbar-y-rail-right: 0 !default;
|
||||||
|
$ps-scrollbar-y-rail-width: 15px !default;
|
||||||
|
$ps-scrollbar-y-right: 2px !default;
|
||||||
|
$ps-scrollbar-y-width: 6px !default;
|
||||||
|
$ps-scrollbar-y-hover-width: 11px !default;
|
14
view/js/perfect-scrollbar/src/js/adaptor/global.js
Normal file
14
view/js/perfect-scrollbar/src/js/adaptor/global.js
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var ps = require('../main');
|
||||||
|
|
||||||
|
if (typeof define === 'function' && define.amd) {
|
||||||
|
// AMD
|
||||||
|
define(ps);
|
||||||
|
} else {
|
||||||
|
// Add to a global object.
|
||||||
|
window.PerfectScrollbar = ps;
|
||||||
|
if (typeof window.Ps === 'undefined') {
|
||||||
|
window.Ps = ps;
|
||||||
|
}
|
||||||
|
}
|
41
view/js/perfect-scrollbar/src/js/adaptor/jquery.js
vendored
Normal file
41
view/js/perfect-scrollbar/src/js/adaptor/jquery.js
vendored
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var ps = require('../main');
|
||||||
|
var psInstances = require('../plugin/instances');
|
||||||
|
|
||||||
|
function mountJQuery(jQuery) {
|
||||||
|
jQuery.fn.perfectScrollbar = function (settingOrCommand) {
|
||||||
|
return this.each(function () {
|
||||||
|
if (typeof settingOrCommand === 'object' ||
|
||||||
|
typeof settingOrCommand === 'undefined') {
|
||||||
|
// If it's an object or none, initialize.
|
||||||
|
var settings = settingOrCommand;
|
||||||
|
|
||||||
|
if (!psInstances.get(this)) {
|
||||||
|
ps.initialize(this, settings);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Unless, it may be a command.
|
||||||
|
var command = settingOrCommand;
|
||||||
|
|
||||||
|
if (command === 'update') {
|
||||||
|
ps.update(this);
|
||||||
|
} else if (command === 'destroy') {
|
||||||
|
ps.destroy(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof define === 'function' && define.amd) {
|
||||||
|
// AMD. Register as an anonymous module.
|
||||||
|
define(['jquery'], mountJQuery);
|
||||||
|
} else {
|
||||||
|
var jq = window.jQuery ? window.jQuery : window.$;
|
||||||
|
if (typeof jq !== 'undefined') {
|
||||||
|
mountJQuery(jq);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = mountJQuery;
|
42
view/js/perfect-scrollbar/src/js/lib/class.js
Normal file
42
view/js/perfect-scrollbar/src/js/lib/class.js
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
function oldAdd(element, className) {
|
||||||
|
var classes = element.className.split(' ');
|
||||||
|
if (classes.indexOf(className) < 0) {
|
||||||
|
classes.push(className);
|
||||||
|
}
|
||||||
|
element.className = classes.join(' ');
|
||||||
|
}
|
||||||
|
|
||||||
|
function oldRemove(element, className) {
|
||||||
|
var classes = element.className.split(' ');
|
||||||
|
var idx = classes.indexOf(className);
|
||||||
|
if (idx >= 0) {
|
||||||
|
classes.splice(idx, 1);
|
||||||
|
}
|
||||||
|
element.className = classes.join(' ');
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.add = function (element, className) {
|
||||||
|
if (element.classList) {
|
||||||
|
element.classList.add(className);
|
||||||
|
} else {
|
||||||
|
oldAdd(element, className);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.remove = function (element, className) {
|
||||||
|
if (element.classList) {
|
||||||
|
element.classList.remove(className);
|
||||||
|
} else {
|
||||||
|
oldRemove(element, className);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.list = function (element) {
|
||||||
|
if (element.classList) {
|
||||||
|
return Array.prototype.slice.apply(element.classList);
|
||||||
|
} else {
|
||||||
|
return element.className.split(' ');
|
||||||
|
}
|
||||||
|
};
|
84
view/js/perfect-scrollbar/src/js/lib/dom.js
Normal file
84
view/js/perfect-scrollbar/src/js/lib/dom.js
Normal file
|
@ -0,0 +1,84 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var DOM = {};
|
||||||
|
|
||||||
|
DOM.e = function (tagName, className) {
|
||||||
|
var element = document.createElement(tagName);
|
||||||
|
element.className = className;
|
||||||
|
return element;
|
||||||
|
};
|
||||||
|
|
||||||
|
DOM.appendTo = function (child, parent) {
|
||||||
|
parent.appendChild(child);
|
||||||
|
return child;
|
||||||
|
};
|
||||||
|
|
||||||
|
function cssGet(element, styleName) {
|
||||||
|
return window.getComputedStyle(element)[styleName];
|
||||||
|
}
|
||||||
|
|
||||||
|
function cssSet(element, styleName, styleValue) {
|
||||||
|
if (typeof styleValue === 'number') {
|
||||||
|
styleValue = styleValue.toString() + 'px';
|
||||||
|
}
|
||||||
|
element.style[styleName] = styleValue;
|
||||||
|
return element;
|
||||||
|
}
|
||||||
|
|
||||||
|
function cssMultiSet(element, obj) {
|
||||||
|
for (var key in obj) {
|
||||||
|
var val = obj[key];
|
||||||
|
if (typeof val === 'number') {
|
||||||
|
val = val.toString() + 'px';
|
||||||
|
}
|
||||||
|
element.style[key] = val;
|
||||||
|
}
|
||||||
|
return element;
|
||||||
|
}
|
||||||
|
|
||||||
|
DOM.css = function (element, styleNameOrObject, styleValue) {
|
||||||
|
if (typeof styleNameOrObject === 'object') {
|
||||||
|
// multiple set with object
|
||||||
|
return cssMultiSet(element, styleNameOrObject);
|
||||||
|
} else {
|
||||||
|
if (typeof styleValue === 'undefined') {
|
||||||
|
return cssGet(element, styleNameOrObject);
|
||||||
|
} else {
|
||||||
|
return cssSet(element, styleNameOrObject, styleValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
DOM.matches = function (element, query) {
|
||||||
|
if (typeof element.matches !== 'undefined') {
|
||||||
|
return element.matches(query);
|
||||||
|
} else {
|
||||||
|
if (typeof element.matchesSelector !== 'undefined') {
|
||||||
|
return element.matchesSelector(query);
|
||||||
|
} else if (typeof element.webkitMatchesSelector !== 'undefined') {
|
||||||
|
return element.webkitMatchesSelector(query);
|
||||||
|
} else if (typeof element.mozMatchesSelector !== 'undefined') {
|
||||||
|
return element.mozMatchesSelector(query);
|
||||||
|
} else if (typeof element.msMatchesSelector !== 'undefined') {
|
||||||
|
return element.msMatchesSelector(query);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
DOM.remove = function (element) {
|
||||||
|
if (typeof element.remove !== 'undefined') {
|
||||||
|
element.remove();
|
||||||
|
} else {
|
||||||
|
if (element.parentNode) {
|
||||||
|
element.parentNode.removeChild(element);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
DOM.queryChildren = function (element, selector) {
|
||||||
|
return Array.prototype.filter.call(element.childNodes, function (child) {
|
||||||
|
return DOM.matches(child, selector);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = DOM;
|
71
view/js/perfect-scrollbar/src/js/lib/event-manager.js
Normal file
71
view/js/perfect-scrollbar/src/js/lib/event-manager.js
Normal file
|
@ -0,0 +1,71 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var EventElement = function (element) {
|
||||||
|
this.element = element;
|
||||||
|
this.events = {};
|
||||||
|
};
|
||||||
|
|
||||||
|
EventElement.prototype.bind = function (eventName, handler) {
|
||||||
|
if (typeof this.events[eventName] === 'undefined') {
|
||||||
|
this.events[eventName] = [];
|
||||||
|
}
|
||||||
|
this.events[eventName].push(handler);
|
||||||
|
this.element.addEventListener(eventName, handler, false);
|
||||||
|
};
|
||||||
|
|
||||||
|
EventElement.prototype.unbind = function (eventName, handler) {
|
||||||
|
var isHandlerProvided = (typeof handler !== 'undefined');
|
||||||
|
this.events[eventName] = this.events[eventName].filter(function (hdlr) {
|
||||||
|
if (isHandlerProvided && hdlr !== handler) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
this.element.removeEventListener(eventName, hdlr, false);
|
||||||
|
return false;
|
||||||
|
}, this);
|
||||||
|
};
|
||||||
|
|
||||||
|
EventElement.prototype.unbindAll = function () {
|
||||||
|
for (var name in this.events) {
|
||||||
|
this.unbind(name);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var EventManager = function () {
|
||||||
|
this.eventElements = [];
|
||||||
|
};
|
||||||
|
|
||||||
|
EventManager.prototype.eventElement = function (element) {
|
||||||
|
var ee = this.eventElements.filter(function (eventElement) {
|
||||||
|
return eventElement.element === element;
|
||||||
|
})[0];
|
||||||
|
if (typeof ee === 'undefined') {
|
||||||
|
ee = new EventElement(element);
|
||||||
|
this.eventElements.push(ee);
|
||||||
|
}
|
||||||
|
return ee;
|
||||||
|
};
|
||||||
|
|
||||||
|
EventManager.prototype.bind = function (element, eventName, handler) {
|
||||||
|
this.eventElement(element).bind(eventName, handler);
|
||||||
|
};
|
||||||
|
|
||||||
|
EventManager.prototype.unbind = function (element, eventName, handler) {
|
||||||
|
this.eventElement(element).unbind(eventName, handler);
|
||||||
|
};
|
||||||
|
|
||||||
|
EventManager.prototype.unbindAll = function () {
|
||||||
|
for (var i = 0; i < this.eventElements.length; i++) {
|
||||||
|
this.eventElements[i].unbindAll();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
EventManager.prototype.once = function (element, eventName, handler) {
|
||||||
|
var ee = this.eventElement(element);
|
||||||
|
var onceHandler = function (e) {
|
||||||
|
ee.unbind(eventName, onceHandler);
|
||||||
|
handler(e);
|
||||||
|
};
|
||||||
|
ee.bind(eventName, onceHandler);
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = EventManager;
|
13
view/js/perfect-scrollbar/src/js/lib/guid.js
Normal file
13
view/js/perfect-scrollbar/src/js/lib/guid.js
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
module.exports = (function () {
|
||||||
|
function s4() {
|
||||||
|
return Math.floor((1 + Math.random()) * 0x10000)
|
||||||
|
.toString(16)
|
||||||
|
.substring(1);
|
||||||
|
}
|
||||||
|
return function () {
|
||||||
|
return s4() + s4() + '-' + s4() + '-' + s4() + '-' +
|
||||||
|
s4() + '-' + s4() + s4() + s4();
|
||||||
|
};
|
||||||
|
})();
|
83
view/js/perfect-scrollbar/src/js/lib/helper.js
Normal file
83
view/js/perfect-scrollbar/src/js/lib/helper.js
Normal file
|
@ -0,0 +1,83 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var cls = require('./class');
|
||||||
|
var dom = require('./dom');
|
||||||
|
|
||||||
|
var toInt = exports.toInt = function (x) {
|
||||||
|
return parseInt(x, 10) || 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
var clone = exports.clone = function (obj) {
|
||||||
|
if (!obj) {
|
||||||
|
return null;
|
||||||
|
} else if (obj.constructor === Array) {
|
||||||
|
return obj.map(clone);
|
||||||
|
} else if (typeof obj === 'object') {
|
||||||
|
var result = {};
|
||||||
|
for (var key in obj) {
|
||||||
|
result[key] = clone(obj[key]);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
} else {
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.extend = function (original, source) {
|
||||||
|
var result = clone(original);
|
||||||
|
for (var key in source) {
|
||||||
|
result[key] = clone(source[key]);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.isEditable = function (el) {
|
||||||
|
return dom.matches(el, "input,[contenteditable]") ||
|
||||||
|
dom.matches(el, "select,[contenteditable]") ||
|
||||||
|
dom.matches(el, "textarea,[contenteditable]") ||
|
||||||
|
dom.matches(el, "button,[contenteditable]");
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.removePsClasses = function (element) {
|
||||||
|
var clsList = cls.list(element);
|
||||||
|
for (var i = 0; i < clsList.length; i++) {
|
||||||
|
var className = clsList[i];
|
||||||
|
if (className.indexOf('ps-') === 0) {
|
||||||
|
cls.remove(element, className);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.outerWidth = function (element) {
|
||||||
|
return toInt(dom.css(element, 'width')) +
|
||||||
|
toInt(dom.css(element, 'paddingLeft')) +
|
||||||
|
toInt(dom.css(element, 'paddingRight')) +
|
||||||
|
toInt(dom.css(element, 'borderLeftWidth')) +
|
||||||
|
toInt(dom.css(element, 'borderRightWidth'));
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.startScrolling = function (element, axis) {
|
||||||
|
cls.add(element, 'ps-in-scrolling');
|
||||||
|
if (typeof axis !== 'undefined') {
|
||||||
|
cls.add(element, 'ps-' + axis);
|
||||||
|
} else {
|
||||||
|
cls.add(element, 'ps-x');
|
||||||
|
cls.add(element, 'ps-y');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.stopScrolling = function (element, axis) {
|
||||||
|
cls.remove(element, 'ps-in-scrolling');
|
||||||
|
if (typeof axis !== 'undefined') {
|
||||||
|
cls.remove(element, 'ps-' + axis);
|
||||||
|
} else {
|
||||||
|
cls.remove(element, 'ps-x');
|
||||||
|
cls.remove(element, 'ps-y');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.env = {
|
||||||
|
isWebKit: 'WebkitAppearance' in document.documentElement.style,
|
||||||
|
supportsTouch: (('ontouchstart' in window) || window.DocumentTouch && document instanceof window.DocumentTouch),
|
||||||
|
supportsIePointer: window.navigator.msMaxTouchPoints !== null
|
||||||
|
};
|
11
view/js/perfect-scrollbar/src/js/main.js
Normal file
11
view/js/perfect-scrollbar/src/js/main.js
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var destroy = require('./plugin/destroy');
|
||||||
|
var initialize = require('./plugin/initialize');
|
||||||
|
var update = require('./plugin/update');
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
initialize: initialize,
|
||||||
|
update: update,
|
||||||
|
destroy: destroy
|
||||||
|
};
|
16
view/js/perfect-scrollbar/src/js/plugin/default-setting.js
Normal file
16
view/js/perfect-scrollbar/src/js/plugin/default-setting.js
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
handlers: ['click-rail', 'drag-scrollbar', 'keyboard', 'wheel', 'touch'],
|
||||||
|
maxScrollbarLength: null,
|
||||||
|
minScrollbarLength: null,
|
||||||
|
scrollXMarginOffset: 0,
|
||||||
|
scrollYMarginOffset: 0,
|
||||||
|
suppressScrollX: false,
|
||||||
|
suppressScrollY: false,
|
||||||
|
swipePropagation: true,
|
||||||
|
useBothWheelAxes: false,
|
||||||
|
wheelPropagation: false,
|
||||||
|
wheelSpeed: 1,
|
||||||
|
theme: 'default'
|
||||||
|
};
|
22
view/js/perfect-scrollbar/src/js/plugin/destroy.js
Normal file
22
view/js/perfect-scrollbar/src/js/plugin/destroy.js
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var _ = require('../lib/helper');
|
||||||
|
var dom = require('../lib/dom');
|
||||||
|
var instances = require('./instances');
|
||||||
|
|
||||||
|
module.exports = function (element) {
|
||||||
|
var i = instances.get(element);
|
||||||
|
|
||||||
|
if (!i) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
i.event.unbindAll();
|
||||||
|
dom.remove(i.scrollbarX);
|
||||||
|
dom.remove(i.scrollbarY);
|
||||||
|
dom.remove(i.scrollbarXRail);
|
||||||
|
dom.remove(i.scrollbarYRail);
|
||||||
|
_.removePsClasses(element);
|
||||||
|
|
||||||
|
instances.remove(element);
|
||||||
|
};
|
|
@ -0,0 +1,39 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var instances = require('../instances');
|
||||||
|
var updateGeometry = require('../update-geometry');
|
||||||
|
var updateScroll = require('../update-scroll');
|
||||||
|
|
||||||
|
function bindClickRailHandler(element, i) {
|
||||||
|
function pageOffset(el) {
|
||||||
|
return el.getBoundingClientRect();
|
||||||
|
}
|
||||||
|
var stopPropagation = function (e) { e.stopPropagation(); };
|
||||||
|
|
||||||
|
i.event.bind(i.scrollbarY, 'click', stopPropagation);
|
||||||
|
i.event.bind(i.scrollbarYRail, 'click', function (e) {
|
||||||
|
var positionTop = e.pageY - window.pageYOffset - pageOffset(i.scrollbarYRail).top;
|
||||||
|
var direction = positionTop > i.scrollbarYTop ? 1 : -1;
|
||||||
|
|
||||||
|
updateScroll(element, 'top', element.scrollTop + direction * i.containerHeight);
|
||||||
|
updateGeometry(element);
|
||||||
|
|
||||||
|
e.stopPropagation();
|
||||||
|
});
|
||||||
|
|
||||||
|
i.event.bind(i.scrollbarX, 'click', stopPropagation);
|
||||||
|
i.event.bind(i.scrollbarXRail, 'click', function (e) {
|
||||||
|
var positionLeft = e.pageX - window.pageXOffset - pageOffset(i.scrollbarXRail).left;
|
||||||
|
var direction = positionLeft > i.scrollbarXLeft ? 1 : -1;
|
||||||
|
|
||||||
|
updateScroll(element, 'left', element.scrollLeft + direction * i.containerWidth);
|
||||||
|
updateGeometry(element);
|
||||||
|
|
||||||
|
e.stopPropagation();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = function (element) {
|
||||||
|
var i = instances.get(element);
|
||||||
|
bindClickRailHandler(element, i);
|
||||||
|
};
|
|
@ -0,0 +1,103 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var _ = require('../../lib/helper');
|
||||||
|
var dom = require('../../lib/dom');
|
||||||
|
var instances = require('../instances');
|
||||||
|
var updateGeometry = require('../update-geometry');
|
||||||
|
var updateScroll = require('../update-scroll');
|
||||||
|
|
||||||
|
function bindMouseScrollXHandler(element, i) {
|
||||||
|
var currentLeft = null;
|
||||||
|
var currentPageX = null;
|
||||||
|
|
||||||
|
function updateScrollLeft(deltaX) {
|
||||||
|
var newLeft = currentLeft + (deltaX * i.railXRatio);
|
||||||
|
var maxLeft = Math.max(0, i.scrollbarXRail.getBoundingClientRect().left) + (i.railXRatio * (i.railXWidth - i.scrollbarXWidth));
|
||||||
|
|
||||||
|
if (newLeft < 0) {
|
||||||
|
i.scrollbarXLeft = 0;
|
||||||
|
} else if (newLeft > maxLeft) {
|
||||||
|
i.scrollbarXLeft = maxLeft;
|
||||||
|
} else {
|
||||||
|
i.scrollbarXLeft = newLeft;
|
||||||
|
}
|
||||||
|
|
||||||
|
var scrollLeft = _.toInt(i.scrollbarXLeft * (i.contentWidth - i.containerWidth) / (i.containerWidth - (i.railXRatio * i.scrollbarXWidth))) - i.negativeScrollAdjustment;
|
||||||
|
updateScroll(element, 'left', scrollLeft);
|
||||||
|
}
|
||||||
|
|
||||||
|
var mouseMoveHandler = function (e) {
|
||||||
|
updateScrollLeft(e.pageX - currentPageX);
|
||||||
|
updateGeometry(element);
|
||||||
|
e.stopPropagation();
|
||||||
|
e.preventDefault();
|
||||||
|
};
|
||||||
|
|
||||||
|
var mouseUpHandler = function () {
|
||||||
|
_.stopScrolling(element, 'x');
|
||||||
|
i.event.unbind(i.ownerDocument, 'mousemove', mouseMoveHandler);
|
||||||
|
};
|
||||||
|
|
||||||
|
i.event.bind(i.scrollbarX, 'mousedown', function (e) {
|
||||||
|
currentPageX = e.pageX;
|
||||||
|
currentLeft = _.toInt(dom.css(i.scrollbarX, 'left')) * i.railXRatio;
|
||||||
|
_.startScrolling(element, 'x');
|
||||||
|
|
||||||
|
i.event.bind(i.ownerDocument, 'mousemove', mouseMoveHandler);
|
||||||
|
i.event.once(i.ownerDocument, 'mouseup', mouseUpHandler);
|
||||||
|
|
||||||
|
e.stopPropagation();
|
||||||
|
e.preventDefault();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function bindMouseScrollYHandler(element, i) {
|
||||||
|
var currentTop = null;
|
||||||
|
var currentPageY = null;
|
||||||
|
|
||||||
|
function updateScrollTop(deltaY) {
|
||||||
|
var newTop = currentTop + (deltaY * i.railYRatio);
|
||||||
|
var maxTop = Math.max(0, i.scrollbarYRail.getBoundingClientRect().top) + (i.railYRatio * (i.railYHeight - i.scrollbarYHeight));
|
||||||
|
|
||||||
|
if (newTop < 0) {
|
||||||
|
i.scrollbarYTop = 0;
|
||||||
|
} else if (newTop > maxTop) {
|
||||||
|
i.scrollbarYTop = maxTop;
|
||||||
|
} else {
|
||||||
|
i.scrollbarYTop = newTop;
|
||||||
|
}
|
||||||
|
|
||||||
|
var scrollTop = _.toInt(i.scrollbarYTop * (i.contentHeight - i.containerHeight) / (i.containerHeight - (i.railYRatio * i.scrollbarYHeight)));
|
||||||
|
updateScroll(element, 'top', scrollTop);
|
||||||
|
}
|
||||||
|
|
||||||
|
var mouseMoveHandler = function (e) {
|
||||||
|
updateScrollTop(e.pageY - currentPageY);
|
||||||
|
updateGeometry(element);
|
||||||
|
e.stopPropagation();
|
||||||
|
e.preventDefault();
|
||||||
|
};
|
||||||
|
|
||||||
|
var mouseUpHandler = function () {
|
||||||
|
_.stopScrolling(element, 'y');
|
||||||
|
i.event.unbind(i.ownerDocument, 'mousemove', mouseMoveHandler);
|
||||||
|
};
|
||||||
|
|
||||||
|
i.event.bind(i.scrollbarY, 'mousedown', function (e) {
|
||||||
|
currentPageY = e.pageY;
|
||||||
|
currentTop = _.toInt(dom.css(i.scrollbarY, 'top')) * i.railYRatio;
|
||||||
|
_.startScrolling(element, 'y');
|
||||||
|
|
||||||
|
i.event.bind(i.ownerDocument, 'mousemove', mouseMoveHandler);
|
||||||
|
i.event.once(i.ownerDocument, 'mouseup', mouseUpHandler);
|
||||||
|
|
||||||
|
e.stopPropagation();
|
||||||
|
e.preventDefault();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = function (element) {
|
||||||
|
var i = instances.get(element);
|
||||||
|
bindMouseScrollXHandler(element, i);
|
||||||
|
bindMouseScrollYHandler(element, i);
|
||||||
|
};
|
154
view/js/perfect-scrollbar/src/js/plugin/handler/keyboard.js
Normal file
154
view/js/perfect-scrollbar/src/js/plugin/handler/keyboard.js
Normal file
|
@ -0,0 +1,154 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var _ = require('../../lib/helper');
|
||||||
|
var dom = require('../../lib/dom');
|
||||||
|
var instances = require('../instances');
|
||||||
|
var updateGeometry = require('../update-geometry');
|
||||||
|
var updateScroll = require('../update-scroll');
|
||||||
|
|
||||||
|
function bindKeyboardHandler(element, i) {
|
||||||
|
var hovered = false;
|
||||||
|
i.event.bind(element, 'mouseenter', function () {
|
||||||
|
hovered = true;
|
||||||
|
});
|
||||||
|
i.event.bind(element, 'mouseleave', function () {
|
||||||
|
hovered = false;
|
||||||
|
});
|
||||||
|
|
||||||
|
var shouldPrevent = false;
|
||||||
|
function shouldPreventDefault(deltaX, deltaY) {
|
||||||
|
var scrollTop = element.scrollTop;
|
||||||
|
if (deltaX === 0) {
|
||||||
|
if (!i.scrollbarYActive) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if ((scrollTop === 0 && deltaY > 0) || (scrollTop >= i.contentHeight - i.containerHeight && deltaY < 0)) {
|
||||||
|
return !i.settings.wheelPropagation;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var scrollLeft = element.scrollLeft;
|
||||||
|
if (deltaY === 0) {
|
||||||
|
if (!i.scrollbarXActive) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if ((scrollLeft === 0 && deltaX < 0) || (scrollLeft >= i.contentWidth - i.containerWidth && deltaX > 0)) {
|
||||||
|
return !i.settings.wheelPropagation;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
i.event.bind(i.ownerDocument, 'keydown', function (e) {
|
||||||
|
if ((e.isDefaultPrevented && e.isDefaultPrevented()) || e.defaultPrevented) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var focused = dom.matches(i.scrollbarX, ':focus') ||
|
||||||
|
dom.matches(i.scrollbarY, ':focus');
|
||||||
|
|
||||||
|
if (!hovered && !focused) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var activeElement = document.activeElement ? document.activeElement : i.ownerDocument.activeElement;
|
||||||
|
if (activeElement) {
|
||||||
|
if (activeElement.tagName === 'IFRAME') {
|
||||||
|
activeElement = activeElement.contentDocument.activeElement;
|
||||||
|
} else {
|
||||||
|
// go deeper if element is a webcomponent
|
||||||
|
while (activeElement.shadowRoot) {
|
||||||
|
activeElement = activeElement.shadowRoot.activeElement;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (_.isEditable(activeElement)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var deltaX = 0;
|
||||||
|
var deltaY = 0;
|
||||||
|
|
||||||
|
switch (e.which) {
|
||||||
|
case 37: // left
|
||||||
|
if (e.metaKey) {
|
||||||
|
deltaX = -i.contentWidth;
|
||||||
|
} else if (e.altKey) {
|
||||||
|
deltaX = -i.containerWidth;
|
||||||
|
} else {
|
||||||
|
deltaX = -30;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 38: // up
|
||||||
|
if (e.metaKey) {
|
||||||
|
deltaY = i.contentHeight;
|
||||||
|
} else if (e.altKey) {
|
||||||
|
deltaY = i.containerHeight;
|
||||||
|
} else {
|
||||||
|
deltaY = 30;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 39: // right
|
||||||
|
if (e.metaKey) {
|
||||||
|
deltaX = i.contentWidth;
|
||||||
|
} else if (e.altKey) {
|
||||||
|
deltaX = i.containerWidth;
|
||||||
|
} else {
|
||||||
|
deltaX = 30;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 40: // down
|
||||||
|
if (e.metaKey) {
|
||||||
|
deltaY = -i.contentHeight;
|
||||||
|
} else if (e.altKey) {
|
||||||
|
deltaY = -i.containerHeight;
|
||||||
|
} else {
|
||||||
|
deltaY = -30;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 33: // page up
|
||||||
|
deltaY = 90;
|
||||||
|
break;
|
||||||
|
case 32: // space bar
|
||||||
|
if (e.shiftKey) {
|
||||||
|
deltaY = 90;
|
||||||
|
} else {
|
||||||
|
deltaY = -90;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 34: // page down
|
||||||
|
deltaY = -90;
|
||||||
|
break;
|
||||||
|
case 35: // end
|
||||||
|
if (e.ctrlKey) {
|
||||||
|
deltaY = -i.contentHeight;
|
||||||
|
} else {
|
||||||
|
deltaY = -i.containerHeight;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 36: // home
|
||||||
|
if (e.ctrlKey) {
|
||||||
|
deltaY = element.scrollTop;
|
||||||
|
} else {
|
||||||
|
deltaY = i.containerHeight;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
updateScroll(element, 'top', element.scrollTop - deltaY);
|
||||||
|
updateScroll(element, 'left', element.scrollLeft + deltaX);
|
||||||
|
updateGeometry(element);
|
||||||
|
|
||||||
|
shouldPrevent = shouldPreventDefault(deltaX, deltaY);
|
||||||
|
if (shouldPrevent) {
|
||||||
|
e.preventDefault();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = function (element) {
|
||||||
|
var i = instances.get(element);
|
||||||
|
bindKeyboardHandler(element, i);
|
||||||
|
};
|
141
view/js/perfect-scrollbar/src/js/plugin/handler/mouse-wheel.js
Normal file
141
view/js/perfect-scrollbar/src/js/plugin/handler/mouse-wheel.js
Normal file
|
@ -0,0 +1,141 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var instances = require('../instances');
|
||||||
|
var updateGeometry = require('../update-geometry');
|
||||||
|
var updateScroll = require('../update-scroll');
|
||||||
|
|
||||||
|
function bindMouseWheelHandler(element, i) {
|
||||||
|
var shouldPrevent = false;
|
||||||
|
|
||||||
|
function shouldPreventDefault(deltaX, deltaY) {
|
||||||
|
var scrollTop = element.scrollTop;
|
||||||
|
if (deltaX === 0) {
|
||||||
|
if (!i.scrollbarYActive) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if ((scrollTop === 0 && deltaY > 0) || (scrollTop >= i.contentHeight - i.containerHeight && deltaY < 0)) {
|
||||||
|
return !i.settings.wheelPropagation;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var scrollLeft = element.scrollLeft;
|
||||||
|
if (deltaY === 0) {
|
||||||
|
if (!i.scrollbarXActive) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if ((scrollLeft === 0 && deltaX < 0) || (scrollLeft >= i.contentWidth - i.containerWidth && deltaX > 0)) {
|
||||||
|
return !i.settings.wheelPropagation;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getDeltaFromEvent(e) {
|
||||||
|
var deltaX = e.deltaX;
|
||||||
|
var deltaY = -1 * e.deltaY;
|
||||||
|
|
||||||
|
if (typeof deltaX === "undefined" || typeof deltaY === "undefined") {
|
||||||
|
// OS X Safari
|
||||||
|
deltaX = -1 * e.wheelDeltaX / 6;
|
||||||
|
deltaY = e.wheelDeltaY / 6;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (e.deltaMode && e.deltaMode === 1) {
|
||||||
|
// Firefox in deltaMode 1: Line scrolling
|
||||||
|
deltaX *= 10;
|
||||||
|
deltaY *= 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (deltaX !== deltaX && deltaY !== deltaY/* NaN checks */) {
|
||||||
|
// IE in some mouse drivers
|
||||||
|
deltaX = 0;
|
||||||
|
deltaY = e.wheelDelta;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (e.shiftKey) {
|
||||||
|
// reverse axis with shift key
|
||||||
|
return [-deltaY, -deltaX];
|
||||||
|
}
|
||||||
|
return [deltaX, deltaY];
|
||||||
|
}
|
||||||
|
|
||||||
|
function shouldBeConsumedByChild(deltaX, deltaY) {
|
||||||
|
var child = element.querySelector('textarea:hover, select[multiple]:hover, .ps-child:hover');
|
||||||
|
if (child) {
|
||||||
|
if (!window.getComputedStyle(child).overflow.match(/(scroll|auto)/)) {
|
||||||
|
// if not scrollable
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var maxScrollTop = child.scrollHeight - child.clientHeight;
|
||||||
|
if (maxScrollTop > 0) {
|
||||||
|
if (!(child.scrollTop === 0 && deltaY > 0) && !(child.scrollTop === maxScrollTop && deltaY < 0)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var maxScrollLeft = child.scrollLeft - child.clientWidth;
|
||||||
|
if (maxScrollLeft > 0) {
|
||||||
|
if (!(child.scrollLeft === 0 && deltaX < 0) && !(child.scrollLeft === maxScrollLeft && deltaX > 0)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function mousewheelHandler(e) {
|
||||||
|
var delta = getDeltaFromEvent(e);
|
||||||
|
|
||||||
|
var deltaX = delta[0];
|
||||||
|
var deltaY = delta[1];
|
||||||
|
|
||||||
|
if (shouldBeConsumedByChild(deltaX, deltaY)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
shouldPrevent = false;
|
||||||
|
if (!i.settings.useBothWheelAxes) {
|
||||||
|
// deltaX will only be used for horizontal scrolling and deltaY will
|
||||||
|
// only be used for vertical scrolling - this is the default
|
||||||
|
updateScroll(element, 'top', element.scrollTop - (deltaY * i.settings.wheelSpeed));
|
||||||
|
updateScroll(element, 'left', element.scrollLeft + (deltaX * i.settings.wheelSpeed));
|
||||||
|
} else if (i.scrollbarYActive && !i.scrollbarXActive) {
|
||||||
|
// only vertical scrollbar is active and useBothWheelAxes option is
|
||||||
|
// active, so let's scroll vertical bar using both mouse wheel axes
|
||||||
|
if (deltaY) {
|
||||||
|
updateScroll(element, 'top', element.scrollTop - (deltaY * i.settings.wheelSpeed));
|
||||||
|
} else {
|
||||||
|
updateScroll(element, 'top', element.scrollTop + (deltaX * i.settings.wheelSpeed));
|
||||||
|
}
|
||||||
|
shouldPrevent = true;
|
||||||
|
} else if (i.scrollbarXActive && !i.scrollbarYActive) {
|
||||||
|
// useBothWheelAxes and only horizontal bar is active, so use both
|
||||||
|
// wheel axes for horizontal bar
|
||||||
|
if (deltaX) {
|
||||||
|
updateScroll(element, 'left', element.scrollLeft + (deltaX * i.settings.wheelSpeed));
|
||||||
|
} else {
|
||||||
|
updateScroll(element, 'left', element.scrollLeft - (deltaY * i.settings.wheelSpeed));
|
||||||
|
}
|
||||||
|
shouldPrevent = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
updateGeometry(element);
|
||||||
|
|
||||||
|
shouldPrevent = (shouldPrevent || shouldPreventDefault(deltaX, deltaY));
|
||||||
|
if (shouldPrevent) {
|
||||||
|
e.stopPropagation();
|
||||||
|
e.preventDefault();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof window.onwheel !== "undefined") {
|
||||||
|
i.event.bind(element, 'wheel', mousewheelHandler);
|
||||||
|
} else if (typeof window.onmousewheel !== "undefined") {
|
||||||
|
i.event.bind(element, 'mousewheel', mousewheelHandler);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = function (element) {
|
||||||
|
var i = instances.get(element);
|
||||||
|
bindMouseWheelHandler(element, i);
|
||||||
|
};
|
|
@ -0,0 +1,15 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var instances = require('../instances');
|
||||||
|
var updateGeometry = require('../update-geometry');
|
||||||
|
|
||||||
|
function bindNativeScrollHandler(element, i) {
|
||||||
|
i.event.bind(element, 'scroll', function () {
|
||||||
|
updateGeometry(element);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = function (element) {
|
||||||
|
var i = instances.get(element);
|
||||||
|
bindNativeScrollHandler(element, i);
|
||||||
|
};
|
115
view/js/perfect-scrollbar/src/js/plugin/handler/selection.js
Normal file
115
view/js/perfect-scrollbar/src/js/plugin/handler/selection.js
Normal file
|
@ -0,0 +1,115 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var _ = require('../../lib/helper');
|
||||||
|
var instances = require('../instances');
|
||||||
|
var updateGeometry = require('../update-geometry');
|
||||||
|
var updateScroll = require('../update-scroll');
|
||||||
|
|
||||||
|
function bindSelectionHandler(element, i) {
|
||||||
|
function getRangeNode() {
|
||||||
|
var selection = window.getSelection ? window.getSelection() :
|
||||||
|
document.getSelection ? document.getSelection() : '';
|
||||||
|
if (selection.toString().length === 0) {
|
||||||
|
return null;
|
||||||
|
} else {
|
||||||
|
return selection.getRangeAt(0).commonAncestorContainer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var scrollingLoop = null;
|
||||||
|
var scrollDiff = {top: 0, left: 0};
|
||||||
|
function startScrolling() {
|
||||||
|
if (!scrollingLoop) {
|
||||||
|
scrollingLoop = setInterval(function () {
|
||||||
|
if (!instances.get(element)) {
|
||||||
|
clearInterval(scrollingLoop);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
updateScroll(element, 'top', element.scrollTop + scrollDiff.top);
|
||||||
|
updateScroll(element, 'left', element.scrollLeft + scrollDiff.left);
|
||||||
|
updateGeometry(element);
|
||||||
|
}, 50); // every .1 sec
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function stopScrolling() {
|
||||||
|
if (scrollingLoop) {
|
||||||
|
clearInterval(scrollingLoop);
|
||||||
|
scrollingLoop = null;
|
||||||
|
}
|
||||||
|
_.stopScrolling(element);
|
||||||
|
}
|
||||||
|
|
||||||
|
var isSelected = false;
|
||||||
|
i.event.bind(i.ownerDocument, 'selectionchange', function () {
|
||||||
|
if (element.contains(getRangeNode())) {
|
||||||
|
isSelected = true;
|
||||||
|
} else {
|
||||||
|
isSelected = false;
|
||||||
|
stopScrolling();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
i.event.bind(window, 'mouseup', function () {
|
||||||
|
if (isSelected) {
|
||||||
|
isSelected = false;
|
||||||
|
stopScrolling();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
i.event.bind(window, 'keyup', function () {
|
||||||
|
if (isSelected) {
|
||||||
|
isSelected = false;
|
||||||
|
stopScrolling();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
i.event.bind(window, 'mousemove', function (e) {
|
||||||
|
if (isSelected) {
|
||||||
|
var mousePosition = {x: e.pageX, y: e.pageY};
|
||||||
|
var containerGeometry = {
|
||||||
|
left: element.offsetLeft,
|
||||||
|
right: element.offsetLeft + element.offsetWidth,
|
||||||
|
top: element.offsetTop,
|
||||||
|
bottom: element.offsetTop + element.offsetHeight
|
||||||
|
};
|
||||||
|
|
||||||
|
if (mousePosition.x < containerGeometry.left + 3) {
|
||||||
|
scrollDiff.left = -5;
|
||||||
|
_.startScrolling(element, 'x');
|
||||||
|
} else if (mousePosition.x > containerGeometry.right - 3) {
|
||||||
|
scrollDiff.left = 5;
|
||||||
|
_.startScrolling(element, 'x');
|
||||||
|
} else {
|
||||||
|
scrollDiff.left = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mousePosition.y < containerGeometry.top + 3) {
|
||||||
|
if (containerGeometry.top + 3 - mousePosition.y < 5) {
|
||||||
|
scrollDiff.top = -5;
|
||||||
|
} else {
|
||||||
|
scrollDiff.top = -20;
|
||||||
|
}
|
||||||
|
_.startScrolling(element, 'y');
|
||||||
|
} else if (mousePosition.y > containerGeometry.bottom - 3) {
|
||||||
|
if (mousePosition.y - containerGeometry.bottom + 3 < 5) {
|
||||||
|
scrollDiff.top = 5;
|
||||||
|
} else {
|
||||||
|
scrollDiff.top = 20;
|
||||||
|
}
|
||||||
|
_.startScrolling(element, 'y');
|
||||||
|
} else {
|
||||||
|
scrollDiff.top = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (scrollDiff.top === 0 && scrollDiff.left === 0) {
|
||||||
|
stopScrolling();
|
||||||
|
} else {
|
||||||
|
startScrolling();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = function (element) {
|
||||||
|
var i = instances.get(element);
|
||||||
|
bindSelectionHandler(element, i);
|
||||||
|
};
|
179
view/js/perfect-scrollbar/src/js/plugin/handler/touch.js
Normal file
179
view/js/perfect-scrollbar/src/js/plugin/handler/touch.js
Normal file
|
@ -0,0 +1,179 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var _ = require('../../lib/helper');
|
||||||
|
var instances = require('../instances');
|
||||||
|
var updateGeometry = require('../update-geometry');
|
||||||
|
var updateScroll = require('../update-scroll');
|
||||||
|
|
||||||
|
function bindTouchHandler(element, i, supportsTouch, supportsIePointer) {
|
||||||
|
function shouldPreventDefault(deltaX, deltaY) {
|
||||||
|
var scrollTop = element.scrollTop;
|
||||||
|
var scrollLeft = element.scrollLeft;
|
||||||
|
var magnitudeX = Math.abs(deltaX);
|
||||||
|
var magnitudeY = Math.abs(deltaY);
|
||||||
|
|
||||||
|
if (magnitudeY > magnitudeX) {
|
||||||
|
// user is perhaps trying to swipe up/down the page
|
||||||
|
|
||||||
|
if (((deltaY < 0) && (scrollTop === i.contentHeight - i.containerHeight)) ||
|
||||||
|
((deltaY > 0) && (scrollTop === 0))) {
|
||||||
|
return !i.settings.swipePropagation;
|
||||||
|
}
|
||||||
|
} else if (magnitudeX > magnitudeY) {
|
||||||
|
// user is perhaps trying to swipe left/right across the page
|
||||||
|
|
||||||
|
if (((deltaX < 0) && (scrollLeft === i.contentWidth - i.containerWidth)) ||
|
||||||
|
((deltaX > 0) && (scrollLeft === 0))) {
|
||||||
|
return !i.settings.swipePropagation;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function applyTouchMove(differenceX, differenceY) {
|
||||||
|
updateScroll(element, 'top', element.scrollTop - differenceY);
|
||||||
|
updateScroll(element, 'left', element.scrollLeft - differenceX);
|
||||||
|
|
||||||
|
updateGeometry(element);
|
||||||
|
}
|
||||||
|
|
||||||
|
var startOffset = {};
|
||||||
|
var startTime = 0;
|
||||||
|
var speed = {};
|
||||||
|
var easingLoop = null;
|
||||||
|
var inGlobalTouch = false;
|
||||||
|
var inLocalTouch = false;
|
||||||
|
|
||||||
|
function globalTouchStart() {
|
||||||
|
inGlobalTouch = true;
|
||||||
|
}
|
||||||
|
function globalTouchEnd() {
|
||||||
|
inGlobalTouch = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getTouch(e) {
|
||||||
|
if (e.targetTouches) {
|
||||||
|
return e.targetTouches[0];
|
||||||
|
} else {
|
||||||
|
// Maybe IE pointer
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function shouldHandle(e) {
|
||||||
|
if (e.targetTouches && e.targetTouches.length === 1) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (e.pointerType && e.pointerType !== 'mouse' && e.pointerType !== e.MSPOINTER_TYPE_MOUSE) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
function touchStart(e) {
|
||||||
|
if (shouldHandle(e)) {
|
||||||
|
inLocalTouch = true;
|
||||||
|
|
||||||
|
var touch = getTouch(e);
|
||||||
|
|
||||||
|
startOffset.pageX = touch.pageX;
|
||||||
|
startOffset.pageY = touch.pageY;
|
||||||
|
|
||||||
|
startTime = (new Date()).getTime();
|
||||||
|
|
||||||
|
if (easingLoop !== null) {
|
||||||
|
clearInterval(easingLoop);
|
||||||
|
}
|
||||||
|
|
||||||
|
e.stopPropagation();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function touchMove(e) {
|
||||||
|
if (!inLocalTouch && i.settings.swipePropagation) {
|
||||||
|
touchStart(e);
|
||||||
|
}
|
||||||
|
if (!inGlobalTouch && inLocalTouch && shouldHandle(e)) {
|
||||||
|
var touch = getTouch(e);
|
||||||
|
|
||||||
|
var currentOffset = {pageX: touch.pageX, pageY: touch.pageY};
|
||||||
|
|
||||||
|
var differenceX = currentOffset.pageX - startOffset.pageX;
|
||||||
|
var differenceY = currentOffset.pageY - startOffset.pageY;
|
||||||
|
|
||||||
|
applyTouchMove(differenceX, differenceY);
|
||||||
|
startOffset = currentOffset;
|
||||||
|
|
||||||
|
var currentTime = (new Date()).getTime();
|
||||||
|
|
||||||
|
var timeGap = currentTime - startTime;
|
||||||
|
if (timeGap > 0) {
|
||||||
|
speed.x = differenceX / timeGap;
|
||||||
|
speed.y = differenceY / timeGap;
|
||||||
|
startTime = currentTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shouldPreventDefault(differenceX, differenceY)) {
|
||||||
|
e.stopPropagation();
|
||||||
|
e.preventDefault();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function touchEnd() {
|
||||||
|
if (!inGlobalTouch && inLocalTouch) {
|
||||||
|
inLocalTouch = false;
|
||||||
|
|
||||||
|
clearInterval(easingLoop);
|
||||||
|
easingLoop = setInterval(function () {
|
||||||
|
if (!instances.get(element)) {
|
||||||
|
clearInterval(easingLoop);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!speed.x && !speed.y) {
|
||||||
|
clearInterval(easingLoop);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Math.abs(speed.x) < 0.01 && Math.abs(speed.y) < 0.01) {
|
||||||
|
clearInterval(easingLoop);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
applyTouchMove(speed.x * 30, speed.y * 30);
|
||||||
|
|
||||||
|
speed.x *= 0.8;
|
||||||
|
speed.y *= 0.8;
|
||||||
|
}, 10);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (supportsTouch) {
|
||||||
|
i.event.bind(window, 'touchstart', globalTouchStart);
|
||||||
|
i.event.bind(window, 'touchend', globalTouchEnd);
|
||||||
|
i.event.bind(element, 'touchstart', touchStart);
|
||||||
|
i.event.bind(element, 'touchmove', touchMove);
|
||||||
|
i.event.bind(element, 'touchend', touchEnd);
|
||||||
|
} else if (supportsIePointer) {
|
||||||
|
if (window.PointerEvent) {
|
||||||
|
i.event.bind(window, 'pointerdown', globalTouchStart);
|
||||||
|
i.event.bind(window, 'pointerup', globalTouchEnd);
|
||||||
|
i.event.bind(element, 'pointerdown', touchStart);
|
||||||
|
i.event.bind(element, 'pointermove', touchMove);
|
||||||
|
i.event.bind(element, 'pointerup', touchEnd);
|
||||||
|
} else if (window.MSPointerEvent) {
|
||||||
|
i.event.bind(window, 'MSPointerDown', globalTouchStart);
|
||||||
|
i.event.bind(window, 'MSPointerUp', globalTouchEnd);
|
||||||
|
i.event.bind(element, 'MSPointerDown', touchStart);
|
||||||
|
i.event.bind(element, 'MSPointerMove', touchMove);
|
||||||
|
i.event.bind(element, 'MSPointerUp', touchEnd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = function (element) {
|
||||||
|
if (!_.env.supportsTouch && !_.env.supportsIePointer) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var i = instances.get(element);
|
||||||
|
bindTouchHandler(element, i, _.env.supportsTouch, _.env.supportsIePointer);
|
||||||
|
};
|
37
view/js/perfect-scrollbar/src/js/plugin/initialize.js
Normal file
37
view/js/perfect-scrollbar/src/js/plugin/initialize.js
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var _ = require('../lib/helper');
|
||||||
|
var cls = require('../lib/class');
|
||||||
|
var instances = require('./instances');
|
||||||
|
var updateGeometry = require('./update-geometry');
|
||||||
|
|
||||||
|
// Handlers
|
||||||
|
var handlers = {
|
||||||
|
'click-rail': require('./handler/click-rail'),
|
||||||
|
'drag-scrollbar': require('./handler/drag-scrollbar'),
|
||||||
|
'keyboard': require('./handler/keyboard'),
|
||||||
|
'wheel': require('./handler/mouse-wheel'),
|
||||||
|
'touch': require('./handler/touch'),
|
||||||
|
'selection': require('./handler/selection')
|
||||||
|
};
|
||||||
|
var nativeScrollHandler = require('./handler/native-scroll');
|
||||||
|
|
||||||
|
module.exports = function (element, userSettings) {
|
||||||
|
userSettings = typeof userSettings === 'object' ? userSettings : {};
|
||||||
|
|
||||||
|
cls.add(element, 'ps-container');
|
||||||
|
|
||||||
|
// Create a plugin instance.
|
||||||
|
var i = instances.add(element);
|
||||||
|
|
||||||
|
i.settings = _.extend(i.settings, userSettings);
|
||||||
|
cls.add(element, 'ps-theme-' + i.settings.theme);
|
||||||
|
|
||||||
|
i.settings.handlers.forEach(function (handlerName) {
|
||||||
|
handlers[handlerName](element);
|
||||||
|
});
|
||||||
|
|
||||||
|
nativeScrollHandler(element);
|
||||||
|
|
||||||
|
updateGeometry(element);
|
||||||
|
};
|
107
view/js/perfect-scrollbar/src/js/plugin/instances.js
Normal file
107
view/js/perfect-scrollbar/src/js/plugin/instances.js
Normal file
|
@ -0,0 +1,107 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var _ = require('../lib/helper');
|
||||||
|
var cls = require('../lib/class');
|
||||||
|
var defaultSettings = require('./default-setting');
|
||||||
|
var dom = require('../lib/dom');
|
||||||
|
var EventManager = require('../lib/event-manager');
|
||||||
|
var guid = require('../lib/guid');
|
||||||
|
|
||||||
|
var instances = {};
|
||||||
|
|
||||||
|
function Instance(element) {
|
||||||
|
var i = this;
|
||||||
|
|
||||||
|
i.settings = _.clone(defaultSettings);
|
||||||
|
i.containerWidth = null;
|
||||||
|
i.containerHeight = null;
|
||||||
|
i.contentWidth = null;
|
||||||
|
i.contentHeight = null;
|
||||||
|
|
||||||
|
i.isRtl = dom.css(element, 'direction') === "rtl";
|
||||||
|
i.isNegativeScroll = (function () {
|
||||||
|
var originalScrollLeft = element.scrollLeft;
|
||||||
|
var result = null;
|
||||||
|
element.scrollLeft = -1;
|
||||||
|
result = element.scrollLeft < 0;
|
||||||
|
element.scrollLeft = originalScrollLeft;
|
||||||
|
return result;
|
||||||
|
})();
|
||||||
|
i.negativeScrollAdjustment = i.isNegativeScroll ? element.scrollWidth - element.clientWidth : 0;
|
||||||
|
i.event = new EventManager();
|
||||||
|
i.ownerDocument = element.ownerDocument || document;
|
||||||
|
|
||||||
|
function focus() {
|
||||||
|
cls.add(element, 'ps-focus');
|
||||||
|
}
|
||||||
|
|
||||||
|
function blur() {
|
||||||
|
cls.remove(element, 'ps-focus');
|
||||||
|
}
|
||||||
|
|
||||||
|
i.scrollbarXRail = dom.appendTo(dom.e('div', 'ps-scrollbar-x-rail'), element);
|
||||||
|
i.scrollbarX = dom.appendTo(dom.e('div', 'ps-scrollbar-x'), i.scrollbarXRail);
|
||||||
|
i.scrollbarX.setAttribute('tabindex', 0);
|
||||||
|
i.event.bind(i.scrollbarX, 'focus', focus);
|
||||||
|
i.event.bind(i.scrollbarX, 'blur', blur);
|
||||||
|
i.scrollbarXActive = null;
|
||||||
|
i.scrollbarXWidth = null;
|
||||||
|
i.scrollbarXLeft = null;
|
||||||
|
i.scrollbarXBottom = _.toInt(dom.css(i.scrollbarXRail, 'bottom'));
|
||||||
|
i.isScrollbarXUsingBottom = i.scrollbarXBottom === i.scrollbarXBottom; // !isNaN
|
||||||
|
i.scrollbarXTop = i.isScrollbarXUsingBottom ? null : _.toInt(dom.css(i.scrollbarXRail, 'top'));
|
||||||
|
i.railBorderXWidth = _.toInt(dom.css(i.scrollbarXRail, 'borderLeftWidth')) + _.toInt(dom.css(i.scrollbarXRail, 'borderRightWidth'));
|
||||||
|
// Set rail to display:block to calculate margins
|
||||||
|
dom.css(i.scrollbarXRail, 'display', 'block');
|
||||||
|
i.railXMarginWidth = _.toInt(dom.css(i.scrollbarXRail, 'marginLeft')) + _.toInt(dom.css(i.scrollbarXRail, 'marginRight'));
|
||||||
|
dom.css(i.scrollbarXRail, 'display', '');
|
||||||
|
i.railXWidth = null;
|
||||||
|
i.railXRatio = null;
|
||||||
|
|
||||||
|
i.scrollbarYRail = dom.appendTo(dom.e('div', 'ps-scrollbar-y-rail'), element);
|
||||||
|
i.scrollbarY = dom.appendTo(dom.e('div', 'ps-scrollbar-y'), i.scrollbarYRail);
|
||||||
|
i.scrollbarY.setAttribute('tabindex', 0);
|
||||||
|
i.event.bind(i.scrollbarY, 'focus', focus);
|
||||||
|
i.event.bind(i.scrollbarY, 'blur', blur);
|
||||||
|
i.scrollbarYActive = null;
|
||||||
|
i.scrollbarYHeight = null;
|
||||||
|
i.scrollbarYTop = null;
|
||||||
|
i.scrollbarYRight = _.toInt(dom.css(i.scrollbarYRail, 'right'));
|
||||||
|
i.isScrollbarYUsingRight = i.scrollbarYRight === i.scrollbarYRight; // !isNaN
|
||||||
|
i.scrollbarYLeft = i.isScrollbarYUsingRight ? null : _.toInt(dom.css(i.scrollbarYRail, 'left'));
|
||||||
|
i.scrollbarYOuterWidth = i.isRtl ? _.outerWidth(i.scrollbarY) : null;
|
||||||
|
i.railBorderYWidth = _.toInt(dom.css(i.scrollbarYRail, 'borderTopWidth')) + _.toInt(dom.css(i.scrollbarYRail, 'borderBottomWidth'));
|
||||||
|
dom.css(i.scrollbarYRail, 'display', 'block');
|
||||||
|
i.railYMarginHeight = _.toInt(dom.css(i.scrollbarYRail, 'marginTop')) + _.toInt(dom.css(i.scrollbarYRail, 'marginBottom'));
|
||||||
|
dom.css(i.scrollbarYRail, 'display', '');
|
||||||
|
i.railYHeight = null;
|
||||||
|
i.railYRatio = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getId(element) {
|
||||||
|
return element.getAttribute('data-ps-id');
|
||||||
|
}
|
||||||
|
|
||||||
|
function setId(element, id) {
|
||||||
|
element.setAttribute('data-ps-id', id);
|
||||||
|
}
|
||||||
|
|
||||||
|
function removeId(element) {
|
||||||
|
element.removeAttribute('data-ps-id');
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.add = function (element) {
|
||||||
|
var newId = guid();
|
||||||
|
setId(element, newId);
|
||||||
|
instances[newId] = new Instance(element);
|
||||||
|
return instances[newId];
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.remove = function (element) {
|
||||||
|
delete instances[getId(element)];
|
||||||
|
removeId(element);
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.get = function (element) {
|
||||||
|
return instances[getId(element)];
|
||||||
|
};
|
126
view/js/perfect-scrollbar/src/js/plugin/update-geometry.js
Normal file
126
view/js/perfect-scrollbar/src/js/plugin/update-geometry.js
Normal file
|
@ -0,0 +1,126 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var _ = require('../lib/helper');
|
||||||
|
var cls = require('../lib/class');
|
||||||
|
var dom = require('../lib/dom');
|
||||||
|
var instances = require('./instances');
|
||||||
|
var updateScroll = require('./update-scroll');
|
||||||
|
|
||||||
|
function getThumbSize(i, thumbSize) {
|
||||||
|
if (i.settings.minScrollbarLength) {
|
||||||
|
thumbSize = Math.max(thumbSize, i.settings.minScrollbarLength);
|
||||||
|
}
|
||||||
|
if (i.settings.maxScrollbarLength) {
|
||||||
|
thumbSize = Math.min(thumbSize, i.settings.maxScrollbarLength);
|
||||||
|
}
|
||||||
|
return thumbSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateCss(element, i) {
|
||||||
|
var xRailOffset = {width: i.railXWidth};
|
||||||
|
if (i.isRtl) {
|
||||||
|
xRailOffset.left = i.negativeScrollAdjustment + element.scrollLeft + i.containerWidth - i.contentWidth;
|
||||||
|
} else {
|
||||||
|
xRailOffset.left = element.scrollLeft;
|
||||||
|
}
|
||||||
|
if (i.isScrollbarXUsingBottom) {
|
||||||
|
xRailOffset.bottom = i.scrollbarXBottom - element.scrollTop;
|
||||||
|
} else {
|
||||||
|
xRailOffset.top = i.scrollbarXTop + element.scrollTop;
|
||||||
|
}
|
||||||
|
dom.css(i.scrollbarXRail, xRailOffset);
|
||||||
|
|
||||||
|
var yRailOffset = {top: element.scrollTop, height: i.railYHeight};
|
||||||
|
if (i.isScrollbarYUsingRight) {
|
||||||
|
if (i.isRtl) {
|
||||||
|
yRailOffset.right = i.contentWidth - (i.negativeScrollAdjustment + element.scrollLeft) - i.scrollbarYRight - i.scrollbarYOuterWidth;
|
||||||
|
} else {
|
||||||
|
yRailOffset.right = i.scrollbarYRight - element.scrollLeft;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (i.isRtl) {
|
||||||
|
yRailOffset.left = i.negativeScrollAdjustment + element.scrollLeft + i.containerWidth * 2 - i.contentWidth - i.scrollbarYLeft - i.scrollbarYOuterWidth;
|
||||||
|
} else {
|
||||||
|
yRailOffset.left = i.scrollbarYLeft + element.scrollLeft;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dom.css(i.scrollbarYRail, yRailOffset);
|
||||||
|
|
||||||
|
dom.css(i.scrollbarX, {left: i.scrollbarXLeft, width: i.scrollbarXWidth - i.railBorderXWidth});
|
||||||
|
dom.css(i.scrollbarY, {top: i.scrollbarYTop, height: i.scrollbarYHeight - i.railBorderYWidth});
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = function (element) {
|
||||||
|
var i = instances.get(element);
|
||||||
|
|
||||||
|
i.containerWidth = element.clientWidth;
|
||||||
|
i.containerHeight = element.clientHeight;
|
||||||
|
i.contentWidth = element.scrollWidth;
|
||||||
|
i.contentHeight = element.scrollHeight;
|
||||||
|
|
||||||
|
var existingRails;
|
||||||
|
if (!element.contains(i.scrollbarXRail)) {
|
||||||
|
existingRails = dom.queryChildren(element, '.ps-scrollbar-x-rail');
|
||||||
|
if (existingRails.length > 0) {
|
||||||
|
existingRails.forEach(function (rail) {
|
||||||
|
dom.remove(rail);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
dom.appendTo(i.scrollbarXRail, element);
|
||||||
|
}
|
||||||
|
if (!element.contains(i.scrollbarYRail)) {
|
||||||
|
existingRails = dom.queryChildren(element, '.ps-scrollbar-y-rail');
|
||||||
|
if (existingRails.length > 0) {
|
||||||
|
existingRails.forEach(function (rail) {
|
||||||
|
dom.remove(rail);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
dom.appendTo(i.scrollbarYRail, element);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!i.settings.suppressScrollX && i.containerWidth + i.settings.scrollXMarginOffset < i.contentWidth) {
|
||||||
|
i.scrollbarXActive = true;
|
||||||
|
i.railXWidth = i.containerWidth - i.railXMarginWidth;
|
||||||
|
i.railXRatio = i.containerWidth / i.railXWidth;
|
||||||
|
i.scrollbarXWidth = getThumbSize(i, _.toInt(i.railXWidth * i.containerWidth / i.contentWidth));
|
||||||
|
i.scrollbarXLeft = _.toInt((i.negativeScrollAdjustment + element.scrollLeft) * (i.railXWidth - i.scrollbarXWidth) / (i.contentWidth - i.containerWidth));
|
||||||
|
} else {
|
||||||
|
i.scrollbarXActive = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!i.settings.suppressScrollY && i.containerHeight + i.settings.scrollYMarginOffset < i.contentHeight) {
|
||||||
|
i.scrollbarYActive = true;
|
||||||
|
i.railYHeight = i.containerHeight - i.railYMarginHeight;
|
||||||
|
i.railYRatio = i.containerHeight / i.railYHeight;
|
||||||
|
i.scrollbarYHeight = getThumbSize(i, _.toInt(i.railYHeight * i.containerHeight / i.contentHeight));
|
||||||
|
i.scrollbarYTop = _.toInt(element.scrollTop * (i.railYHeight - i.scrollbarYHeight) / (i.contentHeight - i.containerHeight));
|
||||||
|
} else {
|
||||||
|
i.scrollbarYActive = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i.scrollbarXLeft >= i.railXWidth - i.scrollbarXWidth) {
|
||||||
|
i.scrollbarXLeft = i.railXWidth - i.scrollbarXWidth;
|
||||||
|
}
|
||||||
|
if (i.scrollbarYTop >= i.railYHeight - i.scrollbarYHeight) {
|
||||||
|
i.scrollbarYTop = i.railYHeight - i.scrollbarYHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
updateCss(element, i);
|
||||||
|
|
||||||
|
if (i.scrollbarXActive) {
|
||||||
|
cls.add(element, 'ps-active-x');
|
||||||
|
} else {
|
||||||
|
cls.remove(element, 'ps-active-x');
|
||||||
|
i.scrollbarXWidth = 0;
|
||||||
|
i.scrollbarXLeft = 0;
|
||||||
|
updateScroll(element, 'left', 0);
|
||||||
|
}
|
||||||
|
if (i.scrollbarYActive) {
|
||||||
|
cls.add(element, 'ps-active-y');
|
||||||
|
} else {
|
||||||
|
cls.remove(element, 'ps-active-y');
|
||||||
|
i.scrollbarYHeight = 0;
|
||||||
|
i.scrollbarYTop = 0;
|
||||||
|
updateScroll(element, 'top', 0);
|
||||||
|
}
|
||||||
|
};
|
97
view/js/perfect-scrollbar/src/js/plugin/update-scroll.js
Normal file
97
view/js/perfect-scrollbar/src/js/plugin/update-scroll.js
Normal file
|
@ -0,0 +1,97 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var instances = require('./instances');
|
||||||
|
|
||||||
|
var lastTop;
|
||||||
|
var lastLeft;
|
||||||
|
|
||||||
|
var createDOMEvent = function (name) {
|
||||||
|
var event = document.createEvent("Event");
|
||||||
|
event.initEvent(name, true, true);
|
||||||
|
return event;
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = function (element, axis, value) {
|
||||||
|
if (typeof element === 'undefined') {
|
||||||
|
throw 'You must provide an element to the update-scroll function';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof axis === 'undefined') {
|
||||||
|
throw 'You must provide an axis to the update-scroll function';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof value === 'undefined') {
|
||||||
|
throw 'You must provide a value to the update-scroll function';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (axis === 'top' && value <= 0) {
|
||||||
|
element.scrollTop = value = 0; // don't allow negative scroll
|
||||||
|
element.dispatchEvent(createDOMEvent('ps-y-reach-start'));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (axis === 'left' && value <= 0) {
|
||||||
|
element.scrollLeft = value = 0; // don't allow negative scroll
|
||||||
|
element.dispatchEvent(createDOMEvent('ps-x-reach-start'));
|
||||||
|
}
|
||||||
|
|
||||||
|
var i = instances.get(element);
|
||||||
|
|
||||||
|
if (axis === 'top' && value >= i.contentHeight - i.containerHeight) {
|
||||||
|
// don't allow scroll past container
|
||||||
|
value = i.contentHeight - i.containerHeight;
|
||||||
|
if (value - element.scrollTop <= 1) {
|
||||||
|
// mitigates rounding errors on non-subpixel scroll values
|
||||||
|
value = element.scrollTop;
|
||||||
|
} else {
|
||||||
|
element.scrollTop = value;
|
||||||
|
}
|
||||||
|
element.dispatchEvent(createDOMEvent('ps-y-reach-end'));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (axis === 'left' && value >= i.contentWidth - i.containerWidth) {
|
||||||
|
// don't allow scroll past container
|
||||||
|
value = i.contentWidth - i.containerWidth;
|
||||||
|
if (value - element.scrollLeft <= 1) {
|
||||||
|
// mitigates rounding errors on non-subpixel scroll values
|
||||||
|
value = element.scrollLeft;
|
||||||
|
} else {
|
||||||
|
element.scrollLeft = value;
|
||||||
|
}
|
||||||
|
element.dispatchEvent(createDOMEvent('ps-x-reach-end'));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!lastTop) {
|
||||||
|
lastTop = element.scrollTop;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!lastLeft) {
|
||||||
|
lastLeft = element.scrollLeft;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (axis === 'top' && value < lastTop) {
|
||||||
|
element.dispatchEvent(createDOMEvent('ps-scroll-up'));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (axis === 'top' && value > lastTop) {
|
||||||
|
element.dispatchEvent(createDOMEvent('ps-scroll-down'));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (axis === 'left' && value < lastLeft) {
|
||||||
|
element.dispatchEvent(createDOMEvent('ps-scroll-left'));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (axis === 'left' && value > lastLeft) {
|
||||||
|
element.dispatchEvent(createDOMEvent('ps-scroll-right'));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (axis === 'top') {
|
||||||
|
element.scrollTop = lastTop = value;
|
||||||
|
element.dispatchEvent(createDOMEvent('ps-scroll-y'));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (axis === 'left') {
|
||||||
|
element.scrollLeft = lastLeft = value;
|
||||||
|
element.dispatchEvent(createDOMEvent('ps-scroll-x'));
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
37
view/js/perfect-scrollbar/src/js/plugin/update.js
Normal file
37
view/js/perfect-scrollbar/src/js/plugin/update.js
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var _ = require('../lib/helper');
|
||||||
|
var dom = require('../lib/dom');
|
||||||
|
var instances = require('./instances');
|
||||||
|
var updateGeometry = require('./update-geometry');
|
||||||
|
var updateScroll = require('./update-scroll');
|
||||||
|
|
||||||
|
module.exports = function (element) {
|
||||||
|
var i = instances.get(element);
|
||||||
|
|
||||||
|
if (!i) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Recalcuate negative scrollLeft adjustment
|
||||||
|
i.negativeScrollAdjustment = i.isNegativeScroll ? element.scrollWidth - element.clientWidth : 0;
|
||||||
|
|
||||||
|
// Recalculate rail margins
|
||||||
|
dom.css(i.scrollbarXRail, 'display', 'block');
|
||||||
|
dom.css(i.scrollbarYRail, 'display', 'block');
|
||||||
|
i.railXMarginWidth = _.toInt(dom.css(i.scrollbarXRail, 'marginLeft')) + _.toInt(dom.css(i.scrollbarXRail, 'marginRight'));
|
||||||
|
i.railYMarginHeight = _.toInt(dom.css(i.scrollbarYRail, 'marginTop')) + _.toInt(dom.css(i.scrollbarYRail, 'marginBottom'));
|
||||||
|
|
||||||
|
// Hide scrollbars not to affect scrollWidth and scrollHeight
|
||||||
|
dom.css(i.scrollbarXRail, 'display', 'none');
|
||||||
|
dom.css(i.scrollbarYRail, 'display', 'none');
|
||||||
|
|
||||||
|
updateGeometry(element);
|
||||||
|
|
||||||
|
// Update top/left scroll to trigger events
|
||||||
|
updateScroll(element, 'top', element.scrollTop);
|
||||||
|
updateScroll(element, 'left', element.scrollLeft);
|
||||||
|
|
||||||
|
dom.css(i.scrollbarXRail, 'display', '');
|
||||||
|
dom.css(i.scrollbarYRail, 'display', '');
|
||||||
|
};
|
|
@ -6,7 +6,7 @@
|
||||||
<link rel="stylesheet" href="view/asset/jquery-colorbox/example5/colorbox.css?v={{$smarty.const.FRIENDICA_VERSION}}" type="text/css" media="screen" />
|
<link rel="stylesheet" href="view/asset/jquery-colorbox/example5/colorbox.css?v={{$smarty.const.FRIENDICA_VERSION}}" type="text/css" media="screen" />
|
||||||
<link rel="stylesheet" href="view/asset/jgrowl/jquery.jgrowl.min.css?v={{$smarty.const.FRIENDICA_VERSION}}" type="text/css" media="screen" />
|
<link rel="stylesheet" href="view/asset/jgrowl/jquery.jgrowl.min.css?v={{$smarty.const.FRIENDICA_VERSION}}" type="text/css" media="screen" />
|
||||||
<link rel="stylesheet" href="view/asset/jquery-datetimepicker/build/jquery.datetimepicker.min.css?v={{$smarty.const.FRIENDICA_VERSION}}" type="text/css" media="screen" />
|
<link rel="stylesheet" href="view/asset/jquery-datetimepicker/build/jquery.datetimepicker.min.css?v={{$smarty.const.FRIENDICA_VERSION}}" type="text/css" media="screen" />
|
||||||
<link rel="stylesheet" href="view/asset/perfect-scrollbar/css/perfect-scrollbar.min.css?v={{$smarty.const.FRIENDICA_VERSION}}" type="text/css" media="screen" />
|
<link rel="stylesheet" href="view/js/perfect-scrollbar/css/perfect-scrollbar.min.css?v={{$smarty.const.FRIENDICA_VERSION}}" type="text/css" media="screen" />
|
||||||
|
|
||||||
{{foreach $stylesheets as $stylesheetUrl}}
|
{{foreach $stylesheets as $stylesheetUrl}}
|
||||||
<link rel="stylesheet" href="{{$stylesheetUrl}}" type="text/css" media="screen" />
|
<link rel="stylesheet" href="{{$stylesheetUrl}}" type="text/css" media="screen" />
|
||||||
|
@ -40,7 +40,7 @@
|
||||||
<script type="text/javascript" src="view/asset/jquery-colorbox/jquery.colorbox-min.js?v={{$smarty.const.FRIENDICA_VERSION}}"></script>
|
<script type="text/javascript" src="view/asset/jquery-colorbox/jquery.colorbox-min.js?v={{$smarty.const.FRIENDICA_VERSION}}"></script>
|
||||||
<script type="text/javascript" src="view/asset/jgrowl/jquery.jgrowl.min.js?v={{$smarty.const.FRIENDICA_VERSION}}"></script>
|
<script type="text/javascript" src="view/asset/jgrowl/jquery.jgrowl.min.js?v={{$smarty.const.FRIENDICA_VERSION}}"></script>
|
||||||
<script type="text/javascript" src="view/asset/jquery-datetimepicker/build/jquery.datetimepicker.full.min.js?v={{$smarty.const.FRIENDICA_VERSION}}"></script>
|
<script type="text/javascript" src="view/asset/jquery-datetimepicker/build/jquery.datetimepicker.full.min.js?v={{$smarty.const.FRIENDICA_VERSION}}"></script>
|
||||||
<script type="text/javascript" src="view/asset/perfect-scrollbar/js/perfect-scrollbar.jquery.min.js?v={{$smarty.const.FRIENDICA_VERSION}}" ></script>
|
<script type="text/javascript" src="view/js/perfect-scrollbar/js/perfect-scrollbar.jquery.min.js?v={{$smarty.const.FRIENDICA_VERSION}}" ></script>
|
||||||
<script type="text/javascript" src="view/asset/imagesloaded/imagesloaded.pkgd.min.js?v={{$smarty.const.FRIENDICA_VERSION}}"></script>
|
<script type="text/javascript" src="view/asset/imagesloaded/imagesloaded.pkgd.min.js?v={{$smarty.const.FRIENDICA_VERSION}}"></script>
|
||||||
<script type="text/javascript" src="view/asset/base64/base64.min.js?v={{$smarty.const.FRIENDICA_VERSION}}" ></script>
|
<script type="text/javascript" src="view/asset/base64/base64.min.js?v={{$smarty.const.FRIENDICA_VERSION}}" ></script>
|
||||||
<script type="text/javascript" src="view/asset/dompurify/dist/purify.min.js?v={{$smarty.const.FRIENDICA_VERSION}}"></script>
|
<script type="text/javascript" src="view/asset/dompurify/dist/purify.min.js?v={{$smarty.const.FRIENDICA_VERSION}}"></script>
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
<link rel="stylesheet" href="view/asset/jquery-colorbox/example5/colorbox.css?v={{$smarty.const.FRIENDICA_VERSION}}" type="text/css" media="screen" />
|
<link rel="stylesheet" href="view/asset/jquery-colorbox/example5/colorbox.css?v={{$smarty.const.FRIENDICA_VERSION}}" type="text/css" media="screen" />
|
||||||
<link rel="stylesheet" href="view/asset/jgrowl/jquery.jgrowl.min.css?v={{$smarty.const.FRIENDICA_VERSION}}" type="text/css" media="screen" />
|
<link rel="stylesheet" href="view/asset/jgrowl/jquery.jgrowl.min.css?v={{$smarty.const.FRIENDICA_VERSION}}" type="text/css" media="screen" />
|
||||||
<link rel="stylesheet" href="view/asset/jquery-datetimepicker/build/jquery.datetimepicker.min.css?v={{$smarty.const.FRIENDICA_VERSION}}" type="text/css" media="screen" />
|
<link rel="stylesheet" href="view/asset/jquery-datetimepicker/build/jquery.datetimepicker.min.css?v={{$smarty.const.FRIENDICA_VERSION}}" type="text/css" media="screen" />
|
||||||
<link rel="stylesheet" href="view/asset/perfect-scrollbar/css/perfect-scrollbar.min.css?v={{$smarty.const.FRIENDICA_VERSION}}" type="text/css" media="screen" />
|
<link rel="stylesheet" href="view/js/perfect-scrollbar/css/perfect-scrollbar.min.css?v={{$smarty.const.FRIENDICA_VERSION}}" type="text/css" media="screen" />
|
||||||
|
|
||||||
<link rel="stylesheet" href="view/theme/frio/frameworks/bootstrap/css/bootstrap.min.css?v={{$smarty.const.FRIENDICA_VERSION}}" type="text/css" media="screen"/>
|
<link rel="stylesheet" href="view/theme/frio/frameworks/bootstrap/css/bootstrap.min.css?v={{$smarty.const.FRIENDICA_VERSION}}" type="text/css" media="screen"/>
|
||||||
<link rel="stylesheet" href="view/theme/frio/frameworks/bootstrap/css/bootstrap-theme.min.css?v={{$smarty.const.FRIENDICA_VERSION}}" type="text/css" media="screen"/>
|
<link rel="stylesheet" href="view/theme/frio/frameworks/bootstrap/css/bootstrap-theme.min.css?v={{$smarty.const.FRIENDICA_VERSION}}" type="text/css" media="screen"/>
|
||||||
|
@ -61,7 +61,7 @@
|
||||||
<script type="text/javascript" src="view/asset/jquery-colorbox/jquery.colorbox-min.js?v={{$smarty.const.FRIENDICA_VERSION}}"></script>
|
<script type="text/javascript" src="view/asset/jquery-colorbox/jquery.colorbox-min.js?v={{$smarty.const.FRIENDICA_VERSION}}"></script>
|
||||||
<script type="text/javascript" src="view/asset/jgrowl/jquery.jgrowl.min.js?v={{$smarty.const.FRIENDICA_VERSION}}"></script>
|
<script type="text/javascript" src="view/asset/jgrowl/jquery.jgrowl.min.js?v={{$smarty.const.FRIENDICA_VERSION}}"></script>
|
||||||
<script type="text/javascript" src="view/asset/jquery-datetimepicker/build/jquery.datetimepicker.full.min.js?v={{$smarty.const.FRIENDICA_VERSION}}"></script>
|
<script type="text/javascript" src="view/asset/jquery-datetimepicker/build/jquery.datetimepicker.full.min.js?v={{$smarty.const.FRIENDICA_VERSION}}"></script>
|
||||||
<script type="text/javascript" src="view/asset/perfect-scrollbar/js/perfect-scrollbar.jquery.min.js?v={{$smarty.const.FRIENDICA_VERSION}}"></script>
|
<script type="text/javascript" src="view/js/perfect-scrollbar/js/perfect-scrollbar.jquery.min.js?v={{$smarty.const.FRIENDICA_VERSION}}"></script>
|
||||||
<script type="text/javascript" src="view/asset/imagesloaded/imagesloaded.pkgd.min.js?v={{$smarty.const.FRIENDICA_VERSION}}"></script>
|
<script type="text/javascript" src="view/asset/imagesloaded/imagesloaded.pkgd.min.js?v={{$smarty.const.FRIENDICA_VERSION}}"></script>
|
||||||
<script type="text/javascript" src="view/asset/base64/base64.min.js?v={{$smarty.const.FRIENDICA_VERSION}}"></script>
|
<script type="text/javascript" src="view/asset/base64/base64.min.js?v={{$smarty.const.FRIENDICA_VERSION}}"></script>
|
||||||
<script type="text/javascript" src="view/asset/dompurify/dist/purify.min.js?v={{$smarty.const.FRIENDICA_VERSION}}"></script>
|
<script type="text/javascript" src="view/asset/dompurify/dist/purify.min.js?v={{$smarty.const.FRIENDICA_VERSION}}"></script>
|
||||||
|
|
Loading…
Reference in a new issue