diff --git a/.tx/config b/.tx/config index a782bec99..d71bb5355 100644 --- a/.tx/config +++ b/.tx/config @@ -1,5 +1,5 @@ [main] -host = https://www.transifex.net +host = https://www.transifex.com [sogo.ui-mailerui] source_file = UI/MailerUI/English.lproj/Localizable.strings diff --git a/ChangeLog b/ChangeLog index c5005f5d7..b8a81a05d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,212 @@ +commit d5f76ac832912402d714dd13291c43aa9f84940f +Author: Francis Lachapelle +Date: Fri Jul 19 13:39:18 2013 -0400 + + Improve CSS print media + +M UI/WebServerResources/generic.css + +commit 12b7fea82543c105a39854eb4bc3f9e68cc080e7 +Author: Francis Lachapelle +Date: Fri Jul 19 13:37:13 2013 -0400 + + Documentation - bump version to 2.0.7 + +M Documentation/SOGo Installation Guide.odt +M Documentation/SOGo Mobile Devices Configuration.odt +M Documentation/SOGo Mozilla Thunderbird Configuration.odt +M Documentation/SOGo Native Microsoft Outlook Configuration.odt + +commit 1c82af8842ac78b70d8e40a4d78e866522adf139 +Author: Francis Lachapelle +Date: Fri Jul 19 11:29:10 2013 -0400 + + Updated pt_BR, cs, nl, de, pl and ru translations + +M .tx/config +M NEWS +M SoObjects/Appointments/German.lproj/Localizable.strings +M UI/MainUI/Czech.lproj/Localizable.strings +M UI/MainUI/German.lproj/Localizable.strings +M UI/PreferencesUI/German.lproj/Localizable.strings +M UI/PreferencesUI/Russian.lproj/Localizable.strings +M UI/Scheduler/BrazilianPortuguese.lproj/Localizable.strings +M UI/Scheduler/Czech.lproj/Localizable.strings +M UI/Scheduler/Dutch.lproj/Localizable.strings +M UI/Scheduler/German.lproj/Localizable.strings +M UI/Scheduler/Polish.lproj/Localizable.strings +M UI/Scheduler/Russian.lproj/Localizable.strings + +commit 6cef5245e10515b1199102cf2c19d48364862027 +Author: Francis Lachapelle +Date: Fri Jul 19 11:27:17 2013 -0400 + + Bump version to 2.0.7 + +M NEWS +M Version + +commit 0069a4200b1d087c9d931289cd57746aaa4e23bd +Author: Francis Lachapelle +Date: Fri Jul 19 10:43:21 2013 -0400 + + Handle possible jQuery error with DnD of contacts + +M UI/WebServerResources/ContactsUI.js + +commit e24c20c48af0e5eadcb4f8a8683bae15e22ae100 +Author: Ludovic Marcotte +Date: Fri Jul 19 10:11:08 2013 -0400 + + Reverted patch + +M SOPE/GDLContentStore/EOQualifier+GCS.m +M SOPE/GDLContentStore/GCSFolder.m + +commit 256b679798404db77fa85b53df6bcf815c8e4007 +Author: Ludovic Marcotte +Date: Thu Jul 18 11:46:49 2013 -0400 + + Bug fix for #2366 + +M NEWS +M SoObjects/Mailer/SOGoMailBaseObject.m + +commit b85ed0db1c1bf37d0f1ec870c8c0a88566954ec6 +Author: Francis Lachapelle +Date: Thu Jul 18 11:32:29 2013 -0400 + + Fix blur of active element on click on a draggable + + This bug has yet to be officially part of jQuery UI, therefore this + commit updates jquery-ui to version 1.10.3 patched with commit fcd1caf: + + https://github.com/jquery/jquery-ui/commit/fcd1cafac8afe3a947676ec018e844eeada5b9de + +M NEWS +M UI/WebServerResources/jquery-ui.js + +commit 048bae2fc510f0cdd39b07d23bb23cf492001921 +Author: Ludovic Marcotte +Date: Thu Jul 18 10:52:37 2013 -0400 + + Applied patch from bug #2235 + +M SOPE/GDLContentStore/EOQualifier+GCS.m +M SOPE/GDLContentStore/GCSFolder.m + +commit 19e542396bc32debab6f53b229166c57d05e4599 +Author: Ludovic Marcotte +Date: Thu Jul 18 10:25:39 2013 -0400 + + Applied patch from bug #2360 + +M UI/MailPartViewers/GNUmakefile +M UI/MailPartViewers/GNUmakefile.preamble +M UI/MailerUI/GNUmakefile + +commit 249a1fcf14f80e1f7a612ae9faa710488e716140 +Author: Francis Lachapelle +Date: Wed Jul 17 14:57:07 2013 -0400 + + Bubble box of event should not overlap event cell + +M NEWS +M UI/WebServerResources/SchedulerUI.js + +commit 7dad5ad84ed5a59409ce7f0083e750ac079beb16 +Author: Ludovic Marcotte +Date: Tue Jul 16 15:20:26 2013 -0400 + + Updated for v2.0.7 + +M NEWS + +commit 16105d37b83a2632e5389407b783ef062939f9c6 +Author: Ludovic Marcotte +Date: Tue Jul 16 15:18:04 2013 -0400 + + Properly handle RFC2231 everywhere + +M SoObjects/Mailer/GNUmakefile +A SoObjects/Mailer/NSDictionary+Mail.h +A SoObjects/Mailer/NSDictionary+Mail.m +M SoObjects/Mailer/SOGoMailBodyPart.m +M SoObjects/Mailer/SOGoMailObject+Draft.m +M UI/MailPartViewers/UIxMailPartViewer.m + +commit e08ebd2390ad81bcf7d63c200de85eddbf80bcd6 +Author: Ludovic Marcotte +Date: Tue Jul 16 11:31:08 2013 -0400 + + Fix for bugs #2368 and #2369 + +M SoObjects/Appointments/SOGoAptMailNotification.m +M UI/MailPartViewers/UIxMailPartICalViewer.m +M UI/MailerUI/UIxMailListActions.m +M UI/Templates/Appointments/SOGoAptMailInvitation.wox +M UI/WebServerResources/SchedulerUI.js + +commit 03553980fd2abb2da397c0810fd8f6d70ba26d65 +Author: Francis Lachapelle +Date: Thu Jul 11 13:55:03 2013 -0400 + + Update NEWS file and add missing image + +M NEWS +A UI/WebServerResources/collapse.png + +commit 33fd60efb335b180938492eddb75ab59591d4153 +Author: Francis Lachapelle +Date: Thu Jul 11 13:50:44 2013 -0400 + + Calendar: print gridlines to 15-minute intervals + +M UI/Templates/SchedulerUI/UIxCalDayTable.wox +M UI/WebServerResources/SchedulerUI.css +M UI/WebServerResources/SchedulerUIDnD.js + +commit b8e2255a071dcb2fd2172a73e95d38600d41c1bf +Author: Francis Lachapelle +Date: Thu Jul 11 13:46:38 2013 -0400 + + Set the events/tasks list collapsable + +M UI/Scheduler/UIxCalMainView.m +M UI/Scheduler/UIxCalView.m +M UI/Scheduler/product.plist +M UI/Templates/SchedulerUI/UIxCalDayView.wox +M UI/Templates/SchedulerUI/UIxCalMainView.wox +M UI/Templates/SchedulerUI/UIxCalMonthView.wox +M UI/Templates/SchedulerUI/UIxCalWeekView.wox +M UI/WebServerResources/SOGoTabsController.js +M UI/WebServerResources/SchedulerUI.css +M UI/WebServerResources/SchedulerUI.js + +commit e687dbf155963e1931fd2f7ac58bd2f4cf862dca +Author: Ludovic Marcotte +Date: Thu Jul 4 13:11:02 2013 -0400 + + If the organizer's name is non-existent, use the email address + +M UI/Scheduler/UIxComponentEditor.m + +commit f42d52743df169d6bfdc58428e920dd6208a1879 +Author: Jean Raby +Date: Thu Jun 27 11:35:17 2013 -0400 + + bump version to 2.0.6b + +M Version + +commit 70cd64a626470e0c07ac0f8cb7119cab6e763bfa +Author: Jean Raby +Date: Thu Jun 27 11:34:06 2013 -0400 + + Update ChangeLog + +M ChangeLog + commit 4359b05da8ba291b9bbc00e330d65575a4dbb253 Author: Jean Raby Date: Thu Jun 27 11:33:44 2013 -0400 diff --git a/Documentation/SOGo Installation Guide.odt b/Documentation/SOGo Installation Guide.odt index 69c779982..6419ee008 100644 Binary files a/Documentation/SOGo Installation Guide.odt and b/Documentation/SOGo Installation Guide.odt differ diff --git a/Documentation/SOGo Mobile Devices Configuration.odt b/Documentation/SOGo Mobile Devices Configuration.odt index 652d8dc6c..72f703344 100644 Binary files a/Documentation/SOGo Mobile Devices Configuration.odt and b/Documentation/SOGo Mobile Devices Configuration.odt differ diff --git a/Documentation/SOGo Mozilla Thunderbird Configuration.odt b/Documentation/SOGo Mozilla Thunderbird Configuration.odt index 47af9f2a3..9277ed018 100644 Binary files a/Documentation/SOGo Mozilla Thunderbird Configuration.odt and b/Documentation/SOGo Mozilla Thunderbird Configuration.odt differ diff --git a/Documentation/SOGo Native Microsoft Outlook Configuration.odt b/Documentation/SOGo Native Microsoft Outlook Configuration.odt index 78b6c6875..9bb9d126a 100644 Binary files a/Documentation/SOGo Native Microsoft Outlook Configuration.odt and b/Documentation/SOGo Native Microsoft Outlook Configuration.odt differ diff --git a/NEWS b/NEWS index cc95fd884..3866b8770 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,20 @@ +2.0.7 (2013-07-19) +------------------ + +New features + - print gridlines of calendar in 15-minute intervals + - allow the events/tasks lists to be collapsable + +Enhancements + - bubble box of events no longer overlaps the current event + - now pass the x-originating-ip using the IMAP ID extension (#2366) + - updated BrazilianPortuguese, Czech, Dutch, German, Polish and Russian translations + +Bug fixes + - properly handle RFC2231 everywhere + - fixed minor XSS issues + - fixed jquery-ui not bluring the active element when clicking on a draggable + 2.0.6b (2013-06-27) ------------------ diff --git a/SoObjects/Appointments/German.lproj/Localizable.strings b/SoObjects/Appointments/German.lproj/Localizable.strings index 2acd882bb..4cd49d8c5 100644 --- a/SoObjects/Appointments/German.lproj/Localizable.strings +++ b/SoObjects/Appointments/German.lproj/Localizable.strings @@ -27,13 +27,13 @@ vtodo_class2 = "(Vertrauliche Aufgabe)"; /* Invitation */ "Event Invitation: \"%{Summary}\"" = "Termineinladung: \"%{Summary}\""; "(sent by %{SentBy}) " = "(gesendet von %{SentBy}) "; -"%{Organizer} %{SentByText}has invited you to %{Summary}.\n\nStart: %{StartDate}\nEnd: %{EndDate}\nDescription: %{Description}" = "%{Organizer} %{SentByText} Hat Sie eingeladen zu %{Summary}.\n\nBeginn: %{StartDate}\nEnde: %{EndDate}\nBeschreibung: %{Description}"; +"%{Organizer} %{SentByText}has invited you to %{Summary}.\n\nStart: %{StartDate}\nEnd: %{EndDate}\nDescription: %{Description}" = "%{Organizer} %{SentByText} Hat Sie eingeladen zu \"%{Summary}\".\n\nBeginn: %{StartDate}\nEnde: %{EndDate}\nBeschreibung: %{Description}"; "%{Organizer} %{SentByText}has invited you to %{Summary}.\n\nStart: %{StartDate} at %{StartTime}\nEnd: %{EndDate} at %{EndTime}\nDescription: %{Description}" = "%{Organizer} %{SentByText} hat Sie eingeladen zu \"%{Summary}\".\n\nBeginn: %{StartDate} um %{StartTime}\nEnde: %{EndDate} um %{EndTime}\nBeschreibung: %{Description}"; /* Deletion */ "Event Cancelled: \"%{Summary}\"" = "Termin abgesagt: \"%{Summary}\""; "%{Organizer} %{SentByText}has cancelled this event: %{Summary}.\n\nStart: %{StartDate}\nEnd: %{EndDate}\nDescription: %{Description}" -= "%{Organizer} %{SentByText} hat den folgenden Termin abgesagt: %{Summary}.\n\nBeginn: %{StartDate}\nEnde: %{EndDate}\nBeschreibung: %{Description}"; += "%{Organizer} %{SentByText} hat den folgenden Termin abgesagt: \"%{Summary}\".\n\nBeginn: %{StartDate}\nEnde: %{EndDate}\nBeschreibung: %{Description}"; "%{Organizer} %{SentByText}has cancelled this event: %{Summary}.\n\nStart: %{StartDate} at %{StartTime}\nEnd: %{EndDate} at %{EndTime}\nDescription: %{Description}" = "%{Organizer} %{SentByText} hat diesen Termin abgesagt: \"%{Summary}\".\n\nBeginn: %{StartDate} um %{StartTime}\nEnde: %{EndDate} um %{EndTime}\nBeschreibung: %{Description}"; @@ -45,7 +45,7 @@ vtodo_class2 = "(Vertrauliche Aufgabe)"; "The following parameters have changed in the \"%{Summary}\" meeting:" = "Folgendes wurde am Termin \"%{Summary}\" geändert:"; "Please accept or decline those changes." -= "Bitte akzeptieren Sie diese Änderung oder lehnen Sie ab."; += "Bitte akzeptieren Sie diese Änderung oder lehnen Sie diese ab."; /* Reply */ "Accepted invitation: \"%{Summary}\"" = "Einladung zugestimmt: \"%{Summary}\""; diff --git a/SoObjects/Appointments/SOGoAptMailNotification.m b/SoObjects/Appointments/SOGoAptMailNotification.m index 026137cc0..0d0db981e 100644 --- a/SoObjects/Appointments/SOGoAptMailNotification.m +++ b/SoObjects/Appointments/SOGoAptMailNotification.m @@ -140,9 +140,14 @@ return newEndDate; } +- (NSString *) location +{ + return [[apt location] stringByEscapingHTMLString]; +} + - (NSString *) summary { - return [apt summary]; + return [[apt summary] stringByEscapingHTMLString]; } - (void) setOrganizerName: (NSString *) theString diff --git a/SoObjects/Mailer/GNUmakefile b/SoObjects/Mailer/GNUmakefile index db5edc0b0..7934e878a 100644 --- a/SoObjects/Mailer/GNUmakefile +++ b/SoObjects/Mailer/GNUmakefile @@ -35,6 +35,7 @@ Mailer_OBJC_FILES += \ \ EOQualifier+MailDAV.m \ NSData+Mail.m \ + NSDictionary+Mail.m \ NSString+Mail.m \ SOGoUser+Mailer.m diff --git a/SoObjects/Mailer/NSDictionary+Mail.h b/SoObjects/Mailer/NSDictionary+Mail.h new file mode 100644 index 000000000..fceea68da --- /dev/null +++ b/SoObjects/Mailer/NSDictionary+Mail.h @@ -0,0 +1,34 @@ +/* NSDictionary+Mail.h - this file is part of SOGo + * + * Copyright (C) 2013 Inverse inc. + * + * This file is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This file is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef NSDICTIONARY_MAIL_H +#define NSDICTIONARY_MAIL_H + +#import + +@class NSString; + +@interface NSDictionary (SOGoExtension) + +- (NSString *) filename; + +@end + +#endif /* NSDICTIONARY_MAIL_H */ diff --git a/SoObjects/Mailer/NSDictionary+Mail.m b/SoObjects/Mailer/NSDictionary+Mail.m new file mode 100644 index 000000000..74311f292 --- /dev/null +++ b/SoObjects/Mailer/NSDictionary+Mail.m @@ -0,0 +1,73 @@ +/* NSDictionary+Mail.m - this file is part of SOGo + * + * Copyright (C) 2013 Inverse inc. + * + * This file is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This file is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#import +#import + +#import "NSDictionary+Mail.h" + +@implementation NSDictionary (SOGoExtension) + +- (NSString *) filename +{ + NSDictionary *parameters; + NSString *filename; + + filename = [[self objectForKey: @"parameterList"] + objectForKey: @"name"]; + + if (!filename) + { + parameters = [[self objectForKey: @"disposition"] + objectForKey: @"parameterList"]; + filename = [parameters objectForKey: @"filename"]; + + + // We might have something like filename*=UTF-8''foobar + // See RFC2231 for details. If it was folded before, it will + // be unfolded when we get here. + if (!filename) + { + filename = [parameters objectForKey: @"filename*"]; + + if (filename) + { + NSRange r; + + filename = [filename stringByUnescapingURL]; + + // We skip up to the language + r = [filename rangeOfString: @"'"]; + + if (r.length) + { + r = [filename rangeOfString: @"'" options: 0 range: NSMakeRange(r.location+1, [filename length]-r.location-1)]; + + if (r.length) + filename = [filename substringFromIndex: r.location+1]; + } + } + } + } + + return filename; +} + +@end diff --git a/SoObjects/Mailer/SOGoMailBaseObject.m b/SoObjects/Mailer/SOGoMailBaseObject.m index 7053b19f7..62f3da511 100644 --- a/SoObjects/Mailer/SOGoMailBaseObject.m +++ b/SoObjects/Mailer/SOGoMailBaseObject.m @@ -151,6 +151,22 @@ static BOOL debugOn = YES; newConnection = (NGImap4Connection *) [NSNull null]; [self errorWithFormat:@"Could not connect IMAP4"]; } + else + { + // If the server has the ID capability (RFC 2971), we set the x-originating-ip + // accordingly for the IMAP connection. + NSString *remoteHost; + + remoteHost = [[context request] headerForKey: @"x-webobjects-remote-host"]; + + if (remoteHost) + { + if ([[[[newConnection client] capability] objectForKey: @"capability"] containsObject: @"id"]) + { + [[newConnection client] processCommand: [NSString stringWithFormat: @"ID (\"x-originating-ip\" \"%@\")", remoteHost]]; + } + } + } return newConnection; } diff --git a/SoObjects/Mailer/SOGoMailBodyPart.m b/SoObjects/Mailer/SOGoMailBodyPart.m index 975463d0e..2fb075f4c 100644 --- a/SoObjects/Mailer/SOGoMailBodyPart.m +++ b/SoObjects/Mailer/SOGoMailBodyPart.m @@ -38,6 +38,7 @@ #import +#import "NSDictionary+Mail.h" #import "SOGoMailObject.h" #import "SOGoMailManager.h" @@ -201,21 +202,9 @@ static BOOL debugOn = NO; - (NSString *) filename { - NSString *filename; - NSDictionary *parameters; - [self partInfo]; - - filename = [[partInfo objectForKey: @"parameterList"] - objectForKey: @"name"]; - if (!filename) - { - parameters = [[partInfo objectForKey: @"disposition"] - objectForKey: @"parameterList"]; - filename = [parameters objectForKey: @"filename"]; - } - - return filename; + + return [partInfo filename]; } /* We overwrite the super's class method in order to make sure diff --git a/SoObjects/Mailer/SOGoMailObject+Draft.m b/SoObjects/Mailer/SOGoMailObject+Draft.m index ff74c8e01..00f34be50 100644 --- a/SoObjects/Mailer/SOGoMailObject+Draft.m +++ b/SoObjects/Mailer/SOGoMailObject+Draft.m @@ -34,6 +34,7 @@ #import #import +#import "NSDictionary+Mail.h" #import "NSString+Mail.h" #import "SOGoMailForward.h" #import "SOGoMailObject+Draft.h" @@ -250,39 +251,10 @@ intoArray: (NSMutableArray *) keys withPath: (NSString *) path { - NSDictionary *disposition, *currentFile; NSString *filename, *mimeType; + NSDictionary *currentFile; - disposition = [part objectForKey: @"disposition"]; - filename = [[disposition objectForKey: @"parameterList"] - objectForKey: @"filename"]; - - // We might have something like filename*=UTF-8''foobar - // See RFC2231 for details. If it was folded before, it will - // be unfolded when we get here. - if (!filename) - { - filename = [[disposition objectForKey: @"parameterList"] - objectForKey: @"filename*"]; - - if (filename) - { - NSRange r; - - filename = [filename stringByUnescapingURL]; - - // We skip up to the language - r = [filename rangeOfString: @"'"]; - - if (r.length) - { - r = [filename rangeOfString: @"'" options: 0 range: NSMakeRange(r.location+1, [filename length]-r.location-1)]; - - if (r.length) - filename = [filename substringFromIndex: r.location+1]; - } - } - } + filename = [part filename]; mimeType = [NSString stringWithFormat: @"%@/%@", [part objectForKey: @"type"], diff --git a/UI/MailPartViewers/GNUmakefile b/UI/MailPartViewers/GNUmakefile index 745914636..509121b74 100644 --- a/UI/MailPartViewers/GNUmakefile +++ b/UI/MailPartViewers/GNUmakefile @@ -26,6 +26,24 @@ MailPartViewers_OBJC_FILES += \ UIxMailPartICalViewer.m \ \ UIxMailPartICalActions.m \ + ../../SoObjects/Mailer/SOGoMailBodyPart.m \ + ../../SoObjects/Mailer/SOGoHTMLMailBodyPart.m \ + ../../SoObjects/Mailer/SOGoCalendarMailBodyPart.m \ + ../../SoObjects/Mailer/SOGoMailAccounts.m \ + ../../SoObjects/Mailer/SOGoMailBaseObject.m \ + ../../SoObjects/Mailer/SOGoMailAccount.m \ + ../../SoObjects/Mailer/SOGoMailNamespace.m \ + ../../SoObjects/Mailer/SOGoDraftsFolder.m \ + ../../SoObjects/Mailer/SOGoSentFolder.m \ + ../../SoObjects/Mailer/SOGoTrashFolder.m \ + ../../SoObjects/Mailer/SOGoMailFolder.m \ + ../../SoObjects/Mailer/SOGoDraftObject.m \ + ../../SoObjects/Mailer/SOGoMailObject.m \ + ../../SoObjects/Appointments/SOGoEMailAlarmsManager.m \ + ../../SoObjects/Appointments/SOGoAppointmentObject.m \ + ../../SoObjects/Appointments/SOGoComponentOccurence.m \ + ../../SoObjects/Appointments/SOGoAppointmentOccurence.m \ + ../../SoObjects/Appointments/SOGoCalendarComponent.m MailPartViewers_RESOURCE_FILES += \ product.plist \ diff --git a/UI/MailPartViewers/GNUmakefile.preamble b/UI/MailPartViewers/GNUmakefile.preamble index 545cdf46b..15440fbdd 100644 --- a/UI/MailPartViewers/GNUmakefile.preamble +++ b/UI/MailPartViewers/GNUmakefile.preamble @@ -2,3 +2,10 @@ ifeq ($(HAS_LIBRARY_ssl),yes) ADDITIONAL_CPPFLAGS += -DHAVE_OPENSSL=1 BUNDLE_LIBS += -lcrypto endif + +ADDITIONAL_CPPFLAGS += \ + -Wall -DCOMPILE_FOR_GSTEP_MAKE=1 \ + -DUIX_MAILER_MAJOR_VERSION="@\"$(MAJOR_VERSION)\"" \ + -DUIX_MAILER_MINOR_VERSION="@\"$(MINOR_VERSION)\"" \ + -DUIX_MAILER_SUBMINOR_VERSION="@\"$(SUBMINOR_VERSION)\"" + diff --git a/UI/MailPartViewers/UIxMailPartICalViewer.m b/UI/MailPartViewers/UIxMailPartICalViewer.m index 66259a2bf..f377234db 100644 --- a/UI/MailPartViewers/UIxMailPartICalViewer.m +++ b/UI/MailPartViewers/UIxMailPartICalViewer.m @@ -1,6 +1,7 @@ /* Copyright (C) 2004-2005 SKYRIX Software AG - + Copyright (C) 2006-2013 Inverse inc. + This file is part of SOGo. SOGo is free software; you can redistribute it and/or modify it under diff --git a/UI/MailPartViewers/UIxMailPartViewer.m b/UI/MailPartViewers/UIxMailPartViewer.m index 2981875fd..51e8752a6 100644 --- a/UI/MailPartViewers/UIxMailPartViewer.m +++ b/UI/MailPartViewers/UIxMailPartViewer.m @@ -1,5 +1,5 @@ /* - Copyright (C) 2007-2009 Inverse inc. + Copyright (C) 2007-2013 Inverse inc. Copyright (C) 2004-2005 SKYRIX Software AG This file is part of SOGo. @@ -33,6 +33,7 @@ #import #import +#import #import #import "MailerUI/WOContext+UIxMailer.h" @@ -210,22 +211,7 @@ - (NSString *) filename { - NSDictionary *parameters; - NSString *filename; - - filename = nil; - parameters = [bodyInfo valueForKey: @"parameterList"]; - if (parameters) - filename = [parameters valueForKey: @"name"]; - - if (!filename) - { - parameters = [[bodyInfo valueForKey: @"disposition"] - valueForKey: @"parameterList"]; - filename = [parameters valueForKey: @"filename"]; - } - - return filename; + return [bodyInfo filename]; } - (NSString *) filenameForDisplay @@ -280,7 +266,7 @@ NSMutableString *filename; NSString *extension; - filename = [NSMutableString stringWithString: [bodyPart filename]]; + filename = [self filename]; if (![filename length]) [filename appendFormat: @"%@-%@", [self labelForKey: @"Untitled"], @@ -323,22 +309,22 @@ NSString *mimeImageFile, *mimeImageUrl; mimeImageFile = [NSString stringWithFormat: @"mime-%@-%@.png", - [bodyInfo objectForKey: @"type"], - [bodyInfo objectForKey: @"subtype"]]; + [bodyInfo objectForKey: @"type"], + [bodyInfo objectForKey: @"subtype"]]; mimeImageUrl = [self urlForResourceFilename: mimeImageFile]; - if ( [mimeImageUrl length] == 0 ) - { - mimeImageFile = [NSString stringWithFormat: @"mime-%@.png", - [bodyInfo objectForKey: @"type"]]; - mimeImageUrl = [self urlForResourceFilename: mimeImageFile]; - } + if ([mimeImageUrl length] == 0) + { + mimeImageFile = [NSString stringWithFormat: @"mime-%@.png", + [bodyInfo objectForKey: @"type"]]; + mimeImageUrl = [self urlForResourceFilename: mimeImageFile]; + } - if ( [mimeImageUrl length] == 0 ) - { - mimeImageUrl = [self urlForResourceFilename: @"mime-unknown.png"]; - } + if ([mimeImageUrl length] == 0) + { + mimeImageUrl = [self urlForResourceFilename: @"mime-unknown.png"]; + } return mimeImageUrl; } diff --git a/UI/MailerUI/GNUmakefile b/UI/MailerUI/GNUmakefile index dc1fdb9cb..b1932214d 100644 --- a/UI/MailerUI/GNUmakefile +++ b/UI/MailerUI/GNUmakefile @@ -32,6 +32,7 @@ MailerUI_OBJC_FILES += \ UIxMailWindowCloser.m \ \ UIxMailUserRightsEditor.m \ + ../MailPartViewers/UIxMailRenderingContext.m \ UIxMailUserDelegationEditor.m \ # UIxMailEditorAction.m \ # UIxMailReplyAction.m \ diff --git a/UI/MailerUI/UIxMailListActions.m b/UI/MailerUI/UIxMailListActions.m index e9142ede4..e766321e9 100644 --- a/UI/MailerUI/UIxMailListActions.m +++ b/UI/MailerUI/UIxMailListActions.m @@ -753,7 +753,7 @@ // To to = [[message objectForKey: @"envelope"] to]; if ([to count] > 0) - [msg addObject: [addressFormatter stringForArray: to]]; + [msg addObject: [[addressFormatter stringForArray: to] stringByEscapingHTMLString]]; else [msg addObject: @""]; @@ -778,7 +778,7 @@ // From from = [[message objectForKey: @"envelope"] from]; if ([from count] > 0) - [msg addObject: [addressFormatter stringForArray: from]]; + [msg addObject: [[addressFormatter stringForArray: from] stringByEscapingHTMLString]]; else [msg addObject: @""]; diff --git a/UI/MainUI/Czech.lproj/Localizable.strings b/UI/MainUI/Czech.lproj/Localizable.strings index b97493efe..9342a11b0 100644 --- a/UI/MainUI/Czech.lproj/Localizable.strings +++ b/UI/MainUI/Czech.lproj/Localizable.strings @@ -44,7 +44,7 @@ "Welsh" = "Cymraeg"; "About" = "O aplikaci"; -"AboutBox" = "SOGo je plně vybavený groupwarový server vyvíjený Inverse, který je zaměřený na jednoduchost a škálovatelnost.

⏎ SOGo poskytuje bohaté webové prostředí založené na technologii AJAX a podporuje i mnoho kalendářových klientů pracujících se standardními protokoly CalDAV a CardDAV.

⏎ SOGo je distribuováno pod licencí GNU GPL verze 2 nebo novější a některé části jsou distribuovány pod licencí GNU LGPL verze 2. Toto je svobodný software: můžete ho svobodně měnit a šířit dále. Neexistuje ŽÁDNÁ ZÁRUKA v rozsahu upraveném zákonem.

⏎ \nRůzné možnosti podpory naleznete na této stránce."; +"AboutBox" = "SOGo je plně vybavený groupwarový server vyvíjený Inverse, který je zaměřený na jednoduchost a škálovatelnost.

\nSOGo poskytuje bohaté webové prostředí založené na technologii AJAX a podporuje i mnoho kalendářových klientů pracujících se standardními protokoly CalDAV a CardDAV.

\nSOGo je distribuováno pod licencí GNU GPL verze 2 nebo novější a některé části jsou distribuovány pod licencí GNU LGPL verze 2. Toto je svobodný software: můžete ho svobodně měnit a šířit dále. Neexistuje ŽÁDNÁ ZÁRUKA v rozsahu upraveném zákonem.

\nRůzné možnosti podpory naleznete na této stránce."; "Your account was locked due to too many failed attempts." = "Váš účet byl zablokován z důvodu mnoha neúspěšných pokusů o přihlášení."; "Your account was locked due to an expired password." = "Váš účet byl zablokován z důvodu expirovaného hesla."; diff --git a/UI/MainUI/German.lproj/Localizable.strings b/UI/MainUI/German.lproj/Localizable.strings index 43d7cd413..69b74ca8d 100644 --- a/UI/MainUI/German.lproj/Localizable.strings +++ b/UI/MainUI/German.lproj/Localizable.strings @@ -10,15 +10,15 @@ "Connect" = "Anmelden"; "Wrong username or password." = "Falscher Benutzername oder falsches Passwort"; -"cookiesNotEnabled" = "Verbindung zu SOGo ist nicht möglich, da Cookies in Ihrem Browser deaktiviert sind. Bitte aktivieren Sie Cookies in Ihrem Browser."; +"cookiesNotEnabled" = "Anmeldung an SOGo ist nicht möglich, da Cookies in Ihrem Browser deaktiviert sind. Bitte aktivieren Sie Cookies in Ihrem Browser und versuchen Sie es erneut."; -"browserNotCompatible" = "Wir haben festgestellt, dass Ihre Browserversion im Moment nicht von SOGo unterstützt wird. Klicken Sie unten auf den Link, um die aktuelle Version Ihres Browsers zu installieren."; +"browserNotCompatible" = "Wir haben festgestellt, dass Ihre Browserversion im Moment nicht von SOGo unterstützt wird. Wir empfehlen Firefox zu verwenden. Klicken Sie unten auf den Link, um die aktuelle Version dieses Browsers zu installieren."; "alternativeBrowsers" = "Sie können auch die folgenden Browser benutzen"; "alternativeBrowserSafari" = "Sie können auch Safari benutzen."; "Download" = "Herunterladen"; "Language:" = "Sprache:"; -"choose" = "Auswählen"; +"choose" = "Auswählen ..."; "Arabic" = "العربية"; "Catalan" = "Català"; "Czech" = "Česky"; @@ -46,7 +46,7 @@ "About" = "Über"; "AboutBox" = "Entwickelt von Inverse. SOGo ist ein vollständiger Groupware-Server mit Fokus auf Skalierbarkeit und Unkompliziertheit.

\nSOGo bietet ein umfangreiches, auf AJAX basierendes Web-Interface. Durch die Verwendung von Protokollstandards wie etwa CalDAV und CardDAV werden verschiedene native Clients unterstützt.

\nSOGo wird unter der GNU GPLv2 oder höher, Teile unter der GNU LGPLv2 angeboten. Dies ist freie Software: Sie haben die Freiheit sie zu verändern und erneut zu verbreiten. Es besteht KEINE GEWÄHRLEISTUNG, soweit dies gesetzlich zulässig ist.

\nAuf dieser Seite (in englischer Sprache) können Sie sich über weitere Support-Möglichkeiten informieren."; -"Your account was locked due to too many failed attempts." = "Ihr Konto wurde wegen zu vieler fehlgeschlagener Versuche gesperrt."; +"Your account was locked due to too many failed attempts." = "Ihr Konto wurde wegen zu vieler fehlgeschlagener Anmeldeversuche gesperrt."; "Your account was locked due to an expired password." = "Ihr Konto wurde wegen eines abgelaufenen Passwortes gesperrt."; "Login failed due to unhandled error case: " = "Die Anmeldung ist aufgrund eines unbehandelten Fehlers fehlgeschlagen: "; "Change your Password" = "Bitte Passwort ändern"; diff --git a/UI/PreferencesUI/German.lproj/Localizable.strings b/UI/PreferencesUI/German.lproj/Localizable.strings index 4e6bd1618..ce5de69ce 100644 --- a/UI/PreferencesUI/German.lproj/Localizable.strings +++ b/UI/PreferencesUI/German.lproj/Localizable.strings @@ -18,7 +18,7 @@ "Delete" = "Löschen"; /* contacts categories */ -"contacts_category_labels" = "Geschäftspartner, Familie, Freund, Kollegin, Konkurrenten, Kunden, Lieferant, Presse, VIP"; +"contacts_category_labels" = "Familie, Freund, Geschäftspartner, Kollegin, Konkurrenten, Kunden, Lieferant, Presse, VIP"; /* vacation (auto-reply) */ "Enable vacation auto reply" = "Automatische Abwesenheitsnachricht aktivieren"; @@ -36,7 +36,7 @@ /* forward messages */ "Forward incoming messages" = "Ankommende Nachrichten weiterleiten"; -"Keep a copy" = "Kopie behalten"; +"Keep a copy" = "Eine Kopie behalten"; "Please specify an address to which you want to forward your messages." = "Bitte Adresse angeben, an die Ihre Nachrichten weitergeleitet werden sollen."; @@ -96,12 +96,12 @@ "Day start time must be prior to day end time." = "Der Tagesanfang muss vor dem Tagesende liegen."; "Show time as busy outside working hours" = "Zeiten außerhalb der Arbeitszeit als belegt anzeigen"; "First week of year :" = "Erste Woche des Jahres:"; -"Enable reminders for Calendar items" = "Terminerinnerung aktivieren"; +"Enable reminders for Calendar items" = "Termin- und Aufgabenerinnerungen aktivieren"; "Play a sound when a reminder comes due" = "Akustisches Signal zur Terminerinnerung"; "Default reminder :" = "Standard Terminerinnerung:"; -"firstWeekOfYear_January1" = "Beginnt am 1.Januar"; +"firstWeekOfYear_January1" = "Beginnt am 1. Januar"; "firstWeekOfYear_First4DayWeek" = "Erste 4 Tage Woche"; "firstWeekOfYear_FirstFullWeek" = "Erste ganze Woche"; @@ -168,7 +168,7 @@ "Email:" = "E-Mail-Adresse:"; "Reply To Email:" = "\"Antworten An\" E-Mail-Adresse (Reply-To):"; "Signature:" = "Signatur:"; -"(Click to create)" = "(Klick zum Erstellen)"; +"(Click to create)" = "(Zum Erstellen klicken)"; "Signature" = "Signatur"; "Please enter your signature below:" = "Bitte fügen Sie die Signatur hier ein:"; @@ -193,17 +193,17 @@ /* Event+task categories */ "category_none" = "Keine"; -"calendar_category_labels" = "Jubiläum,Geburtstag,Geschäft,Anrufe,Klienten,Konkurrenz,Kunde,Favoriten,Fortsetzung,Geschenke,Ferien,Ideen,Besprechung,Fragen,Verschiedenes,Persönlich,Projekte,Feiertag,Status,Lieferanten,Reise,Urlaub"; +"calendar_category_labels" = "Anrufe,Besprechung,Favoriten,Feiertag,Ferien,Fortsetzung,Fragen,Geburtstag,Geschäft,Geschenke,Ideen,Jubiläum,Klienten,Konkurrenz,Kunde,Lieferanten,Persönlich,Projekte,Reise,Status,Urlaub,Verschiedenes"; /* Default module */ "Calendar" = "Kalender"; "Contacts" = "Adressbuch"; -"Mail" = "Mail"; +"Mail" = "E-Mail"; "Last" = "Zuletzt benutztes"; "Default module :" = "Vorgegebenes Modul:"; "Language :" = "Sprache :"; -"choose" = "Auswählen"; +"choose" = "Auswählen ..."; "Arabic" = "العربية"; "Catalan" = "Català"; "Czech" = "Česky"; diff --git a/UI/PreferencesUI/Russian.lproj/Localizable.strings b/UI/PreferencesUI/Russian.lproj/Localizable.strings index e3700265a..2b64bb9e9 100644 --- a/UI/PreferencesUI/Russian.lproj/Localizable.strings +++ b/UI/PreferencesUI/Russian.lproj/Localizable.strings @@ -141,6 +141,7 @@ "messageforward_inline" = "В теле письма"; "messageforward_attached" = "Приложенным файлом"; +"When replying to a message:" = "При ответе на сообщение:"; "replyplacement_above" = "Начинать мой ответ над цитируемым текстом"; "replyplacement_below" = "Начинать мой ответ под цитируемым текстом"; "And place my signature" = "И поместить мою подпись"; @@ -149,12 +150,17 @@ "Compose messages in" = "Compose messages in"; "composemessagestype_html" = "HTML"; "composemessagestype_text" = "Plain text"; +"Display remote inline images" = "Показать встроенные изображения из сети"; +"displayremoteinlineimages_never" = "Никогда"; +"displayremoteinlineimages_always" = "Всегда"; /* IMAP Accounts */ "New Mail Account" = "New Mail Account"; "Server Name:" = "Server Name:"; "Port:" = "Port:"; +"Encryption:" = "Шифрование:"; +"None" = "Нет"; "User Name:" = "User Name:"; "Password:" = "Пароль:"; @@ -247,6 +253,7 @@ "match any of the following rules:" = "отвечают любому из следующих правил:"; "match all messages" = "все сообщения"; "Perform these actions:" = "Произвести следующие действия:"; +"Untitled Filter" = "Фильтр без названия"; "Subject" = "Subject"; "From" = "From"; diff --git a/UI/Scheduler/BrazilianPortuguese.lproj/Localizable.strings b/UI/Scheduler/BrazilianPortuguese.lproj/Localizable.strings index 4570f0b29..73e31e23a 100644 --- a/UI/Scheduler/BrazilianPortuguese.lproj/Localizable.strings +++ b/UI/Scheduler/BrazilianPortuguese.lproj/Localizable.strings @@ -179,6 +179,8 @@ "Reminder:" = "Lembrete:"; "General:" = "Geral:"; "Reply:" = "Responder:"; +"Created by:" = "Criado por:"; + "Target:" = "Marca:"; @@ -373,6 +375,9 @@ "Show Time as Free" = "Exibir Hora como Livre"; +/* email notifications */ +"Send Appointment Notifications" = "Enviar Notificações de Apontamento"; + /* validation errors */ validate_notitle = "Nenhum título informado, continue?"; diff --git a/UI/Scheduler/Czech.lproj/Localizable.strings b/UI/Scheduler/Czech.lproj/Localizable.strings index 4a0d83b91..b64e18b5d 100644 --- a/UI/Scheduler/Czech.lproj/Localizable.strings +++ b/UI/Scheduler/Czech.lproj/Localizable.strings @@ -179,6 +179,8 @@ "Reminder:" = "Připomenutí:"; "General:" = "Obecný:"; "Reply:" = "Odpověď:"; +"Created by:" = "Vytvořeno:"; + "Target:" = "Vložte adresu webové stránky nebo dokumentu."; @@ -373,6 +375,9 @@ "Show Time as Free" = "Čas zobrazit jako volný"; +/* email notifications */ +"Send Appointment Notifications" = "Poslat připomenutí"; + /* validation errors */ validate_notitle = "Název nebyl nastaven, pokračovat?"; diff --git a/UI/Scheduler/Dutch.lproj/Localizable.strings b/UI/Scheduler/Dutch.lproj/Localizable.strings index bfdaff361..6c0695653 100644 --- a/UI/Scheduler/Dutch.lproj/Localizable.strings +++ b/UI/Scheduler/Dutch.lproj/Localizable.strings @@ -179,6 +179,8 @@ "Reminder:" = "Alarm:"; "General:" = "Algemeen:"; "Reply:" = "Antwoord:"; +"Created by:" = "Aangemaakt door:"; + "Target:" = "Bestemming:"; @@ -373,6 +375,9 @@ "Show Time as Free" = "Toon tijd als vrij"; +/* email notifications */ +"Send Appointment Notifications" = "Stuur afspraakmeldingen"; + /* validation errors */ validate_notitle = "U heeft geen titel opgegeven. Wilt u doorgaan?"; diff --git a/UI/Scheduler/German.lproj/Localizable.strings b/UI/Scheduler/German.lproj/Localizable.strings index 4db805264..06f2c7bea 100644 --- a/UI/Scheduler/German.lproj/Localizable.strings +++ b/UI/Scheduler/German.lproj/Localizable.strings @@ -179,6 +179,8 @@ "Reminder:" = "Erinnerung:"; "General:" = "Generell:"; "Reply:" = "Antwort:"; +"Created by:" = "Erstellt von:"; + "Target:" = "Ziel:"; @@ -373,6 +375,9 @@ "Show Time as Free" = "Zeige Zeit als Verfügbar"; +/* email notifications */ +"Send Appointment Notifications" = "Verabredungsbenachrichtigungen senden"; + /* validation errors */ validate_notitle = "Sie haben keinen Titel eingegeben. Wollen Sie trotzdem fortfahren?"; diff --git a/UI/Scheduler/Polish.lproj/Localizable.strings b/UI/Scheduler/Polish.lproj/Localizable.strings index 3ebae4b95..27c84e918 100644 --- a/UI/Scheduler/Polish.lproj/Localizable.strings +++ b/UI/Scheduler/Polish.lproj/Localizable.strings @@ -179,6 +179,8 @@ "Reminder:" = "Przypomnienie:"; "General:" = "Ogólne:"; "Reply:" = "Odpowiedź:"; +"Created by:" = "Stworzone przez:"; + "Target:" = "Cel:"; @@ -373,6 +375,9 @@ "Show Time as Free" = "Pokaż czas jako wolny"; +/* email notifications */ +"Send Appointment Notifications" = "Wyślij powiadomienia o spotkaniu"; + /* validation errors */ validate_notitle = "Nie podano tytułu, kontynuować?"; diff --git a/UI/Scheduler/Russian.lproj/Localizable.strings b/UI/Scheduler/Russian.lproj/Localizable.strings index a3375a778..8dec3259c 100644 --- a/UI/Scheduler/Russian.lproj/Localizable.strings +++ b/UI/Scheduler/Russian.lproj/Localizable.strings @@ -179,6 +179,8 @@ "Reminder:" = "Напоминание:"; "General:" = "Общее:"; "Reply:" = "Ответ:"; +"Created by:" = "Создано:"; + "Target:" = "Цель:"; @@ -373,6 +375,9 @@ "Show Time as Free" = "Отображать время как свободное"; +/* email notifications */ +"Send Appointment Notifications" = "Отправлять напоминания о встречах"; + /* validation errors */ validate_notitle = "Нет названия. Продолжить?"; diff --git a/UI/Scheduler/UIxCalMainView.m b/UI/Scheduler/UIxCalMainView.m index a7f9222a1..ea93a63b9 100644 --- a/UI/Scheduler/UIxCalMainView.m +++ b/UI/Scheduler/UIxCalMainView.m @@ -214,8 +214,6 @@ - (BOOL) showCompletedTasks { - BOOL show; - [self _setupContext]; return [[us objectForKey: @"ShowCompletedTasks"] boolValue]; @@ -237,6 +235,32 @@ return [self responseWithStatus: 204]; } +- (WOResponse *) saveListStateAction +{ + WORequest *request; + NSString *state; + + [self _setupContext]; + request = [context request]; + + state = [request formValueForKey: @"state"]; + [moduleSettings setObject: state + forKey: @"ListState"]; + [us synchronize]; + + return [self responseWithStatus: 204]; +} + +- (NSString *) listStateStyle +{ + NSString *state; + + [self _setupContext]; + state = [moduleSettings objectForKey: @"ListState"]; + + return (state && [state compare: @"collapse"] == NSOrderedSame)? @"display: none;" : @""; +} + - (unsigned int) firstDayOfWeek { SOGoUserDefaults *ud; diff --git a/UI/Scheduler/UIxCalView.m b/UI/Scheduler/UIxCalView.m index 2ed982b00..bbf7b4608 100644 --- a/UI/Scheduler/UIxCalView.m +++ b/UI/Scheduler/UIxCalView.m @@ -343,6 +343,26 @@ } } +- (NSString *) collapseBtnClass +{ + NSString *module, *state; + NSMutableDictionary *moduleSettings; + SOGoUser *activeUser; + SOGoAppointmentFolders *clientObject; + SOGoUserSettings *us; + + activeUser = [context activeUser]; + clientObject = [self clientObject]; + + module = [clientObject nameInContainer]; + + us = [activeUser userSettings]; + moduleSettings = [us objectForKey: module]; + state = [moduleSettings objectForKey: @"ListState"]; + + return (state && [state compare: @"collapse"] == NSOrderedSame)? @"rise" : @"collapse"; +} + /* current day related */ - (void) setCurrentDay:(NSCalendarDate *) _day diff --git a/UI/Scheduler/UIxComponentEditor.m b/UI/Scheduler/UIxComponentEditor.m index 398c2cd15..9c3e7cbc5 100644 --- a/UI/Scheduler/UIxComponentEditor.m +++ b/UI/Scheduler/UIxComponentEditor.m @@ -872,10 +872,16 @@ iRANGE(2); - (NSString *) organizerName { NSDictionary *profile; + NSString *s; profile = [[[self organizerProfile] allValues] lastObject]; + + s = [profile objectForKey: @"name"]; - return [profile objectForKey: @"name"]; + if ([s length] == 0) + s = [profile objectForKey: @"email"]; + + return s; } - (NSString *) jsonOrganizer diff --git a/UI/Scheduler/product.plist b/UI/Scheduler/product.plist index c433d5f84..df8ad4852 100644 --- a/UI/Scheduler/product.plist +++ b/UI/Scheduler/product.plist @@ -55,6 +55,11 @@ pageName = "UIxCalMainView"; actionName = "saveSelectedList"; }; + saveListState = { + protectedBy = "View"; + pageName = "UIxCalMainView"; + actionName = "saveListState"; + }; dateselector = { protectedBy = "View"; pageName = "UIxCalDateSelector"; diff --git a/UI/Templates/Appointments/SOGoAptMailInvitation.wox b/UI/Templates/Appointments/SOGoAptMailInvitation.wox index b5af75331..8efa43197 100644 --- a/UI/Templates/Appointments/SOGoAptMailInvitation.wox +++ b/UI/Templates/Appointments/SOGoAptMailInvitation.wox @@ -24,9 +24,9 @@ h1, dd, .dl-list dt { margin-left: 130px; }
-
-
+
- diff --git a/UI/Templates/SchedulerUI/UIxCalDayTable.wox b/UI/Templates/SchedulerUI/UIxCalDayTable.wox index ff800438b..5bb9f63ee 100644 --- a/UI/Templates/SchedulerUI/UIxCalDayTable.wox +++ b/UI/Templates/SchedulerUI/UIxCalDayTable.wox @@ -45,7 +45,10 @@ >
-
+ + + +
diff --git a/UI/Templates/SchedulerUI/UIxCalDayView.wox b/UI/Templates/SchedulerUI/UIxCalDayView.wox index f41be3a5d..388bd015e 100644 --- a/UI/Templates/SchedulerUI/UIxCalDayView.wox +++ b/UI/Templates/SchedulerUI/UIxCalDayView.wox @@ -1,63 +1,43 @@ - - + - - - - - -
- -
-
+ + + + + + + + + + + +
+ +
+
diff --git a/UI/Templates/SchedulerUI/UIxCalMainView.wox b/UI/Templates/SchedulerUI/UIxCalMainView.wox index 2b34302c6..9cb85f741 100644 --- a/UI/Templates/SchedulerUI/UIxCalMainView.wox +++ b/UI/Templates/SchedulerUI/UIxCalMainView.wox @@ -147,7 +147,7 @@
-
+
  • @@ -202,7 +202,7 @@
-
-
+
+
diff --git a/UI/Templates/SchedulerUI/UIxCalMonthView.wox b/UI/Templates/SchedulerUI/UIxCalMonthView.wox index f01954dcd..c1a47488a 100644 --- a/UI/Templates/SchedulerUI/UIxCalMonthView.wox +++ b/UI/Templates/SchedulerUI/UIxCalMonthView.wox @@ -1,77 +1,58 @@ - + - - - - - - -
-
-
-
+ + + + + + + + + + +
+
+
+
+ >
+ - +
-
- + diff --git a/UI/Templates/SchedulerUI/UIxCalWeekView.wox b/UI/Templates/SchedulerUI/UIxCalWeekView.wox index bcd628801..018be928f 100644 --- a/UI/Templates/SchedulerUI/UIxCalWeekView.wox +++ b/UI/Templates/SchedulerUI/UIxCalWeekView.wox @@ -1,63 +1,43 @@ + xmlns="http://www.w3.org/1999/xhtml" + xmlns:var="http://www.skyrix.com/od/binding" + xmlns:const="http://www.skyrix.com/od/constant" + xmlns:rsrc="OGo:url" + xmlns:label="OGo:label"> - - + - - - + + + + + + + + +
+ className="UIxCalDayTable" + startDate="startDate" + const:CSSClass="weekOverview" + const:numberOfDays="7" />
diff --git a/UI/WebServerResources/ContactsUI.js b/UI/WebServerResources/ContactsUI.js index b83f8a00d..b2ef19b4c 100644 --- a/UI/WebServerResources/ContactsUI.js +++ b/UI/WebServerResources/ContactsUI.js @@ -1502,18 +1502,18 @@ function unsetCategoryOnNode(contactNode, category) { function configureDraggables() { if ($("contactFolders")) { var rows = jQuery("tr.vcard"); - rows.draggable("destroy"); + try { rows.draggable("destroy"); } catch (e) {} rows.draggable({ - helper: function (event) { return '
'; }, - start: startDragging, - drag: whileDragging, - stop: stopDragging, - appendTo: 'body', - cursorAt: { right: 25 }, - scroll: false, - distance: 4, - zIndex: 20 - }); + helper: function (event) { return '
'; }, + start: startDragging, + drag: whileDragging, + stop: stopDragging, + appendTo: 'body', + cursorAt: { right: 25 }, + scroll: false, + distance: 4, + zIndex: 20 + }); } } diff --git a/UI/WebServerResources/SOGoTabsController.js b/UI/WebServerResources/SOGoTabsController.js index d4d7f10bb..31c988823 100644 --- a/UI/WebServerResources/SOGoTabsController.js +++ b/UI/WebServerResources/SOGoTabsController.js @@ -67,6 +67,7 @@ SOGoTabsController.prototype = { attachToTabsContainer: function STC_attachToTabsContainer(container) { this.container = container; + container.controller = this; this.onTabMouseDownBound = this.onTabMouseDown.bindAsEventListener(this); this.onTabClickBound diff --git a/UI/WebServerResources/SchedulerUI.css b/UI/WebServerResources/SchedulerUI.css index e09af2f73..429dc2c57 100644 --- a/UI/WebServerResources/SchedulerUI.css +++ b/UI/WebServerResources/SchedulerUI.css @@ -319,23 +319,23 @@ SPAN.weeksHeader, SPAN.monthsHeader { display: block; white-space: nowrap; + text-align: center; background-color: #DFDFDF; overflow: hidden; width: 100%; margin: 0px; height: 3em; - padding: 2px 1.5em; + padding: 2px 0px; border-bottom: 1px solid #ccc; } SPAN.daysHeader SPAN, SPAN.weeksHeader SPAN, SPAN.monthsHeader SPAN -{ display: block; +{ font-size: large; margin: .1em; - float: left; - width: 18%; - padding: 0px; + padding: 6px 12px; text-align: center; + line-height: 1.5em; border: 1px solid transparent; vertical-align: top; } @@ -343,67 +343,51 @@ SPAN.daysHeader A, SPAN.weeksHeader A, SPAN.monthsHeader A { border: 1px solid transparent; - color: #000; line-height: 1.5em; - padding: 0px .5em; } + padding: 0px 0.7em; } -A.leftNavigationArrow, -A.rightNavigationArrow -{ border: 1px solid transparent; - padding: .5em; - text-align: center; - vertical-align: bottom; } - -A.leftNavigationArrow:hover, -A.rightNavigationArrow:hover, -SPAN.daysHeader A:hover, -SPAN.weeksHeader A:hover, -SPAN.monthsHeader A:hover +.day1 A:hover, +.week1 A:hover, +.month1 A:hover { border-top: 1px solid #fff; border-left: 1px solid #fff; border-bottom: 1px solid #828482; border-right: 1px solid #828482; } -A.leftNavigationArrow:active, -A.rightNavigationArrow:active, -SPAN.daysHeader A:active, -SPAN.weeksHeader A:active, -SPAN.monthsHeader A:active +.day1 A:active, +.week1 A:active, +.month1 A:active { border-top: 1px solid #828482; border-left: 1px solid #828482; border-bottom: 1px solid #fff; border-right: 1px solid #fff; } -SPAN.week2, SPAN.month2 -{ font-size: small; } - -SPAN.day2, SPAN.week1, SPAN.month1 -{ font-size: medium; } - -SPAN.day1, SPAN.week0, SPAN.month0 -{ font-size: large; } - -SPAN.day0 -{ font-size: x-large; } - -SPAN.day0, SPAN.week0, SPAN.month0 -{ border-top: 1px solid #909090 !important; - border-left: 1px solid #909090 !important; - border-bottom: 1px solid #FFFFFF !important; - border-right: 1px solid #FFFFFF !important; - background-color: #ddd; } - -A.leftNavigationArrow +#listCollapse { position: absolute; - display: block; - top: .5em; - left: .5em; } + top: .2em; + right: 0; + margin: 0.5em 1em; } -A.rightNavigationArrow -{ position: absolute; - display: block; - top: .5em; - right: .5em; } +#listCollapse img +{ position: absolute; } + +#listCollapse img.collapse +{ clip: rect(0 18px 18px 0); + left: 0; + top: 0; } + +#listCollapse img.collapse:hover +{ clip: rect(0 36px 18px 18px); + left: -18px; } + +#listCollapse img.rise +{ clip: rect(18px 18px 36px 0); + left: 0; + top: -18px; } + +#listCollapse img.rise:hover +{ clip: rect(18px 36px 36px 18px); + left: -18px; } DIV#calendarHeader, DIV#daysView @@ -595,6 +579,14 @@ DIV.daysViewFor7Days#daysView DIV.selectedDay.weekEndDay DIV.clickableHourCell, DIV.daysViewFor7Days#daysView DIV.selectedDay DIV.clickableHourCell.outOfDay { background-color: #f5dd92; } +.minutes15, .minutes30, .minutes45 +{ display: block; + height: 9px; + border-bottom: 1px dotted #eee; } + +.minutes30 +{ border-bottom: 1px dotted #ccc; } + DIV.weekOf4 { height: 25%; } diff --git a/UI/WebServerResources/SchedulerUI.js b/UI/WebServerResources/SchedulerUI.js index bd7ad3943..4ab06c930 100644 --- a/UI/WebServerResources/SchedulerUI.js +++ b/UI/WebServerResources/SchedulerUI.js @@ -723,9 +723,9 @@ function onViewEventCallback(http) { top -= cell.up("DIV.day").scrollTop; } - left = cellPosition[0] + cellDimensions["width"] - parseInt(cellDimensions["width"]/3); + left = cellPosition[0] + cellDimensions["width"] + 4; if (left + divDimensions["width"] > window.width()) { - left = cellPosition[0] - divDimensions["width"] + 10; + left = cellPosition[0] - divDimensions["width"]; div.removeClassName("left"); div.addClassName("right"); } @@ -748,14 +748,14 @@ function onViewEventCallback(http) { para = $(paras[1]); if (data["calendar"].length) { // Remove owner email from calendar's name - para.down("SPAN", 1).update(data["calendar"].replace(/ \<.*\>/, "")); + para.down("SPAN", 1).update(data["calendar"].escapeHTML()); para.show(); } else para.hide(); para = $(paras[2]); if (data["location"].length) { - para.down("SPAN", 1).update(data["location"]); + para.down("SPAN", 1).update(data["location"].escapeHTML()); para.show(); } else para.hide(); @@ -3205,6 +3205,11 @@ function deletePersonalCalendarCallback(http) { } function configureLists() { + // Move calendar view if lists are collapsed + if (!$("schedulerTabs").visible()) { + $('calendarView').setStyle({ top: '0' }).show(); + } + // TASK LIST var list = $("tasksList"); list.multiselect = true; @@ -3292,6 +3297,37 @@ function drawNowLine() { } } +function onListCollapse(event, element) { + var img = element.select('img').first(); + var tabs = $("schedulerTabs"); + var handle = $("rightDragHandle"); + var view = jQuery("#calendarView"); + var state = 'collapse'; + + if (tabs.visible()) { + img.removeClassName('collapse').addClassName('rise'); + handle.hide(); + view.animate({ top: '0' }, 200, function() { + tabs.hide(); + }); + } + else { + state = 'rise'; + img.removeClassName('rise').addClassName('collapse'); + tabs.show(); + tabs.controller.onWindowResize(); + view.animate({ top: handle.getStyle('top') }, 200, function() { + handle.show(); + }); + } + + var url = ApplicationBaseURL + "saveListState"; + var params = "state=" + state; + triggerAjaxRequest(url, null, null, params, + { "Content-type": "application/x-www-form-urlencoded" }); + +} + function onDocumentKeydown(event) { var target = Event.element(event); if (target.tagName != "INPUT") { @@ -3367,7 +3403,7 @@ function initScheduler() { // Calendar import form $("uploadCancel").observe("click", hideCalendarImport); $("uploadOK").observe("click", hideImportResults); - + $("calendarView").on("click", "#listCollapse", onListCollapse); Event.observe(document, "keydown", onDocumentKeydown); } diff --git a/UI/WebServerResources/SchedulerUIDnD.js b/UI/WebServerResources/SchedulerUIDnD.js index 452cff420..7e74d18f9 100644 --- a/UI/WebServerResources/SchedulerUIDnD.js +++ b/UI/WebServerResources/SchedulerUIDnD.js @@ -1007,6 +1007,10 @@ SOGoEventDragController.prototype = { onDragStart: function SEDC_onDragStart(event) { var target = getTarget(event); if (eventIsLeftClick(event) && (target.nodeType == 1)) { + if (target.hasClassName("minutes15") || + target.hasClassName("minutes30") || + target.hasClassName("minutes45")) + target = target.parentNode; if ((!this.eventCells && (target.hasClassName("clickableHourCell") || target.hasClassName("day")) diff --git a/UI/WebServerResources/collapse.png b/UI/WebServerResources/collapse.png new file mode 100644 index 000000000..0cb238216 Binary files /dev/null and b/UI/WebServerResources/collapse.png differ diff --git a/UI/WebServerResources/generic.css b/UI/WebServerResources/generic.css index 277cfa5ba..b7bfacbe6 100644 --- a/UI/WebServerResources/generic.css +++ b/UI/WebServerResources/generic.css @@ -60,7 +60,6 @@ LABEL H6 { font-size: 11px; - color: #9ABCD8; color: #627e9c; text-transform: uppercase; margin: 10px 0px 5px 0px; @@ -1168,6 +1167,7 @@ span.cke_skin_kama DIV#linkBanner, DIV#toolbar, DIV.menu, + DIV.filterPanel, DIV.tabsContainer { display: none; } } diff --git a/UI/WebServerResources/jquery-ui.js b/UI/WebServerResources/jquery-ui.js old mode 100644 new mode 100755 index bc4c2f2be..96f078011 --- a/UI/WebServerResources/jquery-ui.js +++ b/UI/WebServerResources/jquery-ui.js @@ -1,43 +1,29 @@ -/*! - * jQuery UI 1.8.18 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI - */ +/*! jQuery UI - v1.10.3 - 2013-07-18 +* http://jqueryui.com +* Includes: jquery.ui.core.js, jquery.ui.widget.js, jquery.ui.mouse.js, jquery.ui.draggable.js, jquery.ui.droppable.js +* Copyright 2013 jQuery Foundation and other contributors Licensed MIT */ + (function( $, undefined ) { -// prevent duplicate loading -// this is only a problem because we proxy existing functions -// and we don't want to double proxy them +var uuid = 0, + runiqueId = /^ui-id-\d+$/; + +// $.ui might exist from components with no dependencies, e.g., $.ui.position $.ui = $.ui || {}; -if ( $.ui.version ) { - return; -} $.extend( $.ui, { - version: "1.8.18", + version: "1.10.3", keyCode: { - ALT: 18, BACKSPACE: 8, - CAPS_LOCK: 20, COMMA: 188, - COMMAND: 91, - COMMAND_LEFT: 91, // COMMAND - COMMAND_RIGHT: 93, - CONTROL: 17, DELETE: 46, DOWN: 40, END: 35, ENTER: 13, ESCAPE: 27, HOME: 36, - INSERT: 45, LEFT: 37, - MENU: 93, // COMMAND_RIGHT NUMPAD_ADD: 107, NUMPAD_DECIMAL: 110, NUMPAD_DIVIDE: 111, @@ -48,46 +34,43 @@ $.extend( $.ui, { PAGE_UP: 33, PERIOD: 190, RIGHT: 39, - SHIFT: 16, SPACE: 32, TAB: 9, - UP: 38, - WINDOWS: 91 // COMMAND + UP: 38 } }); // plugins $.fn.extend({ - propAttr: $.fn.prop || $.fn.attr, - - _focus: $.fn.focus, - focus: function( delay, fn ) { - return typeof delay === "number" ? - this.each(function() { - var elem = this; - setTimeout(function() { - $( elem ).focus(); - if ( fn ) { - fn.call( elem ); - } - }, delay ); - }) : - this._focus.apply( this, arguments ); - }, + focus: (function( orig ) { + return function( delay, fn ) { + return typeof delay === "number" ? + this.each(function() { + var elem = this; + setTimeout(function() { + $( elem ).focus(); + if ( fn ) { + fn.call( elem ); + } + }, delay ); + }) : + orig.apply( this, arguments ); + }; + })( $.fn.focus ), scrollParent: function() { var scrollParent; - if (($.browser.msie && (/(static|relative)/).test(this.css('position'))) || (/absolute/).test(this.css('position'))) { + if (($.ui.ie && (/(static|relative)/).test(this.css("position"))) || (/absolute/).test(this.css("position"))) { scrollParent = this.parents().filter(function() { - return (/(relative|absolute|fixed)/).test($.curCSS(this,'position',1)) && (/(auto|scroll)/).test($.curCSS(this,'overflow',1)+$.curCSS(this,'overflow-y',1)+$.curCSS(this,'overflow-x',1)); + return (/(relative|absolute|fixed)/).test($.css(this,"position")) && (/(auto|scroll)/).test($.css(this,"overflow")+$.css(this,"overflow-y")+$.css(this,"overflow-x")); }).eq(0); } else { scrollParent = this.parents().filter(function() { - return (/(auto|scroll)/).test($.curCSS(this,'overflow',1)+$.curCSS(this,'overflow-y',1)+$.curCSS(this,'overflow-x',1)); + return (/(auto|scroll)/).test($.css(this,"overflow")+$.css(this,"overflow-y")+$.css(this,"overflow-x")); }).eq(0); } - return (/fixed/).test(this.css('position')) || !scrollParent.length ? $(document) : scrollParent; + return (/fixed/).test(this.css("position")) || !scrollParent.length ? $(document) : scrollParent; }, zIndex: function( zIndex ) { @@ -119,95 +102,63 @@ $.fn.extend({ return 0; }, - disableSelection: function() { - return this.bind( ( $.support.selectstart ? "selectstart" : "mousedown" ) + - ".ui-disableSelection", function( event ) { - event.preventDefault(); - }); + uniqueId: function() { + return this.each(function() { + if ( !this.id ) { + this.id = "ui-id-" + (++uuid); + } + }); }, - enableSelection: function() { - return this.unbind( ".ui-disableSelection" ); - } -}); - -$.each( [ "Width", "Height" ], function( i, name ) { - var side = name === "Width" ? [ "Left", "Right" ] : [ "Top", "Bottom" ], - type = name.toLowerCase(), - orig = { - innerWidth: $.fn.innerWidth, - innerHeight: $.fn.innerHeight, - outerWidth: $.fn.outerWidth, - outerHeight: $.fn.outerHeight - }; - - function reduce( elem, size, border, margin ) { - $.each( side, function() { - size -= parseFloat( $.curCSS( elem, "padding" + this, true) ) || 0; - if ( border ) { - size -= parseFloat( $.curCSS( elem, "border" + this + "Width", true) ) || 0; - } - if ( margin ) { - size -= parseFloat( $.curCSS( elem, "margin" + this, true) ) || 0; + removeUniqueId: function() { + return this.each(function() { + if ( runiqueId.test( this.id ) ) { + $( this ).removeAttr( "id" ); } }); - return size; } - - $.fn[ "inner" + name ] = function( size ) { - if ( size === undefined ) { - return orig[ "inner" + name ].call( this ); - } - - return this.each(function() { - $( this ).css( type, reduce( this, size ) + "px" ); - }); - }; - - $.fn[ "outer" + name] = function( size, margin ) { - if ( typeof size !== "number" ) { - return orig[ "outer" + name ].call( this, size ); - } - - return this.each(function() { - $( this).css( type, reduce( this, size, true, margin ) + "px" ); - }); - }; }); // selectors function focusable( element, isTabIndexNotNaN ) { - var nodeName = element.nodeName.toLowerCase(); + var map, mapName, img, + nodeName = element.nodeName.toLowerCase(); if ( "area" === nodeName ) { - var map = element.parentNode, - mapName = map.name, - img; + map = element.parentNode; + mapName = map.name; if ( !element.href || !mapName || map.nodeName.toLowerCase() !== "map" ) { return false; } img = $( "img[usemap=#" + mapName + "]" )[0]; return !!img && visible( img ); } - return ( /input|select|textarea|button|object/.test( nodeName ) - ? !element.disabled - : "a" == nodeName - ? element.href || isTabIndexNotNaN - : isTabIndexNotNaN) + return ( /input|select|textarea|button|object/.test( nodeName ) ? + !element.disabled : + "a" === nodeName ? + element.href || isTabIndexNotNaN : + isTabIndexNotNaN) && // the element and all of its ancestors must be visible - && visible( element ); + visible( element ); } function visible( element ) { - return !$( element ).parents().andSelf().filter(function() { - return $.curCSS( this, "visibility" ) === "hidden" || - $.expr.filters.hidden( this ); - }).length; + return $.expr.filters.visible( element ) && + !$( element ).parents().addBack().filter(function() { + return $.css( this, "visibility" ) === "hidden"; + }).length; } $.extend( $.expr[ ":" ], { - data: function( elem, i, match ) { - return !!$.data( elem, match[ 3 ] ); - }, + data: $.expr.createPseudo ? + $.expr.createPseudo(function( dataName ) { + return function( elem ) { + return !!$.data( elem, dataName ); + }; + }) : + // support: jQuery <1.8 + function( elem, i, match ) { + return !!$.data( elem, match[ 3 ] ); + }, focusable: function( element ) { return focusable( element, !isNaN( $.attr( element, "tabindex" ) ) ); @@ -220,82 +171,137 @@ $.extend( $.expr[ ":" ], { } }); -// support -$(function() { - var body = document.body, - div = body.appendChild( div = document.createElement( "div" ) ); +// support: jQuery <1.8 +if ( !$( "" ).outerWidth( 1 ).jquery ) { + $.each( [ "Width", "Height" ], function( i, name ) { + var side = name === "Width" ? [ "Left", "Right" ] : [ "Top", "Bottom" ], + type = name.toLowerCase(), + orig = { + innerWidth: $.fn.innerWidth, + innerHeight: $.fn.innerHeight, + outerWidth: $.fn.outerWidth, + outerHeight: $.fn.outerHeight + }; - // access offsetHeight before setting the style to prevent a layout bug - // in IE 9 which causes the elemnt to continue to take up space even - // after it is removed from the DOM (#8026) - div.offsetHeight; + function reduce( elem, size, border, margin ) { + $.each( side, function() { + size -= parseFloat( $.css( elem, "padding" + this ) ) || 0; + if ( border ) { + size -= parseFloat( $.css( elem, "border" + this + "Width" ) ) || 0; + } + if ( margin ) { + size -= parseFloat( $.css( elem, "margin" + this ) ) || 0; + } + }); + return size; + } - $.extend( div.style, { - minHeight: "100px", - height: "auto", - padding: 0, - borderWidth: 0 + $.fn[ "inner" + name ] = function( size ) { + if ( size === undefined ) { + return orig[ "inner" + name ].call( this ); + } + + return this.each(function() { + $( this ).css( type, reduce( this, size ) + "px" ); + }); + }; + + $.fn[ "outer" + name] = function( size, margin ) { + if ( typeof size !== "number" ) { + return orig[ "outer" + name ].call( this, size ); + } + + return this.each(function() { + $( this).css( type, reduce( this, size, true, margin ) + "px" ); + }); + }; }); +} - $.support.minHeight = div.offsetHeight === 100; - $.support.selectstart = "onselectstart" in div; +// support: jQuery <1.8 +if ( !$.fn.addBack ) { + $.fn.addBack = function( selector ) { + return this.add( selector == null ? + this.prevObject : this.prevObject.filter( selector ) + ); + }; +} - // set display to none to avoid a layout bug in IE - // http://dev.jquery.com/ticket/4014 - body.removeChild( div ).style.display = "none"; -}); +// support: jQuery 1.6.1, 1.6.2 (http://bugs.jquery.com/ticket/9413) +if ( $( "" ).data( "a-b", "a" ).removeData( "a-b" ).data( "a-b" ) ) { + $.fn.removeData = (function( removeData ) { + return function( key ) { + if ( arguments.length ) { + return removeData.call( this, $.camelCase( key ) ); + } else { + return removeData.call( this ); + } + }; + })( $.fn.removeData ); +} // deprecated +$.ui.ie = !!/msie [\w.]+/.exec( navigator.userAgent.toLowerCase() ); + +$.support.selectstart = "onselectstart" in document.createElement( "div" ); +$.fn.extend({ + disableSelection: function() { + return this.bind( ( $.support.selectstart ? "selectstart" : "mousedown" ) + + ".ui-disableSelection", function( event ) { + event.preventDefault(); + }); + }, + + enableSelection: function() { + return this.unbind( ".ui-disableSelection" ); + } +}); + $.extend( $.ui, { - // $.ui.plugin is deprecated. Use the proxy pattern instead. + // $.ui.plugin is deprecated. Use $.widget() extensions instead. plugin: { add: function( module, option, set ) { - var proto = $.ui[ module ].prototype; - for ( var i in set ) { + var i, + proto = $.ui[ module ].prototype; + for ( i in set ) { proto.plugins[ i ] = proto.plugins[ i ] || []; proto.plugins[ i ].push( [ option, set[ i ] ] ); } }, call: function( instance, name, args ) { - var set = instance.plugins[ name ]; - if ( !set || !instance.element[ 0 ].parentNode ) { + var i, + set = instance.plugins[ name ]; + if ( !set || !instance.element[ 0 ].parentNode || instance.element[ 0 ].parentNode.nodeType === 11 ) { return; } - - for ( var i = 0; i < set.length; i++ ) { + + for ( i = 0; i < set.length; i++ ) { if ( instance.options[ set[ i ][ 0 ] ] ) { set[ i ][ 1 ].apply( instance.element, args ); } } } }, - - // will be deprecated when we switch to jQuery 1.4 - use jQuery.contains() - contains: function( a, b ) { - return document.compareDocumentPosition ? - a.compareDocumentPosition( b ) & 16 : - a !== b && a.contains( b ); - }, - + // only used by resizable hasScroll: function( el, a ) { - + //If overflow is hidden, the element might have extra content, but the user wants to hide it if ( $( el ).css( "overflow" ) === "hidden") { return false; } - + var scroll = ( a && a === "left" ) ? "scrollLeft" : "scrollTop", has = false; - + if ( el[ scroll ] > 0 ) { return true; } - + // TODO: determine which cases actually cause this to happen // if the element doesn't have the scroll set, see if it's possible to // set the scroll @@ -303,65 +309,32 @@ $.extend( $.ui, { has = ( el[ scroll ] > 0 ); el[ scroll ] = 0; return has; - }, - - // these are odd functions, fix the API or move into individual plugins - isOverAxis: function( x, reference, size ) { - //Determines when x coordinate is over "b" element axis - return ( x > reference ) && ( x < ( reference + size ) ); - }, - isOver: function( y, x, top, left, height, width ) { - //Determines when x, y coordinates is over "b" element - return $.ui.isOverAxis( y, top, height ) && $.ui.isOverAxis( x, left, width ); } }); })( jQuery ); -/*! - * jQuery UI Widget 1.8.18 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Widget - */ (function( $, undefined ) { -// jQuery 1.4+ -if ( $.cleanData ) { - var _cleanData = $.cleanData; - $.cleanData = function( elems ) { - for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) { - try { - $( elem ).triggerHandler( "remove" ); - // http://bugs.jquery.com/ticket/8235 - } catch( e ) {} - } - _cleanData( elems ); - }; -} else { - var _remove = $.fn.remove; - $.fn.remove = function( selector, keepData ) { - return this.each(function() { - if ( !keepData ) { - if ( !selector || $.filter( selector, [ this ] ).length ) { - $( "*", this ).add( [ this ] ).each(function() { - try { - $( this ).triggerHandler( "remove" ); - // http://bugs.jquery.com/ticket/8235 - } catch( e ) {} - }); - } - } - return _remove.call( $(this), selector, keepData ); - }); - }; -} +var uuid = 0, + slice = Array.prototype.slice, + _cleanData = $.cleanData; +$.cleanData = function( elems ) { + for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) { + try { + $( elem ).triggerHandler( "remove" ); + // http://bugs.jquery.com/ticket/8235 + } catch( e ) {} + } + _cleanData( elems ); +}; $.widget = function( name, base, prototype ) { - var namespace = name.split( "." )[ 0 ], - fullName; + var fullName, existingConstructor, constructor, basePrototype, + // proxiedPrototype allows the provided prototype to remain unmodified + // so that it can be used as a mixin for multiple widgets (#8876) + proxiedPrototype = {}, + namespace = name.split( "." )[ 0 ]; + name = name.split( "." )[ 1 ]; fullName = namespace + "-" + name; @@ -371,81 +344,167 @@ $.widget = function( name, base, prototype ) { } // create selector for plugin - $.expr[ ":" ][ fullName ] = function( elem ) { - return !!$.data( elem, name ); + $.expr[ ":" ][ fullName.toLowerCase() ] = function( elem ) { + return !!$.data( elem, fullName ); }; $[ namespace ] = $[ namespace ] || {}; - $[ namespace ][ name ] = function( options, element ) { + existingConstructor = $[ namespace ][ name ]; + constructor = $[ namespace ][ name ] = function( options, element ) { + // allow instantiation without "new" keyword + if ( !this._createWidget ) { + return new constructor( options, element ); + } + // allow instantiation without initializing for simple inheritance + // must use "new" keyword (the code above always passes args) if ( arguments.length ) { this._createWidget( options, element ); } }; + // extend with the existing constructor to carry over any static properties + $.extend( constructor, existingConstructor, { + version: prototype.version, + // copy the object used to create the prototype in case we need to + // redefine the widget later + _proto: $.extend( {}, prototype ), + // track widgets that inherit from this widget in case this widget is + // redefined after a widget inherits from it + _childConstructors: [] + }); - var basePrototype = new base(); + basePrototype = new base(); // we need to make the options hash a property directly on the new instance // otherwise we'll modify the options hash on the prototype that we're // inheriting from -// $.each( basePrototype, function( key, val ) { -// if ( $.isPlainObject(val) ) { -// basePrototype[ key ] = $.extend( {}, val ); -// } -// }); - basePrototype.options = $.extend( true, {}, basePrototype.options ); - $[ namespace ][ name ].prototype = $.extend( true, basePrototype, { + basePrototype.options = $.widget.extend( {}, basePrototype.options ); + $.each( prototype, function( prop, value ) { + if ( !$.isFunction( value ) ) { + proxiedPrototype[ prop ] = value; + return; + } + proxiedPrototype[ prop ] = (function() { + var _super = function() { + return base.prototype[ prop ].apply( this, arguments ); + }, + _superApply = function( args ) { + return base.prototype[ prop ].apply( this, args ); + }; + return function() { + var __super = this._super, + __superApply = this._superApply, + returnValue; + + this._super = _super; + this._superApply = _superApply; + + returnValue = value.apply( this, arguments ); + + this._super = __super; + this._superApply = __superApply; + + return returnValue; + }; + })(); + }); + constructor.prototype = $.widget.extend( basePrototype, { + // TODO: remove support for widgetEventPrefix + // always use the name + a colon as the prefix, e.g., draggable:start + // don't prefix for widgets that aren't DOM-based + widgetEventPrefix: existingConstructor ? basePrototype.widgetEventPrefix : name + }, proxiedPrototype, { + constructor: constructor, namespace: namespace, widgetName: name, - widgetEventPrefix: $[ namespace ][ name ].prototype.widgetEventPrefix || name, - widgetBaseClass: fullName - }, prototype ); + widgetFullName: fullName + }); - $.widget.bridge( name, $[ namespace ][ name ] ); + // If this widget is being redefined then we need to find all widgets that + // are inheriting from it and redefine all of them so that they inherit from + // the new version of this widget. We're essentially trying to replace one + // level in the prototype chain. + if ( existingConstructor ) { + $.each( existingConstructor._childConstructors, function( i, child ) { + var childPrototype = child.prototype; + + // redefine the child widget using the same prototype that was + // originally used, but inherit from the new version of the base + $.widget( childPrototype.namespace + "." + childPrototype.widgetName, constructor, child._proto ); + }); + // remove the list of existing child constructors from the old constructor + // so the old child constructors can be garbage collected + delete existingConstructor._childConstructors; + } else { + base._childConstructors.push( constructor ); + } + + $.widget.bridge( name, constructor ); +}; + +$.widget.extend = function( target ) { + var input = slice.call( arguments, 1 ), + inputIndex = 0, + inputLength = input.length, + key, + value; + for ( ; inputIndex < inputLength; inputIndex++ ) { + for ( key in input[ inputIndex ] ) { + value = input[ inputIndex ][ key ]; + if ( input[ inputIndex ].hasOwnProperty( key ) && value !== undefined ) { + // Clone objects + if ( $.isPlainObject( value ) ) { + target[ key ] = $.isPlainObject( target[ key ] ) ? + $.widget.extend( {}, target[ key ], value ) : + // Don't extend strings, arrays, etc. with objects + $.widget.extend( {}, value ); + // Copy everything else by reference + } else { + target[ key ] = value; + } + } + } + } + return target; }; $.widget.bridge = function( name, object ) { + var fullName = object.prototype.widgetFullName || name; $.fn[ name ] = function( options ) { var isMethodCall = typeof options === "string", - args = Array.prototype.slice.call( arguments, 1 ), + args = slice.call( arguments, 1 ), returnValue = this; // allow multiple hashes to be passed on init options = !isMethodCall && args.length ? - $.extend.apply( null, [ true, options ].concat(args) ) : + $.widget.extend.apply( null, [ options ].concat(args) ) : options; - // prevent calls to internal methods - if ( isMethodCall && options.charAt( 0 ) === "_" ) { - return returnValue; - } - if ( isMethodCall ) { this.each(function() { - var instance = $.data( this, name ), - methodValue = instance && $.isFunction( instance[options] ) ? - instance[ options ].apply( instance, args ) : - instance; - // TODO: add this back in 1.9 and use $.error() (see #5972) -// if ( !instance ) { -// throw "cannot call methods on " + name + " prior to initialization; " + -// "attempted to call method '" + options + "'"; -// } -// if ( !$.isFunction( instance[options] ) ) { -// throw "no such method '" + options + "' for " + name + " widget instance"; -// } -// var methodValue = instance[ options ].apply( instance, args ); + var methodValue, + instance = $.data( this, fullName ); + if ( !instance ) { + return $.error( "cannot call methods on " + name + " prior to initialization; " + + "attempted to call method '" + options + "'" ); + } + if ( !$.isFunction( instance[options] ) || options.charAt( 0 ) === "_" ) { + return $.error( "no such method '" + options + "' for " + name + " widget instance" ); + } + methodValue = instance[ options ].apply( instance, args ); if ( methodValue !== instance && methodValue !== undefined ) { - returnValue = methodValue; + returnValue = methodValue && methodValue.jquery ? + returnValue.pushStack( methodValue.get() ) : + methodValue; return false; } }); } else { this.each(function() { - var instance = $.data( this, name ); + var instance = $.data( this, fullName ); if ( instance ) { instance.option( options || {} )._init(); } else { - $.data( this, name, new object( options, this ) ); + $.data( this, fullName, new object( options, this ) ); } }); } @@ -454,74 +513,123 @@ $.widget.bridge = function( name, object ) { }; }; -$.Widget = function( options, element ) { - // allow instantiation without initializing for simple inheritance - if ( arguments.length ) { - this._createWidget( options, element ); - } -}; +$.Widget = function( /* options, element */ ) {}; +$.Widget._childConstructors = []; $.Widget.prototype = { widgetName: "widget", widgetEventPrefix: "", + defaultElement: "
", options: { - disabled: false + disabled: false, + + // callbacks + create: null }, _createWidget: function( options, element ) { - // $.widget.bridge stores the plugin instance, but we do it anyway - // so that it's stored even before the _create function runs - $.data( element, this.widgetName, this ); + element = $( element || this.defaultElement || this )[ 0 ]; this.element = $( element ); - this.options = $.extend( true, {}, + this.uuid = uuid++; + this.eventNamespace = "." + this.widgetName + this.uuid; + this.options = $.widget.extend( {}, this.options, this._getCreateOptions(), options ); - var self = this; - this.element.bind( "remove." + this.widgetName, function() { - self.destroy(); - }); + this.bindings = $(); + this.hoverable = $(); + this.focusable = $(); + + if ( element !== this ) { + $.data( element, this.widgetFullName, this ); + this._on( true, this.element, { + remove: function( event ) { + if ( event.target === element ) { + this.destroy(); + } + } + }); + this.document = $( element.style ? + // element within the document + element.ownerDocument : + // element is window or document + element.document || element ); + this.window = $( this.document[0].defaultView || this.document[0].parentWindow ); + } this._create(); - this._trigger( "create" ); + this._trigger( "create", null, this._getCreateEventData() ); this._init(); }, - _getCreateOptions: function() { - return $.metadata && $.metadata.get( this.element[0] )[ this.widgetName ]; - }, - _create: function() {}, - _init: function() {}, + _getCreateOptions: $.noop, + _getCreateEventData: $.noop, + _create: $.noop, + _init: $.noop, destroy: function() { + this._destroy(); + // we can probably remove the unbind calls in 2.0 + // all event bindings should go through this._on() this.element - .unbind( "." + this.widgetName ) - .removeData( this.widgetName ); + .unbind( this.eventNamespace ) + // 1.9 BC for #7810 + // TODO remove dual storage + .removeData( this.widgetName ) + .removeData( this.widgetFullName ) + // support: jquery <1.6.3 + // http://bugs.jquery.com/ticket/9413 + .removeData( $.camelCase( this.widgetFullName ) ); this.widget() - .unbind( "." + this.widgetName ) + .unbind( this.eventNamespace ) .removeAttr( "aria-disabled" ) .removeClass( - this.widgetBaseClass + "-disabled " + + this.widgetFullName + "-disabled " + "ui-state-disabled" ); + + // clean up events and states + this.bindings.unbind( this.eventNamespace ); + this.hoverable.removeClass( "ui-state-hover" ); + this.focusable.removeClass( "ui-state-focus" ); }, + _destroy: $.noop, widget: function() { return this.element; }, option: function( key, value ) { - var options = key; + var options = key, + parts, + curOption, + i; if ( arguments.length === 0 ) { // don't return a reference to the internal hash - return $.extend( {}, this.options ); + return $.widget.extend( {}, this.options ); } - if (typeof key === "string" ) { - if ( value === undefined ) { - return this.options[ key ]; - } + if ( typeof key === "string" ) { + // handle nested keys, e.g., "foo.bar" => { foo: { bar: ___ } } options = {}; - options[ key ] = value; + parts = key.split( "." ); + key = parts.shift(); + if ( parts.length ) { + curOption = options[ key ] = $.widget.extend( {}, this.options[ key ] ); + for ( i = 0; i < parts.length - 1; i++ ) { + curOption[ parts[ i ] ] = curOption[ parts[ i ] ] || {}; + curOption = curOption[ parts[ i ] ]; + } + key = parts.pop(); + if ( value === undefined ) { + return curOption[ key ] === undefined ? null : curOption[ key ]; + } + curOption[ key ] = value; + } else { + if ( value === undefined ) { + return this.options[ key ] === undefined ? null : this.options[ key ]; + } + options[ key ] = value; + } } this._setOptions( options ); @@ -529,10 +637,11 @@ $.Widget.prototype = { return this; }, _setOptions: function( options ) { - var self = this; - $.each( options, function( key, value ) { - self._setOption( key, value ); - }); + var key; + + for ( key in options ) { + this._setOption( key, options[ key ] ); + } return this; }, @@ -541,10 +650,10 @@ $.Widget.prototype = { if ( key === "disabled" ) { this.widget() - [ value ? "addClass" : "removeClass"]( - this.widgetBaseClass + "-disabled" + " " + - "ui-state-disabled" ) + .toggleClass( this.widgetFullName + "-disabled ui-state-disabled", !!value ) .attr( "aria-disabled", value ); + this.hoverable.removeClass( "ui-state-hover" ); + this.focusable.removeClass( "ui-state-focus" ); } return this; @@ -557,6 +666,97 @@ $.Widget.prototype = { return this._setOption( "disabled", true ); }, + _on: function( suppressDisabledCheck, element, handlers ) { + var delegateElement, + instance = this; + + // no suppressDisabledCheck flag, shuffle arguments + if ( typeof suppressDisabledCheck !== "boolean" ) { + handlers = element; + element = suppressDisabledCheck; + suppressDisabledCheck = false; + } + + // no element argument, shuffle and use this.element + if ( !handlers ) { + handlers = element; + element = this.element; + delegateElement = this.widget(); + } else { + // accept selectors, DOM elements + element = delegateElement = $( element ); + this.bindings = this.bindings.add( element ); + } + + $.each( handlers, function( event, handler ) { + function handlerProxy() { + // allow widgets to customize the disabled handling + // - disabled as an array instead of boolean + // - disabled class as method for disabling individual parts + if ( !suppressDisabledCheck && + ( instance.options.disabled === true || + $( this ).hasClass( "ui-state-disabled" ) ) ) { + return; + } + return ( typeof handler === "string" ? instance[ handler ] : handler ) + .apply( instance, arguments ); + } + + // copy the guid so direct unbinding works + if ( typeof handler !== "string" ) { + handlerProxy.guid = handler.guid = + handler.guid || handlerProxy.guid || $.guid++; + } + + var match = event.match( /^(\w+)\s*(.*)$/ ), + eventName = match[1] + instance.eventNamespace, + selector = match[2]; + if ( selector ) { + delegateElement.delegate( selector, eventName, handlerProxy ); + } else { + element.bind( eventName, handlerProxy ); + } + }); + }, + + _off: function( element, eventName ) { + eventName = (eventName || "").split( " " ).join( this.eventNamespace + " " ) + this.eventNamespace; + element.unbind( eventName ).undelegate( eventName ); + }, + + _delay: function( handler, delay ) { + function handlerProxy() { + return ( typeof handler === "string" ? instance[ handler ] : handler ) + .apply( instance, arguments ); + } + var instance = this; + return setTimeout( handlerProxy, delay || 0 ); + }, + + _hoverable: function( element ) { + this.hoverable = this.hoverable.add( element ); + this._on( element, { + mouseenter: function( event ) { + $( event.currentTarget ).addClass( "ui-state-hover" ); + }, + mouseleave: function( event ) { + $( event.currentTarget ).removeClass( "ui-state-hover" ); + } + }); + }, + + _focusable: function( element ) { + this.focusable = this.focusable.add( element ); + this._on( element, { + focusin: function( event ) { + $( event.currentTarget ).addClass( "ui-state-focus" ); + }, + focusout: function( event ) { + $( event.currentTarget ).removeClass( "ui-state-focus" ); + } + }); + }, + _trigger: function( type, event, data ) { var prop, orig, callback = this.options[ type ]; @@ -581,49 +781,73 @@ $.Widget.prototype = { } this.element.trigger( event, data ); - - return !( $.isFunction(callback) && - callback.call( this.element[0], event, data ) === false || + return !( $.isFunction( callback ) && + callback.apply( this.element[0], [ event ].concat( data ) ) === false || event.isDefaultPrevented() ); } }; +$.each( { show: "fadeIn", hide: "fadeOut" }, function( method, defaultEffect ) { + $.Widget.prototype[ "_" + method ] = function( element, options, callback ) { + if ( typeof options === "string" ) { + options = { effect: options }; + } + var hasOptions, + effectName = !options ? + method : + options === true || typeof options === "number" ? + defaultEffect : + options.effect || defaultEffect; + options = options || {}; + if ( typeof options === "number" ) { + options = { duration: options }; + } + hasOptions = !$.isEmptyObject( options ); + options.complete = callback; + if ( options.delay ) { + element.delay( options.delay ); + } + if ( hasOptions && $.effects && $.effects.effect[ effectName ] ) { + element[ method ]( options ); + } else if ( effectName !== method && element[ effectName ] ) { + element[ effectName ]( options.duration, options.easing, callback ); + } else { + element.queue(function( next ) { + $( this )[ method ](); + if ( callback ) { + callback.call( element[ 0 ] ); + } + next(); + }); + } + }; +}); + })( jQuery ); -/*! - * jQuery UI Mouse 1.8.18 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Mouse - * - * Depends: - * jquery.ui.widget.js - */ (function( $, undefined ) { var mouseHandled = false; -$( document ).mouseup( function( e ) { +$( document ).mouseup( function() { mouseHandled = false; }); $.widget("ui.mouse", { + version: "1.10.3", options: { - cancel: ':input,option', + cancel: "input,textarea,button,select,option", distance: 1, delay: 0 }, _mouseInit: function() { - var self = this; + var that = this; this.element - .bind('mousedown.'+this.widgetName, function(event) { - return self._mouseDown(event); + .bind("mousedown."+this.widgetName, function(event) { + return that._mouseDown(event); }) - .bind('click.'+this.widgetName, function(event) { - if (true === $.data(event.target, self.widgetName + '.preventClickEvent')) { - $.removeData(event.target, self.widgetName + '.preventClickEvent'); + .bind("click."+this.widgetName, function(event) { + if (true === $.data(event.target, that.widgetName + ".preventClickEvent")) { + $.removeData(event.target, that.widgetName + ".preventClickEvent"); event.stopImmediatePropagation(); return false; } @@ -635,23 +859,28 @@ $.widget("ui.mouse", { // TODO: make sure destroying one instance of mouse doesn't mess with // other instances of mouse _mouseDestroy: function() { - this.element.unbind('.'+this.widgetName); + this.element.unbind("."+this.widgetName); + if ( this._mouseMoveDelegate ) { + $(document) + .unbind("mousemove."+this.widgetName, this._mouseMoveDelegate) + .unbind("mouseup."+this.widgetName, this._mouseUpDelegate); + } }, _mouseDown: function(event) { // don't let more than one widget handle mouseStart - if( mouseHandled ) { return }; + if( mouseHandled ) { return; } // we may have missed mouseup (out of window) (this._mouseStarted && this._mouseUp(event)); this._mouseDownEvent = event; - var self = this, - btnIsLeft = (event.which == 1), + var that = this, + btnIsLeft = (event.which === 1), // event.target.nodeName works around a bug in IE 8 with // disabled inputs (#7620) - elIsCancel = (typeof this.options.cancel == "string" && event.target.nodeName ? $(event.target).closest(this.options.cancel).length : false); + elIsCancel = (typeof this.options.cancel === "string" && event.target.nodeName ? $(event.target).closest(this.options.cancel).length : false); if (!btnIsLeft || elIsCancel || !this._mouseCapture(event)) { return true; } @@ -659,7 +888,7 @@ $.widget("ui.mouse", { this.mouseDelayMet = !this.options.delay; if (!this.mouseDelayMet) { this._mouseDelayTimer = setTimeout(function() { - self.mouseDelayMet = true; + that.mouseDelayMet = true; }, this.options.delay); } @@ -672,30 +901,30 @@ $.widget("ui.mouse", { } // Click event may never have fired (Gecko & Opera) - if (true === $.data(event.target, this.widgetName + '.preventClickEvent')) { - $.removeData(event.target, this.widgetName + '.preventClickEvent'); + if (true === $.data(event.target, this.widgetName + ".preventClickEvent")) { + $.removeData(event.target, this.widgetName + ".preventClickEvent"); } // these delegates are required to keep context this._mouseMoveDelegate = function(event) { - return self._mouseMove(event); + return that._mouseMove(event); }; this._mouseUpDelegate = function(event) { - return self._mouseUp(event); + return that._mouseUp(event); }; $(document) - .bind('mousemove.'+this.widgetName, this._mouseMoveDelegate) - .bind('mouseup.'+this.widgetName, this._mouseUpDelegate); + .bind("mousemove."+this.widgetName, this._mouseMoveDelegate) + .bind("mouseup."+this.widgetName, this._mouseUpDelegate); event.preventDefault(); - + mouseHandled = true; return true; }, _mouseMove: function(event) { // IE mouseup check - mouseup happened when mouse was out of window - if ($.browser.msie && !(document.documentMode >= 9) && !event.button) { + if ($.ui.ie && ( !document.documentMode || document.documentMode < 9 ) && !event.button) { return this._mouseUp(event); } @@ -715,14 +944,14 @@ $.widget("ui.mouse", { _mouseUp: function(event) { $(document) - .unbind('mousemove.'+this.widgetName, this._mouseMoveDelegate) - .unbind('mouseup.'+this.widgetName, this._mouseUpDelegate); + .unbind("mousemove."+this.widgetName, this._mouseMoveDelegate) + .unbind("mouseup."+this.widgetName, this._mouseUpDelegate); if (this._mouseStarted) { this._mouseStarted = false; - if (event.target == this._mouseDownEvent.target) { - $.data(event.target, this.widgetName + '.preventClickEvent', true); + if (event.target === this._mouseDownEvent.target) { + $.data(event.target, this.widgetName + ".preventClickEvent", true); } this._mouseStop(event); @@ -739,35 +968,22 @@ $.widget("ui.mouse", { ); }, - _mouseDelayMet: function(event) { + _mouseDelayMet: function(/* event */) { return this.mouseDelayMet; }, // These are placeholder methods, to be overriden by extending plugin - _mouseStart: function(event) {}, - _mouseDrag: function(event) {}, - _mouseStop: function(event) {}, - _mouseCapture: function(event) { return true; } + _mouseStart: function(/* event */) {}, + _mouseDrag: function(/* event */) {}, + _mouseStop: function(/* event */) {}, + _mouseCapture: function(/* event */) { return true; } }); })(jQuery); -/* - * jQuery UI Draggable 1.8.18 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Draggables - * - * Depends: - * jquery.ui.core.js - * jquery.ui.mouse.js - * jquery.ui.widget.js - */ (function( $, undefined ) { $.widget("ui.draggable", $.ui.mouse, { + version: "1.10.3", widgetEventPrefix: "drag", options: { addClasses: true, @@ -793,58 +1009,61 @@ $.widget("ui.draggable", $.ui.mouse, { snapMode: "both", snapTolerance: 20, stack: false, - zIndex: false + zIndex: false, + + // callbacks + drag: null, + start: null, + stop: null }, _create: function() { - if (this.options.helper == 'original' && !(/^(?:r|a|f)/).test(this.element.css("position"))) - this.element[0].style.position = 'relative'; - - (this.options.addClasses && this.element.addClass("ui-draggable")); - (this.options.disabled && this.element.addClass("ui-draggable-disabled")); + if (this.options.helper === "original" && !(/^(?:r|a|f)/).test(this.element.css("position"))) { + this.element[0].style.position = "relative"; + } + if (this.options.addClasses){ + this.element.addClass("ui-draggable"); + } + if (this.options.disabled){ + this.element.addClass("ui-draggable-disabled"); + } this._mouseInit(); }, - destroy: function() { - if(!this.element.data('draggable')) return; - this.element - .removeData("draggable") - .unbind(".draggable") - .removeClass("ui-draggable" - + " ui-draggable-dragging" - + " ui-draggable-disabled"); + _destroy: function() { + this.element.removeClass( "ui-draggable ui-draggable-dragging ui-draggable-disabled" ); this._mouseDestroy(); - - return this; }, _mouseCapture: function(event) { var o = this.options; + $( document.activeElement ).blur(); + // among others, prevent a drag on a resizable-handle - if (this.helper || o.disabled || $(event.target).is('.ui-resizable-handle')) + if (this.helper || o.disabled || $(event.target).closest(".ui-resizable-handle").length > 0) { return false; + } //Quit if we're not on a valid handle this.handle = this._getHandle(event); - if (!this.handle) + if (!this.handle) { return false; - - if ( o.iframeFix ) { - $(o.iframeFix === true ? "iframe" : o.iframeFix).each(function() { - $('
') - .css({ - width: this.offsetWidth+"px", height: this.offsetHeight+"px", - position: "absolute", opacity: "0.001", zIndex: 1000 - }) - .css($(this).offset()) - .appendTo("body"); - }); } + $(o.iframeFix === true ? "iframe" : o.iframeFix).each(function() { + $("
") + .css({ + width: this.offsetWidth+"px", height: this.offsetHeight+"px", + position: "absolute", opacity: "0.001", zIndex: 1000 + }) + .css($(this).offset()) + .appendTo("body"); + }); + return true; }, @@ -856,12 +1075,15 @@ $.widget("ui.draggable", $.ui.mouse, { //Create and append the visible helper this.helper = this._createHelper(event); + this.helper.addClass("ui-draggable-dragging"); + //Cache the helper size this._cacheHelperProportions(); //If ddmanager is used for droppables, set the global draggable - if($.ui.ddmanager) + if($.ui.ddmanager) { $.ui.ddmanager.current = this; + } /* * - Position generation - @@ -872,8 +1094,10 @@ $.widget("ui.draggable", $.ui.mouse, { this._cacheMargins(); //Store the helper's css position - this.cssPosition = this.helper.css("position"); + this.cssPosition = this.helper.css( "position" ); this.scrollParent = this.helper.scrollParent(); + this.offsetParent = this.helper.offsetParent(); + this.offsetParentCssPosition = this.offsetParent.css( "position" ); //The element's absolute position on the page minus margins this.offset = this.positionAbs = this.element.offset(); @@ -882,6 +1106,9 @@ $.widget("ui.draggable", $.ui.mouse, { left: this.offset.left - this.margins.left }; + //Reset scroll cache + this.offset.scroll = false; + $.extend(this.offset, { click: { //Where the click happened, relative to the element left: event.pageX - this.offset.left, @@ -896,12 +1123,11 @@ $.widget("ui.draggable", $.ui.mouse, { this.originalPageX = event.pageX; this.originalPageY = event.pageY; - //Adjust the mouse offset relative to the helper if 'cursorAt' is supplied + //Adjust the mouse offset relative to the helper if "cursorAt" is supplied (o.cursorAt && this._adjustOffsetFromHelper(o.cursorAt)); //Set a containment if given in the options - if(o.containment) - this._setContainment(); + this._setContainment(); //Trigger event + callbacks if(this._trigger("start", event) === false) { @@ -913,19 +1139,26 @@ $.widget("ui.draggable", $.ui.mouse, { this._cacheHelperProportions(); //Prepare the droppable offsets - if ($.ui.ddmanager && !o.dropBehaviour) + if ($.ui.ddmanager && !o.dropBehaviour) { $.ui.ddmanager.prepareOffsets(this, event); + } + - this.helper.addClass("ui-draggable-dragging"); this._mouseDrag(event, true); //Execute the drag once - this causes the helper not to be visible before getting its correct position - + //If the ddmanager is used for droppables, inform the manager that dragging has started (see #5003) - if ( $.ui.ddmanager ) $.ui.ddmanager.dragStart(this, event); - + if ( $.ui.ddmanager ) { + $.ui.ddmanager.dragStart(this, event); + } + return true; }, _mouseDrag: function(event, noPropagation) { + // reset any necessary cached properties (see #5009) + if ( this.offsetParentCssPosition === "fixed" ) { + this.offset.parent = this._getParentOffset(); + } //Compute the helpers position this.position = this._generatePosition(event); @@ -934,16 +1167,22 @@ $.widget("ui.draggable", $.ui.mouse, { //Call plugins and callbacks and use the resulting position if something is returned if (!noPropagation) { var ui = this._uiHash(); - if(this._trigger('drag', event, ui) === false) { + if(this._trigger("drag", event, ui) === false) { this._mouseUp({}); return false; } this.position = ui.position; } - if(!this.options.axis || this.options.axis != "y") this.helper[0].style.left = this.position.left+'px'; - if(!this.options.axis || this.options.axis != "x") this.helper[0].style.top = this.position.top+'px'; - if($.ui.ddmanager) $.ui.ddmanager.drag(this, event); + if(!this.options.axis || this.options.axis !== "y") { + this.helper[0].style.left = this.position.left+"px"; + } + if(!this.options.axis || this.options.axis !== "x") { + this.helper[0].style.top = this.position.top+"px"; + } + if($.ui.ddmanager) { + $.ui.ddmanager.drag(this, event); + } return false; }, @@ -951,25 +1190,27 @@ $.widget("ui.draggable", $.ui.mouse, { _mouseStop: function(event) { //If we are using droppables, inform the manager about the drop - var dropped = false; - if ($.ui.ddmanager && !this.options.dropBehaviour) + var that = this, + dropped = false; + if ($.ui.ddmanager && !this.options.dropBehaviour) { dropped = $.ui.ddmanager.drop(this, event); + } //if a drop comes from outside (a sortable) if(this.dropped) { dropped = this.dropped; this.dropped = false; } - - //if the original element is removed, don't bother to continue if helper is set to "original" - if((!this.element[0] || !this.element[0].parentNode) && this.options.helper == "original") - return false; - if((this.options.revert == "invalid" && !dropped) || (this.options.revert == "valid" && dropped) || this.options.revert === true || ($.isFunction(this.options.revert) && this.options.revert.call(this.element, dropped))) { - var self = this; + //if the original element is no longer in the DOM don't bother to continue (see #8269) + if ( this.options.helper === "original" && !$.contains( this.element[ 0 ].ownerDocument, this.element[ 0 ] ) ) { + return false; + } + + if((this.options.revert === "invalid" && !dropped) || (this.options.revert === "valid" && dropped) || this.options.revert === true || ($.isFunction(this.options.revert) && this.options.revert.call(this.element, dropped))) { $(this.helper).animate(this.originalPosition, parseInt(this.options.revertDuration, 10), function() { - if(self._trigger("stop", event) !== false) { - self._clear(); + if(that._trigger("stop", event) !== false) { + that._clear(); } }); } else { @@ -980,78 +1221,73 @@ $.widget("ui.draggable", $.ui.mouse, { return false; }, - + _mouseUp: function(event) { - if (this.options.iframeFix === true) { - $("div.ui-draggable-iframeFix").each(function() { - this.parentNode.removeChild(this); - }); //Remove frame helpers - } - + //Remove frame helpers + $("div.ui-draggable-iframeFix").each(function() { + this.parentNode.removeChild(this); + }); + //If the ddmanager is used for droppables, inform the manager that dragging has stopped (see #5003) - if( $.ui.ddmanager ) $.ui.ddmanager.dragStop(this, event); - + if( $.ui.ddmanager ) { + $.ui.ddmanager.dragStop(this, event); + } + return $.ui.mouse.prototype._mouseUp.call(this, event); }, - + cancel: function() { - + if(this.helper.is(".ui-draggable-dragging")) { this._mouseUp({}); } else { this._clear(); } - + return this; - + }, _getHandle: function(event) { - - var handle = !this.options.handle || !$(this.options.handle, this.element).length ? true : false; - $(this.options.handle, this.element) - .find("*") - .andSelf() - .each(function() { - if(this == event.target) handle = true; - }); - - return handle; - + return this.options.handle ? + !!$( event.target ).closest( this.element.find( this.options.handle ) ).length : + true; }, _createHelper: function(event) { - var o = this.options; - var helper = $.isFunction(o.helper) ? $(o.helper.apply(this.element[0], [event])) : (o.helper == 'clone' ? this.element.clone().removeAttr('id') : this.element); + var o = this.options, + helper = $.isFunction(o.helper) ? $(o.helper.apply(this.element[0], [event])) : (o.helper === "clone" ? this.element.clone().removeAttr("id") : this.element); - if(!helper.parents('body').length) - helper.appendTo((o.appendTo == 'parent' ? this.element[0].parentNode : o.appendTo)); + if(!helper.parents("body").length) { + helper.appendTo((o.appendTo === "parent" ? this.element[0].parentNode : o.appendTo)); + } - if(helper[0] != this.element[0] && !(/(fixed|absolute)/).test(helper.css("position"))) + if(helper[0] !== this.element[0] && !(/(fixed|absolute)/).test(helper.css("position"))) { helper.css("position", "absolute"); + } return helper; }, _adjustOffsetFromHelper: function(obj) { - if (typeof obj == 'string') { - obj = obj.split(' '); + if (typeof obj === "string") { + obj = obj.split(" "); } if ($.isArray(obj)) { obj = {left: +obj[0], top: +obj[1] || 0}; } - if ('left' in obj) { + if ("left" in obj) { this.offset.click.left = obj.left + this.margins.left; } - if ('right' in obj) { + if ("right" in obj) { this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left; } - if ('top' in obj) { + if ("top" in obj) { this.offset.click.top = obj.top + this.margins.top; } - if ('bottom' in obj) { + if ("bottom" in obj) { this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top; } }, @@ -1059,21 +1295,23 @@ $.widget("ui.draggable", $.ui.mouse, { _getParentOffset: function() { //Get the offsetParent and cache its position - this.offsetParent = this.helper.offsetParent(); var po = this.offsetParent.offset(); // This is a special case where we need to modify a offset calculated on start, since the following happened: // 1. The position of the helper is absolute, so it's position is calculated based on the next positioned parent // 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't the document, which means that // the scroll is included in the initial calculation of the offset of the parent, and never recalculated upon drag - if(this.cssPosition == 'absolute' && this.scrollParent[0] != document && $.ui.contains(this.scrollParent[0], this.offsetParent[0])) { + if(this.cssPosition === "absolute" && this.scrollParent[0] !== document && $.contains(this.scrollParent[0], this.offsetParent[0])) { po.left += this.scrollParent.scrollLeft(); po.top += this.scrollParent.scrollTop(); } - if((this.offsetParent[0] == document.body) //This needs to be actually done for all browsers, since pageX/pageY includes this information - || (this.offsetParent[0].tagName && this.offsetParent[0].tagName.toLowerCase() == 'html' && $.browser.msie)) //Ugly IE fix + //This needs to be actually done for all browsers, since pageX/pageY includes this information + //Ugly IE fix + if((this.offsetParent[0] === document.body) || + (this.offsetParent[0].tagName && this.offsetParent[0].tagName.toLowerCase() === "html" && $.ui.ie)) { po = { top: 0, left: 0 }; + } return { top: po.top + (parseInt(this.offsetParent.css("borderTopWidth"),10) || 0), @@ -1084,7 +1322,7 @@ $.widget("ui.draggable", $.ui.mouse, { _getRelativeOffset: function() { - if(this.cssPosition == "relative") { + if(this.cssPosition === "relative") { var p = this.element.position(); return { top: p.top - (parseInt(this.helper.css("top"),10) || 0) + this.scrollParent.scrollTop(), @@ -1114,53 +1352,87 @@ $.widget("ui.draggable", $.ui.mouse, { _setContainment: function() { - var o = this.options; - if(o.containment == 'parent') o.containment = this.helper[0].parentNode; - if(o.containment == 'document' || o.containment == 'window') this.containment = [ - o.containment == 'document' ? 0 : $(window).scrollLeft() - this.offset.relative.left - this.offset.parent.left, - o.containment == 'document' ? 0 : $(window).scrollTop() - this.offset.relative.top - this.offset.parent.top, - (o.containment == 'document' ? 0 : $(window).scrollLeft()) + $(o.containment == 'document' ? document : window).width() - this.helperProportions.width - this.margins.left, - (o.containment == 'document' ? 0 : $(window).scrollTop()) + ($(o.containment == 'document' ? document : window).height() || document.body.parentNode.scrollHeight) - this.helperProportions.height - this.margins.top - ]; + var over, c, ce, + o = this.options; - if(!(/^(document|window|parent)$/).test(o.containment) && o.containment.constructor != Array) { - var c = $(o.containment); - var ce = c[0]; if(!ce) return; - var co = c.offset(); - var over = ($(ce).css("overflow") != 'hidden'); - - this.containment = [ - (parseInt($(ce).css("borderLeftWidth"),10) || 0) + (parseInt($(ce).css("paddingLeft"),10) || 0), - (parseInt($(ce).css("borderTopWidth"),10) || 0) + (parseInt($(ce).css("paddingTop"),10) || 0), - (over ? Math.max(ce.scrollWidth,ce.offsetWidth) : ce.offsetWidth) - (parseInt($(ce).css("borderLeftWidth"),10) || 0) - (parseInt($(ce).css("paddingRight"),10) || 0) - this.helperProportions.width - this.margins.left - this.margins.right, - (over ? Math.max(ce.scrollHeight,ce.offsetHeight) : ce.offsetHeight) - (parseInt($(ce).css("borderTopWidth"),10) || 0) - (parseInt($(ce).css("paddingBottom"),10) || 0) - this.helperProportions.height - this.margins.top - this.margins.bottom - ]; - this.relative_container = c; - - } else if(o.containment.constructor == Array) { - this.containment = o.containment; + if ( !o.containment ) { + this.containment = null; + return; } + if ( o.containment === "window" ) { + this.containment = [ + $( window ).scrollLeft() - this.offset.relative.left - this.offset.parent.left, + $( window ).scrollTop() - this.offset.relative.top - this.offset.parent.top, + $( window ).scrollLeft() + $( window ).width() - this.helperProportions.width - this.margins.left, + $( window ).scrollTop() + ( $( window ).height() || document.body.parentNode.scrollHeight ) - this.helperProportions.height - this.margins.top + ]; + return; + } + + if ( o.containment === "document") { + this.containment = [ + 0, + 0, + $( document ).width() - this.helperProportions.width - this.margins.left, + ( $( document ).height() || document.body.parentNode.scrollHeight ) - this.helperProportions.height - this.margins.top + ]; + return; + } + + if ( o.containment.constructor === Array ) { + this.containment = o.containment; + return; + } + + if ( o.containment === "parent" ) { + o.containment = this.helper[ 0 ].parentNode; + } + + c = $( o.containment ); + ce = c[ 0 ]; + + if( !ce ) { + return; + } + + over = c.css( "overflow" ) !== "hidden"; + + this.containment = [ + ( parseInt( c.css( "borderLeftWidth" ), 10 ) || 0 ) + ( parseInt( c.css( "paddingLeft" ), 10 ) || 0 ), + ( parseInt( c.css( "borderTopWidth" ), 10 ) || 0 ) + ( parseInt( c.css( "paddingTop" ), 10 ) || 0 ) , + ( over ? Math.max( ce.scrollWidth, ce.offsetWidth ) : ce.offsetWidth ) - ( parseInt( c.css( "borderRightWidth" ), 10 ) || 0 ) - ( parseInt( c.css( "paddingRight" ), 10 ) || 0 ) - this.helperProportions.width - this.margins.left - this.margins.right, + ( over ? Math.max( ce.scrollHeight, ce.offsetHeight ) : ce.offsetHeight ) - ( parseInt( c.css( "borderBottomWidth" ), 10 ) || 0 ) - ( parseInt( c.css( "paddingBottom" ), 10 ) || 0 ) - this.helperProportions.height - this.margins.top - this.margins.bottom + ]; + this.relative_container = c; }, _convertPositionTo: function(d, pos) { - if(!pos) pos = this.position; - var mod = d == "absolute" ? 1 : -1; - var o = this.options, scroll = this.cssPosition == 'absolute' && !(this.scrollParent[0] != document && $.ui.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent, scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName); + if(!pos) { + pos = this.position; + } + + var mod = d === "absolute" ? 1 : -1, + scroll = this.cssPosition === "absolute" && !( this.scrollParent[ 0 ] !== document && $.contains( this.scrollParent[ 0 ], this.offsetParent[ 0 ] ) ) ? this.offsetParent : this.scrollParent; + + //Cache the scroll + if (!this.offset.scroll) { + this.offset.scroll = {top : scroll.scrollTop(), left : scroll.scrollLeft()}; + } return { top: ( - pos.top // The absolute mouse position - + this.offset.relative.top * mod // Only for relative positioned nodes: Relative offset from element to offset parent - + this.offset.parent.top * mod // The offsetParent's offset without borders (offset + border) - - ($.browser.safari && $.browser.version < 526 && this.cssPosition == 'fixed' ? 0 : ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ) * mod) + pos.top + // The absolute mouse position + this.offset.relative.top * mod + // Only for relative positioned nodes: Relative offset from element to offset parent + this.offset.parent.top * mod - // The offsetParent's offset without borders (offset + border) + ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollTop() : this.offset.scroll.top ) * mod ) ), left: ( - pos.left // The absolute mouse position - + this.offset.relative.left * mod // Only for relative positioned nodes: Relative offset from element to offset parent - + this.offset.parent.left * mod // The offsetParent's offset without borders (offset + border) - - ($.browser.safari && $.browser.version < 526 && this.cssPosition == 'fixed' ? 0 : ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() ) * mod) + pos.left + // The absolute mouse position + this.offset.relative.left * mod + // Only for relative positioned nodes: Relative offset from element to offset parent + this.offset.parent.left * mod - // The offsetParent's offset without borders (offset + border) + ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollLeft() : this.offset.scroll.left ) * mod ) ) }; @@ -1168,60 +1440,77 @@ $.widget("ui.draggable", $.ui.mouse, { _generatePosition: function(event) { - var o = this.options, scroll = this.cssPosition == 'absolute' && !(this.scrollParent[0] != document && $.ui.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent, scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName); - var pageX = event.pageX; - var pageY = event.pageY; + var containment, co, top, left, + o = this.options, + scroll = this.cssPosition === "absolute" && !( this.scrollParent[ 0 ] !== document && $.contains( this.scrollParent[ 0 ], this.offsetParent[ 0 ] ) ) ? this.offsetParent : this.scrollParent, + pageX = event.pageX, + pageY = event.pageY; + + //Cache the scroll + if (!this.offset.scroll) { + this.offset.scroll = {top : scroll.scrollTop(), left : scroll.scrollLeft()}; + } /* * - Position constraining - * Constrain the position to a mix of grid, containment. */ - if(this.originalPosition) { //If we are not dragging yet, we won't check for options - var containment; - if(this.containment) { - if (this.relative_container){ - var co = this.relative_container.offset(); - containment = [ this.containment[0] + co.left, - this.containment[1] + co.top, - this.containment[2] + co.left, - this.containment[3] + co.top ]; - } - else { - containment = this.containment; - } + // If we are not dragging yet, we won't check for options + if ( this.originalPosition ) { + if ( this.containment ) { + if ( this.relative_container ){ + co = this.relative_container.offset(); + containment = [ + this.containment[ 0 ] + co.left, + this.containment[ 1 ] + co.top, + this.containment[ 2 ] + co.left, + this.containment[ 3 ] + co.top + ]; + } + else { + containment = this.containment; + } - if(event.pageX - this.offset.click.left < containment[0]) pageX = containment[0] + this.offset.click.left; - if(event.pageY - this.offset.click.top < containment[1]) pageY = containment[1] + this.offset.click.top; - if(event.pageX - this.offset.click.left > containment[2]) pageX = containment[2] + this.offset.click.left; - if(event.pageY - this.offset.click.top > containment[3]) pageY = containment[3] + this.offset.click.top; + if(event.pageX - this.offset.click.left < containment[0]) { + pageX = containment[0] + this.offset.click.left; + } + if(event.pageY - this.offset.click.top < containment[1]) { + pageY = containment[1] + this.offset.click.top; + } + if(event.pageX - this.offset.click.left > containment[2]) { + pageX = containment[2] + this.offset.click.left; + } + if(event.pageY - this.offset.click.top > containment[3]) { + pageY = containment[3] + this.offset.click.top; + } } if(o.grid) { //Check for grid elements set to 0 to prevent divide by 0 error causing invalid argument errors in IE (see ticket #6950) - var top = o.grid[1] ? this.originalPageY + Math.round((pageY - this.originalPageY) / o.grid[1]) * o.grid[1] : this.originalPageY; - pageY = containment ? (!(top - this.offset.click.top < containment[1] || top - this.offset.click.top > containment[3]) ? top : (!(top - this.offset.click.top < containment[1]) ? top - o.grid[1] : top + o.grid[1])) : top; + top = o.grid[1] ? this.originalPageY + Math.round((pageY - this.originalPageY) / o.grid[1]) * o.grid[1] : this.originalPageY; + pageY = containment ? ((top - this.offset.click.top >= containment[1] || top - this.offset.click.top > containment[3]) ? top : ((top - this.offset.click.top >= containment[1]) ? top - o.grid[1] : top + o.grid[1])) : top; - var left = o.grid[0] ? this.originalPageX + Math.round((pageX - this.originalPageX) / o.grid[0]) * o.grid[0] : this.originalPageX; - pageX = containment ? (!(left - this.offset.click.left < containment[0] || left - this.offset.click.left > containment[2]) ? left : (!(left - this.offset.click.left < containment[0]) ? left - o.grid[0] : left + o.grid[0])) : left; + left = o.grid[0] ? this.originalPageX + Math.round((pageX - this.originalPageX) / o.grid[0]) * o.grid[0] : this.originalPageX; + pageX = containment ? ((left - this.offset.click.left >= containment[0] || left - this.offset.click.left > containment[2]) ? left : ((left - this.offset.click.left >= containment[0]) ? left - o.grid[0] : left + o.grid[0])) : left; } } return { top: ( - pageY // The absolute mouse position - - this.offset.click.top // Click offset (relative to the element) - - this.offset.relative.top // Only for relative positioned nodes: Relative offset from element to offset parent - - this.offset.parent.top // The offsetParent's offset without borders (offset + border) - + ($.browser.safari && $.browser.version < 526 && this.cssPosition == 'fixed' ? 0 : ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) )) + pageY - // The absolute mouse position + this.offset.click.top - // Click offset (relative to the element) + this.offset.relative.top - // Only for relative positioned nodes: Relative offset from element to offset parent + this.offset.parent.top + // The offsetParent's offset without borders (offset + border) + ( this.cssPosition === "fixed" ? -this.scrollParent.scrollTop() : this.offset.scroll.top ) ), left: ( - pageX // The absolute mouse position - - this.offset.click.left // Click offset (relative to the element) - - this.offset.relative.left // Only for relative positioned nodes: Relative offset from element to offset parent - - this.offset.parent.left // The offsetParent's offset without borders (offset + border) - + ($.browser.safari && $.browser.version < 526 && this.cssPosition == 'fixed' ? 0 : ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() )) + pageX - // The absolute mouse position + this.offset.click.left - // Click offset (relative to the element) + this.offset.relative.left - // Only for relative positioned nodes: Relative offset from element to offset parent + this.offset.parent.left + // The offsetParent's offset without borders (offset + border) + ( this.cssPosition === "fixed" ? -this.scrollParent.scrollLeft() : this.offset.scroll.left ) ) }; @@ -1229,8 +1518,9 @@ $.widget("ui.draggable", $.ui.mouse, { _clear: function() { this.helper.removeClass("ui-draggable-dragging"); - if(this.helper[0] != this.element[0] && !this.cancelHelperRemoval) this.helper.remove(); - //if($.ui.ddmanager) $.ui.ddmanager.current = null; + if(this.helper[0] !== this.element[0] && !this.cancelHelperRemoval) { + this.helper.remove(); + } this.helper = null; this.cancelHelperRemoval = false; }, @@ -1240,13 +1530,16 @@ $.widget("ui.draggable", $.ui.mouse, { _trigger: function(type, event, ui) { ui = ui || this._uiHash(); $.ui.plugin.call(this, type, [event, ui]); - if(type == "drag") this.positionAbs = this._convertPositionTo("absolute"); //The absolute position has to be recalculated after plugins + //The absolute position has to be recalculated after plugins + if(type === "drag") { + this.positionAbs = this._convertPositionTo("absolute"); + } return $.Widget.prototype._trigger.call(this, type, event, ui); }, plugins: {}, - _uiHash: function(event) { + _uiHash: function() { return { helper: this.helper, position: this.position, @@ -1257,18 +1550,14 @@ $.widget("ui.draggable", $.ui.mouse, { }); -$.extend($.ui.draggable, { - version: "1.8.18" -}); - $.ui.plugin.add("draggable", "connectToSortable", { start: function(event, ui) { - var inst = $(this).data("draggable"), o = inst.options, + var inst = $(this).data("ui-draggable"), o = inst.options, uiSortable = $.extend({}, ui, { item: inst.element }); inst.sortables = []; $(o.connectToSortable).each(function() { - var sortable = $.data(this, 'sortable'); + var sortable = $.data(this, "ui-sortable"); if (sortable && !sortable.options.disabled) { inst.sortables.push({ instance: sortable, @@ -1283,7 +1572,7 @@ $.ui.plugin.add("draggable", "connectToSortable", { stop: function(event, ui) { //If we are still over the sortable, we fake the stop event of the sortable, but also remove helper - var inst = $(this).data("draggable"), + var inst = $(this).data("ui-draggable"), uiSortable = $.extend({}, ui, { item: inst.element }); $.each(inst.sortables, function() { @@ -1294,8 +1583,10 @@ $.ui.plugin.add("draggable", "connectToSortable", { inst.cancelHelperRemoval = true; //Don't remove the helper in the draggable instance this.instance.cancelHelperRemoval = false; //Remove it in the sortable instance (so sortable plugins like revert still work) - //The sortable revert is supported, and we have to set a temporary dropped variable on the draggable to support revert: 'valid/invalid' - if(this.shouldRevert) this.instance.options.revert = true; + //The sortable revert is supported, and we have to set a temporary dropped variable on the draggable to support revert: "valid/invalid" + if(this.shouldRevert) { + this.instance.options.revert = this.shouldRevert; + } //Trigger the stop of the sortable this.instance._mouseStop(event); @@ -1303,8 +1594,9 @@ $.ui.plugin.add("draggable", "connectToSortable", { this.instance.options.helper = this.instance.options._helper; //If the helper has been the original item, restore properties in the sortable - if(inst.options.helper == 'original') - this.instance.currentItem.css({ top: 'auto', left: 'auto' }); + if(inst.options.helper === "original") { + this.instance.currentItem.css({ top: "auto", left: "auto" }); + } } else { this.instance.cancelHelperRemoval = false; //Remove the helper in the sortable instance @@ -1316,26 +1608,36 @@ $.ui.plugin.add("draggable", "connectToSortable", { }, drag: function(event, ui) { - var inst = $(this).data("draggable"), self = this; + var inst = $(this).data("ui-draggable"), that = this; - var checkPos = function(o) { - var dyClick = this.offset.click.top, dxClick = this.offset.click.left; - var helperTop = this.positionAbs.top, helperLeft = this.positionAbs.left; - var itemHeight = o.height, itemWidth = o.width; - var itemTop = o.top, itemLeft = o.left; + $.each(inst.sortables, function() { - return $.ui.isOver(helperTop + dyClick, helperLeft + dxClick, itemTop, itemLeft, itemHeight, itemWidth); - }; + var innermostIntersecting = false, + thisSortable = this; - $.each(inst.sortables, function(i) { - //Copy over some variables to allow calling the sortable's native _intersectsWith this.instance.positionAbs = inst.positionAbs; this.instance.helperProportions = inst.helperProportions; this.instance.offset.click = inst.offset.click; - - if(this.instance._intersectsWith(this.instance.containerCache)) { + if(this.instance._intersectsWith(this.instance.containerCache)) { + innermostIntersecting = true; + $.each(inst.sortables, function () { + this.instance.positionAbs = inst.positionAbs; + this.instance.helperProportions = inst.helperProportions; + this.instance.offset.click = inst.offset.click; + if (this !== thisSortable && + this.instance._intersectsWith(this.instance.containerCache) && + $.contains(thisSortable.instance.element[0], this.instance.element[0]) + ) { + innermostIntersecting = false; + } + return innermostIntersecting; + }); + } + + + if(innermostIntersecting) { //If it intersects, we use a little isOver variable and set it once, so our move-in stuff gets fired only once if(!this.instance.isOver) { @@ -1343,7 +1645,7 @@ $.ui.plugin.add("draggable", "connectToSortable", { //Now we fake the start of dragging for the sortable instance, //by cloning the list group item, appending it to the sortable and using it as inst.currentItem //We can then fire the start event of the sortable with our passed browser event, and our own helper (so it doesn't create a new one) - this.instance.currentItem = $(self).clone().removeAttr('id').appendTo(this.instance.element).data("sortable-item", true); + this.instance.currentItem = $(that).clone().removeAttr("id").appendTo(this.instance.element).data("ui-sortable-item", true); this.instance.options._helper = this.instance.options.helper; //Store helper option to later restore it this.instance.options.helper = function() { return ui.helper[0]; }; @@ -1366,7 +1668,9 @@ $.ui.plugin.add("draggable", "connectToSortable", { } //Provided we did all the previous steps, we can fire the drag event of the sortable on every draggable drag, when it intersects with the sortable - if(this.instance.currentItem) this.instance._mouseDrag(event); + if(this.instance.currentItem) { + this.instance._mouseDrag(event); + } } else { @@ -1376,25 +1680,27 @@ $.ui.plugin.add("draggable", "connectToSortable", { this.instance.isOver = 0; this.instance.cancelHelperRemoval = true; - + //Prevent reverting on this forced stop this.instance.options.revert = false; - + // The out event needs to be triggered independently - this.instance._trigger('out', event, this.instance._uiHash(this.instance)); - + this.instance._trigger("out", event, this.instance._uiHash(this.instance)); + this.instance._mouseStop(event, true); this.instance.options.helper = this.instance.options._helper; //Now we remove our currentItem, the list group clone again, and the placeholder, and animate the helper back to it's original size this.instance.currentItem.remove(); - if(this.instance.placeholder) this.instance.placeholder.remove(); + if(this.instance.placeholder) { + this.instance.placeholder.remove(); + } inst._trigger("fromSortable", event); inst.dropped = false; //draggable revert needs that } - }; + } }); @@ -1402,212 +1708,255 @@ $.ui.plugin.add("draggable", "connectToSortable", { }); $.ui.plugin.add("draggable", "cursor", { - start: function(event, ui) { - var t = $('body'), o = $(this).data('draggable').options; - if (t.css("cursor")) o._cursor = t.css("cursor"); + start: function() { + var t = $("body"), o = $(this).data("ui-draggable").options; + if (t.css("cursor")) { + o._cursor = t.css("cursor"); + } t.css("cursor", o.cursor); }, - stop: function(event, ui) { - var o = $(this).data('draggable').options; - if (o._cursor) $('body').css("cursor", o._cursor); + stop: function() { + var o = $(this).data("ui-draggable").options; + if (o._cursor) { + $("body").css("cursor", o._cursor); + } } }); $.ui.plugin.add("draggable", "opacity", { start: function(event, ui) { - var t = $(ui.helper), o = $(this).data('draggable').options; - if(t.css("opacity")) o._opacity = t.css("opacity"); - t.css('opacity', o.opacity); + var t = $(ui.helper), o = $(this).data("ui-draggable").options; + if(t.css("opacity")) { + o._opacity = t.css("opacity"); + } + t.css("opacity", o.opacity); }, stop: function(event, ui) { - var o = $(this).data('draggable').options; - if(o._opacity) $(ui.helper).css('opacity', o._opacity); + var o = $(this).data("ui-draggable").options; + if(o._opacity) { + $(ui.helper).css("opacity", o._opacity); + } } }); $.ui.plugin.add("draggable", "scroll", { - start: function(event, ui) { - var i = $(this).data("draggable"); - if(i.scrollParent[0] != document && i.scrollParent[0].tagName != 'HTML') i.overflowOffset = i.scrollParent.offset(); + start: function() { + var i = $(this).data("ui-draggable"); + if(i.scrollParent[0] !== document && i.scrollParent[0].tagName !== "HTML") { + i.overflowOffset = i.scrollParent.offset(); + } }, - drag: function(event, ui) { + drag: function( event ) { - var i = $(this).data("draggable"), o = i.options, scrolled = false; + var i = $(this).data("ui-draggable"), o = i.options, scrolled = false; - if(i.scrollParent[0] != document && i.scrollParent[0].tagName != 'HTML') { + if(i.scrollParent[0] !== document && i.scrollParent[0].tagName !== "HTML") { - if(!o.axis || o.axis != 'x') { - if((i.overflowOffset.top + i.scrollParent[0].offsetHeight) - event.pageY < o.scrollSensitivity) + if(!o.axis || o.axis !== "x") { + if((i.overflowOffset.top + i.scrollParent[0].offsetHeight) - event.pageY < o.scrollSensitivity) { i.scrollParent[0].scrollTop = scrolled = i.scrollParent[0].scrollTop + o.scrollSpeed; - else if(event.pageY - i.overflowOffset.top < o.scrollSensitivity) + } else if(event.pageY - i.overflowOffset.top < o.scrollSensitivity) { i.scrollParent[0].scrollTop = scrolled = i.scrollParent[0].scrollTop - o.scrollSpeed; + } } - if(!o.axis || o.axis != 'y') { - if((i.overflowOffset.left + i.scrollParent[0].offsetWidth) - event.pageX < o.scrollSensitivity) + if(!o.axis || o.axis !== "y") { + if((i.overflowOffset.left + i.scrollParent[0].offsetWidth) - event.pageX < o.scrollSensitivity) { i.scrollParent[0].scrollLeft = scrolled = i.scrollParent[0].scrollLeft + o.scrollSpeed; - else if(event.pageX - i.overflowOffset.left < o.scrollSensitivity) + } else if(event.pageX - i.overflowOffset.left < o.scrollSensitivity) { i.scrollParent[0].scrollLeft = scrolled = i.scrollParent[0].scrollLeft - o.scrollSpeed; + } } } else { - if(!o.axis || o.axis != 'x') { - if(event.pageY - $(document).scrollTop() < o.scrollSensitivity) + if(!o.axis || o.axis !== "x") { + if(event.pageY - $(document).scrollTop() < o.scrollSensitivity) { scrolled = $(document).scrollTop($(document).scrollTop() - o.scrollSpeed); - else if($(window).height() - (event.pageY - $(document).scrollTop()) < o.scrollSensitivity) + } else if($(window).height() - (event.pageY - $(document).scrollTop()) < o.scrollSensitivity) { scrolled = $(document).scrollTop($(document).scrollTop() + o.scrollSpeed); + } } - if(!o.axis || o.axis != 'y') { - if(event.pageX - $(document).scrollLeft() < o.scrollSensitivity) + if(!o.axis || o.axis !== "y") { + if(event.pageX - $(document).scrollLeft() < o.scrollSensitivity) { scrolled = $(document).scrollLeft($(document).scrollLeft() - o.scrollSpeed); - else if($(window).width() - (event.pageX - $(document).scrollLeft()) < o.scrollSensitivity) + } else if($(window).width() - (event.pageX - $(document).scrollLeft()) < o.scrollSensitivity) { scrolled = $(document).scrollLeft($(document).scrollLeft() + o.scrollSpeed); + } } } - if(scrolled !== false && $.ui.ddmanager && !o.dropBehaviour) + if(scrolled !== false && $.ui.ddmanager && !o.dropBehaviour) { $.ui.ddmanager.prepareOffsets(i, event); + } } }); $.ui.plugin.add("draggable", "snap", { - start: function(event, ui) { + start: function() { + + var i = $(this).data("ui-draggable"), + o = i.options; - var i = $(this).data("draggable"), o = i.options; i.snapElements = []; - $(o.snap.constructor != String ? ( o.snap.items || ':data(draggable)' ) : o.snap).each(function() { - var $t = $(this); var $o = $t.offset(); - if(this != i.element[0]) i.snapElements.push({ - item: this, - width: $t.outerWidth(), height: $t.outerHeight(), - top: $o.top, left: $o.left - }); + $(o.snap.constructor !== String ? ( o.snap.items || ":data(ui-draggable)" ) : o.snap).each(function() { + var $t = $(this), + $o = $t.offset(); + if(this !== i.element[0]) { + i.snapElements.push({ + item: this, + width: $t.outerWidth(), height: $t.outerHeight(), + top: $o.top, left: $o.left + }); + } }); }, drag: function(event, ui) { - var inst = $(this).data("draggable"), o = inst.options; - var d = o.snapTolerance; - - var x1 = ui.offset.left, x2 = x1 + inst.helperProportions.width, + var ts, bs, ls, rs, l, r, t, b, i, first, + inst = $(this).data("ui-draggable"), + o = inst.options, + d = o.snapTolerance, + x1 = ui.offset.left, x2 = x1 + inst.helperProportions.width, y1 = ui.offset.top, y2 = y1 + inst.helperProportions.height; - for (var i = inst.snapElements.length - 1; i >= 0; i--){ + for (i = inst.snapElements.length - 1; i >= 0; i--){ - var l = inst.snapElements[i].left, r = l + inst.snapElements[i].width, - t = inst.snapElements[i].top, b = t + inst.snapElements[i].height; + l = inst.snapElements[i].left; + r = l + inst.snapElements[i].width; + t = inst.snapElements[i].top; + b = t + inst.snapElements[i].height; - //Yes, I know, this is insane ;) - if(!((l-d < x1 && x1 < r+d && t-d < y1 && y1 < b+d) || (l-d < x1 && x1 < r+d && t-d < y2 && y2 < b+d) || (l-d < x2 && x2 < r+d && t-d < y1 && y1 < b+d) || (l-d < x2 && x2 < r+d && t-d < y2 && y2 < b+d))) { - if(inst.snapElements[i].snapping) (inst.options.snap.release && inst.options.snap.release.call(inst.element, event, $.extend(inst._uiHash(), { snapItem: inst.snapElements[i].item }))); + if ( x2 < l - d || x1 > r + d || y2 < t - d || y1 > b + d || !$.contains( inst.snapElements[ i ].item.ownerDocument, inst.snapElements[ i ].item ) ) { + if(inst.snapElements[i].snapping) { + (inst.options.snap.release && inst.options.snap.release.call(inst.element, event, $.extend(inst._uiHash(), { snapItem: inst.snapElements[i].item }))); + } inst.snapElements[i].snapping = false; continue; } - if(o.snapMode != 'inner') { - var ts = Math.abs(t - y2) <= d; - var bs = Math.abs(b - y1) <= d; - var ls = Math.abs(l - x2) <= d; - var rs = Math.abs(r - x1) <= d; - if(ts) ui.position.top = inst._convertPositionTo("relative", { top: t - inst.helperProportions.height, left: 0 }).top - inst.margins.top; - if(bs) ui.position.top = inst._convertPositionTo("relative", { top: b, left: 0 }).top - inst.margins.top; - if(ls) ui.position.left = inst._convertPositionTo("relative", { top: 0, left: l - inst.helperProportions.width }).left - inst.margins.left; - if(rs) ui.position.left = inst._convertPositionTo("relative", { top: 0, left: r }).left - inst.margins.left; + if(o.snapMode !== "inner") { + ts = Math.abs(t - y2) <= d; + bs = Math.abs(b - y1) <= d; + ls = Math.abs(l - x2) <= d; + rs = Math.abs(r - x1) <= d; + if(ts) { + ui.position.top = inst._convertPositionTo("relative", { top: t - inst.helperProportions.height, left: 0 }).top - inst.margins.top; + } + if(bs) { + ui.position.top = inst._convertPositionTo("relative", { top: b, left: 0 }).top - inst.margins.top; + } + if(ls) { + ui.position.left = inst._convertPositionTo("relative", { top: 0, left: l - inst.helperProportions.width }).left - inst.margins.left; + } + if(rs) { + ui.position.left = inst._convertPositionTo("relative", { top: 0, left: r }).left - inst.margins.left; + } } - var first = (ts || bs || ls || rs); + first = (ts || bs || ls || rs); - if(o.snapMode != 'outer') { - var ts = Math.abs(t - y1) <= d; - var bs = Math.abs(b - y2) <= d; - var ls = Math.abs(l - x1) <= d; - var rs = Math.abs(r - x2) <= d; - if(ts) ui.position.top = inst._convertPositionTo("relative", { top: t, left: 0 }).top - inst.margins.top; - if(bs) ui.position.top = inst._convertPositionTo("relative", { top: b - inst.helperProportions.height, left: 0 }).top - inst.margins.top; - if(ls) ui.position.left = inst._convertPositionTo("relative", { top: 0, left: l }).left - inst.margins.left; - if(rs) ui.position.left = inst._convertPositionTo("relative", { top: 0, left: r - inst.helperProportions.width }).left - inst.margins.left; + if(o.snapMode !== "outer") { + ts = Math.abs(t - y1) <= d; + bs = Math.abs(b - y2) <= d; + ls = Math.abs(l - x1) <= d; + rs = Math.abs(r - x2) <= d; + if(ts) { + ui.position.top = inst._convertPositionTo("relative", { top: t, left: 0 }).top - inst.margins.top; + } + if(bs) { + ui.position.top = inst._convertPositionTo("relative", { top: b - inst.helperProportions.height, left: 0 }).top - inst.margins.top; + } + if(ls) { + ui.position.left = inst._convertPositionTo("relative", { top: 0, left: l }).left - inst.margins.left; + } + if(rs) { + ui.position.left = inst._convertPositionTo("relative", { top: 0, left: r - inst.helperProportions.width }).left - inst.margins.left; + } } - if(!inst.snapElements[i].snapping && (ts || bs || ls || rs || first)) + if(!inst.snapElements[i].snapping && (ts || bs || ls || rs || first)) { (inst.options.snap.snap && inst.options.snap.snap.call(inst.element, event, $.extend(inst._uiHash(), { snapItem: inst.snapElements[i].item }))); + } inst.snapElements[i].snapping = (ts || bs || ls || rs || first); - }; + } } }); $.ui.plugin.add("draggable", "stack", { - start: function(event, ui) { + start: function() { + var min, + o = this.data("ui-draggable").options, + group = $.makeArray($(o.stack)).sort(function(a,b) { + return (parseInt($(a).css("zIndex"),10) || 0) - (parseInt($(b).css("zIndex"),10) || 0); + }); - var o = $(this).data("draggable").options; - - var group = $.makeArray($(o.stack)).sort(function(a,b) { - return (parseInt($(a).css("zIndex"),10) || 0) - (parseInt($(b).css("zIndex"),10) || 0); - }); if (!group.length) { return; } - - var min = parseInt(group[0].style.zIndex) || 0; + + min = parseInt($(group[0]).css("zIndex"), 10) || 0; $(group).each(function(i) { - this.style.zIndex = min + i; + $(this).css("zIndex", min + i); }); - - this[0].style.zIndex = min + group.length; - + this.css("zIndex", (min + group.length)); } }); $.ui.plugin.add("draggable", "zIndex", { start: function(event, ui) { - var t = $(ui.helper), o = $(this).data("draggable").options; - if(t.css("zIndex")) o._zIndex = t.css("zIndex"); - t.css('zIndex', o.zIndex); + var t = $(ui.helper), o = $(this).data("ui-draggable").options; + if(t.css("zIndex")) { + o._zIndex = t.css("zIndex"); + } + t.css("zIndex", o.zIndex); }, stop: function(event, ui) { - var o = $(this).data("draggable").options; - if(o._zIndex) $(ui.helper).css('zIndex', o._zIndex); + var o = $(this).data("ui-draggable").options; + if(o._zIndex) { + $(ui.helper).css("zIndex", o._zIndex); + } } }); })(jQuery); -/* - * jQuery UI Droppable 1.8.18 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Droppables - * - * Depends: - * jquery.ui.core.js - * jquery.ui.widget.js - * jquery.ui.mouse.js - * jquery.ui.draggable.js - */ (function( $, undefined ) { +function isOverAxis( x, reference, size ) { + return ( x > reference ) && ( x < ( reference + size ) ); +} + $.widget("ui.droppable", { + version: "1.10.3", widgetEventPrefix: "drop", options: { - accept: '*', + accept: "*", activeClass: false, addClasses: true, greedy: false, hoverClass: false, - scope: 'default', - tolerance: 'intersect' + scope: "default", + tolerance: "intersect", + + // callbacks + activate: null, + deactivate: null, + drop: null, + out: null, + over: null }, _create: function() { - var o = this.options, accept = o.accept; - this.isover = 0; this.isout = 1; + var o = this.options, + accept = o.accept; + + this.isover = false; + this.isout = true; this.accept = $.isFunction(accept) ? accept : function(d) { return d.is(accept); @@ -1624,23 +1973,22 @@ $.widget("ui.droppable", { }, - destroy: function() { - var drop = $.ui.ddmanager.droppables[this.options.scope]; - for ( var i = 0; i < drop.length; i++ ) - if ( drop[i] == this ) + _destroy: function() { + var i = 0, + drop = $.ui.ddmanager.droppables[this.options.scope]; + + for ( ; i < drop.length; i++ ) { + if ( drop[i] === this ) { drop.splice(i, 1); + } + } - this.element - .removeClass("ui-droppable ui-droppable-disabled") - .removeData("droppable") - .unbind(".droppable"); - - return this; + this.element.removeClass("ui-droppable ui-droppable-disabled"); }, _setOption: function(key, value) { - if(key == 'accept') { + if(key === "accept") { this.accept = $.isFunction(value) ? value : function(d) { return d.is(value); }; @@ -1650,24 +1998,38 @@ $.widget("ui.droppable", { _activate: function(event) { var draggable = $.ui.ddmanager.current; - if(this.options.activeClass) this.element.addClass(this.options.activeClass); - (draggable && this._trigger('activate', event, this.ui(draggable))); + if(this.options.activeClass) { + this.element.addClass(this.options.activeClass); + } + if(draggable){ + this._trigger("activate", event, this.ui(draggable)); + } }, _deactivate: function(event) { var draggable = $.ui.ddmanager.current; - if(this.options.activeClass) this.element.removeClass(this.options.activeClass); - (draggable && this._trigger('deactivate', event, this.ui(draggable))); + if(this.options.activeClass) { + this.element.removeClass(this.options.activeClass); + } + if(draggable){ + this._trigger("deactivate", event, this.ui(draggable)); + } }, _over: function(event) { var draggable = $.ui.ddmanager.current; - if (!draggable || (draggable.currentItem || draggable.element)[0] == this.element[0]) return; // Bail if draggable and droppable are same element + + // Bail if draggable and droppable are same element + if (!draggable || (draggable.currentItem || draggable.element)[0] === this.element[0]) { + return; + } if (this.accept.call(this.element[0],(draggable.currentItem || draggable.element))) { - if(this.options.hoverClass) this.element.addClass(this.options.hoverClass); - this._trigger('over', event, this.ui(draggable)); + if(this.options.hoverClass) { + this.element.addClass(this.options.hoverClass); + } + this._trigger("over", event, this.ui(draggable)); } }, @@ -1675,37 +2037,53 @@ $.widget("ui.droppable", { _out: function(event) { var draggable = $.ui.ddmanager.current; - if (!draggable || (draggable.currentItem || draggable.element)[0] == this.element[0]) return; // Bail if draggable and droppable are same element + + // Bail if draggable and droppable are same element + if (!draggable || (draggable.currentItem || draggable.element)[0] === this.element[0]) { + return; + } if (this.accept.call(this.element[0],(draggable.currentItem || draggable.element))) { - if(this.options.hoverClass) this.element.removeClass(this.options.hoverClass); - this._trigger('out', event, this.ui(draggable)); + if(this.options.hoverClass) { + this.element.removeClass(this.options.hoverClass); + } + this._trigger("out", event, this.ui(draggable)); } }, _drop: function(event,custom) { - var draggable = custom || $.ui.ddmanager.current; - if (!draggable || (draggable.currentItem || draggable.element)[0] == this.element[0]) return false; // Bail if draggable and droppable are same element + var draggable = custom || $.ui.ddmanager.current, + childrenIntersection = false; - var childrenIntersection = false; - this.element.find(":data(droppable)").not(".ui-draggable-dragging").each(function() { - var inst = $.data(this, 'droppable'); + // Bail if draggable and droppable are same element + if (!draggable || (draggable.currentItem || draggable.element)[0] === this.element[0]) { + return false; + } + + this.element.find(":data(ui-droppable)").not(".ui-draggable-dragging").each(function() { + var inst = $.data(this, "ui-droppable"); if( - inst.options.greedy - && !inst.options.disabled - && inst.options.scope == draggable.options.scope - && inst.accept.call(inst.element[0], (draggable.currentItem || draggable.element)) - && $.ui.intersect(draggable, $.extend(inst, { offset: inst.element.offset() }), inst.options.tolerance) + inst.options.greedy && + !inst.options.disabled && + inst.options.scope === draggable.options.scope && + inst.accept.call(inst.element[0], (draggable.currentItem || draggable.element)) && + $.ui.intersect(draggable, $.extend(inst, { offset: inst.element.offset() }), inst.options.tolerance) ) { childrenIntersection = true; return false; } }); - if(childrenIntersection) return false; + if(childrenIntersection) { + return false; + } if(this.accept.call(this.element[0],(draggable.currentItem || draggable.element))) { - if(this.options.activeClass) this.element.removeClass(this.options.activeClass); - if(this.options.hoverClass) this.element.removeClass(this.options.hoverClass); - this._trigger('drop', event, this.ui(draggable)); + if(this.options.activeClass) { + this.element.removeClass(this.options.activeClass); + } + if(this.options.hoverClass) { + this.element.removeClass(this.options.hoverClass); + } + this._trigger("drop", event, this.ui(draggable)); return this.element; } @@ -1724,50 +2102,42 @@ $.widget("ui.droppable", { }); -$.extend($.ui.droppable, { - version: "1.8.18" -}); - $.ui.intersect = function(draggable, droppable, toleranceMode) { - if (!droppable.offset) return false; + if (!droppable.offset) { + return false; + } - var x1 = (draggable.positionAbs || draggable.position.absolute).left, x2 = x1 + draggable.helperProportions.width, - y1 = (draggable.positionAbs || draggable.position.absolute).top, y2 = y1 + draggable.helperProportions.height; - var l = droppable.offset.left, r = l + droppable.proportions.width, + var draggableLeft, draggableTop, + x1 = (draggable.positionAbs || draggable.position.absolute).left, x2 = x1 + draggable.helperProportions.width, + y1 = (draggable.positionAbs || draggable.position.absolute).top, y2 = y1 + draggable.helperProportions.height, + l = droppable.offset.left, r = l + droppable.proportions.width, t = droppable.offset.top, b = t + droppable.proportions.height; switch (toleranceMode) { - case 'fit': - return (l <= x1 && x2 <= r - && t <= y1 && y2 <= b); - break; - case 'intersect': - return (l < x1 + (draggable.helperProportions.width / 2) // Right Half - && x2 - (draggable.helperProportions.width / 2) < r // Left Half - && t < y1 + (draggable.helperProportions.height / 2) // Bottom Half - && y2 - (draggable.helperProportions.height / 2) < b ); // Top Half - break; - case 'pointer': - var draggableLeft = ((draggable.positionAbs || draggable.position.absolute).left + (draggable.clickOffset || draggable.offset.click).left), - draggableTop = ((draggable.positionAbs || draggable.position.absolute).top + (draggable.clickOffset || draggable.offset.click).top), - isOver = $.ui.isOver(draggableTop, draggableLeft, t, l, droppable.proportions.height, droppable.proportions.width); - return isOver; - break; - case 'touch': + case "fit": + return (l <= x1 && x2 <= r && t <= y1 && y2 <= b); + case "intersect": + return (l < x1 + (draggable.helperProportions.width / 2) && // Right Half + x2 - (draggable.helperProportions.width / 2) < r && // Left Half + t < y1 + (draggable.helperProportions.height / 2) && // Bottom Half + y2 - (draggable.helperProportions.height / 2) < b ); // Top Half + case "pointer": + draggableLeft = ((draggable.positionAbs || draggable.position.absolute).left + (draggable.clickOffset || draggable.offset.click).left); + draggableTop = ((draggable.positionAbs || draggable.position.absolute).top + (draggable.clickOffset || draggable.offset.click).top); + return isOverAxis( draggableTop, t, droppable.proportions.height ) && isOverAxis( draggableLeft, l, droppable.proportions.width ); + case "touch": return ( - (y1 >= t && y1 <= b) || // Top edge touching - (y2 >= t && y2 <= b) || // Bottom edge touching - (y1 < t && y2 > b) // Surrounded vertically - ) && ( - (x1 >= l && x1 <= r) || // Left edge touching - (x2 >= l && x2 <= r) || // Right edge touching - (x1 < l && x2 > r) // Surrounded horizontally - ); - break; + (y1 >= t && y1 <= b) || // Top edge touching + (y2 >= t && y2 <= b) || // Bottom edge touching + (y1 < t && y2 > b) // Surrounded vertically + ) && ( + (x1 >= l && x1 <= r) || // Left edge touching + (x2 >= l && x2 <= r) || // Right edge touching + (x1 < l && x2 > r) // Surrounded horizontally + ); default: return false; - break; } }; @@ -1777,20 +2147,38 @@ $.ui.intersect = function(draggable, droppable, toleranceMode) { */ $.ui.ddmanager = { current: null, - droppables: { 'default': [] }, + droppables: { "default": [] }, prepareOffsets: function(t, event) { - var m = $.ui.ddmanager.droppables[t.options.scope] || []; - var type = event ? event.type : null; // workaround for #2317 - var list = (t.currentItem || t.element).find(":data(droppable)").andSelf(); + var i, j, + m = $.ui.ddmanager.droppables[t.options.scope] || [], + type = event ? event.type : null, // workaround for #2317 + list = (t.currentItem || t.element).find(":data(ui-droppable)").addBack(); - droppablesLoop: for (var i = 0; i < m.length; i++) { + droppablesLoop: for (i = 0; i < m.length; i++) { - if(m[i].options.disabled || (t && !m[i].accept.call(m[i].element[0],(t.currentItem || t.element)))) continue; //No disabled and non-accepted - for (var j=0; j < list.length; j++) { if(list[j] == m[i].element[0]) { m[i].proportions.height = 0; continue droppablesLoop; } }; //Filter out elements in the current dragged item - m[i].visible = m[i].element.css("display") != "none"; if(!m[i].visible) continue; //If the element is not visible, continue + //No disabled and non-accepted + if(m[i].options.disabled || (t && !m[i].accept.call(m[i].element[0],(t.currentItem || t.element)))) { + continue; + } - if(type == "mousedown") m[i]._activate.call(m[i], event); //Activate the droppable if used directly from draggables + // Filter out elements in the current dragged item + for (j=0; j < list.length; j++) { + if(list[j] === m[i].element[0]) { + m[i].proportions.height = 0; + continue droppablesLoop; + } + } + + m[i].visible = m[i].element.css("display") !== "none"; + if(!m[i].visible) { + continue; + } + + //Activate the droppable if used directly from draggables + if(type === "mousedown") { + m[i]._activate.call(m[i], event); + } m[i].offset = m[i].element.offset(); m[i].proportions = { width: m[i].element[0].offsetWidth, height: m[i].element[0].offsetHeight }; @@ -1801,14 +2189,19 @@ $.ui.ddmanager = { drop: function(draggable, event) { var dropped = false; - $.each($.ui.ddmanager.droppables[draggable.options.scope] || [], function() { + // Create a copy of the droppables in case the list changes during the drop (#9116) + $.each(($.ui.ddmanager.droppables[draggable.options.scope] || []).slice(), function() { - if(!this.options) return; - if (!this.options.disabled && this.visible && $.ui.intersect(draggable, this, this.options.tolerance)) + if(!this.options) { + return; + } + if (!this.options.disabled && this.visible && $.ui.intersect(draggable, this, this.options.tolerance)) { dropped = this._drop.call(this, event) || dropped; + } if (!this.options.disabled && this.visible && this.accept.call(this.element[0],(draggable.currentItem || draggable.element))) { - this.isout = 1; this.isover = 0; + this.isout = true; + this.isover = false; this._deactivate.call(this, event); } @@ -1818,56 +2211,72 @@ $.ui.ddmanager = { }, dragStart: function( draggable, event ) { //Listen for scrolling so that if the dragging causes scrolling the position of the droppables can be recalculated (see #5003) - draggable.element.parents( ":not(body,html)" ).bind( "scroll.droppable", function() { - if( !draggable.options.refreshPositions ) $.ui.ddmanager.prepareOffsets( draggable, event ); + draggable.element.parentsUntil( "body" ).bind( "scroll.droppable", function() { + if( !draggable.options.refreshPositions ) { + $.ui.ddmanager.prepareOffsets( draggable, event ); + } }); }, drag: function(draggable, event) { //If you have a highly dynamic page, you might try this option. It renders positions every time you move the mouse. - if(draggable.options.refreshPositions) $.ui.ddmanager.prepareOffsets(draggable, event); + if(draggable.options.refreshPositions) { + $.ui.ddmanager.prepareOffsets(draggable, event); + } //Run through all droppables and check their positions based on specific tolerance options $.each($.ui.ddmanager.droppables[draggable.options.scope] || [], function() { - if(this.options.disabled || this.greedyChild || !this.visible) return; - var intersects = $.ui.intersect(draggable, this, this.options.tolerance); + if(this.options.disabled || this.greedyChild || !this.visible) { + return; + } - var c = !intersects && this.isover == 1 ? 'isout' : (intersects && this.isover == 0 ? 'isover' : null); - if(!c) return; + var parentInstance, scope, parent, + intersects = $.ui.intersect(draggable, this, this.options.tolerance), + c = !intersects && this.isover ? "isout" : (intersects && !this.isover ? "isover" : null); + if(!c) { + return; + } - var parentInstance; if (this.options.greedy) { - var parent = this.element.parents(':data(droppable):eq(0)'); + // find droppable parents with same scope + scope = this.options.scope; + parent = this.element.parents(":data(ui-droppable)").filter(function () { + return $.data(this, "ui-droppable").options.scope === scope; + }); + if (parent.length) { - parentInstance = $.data(parent[0], 'droppable'); - parentInstance.greedyChild = (c == 'isover' ? 1 : 0); + parentInstance = $.data(parent[0], "ui-droppable"); + parentInstance.greedyChild = (c === "isover"); } } // we just moved into a greedy child - if (parentInstance && c == 'isover') { - parentInstance['isover'] = 0; - parentInstance['isout'] = 1; + if (parentInstance && c === "isover") { + parentInstance.isover = false; + parentInstance.isout = true; parentInstance._out.call(parentInstance, event); } - this[c] = 1; this[c == 'isout' ? 'isover' : 'isout'] = 0; - this[c == "isover" ? "_over" : "_out"].call(this, event); + this[c] = true; + this[c === "isout" ? "isover" : "isout"] = false; + this[c === "isover" ? "_over" : "_out"].call(this, event); // we just moved out of a greedy child - if (parentInstance && c == 'isout') { - parentInstance['isout'] = 0; - parentInstance['isover'] = 1; + if (parentInstance && c === "isout") { + parentInstance.isout = false; + parentInstance.isover = true; parentInstance._over.call(parentInstance, event); } }); }, dragStop: function( draggable, event ) { - draggable.element.parents( ":not(body,html)" ).unbind( "scroll.droppable" ); + draggable.element.parentsUntil( "body" ).unbind( "scroll.droppable" ); //Call prepareOffsets one final time since IE does not fire return scroll events when overflow was caused by drag (see #5003) - if( !draggable.options.refreshPositions ) $.ui.ddmanager.prepareOffsets( draggable, event ); + if( !draggable.options.refreshPositions ) { + $.ui.ddmanager.prepareOffsets( draggable, event ); + } } }; diff --git a/Version b/Version index 67a949875..56f4d1e6b 100644 --- a/Version +++ b/Version @@ -4,4 +4,4 @@ MAJOR_VERSION=2 MINOR_VERSION=0 -SUBMINOR_VERSION=6b +SUBMINOR_VERSION=7