зеркало из https://github.com/mozilla/gecko-dev.git
Bug 591705 Don't animate on tab view startup [r+a=dietrich]
This commit is contained in:
Родитель
1f55f20dd4
Коммит
85b674a456
|
@ -62,7 +62,8 @@
|
||||||
// bounds - a <Rect>; otherwise based on the locations of the provided elements
|
// bounds - a <Rect>; otherwise based on the locations of the provided elements
|
||||||
// container - a DOM element to use as the container for this groupItem; otherwise will create
|
// container - a DOM element to use as the container for this groupItem; otherwise will create
|
||||||
// title - the title for the groupItem; otherwise blank
|
// title - the title for the groupItem; otherwise blank
|
||||||
// dontPush - true if this groupItem shouldn't push away on creation; default is false
|
// dontPush - true if this groupItem shouldn't push away or snap on creation; default is false
|
||||||
|
// immediately - true if we want all placement immediately, not with animation
|
||||||
let GroupItem = function GroupItem(listOfEls, options) {
|
let GroupItem = function GroupItem(listOfEls, options) {
|
||||||
try {
|
try {
|
||||||
if (typeof options == 'undefined')
|
if (typeof options == 'undefined')
|
||||||
|
@ -110,6 +111,7 @@ let GroupItem = function GroupItem(listOfEls, options) {
|
||||||
}
|
}
|
||||||
|
|
||||||
var $container = options.container;
|
var $container = options.container;
|
||||||
|
let immediately = options.immediately || $container ? true : false;
|
||||||
if (!$container) {
|
if (!$container) {
|
||||||
$container = iQ('<div>')
|
$container = iQ('<div>')
|
||||||
.addClass('groupItem')
|
.addClass('groupItem')
|
||||||
|
@ -169,7 +171,7 @@ let GroupItem = function GroupItem(listOfEls, options) {
|
||||||
this.$titleShield = iQ('.title-shield', this.$titlebar);
|
this.$titleShield = iQ('.title-shield', this.$titlebar);
|
||||||
this.setTitle(options.title || this.defaultName);
|
this.setTitle(options.title || this.defaultName);
|
||||||
|
|
||||||
var titleUnfocus = function() {
|
var titleUnfocus = function(immediately) {
|
||||||
self.$titleShield.show();
|
self.$titleShield.show();
|
||||||
if (!self.getTitle()) {
|
if (!self.getTitle()) {
|
||||||
self.$title
|
self.$title
|
||||||
|
@ -177,13 +179,19 @@ let GroupItem = function GroupItem(listOfEls, options) {
|
||||||
.val(self.defaultName);
|
.val(self.defaultName);
|
||||||
} else {
|
} else {
|
||||||
self.$title
|
self.$title
|
||||||
.css({"background":"none"})
|
.css({"background":"none"});
|
||||||
.animate({
|
if (immediately) {
|
||||||
"padding-left": "1px"
|
self.$title.css({
|
||||||
}, {
|
"padding-left": "1px"
|
||||||
duration: 200,
|
});
|
||||||
easing: "tabviewBounce"
|
} else {
|
||||||
});
|
self.$title.animate({
|
||||||
|
"padding-left": "1px"
|
||||||
|
}, {
|
||||||
|
duration: 200,
|
||||||
|
easing: "tabviewBounce"
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -218,7 +226,7 @@ let GroupItem = function GroupItem(listOfEls, options) {
|
||||||
})
|
})
|
||||||
.keyup(handleKeyPress);
|
.keyup(handleKeyPress);
|
||||||
|
|
||||||
titleUnfocus();
|
titleUnfocus(immediately);
|
||||||
|
|
||||||
if (this.locked.title)
|
if (this.locked.title)
|
||||||
this.$title.addClass('name-locked');
|
this.$title.addClass('name-locked');
|
||||||
|
@ -268,14 +276,14 @@ let GroupItem = function GroupItem(listOfEls, options) {
|
||||||
this._addHandlers($container);
|
this._addHandlers($container);
|
||||||
|
|
||||||
if (!this.locked.bounds)
|
if (!this.locked.bounds)
|
||||||
this.setResizable(true);
|
this.setResizable(true, immediately);
|
||||||
|
|
||||||
GroupItems.register(this);
|
GroupItems.register(this);
|
||||||
|
|
||||||
// ___ Position
|
// ___ Position
|
||||||
var immediately = $container ? true : false;
|
|
||||||
this.setBounds(rectToBe, immediately);
|
this.setBounds(rectToBe, immediately);
|
||||||
this.snap();
|
if (!options.dontPush)
|
||||||
|
this.snap();
|
||||||
if ($container)
|
if ($container)
|
||||||
this.setBounds(rectToBe, immediately);
|
this.setBounds(rectToBe, immediately);
|
||||||
|
|
||||||
|
@ -556,7 +564,8 @@ window.GroupItem.prototype = Utils.extend(new Item(), new Subscribable(), {
|
||||||
// a - The item to add. Can be an <Item>, a DOM element or an iQ object.
|
// a - The item to add. Can be an <Item>, a DOM element or an iQ object.
|
||||||
// The latter two must refer to the container of an <Item>.
|
// The latter two must refer to the container of an <Item>.
|
||||||
// dropPos - An object with left and top properties referring to the location dropped at. Optional.
|
// dropPos - An object with left and top properties referring to the location dropped at. Optional.
|
||||||
// options - An object with optional settings for this call. Currently the only one is dontArrange.
|
// options - An object with optional settings for this call. Currently this includes dontArrange
|
||||||
|
// and immediately
|
||||||
add: function(a, dropPos, options) {
|
add: function(a, dropPos, options) {
|
||||||
try {
|
try {
|
||||||
var item;
|
var item;
|
||||||
|
@ -646,15 +655,16 @@ window.GroupItem.prototype = Utils.extend(new Item(), new Subscribable(), {
|
||||||
item.setParent(this);
|
item.setParent(this);
|
||||||
|
|
||||||
if (typeof item.setResizable == 'function')
|
if (typeof item.setResizable == 'function')
|
||||||
item.setResizable(false);
|
item.setResizable(false, options.immediately);
|
||||||
|
|
||||||
if (item.tab == gBrowser.selectedTab)
|
if (item.tab == gBrowser.selectedTab)
|
||||||
GroupItems.setActiveGroupItem(this);
|
GroupItems.setActiveGroupItem(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!options.dontArrange) {
|
if (!options.dontArrange) {
|
||||||
this.arrange();
|
this.arrange({animate: !options.immediately});
|
||||||
}
|
}
|
||||||
|
|
||||||
UI.setReorderTabsOnHide(this);
|
UI.setReorderTabsOnHide(this);
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
Utils.log('GroupItem.add error', e);
|
Utils.log('GroupItem.add error', e);
|
||||||
|
@ -668,7 +678,8 @@ window.GroupItem.prototype = Utils.extend(new Item(), new Subscribable(), {
|
||||||
//
|
//
|
||||||
// a - The item to remove. Can be an <Item>, a DOM element or an iQ object.
|
// a - The item to remove. Can be an <Item>, a DOM element or an iQ object.
|
||||||
// The latter two must refer to the container of an <Item>.
|
// The latter two must refer to the container of an <Item>.
|
||||||
// options - An object with optional settings for this call. Currently the only one is dontArrange.
|
// options - An object with optional settings for this call. Currently this includes
|
||||||
|
// dontArrange and immediately
|
||||||
remove: function(a, options) {
|
remove: function(a, options) {
|
||||||
try {
|
try {
|
||||||
var $el;
|
var $el;
|
||||||
|
@ -699,12 +710,12 @@ window.GroupItem.prototype = Utils.extend(new Item(), new Subscribable(), {
|
||||||
item.removeSubscriber(this, "close");
|
item.removeSubscriber(this, "close");
|
||||||
|
|
||||||
if (typeof item.setResizable == 'function')
|
if (typeof item.setResizable == 'function')
|
||||||
item.setResizable(true);
|
item.setResizable(true, options.immediately);
|
||||||
|
|
||||||
if (!this._children.length && !this.locked.close && !this.getTitle() && !options.dontClose) {
|
if (!this._children.length && !this.locked.close && !this.getTitle() && !options.dontClose) {
|
||||||
this.close();
|
this.close();
|
||||||
} else if (!options.dontArrange) {
|
} else if (!options.dontArrange) {
|
||||||
this.arrange();
|
this.arrange({animate: !options.immediately});
|
||||||
}
|
}
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
Utils.log(e);
|
Utils.log(e);
|
||||||
|
@ -782,15 +793,15 @@ window.GroupItem.prototype = Utils.extend(new Item(), new Subscribable(), {
|
||||||
var bb = this.getContentBounds();
|
var bb = this.getContentBounds();
|
||||||
var count = this._children.length;
|
var count = this._children.length;
|
||||||
if (!this.shouldStack(count)) {
|
if (!this.shouldStack(count)) {
|
||||||
|
if (!options)
|
||||||
|
options = {};
|
||||||
|
|
||||||
var animate;
|
var animate;
|
||||||
if (!options || typeof options.animate == 'undefined')
|
if (typeof options.animate == 'undefined')
|
||||||
animate = true;
|
animate = true;
|
||||||
else
|
else
|
||||||
animate = options.animate;
|
animate = options.animate;
|
||||||
|
|
||||||
if (typeof options == 'undefined')
|
|
||||||
options = {};
|
|
||||||
|
|
||||||
this._children.forEach(function(child) {
|
this._children.forEach(function(child) {
|
||||||
child.removeClass("stacked")
|
child.removeClass("stacked")
|
||||||
});
|
});
|
||||||
|
@ -1151,15 +1162,15 @@ window.GroupItem.prototype = Utils.extend(new Item(), new Subscribable(), {
|
||||||
// ----------
|
// ----------
|
||||||
// Function: setResizable
|
// Function: setResizable
|
||||||
// Sets whether the groupItem is resizable and updates the UI accordingly.
|
// Sets whether the groupItem is resizable and updates the UI accordingly.
|
||||||
setResizable: function(value) {
|
setResizable: function(value, immediately) {
|
||||||
this.resizeOptions.minWidth = 90;
|
this.resizeOptions.minWidth = 90;
|
||||||
this.resizeOptions.minHeight = 90;
|
this.resizeOptions.minHeight = 90;
|
||||||
|
|
||||||
if (value) {
|
if (value) {
|
||||||
this.$resizer.fadeIn();
|
immediately ? this.$resizer.show() : this.$resizer.fadeIn();
|
||||||
this.resizable(true);
|
this.resizable(true);
|
||||||
} else {
|
} else {
|
||||||
this.$resizer.fadeOut();
|
immediately ? this.$resizer.hide() : this.$resizer.fadeOut();
|
||||||
this.resizable(false);
|
this.resizable(false);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -1377,7 +1388,8 @@ window.GroupItems = {
|
||||||
var groupItem = groupItemData[id];
|
var groupItem = groupItemData[id];
|
||||||
if (this.groupItemStorageSanity(groupItem)) {
|
if (this.groupItemStorageSanity(groupItem)) {
|
||||||
var options = {
|
var options = {
|
||||||
dontPush: true
|
dontPush: true,
|
||||||
|
immediately: true
|
||||||
};
|
};
|
||||||
|
|
||||||
new GroupItem([], Utils.extend({}, groupItem, options));
|
new GroupItem([], Utils.extend({}, groupItem, options));
|
||||||
|
@ -1505,12 +1517,12 @@ window.GroupItems = {
|
||||||
// ----------
|
// ----------
|
||||||
// Function: newTab
|
// Function: newTab
|
||||||
// Given a <TabItem>, files it in the appropriate groupItem.
|
// Given a <TabItem>, files it in the appropriate groupItem.
|
||||||
newTab: function(tabItem) {
|
newTab: function(tabItem, options) {
|
||||||
let activeGroupItem = this.getActiveGroupItem();
|
let activeGroupItem = this.getActiveGroupItem();
|
||||||
let orphanTab = this.getActiveOrphanTab();
|
let orphanTab = this.getActiveOrphanTab();
|
||||||
// Utils.log('newTab', activeGroupItem, orphanTab);
|
// Utils.log('newTab', activeGroupItem, orphanTab);
|
||||||
if (activeGroupItem) {
|
if (activeGroupItem) {
|
||||||
activeGroupItem.add(tabItem);
|
activeGroupItem.add(tabItem, null, options);
|
||||||
} else if (orphanTab) {
|
} else if (orphanTab) {
|
||||||
let newGroupItemBounds = orphanTab.getBoundsWithTitle();
|
let newGroupItemBounds = orphanTab.getBoundsWithTitle();
|
||||||
newGroupItemBounds.inset(-40,-40);
|
newGroupItemBounds.inset(-40,-40);
|
||||||
|
@ -1518,7 +1530,7 @@ window.GroupItems = {
|
||||||
newGroupItem.snap();
|
newGroupItem.snap();
|
||||||
this.setActiveGroupItem(newGroupItem);
|
this.setActiveGroupItem(newGroupItem);
|
||||||
} else {
|
} else {
|
||||||
this.positionNewTabAtBottom(tabItem);
|
this.positionNewTabAtBottom(tabItem, options);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -1528,7 +1540,9 @@ window.GroupItems = {
|
||||||
// TODO: Make more robust and improve documentation,
|
// TODO: Make more robust and improve documentation,
|
||||||
// Also, this probably belongs in tabitems.js
|
// Also, this probably belongs in tabitems.js
|
||||||
// Bug 586558
|
// Bug 586558
|
||||||
positionNewTabAtBottom: function(tabItem) {
|
// TODO: perhaps this should be positioned not at the bottom but in an
|
||||||
|
// empty part of the frame: Bug 592932
|
||||||
|
positionNewTabAtBottom: function(tabItem, options) {
|
||||||
let windowBounds = Items.getSafeWindowBounds();
|
let windowBounds = Items.getSafeWindowBounds();
|
||||||
|
|
||||||
let itemBounds = new Rect(
|
let itemBounds = new Rect(
|
||||||
|
@ -1538,7 +1552,10 @@ window.GroupItems = {
|
||||||
TabItems.tabHeight
|
TabItems.tabHeight
|
||||||
);
|
);
|
||||||
|
|
||||||
tabItem.setBounds(itemBounds);
|
if (!options)
|
||||||
|
options = {};
|
||||||
|
|
||||||
|
tabItem.setBounds(itemBounds, options.immediately);
|
||||||
},
|
},
|
||||||
|
|
||||||
// ----------
|
// ----------
|
||||||
|
|
|
@ -724,13 +724,11 @@ window.Item.prototype = {
|
||||||
droppable: function(value) {
|
droppable: function(value) {
|
||||||
try {
|
try {
|
||||||
var $container = iQ(this.container);
|
var $container = iQ(this.container);
|
||||||
if (value)
|
if (value) {
|
||||||
$container.addClass('iq-droppable');
|
|
||||||
else {
|
|
||||||
Utils.assert(this.dropOptions, 'dropOptions');
|
Utils.assert(this.dropOptions, 'dropOptions');
|
||||||
|
$container.addClass('iq-droppable');
|
||||||
|
} else
|
||||||
$container.removeClass('iq-droppable');
|
$container.removeClass('iq-droppable');
|
||||||
}
|
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
Utils.log(e);
|
Utils.log(e);
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,7 +48,7 @@
|
||||||
//
|
//
|
||||||
// Parameters:
|
// Parameters:
|
||||||
// tab - a xul:tab
|
// tab - a xul:tab
|
||||||
window.TabItem = function(tab) {
|
window.TabItem = function(tab, options) {
|
||||||
|
|
||||||
Utils.assert(tab, "tab");
|
Utils.assert(tab, "tab");
|
||||||
|
|
||||||
|
@ -56,6 +56,9 @@ window.TabItem = function(tab) {
|
||||||
// register this as the tab's tabItem
|
// register this as the tab's tabItem
|
||||||
this.tab.tabItem = this;
|
this.tab.tabItem = this;
|
||||||
|
|
||||||
|
if (!options)
|
||||||
|
options = {};
|
||||||
|
|
||||||
// ___ set up div
|
// ___ set up div
|
||||||
var $div = iQ('<div>')
|
var $div = iQ('<div>')
|
||||||
.addClass('tab')
|
.addClass('tab')
|
||||||
|
@ -97,6 +100,10 @@ window.TabItem = function(tab) {
|
||||||
// ___ superclass setup
|
// ___ superclass setup
|
||||||
this._init($div[0]);
|
this._init($div[0]);
|
||||||
|
|
||||||
|
// ___ attempt to reconnect to data from Storage
|
||||||
|
this._hasBeenDrawn = false;
|
||||||
|
let reconnected = TabItems.reconnect(this);
|
||||||
|
|
||||||
// ___ drag/drop
|
// ___ drag/drop
|
||||||
// override dropOptions with custom tabitem methods
|
// override dropOptions with custom tabitem methods
|
||||||
// This is mostly to support the phantom groupItems.
|
// This is mostly to support the phantom groupItems.
|
||||||
|
@ -164,7 +171,6 @@ window.TabItem = function(tab) {
|
||||||
};
|
};
|
||||||
|
|
||||||
this.draggable();
|
this.draggable();
|
||||||
this.droppable(true);
|
|
||||||
|
|
||||||
// ___ more div setup
|
// ___ more div setup
|
||||||
$div.mousedown(function(e) {
|
$div.mousedown(function(e) {
|
||||||
|
@ -194,17 +200,20 @@ window.TabItem = function(tab) {
|
||||||
.addClass('expander')
|
.addClass('expander')
|
||||||
.appendTo($div);
|
.appendTo($div);
|
||||||
|
|
||||||
// ___ additional setup
|
|
||||||
this.reconnected = false;
|
|
||||||
this._hasBeenDrawn = false;
|
|
||||||
this.setResizable(true);
|
|
||||||
|
|
||||||
this._updateDebugBounds();
|
this._updateDebugBounds();
|
||||||
|
|
||||||
TabItems.register(this);
|
TabItems.register(this);
|
||||||
|
|
||||||
if (!TabItems.reconnect(this))
|
if (!this.reconnected) {
|
||||||
GroupItems.newTab(this);
|
GroupItems.newTab(this, options);
|
||||||
|
}
|
||||||
|
|
||||||
|
// tabs which were not reconnected at all or were not immediately added
|
||||||
|
// to a group get the same treatment.
|
||||||
|
if (!this.reconnected || (reconnected && !reconnected.addedToGroup) ) {
|
||||||
|
this.setResizable(true, options.immediately);
|
||||||
|
this.droppable(true);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
window.TabItem.prototype = Utils.extend(new Item(), new Subscribable(), {
|
window.TabItem.prototype = Utils.extend(new Item(), new Subscribable(), {
|
||||||
|
@ -364,9 +373,9 @@ window.TabItem.prototype = Utils.extend(new Item(), new Subscribable(), {
|
||||||
|
|
||||||
if (css.fontSize && !this.inStack()) {
|
if (css.fontSize && !this.inStack()) {
|
||||||
if (css.fontSize < fontSizeRange.min)
|
if (css.fontSize < fontSizeRange.min)
|
||||||
$title.fadeOut();
|
immediately ? $title.hide() : $title.fadeOut();
|
||||||
else
|
else
|
||||||
$title.fadeIn();
|
immediately ? $title.show() : $title.fadeIn();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (css.width) {
|
if (css.width) {
|
||||||
|
@ -470,17 +479,16 @@ window.TabItem.prototype = Utils.extend(new Item(), new Subscribable(), {
|
||||||
// Function: setResizable
|
// Function: setResizable
|
||||||
// If value is true, makes this item resizable, otherwise non-resizable.
|
// If value is true, makes this item resizable, otherwise non-resizable.
|
||||||
// Shows/hides a visible resize handle as appropriate.
|
// Shows/hides a visible resize handle as appropriate.
|
||||||
setResizable: function(value) {
|
setResizable: function(value, immediately) {
|
||||||
var $resizer = iQ('.expander', this.container);
|
var $resizer = iQ('.expander', this.container);
|
||||||
|
|
||||||
this.resizeOptions.minWidth = TabItems.minTabWidth;
|
|
||||||
this.resizeOptions.minHeight = TabItems.minTabWidth * (TabItems.tabHeight / TabItems.tabWidth);
|
|
||||||
|
|
||||||
if (value) {
|
if (value) {
|
||||||
$resizer.fadeIn();
|
this.resizeOptions.minWidth = TabItems.minTabWidth;
|
||||||
|
this.resizeOptions.minHeight = TabItems.minTabWidth * (TabItems.tabHeight / TabItems.tabWidth);
|
||||||
|
immediately ? $resizer.show() : $resizer.fadeIn();
|
||||||
this.resizable(true);
|
this.resizable(true);
|
||||||
} else {
|
} else {
|
||||||
$resizer.fadeOut();
|
immediately ? $resizer.hide() : $resizer.fadeOut();
|
||||||
this.resizable(false);
|
this.resizable(false);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -695,7 +703,7 @@ window.TabItems = {
|
||||||
if (tab.ownerDocument.defaultView != gWindow)
|
if (tab.ownerDocument.defaultView != gWindow)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
self.link(tab);
|
self.link(tab, {immediately: true});
|
||||||
self.update(tab);
|
self.update(tab);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
@ -816,11 +824,11 @@ window.TabItems = {
|
||||||
// ----------
|
// ----------
|
||||||
// Function: link
|
// Function: link
|
||||||
// Takes in a xul:tab.
|
// Takes in a xul:tab.
|
||||||
link: function(tab){
|
link: function(tab, options){
|
||||||
try {
|
try {
|
||||||
Utils.assertThrow(tab, "tab");
|
Utils.assertThrow(tab, "tab");
|
||||||
Utils.assertThrow(!tab.tabItem, "shouldn't already be linked");
|
Utils.assertThrow(!tab.tabItem, "shouldn't already be linked");
|
||||||
new TabItem(tab); // sets tab.tabItem to itself
|
new TabItem(tab, options); // sets tab.tabItem to itself
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
Utils.log(e);
|
Utils.log(e);
|
||||||
}
|
}
|
||||||
|
@ -981,7 +989,7 @@ window.TabItems = {
|
||||||
let tabData = Storage.getTabData(item.tab);
|
let tabData = Storage.getTabData(item.tab);
|
||||||
if (tabData && this.storageSanity(tabData)) {
|
if (tabData && this.storageSanity(tabData)) {
|
||||||
if (item.parent)
|
if (item.parent)
|
||||||
item.parent.remove(item);
|
item.parent.remove(item, {immediately: true});
|
||||||
|
|
||||||
item.setBounds(tabData.bounds, true);
|
item.setBounds(tabData.bounds, true);
|
||||||
|
|
||||||
|
@ -991,7 +999,7 @@ window.TabItems = {
|
||||||
if (tabData.groupID) {
|
if (tabData.groupID) {
|
||||||
var groupItem = GroupItems.groupItem(tabData.groupID);
|
var groupItem = GroupItems.groupItem(tabData.groupID);
|
||||||
if (groupItem) {
|
if (groupItem) {
|
||||||
groupItem.add(item);
|
groupItem.add(item, null, {immediately: true});
|
||||||
|
|
||||||
if (item.tab == gBrowser.selectedTab)
|
if (item.tab == gBrowser.selectedTab)
|
||||||
GroupItems.setActiveGroupItem(item.parent);
|
GroupItems.setActiveGroupItem(item.parent);
|
||||||
|
@ -1010,7 +1018,7 @@ window.TabItems = {
|
||||||
}
|
}
|
||||||
|
|
||||||
item.reconnected = true;
|
item.reconnected = true;
|
||||||
found = true;
|
found = {addedToGroup: tabData.groupID};
|
||||||
} else
|
} else
|
||||||
item.reconnected = item.tab.linkedBrowser.currentURI.spec != 'about:blank';
|
item.reconnected = item.tab.linkedBrowser.currentURI.spec != 'about:blank';
|
||||||
|
|
||||||
|
|
Загрузка…
Ссылка в новой задаче