mirror of
https://github.com/jwinterm/modoboa.git
synced 2026-10-18 05:51:26 +02:00
Ticket #9
Mootools update (1.2.4 now). Added custom confirmation box using SqueezeBox. Bugfix: avoid main frame repositionning when loading a SqueezeBox. Bugfix: update autoreply address alias when modifying an email address.
This commit is contained in:
@@ -258,7 +258,7 @@ user quotas::
|
||||
|
||||
user_query = SELECT path AS home, uid, gid, concat('*:storage=', quota, 'M') AS quota_rule FROM admin_mailbox WHERE full_address = '%u'
|
||||
|
||||
Tips to server Mailng behind Apache2
|
||||
Tips to serve Mailng behind Apache2
|
||||
------------------------------------
|
||||
|
||||
First, be sure to have apache2 and mod_python installed on your
|
||||
|
||||
@@ -66,6 +66,8 @@ class Mailbox(models.Model):
|
||||
|
||||
def create_dir(self, domain):
|
||||
path = "%s/%s/%s" % (settings.STORAGE_PATH, domain.name, self.address)
|
||||
if os.path.exists(path):
|
||||
return True
|
||||
if not exec_as_vuser("mkdir -p %s" % path):
|
||||
return False
|
||||
if self.mbtype == "mbox":
|
||||
|
||||
+10
-3
@@ -15,6 +15,7 @@ from forms import MailboxForm, DomainForm, AliasForm, PermissionForm
|
||||
from mailng.lib.authbackends import crypt_password
|
||||
from mailng.lib import _render, _ctx_ok, _ctx_ko
|
||||
from mailng.lib import events
|
||||
import copy
|
||||
|
||||
def is_superuser(user):
|
||||
if not user.is_superuser:
|
||||
@@ -182,6 +183,7 @@ def newmailbox(request, dom_id=None):
|
||||
def editmailbox(request, dom_id, mbox_id=None):
|
||||
mb = Mailbox.objects.get(pk=mbox_id)
|
||||
if request.method == "POST":
|
||||
oldmb = copy.deepcopy(mb)
|
||||
form = MailboxForm(request.POST, instance=mb)
|
||||
error = None
|
||||
if form.is_valid():
|
||||
@@ -206,6 +208,7 @@ def editmailbox(request, dom_id, mbox_id=None):
|
||||
mb.quota = mb.domain.quota
|
||||
mb.full_address = "%s@%s" % (mb.address, mb.domain.name)
|
||||
mb.save()
|
||||
events.raiseEvent("ModifyMailbox", mbox=mb, oldmbox=oldmb)
|
||||
ctx = _ctx_ok(reverse(admin.views.mailboxes, args=[dom_id]))
|
||||
return HttpResponse(simplejson.dumps(ctx),
|
||||
mimetype="application/json")
|
||||
@@ -228,11 +231,15 @@ def editmailbox(request, dom_id, mbox_id=None):
|
||||
def delmailbox(request, dom_id, mbox_id=None):
|
||||
mb = Mailbox.objects.get(pk=mbox_id)
|
||||
events.raiseEvent("DeleteMailbox", mbox=mb)
|
||||
mb.delete_dir()
|
||||
if not request.GET.has_key("keepdir") or request.GET["keepdir"] != "true":
|
||||
mb.delete_dir()
|
||||
mb.user.delete()
|
||||
mb.delete()
|
||||
return HttpResponseRedirect(reverse(admin.views.mailboxes,
|
||||
args=[dom_id]))
|
||||
ctx = _ctx_ok("");
|
||||
return HttpResponse(simplejson.dumps(ctx),
|
||||
mimetype="application/json")
|
||||
# return HttpResponseRedirect(reverse(admin.views.mailboxes,
|
||||
# args=[dom_id]))
|
||||
|
||||
@login_required
|
||||
@permission_required("admin.view_aliases")
|
||||
|
||||
@@ -15,6 +15,7 @@ def init():
|
||||
events.register("DeleteDomain", onDeleteDomain)
|
||||
events.register("CreateMailbox", onCreateMailbox)
|
||||
events.register("DeleteMailbox", onDeleteMailbox)
|
||||
events.register("ModifyMailbox", onModifyMailbox)
|
||||
|
||||
def urls():
|
||||
return ()
|
||||
@@ -29,7 +30,7 @@ def onCreateDomain(**kwargs):
|
||||
def onDeleteDomain(**kwargs):
|
||||
dom = kwargs["dom"]
|
||||
trans = Transport.objects.get(domain="autoreply.%s" % dom.name)
|
||||
trabs.delete()
|
||||
trans.delete()
|
||||
|
||||
def onCreateMailbox(**kwargs):
|
||||
mbox = kwargs["mbox"]
|
||||
@@ -41,5 +42,19 @@ def onCreateMailbox(**kwargs):
|
||||
|
||||
def onDeleteMailbox(**kwargs):
|
||||
mbox = kwargs["mbox"]
|
||||
alias = Alias.objects.get(full_address=mbox.full_address)
|
||||
alias.delete()
|
||||
try:
|
||||
alias = Alias.objects.get(full_address=mbox.full_address)
|
||||
alias.delete()
|
||||
except Alias.DoesNotExist:
|
||||
pass
|
||||
|
||||
def onModifyMailbox(**kwargs):
|
||||
mbox = kwargs["mbox"]
|
||||
oldmbox = kwargs["oldmbox"]
|
||||
if oldmbox.full_address == mbox.full_address:
|
||||
return
|
||||
alias = Alias.objects.get(full_address=oldmbox.full_address)
|
||||
alias.full_address = mbox.full_address
|
||||
alias.autoreply_address = \
|
||||
"%s@autoreply.%s" % (mbox.full_address, mbox.domain.name)
|
||||
alias.save()
|
||||
|
||||
@@ -10,6 +10,7 @@ events = ["CreateDomain",
|
||||
"DeleteDomain",
|
||||
"CreateMailbox",
|
||||
"DeleteMailbox",
|
||||
"ModifyMailbox",
|
||||
|
||||
"UserMenuDisplay"]
|
||||
|
||||
|
||||
+38
-33
@@ -17,43 +17,48 @@ window.addEvent('domready', function(){
|
||||
}
|
||||
});
|
||||
|
||||
var toggleModal = function(backgroundColour, options) {
|
||||
// modal view for the whole screen
|
||||
// ver 2.02 17/10/2008 03:42:06
|
||||
if ($("modal")) {
|
||||
$("modal").dispose();
|
||||
return false;
|
||||
get_iframe_body = function(id) {
|
||||
var saf = navigator.userAgent.match(/Safari/i);
|
||||
var safver = (saf ? parseFloat(navigator.userAgent.match(/[\d\.]+Safari/i)) : 0);
|
||||
var targetif = $(id);
|
||||
var data;
|
||||
|
||||
if (targetif.contentDocument && (!saf || (saf && safver >= 3))) {
|
||||
// NS6 & Gecko & Opera & IE7+
|
||||
if (!saf || (saf && safver >= 3)) {
|
||||
data = targetif.contentDocument.defaultView.document.body;
|
||||
} else {
|
||||
data = targetif.document.body;
|
||||
}
|
||||
} else if (targetif.contentWindow && !saf) {
|
||||
// IE 5.5 & 6.x
|
||||
data = targetif.contentWindow.document.body;
|
||||
}
|
||||
|
||||
var options = $merge({
|
||||
zIndex: 10000000,
|
||||
opacity: .8,
|
||||
events: $empty()
|
||||
}, options);
|
||||
|
||||
if (!$type(backgroundColour) && !$("modal"))
|
||||
return false;
|
||||
|
||||
return new Element("div", {
|
||||
id: "modal",
|
||||
styles: {
|
||||
position: "absolute",
|
||||
top: 0,
|
||||
left: 0,
|
||||
width: window.getScrollWidth(),
|
||||
height: window.getScrollHeight(),
|
||||
background: backgroundColour,
|
||||
"z-index": options.zIndex
|
||||
},
|
||||
opacity: options.opacity,
|
||||
events: options.events
|
||||
}).inject(document.body);
|
||||
return (data);
|
||||
}
|
||||
|
||||
confirmation = function(question) {
|
||||
confirmation = function(question, action, callback) {
|
||||
SqueezeBox.initialize({
|
||||
size: {x: 300, y: 150},
|
||||
handler: 'iframe'
|
||||
size: {x: 300, y: 130},
|
||||
handler: 'iframe',
|
||||
onClose: function(content) {
|
||||
var ibody = get_iframe_body(this.asset);
|
||||
var elt = ibody.getElement("input[name=result]");
|
||||
|
||||
if (elt.get("value") == "ok") {
|
||||
params = ""
|
||||
if (typeof callback != "undefined") {
|
||||
params = callback(ibody);
|
||||
}
|
||||
new Request({
|
||||
method: "get",
|
||||
url: action.get("href"),
|
||||
onSuccess: function(res) {
|
||||
window.location.reload();
|
||||
}
|
||||
}).send(params);
|
||||
}
|
||||
}
|
||||
});
|
||||
SqueezeBox.open("/mailng/main/confirm/?question=" + question);
|
||||
}
|
||||
|
||||
+10
-4
@@ -20,11 +20,17 @@ window.addEvent('domready', function() {
|
||||
|
||||
if ($$("a[name=deleteMb]"))
|
||||
$$("a[name=deleteMb]").addEvent('click', function(event) {
|
||||
/*if (!confirm(gettext("Delete this mailbox?")))
|
||||
event.stop();*/
|
||||
// the function also returns the object so you can tweak it from the outside:
|
||||
confirmation(gettext("Delete this mailbox?"));
|
||||
event.stop();
|
||||
confirmation(gettext("Delete this mailbox?"), this, function(body) {
|
||||
result = ""
|
||||
body.getElements("input[type=checkbox]:checked").each(function(obj) {
|
||||
if (result != "") {
|
||||
result += "&";
|
||||
}
|
||||
result += obj.name + "=true";
|
||||
});
|
||||
return result;
|
||||
});
|
||||
});
|
||||
|
||||
if ($$("a[name=deleteAlias]"))
|
||||
|
||||
+5
-5
@@ -2,14 +2,14 @@ window.addEvent("domready", function() {
|
||||
sqbsubmit = function(obj, dest, id, callback) {
|
||||
obj.set('send', {
|
||||
onSuccess: function(responseText) {
|
||||
response = JSON.decode(responseText);
|
||||
if (response.status == "ko") {
|
||||
$(dest).set("html", response.content);
|
||||
var decode = JSON.decode(responseText);
|
||||
if (decode.status == "ko") {
|
||||
$(dest).set("html", decode.content);
|
||||
$(id).addEvent("submit", callback);
|
||||
} else {
|
||||
if (decode.url != "")
|
||||
parent.location.href = decode.url;
|
||||
parent.SqueezeBox.close();
|
||||
if (response.url != "")
|
||||
parent.location.href = response.url;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1,18 +1,51 @@
|
||||
//MooTools More, <http://mootools.net/more>. Copyright (c) 2006-2009 Aaron Newton <http://clientcide.com/>, Valerio Proietti <http://mad4milk.net> & the MooTools team <http://mootools.net/developers>, MIT Style License.
|
||||
|
||||
/*
|
||||
---
|
||||
|
||||
script: More.js
|
||||
|
||||
description: MooTools More
|
||||
|
||||
license: MIT-style license
|
||||
|
||||
authors:
|
||||
- Guillermo Rauch
|
||||
- Thomas Aylott
|
||||
- Scott Kyle
|
||||
|
||||
requires:
|
||||
- core:1.2.4/MooTools
|
||||
|
||||
provides: [MooTools.More]
|
||||
|
||||
...
|
||||
*/
|
||||
|
||||
MooTools.More = {
|
||||
'version': '1.2.3.1'
|
||||
'version': '1.2.4.2dev',
|
||||
'build': '%build%'
|
||||
};
|
||||
|
||||
/*
|
||||
Script: Fx.Slide.js
|
||||
Effect to slide an element in and out of view.
|
||||
---
|
||||
|
||||
License:
|
||||
MIT-style license.
|
||||
script: Fx.Slide.js
|
||||
|
||||
Authors:
|
||||
Valerio Proietti
|
||||
description: Effect to slide an element in and out of view.
|
||||
|
||||
license: MIT-style license
|
||||
|
||||
authors:
|
||||
- Valerio Proietti
|
||||
|
||||
requires:
|
||||
- core:1.2.4/Fx Element.Style
|
||||
- /MooTools.More
|
||||
|
||||
provides: [Fx.Slide]
|
||||
|
||||
...
|
||||
*/
|
||||
|
||||
Fx.Slide = new Class({
|
||||
@@ -32,7 +65,7 @@ Fx.Slide = new Class({
|
||||
this.parent(options);
|
||||
var wrapper = this.element.retrieve('wrapper');
|
||||
this.wrapper = wrapper || new Element('div', {
|
||||
styles: $extend(this.element.getStyles('margin', 'position'), {overflow: 'hidden'})
|
||||
styles: this.element.getStyles('margin', 'position', 'overflow')
|
||||
}).wraps(this.element);
|
||||
this.element.store('wrapper', this.wrapper).setStyle('margin', 0);
|
||||
this.now = [];
|
||||
|
||||
+446
-153
@@ -1,24 +1,28 @@
|
||||
/*
|
||||
Script: Core.js
|
||||
MooTools - My Object Oriented JavaScript Tools.
|
||||
---
|
||||
|
||||
License:
|
||||
MIT-style license.
|
||||
script: Core.js
|
||||
|
||||
Copyright:
|
||||
Copyright (c) 2006-2008 [Valerio Proietti](http://mad4milk.net/).
|
||||
description: The core of MooTools, contains all the base functions and the Native and Hash implementations. Required by all the other scripts.
|
||||
|
||||
Code & Documentation:
|
||||
[The MooTools production team](http://mootools.net/developers/).
|
||||
license: MIT-style license.
|
||||
|
||||
Inspiration:
|
||||
- Class implementation inspired by [Base.js](http://dean.edwards.name/weblog/2006/03/base/) Copyright (c) 2006 Dean Edwards, [GNU Lesser General Public License](http://opensource.org/licenses/lgpl-license.php)
|
||||
- Some functionality inspired by [Prototype.js](http://prototypejs.org) Copyright (c) 2005-2007 Sam Stephenson, [MIT License](http://opensource.org/licenses/mit-license.php)
|
||||
copyright: Copyright (c) 2006-2008 [Valerio Proietti](http://mad4milk.net/).
|
||||
|
||||
authors: The MooTools production team (http://mootools.net/developers/)
|
||||
|
||||
inspiration:
|
||||
- Class implementation inspired by [Base.js](http://dean.edwards.name/weblog/2006/03/base/) Copyright (c) 2006 Dean Edwards, [GNU Lesser General Public License](http://opensource.org/licenses/lgpl-license.php)
|
||||
- Some functionality inspired by [Prototype.js](http://prototypejs.org) Copyright (c) 2005-2007 Sam Stephenson, [MIT License](http://opensource.org/licenses/mit-license.php)
|
||||
|
||||
provides: [Mootools, Native, Hash.base, Array.each, $util]
|
||||
|
||||
...
|
||||
*/
|
||||
|
||||
var MooTools = {
|
||||
'version': '1.2.3',
|
||||
'build': '4980aa0fb74d2f6eb80bcd9f5b8e1fd6fbb8f607'
|
||||
'version': '1.2.4',
|
||||
'build': '0d9113241a90b9cd5643b926795852a2026710d4'
|
||||
};
|
||||
|
||||
var Native = function(options){
|
||||
@@ -288,11 +292,21 @@ function $unlink(object){
|
||||
|
||||
|
||||
/*
|
||||
Script: Browser.js
|
||||
The Browser Core. Contains Browser initialization, Window and Document, and the Browser Hash.
|
||||
---
|
||||
|
||||
License:
|
||||
MIT-style license.
|
||||
script: Browser.js
|
||||
|
||||
description: The Browser Core. Contains Browser initialization, Window and Document, and the Browser Hash.
|
||||
|
||||
license: MIT-style license.
|
||||
|
||||
requires:
|
||||
- /Native
|
||||
- /$util
|
||||
|
||||
provides: [Browser, Window, Document, $exec]
|
||||
|
||||
...
|
||||
*/
|
||||
|
||||
var Browser = $merge({
|
||||
@@ -312,7 +326,7 @@ var Browser = $merge({
|
||||
},
|
||||
|
||||
trident: function(){
|
||||
return (!window.ActiveXObject) ? false : ((window.XMLHttpRequest) ? 5 : 4);
|
||||
return (!window.ActiveXObject) ? false : ((window.XMLHttpRequest) ? ((document.querySelectorAll) ? 6 : 5) : 4);
|
||||
},
|
||||
|
||||
webkit: function(){
|
||||
@@ -320,7 +334,7 @@ var Browser = $merge({
|
||||
},
|
||||
|
||||
gecko: function(){
|
||||
return (document.getBoxObjectFor == undefined) ? false : ((document.getElementsByClassName) ? 19 : 18);
|
||||
return (!document.getBoxObjectFor && window.mozInnerScreenX == null) ? false : ((document.getElementsByClassName) ? 19 : 18);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -351,6 +365,8 @@ Browser.Request = function(){
|
||||
return new XMLHttpRequest();
|
||||
}, function(){
|
||||
return new ActiveXObject('MSXML2.XMLHTTP');
|
||||
}, function(){
|
||||
return new ActiveXObject('Microsoft.XMLHTTP');
|
||||
});
|
||||
};
|
||||
|
||||
@@ -427,7 +443,7 @@ var Document = new Native({
|
||||
if (Browser.Engine.trident && Browser.Engine.version <= 4) $try(function(){
|
||||
doc.execCommand("BackgroundImageCache", false, true);
|
||||
});
|
||||
if (Browser.Engine.trident) doc.window.attachEvent('onunload', function() {
|
||||
if (Browser.Engine.trident) doc.window.attachEvent('onunload', function(){
|
||||
doc.window.detachEvent('onunload', arguments.callee);
|
||||
doc.head = doc.html = doc.window = null;
|
||||
});
|
||||
@@ -446,11 +462,21 @@ new Document(document);
|
||||
|
||||
|
||||
/*
|
||||
Script: Array.js
|
||||
Contains Array Prototypes like each, contains, and erase.
|
||||
---
|
||||
|
||||
License:
|
||||
MIT-style license.
|
||||
script: Array.js
|
||||
|
||||
description: Contains Array Prototypes like each, contains, and erase.
|
||||
|
||||
license: MIT-style license.
|
||||
|
||||
requires:
|
||||
- /$util
|
||||
- /Array.each
|
||||
|
||||
provides: [Array]
|
||||
|
||||
...
|
||||
*/
|
||||
|
||||
Array.implement({
|
||||
@@ -470,7 +496,7 @@ Array.implement({
|
||||
return results;
|
||||
},
|
||||
|
||||
clean: function() {
|
||||
clean: function(){
|
||||
return this.filter($defined);
|
||||
},
|
||||
|
||||
@@ -588,11 +614,21 @@ Array.implement({
|
||||
|
||||
|
||||
/*
|
||||
Script: Function.js
|
||||
Contains Function Prototypes like create, bind, pass, and delay.
|
||||
---
|
||||
|
||||
License:
|
||||
MIT-style license.
|
||||
script: Function.js
|
||||
|
||||
description: Contains Function Prototypes like create, bind, pass, and delay.
|
||||
|
||||
license: MIT-style license.
|
||||
|
||||
requires:
|
||||
- /Native
|
||||
- /$util
|
||||
|
||||
provides: [Function]
|
||||
|
||||
...
|
||||
*/
|
||||
|
||||
Function.implement({
|
||||
@@ -651,11 +687,21 @@ Function.implement({
|
||||
|
||||
|
||||
/*
|
||||
Script: Number.js
|
||||
Contains Number Prototypes like limit, round, times, and ceil.
|
||||
---
|
||||
|
||||
License:
|
||||
MIT-style license.
|
||||
script: Number.js
|
||||
|
||||
description: Contains Number Prototypes like limit, round, times, and ceil.
|
||||
|
||||
license: MIT-style license.
|
||||
|
||||
requires:
|
||||
- /Native
|
||||
- /$util
|
||||
|
||||
provides: [Number]
|
||||
|
||||
...
|
||||
*/
|
||||
|
||||
Number.implement({
|
||||
@@ -697,11 +743,20 @@ Number.alias('times', 'each');
|
||||
|
||||
|
||||
/*
|
||||
Script: String.js
|
||||
Contains String Prototypes like camelCase, capitalize, test, and toInt.
|
||||
---
|
||||
|
||||
License:
|
||||
MIT-style license.
|
||||
script: String.js
|
||||
|
||||
description: Contains String Prototypes like camelCase, capitalize, test, and toInt.
|
||||
|
||||
license: MIT-style license.
|
||||
|
||||
requires:
|
||||
- /Native
|
||||
|
||||
provides: [String]
|
||||
|
||||
...
|
||||
*/
|
||||
|
||||
String.implement({
|
||||
@@ -784,11 +839,20 @@ String.implement({
|
||||
|
||||
|
||||
/*
|
||||
Script: Hash.js
|
||||
Contains Hash Prototypes. Provides a means for overcoming the JavaScript practical impossibility of extending native Objects.
|
||||
---
|
||||
|
||||
License:
|
||||
MIT-style license.
|
||||
script: Hash.js
|
||||
|
||||
description: Contains Hash Prototypes. Provides a means for overcoming the JavaScript practical impossibility of extending native Objects.
|
||||
|
||||
license: MIT-style license.
|
||||
|
||||
requires:
|
||||
- /Hash.base
|
||||
|
||||
provides: [Hash]
|
||||
|
||||
...
|
||||
*/
|
||||
|
||||
Hash.implement({
|
||||
@@ -920,11 +984,25 @@ Hash.alias({keyOf: 'indexOf', hasValue: 'contains'});
|
||||
|
||||
|
||||
/*
|
||||
Script: Event.js
|
||||
Contains the Event Native, to make the event object completely crossbrowser.
|
||||
---
|
||||
|
||||
License:
|
||||
MIT-style license.
|
||||
script: Event.js
|
||||
|
||||
description: Contains the Event Class, to make the event object cross-browser.
|
||||
|
||||
license: MIT-style license.
|
||||
|
||||
requires:
|
||||
- /Window
|
||||
- /Document
|
||||
- /Hash
|
||||
- /Array
|
||||
- /Function
|
||||
- /String
|
||||
|
||||
provides: [Event]
|
||||
|
||||
...
|
||||
*/
|
||||
|
||||
var Event = new Native({
|
||||
@@ -1036,11 +1114,26 @@ Event.implement({
|
||||
|
||||
|
||||
/*
|
||||
Script: Class.js
|
||||
Contains the Class Function for easily creating, extending, and implementing reusable Classes.
|
||||
---
|
||||
|
||||
License:
|
||||
MIT-style license.
|
||||
script: Class.js
|
||||
|
||||
description: Contains the Class Function for easily creating, extending, and implementing reusable Classes.
|
||||
|
||||
license: MIT-style license.
|
||||
|
||||
requires:
|
||||
- /$util
|
||||
- /Native
|
||||
- /Array
|
||||
- /String
|
||||
- /Function
|
||||
- /Number
|
||||
- /Hash
|
||||
|
||||
provides: [Class]
|
||||
|
||||
...
|
||||
*/
|
||||
|
||||
function Class(params){
|
||||
@@ -1190,11 +1283,20 @@ Class.Mutators = {
|
||||
|
||||
|
||||
/*
|
||||
Script: Class.Extras.js
|
||||
Contains Utility Classes that can be implemented into your own Classes to ease the execution of many common tasks.
|
||||
---
|
||||
|
||||
License:
|
||||
MIT-style license.
|
||||
script: Class.Extras.js
|
||||
|
||||
description: Contains Utility Classes that can be implemented into your own Classes to ease the execution of many common tasks.
|
||||
|
||||
license: MIT-style license.
|
||||
|
||||
requires:
|
||||
- /Class
|
||||
|
||||
provides: [Chain, Events, Options]
|
||||
|
||||
...
|
||||
*/
|
||||
|
||||
var Chain = new Class({
|
||||
@@ -1270,7 +1372,7 @@ var Events = new Class({
|
||||
});
|
||||
|
||||
Events.removeOn = function(string){
|
||||
return string.replace(/^on([A-Z])/, function(full, first) {
|
||||
return string.replace(/^on([A-Z])/, function(full, first){
|
||||
return first.toLowerCase();
|
||||
});
|
||||
};
|
||||
@@ -1292,12 +1394,26 @@ var Options = new Class({
|
||||
|
||||
|
||||
/*
|
||||
Script: Element.js
|
||||
One of the most important items in MooTools. Contains the dollar function, the dollars function, and an handful of cross-browser,
|
||||
time-saver methods to let you easily work with HTML Elements.
|
||||
---
|
||||
|
||||
License:
|
||||
MIT-style license.
|
||||
script: Element.js
|
||||
|
||||
description: One of the most important items in MooTools. Contains the dollar function, the dollars function, and an handful of cross-browser, time-saver methods to let you easily work with HTML Elements.
|
||||
|
||||
license: MIT-style license.
|
||||
|
||||
requires:
|
||||
- /Window
|
||||
- /Document
|
||||
- /Array
|
||||
- /String
|
||||
- /Function
|
||||
- /Number
|
||||
- /Hash
|
||||
|
||||
provides: [Element, Elements, $, $$, Iframe]
|
||||
|
||||
...
|
||||
*/
|
||||
|
||||
var Element = new Native({
|
||||
@@ -1380,7 +1496,7 @@ var Elements = new Native({
|
||||
if (uniques[el.uid]) continue;
|
||||
uniques[el.uid] = true;
|
||||
}
|
||||
returned.push(el);
|
||||
if (el) returned.push(el);
|
||||
}
|
||||
elements = returned;
|
||||
}
|
||||
@@ -1764,7 +1880,7 @@ Element.implement({
|
||||
return walk(this, 'parentNode', null, match, true, nocash);
|
||||
},
|
||||
|
||||
getSiblings: function(match, nocash) {
|
||||
getSiblings: function(match, nocash){
|
||||
return this.getParent().getChildren(match, nocash).erase(this);
|
||||
},
|
||||
|
||||
@@ -1989,11 +2105,21 @@ if (Browser.Engine.webkit && Browser.Engine.version < 420) Element.Properties.te
|
||||
|
||||
|
||||
/*
|
||||
Script: Element.Event.js
|
||||
Contains Element methods for dealing with events, and custom Events.
|
||||
---
|
||||
|
||||
License:
|
||||
MIT-style license.
|
||||
script: Element.Event.js
|
||||
|
||||
description: Contains Element methods for dealing with events. This file also includes mouseenter and mouseleave custom Element Events.
|
||||
|
||||
license: MIT-style license.
|
||||
|
||||
requires:
|
||||
- /Element
|
||||
- /Event
|
||||
|
||||
provides: [Element.Event]
|
||||
|
||||
...
|
||||
*/
|
||||
|
||||
Element.Properties.events = {set: function(events){
|
||||
@@ -2139,11 +2265,20 @@ Element.Events = new Hash({
|
||||
|
||||
|
||||
/*
|
||||
Script: Element.Style.js
|
||||
Contains methods for interacting with the styles of Elements in a fashionable way.
|
||||
---
|
||||
|
||||
License:
|
||||
MIT-style license.
|
||||
script: Element.Style.js
|
||||
|
||||
description: Contains methods for interacting with the styles of Elements in a fashionable way.
|
||||
|
||||
license: MIT-style license.
|
||||
|
||||
requires:
|
||||
- /Element
|
||||
|
||||
provides: [Element.Style]
|
||||
|
||||
...
|
||||
*/
|
||||
|
||||
Element.Properties.styles = {set: function(styles){
|
||||
@@ -2281,15 +2416,24 @@ Element.ShortStyles = {margin: {}, padding: {}, border: {}, borderWidth: {}, bor
|
||||
|
||||
|
||||
/*
|
||||
Script: Element.Dimensions.js
|
||||
Contains methods to work with size, scroll, or positioning of Elements and the window object.
|
||||
---
|
||||
|
||||
License:
|
||||
MIT-style license.
|
||||
script: Element.Dimensions.js
|
||||
|
||||
Credits:
|
||||
- Element positioning based on the [qooxdoo](http://qooxdoo.org/) code and smart browser fixes, [LGPL License](http://www.gnu.org/licenses/lgpl.html).
|
||||
- Viewport dimensions based on [YUI](http://developer.yahoo.com/yui/) code, [BSD License](http://developer.yahoo.com/yui/license.html).
|
||||
description: Contains methods to work with size, scroll, or positioning of Elements and the window object.
|
||||
|
||||
license: MIT-style license.
|
||||
|
||||
credits:
|
||||
- Element positioning based on the [qooxdoo](http://qooxdoo.org/) code and smart browser fixes, [LGPL License](http://www.gnu.org/licenses/lgpl.html).
|
||||
- Viewport dimensions based on [YUI](http://developer.yahoo.com/yui/) code, [BSD License](http://developer.yahoo.com/yui/license.html).
|
||||
|
||||
requires:
|
||||
- /Element
|
||||
|
||||
provides: [Element.Dimensions]
|
||||
|
||||
...
|
||||
*/
|
||||
|
||||
(function(){
|
||||
@@ -2341,15 +2485,18 @@ Element.implement({
|
||||
return null;
|
||||
},
|
||||
|
||||
getOffsets: function(){
|
||||
getOffsets: function(){
|
||||
if (this.getBoundingClientRect){
|
||||
var bound = this.getBoundingClientRect(),
|
||||
html = document.id(this.getDocument().documentElement),
|
||||
scroll = html.getScroll(),
|
||||
isFixed = (styleString(this, 'position') == 'fixed');
|
||||
html = document.id(this.getDocument().documentElement),
|
||||
htmlScroll = html.getScroll(),
|
||||
elemScrolls = this.getScrolls(),
|
||||
elemScroll = this.getScroll(),
|
||||
isFixed = (styleString(this, 'position') == 'fixed');
|
||||
|
||||
return {
|
||||
x: parseInt(bound.left, 10) + ((isFixed) ? 0 : scroll.x) - html.clientLeft,
|
||||
y: parseInt(bound.top, 10) + ((isFixed) ? 0 : scroll.y) - html.clientTop
|
||||
x: bound.left.toInt() + elemScrolls.x - elemScroll.x + ((isFixed) ? 0 : htmlScroll.x) - html.clientLeft,
|
||||
y: bound.top.toInt() + elemScrolls.y - elemScroll.y + ((isFixed) ? 0 : htmlScroll.y) - html.clientTop
|
||||
};
|
||||
}
|
||||
|
||||
@@ -2386,23 +2533,36 @@ Element.implement({
|
||||
|
||||
getPosition: function(relative){
|
||||
if (isBody(this)) return {x: 0, y: 0};
|
||||
var offset = this.getOffsets(), scroll = this.getScrolls();
|
||||
var position = {x: offset.x - scroll.x, y: offset.y - scroll.y};
|
||||
var offset = this.getOffsets(),
|
||||
scroll = this.getScrolls();
|
||||
var position = {
|
||||
x: offset.x - scroll.x,
|
||||
y: offset.y - scroll.y
|
||||
};
|
||||
var relativePosition = (relative && (relative = document.id(relative))) ? relative.getPosition() : {x: 0, y: 0};
|
||||
return {x: position.x - relativePosition.x, y: position.y - relativePosition.y};
|
||||
},
|
||||
|
||||
getCoordinates: function(element){
|
||||
if (isBody(this)) return this.getWindow().getCoordinates();
|
||||
var position = this.getPosition(element), size = this.getSize();
|
||||
var obj = {left: position.x, top: position.y, width: size.x, height: size.y};
|
||||
var position = this.getPosition(element),
|
||||
size = this.getSize();
|
||||
var obj = {
|
||||
left: position.x,
|
||||
top: position.y,
|
||||
width: size.x,
|
||||
height: size.y
|
||||
};
|
||||
obj.right = obj.left + obj.width;
|
||||
obj.bottom = obj.top + obj.height;
|
||||
return obj;
|
||||
},
|
||||
|
||||
computePosition: function(obj){
|
||||
return {left: obj.x - styleNumber(this, 'margin-left'), top: obj.y - styleNumber(this, 'margin-top')};
|
||||
return {
|
||||
left: obj.x - styleNumber(this, 'margin-left'),
|
||||
top: obj.y - styleNumber(this, 'margin-top')
|
||||
};
|
||||
},
|
||||
|
||||
setPosition: function(obj){
|
||||
@@ -2415,7 +2575,7 @@ Element.implement({
|
||||
Native.implement([Document, Window], {
|
||||
|
||||
getSize: function(){
|
||||
if (Browser.Engine.presto || Browser.Engine.webkit) {
|
||||
if (Browser.Engine.presto || Browser.Engine.webkit){
|
||||
var win = this.getWindow();
|
||||
return {x: win.innerWidth, y: win.innerHeight};
|
||||
}
|
||||
@@ -2516,11 +2676,20 @@ Native.implement([Window, Document, Element], {
|
||||
|
||||
|
||||
/*
|
||||
Script: Selectors.js
|
||||
Adds advanced CSS Querying capabilities for targeting elements. Also includes pseudoselectors support.
|
||||
---
|
||||
|
||||
License:
|
||||
MIT-style license.
|
||||
script: Selectors.js
|
||||
|
||||
description: Adds advanced CSS-style querying capabilities for targeting HTML Elements. Includes pseudo selectors.
|
||||
|
||||
license: MIT-style license.
|
||||
|
||||
requires:
|
||||
- /Element
|
||||
|
||||
provides: [Selectors]
|
||||
|
||||
...
|
||||
*/
|
||||
|
||||
Native.implement([Document, Element], {
|
||||
@@ -2763,7 +2932,7 @@ Selectors.Filters = {
|
||||
},
|
||||
|
||||
byClass: function(self, klass){
|
||||
return (self.className && self.className.contains(klass, ' '));
|
||||
return (self.className && self.className.contains && self.className.contains(klass, ' '));
|
||||
},
|
||||
|
||||
byPseudo: function(self, parser, argument, local){
|
||||
@@ -2885,11 +3054,20 @@ Selectors.Pseudo = new Hash({
|
||||
|
||||
|
||||
/*
|
||||
Script: Domready.js
|
||||
Contains the domready custom event.
|
||||
---
|
||||
|
||||
License:
|
||||
MIT-style license.
|
||||
script: DomReady.js
|
||||
|
||||
description: Contains the custom event domready.
|
||||
|
||||
license: MIT-style license.
|
||||
|
||||
requires:
|
||||
- /Element.Event
|
||||
|
||||
provides: [DomReady]
|
||||
|
||||
...
|
||||
*/
|
||||
|
||||
Element.Events.domready = {
|
||||
@@ -2908,6 +3086,8 @@ Element.Events.domready = {
|
||||
window.fireEvent('domready');
|
||||
document.fireEvent('domready');
|
||||
};
|
||||
|
||||
window.addEvent('load', domready);
|
||||
|
||||
if (Browser.Engine.trident){
|
||||
var temp = document.createElement('div');
|
||||
@@ -2922,7 +3102,6 @@ Element.Events.domready = {
|
||||
(['loaded', 'complete'].contains(document.readyState)) ? domready() : arguments.callee.delay(50);
|
||||
})();
|
||||
} else {
|
||||
window.addEvent('load', domready);
|
||||
document.addEvent('DOMContentLoaded', domready);
|
||||
}
|
||||
|
||||
@@ -2930,18 +3109,33 @@ Element.Events.domready = {
|
||||
|
||||
|
||||
/*
|
||||
Script: JSON.js
|
||||
JSON encoder and decoder.
|
||||
---
|
||||
|
||||
License:
|
||||
MIT-style license.
|
||||
script: JSON.js
|
||||
|
||||
See Also:
|
||||
<http://www.json.org/>
|
||||
description: JSON encoder and decoder.
|
||||
|
||||
license: MIT-style license.
|
||||
|
||||
See Also: <http://www.json.org/>
|
||||
|
||||
requires:
|
||||
- /Array
|
||||
- /String
|
||||
- /Number
|
||||
- /Function
|
||||
- /Hash
|
||||
|
||||
provides: [JSON]
|
||||
|
||||
...
|
||||
*/
|
||||
|
||||
var JSON = new Hash({
|
||||
|
||||
var JSON = new Hash(this.JSON && {
|
||||
stringify: JSON.stringify,
|
||||
parse: JSON.parse
|
||||
}).extend({
|
||||
|
||||
$specialChars: {'\b': '\\b', '\t': '\\t', '\n': '\\n', '\f': '\\f', '\r': '\\r', '"' : '\\"', '\\': '\\\\'},
|
||||
|
||||
$replaceChars: function(chr){
|
||||
@@ -2985,14 +3179,23 @@ Native.implement([Hash, Array, String, Number], {
|
||||
|
||||
|
||||
/*
|
||||
Script: Cookie.js
|
||||
Class for creating, loading, and saving browser Cookies.
|
||||
---
|
||||
|
||||
License:
|
||||
MIT-style license.
|
||||
script: Cookie.js
|
||||
|
||||
Credits:
|
||||
Based on the functions by Peter-Paul Koch (http://quirksmode.org).
|
||||
description: Class for creating, reading, and deleting browser Cookies.
|
||||
|
||||
license: MIT-style license.
|
||||
|
||||
credits:
|
||||
- Based on the functions by Peter-Paul Koch (http://quirksmode.org).
|
||||
|
||||
requires:
|
||||
- /Options
|
||||
|
||||
provides: [Cookie]
|
||||
|
||||
...
|
||||
*/
|
||||
|
||||
var Cookie = new Class({
|
||||
@@ -3052,14 +3255,24 @@ Cookie.dispose = function(key, options){
|
||||
|
||||
|
||||
/*
|
||||
Script: Swiff.js
|
||||
Wrapper for embedding SWF movies. Supports (and fixes) External Interface Communication.
|
||||
---
|
||||
|
||||
License:
|
||||
MIT-style license.
|
||||
script: Swiff.js
|
||||
|
||||
Credits:
|
||||
Flash detection & Internet Explorer + Flash Player 9 fix inspired by SWFObject.
|
||||
description: Wrapper for embedding SWF movies. Supports External Interface Communication.
|
||||
|
||||
license: MIT-style license.
|
||||
|
||||
credits:
|
||||
- Flash detection & Internet Explorer + Flash Player 9 fix inspired by SWFObject.
|
||||
|
||||
requires:
|
||||
- /Options
|
||||
- /$util
|
||||
|
||||
provides: [Swiff]
|
||||
|
||||
...
|
||||
*/
|
||||
|
||||
var Swiff = new Class({
|
||||
@@ -3154,11 +3367,22 @@ Swiff.remote = function(obj, fn){
|
||||
|
||||
|
||||
/*
|
||||
Script: Fx.js
|
||||
Contains the basic animation logic to be extended by all other Fx Classes.
|
||||
---
|
||||
|
||||
License:
|
||||
MIT-style license.
|
||||
script: Fx.js
|
||||
|
||||
description: Contains the basic animation logic to be extended by all other Fx Classes.
|
||||
|
||||
license: MIT-style license.
|
||||
|
||||
requires:
|
||||
- /Chain
|
||||
- /Events
|
||||
- /Options
|
||||
|
||||
provides: [Fx]
|
||||
|
||||
...
|
||||
*/
|
||||
|
||||
var Fx = new Class({
|
||||
@@ -3287,11 +3511,21 @@ Fx.Durations = {'short': 250, 'normal': 500, 'long': 1000};
|
||||
|
||||
|
||||
/*
|
||||
Script: Fx.CSS.js
|
||||
Contains the CSS animation logic. Used by Fx.Tween, Fx.Morph, Fx.Elements.
|
||||
---
|
||||
|
||||
License:
|
||||
MIT-style license.
|
||||
script: Fx.CSS.js
|
||||
|
||||
description: Contains the CSS animation logic. Used by Fx.Tween, Fx.Morph, Fx.Elements.
|
||||
|
||||
license: MIT-style license.
|
||||
|
||||
requires:
|
||||
- /Fx
|
||||
- /Element.Style
|
||||
|
||||
provides: [Fx.CSS]
|
||||
|
||||
...
|
||||
*/
|
||||
|
||||
Fx.CSS = new Class({
|
||||
@@ -3421,11 +3655,20 @@ Fx.CSS.Parsers = new Hash({
|
||||
|
||||
|
||||
/*
|
||||
Script: Fx.Tween.js
|
||||
Formerly Fx.Style, effect to transition any CSS property for an element.
|
||||
---
|
||||
|
||||
License:
|
||||
MIT-style license.
|
||||
script: Fx.Tween.js
|
||||
|
||||
description: Formerly Fx.Style, effect to transition any CSS property for an element.
|
||||
|
||||
license: MIT-style license.
|
||||
|
||||
requires:
|
||||
- /Fx.CSS
|
||||
|
||||
provides: [Fx.Tween, Element.fade, Element.highlight]
|
||||
|
||||
...
|
||||
*/
|
||||
|
||||
Fx.Tween = new Class({
|
||||
@@ -3518,11 +3761,20 @@ Element.implement({
|
||||
|
||||
|
||||
/*
|
||||
Script: Fx.Morph.js
|
||||
Formerly Fx.Styles, effect to transition any number of CSS properties for an element using an object of rules, or CSS based selector rules.
|
||||
---
|
||||
|
||||
License:
|
||||
MIT-style license.
|
||||
script: Fx.Morph.js
|
||||
|
||||
description: Formerly Fx.Styles, effect to transition any number of CSS properties for an element using an object of rules, or CSS based selector rules.
|
||||
|
||||
license: MIT-style license.
|
||||
|
||||
requires:
|
||||
- /Fx.CSS
|
||||
|
||||
provides: [Fx.Morph]
|
||||
|
||||
...
|
||||
*/
|
||||
|
||||
Fx.Morph = new Class({
|
||||
@@ -3589,14 +3841,23 @@ Element.implement({
|
||||
|
||||
|
||||
/*
|
||||
Script: Fx.Transitions.js
|
||||
Contains a set of advanced transitions to be used with any of the Fx Classes.
|
||||
---
|
||||
|
||||
License:
|
||||
MIT-style license.
|
||||
script: Fx.Transitions.js
|
||||
|
||||
Credits:
|
||||
Easing Equations by Robert Penner, <http://www.robertpenner.com/easing/>, modified and optimized to be used with MooTools.
|
||||
description: Contains a set of advanced transitions to be used with any of the Fx Classes.
|
||||
|
||||
license: MIT-style license.
|
||||
|
||||
credits:
|
||||
- Easing Equations by Robert Penner, <http://www.robertpenner.com/easing/>, modified and optimized to be used with MooTools.
|
||||
|
||||
requires:
|
||||
- /Fx
|
||||
|
||||
provides: [Fx.Transitions]
|
||||
|
||||
...
|
||||
*/
|
||||
|
||||
Fx.implement({
|
||||
@@ -3687,11 +3948,24 @@ Fx.Transitions.extend({
|
||||
|
||||
|
||||
/*
|
||||
Script: Request.js
|
||||
Powerful all purpose Request Class. Uses XMLHTTPRequest.
|
||||
---
|
||||
|
||||
License:
|
||||
MIT-style license.
|
||||
script: Request.js
|
||||
|
||||
description: Powerful all purpose Request Class. Uses XMLHTTPRequest.
|
||||
|
||||
license: MIT-style license.
|
||||
|
||||
requires:
|
||||
- /Element
|
||||
- /Chain
|
||||
- /Events
|
||||
- /Options
|
||||
- /Browser
|
||||
|
||||
provides: [Request]
|
||||
|
||||
...
|
||||
*/
|
||||
|
||||
var Request = new Class({
|
||||
@@ -3802,7 +4076,7 @@ var Request = new Class({
|
||||
|
||||
var old = this.options;
|
||||
options = $extend({data: old.data, url: old.url, method: old.method}, options);
|
||||
var data = options.data, url = options.url, method = options.method.toLowerCase();
|
||||
var data = options.data, url = String(options.url), method = options.method.toLowerCase();
|
||||
|
||||
switch ($type(data)){
|
||||
case 'element': data = document.id(data).toQueryString(); break;
|
||||
@@ -3914,11 +4188,21 @@ Element.implement({
|
||||
|
||||
|
||||
/*
|
||||
Script: Request.HTML.js
|
||||
Extends the basic Request Class with additional methods for interacting with HTML responses.
|
||||
---
|
||||
|
||||
License:
|
||||
MIT-style license.
|
||||
script: Request.HTML.js
|
||||
|
||||
description: Extends the basic Request Class with additional methods for interacting with HTML responses.
|
||||
|
||||
license: MIT-style license.
|
||||
|
||||
requires:
|
||||
- /Request
|
||||
- /Element
|
||||
|
||||
provides: [Request.HTML]
|
||||
|
||||
...
|
||||
*/
|
||||
|
||||
Request.HTML = new Class({
|
||||
@@ -4008,11 +4292,20 @@ Element.implement({
|
||||
|
||||
|
||||
/*
|
||||
Script: Request.JSON.js
|
||||
Extends the basic Request Class with additional methods for sending and receiving JSON data.
|
||||
---
|
||||
|
||||
License:
|
||||
MIT-style license.
|
||||
script: Request.JSON.js
|
||||
|
||||
description: Extends the basic Request Class with additional methods for sending and receiving JSON data.
|
||||
|
||||
license: MIT-style license.
|
||||
|
||||
requires:
|
||||
- /Request JSON
|
||||
|
||||
provides: [Request.HTML]
|
||||
|
||||
...
|
||||
*/
|
||||
|
||||
Request.JSON = new Class({
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 1.4 KiB |
@@ -2,6 +2,9 @@ body {
|
||||
font-family: arial, helvetica, verdana, tahoma, sans-serif;
|
||||
font-size: small;
|
||||
background: #153F65;
|
||||
}
|
||||
|
||||
#first-container {
|
||||
width: 950px;
|
||||
margin: 0 auto;
|
||||
padding: 0;
|
||||
@@ -297,6 +300,7 @@ body {
|
||||
|
||||
#setcontent {
|
||||
margin: 0px auto;
|
||||
margin-top: 60px;
|
||||
width: 90%;
|
||||
}
|
||||
|
||||
@@ -333,4 +337,4 @@ body {
|
||||
.info {
|
||||
float: left;
|
||||
font-style: italic;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,4 +78,27 @@ input:hover {
|
||||
|
||||
#id_password {
|
||||
width: 120px;
|
||||
}
|
||||
|
||||
/* Dialog box */
|
||||
#dlg-buttons {
|
||||
clear: both;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
padding-top: 20px;
|
||||
}
|
||||
|
||||
#dlg-iconbox {
|
||||
float: left;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
#dlg-textbox {
|
||||
float: left;
|
||||
margin-left: 20px;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
#dlg-buttons input {
|
||||
width: 90px;
|
||||
}
|
||||
@@ -16,6 +16,7 @@
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="first-container">
|
||||
<div id="header" class="rounded">
|
||||
<div id="logo"></div>
|
||||
<div id="title">
|
||||
@@ -101,5 +102,6 @@
|
||||
<div id="footer">
|
||||
© Antoine Nguyen 2009
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -1,16 +1,36 @@
|
||||
{% extends "layout_simple.html" %}
|
||||
{% block html_head %}
|
||||
<script src="/static/js/form.js" type="text/javascript"></script>
|
||||
<script type="text/javascript">
|
||||
window.addEvent('domready', function(){
|
||||
$("ok").addEvent("click", function(event) {
|
||||
$("result").value = "ok";
|
||||
parent.SqueezeBox.close();
|
||||
});
|
||||
$("cancel").addEvent("click", function(event) {
|
||||
parent.SqueezeBox.close();
|
||||
});
|
||||
});
|
||||
|
||||
</script>
|
||||
{% endblock %}
|
||||
{% block content %}
|
||||
{% load i18n %}
|
||||
<b>{{ msg }}</b><br/>
|
||||
|
||||
<p>
|
||||
<input type="checkbox" id="keepdir" value="" />{% trans "Do not delete mailbox directory" %}
|
||||
</p>
|
||||
<div id="dlg-iconbox">
|
||||
<img src="/static/pics/dialog-warning.png" alt="Warning" />
|
||||
</div>
|
||||
<div id="dlg-textbox">
|
||||
<b>{{ msg }}</b><br/>
|
||||
<p>
|
||||
<input type="checkbox" name="keepdir" value="" />{% trans "Do not delete mailbox directory" %}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<input type="button" id="ok" value="Ok" />
|
||||
<input type="button" id="cancel" value="Cancel" />
|
||||
<div id="dlg-buttons">
|
||||
<input type="button" name="ok" id="ok" value="Ok" />
|
||||
<input type="button" id="cancel" value="Cancel" />
|
||||
</div>
|
||||
<input type="hidden" name="result" id="result" value="cancel" />
|
||||
{% endblock %}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user