diff --git a/src/Orchard.Core.Tests/Common/Providers/CommonPartProviderTests.cs b/src/Orchard.Core.Tests/Common/Providers/CommonPartProviderTests.cs index fde903ad3..27bf95f78 100644 --- a/src/Orchard.Core.Tests/Common/Providers/CommonPartProviderTests.cs +++ b/src/Orchard.Core.Tests/Common/Providers/CommonPartProviderTests.cs @@ -14,6 +14,7 @@ using Orchard.ContentManagement; using Orchard.ContentManagement.Handlers; using Orchard.ContentManagement.Records; using Orchard.Core.Common.Services; +using Orchard.Core.PublishLater.Services; using Orchard.Core.Scheduling.Models; using Orchard.Core.Scheduling.Services; using Orchard.Localization; diff --git a/src/Orchard.Web/Config/Diagnostics.config b/src/Orchard.Web/Config/Diagnostics.config index ee34eaabf..e7dc6dbf9 100644 --- a/src/Orchard.Web/Config/Diagnostics.config +++ b/src/Orchard.Web/Config/Diagnostics.config @@ -1,7 +1,7 @@  - + @@ -13,7 +13,7 @@ - + diff --git a/src/Orchard.Web/Core/Orchard.Core.csproj b/src/Orchard.Web/Core/Orchard.Core.csproj index 14afb5fc1..ad30d94b0 100644 --- a/src/Orchard.Web/Core/Orchard.Core.csproj +++ b/src/Orchard.Web/Core/Orchard.Core.csproj @@ -188,8 +188,8 @@ - - + + diff --git a/src/Orchard.Web/Core/Scheduling/Services/PublishingTaskHandler.cs b/src/Orchard.Web/Core/PublishLater/Handlers/PublishingTaskHandler.cs similarity index 66% rename from src/Orchard.Web/Core/Scheduling/Services/PublishingTaskHandler.cs rename to src/Orchard.Web/Core/PublishLater/Handlers/PublishingTaskHandler.cs index 2c870d405..cf058a998 100644 --- a/src/Orchard.Web/Core/Scheduling/Services/PublishingTaskHandler.cs +++ b/src/Orchard.Web/Core/PublishLater/Handlers/PublishingTaskHandler.cs @@ -3,7 +3,7 @@ using Orchard.ContentManagement; using Orchard.Logging; using Orchard.Tasks.Scheduling; -namespace Orchard.Core.Scheduling.Services { +namespace Orchard.Core.PublishLater.Handlers { [UsedImplicitly] public class PublishingTaskHandler : IScheduledTaskHandler { private readonly IContentManager _contentManager; @@ -24,14 +24,6 @@ namespace Orchard.Core.Scheduling.Services { _contentManager.Publish(context.Task.ContentItem); } - else if (context.Task.TaskType == "Unpublish") { - Logger.Information("Unpublishing item #{0} version {1} scheduled at {2} utc", - context.Task.ContentItem.Id, - context.Task.ContentItem.Version, - context.Task.ScheduledUtc); - - _contentManager.Unpublish(context.Task.ContentItem); - } } } } diff --git a/src/Orchard.Web/Core/Scheduling/Services/PublishingTaskManager.cs b/src/Orchard.Web/Core/PublishLater/Services/PublishingTaskManager.cs similarity index 83% rename from src/Orchard.Web/Core/Scheduling/Services/PublishingTaskManager.cs rename to src/Orchard.Web/Core/PublishLater/Services/PublishingTaskManager.cs index 240415103..f99aaab1f 100644 --- a/src/Orchard.Web/Core/Scheduling/Services/PublishingTaskManager.cs +++ b/src/Orchard.Web/Core/PublishLater/Services/PublishingTaskManager.cs @@ -4,11 +4,10 @@ using JetBrains.Annotations; using Orchard.ContentManagement; using Orchard.Tasks.Scheduling; -namespace Orchard.Core.Scheduling.Services { +namespace Orchard.Core.PublishLater.Services { [UsedImplicitly] public class PublishingTaskManager : IPublishingTaskManager { private const string PublishTaskType = "Publish"; - private const string UnpublishTaskType = "Unpublish"; private readonly IScheduledTaskManager _scheduledTaskManager; @@ -29,7 +28,7 @@ namespace Orchard.Core.Scheduling.Services { } public void DeleteTasks(ContentItem item) { - _scheduledTaskManager.DeleteTasks(item, task => task.TaskType == PublishTaskType || task.TaskType == UnpublishTaskType); + _scheduledTaskManager.DeleteTasks(item, task => task.TaskType == PublishTaskType); } } } \ No newline at end of file diff --git a/src/Orchard.Web/Core/Scheduling/Services/ScheduledTaskManager.cs b/src/Orchard.Web/Core/Scheduling/Services/ScheduledTaskManager.cs index 19c73dce7..7d818c282 100644 --- a/src/Orchard.Web/Core/Scheduling/Services/ScheduledTaskManager.cs +++ b/src/Orchard.Web/Core/Scheduling/Services/ScheduledTaskManager.cs @@ -44,16 +44,28 @@ namespace Orchard.Core.Scheduling.Services { .ToReadOnlyCollection(); } - public void DeleteTasks(ContentItem contentItem, Func predicate) { - //TEMP: Is this thread safe? Does it matter? + public IEnumerable GetTasks(string taskType, DateTime? scheduledBeforeUtc = null) { + var query = scheduledBeforeUtc == null + ? _repository.Fetch(t => t.TaskType == taskType && t.ScheduledUtc <= scheduledBeforeUtc) + : _repository.Fetch(t => t.TaskType == taskType); + + return + query.Select(x => new Task(_contentManager, x)) + .Cast() + .ToReadOnlyCollection(); + } + + public void DeleteTasks(ContentItem contentItem, Func predicate = null ) { var tasks = _repository .Fetch(x => x.ContentItemVersionRecord.ContentItemRecord == contentItem.Record); foreach (var task in tasks) { - if (predicate(new Task(_contentManager, task))) { + if (predicate == null || predicate(new Task(_contentManager, task))) { _repository.Delete(task); } } + + _repository.Flush(); } } } diff --git a/src/Orchard.Web/Modules/ArchiveLater/Content/Admin/images/scheduled.gif b/src/Orchard.Web/Modules/ArchiveLater/Content/Admin/images/scheduled.gif new file mode 100644 index 000000000..827afcade Binary files /dev/null and b/src/Orchard.Web/Modules/ArchiveLater/Content/Admin/images/scheduled.gif differ diff --git a/src/Orchard.Web/Modules/ArchiveLater/DataMigrations/ArchiveLaterDataMigration.cs b/src/Orchard.Web/Modules/ArchiveLater/DataMigrations/ArchiveLaterDataMigration.cs new file mode 100644 index 000000000..ff010f8b1 --- /dev/null +++ b/src/Orchard.Web/Modules/ArchiveLater/DataMigrations/ArchiveLaterDataMigration.cs @@ -0,0 +1,25 @@ +using System.Collections.Generic; +using ArchiveLater.Models; +using Orchard.ContentManagement.Drivers; +using Orchard.ContentManagement.MetaData; +using Orchard.ContentManagement.MetaData.Builders; +using Orchard.Core.Contents.Extensions; +using Orchard.Data.Migration; + +namespace ArchiveLater.DataMigrations { + public class ArchiveLaterDataMigration : DataMigrationImpl { + public int Create() { + ContentDefinitionManager.AlterPartDefinition(typeof(ArchiveLaterPart).Name, cfg => cfg + .WithLocation(new Dictionary { + {"Default", new ContentLocation { Zone = "metadata", Position = "2" }}, + {"Editor", new ContentLocation { Zone = "secondary", Position = "2" }} + })); + return 1; + } + + public int UpdateFrom1() { + ContentDefinitionManager.AlterPartDefinition("ArchiveLaterPart", builder => builder.Attachable()); + return 2; + } + } +} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/ArchiveLater/Drivers/ArchiveLaterPartDriver.cs b/src/Orchard.Web/Modules/ArchiveLater/Drivers/ArchiveLaterPartDriver.cs new file mode 100644 index 000000000..b018df3c8 --- /dev/null +++ b/src/Orchard.Web/Modules/ArchiveLater/Drivers/ArchiveLaterPartDriver.cs @@ -0,0 +1,65 @@ +using System; +using ArchiveLater.Models; +using ArchiveLater.Services; +using ArchiveLater.ViewModels; +using Orchard; +using Orchard.ContentManagement; +using Orchard.ContentManagement.Drivers; +using Orchard.Core.Common.Services; +using Orchard.Core.ContentsLocation.Models; +using Orchard.Localization; + +namespace ArchiveLater.Drivers { + public class ArchiveLaterPartDriver : ContentPartDriver { + private const string TemplatePrefix = "ArchiveLater"; + private readonly ICommonService _commonService; + private readonly IArchiveLaterService _archiveLaterService; + + public ArchiveLaterPartDriver( + IOrchardServices services, + ICommonService commonService, + IArchiveLaterService archiveLaterService) { + _commonService = commonService; + _archiveLaterService = archiveLaterService; + T = NullLocalizer.Instance; + Services = services; + } + + public Localizer T { get; set; } + public IOrchardServices Services { get; set; } + + protected override DriverResult Display(ArchiveLaterPart part, string displayType) { + var model = new ArchiveLaterViewModel(part) { + ScheduledArchiveUtc = part.ScheduledArchiveUtc.Value + }; + return ContentPartTemplate(model, "Parts/ArchiveLater.Metadata").LongestMatch(displayType, "Summary", "SummaryAdmin").Location(part.GetLocation(displayType)); + } + + protected override DriverResult Editor(ArchiveLaterPart part) { + return ArchiveEditor(part, null); + } + + protected override DriverResult Editor(ArchiveLaterPart instance, IUpdateModel updater) { + return ArchiveEditor(instance, updater); + } + + DriverResult ArchiveEditor(ArchiveLaterPart part, IUpdateModel updater) { + var model = new ArchiveLaterViewModel(part); + + if ( updater != null && updater.TryUpdateModel(model, TemplatePrefix, null, null) ) { + if (model.ArchiveLater) { + DateTime scheduled; + if (DateTime.TryParse(string.Format("{0} {1}", model.ScheduledArchiveDate, model.ScheduledArchiveTime), out scheduled)) + model.ScheduledArchiveUtc = scheduled.ToUniversalTime(); + _archiveLaterService.ArchiveLater(model.ContentItem, model.ScheduledArchiveUtc.HasValue ? model.ScheduledArchiveUtc.Value : DateTime.MaxValue); + //Services.Notifier.Information(T("{0} has been scheduled for publishing!", model.ContentItem.TypeDefinition.DisplayName)); + } + else { + //_archiveLaterService.RemoveArchiveLaterTasks(model.ContentItem); + } + } + + return ContentPartTemplate(model, "Parts/ArchiveLater", TemplatePrefix).Location(part.GetLocation("Editor")); + } + } +} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/ArchiveLater/Handlers/ArchiveLaterPartHandler.cs b/src/Orchard.Web/Modules/ArchiveLater/Handlers/ArchiveLaterPartHandler.cs new file mode 100644 index 000000000..ceef9424c --- /dev/null +++ b/src/Orchard.Web/Modules/ArchiveLater/Handlers/ArchiveLaterPartHandler.cs @@ -0,0 +1,16 @@ +using ArchiveLater.Models; +using ArchiveLater.Services; +using Orchard.ContentManagement; +using Orchard.ContentManagement.Handlers; + +namespace ArchiveLater.Handlers { + public class ArchiveLaterPartHandler : ContentHandler { + private readonly IArchiveLaterService _archiveLaterService; + + public ArchiveLaterPartHandler(IArchiveLaterService archiveLaterService) { + _archiveLaterService = archiveLaterService; + + OnLoaded((context, archiveLater) => archiveLater.ScheduledArchiveUtc.Loader(delegate { return _archiveLaterService.GetScheduledArchiveUtc(archiveLater.As()); })); + } + } +} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/ArchiveLater/Handlers/UnpublishingTaskHandler.cs b/src/Orchard.Web/Modules/ArchiveLater/Handlers/UnpublishingTaskHandler.cs new file mode 100644 index 000000000..b1ef43db2 --- /dev/null +++ b/src/Orchard.Web/Modules/ArchiveLater/Handlers/UnpublishingTaskHandler.cs @@ -0,0 +1,29 @@ +using JetBrains.Annotations; +using Orchard.ContentManagement; +using Orchard.Logging; +using Orchard.Tasks.Scheduling; + +namespace ArchiveLater.Handlers { + [UsedImplicitly] + public class UnpublishingTaskHandler : IScheduledTaskHandler { + private readonly IContentManager _contentManager; + + public UnpublishingTaskHandler(IContentManager contentManager) { + _contentManager = contentManager; + Logger = NullLogger.Instance; + } + + public ILogger Logger { get; set; } + + public void Process(ScheduledTaskContext context) { + if (context.Task.TaskType == "Unpublish") { + Logger.Information("Unpublishing item #{0} version {1} scheduled at {2} utc", + context.Task.ContentItem.Id, + context.Task.ContentItem.Version, + context.Task.ScheduledUtc); + + _contentManager.Unpublish(context.Task.ContentItem); + } + } + } +} diff --git a/src/Orchard.Web/Modules/ArchiveLater/Models/ArchiveLaterPart.cs b/src/Orchard.Web/Modules/ArchiveLater/Models/ArchiveLaterPart.cs new file mode 100644 index 000000000..504d5e221 --- /dev/null +++ b/src/Orchard.Web/Modules/ArchiveLater/Models/ArchiveLaterPart.cs @@ -0,0 +1,10 @@ +using System; +using Orchard.ContentManagement; +using Orchard.ContentManagement.Utilities; + +namespace ArchiveLater.Models { + public class ArchiveLaterPart : ContentPart { + private readonly LazyField _scheduledArchiveUtc = new LazyField(); + public LazyField ScheduledArchiveUtc { get { return _scheduledArchiveUtc; } } + } +} diff --git a/src/Orchard.Web/Modules/ArchiveLater/Module.txt b/src/Orchard.Web/Modules/ArchiveLater/Module.txt new file mode 100644 index 000000000..b1082453e --- /dev/null +++ b/src/Orchard.Web/Modules/ArchiveLater/Module.txt @@ -0,0 +1,12 @@ +Name: ArchiveLater +antiforgery: enabled +author: The Orchard Team +website: http://orchardproject.net +version: 0.1.0 +orchardversion: 0.6.0 +description: The ArhiveLater module introduces scheduled archiving functionality. +features: + Orchard.ArchiveLater: + Description: Scheduled archiving. + Category: Content + Dependencies: Common, Settings diff --git a/src/Orchard.Web/Modules/ArchiveLater/Orchard.ArchiveLater.csproj b/src/Orchard.Web/Modules/ArchiveLater/Orchard.ArchiveLater.csproj new file mode 100644 index 000000000..a1547fe49 --- /dev/null +++ b/src/Orchard.Web/Modules/ArchiveLater/Orchard.ArchiveLater.csproj @@ -0,0 +1,148 @@ + + + + Debug + AnyCPU + + + 2.0 + {1C981BB3-26F7-494C-9005-CC27A5144233} + {F85E285D-A4E0-4152-9332-AB1D724D3325};{349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc} + Library + Properties + Orchard.ArchiveLater + Orchard.ArchiveLater + v4.0 + false + + + true + full + false + bin\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\ + TRACE + prompt + 4 + + + + + + + + + + + 3.5 + + + 3.5 + + + 3.5 + + + + 3.5 + + + + 3.5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {9916839C-39FC-4CEB-A5AF-89CA7E87119F} + Orchard.Core + + + {2D1D92BB-4555-4CBE-8D0E-63563D6CE4C6} + Orchard.Framework + + + + + + + + + + + + + False + True + 11877 + / + + + False + False + + + False + + + + + \ No newline at end of file diff --git a/src/Orchard.Web/Modules/ArchiveLater/Properties/AssemblyInfo.cs b/src/Orchard.Web/Modules/ArchiveLater/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..d4faa60a7 --- /dev/null +++ b/src/Orchard.Web/Modules/ArchiveLater/Properties/AssemblyInfo.cs @@ -0,0 +1,35 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("PublishLater")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("Microsoft")] +[assembly: AssemblyProduct("PublishLater")] +[assembly: AssemblyCopyright("Copyright © Microsoft 2010")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("41dff4d9-c77b-447f-a557-ca4289b6f50b")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Revision and Build Numbers +// by using the '*' as shown below: +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/src/Orchard.Web/Modules/ArchiveLater/Scripts/jquery.ui.core.js b/src/Orchard.Web/Modules/ArchiveLater/Scripts/jquery.ui.core.js new file mode 100644 index 000000000..e6e4fb3cc --- /dev/null +++ b/src/Orchard.Web/Modules/ArchiveLater/Scripts/jquery.ui.core.js @@ -0,0 +1,226 @@ +/*! + * jQuery UI 1.8b1 + * + * Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + * http://docs.jquery.com/UI + */ +;jQuery.ui || (function($) { + +var isFF2 = $.browser.mozilla && (parseFloat($.browser.version) < 1.9); + +//Helper functions and ui object +$.ui = { + version: "1.8b1", + + // $.ui.plugin is deprecated. Use the proxy pattern instead. + plugin: { + add: function(module, option, set) { + var proto = $.ui[module].prototype; + for(var 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) { return; } + + for (var i = 0; i < set.length; i++) { + if (instance.options[set[i][0]]) { + set[i][1].apply(instance.element, args); + } + } + } + }, + + contains: function(a, b) { + return document.compareDocumentPosition + ? a.compareDocumentPosition(b) & 16 + : a !== b && a.contains(b); + }, + + 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 + el[scroll] = 1; + has = (el[scroll] > 0); + el[scroll] = 0; + return has; + }, + + 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); + }, + + keyCode: { + BACKSPACE: 8, + CAPS_LOCK: 20, + COMMA: 188, + CONTROL: 17, + DELETE: 46, + DOWN: 40, + END: 35, + ENTER: 13, + ESCAPE: 27, + HOME: 36, + INSERT: 45, + LEFT: 37, + NUMPAD_ADD: 107, + NUMPAD_DECIMAL: 110, + NUMPAD_DIVIDE: 111, + NUMPAD_ENTER: 108, + NUMPAD_MULTIPLY: 106, + NUMPAD_SUBTRACT: 109, + PAGE_DOWN: 34, + PAGE_UP: 33, + PERIOD: 190, + RIGHT: 39, + SHIFT: 16, + SPACE: 32, + TAB: 9, + UP: 38 + } +}; + +// WAI-ARIA normalization +if (isFF2) { + var attr = $.attr, + removeAttr = $.fn.removeAttr, + ariaNS = "http://www.w3.org/2005/07/aaa", + ariaState = /^aria-/, + ariaRole = /^wairole:/; + + $.attr = function(elem, name, value) { + var set = value !== undefined; + + return (name == 'role' + ? (set + ? attr.call(this, elem, name, "wairole:" + value) + : (attr.apply(this, arguments) || "").replace(ariaRole, "")) + : (ariaState.test(name) + ? (set + ? elem.setAttributeNS(ariaNS, + name.replace(ariaState, "aaa:"), value) + : attr.call(this, elem, name.replace(ariaState, "aaa:"))) + : attr.apply(this, arguments))); + }; + + $.fn.removeAttr = function(name) { + return (ariaState.test(name) + ? this.each(function() { + this.removeAttributeNS(ariaNS, name.replace(ariaState, "")); + }) : removeAttr.call(this, name)); + }; +} + +//jQuery plugins +$.fn.extend({ + _focus: $.fn.focus, + focus: function(delay, fn) { + return typeof delay === 'number' + ? this.each(function() { + var elem = this; + setTimeout(function() { + $(elem).focus(); + (fn && fn.call(elem)); + }, delay); + }) + : this._focus.apply(this, arguments); + }, + + enableSelection: function() { + return this + .attr('unselectable', 'off') + .css('MozUserSelect', '') + .unbind('selectstart.ui'); + }, + + disableSelection: function() { + return this + .attr('unselectable', 'on') + .css('MozUserSelect', 'none') + .bind('selectstart.ui', function() { return false; }); + }, + + scrollParent: function() { + var scrollParent; + if(($.browser.msie && (/(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)); + }).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)); + }).eq(0); + } + + return (/fixed/).test(this.css('position')) || !scrollParent.length ? $(document) : scrollParent; + }, + + zIndex: function(zIndex) { + if (zIndex !== undefined) { + return this.css('zIndex', zIndex); + } + + var elem = this[0]; + while (elem && elem.style) { + // IE returns 0 when zIndex is not specified + // other browsers return an empty string + // we ignore the case of nested elements with an explicit value of 0 + //
+ if (elem.style.zIndex !== '' && elem.style.zIndex !== 0) { + return +elem.style.zIndex; + } + elem = elem.parentNode; + } + + return 0; + } +}); + + +//Additional selectors +$.extend($.expr[':'], { + data: function(elem, i, match) { + return !!$.data(elem, match[3]); + }, + + focusable: function(element) { + var nodeName = element.nodeName.toLowerCase(), + tabIndex = $.attr(element, 'tabindex'); + return (/input|select|textarea|button|object/.test(nodeName) + ? !element.disabled + : 'a' == nodeName || 'area' == nodeName + ? element.href || !isNaN(tabIndex) + : !isNaN(tabIndex)) + // the element and all of its ancestors must be visible + // the browser may report that the area is hidden + && !$(element)['area' == nodeName ? 'parents' : 'closest'](':hidden').length; + }, + + tabbable: function(element) { + var tabIndex = $.attr(element, 'tabindex'); + return (isNaN(tabIndex) || tabIndex >= 0) && $(element).is(':focusable'); + } +}); + +})(jQuery); diff --git a/src/Orchard.Web/Modules/ArchiveLater/Scripts/jquery.ui.datepicker.js b/src/Orchard.Web/Modules/ArchiveLater/Scripts/jquery.ui.datepicker.js new file mode 100644 index 000000000..092cdebf3 --- /dev/null +++ b/src/Orchard.Web/Modules/ArchiveLater/Scripts/jquery.ui.datepicker.js @@ -0,0 +1,1721 @@ +/* + * jQuery UI Datepicker 1.8b1 + * + * Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + * http://docs.jquery.com/UI/Datepicker + * + * Depends: + * jquery.ui.core.js + * jquery.ui.widget.js + */ + +(function($) { // hide the namespace + +$.extend($.ui, { datepicker: { version: "1.8b1" } }); + +var PROP_NAME = 'datepicker'; +var dpuuid = new Date().getTime(); + +/* Date picker manager. + Use the singleton instance of this class, $.datepicker, to interact with the date picker. + Settings for (groups of) date pickers are maintained in an instance object, + allowing multiple different settings on the same page. */ + +function Datepicker() { + this.debug = false; // Change this to true to start debugging + this._curInst = null; // The current instance in use + this._keyEvent = false; // If the last event was a key event + this._disabledInputs = []; // List of date picker inputs that have been disabled + this._datepickerShowing = false; // True if the popup picker is showing , false if not + this._inDialog = false; // True if showing within a "dialog", false if not + this._mainDivId = 'ui-datepicker-div'; // The ID of the main datepicker division + this._inlineClass = 'ui-datepicker-inline'; // The name of the inline marker class + this._appendClass = 'ui-datepicker-append'; // The name of the append marker class + this._triggerClass = 'ui-datepicker-trigger'; // The name of the trigger marker class + this._dialogClass = 'ui-datepicker-dialog'; // The name of the dialog marker class + this._disableClass = 'ui-datepicker-disabled'; // The name of the disabled covering marker class + this._unselectableClass = 'ui-datepicker-unselectable'; // The name of the unselectable cell marker class + this._currentClass = 'ui-datepicker-current-day'; // The name of the current day marker class + this._dayOverClass = 'ui-datepicker-days-cell-over'; // The name of the day hover marker class + this.regional = []; // Available regional settings, indexed by language code + this.regional[''] = { // Default regional settings + closeText: 'Done', // Display text for close link + prevText: 'Prev', // Display text for previous month link + nextText: 'Next', // Display text for next month link + currentText: 'Today', // Display text for current month link + monthNames: ['January','February','March','April','May','June', + 'July','August','September','October','November','December'], // Names of months for drop-down and formatting + monthNamesShort: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'], // For formatting + dayNames: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'], // For formatting + dayNamesShort: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'], // For formatting + dayNamesMin: ['Su','Mo','Tu','We','Th','Fr','Sa'], // Column headings for days starting at Sunday + weekHeader: 'Wk', // Column header for week of the year + dateFormat: 'mm/dd/yy', // See format options on parseDate + firstDay: 0, // The first day of the week, Sun = 0, Mon = 1, ... + isRTL: false, // True if right-to-left language, false if left-to-right + showMonthAfterYear: false, // True if the year select precedes month, false for month then year + yearSuffix: '' // Additional text to append to the year in the month headers + }; + this._defaults = { // Global defaults for all the date picker instances + showOn: 'focus', // 'focus' for popup on focus, + // 'button' for trigger button, or 'both' for either + showAnim: 'show', // Name of jQuery animation for popup + showOptions: {}, // Options for enhanced animations + defaultDate: null, // Used when field is blank: actual date, + // +/-number for offset from today, null for today + appendText: '', // Display text following the input box, e.g. showing the format + buttonText: '...', // Text for trigger button + buttonImage: '', // URL for trigger button image + buttonImageOnly: false, // True if the image appears alone, false if it appears on a button + hideIfNoPrevNext: false, // True to hide next/previous month links + // if not applicable, false to just disable them + navigationAsDateFormat: false, // True if date formatting applied to prev/today/next links + gotoCurrent: false, // True if today link goes back to current selection instead + changeMonth: false, // True if month can be selected directly, false if only prev/next + changeYear: false, // True if year can be selected directly, false if only prev/next + yearRange: 'c-10:c+10', // Range of years to display in drop-down, + // either relative to today's year (-nn:+nn), relative to currently displayed year + // (c-nn:c+nn), absolute (nnnn:nnnn), or a combination of the above (nnnn:-n) + showOtherMonths: false, // True to show dates in other months, false to leave blank + selectOtherMonths: false, // True to allow selection of dates in other months, false for unselectable + showWeek: false, // True to show week of the year, false to not show it + calculateWeek: this.iso8601Week, // How to calculate the week of the year, + // takes a Date and returns the number of the week for it + shortYearCutoff: '+10', // Short year values < this are in the current century, + // > this are in the previous century, + // string value starting with '+' for current year + value + minDate: null, // The earliest selectable date, or null for no limit + maxDate: null, // The latest selectable date, or null for no limit + duration: '_default', // Duration of display/closure + beforeShowDay: null, // Function that takes a date and returns an array with + // [0] = true if selectable, false if not, [1] = custom CSS class name(s) or '', + // [2] = cell title (optional), e.g. $.datepicker.noWeekends + beforeShow: null, // Function that takes an input field and + // returns a set of custom settings for the date picker + onSelect: null, // Define a callback function when a date is selected + onChangeMonthYear: null, // Define a callback function when the month or year is changed + onClose: null, // Define a callback function when the datepicker is closed + numberOfMonths: 1, // Number of months to show at a time + showCurrentAtPos: 0, // The position in multipe months at which to show the current month (starting at 0) + stepMonths: 1, // Number of months to step back/forward + stepBigMonths: 12, // Number of months to step back/forward for the big links + altField: '', // Selector for an alternate field to store selected dates into + altFormat: '', // The date format to use for the alternate field + constrainInput: true, // The input is constrained by the current date format + showButtonPanel: false, // True to show button panel, false to not show it + autoSize: false // True to size the input for the date format, false to leave as is + }; + $.extend(this._defaults, this.regional['']); + this.dpDiv = $('
'); +} + +$.extend(Datepicker.prototype, { + /* Class name added to elements to indicate already configured with a date picker. */ + markerClassName: 'hasDatepicker', + + /* Debug logging (if enabled). */ + log: function () { + if (this.debug) + console.log.apply('', arguments); + }, + + // TODO rename to "widget" when switching to widget factory + _widgetDatepicker: function() { + return this.dpDiv; + }, + + /* Override the default settings for all instances of the date picker. + @param settings object - the new settings to use as defaults (anonymous object) + @return the manager object */ + setDefaults: function(settings) { + extendRemove(this._defaults, settings || {}); + return this; + }, + + /* Attach the date picker to a jQuery selection. + @param target element - the target input field or division or span + @param settings object - the new settings to use for this date picker instance (anonymous) */ + _attachDatepicker: function(target, settings) { + // check for settings on the control itself - in namespace 'date:' + var inlineSettings = null; + for (var attrName in this._defaults) { + var attrValue = target.getAttribute('date:' + attrName); + if (attrValue) { + inlineSettings = inlineSettings || {}; + try { + inlineSettings[attrName] = eval(attrValue); + } catch (err) { + inlineSettings[attrName] = attrValue; + } + } + } + var nodeName = target.nodeName.toLowerCase(); + var inline = (nodeName == 'div' || nodeName == 'span'); + if (!target.id) + target.id = 'dp' + (++this.uuid); + var inst = this._newInst($(target), inline); + inst.settings = $.extend({}, settings || {}, inlineSettings || {}); + if (nodeName == 'input') { + this._connectDatepicker(target, inst); + } else if (inline) { + this._inlineDatepicker(target, inst); + } + }, + + /* Create a new instance object. */ + _newInst: function(target, inline) { + var id = target[0].id.replace(/([^A-Za-z0-9_])/g, '\\\\$1'); // escape jQuery meta chars + return {id: id, input: target, // associated target + selectedDay: 0, selectedMonth: 0, selectedYear: 0, // current selection + drawMonth: 0, drawYear: 0, // month being drawn + inline: inline, // is datepicker inline or not + dpDiv: (!inline ? this.dpDiv : // presentation div + $('
'))}; + }, + + /* Attach the date picker to an input field. */ + _connectDatepicker: function(target, inst) { + var input = $(target); + inst.append = $([]); + inst.trigger = $([]); + if (input.hasClass(this.markerClassName)) + return; + this._attachments(input, inst); + input.addClass(this.markerClassName).keydown(this._doKeyDown). + keypress(this._doKeyPress).keyup(this._doKeyUp). + bind("setData.datepicker", function(event, key, value) { + inst.settings[key] = value; + }).bind("getData.datepicker", function(event, key) { + return this._get(inst, key); + }); + this._autoSize(inst); + $.data(target, PROP_NAME, inst); + }, + + /* Make attachments based on settings. */ + _attachments: function(input, inst) { + var appendText = this._get(inst, 'appendText'); + var isRTL = this._get(inst, 'isRTL'); + if (inst.append) + inst.append.remove(); + if (appendText) { + inst.append = $('' + appendText + ''); + input[isRTL ? 'before' : 'after'](inst.append); + } + input.unbind('focus', this._showDatepicker); + if (inst.trigger) + inst.trigger.remove(); + var showOn = this._get(inst, 'showOn'); + if (showOn == 'focus' || showOn == 'both') // pop-up date picker when in the marked field + input.focus(this._showDatepicker); + if (showOn == 'button' || showOn == 'both') { // pop-up date picker when button clicked + var buttonText = this._get(inst, 'buttonText'); + var buttonImage = this._get(inst, 'buttonImage'); + inst.trigger = $(this._get(inst, 'buttonImageOnly') ? + $('').addClass(this._triggerClass). + attr({ src: buttonImage, alt: buttonText, title: buttonText }) : + $('').addClass(this._triggerClass). + html(buttonImage == '' ? buttonText : $('').attr( + { src:buttonImage, alt:buttonText, title:buttonText }))); + input[isRTL ? 'before' : 'after'](inst.trigger); + inst.trigger.click(function() { + if ($.datepicker._datepickerShowing && $.datepicker._lastInput == input[0]) + $.datepicker._hideDatepicker(); + else + $.datepicker._showDatepicker(input[0]); + return false; + }); + } + }, + + /* Apply the maximum length for the date format. */ + _autoSize: function(inst) { + if (this._get(inst, 'autoSize') && !inst.inline) { + var date = new Date(2009, 12 - 1, 20); // Ensure double digits + var dateFormat = this._get(inst, 'dateFormat'); + if (dateFormat.match(/[DM]/)) { + var findMax = function(names) { + var max = 0; + var maxI = 0; + for (var i = 0; i < names.length; i++) { + if (names[i].length > max) { + max = names[i].length; + maxI = i; + } + } + return maxI; + }; + date.setMonth(findMax(this._get(inst, (dateFormat.match(/MM/) ? + 'monthNames' : 'monthNamesShort')))); + date.setDate(findMax(this._get(inst, (dateFormat.match(/DD/) ? + 'dayNames' : 'dayNamesShort'))) + 20 - date.getDay()); + } + inst.input.attr('size', this._formatDate(inst, date).length); + } + }, + + /* Attach an inline date picker to a div. */ + _inlineDatepicker: function(target, inst) { + var divSpan = $(target); + if (divSpan.hasClass(this.markerClassName)) + return; + divSpan.addClass(this.markerClassName).append(inst.dpDiv). + bind("setData.datepicker", function(event, key, value){ + inst.settings[key] = value; + }).bind("getData.datepicker", function(event, key){ + return this._get(inst, key); + }); + $.data(target, PROP_NAME, inst); + this._setDate(inst, this._getDefaultDate(inst), true); + this._updateDatepicker(inst); + this._updateAlternate(inst); + }, + + /* Pop-up the date picker in a "dialog" box. + @param input element - ignored + @param date string or Date - the initial date to display + @param onSelect function - the function to call when a date is selected + @param settings object - update the dialog date picker instance's settings (anonymous object) + @param pos int[2] - coordinates for the dialog's position within the screen or + event - with x/y coordinates or + leave empty for default (screen centre) + @return the manager object */ + _dialogDatepicker: function(input, date, onSelect, settings, pos) { + var inst = this._dialogInst; // internal instance + if (!inst) { + var id = 'dp' + (++this.uuid); + this._dialogInput = $(''); + this._dialogInput.keydown(this._doKeyDown); + $('body').append(this._dialogInput); + inst = this._dialogInst = this._newInst(this._dialogInput, false); + inst.settings = {}; + $.data(this._dialogInput[0], PROP_NAME, inst); + } + extendRemove(inst.settings, settings || {}); + date = (date && date.constructor == Date ? this._formatDate(inst, date) : date); + this._dialogInput.val(date); + + this._pos = (pos ? (pos.length ? pos : [pos.pageX, pos.pageY]) : null); + if (!this._pos) { + var browserWidth = document.documentElement.clientWidth; + var browserHeight = document.documentElement.clientHeight; + var scrollX = document.documentElement.scrollLeft || document.body.scrollLeft; + var scrollY = document.documentElement.scrollTop || document.body.scrollTop; + this._pos = // should use actual width/height below + [(browserWidth / 2) - 100 + scrollX, (browserHeight / 2) - 150 + scrollY]; + } + + // move input on screen for focus, but hidden behind dialog + this._dialogInput.css('left', (this._pos[0] + 20) + 'px').css('top', this._pos[1] + 'px'); + inst.settings.onSelect = onSelect; + this._inDialog = true; + this.dpDiv.addClass(this._dialogClass); + this._showDatepicker(this._dialogInput[0]); + if ($.blockUI) + $.blockUI(this.dpDiv); + $.data(this._dialogInput[0], PROP_NAME, inst); + return this; + }, + + /* Detach a datepicker from its control. + @param target element - the target input field or division or span */ + _destroyDatepicker: function(target) { + var $target = $(target); + var inst = $.data(target, PROP_NAME); + if (!$target.hasClass(this.markerClassName)) { + return; + } + var nodeName = target.nodeName.toLowerCase(); + $.removeData(target, PROP_NAME); + if (nodeName == 'input') { + inst.append.remove(); + inst.trigger.remove(); + $target.removeClass(this.markerClassName). + unbind('focus', this._showDatepicker). + unbind('keydown', this._doKeyDown). + unbind('keypress', this._doKeyPress). + unbind('keyup', this._doKeyUp); + } else if (nodeName == 'div' || nodeName == 'span') + $target.removeClass(this.markerClassName).empty(); + }, + + /* Enable the date picker to a jQuery selection. + @param target element - the target input field or division or span */ + _enableDatepicker: function(target) { + var $target = $(target); + var inst = $.data(target, PROP_NAME); + if (!$target.hasClass(this.markerClassName)) { + return; + } + var nodeName = target.nodeName.toLowerCase(); + if (nodeName == 'input') { + target.disabled = false; + inst.trigger.filter('button'). + each(function() { this.disabled = false; }).end(). + filter('img').css({opacity: '1.0', cursor: ''}); + } + else if (nodeName == 'div' || nodeName == 'span') { + var inline = $target.children('.' + this._inlineClass); + inline.children().removeClass('ui-state-disabled'); + } + this._disabledInputs = $.map(this._disabledInputs, + function(value) { return (value == target ? null : value); }); // delete entry + }, + + /* Disable the date picker to a jQuery selection. + @param target element - the target input field or division or span */ + _disableDatepicker: function(target) { + var $target = $(target); + var inst = $.data(target, PROP_NAME); + if (!$target.hasClass(this.markerClassName)) { + return; + } + var nodeName = target.nodeName.toLowerCase(); + if (nodeName == 'input') { + target.disabled = true; + inst.trigger.filter('button'). + each(function() { this.disabled = true; }).end(). + filter('img').css({opacity: '0.5', cursor: 'default'}); + } + else if (nodeName == 'div' || nodeName == 'span') { + var inline = $target.children('.' + this._inlineClass); + inline.children().addClass('ui-state-disabled'); + } + this._disabledInputs = $.map(this._disabledInputs, + function(value) { return (value == target ? null : value); }); // delete entry + this._disabledInputs[this._disabledInputs.length] = target; + }, + + /* Is the first field in a jQuery collection disabled as a datepicker? + @param target element - the target input field or division or span + @return boolean - true if disabled, false if enabled */ + _isDisabledDatepicker: function(target) { + if (!target) { + return false; + } + for (var i = 0; i < this._disabledInputs.length; i++) { + if (this._disabledInputs[i] == target) + return true; + } + return false; + }, + + /* Retrieve the instance data for the target control. + @param target element - the target input field or division or span + @return object - the associated instance data + @throws error if a jQuery problem getting data */ + _getInst: function(target) { + try { + return $.data(target, PROP_NAME); + } + catch (err) { + throw 'Missing instance data for this datepicker'; + } + }, + + /* Update or retrieve the settings for a date picker attached to an input field or division. + @param target element - the target input field or division or span + @param name object - the new settings to update or + string - the name of the setting to change or retrieve, + when retrieving also 'all' for all instance settings or + 'defaults' for all global defaults + @param value any - the new value for the setting + (omit if above is an object or to retrieve a value) */ + _optionDatepicker: function(target, name, value) { + var inst = this._getInst(target); + if (arguments.length == 2 && typeof name == 'string') { + return (name == 'defaults' ? $.extend({}, $.datepicker._defaults) : + (inst ? (name == 'all' ? $.extend({}, inst.settings) : + this._get(inst, name)) : null)); + } + var settings = name || {}; + if (typeof name == 'string') { + settings = {}; + settings[name] = value; + } + if (inst) { + if (this._curInst == inst) { + this._hideDatepicker(); + } + var date = this._getDateDatepicker(target, true); + extendRemove(inst.settings, settings); + this._attachments($(target), inst); + this._autoSize(inst); + this._setDateDatepicker(target, date); + this._updateDatepicker(inst); + } + }, + + // change method deprecated + _changeDatepicker: function(target, name, value) { + this._optionDatepicker(target, name, value); + }, + + /* Redraw the date picker attached to an input field or division. + @param target element - the target input field or division or span */ + _refreshDatepicker: function(target) { + var inst = this._getInst(target); + if (inst) { + this._updateDatepicker(inst); + } + }, + + /* Set the dates for a jQuery selection. + @param target element - the target input field or division or span + @param date Date - the new date */ + _setDateDatepicker: function(target, date) { + var inst = this._getInst(target); + if (inst) { + this._setDate(inst, date); + this._updateDatepicker(inst); + this._updateAlternate(inst); + } + }, + + /* Get the date(s) for the first entry in a jQuery selection. + @param target element - the target input field or division or span + @param noDefault boolean - true if no default date is to be used + @return Date - the current date */ + _getDateDatepicker: function(target, noDefault) { + var inst = this._getInst(target); + if (inst && !inst.inline) + this._setDateFromField(inst, noDefault); + return (inst ? this._getDate(inst) : null); + }, + + /* Handle keystrokes. */ + _doKeyDown: function(event) { + var inst = $.datepicker._getInst(event.target); + var handled = true; + var isRTL = inst.dpDiv.is('.ui-datepicker-rtl'); + inst._keyEvent = true; + if ($.datepicker._datepickerShowing) + switch (event.keyCode) { + case 9: $.datepicker._hideDatepicker(); + handled = false; + break; // hide on tab out + case 13: var sel = $('td.' + $.datepicker._dayOverClass, inst.dpDiv). + add($('td.' + $.datepicker._currentClass, inst.dpDiv)); + if (sel[0]) + $.datepicker._selectDay(event.target, inst.selectedMonth, inst.selectedYear, sel[0]); + else + $.datepicker._hideDatepicker(); + return false; // don't submit the form + break; // select the value on enter + case 27: $.datepicker._hideDatepicker(); + break; // hide on escape + case 33: $.datepicker._adjustDate(event.target, (event.ctrlKey ? + -$.datepicker._get(inst, 'stepBigMonths') : + -$.datepicker._get(inst, 'stepMonths')), 'M'); + break; // previous month/year on page up/+ ctrl + case 34: $.datepicker._adjustDate(event.target, (event.ctrlKey ? + +$.datepicker._get(inst, 'stepBigMonths') : + +$.datepicker._get(inst, 'stepMonths')), 'M'); + break; // next month/year on page down/+ ctrl + case 35: if (event.ctrlKey || event.metaKey) $.datepicker._clearDate(event.target); + handled = event.ctrlKey || event.metaKey; + break; // clear on ctrl or command +end + case 36: if (event.ctrlKey || event.metaKey) $.datepicker._gotoToday(event.target); + handled = event.ctrlKey || event.metaKey; + break; // current on ctrl or command +home + case 37: if (event.ctrlKey || event.metaKey) $.datepicker._adjustDate(event.target, (isRTL ? +1 : -1), 'D'); + handled = event.ctrlKey || event.metaKey; + // -1 day on ctrl or command +left + if (event.originalEvent.altKey) $.datepicker._adjustDate(event.target, (event.ctrlKey ? + -$.datepicker._get(inst, 'stepBigMonths') : + -$.datepicker._get(inst, 'stepMonths')), 'M'); + // next month/year on alt +left on Mac + break; + case 38: if (event.ctrlKey || event.metaKey) $.datepicker._adjustDate(event.target, -7, 'D'); + handled = event.ctrlKey || event.metaKey; + break; // -1 week on ctrl or command +up + case 39: if (event.ctrlKey || event.metaKey) $.datepicker._adjustDate(event.target, (isRTL ? -1 : +1), 'D'); + handled = event.ctrlKey || event.metaKey; + // +1 day on ctrl or command +right + if (event.originalEvent.altKey) $.datepicker._adjustDate(event.target, (event.ctrlKey ? + +$.datepicker._get(inst, 'stepBigMonths') : + +$.datepicker._get(inst, 'stepMonths')), 'M'); + // next month/year on alt +right + break; + case 40: if (event.ctrlKey || event.metaKey) $.datepicker._adjustDate(event.target, +7, 'D'); + handled = event.ctrlKey || event.metaKey; + break; // +1 week on ctrl or command +down + default: handled = false; + } + else if (event.keyCode == 36 && event.ctrlKey) // display the date picker on ctrl+home + $.datepicker._showDatepicker(this); + else { + handled = false; + } + if (handled) { + event.preventDefault(); + event.stopPropagation(); + } + }, + + /* Filter entered characters - based on date format. */ + _doKeyPress: function(event) { + var inst = $.datepicker._getInst(event.target); + if ($.datepicker._get(inst, 'constrainInput')) { + var chars = $.datepicker._possibleChars($.datepicker._get(inst, 'dateFormat')); + var chr = String.fromCharCode(event.charCode == undefined ? event.keyCode : event.charCode); + return event.ctrlKey || (chr < ' ' || !chars || chars.indexOf(chr) > -1); + } + }, + + /* Synchronise manual entry and field/alternate field. */ + _doKeyUp: function(event) { + var inst = $.datepicker._getInst(event.target); + if (inst.input.val() != inst.lastVal) { + try { + var date = $.datepicker.parseDate($.datepicker._get(inst, 'dateFormat'), + (inst.input ? inst.input.val() : null), + $.datepicker._getFormatConfig(inst)); + if (date) { // only if valid + $.datepicker._setDateFromField(inst); + $.datepicker._updateAlternate(inst); + $.datepicker._updateDatepicker(inst); + } + } + catch (event) { + $.datepicker.log(event); + } + } + return true; + }, + + /* Pop-up the date picker for a given input field. + @param input element - the input field attached to the date picker or + event - if triggered by focus */ + _showDatepicker: function(input) { + input = input.target || input; + if (input.nodeName.toLowerCase() != 'input') // find from button/image trigger + input = $('input', input.parentNode)[0]; + if ($.datepicker._isDisabledDatepicker(input) || $.datepicker._lastInput == input) // already here + return; + var inst = $.datepicker._getInst(input); + if ($.datepicker._curInst && $.datepicker._curInst != inst) { + $.datepicker._curInst.dpDiv.stop(true, true); + } + var beforeShow = $.datepicker._get(inst, 'beforeShow'); + extendRemove(inst.settings, (beforeShow ? beforeShow.apply(input, [input, inst]) : {})); + $.datepicker._lastInput = input; + $.datepicker._setDateFromField(inst); + if ($.datepicker._inDialog) // hide cursor + input.value = ''; + if (!$.datepicker._pos) { // position below input + $.datepicker._pos = $.datepicker._findPos(input); + $.datepicker._pos[1] += input.offsetHeight; // add the height + } + var isFixed = false; + $(input).parents().each(function() { + isFixed |= $(this).css('position') == 'fixed'; + return !isFixed; + }); + if (isFixed && $.browser.opera) { // correction for Opera when fixed and scrolled + $.datepicker._pos[0] -= document.documentElement.scrollLeft; + $.datepicker._pos[1] -= document.documentElement.scrollTop; + } + var offset = {left: $.datepicker._pos[0], top: $.datepicker._pos[1]}; + $.datepicker._pos = null; + // determine sizing offscreen + inst.dpDiv.css({position: 'absolute', display: 'block', top: '-1000px'}); + $.datepicker._updateDatepicker(inst); + // fix width for dynamic number of date pickers + // and adjust position before showing + offset = $.datepicker._checkOffset(inst, offset, isFixed); + inst.dpDiv.css({position: ($.datepicker._inDialog && $.blockUI ? + 'static' : (isFixed ? 'fixed' : 'absolute')), display: 'none', + left: offset.left + 'px', top: offset.top + 'px'}); + if (!inst.inline) { + var showAnim = $.datepicker._get(inst, 'showAnim'); + var duration = $.datepicker._get(inst, 'duration'); + var postProcess = function() { + $.datepicker._datepickerShowing = true; + var borders = $.datepicker._getBorders(inst.dpDiv); + inst.dpDiv.find('iframe.ui-datepicker-cover'). // IE6- only + css({left: -borders[0], top: -borders[1], + width: inst.dpDiv.outerWidth(), height: inst.dpDiv.outerHeight()}); + }; + if ($.effects && $.effects[showAnim]) + inst.dpDiv.show(showAnim, $.datepicker._get(inst, 'showOptions'), duration, postProcess); + else + inst.dpDiv[showAnim || 'show']((showAnim ? duration : ''), postProcess); + if (!showAnim) + postProcess(); + if (inst.input[0].type != 'hidden') + inst.input[0].focus(); + $.datepicker._curInst = inst; + } + }, + + /* Generate the date picker content. */ + _updateDatepicker: function(inst) { + var self = this; + var borders = $.datepicker._getBorders(inst.dpDiv); + inst.dpDiv.empty().append(this._generateHTML(inst)) + .find('iframe.ui-datepicker-cover') // IE6- only + .css({left: -borders[0], top: -borders[1], + width: inst.dpDiv.outerWidth(), height: inst.dpDiv.outerHeight()}) + .end() + .find('button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a') + .bind('mouseout', function(){ + $(this).removeClass('ui-state-hover'); + if(this.className.indexOf('ui-datepicker-prev') != -1) $(this).removeClass('ui-datepicker-prev-hover'); + if(this.className.indexOf('ui-datepicker-next') != -1) $(this).removeClass('ui-datepicker-next-hover'); + }) + .bind('mouseover', function(){ + if (!self._isDisabledDatepicker( inst.inline ? inst.dpDiv.parent()[0] : inst.input[0])) { + $(this).parents('.ui-datepicker-calendar').find('a').removeClass('ui-state-hover'); + $(this).addClass('ui-state-hover'); + if(this.className.indexOf('ui-datepicker-prev') != -1) $(this).addClass('ui-datepicker-prev-hover'); + if(this.className.indexOf('ui-datepicker-next') != -1) $(this).addClass('ui-datepicker-next-hover'); + } + }) + .end() + .find('.' + this._dayOverClass + ' a') + .trigger('mouseover') + .end(); + var numMonths = this._getNumberOfMonths(inst); + var cols = numMonths[1]; + var width = 17; + if (cols > 1) + inst.dpDiv.addClass('ui-datepicker-multi-' + cols).css('width', (width * cols) + 'em'); + else + inst.dpDiv.removeClass('ui-datepicker-multi-2 ui-datepicker-multi-3 ui-datepicker-multi-4').width(''); + inst.dpDiv[(numMonths[0] != 1 || numMonths[1] != 1 ? 'add' : 'remove') + + 'Class']('ui-datepicker-multi'); + inst.dpDiv[(this._get(inst, 'isRTL') ? 'add' : 'remove') + + 'Class']('ui-datepicker-rtl'); + if (inst.input && inst.input[0].type != 'hidden' && inst == $.datepicker._curInst) + $(inst.input[0]).focus(); + }, + + /* Retrieve the size of left and top borders for an element. + @param elem (jQuery object) the element of interest + @return (number[2]) the left and top borders */ + _getBorders: function(elem) { + var convert = function(value) { + return {thin: 1, medium: 2, thick: 3}[value] || value; + }; + return [parseFloat(convert(elem.css('border-left-width'))), + parseFloat(convert(elem.css('border-top-width')))]; + }, + + /* Check positioning to remain on screen. */ + _checkOffset: function(inst, offset, isFixed) { + var dpWidth = inst.dpDiv.outerWidth(); + var dpHeight = inst.dpDiv.outerHeight(); + var inputWidth = inst.input ? inst.input.outerWidth() : 0; + var inputHeight = inst.input ? inst.input.outerHeight() : 0; + var viewWidth = document.documentElement.clientWidth + $(document).scrollLeft(); + var viewHeight = document.documentElement.clientHeight + $(document).scrollTop(); + + offset.left -= (this._get(inst, 'isRTL') ? (dpWidth - inputWidth) : 0); + offset.left -= (isFixed && offset.left == inst.input.offset().left) ? $(document).scrollLeft() : 0; + offset.top -= (isFixed && offset.top == (inst.input.offset().top + inputHeight)) ? $(document).scrollTop() : 0; + + // now check if datepicker is showing outside window viewport - move to a better place if so. + offset.left -= Math.min(offset.left, (offset.left + dpWidth > viewWidth && viewWidth > dpWidth) ? + Math.abs(offset.left + dpWidth - viewWidth) : 0); + offset.top -= Math.min(offset.top, (offset.top + dpHeight > viewHeight && viewHeight > dpHeight) ? + Math.abs(offset.top + dpHeight + inputHeight * 2 - viewHeight) : 0); + + return offset; + }, + + /* Find an object's position on the screen. */ + _findPos: function(obj) { + while (obj && (obj.type == 'hidden' || obj.nodeType != 1)) { + obj = obj.nextSibling; + } + var position = $(obj).offset(); + return [position.left, position.top]; + }, + + /* Hide the date picker from view. + @param input element - the input field attached to the date picker */ + _hideDatepicker: function(input) { + var inst = this._curInst; + if (!inst || (input && inst != $.data(input, PROP_NAME))) + return; + if (this._datepickerShowing) { + var showAnim = this._get(inst, 'showAnim'); + var duration = this._get(inst, 'duration'); + var postProcess = function() { + $.datepicker._tidyDialog(inst); + this._curInst = null; + }; + if ($.effects && $.effects[showAnim]) + inst.dpDiv.hide(showAnim, $.datepicker._get(inst, 'showOptions'), duration, postProcess); + else + inst.dpDiv[(showAnim == 'slideDown' ? 'slideUp' : + (showAnim == 'fadeIn' ? 'fadeOut' : 'hide'))]((showAnim ? duration : ''), postProcess); + if (!showAnim) + postProcess(); + var onClose = this._get(inst, 'onClose'); + if (onClose) + onClose.apply((inst.input ? inst.input[0] : null), + [(inst.input ? inst.input.val() : ''), inst]); // trigger custom callback + this._datepickerShowing = false; + this._lastInput = null; + if (this._inDialog) { + this._dialogInput.css({ position: 'absolute', left: '0', top: '-100px' }); + if ($.blockUI) { + $.unblockUI(); + $('body').append(this.dpDiv); + } + } + this._inDialog = false; + } + }, + + /* Tidy up after a dialog display. */ + _tidyDialog: function(inst) { + inst.dpDiv.removeClass(this._dialogClass).unbind('.ui-datepicker-calendar'); + }, + + /* Close date picker if clicked elsewhere. */ + _checkExternalClick: function(event) { + if (!$.datepicker._curInst) + return; + var $target = $(event.target); + if ($target[0].id != $.datepicker._mainDivId && + $target.parents('#' + $.datepicker._mainDivId).length == 0 && + !$target.hasClass($.datepicker.markerClassName) && + !$target.hasClass($.datepicker._triggerClass) && + $.datepicker._datepickerShowing && !($.datepicker._inDialog && $.blockUI)) + $.datepicker._hideDatepicker(); + }, + + /* Adjust one of the date sub-fields. */ + _adjustDate: function(id, offset, period) { + var target = $(id); + var inst = this._getInst(target[0]); + if (this._isDisabledDatepicker(target[0])) { + return; + } + this._adjustInstDate(inst, offset + + (period == 'M' ? this._get(inst, 'showCurrentAtPos') : 0), // undo positioning + period); + this._updateDatepicker(inst); + }, + + /* Action for current link. */ + _gotoToday: function(id) { + var target = $(id); + var inst = this._getInst(target[0]); + if (this._get(inst, 'gotoCurrent') && inst.currentDay) { + inst.selectedDay = inst.currentDay; + inst.drawMonth = inst.selectedMonth = inst.currentMonth; + inst.drawYear = inst.selectedYear = inst.currentYear; + } + else { + var date = new Date(); + inst.selectedDay = date.getDate(); + inst.drawMonth = inst.selectedMonth = date.getMonth(); + inst.drawYear = inst.selectedYear = date.getFullYear(); + } + this._notifyChange(inst); + this._adjustDate(target); + }, + + /* Action for selecting a new month/year. */ + _selectMonthYear: function(id, select, period) { + var target = $(id); + var inst = this._getInst(target[0]); + inst._selectingMonthYear = false; + inst['selected' + (period == 'M' ? 'Month' : 'Year')] = + inst['draw' + (period == 'M' ? 'Month' : 'Year')] = + parseInt(select.options[select.selectedIndex].value,10); + this._notifyChange(inst); + this._adjustDate(target); + }, + + /* Restore input focus after not changing month/year. */ + _clickMonthYear: function(id) { + var target = $(id); + var inst = this._getInst(target[0]); + if (inst.input && inst._selectingMonthYear && !$.browser.msie) + inst.input[0].focus(); + inst._selectingMonthYear = !inst._selectingMonthYear; + }, + + /* Action for selecting a day. */ + _selectDay: function(id, month, year, td) { + var target = $(id); + if ($(td).hasClass(this._unselectableClass) || this._isDisabledDatepicker(target[0])) { + return; + } + var inst = this._getInst(target[0]); + inst.selectedDay = inst.currentDay = $('a', td).html(); + inst.selectedMonth = inst.currentMonth = month; + inst.selectedYear = inst.currentYear = year; + this._selectDate(id, this._formatDate(inst, + inst.currentDay, inst.currentMonth, inst.currentYear)); + }, + + /* Erase the input field and hide the date picker. */ + _clearDate: function(id) { + var target = $(id); + var inst = this._getInst(target[0]); + this._selectDate(target, ''); + }, + + /* Update the input field with the selected date. */ + _selectDate: function(id, dateStr) { + var target = $(id); + var inst = this._getInst(target[0]); + dateStr = (dateStr != null ? dateStr : this._formatDate(inst)); + if (inst.input) + inst.input.val(dateStr); + this._updateAlternate(inst); + var onSelect = this._get(inst, 'onSelect'); + if (onSelect) + onSelect.apply((inst.input ? inst.input[0] : null), [dateStr, inst]); // trigger custom callback + else if (inst.input) + inst.input.trigger('change'); // fire the change event + if (inst.inline) + this._updateDatepicker(inst); + else { + this._hideDatepicker(); + this._lastInput = inst.input[0]; + if (typeof(inst.input[0]) != 'object') + inst.input[0].focus(); // restore focus + this._lastInput = null; + } + }, + + /* Update any alternate field to synchronise with the main field. */ + _updateAlternate: function(inst) { + var altField = this._get(inst, 'altField'); + if (altField) { // update alternate field too + var altFormat = this._get(inst, 'altFormat') || this._get(inst, 'dateFormat'); + var date = this._getDate(inst); + var dateStr = this.formatDate(altFormat, date, this._getFormatConfig(inst)); + $(altField).each(function() { $(this).val(dateStr); }); + } + }, + + /* Set as beforeShowDay function to prevent selection of weekends. + @param date Date - the date to customise + @return [boolean, string] - is this date selectable?, what is its CSS class? */ + noWeekends: function(date) { + var day = date.getDay(); + return [(day > 0 && day < 6), '']; + }, + + /* Set as calculateWeek to determine the week of the year based on the ISO 8601 definition. + @param date Date - the date to get the week for + @return number - the number of the week within the year that contains this date */ + iso8601Week: function(date) { + var checkDate = new Date(date.getTime()); + // Find Thursday of this week starting on Monday + checkDate.setDate(checkDate.getDate() + 4 - (checkDate.getDay() || 7)); + var time = checkDate.getTime(); + checkDate.setMonth(0); // Compare with Jan 1 + checkDate.setDate(1); + return Math.floor(Math.round((time - checkDate) / 86400000) / 7) + 1; + }, + + /* Parse a string value into a date object. + See formatDate below for the possible formats. + + @param format string - the expected format of the date + @param value string - the date in the above format + @param settings Object - attributes include: + shortYearCutoff number - the cutoff year for determining the century (optional) + dayNamesShort string[7] - abbreviated names of the days from Sunday (optional) + dayNames string[7] - names of the days from Sunday (optional) + monthNamesShort string[12] - abbreviated names of the months (optional) + monthNames string[12] - names of the months (optional) + @return Date - the extracted date value or null if value is blank */ + parseDate: function (format, value, settings) { + if (format == null || value == null) + throw 'Invalid arguments'; + value = (typeof value == 'object' ? value.toString() : value + ''); + if (value == '') + return null; + var shortYearCutoff = (settings ? settings.shortYearCutoff : null) || this._defaults.shortYearCutoff; + var dayNamesShort = (settings ? settings.dayNamesShort : null) || this._defaults.dayNamesShort; + var dayNames = (settings ? settings.dayNames : null) || this._defaults.dayNames; + var monthNamesShort = (settings ? settings.monthNamesShort : null) || this._defaults.monthNamesShort; + var monthNames = (settings ? settings.monthNames : null) || this._defaults.monthNames; + var year = -1; + var month = -1; + var day = -1; + var doy = -1; + var literal = false; + // Check whether a format character is doubled + var lookAhead = function(match) { + var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) == match); + if (matches) + iFormat++; + return matches; + }; + // Extract a number from the string value + var getNumber = function(match) { + lookAhead(match); + var size = (match == '@' ? 14 : (match == '!' ? 20 : + (match == 'y' ? 4 : (match == 'o' ? 3 : 2)))); + var digits = new RegExp('^\\d{1,' + size + '}'); + var num = value.substring(iValue).match(digits); + if (!num) + throw 'Missing number at position ' + iValue; + iValue += num[0].length; + return parseInt(num[0], 10); + }; + // Extract a name from the string value and convert to an index + var getName = function(match, shortNames, longNames) { + var names = (lookAhead(match) ? longNames : shortNames); + for (var i = 0; i < names.length; i++) { + if (value.substr(iValue, names[i].length) == names[i]) { + iValue += names[i].length; + return i + 1; + } + } + throw 'Unknown name at position ' + iValue; + }; + // Confirm that a literal character matches the string value + var checkLiteral = function() { + if (value.charAt(iValue) != format.charAt(iFormat)) + throw 'Unexpected literal at position ' + iValue; + iValue++; + }; + var iValue = 0; + for (var iFormat = 0; iFormat < format.length; iFormat++) { + if (literal) + if (format.charAt(iFormat) == "'" && !lookAhead("'")) + literal = false; + else + checkLiteral(); + else + switch (format.charAt(iFormat)) { + case 'd': + day = getNumber('d'); + break; + case 'D': + getName('D', dayNamesShort, dayNames); + break; + case 'o': + doy = getNumber('o'); + break; + case 'm': + month = getNumber('m'); + break; + case 'M': + month = getName('M', monthNamesShort, monthNames); + break; + case 'y': + year = getNumber('y'); + break; + case '@': + var date = new Date(getNumber('@')); + year = date.getFullYear(); + month = date.getMonth() + 1; + day = date.getDate(); + break; + case '!': + var date = new Date((getNumber('!') - this._ticksTo1970) / 10000); + year = date.getFullYear(); + month = date.getMonth() + 1; + day = date.getDate(); + break; + case "'": + if (lookAhead("'")) + checkLiteral(); + else + literal = true; + break; + default: + checkLiteral(); + } + } + if (year == -1) + year = new Date().getFullYear(); + else if (year < 100) + year += new Date().getFullYear() - new Date().getFullYear() % 100 + + (year <= shortYearCutoff ? 0 : -100); + if (doy > -1) { + month = 1; + day = doy; + do { + var dim = this._getDaysInMonth(year, month - 1); + if (day <= dim) + break; + month++; + day -= dim; + } while (true); + } + var date = this._daylightSavingAdjust(new Date(year, month - 1, day)); + if (date.getFullYear() != year || date.getMonth() + 1 != month || date.getDate() != day) + throw 'Invalid date'; // E.g. 31/02/* + return date; + }, + + /* Standard date formats. */ + ATOM: 'yy-mm-dd', // RFC 3339 (ISO 8601) + COOKIE: 'D, dd M yy', + ISO_8601: 'yy-mm-dd', + RFC_822: 'D, d M y', + RFC_850: 'DD, dd-M-y', + RFC_1036: 'D, d M y', + RFC_1123: 'D, d M yy', + RFC_2822: 'D, d M yy', + RSS: 'D, d M y', // RFC 822 + TICKS: '!', + TIMESTAMP: '@', + W3C: 'yy-mm-dd', // ISO 8601 + + _ticksTo1970: (((1970 - 1) * 365 + Math.floor(1970 / 4) - Math.floor(1970 / 100) + + Math.floor(1970 / 400)) * 24 * 60 * 60 * 10000000), + + /* Format a date object into a string value. + The format can be combinations of the following: + d - day of month (no leading zero) + dd - day of month (two digit) + o - day of year (no leading zeros) + oo - day of year (three digit) + D - day name short + DD - day name long + m - month of year (no leading zero) + mm - month of year (two digit) + M - month name short + MM - month name long + y - year (two digit) + yy - year (four digit) + @ - Unix timestamp (ms since 01/01/1970) + ! - Windows ticks (100ns since 01/01/0001) + '...' - literal text + '' - single quote + + @param format string - the desired format of the date + @param date Date - the date value to format + @param settings Object - attributes include: + dayNamesShort string[7] - abbreviated names of the days from Sunday (optional) + dayNames string[7] - names of the days from Sunday (optional) + monthNamesShort string[12] - abbreviated names of the months (optional) + monthNames string[12] - names of the months (optional) + @return string - the date in the above format */ + formatDate: function (format, date, settings) { + if (!date) + return ''; + var dayNamesShort = (settings ? settings.dayNamesShort : null) || this._defaults.dayNamesShort; + var dayNames = (settings ? settings.dayNames : null) || this._defaults.dayNames; + var monthNamesShort = (settings ? settings.monthNamesShort : null) || this._defaults.monthNamesShort; + var monthNames = (settings ? settings.monthNames : null) || this._defaults.monthNames; + // Check whether a format character is doubled + var lookAhead = function(match) { + var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) == match); + if (matches) + iFormat++; + return matches; + }; + // Format a number, with leading zero if necessary + var formatNumber = function(match, value, len) { + var num = '' + value; + if (lookAhead(match)) + while (num.length < len) + num = '0' + num; + return num; + }; + // Format a name, short or long as requested + var formatName = function(match, value, shortNames, longNames) { + return (lookAhead(match) ? longNames[value] : shortNames[value]); + }; + var output = ''; + var literal = false; + if (date) + for (var iFormat = 0; iFormat < format.length; iFormat++) { + if (literal) + if (format.charAt(iFormat) == "'" && !lookAhead("'")) + literal = false; + else + output += format.charAt(iFormat); + else + switch (format.charAt(iFormat)) { + case 'd': + output += formatNumber('d', date.getDate(), 2); + break; + case 'D': + output += formatName('D', date.getDay(), dayNamesShort, dayNames); + break; + case 'o': + output += formatNumber('o', + (date.getTime() - new Date(date.getFullYear(), 0, 0).getTime()) / 86400000, 3); + break; + case 'm': + output += formatNumber('m', date.getMonth() + 1, 2); + break; + case 'M': + output += formatName('M', date.getMonth(), monthNamesShort, monthNames); + break; + case 'y': + output += (lookAhead('y') ? date.getFullYear() : + (date.getYear() % 100 < 10 ? '0' : '') + date.getYear() % 100); + break; + case '@': + output += date.getTime(); + break; + case '!': + output += date.getTime() * 10000 + this._ticksTo1970; + break; + case "'": + if (lookAhead("'")) + output += "'"; + else + literal = true; + break; + default: + output += format.charAt(iFormat); + } + } + return output; + }, + + /* Extract all possible characters from the date format. */ + _possibleChars: function (format) { + var chars = ''; + var literal = false; + // Check whether a format character is doubled + var lookAhead = function(match) { + var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) == match); + if (matches) + iFormat++; + return matches; + }; + for (var iFormat = 0; iFormat < format.length; iFormat++) + if (literal) + if (format.charAt(iFormat) == "'" && !lookAhead("'")) + literal = false; + else + chars += format.charAt(iFormat); + else + switch (format.charAt(iFormat)) { + case 'd': case 'm': case 'y': case '@': + chars += '0123456789'; + break; + case 'D': case 'M': + return null; // Accept anything + case "'": + if (lookAhead("'")) + chars += "'"; + else + literal = true; + break; + default: + chars += format.charAt(iFormat); + } + return chars; + }, + + /* Get a setting value, defaulting if necessary. */ + _get: function(inst, name) { + return inst.settings[name] !== undefined ? + inst.settings[name] : this._defaults[name]; + }, + + /* Parse existing date and initialise date picker. */ + _setDateFromField: function(inst, noDefault) { + var dateFormat = this._get(inst, 'dateFormat'); + inst.lastVal = inst.input ? inst.input.val() : null; + var dates = inst.lastVal; + var date, defaultDate; + date = defaultDate = this._getDefaultDate(inst); + var settings = this._getFormatConfig(inst); + try { + date = this.parseDate(dateFormat, dates, settings) || defaultDate; + } catch (event) { + this.log(event); + dates = (noDefault ? '' : dates); + } + inst.selectedDay = date.getDate(); + inst.drawMonth = inst.selectedMonth = date.getMonth(); + inst.drawYear = inst.selectedYear = date.getFullYear(); + inst.currentDay = (dates ? date.getDate() : 0); + inst.currentMonth = (dates ? date.getMonth() : 0); + inst.currentYear = (dates ? date.getFullYear() : 0); + this._adjustInstDate(inst); + }, + + /* Retrieve the default date shown on opening. */ + _getDefaultDate: function(inst) { + return this._restrictMinMax(inst, + this._determineDate(inst, this._get(inst, 'defaultDate'), new Date())); + }, + + /* A date may be specified as an exact value or a relative one. */ + _determineDate: function(inst, date, defaultDate) { + var offsetNumeric = function(offset) { + var date = new Date(); + date.setDate(date.getDate() + offset); + return date; + }; + var offsetString = function(offset) { + try { + return $.datepicker.parseDate($.datepicker._get(inst, 'dateFormat'), + offset, $.datepicker._getFormatConfig(inst)); + } + catch (e) { + // Ignore + } + var date = (offset.toLowerCase().match(/^c/) ? + $.datepicker._getDate(inst) : null) || new Date(); + var year = date.getFullYear(); + var month = date.getMonth(); + var day = date.getDate(); + var pattern = /([+-]?[0-9]+)\s*(d|D|w|W|m|M|y|Y)?/g; + var matches = pattern.exec(offset); + while (matches) { + switch (matches[2] || 'd') { + case 'd' : case 'D' : + day += parseInt(matches[1],10); break; + case 'w' : case 'W' : + day += parseInt(matches[1],10) * 7; break; + case 'm' : case 'M' : + month += parseInt(matches[1],10); + day = Math.min(day, $.datepicker._getDaysInMonth(year, month)); + break; + case 'y': case 'Y' : + year += parseInt(matches[1],10); + day = Math.min(day, $.datepicker._getDaysInMonth(year, month)); + break; + } + matches = pattern.exec(offset); + } + return new Date(year, month, day); + }; + date = (date == null ? defaultDate : (typeof date == 'string' ? offsetString(date) : + (typeof date == 'number' ? (isNaN(date) ? defaultDate : offsetNumeric(date)) : date))); + date = (date && date.toString() == 'Invalid Date' ? defaultDate : date); + if (date) { + date.setHours(0); + date.setMinutes(0); + date.setSeconds(0); + date.setMilliseconds(0); + } + return this._daylightSavingAdjust(date); + }, + + /* Handle switch to/from daylight saving. + Hours may be non-zero on daylight saving cut-over: + > 12 when midnight changeover, but then cannot generate + midnight datetime, so jump to 1AM, otherwise reset. + @param date (Date) the date to check + @return (Date) the corrected date */ + _daylightSavingAdjust: function(date) { + if (!date) return null; + date.setHours(date.getHours() > 12 ? date.getHours() + 2 : 0); + return date; + }, + + /* Set the date(s) directly. */ + _setDate: function(inst, date, noChange) { + var clear = !(date); + var origMonth = inst.selectedMonth; + var origYear = inst.selectedYear; + date = this._restrictMinMax(inst, this._determineDate(inst, date, new Date())); + inst.selectedDay = inst.currentDay = date.getDate(); + inst.drawMonth = inst.selectedMonth = inst.currentMonth = date.getMonth(); + inst.drawYear = inst.selectedYear = inst.currentYear = date.getFullYear(); + if ((origMonth != inst.selectedMonth || origYear != inst.selectedYear) && !noChange) + this._notifyChange(inst); + this._adjustInstDate(inst); + if (inst.input) { + inst.input.val(clear ? '' : this._formatDate(inst)); + } + }, + + /* Retrieve the date(s) directly. */ + _getDate: function(inst) { + var startDate = (!inst.currentYear || (inst.input && inst.input.val() == '') ? null : + this._daylightSavingAdjust(new Date( + inst.currentYear, inst.currentMonth, inst.currentDay))); + return startDate; + }, + + /* Generate the HTML for the current state of the date picker. */ + _generateHTML: function(inst) { + var today = new Date(); + today = this._daylightSavingAdjust( + new Date(today.getFullYear(), today.getMonth(), today.getDate())); // clear time + var isRTL = this._get(inst, 'isRTL'); + var showButtonPanel = this._get(inst, 'showButtonPanel'); + var hideIfNoPrevNext = this._get(inst, 'hideIfNoPrevNext'); + var navigationAsDateFormat = this._get(inst, 'navigationAsDateFormat'); + var numMonths = this._getNumberOfMonths(inst); + var showCurrentAtPos = this._get(inst, 'showCurrentAtPos'); + var stepMonths = this._get(inst, 'stepMonths'); + var isMultiMonth = (numMonths[0] != 1 || numMonths[1] != 1); + var currentDate = this._daylightSavingAdjust((!inst.currentDay ? new Date(9999, 9, 9) : + new Date(inst.currentYear, inst.currentMonth, inst.currentDay))); + var minDate = this._getMinMaxDate(inst, 'min'); + var maxDate = this._getMinMaxDate(inst, 'max'); + var drawMonth = inst.drawMonth - showCurrentAtPos; + var drawYear = inst.drawYear; + if (drawMonth < 0) { + drawMonth += 12; + drawYear--; + } + if (maxDate) { + var maxDraw = this._daylightSavingAdjust(new Date(maxDate.getFullYear(), + maxDate.getMonth() - (numMonths[0] * numMonths[1]) + 1, maxDate.getDate())); + maxDraw = (minDate && maxDraw < minDate ? minDate : maxDraw); + while (this._daylightSavingAdjust(new Date(drawYear, drawMonth, 1)) > maxDraw) { + drawMonth--; + if (drawMonth < 0) { + drawMonth = 11; + drawYear--; + } + } + } + inst.drawMonth = drawMonth; + inst.drawYear = drawYear; + var prevText = this._get(inst, 'prevText'); + prevText = (!navigationAsDateFormat ? prevText : this.formatDate(prevText, + this._daylightSavingAdjust(new Date(drawYear, drawMonth - stepMonths, 1)), + this._getFormatConfig(inst))); + var prev = (this._canAdjustMonth(inst, -1, drawYear, drawMonth) ? + '' + prevText + '' : + (hideIfNoPrevNext ? '' : '' + prevText + '')); + var nextText = this._get(inst, 'nextText'); + nextText = (!navigationAsDateFormat ? nextText : this.formatDate(nextText, + this._daylightSavingAdjust(new Date(drawYear, drawMonth + stepMonths, 1)), + this._getFormatConfig(inst))); + var next = (this._canAdjustMonth(inst, +1, drawYear, drawMonth) ? + '' + nextText + '' : + (hideIfNoPrevNext ? '' : '' + nextText + '')); + var currentText = this._get(inst, 'currentText'); + var gotoDate = (this._get(inst, 'gotoCurrent') && inst.currentDay ? currentDate : today); + currentText = (!navigationAsDateFormat ? currentText : + this.formatDate(currentText, gotoDate, this._getFormatConfig(inst))); + var controls = (!inst.inline ? '' : ''); + var buttonPanel = (showButtonPanel) ? '
' + (isRTL ? controls : '') + + (this._isInRange(inst, gotoDate) ? '' : '') + (isRTL ? '' : controls) + '
' : ''; + var firstDay = parseInt(this._get(inst, 'firstDay'),10); + firstDay = (isNaN(firstDay) ? 0 : firstDay); + var showWeek = this._get(inst, 'showWeek'); + var dayNames = this._get(inst, 'dayNames'); + var dayNamesShort = this._get(inst, 'dayNamesShort'); + var dayNamesMin = this._get(inst, 'dayNamesMin'); + var monthNames = this._get(inst, 'monthNames'); + var monthNamesShort = this._get(inst, 'monthNamesShort'); + var beforeShowDay = this._get(inst, 'beforeShowDay'); + var showOtherMonths = this._get(inst, 'showOtherMonths'); + var selectOtherMonths = this._get(inst, 'selectOtherMonths'); + var calculateWeek = this._get(inst, 'calculateWeek') || this.iso8601Week; + var defaultDate = this._getDefaultDate(inst); + var html = ''; + for (var row = 0; row < numMonths[0]; row++) { + var group = ''; + for (var col = 0; col < numMonths[1]; col++) { + var selectedDate = this._daylightSavingAdjust(new Date(drawYear, drawMonth, inst.selectedDay)); + var cornerClass = ' ui-corner-all'; + var calender = ''; + if (isMultiMonth) { + calender += '
'; + } + calender += '
' + + (/all|left/.test(cornerClass) && row == 0 ? (isRTL ? next : prev) : '') + + (/all|right/.test(cornerClass) && row == 0 ? (isRTL ? prev : next) : '') + + this._generateMonthYearHeader(inst, drawMonth, drawYear, minDate, maxDate, + row > 0 || col > 0, monthNames, monthNamesShort) + // draw month headers + '
' + + ''; + var thead = (showWeek ? '' : ''); + for (var dow = 0; dow < 7; dow++) { // days of the week + var day = (dow + firstDay) % 7; + thead += '= 5 ? ' class="ui-datepicker-week-end"' : '') + '>' + + '' + dayNamesMin[day] + ''; + } + calender += thead + ''; + var daysInMonth = this._getDaysInMonth(drawYear, drawMonth); + if (drawYear == inst.selectedYear && drawMonth == inst.selectedMonth) + inst.selectedDay = Math.min(inst.selectedDay, daysInMonth); + var leadDays = (this._getFirstDayOfMonth(drawYear, drawMonth) - firstDay + 7) % 7; + var numRows = (isMultiMonth ? 6 : Math.ceil((leadDays + daysInMonth) / 7)); // calculate the number of rows to generate + var printDate = this._daylightSavingAdjust(new Date(drawYear, drawMonth, 1 - leadDays)); + for (var dRow = 0; dRow < numRows; dRow++) { // create date picker rows + calender += ''; + var tbody = (!showWeek ? '' : ''); + for (var dow = 0; dow < 7; dow++) { // create date picker days + var daySettings = (beforeShowDay ? + beforeShowDay.apply((inst.input ? inst.input[0] : null), [printDate]) : [true, '']); + var otherMonth = (printDate.getMonth() != drawMonth); + var unselectable = (otherMonth && !selectOtherMonths) || !daySettings[0] || + (minDate && printDate < minDate) || (maxDate && printDate > maxDate); + tbody += ''; // display selectable date + printDate.setDate(printDate.getDate() + 1); + printDate = this._daylightSavingAdjust(printDate); + } + calender += tbody + ''; + } + drawMonth++; + if (drawMonth > 11) { + drawMonth = 0; + drawYear++; + } + calender += '
' + this._get(inst, 'weekHeader') + '
' + + this._get(inst, 'calculateWeek')(printDate) + '' + // actions + (otherMonth && !showOtherMonths ? ' ' : // display for other months + (unselectable ? '' + printDate.getDate() + '' : '' + printDate.getDate() + '')) + '
' + (isMultiMonth ? '
' + + ((numMonths[0] > 0 && col == numMonths[1]-1) ? '
' : '') : ''); + group += calender; + } + html += group; + } + html += buttonPanel + ($.browser.msie && parseInt($.browser.version,10) < 7 && !inst.inline ? + '' : ''); + inst._keyEvent = false; + return html; + }, + + /* Generate the month and year header. */ + _generateMonthYearHeader: function(inst, drawMonth, drawYear, minDate, maxDate, + secondary, monthNames, monthNamesShort) { + var changeMonth = this._get(inst, 'changeMonth'); + var changeYear = this._get(inst, 'changeYear'); + var showMonthAfterYear = this._get(inst, 'showMonthAfterYear'); + var html = '
'; + var monthHtml = ''; + // month selection + if (secondary || !changeMonth) + monthHtml += '' + monthNames[drawMonth] + ' '; + else { + var inMinYear = (minDate && minDate.getFullYear() == drawYear); + var inMaxYear = (maxDate && maxDate.getFullYear() == drawYear); + monthHtml += ''; + } + if (!showMonthAfterYear) + html += monthHtml + ((secondary || changeMonth || changeYear) && (!(changeMonth && changeYear)) ? ' ' : ''); + // year selection + if (secondary || !changeYear) + html += '' + drawYear + ''; + else { + // determine range of years to display + var years = this._get(inst, 'yearRange').split(':'); + var thisYear = new Date().getFullYear(); + var determineYear = function(value) { + var year = (value.match(/c[+-].*/) ? drawYear + parseInt(value.substring(1), 10) : + (value.match(/[+-].*/) ? thisYear + parseInt(value, 10) : + parseInt(value, 10))); + return (isNaN(year) ? thisYear : year); + }; + var year = determineYear(years[0]); + var endYear = Math.max(year, determineYear(years[1] || '')); + year = (minDate ? Math.max(year, minDate.getFullYear()) : year); + endYear = (maxDate ? Math.min(endYear, maxDate.getFullYear()) : endYear); + html += ''; + } + html += this._get(inst, 'yearSuffix'); + if (showMonthAfterYear) + html += ((secondary || changeMonth || changeYear) && (!(changeMonth && changeYear)) ? ' ' : '') + monthHtml; + html += '
'; // Close datepicker_header + return html; + }, + + /* Adjust one of the date sub-fields. */ + _adjustInstDate: function(inst, offset, period) { + var year = inst.drawYear + (period == 'Y' ? offset : 0); + var month = inst.drawMonth + (period == 'M' ? offset : 0); + var day = Math.min(inst.selectedDay, this._getDaysInMonth(year, month)) + + (period == 'D' ? offset : 0); + var date = this._restrictMinMax(inst, + this._daylightSavingAdjust(new Date(year, month, day))); + inst.selectedDay = date.getDate(); + inst.drawMonth = inst.selectedMonth = date.getMonth(); + inst.drawYear = inst.selectedYear = date.getFullYear(); + if (period == 'M' || period == 'Y') + this._notifyChange(inst); + }, + + /* Ensure a date is within any min/max bounds. */ + _restrictMinMax: function(inst, date) { + var minDate = this._getMinMaxDate(inst, 'min'); + var maxDate = this._getMinMaxDate(inst, 'max'); + date = (minDate && date < minDate ? minDate : date); + date = (maxDate && date > maxDate ? maxDate : date); + return date; + }, + + /* Notify change of month/year. */ + _notifyChange: function(inst) { + var onChange = this._get(inst, 'onChangeMonthYear'); + if (onChange) + onChange.apply((inst.input ? inst.input[0] : null), + [inst.selectedYear, inst.selectedMonth + 1, inst]); + }, + + /* Determine the number of months to show. */ + _getNumberOfMonths: function(inst) { + var numMonths = this._get(inst, 'numberOfMonths'); + return (numMonths == null ? [1, 1] : (typeof numMonths == 'number' ? [1, numMonths] : numMonths)); + }, + + /* Determine the current maximum date - ensure no time components are set. */ + _getMinMaxDate: function(inst, minMax) { + return this._determineDate(inst, this._get(inst, minMax + 'Date'), null); + }, + + /* Find the number of days in a given month. */ + _getDaysInMonth: function(year, month) { + return 32 - new Date(year, month, 32).getDate(); + }, + + /* Find the day of the week of the first of a month. */ + _getFirstDayOfMonth: function(year, month) { + return new Date(year, month, 1).getDay(); + }, + + /* Determines if we should allow a "next/prev" month display change. */ + _canAdjustMonth: function(inst, offset, curYear, curMonth) { + var numMonths = this._getNumberOfMonths(inst); + var date = this._daylightSavingAdjust(new Date(curYear, + curMonth + (offset < 0 ? offset : numMonths[0] * numMonths[1]), 1)); + if (offset < 0) + date.setDate(this._getDaysInMonth(date.getFullYear(), date.getMonth())); + return this._isInRange(inst, date); + }, + + /* Is the given date in the accepted range? */ + _isInRange: function(inst, date) { + var minDate = this._getMinMaxDate(inst, 'min'); + var maxDate = this._getMinMaxDate(inst, 'max'); + return ((!minDate || date.getTime() >= minDate.getTime()) && + (!maxDate || date.getTime() <= maxDate.getTime())); + }, + + /* Provide the configuration settings for formatting/parsing. */ + _getFormatConfig: function(inst) { + var shortYearCutoff = this._get(inst, 'shortYearCutoff'); + shortYearCutoff = (typeof shortYearCutoff != 'string' ? shortYearCutoff : + new Date().getFullYear() % 100 + parseInt(shortYearCutoff, 10)); + return {shortYearCutoff: shortYearCutoff, + dayNamesShort: this._get(inst, 'dayNamesShort'), dayNames: this._get(inst, 'dayNames'), + monthNamesShort: this._get(inst, 'monthNamesShort'), monthNames: this._get(inst, 'monthNames')}; + }, + + /* Format the given date for display. */ + _formatDate: function(inst, day, month, year) { + if (!day) { + inst.currentDay = inst.selectedDay; + inst.currentMonth = inst.selectedMonth; + inst.currentYear = inst.selectedYear; + } + var date = (day ? (typeof day == 'object' ? day : + this._daylightSavingAdjust(new Date(year, month, day))) : + this._daylightSavingAdjust(new Date(inst.currentYear, inst.currentMonth, inst.currentDay))); + return this.formatDate(this._get(inst, 'dateFormat'), date, this._getFormatConfig(inst)); + } +}); + +/* jQuery extend now ignores nulls! */ +function extendRemove(target, props) { + $.extend(target, props); + for (var name in props) + if (props[name] == null || props[name] == undefined) + target[name] = props[name]; + return target; +}; + +/* Determine whether an object is an array. */ +function isArray(a) { + return (a && (($.browser.safari && typeof a == 'object' && a.length) || + (a.constructor && a.constructor.toString().match(/\Array\(\)/)))); +}; + +/* Invoke the datepicker functionality. + @param options string - a command, optionally followed by additional parameters or + Object - settings for attaching new datepicker functionality + @return jQuery object */ +$.fn.datepicker = function(options){ + + /* Initialise the date picker. */ + if (!$.datepicker.initialized) { + $(document).mousedown($.datepicker._checkExternalClick). + find('body').append($.datepicker.dpDiv); + $.datepicker.initialized = true; + } + + var otherArgs = Array.prototype.slice.call(arguments, 1); + if (typeof options == 'string' && (options == 'isDisabled' || options == 'getDate' || options == 'widget')) + return $.datepicker['_' + options + 'Datepicker']. + apply($.datepicker, [this[0]].concat(otherArgs)); + if (options == 'option' && arguments.length == 2 && typeof arguments[1] == 'string') + return $.datepicker['_' + options + 'Datepicker']. + apply($.datepicker, [this[0]].concat(otherArgs)); + return this.each(function() { + typeof options == 'string' ? + $.datepicker['_' + options + 'Datepicker']. + apply($.datepicker, [this].concat(otherArgs)) : + $.datepicker._attachDatepicker(this, options); + }); +}; + +$.datepicker = new Datepicker(); // singleton instance +$.datepicker.initialized = false; +$.datepicker.uuid = new Date().getTime(); +$.datepicker.version = "1.8b1"; + +// Workaround for #4055 +// Add another global to avoid noConflict issues with inline event handlers +window['DP_jQuery_' + dpuuid] = $; + +})(jQuery); diff --git a/src/Orchard.Web/Modules/ArchiveLater/Scripts/jquery.ui.widget.js b/src/Orchard.Web/Modules/ArchiveLater/Scripts/jquery.ui.widget.js new file mode 100644 index 000000000..9b616bcf7 --- /dev/null +++ b/src/Orchard.Web/Modules/ArchiveLater/Scripts/jquery.ui.widget.js @@ -0,0 +1,232 @@ +/*! + * jQuery UI Widget 1.8b1 + * + * Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + * http://docs.jquery.com/UI/Widget + */ +(function( $ ) { + +var _remove = $.fn.remove; + +$.fn.remove = function( selector, keepData ) { + if ( !keepData ) { + $( "*", this ).add( this ).each(function() { + $( this ).triggerHandler( "remove" ); + }); + } + return _remove.apply( this, arguments ); +}; + +$.widget = function( name, base, prototype ) { + var namespace = name.split( "." )[ 0 ], + fullName; + name = name.split( "." )[ 1 ]; + fullName = namespace + "-" + name; + + if ( !prototype ) { + prototype = base; + base = $.Widget; + } + + // create selector for plugin + $.expr[ ":" ][ fullName ] = function( elem ) { + return !!$.data( elem, name ); + }; + + $[ namespace ] = $[ namespace ] || {}; + $[ namespace ][ name ] = function( options, element ) { + // allow instantiation without initializing for simple inheritance + if ( arguments.length ) { + this._createWidget( options, element ); + } + }; + + var 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( {}, basePrototype.options ); + $[ namespace ][ name ].prototype = $.extend( true, basePrototype, { + namespace: namespace, + widgetName: name, + widgetEventPrefix: $[ namespace ][ name ].prototype.widgetEventPrefix || name, + widgetBaseClass: fullName + }, prototype ); + + $.widget.bridge( name, $[ namespace ][ name ] ); +}; + +$.widget.bridge = function( name, object ) { + $.fn[ name ] = function( options ) { + var isMethodCall = typeof options === "string", + args = Array.prototype.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) ) : + options; + + // prevent calls to internal methods + if ( isMethodCall && options.substring( 0, 1 ) === "_" ) { + return returnValue; + } + + if ( isMethodCall ) { + this.each(function() { + var instance = $.data( this, name ), + methodValue = instance && $.isFunction( instance[options] ) ? + instance[ options ].apply( instance, args ) : + instance; + if ( methodValue !== instance && methodValue !== undefined ) { + returnValue = methodValue; + return false; + } + }); + } else { + this.each(function() { + var instance = $.data( this, name ); + if ( instance ) { + if ( options ) { + instance.option( options ); + } + instance._init(); + } else { + $.data( this, name, new object( options, this ) ); + } + }); + } + + return returnValue; + }; +}; + +$.Widget = function( options, element ) { + // allow instantiation without initializing for simple inheritance + if ( arguments.length ) { + this._createWidget( options, element ); + } +}; + +$.Widget.prototype = { + widgetName: "widget", + widgetEventPrefix: "", + options: { + disabled: false + }, + _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 + this.element = $( element ).data( this.widgetName, this ); + this.options = $.extend( true, {}, + this.options, + $.metadata && $.metadata.get( element )[ this.widgetName ], + options ); + + var self = this; + this.element.bind( "remove." + this.widgetName, function() { + self.destroy(); + }); + + this._create(); + this._init(); + }, + _create: function() {}, + _init: function() {}, + + destroy: function() { + this.element + .unbind( "." + this.widgetName ) + .removeData( this.widgetName ); + this.widget() + .unbind( "." + this.widgetName ) + .removeAttr( "aria-disabled" ) + .removeClass( + this.widgetBaseClass + "-disabled " + + this.namespace + "-state-disabled" ); + }, + + widget: function() { + return this.element; + }, + + option: function( key, value ) { + var options = key, + self = this; + + if ( arguments.length === 0 ) { + // don't return a reference to the internal hash + return $.extend( {}, self.options ); + } + + if (typeof key === "string" ) { + if ( value === undefined ) { + return this.options[ key ]; + } + options = {}; + options[ key ] = value; + } + + $.each( options, function( key, value ) { + self._setOption( key, value ); + }); + + return self; + }, + _setOption: function( key, value ) { + this.options[ key ] = value; + + if ( key === "disabled" ) { + this.widget() + [ value ? "addClass" : "removeClass"]( + this.widgetBaseClass + "-disabled" + " " + + this.namespace + "-state-disabled" ) + .attr( "aria-disabled", value ); + } + + return this; + }, + + enable: function() { + return this._setOption( "disabled", false ); + }, + disable: function() { + return this._setOption( "disabled", true ); + }, + + _trigger: function( type, event, data ) { + var callback = this.options[ type ]; + + event = $.Event( event ); + event.type = ( type === this.widgetEventPrefix ? + type : + this.widgetEventPrefix + type ).toLowerCase(); + data = data || {}; + + // copy original event properties over to the new event + // this would happen if we could call $.event.fix instead of $.Event + // but we don't have a way to force an event to be fixed multiple times + if ( event.originalEvent ) { + for ( var i = $.event.props.length, prop; i; ) { + prop = $.event.props[ --i ]; + event[ prop ] = event.originalEvent[ prop ]; + } + } + + this.element.trigger( event, data ); + + return !( $.isFunction(callback) && + callback.call( this.element[0], event, data ) === false || + event.isDefaultPrevented() ); + } +}; + +})( jQuery ); diff --git a/src/Orchard.Web/Modules/ArchiveLater/Scripts/jquery.utils.js b/src/Orchard.Web/Modules/ArchiveLater/Scripts/jquery.utils.js new file mode 100644 index 000000000..564d4c698 --- /dev/null +++ b/src/Orchard.Web/Modules/ArchiveLater/Scripts/jquery.utils.js @@ -0,0 +1,2777 @@ +/* + jQuery utils - 0.8.5 + http://code.google.com/p/jquery-utils/ + + (c) Maxime Haineault + http://haineault.com + + MIT License (http://www.opensource.org/licenses/mit-license.php + +*/ + +(function($){ + $.extend($.expr[':'], { + // case insensitive version of :contains + icontains: function(a,i,m){return (a.textContent||a.innerText||jQuery(a).text()||"").toLowerCase().indexOf(m[3].toLowerCase())>=0;} + }); + + $.iterators = { + getText: function() { return $(this).text(); }, + parseInt: function(v){ return parseInt(v, 10); } + }; + + $.extend({ + + // Returns a range object + // Author: Matthias Miller + // Site: http://blog.outofhanwell.com/2006/03/29/javascript-range-function/ + range: function() { + if (!arguments.length) { return []; } + var min, max, step; + if (arguments.length == 1) { + min = 0; + max = arguments[0]-1; + step = 1; + } + else { + // default step to 1 if it's zero or undefined + min = arguments[0]; + max = arguments[1]-1; + step = arguments[2] || 1; + } + // convert negative steps to positive and reverse min/max + if (step < 0 && min >= max) { + step *= -1; + var tmp = min; + min = max; + max = tmp; + min += ((max-min) % step); + } + var a = []; + for (var i = min; i <= max; i += step) { a.push(i); } + return a; + }, + + // Taken from ui.core.js. + // Why are you keeping this gem for yourself guys ? :| + keyCode: { + BACKSPACE: 8, CAPS_LOCK: 20, COMMA: 188, CONTROL: 17, DELETE: 46, DOWN: 40, + END: 35, ENTER: 13, ESCAPE: 27, HOME: 36, INSERT: 45, LEFT: 37, + NUMPAD_ADD: 107, NUMPAD_DECIMAL: 110, NUMPAD_DIVIDE: 111, NUMPAD_ENTER: 108, + NUMPAD_MULTIPLY: 106, NUMPAD_SUBTRACT: 109, PAGE_DOWN: 34, PAGE_UP: 33, + PERIOD: 190, RIGHT: 39, SHIFT: 16, SPACE: 32, TAB: 9, UP: 38 + }, + + // Takes a keyboard event and return true if the keycode match the specified keycode + keyIs: function(k, e) { + return parseInt($.keyCode[k.toUpperCase()], 10) == parseInt((typeof(e) == 'number' )? e: e.keyCode, 10); + }, + + // Returns the key of an array + keys: function(arr) { + var o = []; + for (k in arr) { o.push(k); } + return o; + }, + + // Redirect to a specified url + redirect: function(url) { + window.location.href = url; + return url; + }, + + // Stop event shorthand + stop: function(e, preventDefault, stopPropagation) { + if (preventDefault) { e.preventDefault(); } + if (stopPropagation) { e.stopPropagation(); } + return preventDefault && false || true; + }, + + // Returns the basename of a path + basename: function(path) { + var t = path.split('/'); + return t[t.length] === '' && s || t.slice(0, t.length).join('/'); + }, + + // Returns the filename of a path + filename: function(path) { + return path.split('/').pop(); + }, + + // Returns a formated file size + filesizeformat: function(bytes, suffixes){ + var b = parseInt(bytes, 10); + var s = suffixes || ['byte', 'bytes', 'KB', 'MB', 'GB']; + if (isNaN(b) || b === 0) { return '0 ' + s[0]; } + if (b == 1) { return '1 ' + s[0]; } + if (b < 1024) { return b.toFixed(2) + ' ' + s[1]; } + if (b < 1048576) { return (b / 1024).toFixed(2) + ' ' + s[2]; } + if (b < 1073741824) { return (b / 1048576).toFixed(2) + ' '+ s[3]; } + else { return (b / 1073741824).toFixed(2) + ' '+ s[4]; } + }, + + fileExtension: function(s) { + var tokens = s.split('.'); + return tokens[tokens.length-1] || false; + }, + + // Returns true if an object is a String + isString: function(o) { + return typeof(o) == 'string' && true || false; + }, + + // Returns true if an object is a RegExp + isRegExp: function(o) { + return o && o.constructor.toString().indexOf('RegExp()') != -1 || false; + }, + + isObject: function(o) { + return (typeof(o) == 'object'); + }, + + // Convert input to currency (two decimal fixed number) + toCurrency: function(i) { + i = parseFloat(i, 10).toFixed(2); + return (i=='NaN') ? '0.00' : i; + }, + + /*-------------------------------------------------------------------- + * javascript method: "pxToEm" + * by: + Scott Jehl (scott@filamentgroup.com) + Maggie Wachs (maggie@filamentgroup.com) + http://www.filamentgroup.com + * + * Copyright (c) 2008 Filament Group + * Dual licensed under the MIT (filamentgroup.com/examples/mit-license.txt) and GPL (filamentgroup.com/examples/gpl-license.txt) licenses. + * + * Description: pxToEm converts a pixel value to ems depending on inherited font size. + * Article: http://www.filamentgroup.com/lab/retaining_scalable_interfaces_with_pixel_to_em_conversion/ + * Demo: http://www.filamentgroup.com/examples/pxToEm/ + * + * Options: + scope: string or jQuery selector for font-size scoping + reverse: Boolean, true reverses the conversion to em-px + * Dependencies: jQuery library + * Usage Example: myPixelValue.pxToEm(); or myPixelValue.pxToEm({'scope':'#navigation', reverse: true}); + * + * Version: 2.1, 18.12.2008 + * Changelog: + * 08.02.2007 initial Version 1.0 + * 08.01.2008 - fixed font-size calculation for IE + * 18.12.2008 - removed native object prototyping to stay in jQuery's spirit, jsLinted (Maxime Haineault ) + --------------------------------------------------------------------*/ + + pxToEm: function(i, settings){ + //set defaults + settings = jQuery.extend({ + scope: 'body', + reverse: false + }, settings); + + var pxVal = (i === '') ? 0 : parseFloat(i); + var scopeVal; + var getWindowWidth = function(){ + var de = document.documentElement; + return self.innerWidth || (de && de.clientWidth) || document.body.clientWidth; + }; + + /* When a percentage-based font-size is set on the body, IE returns that percent of the window width as the font-size. + For example, if the body font-size is 62.5% and the window width is 1000px, IE will return 625px as the font-size. + When this happens, we calculate the correct body font-size (%) and multiply it by 16 (the standard browser font size) + to get an accurate em value. */ + + if (settings.scope == 'body' && $.browser.msie && (parseFloat($('body').css('font-size')) / getWindowWidth()).toFixed(1) > 0.0) { + var calcFontSize = function(){ + return (parseFloat($('body').css('font-size'))/getWindowWidth()).toFixed(3) * 16; + }; + scopeVal = calcFontSize(); + } + else { scopeVal = parseFloat(jQuery(settings.scope).css("font-size")); } + + var result = (settings.reverse === true) ? (pxVal * scopeVal).toFixed(2) + 'px' : (pxVal / scopeVal).toFixed(2) + 'em'; + return result; + } + }); + + $.extend($.fn, { + type: function() { + try { return $(this).get(0).nodeName.toLowerCase(); } + catch(e) { return false; } + }, + // Select a text range in a textarea + selectRange: function(start, end){ + // use only the first one since only one input can be focused + if ($(this).get(0).createTextRange) { + var range = $(this).get(0).createTextRange(); + range.collapse(true); + range.moveEnd('character', end); + range.moveStart('character', start); + range.select(); + } + else if ($(this).get(0).setSelectionRange) { + $(this).bind('focus', function(e){ + e.preventDefault(); + }).get(0).setSelectionRange(start, end); + } + return $(this); + }, + + /*-------------------------------------------------------------------- + * JQuery Plugin: "EqualHeights" + * by: Scott Jehl, Todd Parker, Maggie Costello Wachs (http://www.filamentgroup.com) + * + * Copyright (c) 2008 Filament Group + * Licensed under GPL (http://www.opensource.org/licenses/gpl-license.php) + * + * Description: Compares the heights or widths of the top-level children of a provided element + and sets their min-height to the tallest height (or width to widest width). Sets in em units + by default if pxToEm() method is available. + * Dependencies: jQuery library, pxToEm method (article: + http://www.filamentgroup.com/lab/retaining_scalable_interfaces_with_pixel_to_em_conversion/) + * Usage Example: $(element).equalHeights(); + Optional: to set min-height in px, pass a true argument: $(element).equalHeights(true); + * Version: 2.1, 18.12.2008 + * + * Note: Changed pxToEm call to call $.pxToEm instead, jsLinted (Maxime Haineault ) + --------------------------------------------------------------------*/ + + equalHeights: function(px){ + $(this).each(function(){ + var currentTallest = 0; + $(this).children().each(function(i){ + if ($(this).height() > currentTallest) { currentTallest = $(this).height(); } + }); + if (!px || !$.pxToEm) { currentTallest = $.pxToEm(currentTallest); } //use ems unless px is specified + // for ie6, set height since min-height isn't supported + if ($.browser.msie && $.browser.version == 6.0) { $(this).children().css({'height': currentTallest}); } + $(this).children().css({'min-height': currentTallest}); + }); + return this; + }, + + // Copyright (c) 2009 James Padolsey + // http://james.padolsey.com/javascript/jquery-delay-plugin/ + delay: function(time, callback){ + jQuery.fx.step.delay = function(){}; + return this.animate({delay:1}, time, callback); + } + }); +})(jQuery); +/* + jQuery strings - 0.3 + http://code.google.com/p/jquery-utils/ + + (c) Maxime Haineault + http://haineault.com + + MIT License (http://www.opensource.org/licenses/mit-license.php) + + Implementation of Python3K advanced string formatting + http://www.python.org/dev/peps/pep-3101/ + + Documentation: http://code.google.com/p/jquery-utils/wiki/StringFormat + +*/ +(function($){ + var strings = { + strConversion: { + // tries to translate any objects type into string gracefully + __repr: function(i){ + switch(this.__getType(i)) { + case 'array':case 'date':case 'number': + return i.toString(); + case 'object': + var o = []; + for (x=0; x 0) { + o = new Array(Math.ceil(l / p.length)).join(p).substr(0, t = !t ? l : t == 1 ? 0 : Math.ceil(l / 2)) + str + p.substr(0, l - t); + } + return o; + }, + __getInput: function(arg, args) { + var key = arg.getKey(); + switch(this.__getType(args)){ + case 'object': // Thanks to Jonathan Works for the patch + var keys = key.split('.'); + var obj = args; + for(var subkey = 0; subkey < keys.length; subkey++){ + obj = obj[keys[subkey]]; + } + if (typeof(obj) != 'undefined') { + if (strings.strConversion.__getType(obj) == 'array') { + return arg.getFormat().match(/\.\*/) && obj[1] || obj; + } + return obj; + } + else { + // TODO: try by numerical index + } + break; + case 'array': + key = parseInt(key, 10); + if (arg.getFormat().match(/\.\*/) && typeof args[key+1] != 'undefined') { return args[key+1]; } + else if (typeof args[key] != 'undefined') { return args[key]; } + else { return key; } + break; + } + return '{'+key+'}'; + }, + __formatToken: function(token, args) { + var arg = new Argument(token, args); + return strings.strConversion[arg.getFormat().slice(-1)](this.__getInput(arg, args), arg); + }, + + // Signed integer decimal. + d: function(input, arg){ + var o = parseInt(input, 10); // enforce base 10 + var p = arg.getPaddingLength(); + if (p) { return this.__pad(o.toString(), p, arg.getPaddingString(), 0); } + else { return o; } + }, + // Signed integer decimal. + i: function(input, args){ + return this.d(input, args); + }, + // Unsigned octal + o: function(input, arg){ + var o = input.toString(8); + if (arg.isAlternate()) { o = this.__pad(o, o.length+1, '0', 0); } + return this.__pad(o, arg.getPaddingLength(), arg.getPaddingString(), 0); + }, + // Unsigned decimal + u: function(input, args) { + return Math.abs(this.d(input, args)); + }, + // Unsigned hexadecimal (lowercase) + x: function(input, arg){ + var o = parseInt(input, 10).toString(16); + o = this.__pad(o, arg.getPaddingLength(), arg.getPaddingString(),0); + return arg.isAlternate() ? '0x'+o : o; + }, + // Unsigned hexadecimal (uppercase) + X: function(input, arg){ + return this.x(input, arg).toUpperCase(); + }, + // Floating point exponential format (lowercase) + e: function(input, arg){ + return parseFloat(input, 10).toExponential(arg.getPrecision()); + }, + // Floating point exponential format (uppercase) + E: function(input, arg){ + return this.e(input, arg).toUpperCase(); + }, + // Floating point decimal format + f: function(input, arg){ + return this.__pad(parseFloat(input, 10).toFixed(arg.getPrecision()), arg.getPaddingLength(), arg.getPaddingString(),0); + }, + // Floating point decimal format (alias) + F: function(input, args){ + return this.f(input, args); + }, + // Floating point format. Uses exponential format if exponent is greater than -4 or less than precision, decimal format otherwise + g: function(input, arg){ + var o = parseFloat(input, 10); + return (o.toString().length > 6) ? Math.round(o.toExponential(arg.getPrecision())): o; + }, + // Floating point format. Uses exponential format if exponent is greater than -4 or less than precision, decimal format otherwise + G: function(input, args){ + return this.g(input, args); + }, + // Single character (accepts integer or single character string). + c: function(input, args) { + var match = input.match(/\w|\d/); + return match && match[0] || ''; + }, + // String (converts any JavaScript object to anotated format) + r: function(input, args) { + return this.__repr(input); + }, + // String (converts any JavaScript object using object.toString()) + s: function(input, args) { + return input.toString && input.toString() || ''+input; + } + }, + + format: function(str, args) { + var end = 0; + var start = 0; + var match = false; + var buffer = []; + var token = ''; + var tmp = (str||'').split(''); + for(start=0; start < tmp.length; start++) { + if (tmp[start] == '{' && tmp[start+1] !='{') { + end = str.indexOf('}', start); + token = tmp.slice(start+1, end).join(''); + if (tmp[start-1] != '{' && tmp[end+1] != '}') { + var tokenArgs = (typeof arguments[1] != 'object')? arguments2Array(arguments, 2): args || []; + buffer.push(strings.strConversion.__formatToken(token, tokenArgs)); + } + else { + buffer.push(token); + } + } + else if (start > end || buffer.length < 1) { buffer.push(tmp[start]); } + } + return (buffer.length > 1)? buffer.join(''): buffer[0]; + }, + + calc: function(str, args) { + return eval(format(str, args)); + }, + + repeat: function(s, n) { + return new Array(n+1).join(s); + }, + + UTF8encode: function(s) { + return unescape(encodeURIComponent(s)); + }, + + UTF8decode: function(s) { + return decodeURIComponent(escape(s)); + }, + + tpl: function() { + var out = ''; + var render = true; + // Set + // $.tpl('ui.test', ['', helloWorld ,'']); + if (arguments.length == 2 && $.isArray(arguments[1])) { + this[arguments[0]] = arguments[1].join(''); + return $(this[arguments[0]]); + } + // $.tpl('ui.test', 'hello world'); + if (arguments.length == 2 && $.isString(arguments[1])) { + this[arguments[0]] = arguments[1]; + return $(this[arguments[0]]); + } + // Call + // $.tpl('ui.test'); + if (arguments.length == 1) { + return $(this[arguments[0]]); + } + // $.tpl('ui.test', false); + if (arguments.length == 2 && arguments[1] == false) { + return this[arguments[0]]; + } + // $.tpl('ui.test', {value:blah}); + if (arguments.length == 2 && $.isObject(arguments[1])) { + return $($.format(this[arguments[0]], arguments[1])); + } + // $.tpl('ui.test', {value:blah}, false); + if (arguments.length == 3 && $.isObject(arguments[1])) { + return (arguments[2] == true) + ? $.format(this[arguments[0]], arguments[1]) + : $($.format(this[arguments[0]], arguments[1])); + } + } + }; + + var Argument = function(arg, args) { + this.__arg = arg; + this.__args = args; + this.__max_precision = parseFloat('1.'+ (new Array(32)).join('1'), 10).toString().length-3; + this.__def_precision = 6; + this.getString = function(){ + return this.__arg; + }; + this.getKey = function(){ + return this.__arg.split(':')[0]; + }; + this.getFormat = function(){ + var match = this.getString().split(':'); + return (match && match[1])? match[1]: 's'; + }; + this.getPrecision = function(){ + var match = this.getFormat().match(/\.(\d+|\*)/g); + if (!match) { return this.__def_precision; } + else { + match = match[0].slice(1); + if (match != '*') { return parseInt(match, 10); } + else if(strings.strConversion.__getType(this.__args) == 'array') { + return this.__args[1] && this.__args[0] || this.__def_precision; + } + else if(strings.strConversion.__getType(this.__args) == 'object') { + return this.__args[this.getKey()] && this.__args[this.getKey()][0] || this.__def_precision; + } + else { return this.__def_precision; } + } + }; + this.getPaddingLength = function(){ + var match = false; + if (this.isAlternate()) { + match = this.getString().match(/0?#0?(\d+)/); + if (match && match[1]) { return parseInt(match[1], 10); } + } + match = this.getString().match(/(0|\.)(\d+|\*)/g); + return match && parseInt(match[0].slice(1), 10) || 0; + }; + this.getPaddingString = function(){ + var o = ''; + if (this.isAlternate()) { o = ' '; } + // 0 take precedence on alternate format + if (this.getFormat().match(/#0|0#|^0|\.\d+/)) { o = '0'; } + return o; + }; + this.getFlags = function(){ + var match = this.getString().matc(/^(0|\#|\-|\+|\s)+/); + return match && match[0].split('') || []; + }; + this.isAlternate = function() { + return !!this.getFormat().match(/^0?#/); + }; + }; + + var arguments2Array = function(args, shift) { + var o = []; + for (l=args.length, x=(shift || 0)-1; x + http://haineault.com + + MIT License (http://www.opensource.org/licenses/mit-license.php) + +*/ + +(function($){ + var hash = window.location.hash; + var handlers = []; + var opt = {}; + + $.extend({ + anchorHandler: { + apply: function() { + $.map(handlers, function(handler){ + var match = hash.match(handler.r) && hash.match(handler.r)[0] || false; + if (match) { handler.cb.apply($('a[href*='+match+']').get(0), [handler.r, hash || '']); } + }); + return $.anchorHandler; + }, + add: function(regexp, callback, options) { + var opt = $.extend({handleClick: true, preserveHash: true}, options); + if (opt.handleClick) { + $('a[href*=#]').each(function(i, a){ + if (a.href.match(regexp)) { + $(a).bind('click.anchorHandler', function(){ + if (opt.preserveHash) { window.location.hash = a.hash; } + return callback.apply(this, [regexp, a.href]); + }); + } + }); + } + handlers.push({r: regexp, cb: callback}); + $($.anchorHandler.apply); + return $.anchorHandler; + } + } + }); +})(jQuery); +/** + * Cookie plugin + * + * Copyright (c) 2006 Klaus Hartl (stilbuero.de) + * Dual licensed under the MIT and GPL licenses: + * http://www.opensource.org/licenses/mit-license.php + * http://www.gnu.org/licenses/gpl.html + * + */ + +/** + * Create a cookie with the given name and value and other optional parameters. + * + * @example $.cookie('the_cookie', 'the_value'); + * @desc Set the value of a cookie. + * @example $.cookie('the_cookie', 'the_value', { expires: 7, path: '/', domain: 'jquery.com', secure: true }); + * @desc Create a cookie with all available options. + * @example $.cookie('the_cookie', 'the_value'); + * @desc Create a session cookie. + * @example $.cookie('the_cookie', null); + * @desc Delete a cookie by passing null as value. Keep in mind that you have to use the same path and domain + * used when the cookie was set. + * + * @param String name The name of the cookie. + * @param String value The value of the cookie. + * @param Object options An object literal containing key/value pairs to provide optional cookie attributes. + * @option Number|Date expires Either an integer specifying the expiration date from now on in days or a Date object. + * If a negative value is specified (e.g. a date in the past), the cookie will be deleted. + * If set to null or omitted, the cookie will be a session cookie and will not be retained + * when the the browser exits. + * @option String path The value of the path atribute of the cookie (default: path of page that created the cookie). + * @option String domain The value of the domain attribute of the cookie (default: domain of page that created the cookie). + * @option Boolean secure If true, the secure attribute of the cookie will be set and the cookie transmission will + * require a secure protocol (like HTTPS). + * @type undefined + * + * @name $.cookie + * @cat Plugins/Cookie + * @author Klaus Hartl/klaus.hartl@stilbuero.de + */ + +/** + * Get the value of a cookie with the given name. + * + * @example $.cookie('the_cookie'); + * @desc Get the value of a cookie. + * + * @param String name The name of the cookie. + * @return The value of the cookie. + * @type String + * + * @name $.cookie + * @cat Plugins/Cookie + * @author Klaus Hartl/klaus.hartl@stilbuero.de + */ +jQuery.cookie = function(name, value, options) { + if (typeof value != 'undefined') { // name and value given, set cookie + options = options || {}; + if (value === null) { + value = ''; + options.expires = -1; + } + var expires = ''; + if (options.expires && (typeof options.expires == 'number' || options.expires.toUTCString)) { + var date; + if (typeof options.expires == 'number') { + date = new Date(); + date.setTime(date.getTime() + (options.expires * 24 * 60 * 60 * 1000)); + } else { + date = options.expires; + } + expires = '; expires=' + date.toUTCString(); // use expires attribute, max-age is not supported by IE + } + // CAUTION: Needed to parenthesize options.path and options.domain + // in the following expressions, otherwise they evaluate to undefined + // in the packed version for some reason... + var path = options.path ? '; path=' + (options.path) : ''; + var domain = options.domain ? '; domain=' + (options.domain) : ''; + var secure = options.secure ? '; secure' : ''; + document.cookie = [name, '=', encodeURIComponent(value), expires, path, domain, secure].join(''); + } else { // only name given, get cookie + var cookieValue = null; + if (document.cookie && document.cookie != '') { + var cookies = document.cookie.split(';'); + for (var i = 0; i < cookies.length; i++) { + var cookie = jQuery.trim(cookies[i]); + // Does this cookie string begin with the name we want? + if (cookie.substring(0, name.length + 1) == (name + '=')) { + cookieValue = decodeURIComponent(cookie.substring(name.length + 1)); + break; + } + } + } + return cookieValue; + } +}; +/* + jQuery countdown - 0.2 + http://code.google.com/p/jquery-utils/ + + (c) Maxime Haineault + http://haineault.com + + MIT License (http://www.opensource.org/licenses/mit-license.php) + +*/ + +(function($) { + function countdown(el, options) { + var calc = function (target, current) { + /* Return true if the target date has arrived, + * an object of the time left otherwise. + */ + var current = current || new Date(); + if (current >= target) { return true; } + + var o = {}; + var remain = Math.floor((target.getTime() - current.getTime()) / 1000); + + o.days = Math.floor(remain / 86400); + remain %= 86400; + o.hours = Math.floor(remain / 3600); + remain %= 3600; + o.minutes = Math.floor(remain / 60); + remain %= 60; + o.seconds = remain; + o.years = Math.floor(o.days / 365); + o.months = Math.floor(o.days / 30); + o.weeks = Math.floor(o.days / 7); + + return o; + }; + + var getWeek = function(date) { + var onejan = new Date(date.getFullYear(),0,1); + return Math.ceil((((date - onejan) / 86400000) + onejan.getDay())/7); + }; + + var options = $.extend({ + date: new Date(), + modifiers: [], + interval: 1000, + msgFormat: '%d [day|days] %hh %mm %ss', + msgNow: 'Now !' + }, options); + + var tokens = { + y: new RegExp ('\\%y(.+?)\\[(\\w+)\\|(\\w+)\\]', 'g'), // years + M: new RegExp ('\\%M(.+?)\\[(\\w+)\\|(\\w+)\\]', 'g'), // months + w: new RegExp ('\\%w(.+?)\\[(\\w+)\\|(\\w+)\\]', 'g'), // weeks + d: new RegExp ('\\%d(.+?)\\[(\\w+)\\|(\\w+)\\]', 'g'), // days + h: new RegExp ('\\%h(.+?)\\[(\\w+)\\|(\\w+)\\]', 'g'), // hours + m: new RegExp ('\\%m(.+?)\\[(\\w+)\\|(\\w+)\\]', 'g'), // minutes + s: new RegExp ('\\%s(.+?)\\[(\\w+)\\|(\\w+)\\]', 'g') // seconds + }; + + var formatToken = function(str, token, val) { + return (!tokens[token])? '': str.match(/\[|\]/g) + && (str.replace(tokens[token], val+'$1'+ ((parseInt(val, 10)<2)?'$2':'$3')) || '') + || str.replace('%'+token, val); + }; + + var format = function(str, obj) { + var o = str; + o = formatToken(o, 'y', obj.years); + o = formatToken(o, 'M', obj.months); + o = formatToken(o, 'w', obj.weeks); + o = formatToken(o, 'd', obj.days); + o = formatToken(o, 'h', obj.hours); + o = formatToken(o, 'm', obj.minutes); + o = formatToken(o, 's', obj.seconds); + return o; + }; + + var update = function() { + var date_obj = calc(cd.date); + if (date_obj === true) { + cd.stop(); clearInterval(cd.id); + $(cd.el).html(options.msgNow); + return true; + } + else { + $(cd.el).text(format(options.msgFormat, date_obj)); + } + }; + + var apply_modifiers = function (modifiers, date) { + if (modifiers.length === 0) { + return date; + } + + var modifier_re = /^([+-]\d+)([yMdhms])$/; + var conversions = { + s: 1000, + m: 60 * 1000, + h: 60 * 60 * 1000, + d: 24 * 60 * 60 * 1000, + M: 30 * 24 * 60 * 60 * 1000, + y: 365 * 24 * 60 * 60 * 1000 + }; + + var displacement = 0; + for (var i = 0, n = modifiers.length; i < n; ++i) { + var match = modifiers[i].match(modifier_re); + if (match !== null) { + displacement += parseInt(match[1], 10) * conversions[match[2]]; + } + } + return new Date(date.getTime() + displacement); + }; + + var cd = { + id : setInterval(update, options.interval), + el : el, + start : function(){ return new countdown($(this.el), options); }, + stop : function(){ return clearInterval(this.id); }, + date : apply_modifiers(options.modifiers, options.date) + }; + $(el).data('countdown', cd); + update(); + return $(el).data('countdown'); + } + $.fn.countdown = function(args) { if(this.get(0)) return new countdown(this.get(0), args); }; +})(jQuery); +/* + * jQuery Cycle Plugin for light-weight slideshows + * Examples and documentation at: http://malsup.com/jquery/cycle/ + * Copyright (c) 2007-2008 M. Alsup + * Version: 2.24 (07/30/2008) + * Dual licensed under the MIT and GPL licenses: + * http://www.opensource.org/licenses/mit-license.php + * http://www.gnu.org/licenses/gpl.html + * Requires: jQuery v1.2.3 or later + * + * Based on the work of: + * 1) Matt Oakes (http://portfolio.gizone.co.uk/applications/slideshow/) + * 2) Torsten Baldes (http://medienfreunde.com/lab/innerfade/) + * 3) Benjamin Sterling (http://www.benjaminsterling.com/experiments/jqShuffle/) + */ +;(function($) { + +var ver = '2.24'; +var ie6 = $.browser.msie && /MSIE 6.0/.test(navigator.userAgent); + +function log() { + if (window.console && window.console.log) + window.console.log('[cycle] ' + Array.prototype.join.call(arguments,'')); +}; + +$.fn.cycle = function(options) { + return this.each(function() { + if (options === undefined || options === null) + options = {}; + if (options.constructor == String) { + switch(options) { + case 'stop': + if (this.cycleTimeout) clearTimeout(this.cycleTimeout); + this.cycleTimeout = 0; + $(this).data('cycle.opts', ''); + return; + case 'pause': + this.cyclePause = 1; + return; + case 'resume': + this.cyclePause = 0; + return; + default: + options = { fx: options }; + }; + } + else if (options.constructor == Number) { + // go to the requested slide slide + var num = options; + options = $(this).data('cycle.opts'); + if (!options) { + log('options not found, can not advance slide'); + return; + } + if (num < 0 || num >= options.elements.length) { + log('invalid slide index: ' + num); + return; + } + options.nextSlide = num; + if (this.cycleTimeout) { + clearTimeout(this.cycleTimeout); + this.cycleTimeout = 0; + } + go(options.elements, options, 1, 1); + return; + } + + // stop existing slideshow for this container (if there is one) + if (this.cycleTimeout) clearTimeout(this.cycleTimeout); + this.cycleTimeout = 0; + this.cyclePause = 0; + + var $cont = $(this); + var $slides = options.slideExpr ? $(options.slideExpr, this) : $cont.children(); + var els = $slides.get(); + if (els.length < 2) { + log('terminating; too few slides: ' + els.length); + return; // don't bother + } + + // support metadata plugin (v1.0 and v2.0) + var opts = $.extend({}, $.fn.cycle.defaults, options || {}, $.metadata ? $cont.metadata() : $.meta ? $cont.data() : {}); + if (opts.autostop) + opts.countdown = opts.autostopCount || els.length; + + $cont.data('cycle.opts', opts); + opts.container = this; + + opts.elements = els; + opts.before = opts.before ? [opts.before] : []; + opts.after = opts.after ? [opts.after] : []; + opts.after.unshift(function(){ opts.busy=0; }); + if (opts.continuous) + opts.after.push(function() { go(els,opts,0,!opts.rev); }); + + // clearType corrections + if (ie6 && opts.cleartype && !opts.cleartypeNoBg) + clearTypeFix($slides); + + // allow shorthand overrides of width, height and timeout + var cls = this.className; + opts.width = parseInt((cls.match(/w:(\d+)/)||[])[1]) || opts.width; + opts.height = parseInt((cls.match(/h:(\d+)/)||[])[1]) || opts.height; + opts.timeout = parseInt((cls.match(/t:(\d+)/)||[])[1]) || opts.timeout; + + if ($cont.css('position') == 'static') + $cont.css('position', 'relative'); + if (opts.width) + $cont.width(opts.width); + if (opts.height && opts.height != 'auto') + $cont.height(opts.height); + + if (opts.random) { + opts.randomMap = []; + for (var i = 0; i < els.length; i++) + opts.randomMap.push(i); + opts.randomMap.sort(function(a,b) {return Math.random() - 0.5;}); + opts.randomIndex = 0; + opts.startingSlide = opts.randomMap[0]; + } + else if (opts.startingSlide >= els.length) + opts.startingSlide = 0; // catch bogus input + var first = opts.startingSlide || 0; + $slides.css({position: 'absolute', top:0, left:0}).hide().each(function(i) { + var z = first ? i >= first ? els.length - (i-first) : first-i : els.length-i; + $(this).css('z-index', z) + }); + + $(els[first]).css('opacity',1).show(); // opacity bit needed to handle reinit case + if ($.browser.msie) els[first].style.removeAttribute('filter'); + + if (opts.fit && opts.width) + $slides.width(opts.width); + if (opts.fit && opts.height && opts.height != 'auto') + $slides.height(opts.height); + if (opts.pause) + $cont.hover(function(){this.cyclePause=1;},function(){this.cyclePause=0;}); + + // run transition init fn + var init = $.fn.cycle.transitions[opts.fx]; + if ($.isFunction(init)) + init($cont, $slides, opts); + else if (opts.fx != 'custom') + log('unknown transition: ' + opts.fx); + + $slides.each(function() { + var $el = $(this); + this.cycleH = (opts.fit && opts.height) ? opts.height : $el.height(); + this.cycleW = (opts.fit && opts.width) ? opts.width : $el.width(); + }); + + opts.cssBefore = opts.cssBefore || {}; + opts.animIn = opts.animIn || {}; + opts.animOut = opts.animOut || {}; + + $slides.not(':eq('+first+')').css(opts.cssBefore); + if (opts.cssFirst) + $($slides[first]).css(opts.cssFirst); + + if (opts.timeout) { + // ensure that timeout and speed settings are sane + if (opts.speed.constructor == String) + opts.speed = {slow: 600, fast: 200}[opts.speed] || 400; + if (!opts.sync) + opts.speed = opts.speed / 2; + while((opts.timeout - opts.speed) < 250) + opts.timeout += opts.speed; + } + if (opts.easing) + opts.easeIn = opts.easeOut = opts.easing; + if (!opts.speedIn) + opts.speedIn = opts.speed; + if (!opts.speedOut) + opts.speedOut = opts.speed; + + opts.slideCount = els.length; + opts.currSlide = first; + if (opts.random) { + opts.nextSlide = opts.currSlide; + if (++opts.randomIndex == els.length) + opts.randomIndex = 0; + opts.nextSlide = opts.randomMap[opts.randomIndex]; + } + else + opts.nextSlide = opts.startingSlide >= (els.length-1) ? 0 : opts.startingSlide+1; + + // fire artificial events + var e0 = $slides[first]; + if (opts.before.length) + opts.before[0].apply(e0, [e0, e0, opts, true]); + if (opts.after.length > 1) + opts.after[1].apply(e0, [e0, e0, opts, true]); + + if (opts.click && !opts.next) + opts.next = opts.click; + if (opts.next) + $(opts.next).bind('click', function(){return advance(els,opts,opts.rev?-1:1)}); + if (opts.prev) + $(opts.prev).bind('click', function(){return advance(els,opts,opts.rev?1:-1)}); + if (opts.pager) + buildPager(els,opts); + + // expose fn for adding slides after the show has started + opts.addSlide = function(newSlide) { + var $s = $(newSlide), s = $s[0]; + if (!opts.autostopCount) + opts.countdown++; + els.push(s); + if (opts.els) + opts.els.push(s); // shuffle needs this + opts.slideCount = els.length; + + $s.css('position','absolute').appendTo($cont); + + if (ie6 && opts.cleartype && !opts.cleartypeNoBg) + clearTypeFix($s); + + if (opts.fit && opts.width) + $s.width(opts.width); + if (opts.fit && opts.height && opts.height != 'auto') + $slides.height(opts.height); + s.cycleH = (opts.fit && opts.height) ? opts.height : $s.height(); + s.cycleW = (opts.fit && opts.width) ? opts.width : $s.width(); + + $s.css(opts.cssBefore); + + if (opts.pager) + $.fn.cycle.createPagerAnchor(els.length-1, s, $(opts.pager), els, opts); + + if (typeof opts.onAddSlide == 'function') + opts.onAddSlide($s); + }; + + if (opts.timeout || opts.continuous) + this.cycleTimeout = setTimeout( + function(){go(els,opts,0,!opts.rev)}, + opts.continuous ? 10 : opts.timeout + (opts.delay||0)); + }); +}; + +function go(els, opts, manual, fwd) { + if (opts.busy) return; + var p = opts.container, curr = els[opts.currSlide], next = els[opts.nextSlide]; + if (p.cycleTimeout === 0 && !manual) + return; + + if (!manual && !p.cyclePause && + ((opts.autostop && (--opts.countdown <= 0)) || + (opts.nowrap && !opts.random && opts.nextSlide < opts.currSlide))) { + if (opts.end) + opts.end(opts); + return; + } + + if (manual || !p.cyclePause) { + if (opts.before.length) + $.each(opts.before, function(i,o) { o.apply(next, [curr, next, opts, fwd]); }); + var after = function() { + if ($.browser.msie && opts.cleartype) + this.style.removeAttribute('filter'); + $.each(opts.after, function(i,o) { o.apply(next, [curr, next, opts, fwd]); }); + }; + + if (opts.nextSlide != opts.currSlide) { + opts.busy = 1; + if (opts.fxFn) + opts.fxFn(curr, next, opts, after, fwd); + else if ($.isFunction($.fn.cycle[opts.fx])) + $.fn.cycle[opts.fx](curr, next, opts, after); + else + $.fn.cycle.custom(curr, next, opts, after); + } + if (opts.random) { + opts.currSlide = opts.nextSlide; + if (++opts.randomIndex == els.length) + opts.randomIndex = 0; + opts.nextSlide = opts.randomMap[opts.randomIndex]; + } + else { // sequence + var roll = (opts.nextSlide + 1) == els.length; + opts.nextSlide = roll ? 0 : opts.nextSlide+1; + opts.currSlide = roll ? els.length-1 : opts.nextSlide-1; + } + if (opts.pager) + $.fn.cycle.updateActivePagerLink(opts.pager, opts.currSlide); + } + if (opts.timeout && !opts.continuous) + p.cycleTimeout = setTimeout(function() { go(els,opts,0,!opts.rev) }, opts.timeout); + else if (opts.continuous && p.cyclePause) + p.cycleTimeout = setTimeout(function() { go(els,opts,0,!opts.rev) }, 10); +}; + +$.fn.cycle.updateActivePagerLink = function(pager, currSlide) { + $(pager).find('a').removeClass('activeSlide').filter('a:eq('+currSlide+')').addClass('activeSlide'); +}; + +// advance slide forward or back +function advance(els, opts, val) { + var p = opts.container, timeout = p.cycleTimeout; + if (timeout) { + clearTimeout(timeout); + p.cycleTimeout = 0; + } + if (opts.random && val < 0) { + // move back to the previously display slide + opts.randomIndex--; + if (--opts.randomIndex == -2) + opts.randomIndex = els.length-2; + else if (opts.randomIndex == -1) + opts.randomIndex = els.length-1; + opts.nextSlide = opts.randomMap[opts.randomIndex]; + } + else if (opts.random) { + if (++opts.randomIndex == els.length) + opts.randomIndex = 0; + opts.nextSlide = opts.randomMap[opts.randomIndex]; + } + else { + opts.nextSlide = opts.currSlide + val; + if (opts.nextSlide < 0) { + if (opts.nowrap) return false; + opts.nextSlide = els.length - 1; + } + else if (opts.nextSlide >= els.length) { + if (opts.nowrap) return false; + opts.nextSlide = 0; + } + } + +log('nextSlide: ' + opts.nextSlide + '; randomIndex: ' + opts.randomIndex); + if (opts.prevNextClick && typeof opts.prevNextClick == 'function') + opts.prevNextClick(val > 0, opts.nextSlide, els[opts.nextSlide]); + go(els, opts, 1, val>=0); + return false; +}; + +function buildPager(els, opts) { + var $p = $(opts.pager); + $.each(els, function(i,o) { + $.fn.cycle.createPagerAnchor(i,o,$p,els,opts); + }); + $.fn.cycle.updateActivePagerLink(opts.pager, opts.startingSlide); +}; + +$.fn.cycle.createPagerAnchor = function(i, el, $p, els, opts) { + var $a = (typeof opts.pagerAnchorBuilder == 'function') + ? $(opts.pagerAnchorBuilder(i,el)) + : $(''+(i+1)+''); + + // don't reparent if anchor is in the dom + if ($a.parents('body').length == 0) + $a.appendTo($p); + + $a.bind(opts.pagerEvent, function() { + opts.nextSlide = i; + var p = opts.container, timeout = p.cycleTimeout; + if (timeout) { + clearTimeout(timeout); + p.cycleTimeout = 0; + } + if (typeof opts.pagerClick == 'function') + opts.pagerClick(opts.nextSlide, els[opts.nextSlide]); + go(els,opts,1,opts.currSlide < i); + return false; + }); +}; + + +// this fixes clearType problems in ie6 by setting an explicit bg color +function clearTypeFix($slides) { + function hex(s) { + var s = parseInt(s).toString(16); + return s.length < 2 ? '0'+s : s; + }; + function getBg(e) { + for ( ; e && e.nodeName.toLowerCase() != 'html'; e = e.parentNode) { + var v = $.css(e,'background-color'); + if (v.indexOf('rgb') >= 0 ) { + var rgb = v.match(/\d+/g); + return '#'+ hex(rgb[0]) + hex(rgb[1]) + hex(rgb[2]); + } + if (v && v != 'transparent') + return v; + } + return '#ffffff'; + }; + $slides.each(function() { $(this).css('background-color', getBg(this)); }); +}; + + +$.fn.cycle.custom = function(curr, next, opts, cb) { + var $l = $(curr), $n = $(next); + $n.css(opts.cssBefore); + var fn = function() {$n.animate(opts.animIn, opts.speedIn, opts.easeIn, cb)}; + $l.animate(opts.animOut, opts.speedOut, opts.easeOut, function() { + if (opts.cssAfter) $l.css(opts.cssAfter); + if (!opts.sync) fn(); + }); + if (opts.sync) fn(); +}; + +$.fn.cycle.transitions = { + fade: function($cont, $slides, opts) { + $slides.not(':eq('+opts.startingSlide+')').css('opacity',0); + opts.before.push(function() { $(this).show() }); + opts.animIn = { opacity: 1 }; + opts.animOut = { opacity: 0 }; + opts.cssBefore = { opacity: 0 }; + opts.cssAfter = { display: 'none' }; + } +}; + +$.fn.cycle.ver = function() { return ver; }; + +// override these globally if you like (they are all optional) +$.fn.cycle.defaults = { + fx: 'fade', // one of: fade, shuffle, zoom, scrollLeft, etc + timeout: 4000, // milliseconds between slide transitions (0 to disable auto advance) + continuous: 0, // true to start next transition immediately after current one completes + speed: 1000, // speed of the transition (any valid fx speed value) + speedIn: null, // speed of the 'in' transition + speedOut: null, // speed of the 'out' transition + next: null, // id of element to use as click trigger for next slide + prev: null, // id of element to use as click trigger for previous slide + prevNextClick: null, // callback fn for prev/next clicks: function(isNext, zeroBasedSlideIndex, slideElement) + pager: null, // id of element to use as pager container + pagerClick: null, // callback fn for pager clicks: function(zeroBasedSlideIndex, slideElement) + pagerEvent: 'click', // event which drives the pager navigation + pagerAnchorBuilder: null, // callback fn for building anchor links + before: null, // transition callback (scope set to element to be shown) + after: null, // transition callback (scope set to element that was shown) + end: null, // callback invoked when the slideshow terminates (use with autostop or nowrap options) + easing: null, // easing method for both in and out transitions + easeIn: null, // easing for "in" transition + easeOut: null, // easing for "out" transition + shuffle: null, // coords for shuffle animation, ex: { top:15, left: 200 } + animIn: null, // properties that define how the slide animates in + animOut: null, // properties that define how the slide animates out + cssBefore: null, // properties that define the initial state of the slide before transitioning in + cssAfter: null, // properties that defined the state of the slide after transitioning out + fxFn: null, // function used to control the transition + height: 'auto', // container height + startingSlide: 0, // zero-based index of the first slide to be displayed + sync: 1, // true if in/out transitions should occur simultaneously + random: 0, // true for random, false for sequence (not applicable to shuffle fx) + fit: 0, // force slides to fit container + pause: 0, // true to enable "pause on hover" + autostop: 0, // true to end slideshow after X transitions (where X == slide count) + autostopCount: 0, // number of transitions (optionally used with autostop to define X) + delay: 0, // additional delay (in ms) for first transition (hint: can be negative) + slideExpr: null, // expression for selecting slides (if something other than all children is required) + cleartype: 0, // true if clearType corrections should be applied (for IE) + nowrap: 0 // true to prevent slideshow from wrapping +}; + +})(jQuery); + + +/* + * jQuery Cycle Plugin Transition Definitions + * This script is a plugin for the jQuery Cycle Plugin + * Examples and documentation at: http://malsup.com/jquery/cycle/ + * Copyright (c) 2007-2008 M. Alsup + * Version: 2.22 + * Dual licensed under the MIT and GPL licenses: + * http://www.opensource.org/licenses/mit-license.php + * http://www.gnu.org/licenses/gpl.html + */ +(function($) { + +// +// These functions define one-time slide initialization for the named +// transitions. To save file size feel free to remove any of these that you +// don't need. +// + +// scrollUp/Down/Left/Right +$.fn.cycle.transitions.scrollUp = function($cont, $slides, opts) { + $cont.css('overflow','hidden'); + opts.before.push(function(curr, next, opts) { + $(this).show(); + opts.cssBefore.top = next.offsetHeight; + opts.animOut.top = 0-curr.offsetHeight; + }); + opts.cssFirst = { top: 0 }; + opts.animIn = { top: 0 }; + opts.cssAfter = { display: 'none' }; +}; +$.fn.cycle.transitions.scrollDown = function($cont, $slides, opts) { + $cont.css('overflow','hidden'); + opts.before.push(function(curr, next, opts) { + $(this).show(); + opts.cssBefore.top = 0-next.offsetHeight; + opts.animOut.top = curr.offsetHeight; + }); + opts.cssFirst = { top: 0 }; + opts.animIn = { top: 0 }; + opts.cssAfter = { display: 'none' }; +}; +$.fn.cycle.transitions.scrollLeft = function($cont, $slides, opts) { + $cont.css('overflow','hidden'); + opts.before.push(function(curr, next, opts) { + $(this).show(); + opts.cssBefore.left = next.offsetWidth; + opts.animOut.left = 0-curr.offsetWidth; + }); + opts.cssFirst = { left: 0 }; + opts.animIn = { left: 0 }; +}; +$.fn.cycle.transitions.scrollRight = function($cont, $slides, opts) { + $cont.css('overflow','hidden'); + opts.before.push(function(curr, next, opts) { + $(this).show(); + opts.cssBefore.left = 0-next.offsetWidth; + opts.animOut.left = curr.offsetWidth; + }); + opts.cssFirst = { left: 0 }; + opts.animIn = { left: 0 }; +}; +$.fn.cycle.transitions.scrollHorz = function($cont, $slides, opts) { + $cont.css('overflow','hidden').width(); +// $slides.show(); + opts.before.push(function(curr, next, opts, fwd) { + $(this).show(); + var currW = curr.offsetWidth, nextW = next.offsetWidth; + opts.cssBefore = fwd ? { left: nextW } : { left: -nextW }; + opts.animIn.left = 0; + opts.animOut.left = fwd ? -currW : currW; + $slides.not(curr).css(opts.cssBefore); + }); + opts.cssFirst = { left: 0 }; + opts.cssAfter = { display: 'none' } +}; +$.fn.cycle.transitions.scrollVert = function($cont, $slides, opts) { + $cont.css('overflow','hidden'); +// $slides.show(); + opts.before.push(function(curr, next, opts, fwd) { + $(this).show(); + var currH = curr.offsetHeight, nextH = next.offsetHeight; + opts.cssBefore = fwd ? { top: -nextH } : { top: nextH }; + opts.animIn.top = 0; + opts.animOut.top = fwd ? currH : -currH; + $slides.not(curr).css(opts.cssBefore); + }); + opts.cssFirst = { top: 0 }; + opts.cssAfter = { display: 'none' } +}; + +// slideX/slideY +$.fn.cycle.transitions.slideX = function($cont, $slides, opts) { + opts.before.push(function(curr, next, opts) { + $(curr).css('zIndex',1); + }); + opts.onAddSlide = function($s) { $s.hide(); }; + opts.cssBefore = { zIndex: 2 }; + opts.animIn = { width: 'show' }; + opts.animOut = { width: 'hide' }; +}; +$.fn.cycle.transitions.slideY = function($cont, $slides, opts) { + opts.before.push(function(curr, next, opts) { + $(curr).css('zIndex',1); + }); + opts.onAddSlide = function($s) { $s.hide(); }; + opts.cssBefore = { zIndex: 2 }; + opts.animIn = { height: 'show' }; + opts.animOut = { height: 'hide' }; +}; + +// shuffle +$.fn.cycle.transitions.shuffle = function($cont, $slides, opts) { + var w = $cont.css('overflow', 'visible').width(); + $slides.css({left: 0, top: 0}); + opts.before.push(function() { $(this).show() }); + opts.speed = opts.speed / 2; // shuffle has 2 transitions + opts.random = 0; + opts.shuffle = opts.shuffle || {left:-w, top:15}; + opts.els = []; + for (var i=0; i < $slides.length; i++) + opts.els.push($slides[i]); + + for (var i=0; i < opts.startingSlide; i++) + opts.els.push(opts.els.shift()); + + // custom transition fn (hat tip to Benjamin Sterling for this bit of sweetness!) + opts.fxFn = function(curr, next, opts, cb, fwd) { + var $el = fwd ? $(curr) : $(next); + $el.animate(opts.shuffle, opts.speedIn, opts.easeIn, function() { + fwd ? opts.els.push(opts.els.shift()) : opts.els.unshift(opts.els.pop()); + if (fwd) + for (var i=0, len=opts.els.length; i < len; i++) + $(opts.els[i]).css('z-index', len-i); + else { + var z = $(curr).css('z-index'); + $el.css('z-index', parseInt(z)+1); + } + $el.animate({left:0, top:0}, opts.speedOut, opts.easeOut, function() { + $(fwd ? this : curr).hide(); + if (cb) cb(); + }); + }); + }; + opts.onAddSlide = function($s) { $s.hide(); }; +}; + +// turnUp/Down/Left/Right +$.fn.cycle.transitions.turnUp = function($cont, $slides, opts) { + opts.before.push(function(curr, next, opts) { + $(this).show(); + opts.cssBefore.top = next.cycleH; + opts.animIn.height = next.cycleH; + }); + opts.onAddSlide = function($s) { $s.hide(); }; + opts.cssFirst = { top: 0 }; + opts.cssBefore = { height: 0 }; + opts.animIn = { top: 0 }; + opts.animOut = { height: 0 }; + opts.cssAfter = { display: 'none' }; +}; +$.fn.cycle.transitions.turnDown = function($cont, $slides, opts) { + opts.before.push(function(curr, next, opts) { + $(this).show(); + opts.animIn.height = next.cycleH; + opts.animOut.top = curr.cycleH; + }); + opts.onAddSlide = function($s) { $s.hide(); }; + opts.cssFirst = { top: 0 }; + opts.cssBefore = { top: 0, height: 0 }; + opts.animOut = { height: 0 }; + opts.cssAfter = { display: 'none' }; +}; +$.fn.cycle.transitions.turnLeft = function($cont, $slides, opts) { + opts.before.push(function(curr, next, opts) { + $(this).show(); + opts.cssBefore.left = next.cycleW; + opts.animIn.width = next.cycleW; + }); + opts.onAddSlide = function($s) { $s.hide(); }; + opts.cssBefore = { width: 0 }; + opts.animIn = { left: 0 }; + opts.animOut = { width: 0 }; + opts.cssAfter = { display: 'none' }; +}; +$.fn.cycle.transitions.turnRight = function($cont, $slides, opts) { + opts.before.push(function(curr, next, opts) { + $(this).show(); + opts.animIn.width = next.cycleW; + opts.animOut.left = curr.cycleW; + }); + opts.onAddSlide = function($s) { $s.hide(); }; + opts.cssBefore = { left: 0, width: 0 }; + opts.animIn = { left: 0 }; + opts.animOut = { width: 0 }; + opts.cssAfter = { display: 'none' }; +}; + +// zoom +$.fn.cycle.transitions.zoom = function($cont, $slides, opts) { + opts.cssFirst = { top:0, left: 0 }; + opts.cssAfter = { display: 'none' }; + + opts.before.push(function(curr, next, opts) { + $(this).show(); + opts.cssBefore = { width: 0, height: 0, top: next.cycleH/2, left: next.cycleW/2 }; + opts.cssAfter = { display: 'none' }; + opts.animIn = { top: 0, left: 0, width: next.cycleW, height: next.cycleH }; + opts.animOut = { width: 0, height: 0, top: curr.cycleH/2, left: curr.cycleW/2 }; + $(curr).css('zIndex',2); + $(next).css('zIndex',1); + }); + opts.onAddSlide = function($s) { $s.hide(); }; +}; + +// fadeZoom +$.fn.cycle.transitions.fadeZoom = function($cont, $slides, opts) { + opts.before.push(function(curr, next, opts) { + opts.cssBefore = { width: 0, height: 0, opacity: 1, left: next.cycleW/2, top: next.cycleH/2, zIndex: 1 }; + opts.animIn = { top: 0, left: 0, width: next.cycleW, height: next.cycleH }; + }); + opts.animOut = { opacity: 0 }; + opts.cssAfter = { zIndex: 0 }; +}; + +// blindX +$.fn.cycle.transitions.blindX = function($cont, $slides, opts) { + var w = $cont.css('overflow','hidden').width(); + $slides.show(); + opts.before.push(function(curr, next, opts) { + $(curr).css('zIndex',1); + }); + opts.cssBefore = { left: w, zIndex: 2 }; + opts.cssAfter = { zIndex: 1 }; + opts.animIn = { left: 0 }; + opts.animOut = { left: w }; +}; +// blindY +$.fn.cycle.transitions.blindY = function($cont, $slides, opts) { + var h = $cont.css('overflow','hidden').height(); + $slides.show(); + opts.before.push(function(curr, next, opts) { + $(curr).css('zIndex',1); + }); + opts.cssBefore = { top: h, zIndex: 2 }; + opts.cssAfter = { zIndex: 1 }; + opts.animIn = { top: 0 }; + opts.animOut = { top: h }; +}; +// blindZ +$.fn.cycle.transitions.blindZ = function($cont, $slides, opts) { + var h = $cont.css('overflow','hidden').height(); + var w = $cont.width(); + $slides.show(); + opts.before.push(function(curr, next, opts) { + $(curr).css('zIndex',1); + }); + opts.cssBefore = { top: h, left: w, zIndex: 2 }; + opts.cssAfter = { zIndex: 1 }; + opts.animIn = { top: 0, left: 0 }; + opts.animOut = { top: h, left: w }; +}; + +// growX - grow horizontally from centered 0 width +$.fn.cycle.transitions.growX = function($cont, $slides, opts) { + opts.before.push(function(curr, next, opts) { + opts.cssBefore = { left: this.cycleW/2, width: 0, zIndex: 2 }; + opts.animIn = { left: 0, width: this.cycleW }; + opts.animOut = { left: 0 }; + $(curr).css('zIndex',1); + }); + opts.onAddSlide = function($s) { $s.hide().css('zIndex',1); }; +}; +// growY - grow vertically from centered 0 height +$.fn.cycle.transitions.growY = function($cont, $slides, opts) { + opts.before.push(function(curr, next, opts) { + opts.cssBefore = { top: this.cycleH/2, height: 0, zIndex: 2 }; + opts.animIn = { top: 0, height: this.cycleH }; + opts.animOut = { top: 0 }; + $(curr).css('zIndex',1); + }); + opts.onAddSlide = function($s) { $s.hide().css('zIndex',1); }; +}; + +// curtainX - squeeze in both edges horizontally +$.fn.cycle.transitions.curtainX = function($cont, $slides, opts) { + opts.before.push(function(curr, next, opts) { + opts.cssBefore = { left: next.cycleW/2, width: 0, zIndex: 1, display: 'block' }; + opts.animIn = { left: 0, width: this.cycleW }; + opts.animOut = { left: curr.cycleW/2, width: 0 }; + $(curr).css('zIndex',2); + }); + opts.onAddSlide = function($s) { $s.hide(); }; + opts.cssAfter = { zIndex: 1, display: 'none' }; +}; +// curtainY - squeeze in both edges vertically +$.fn.cycle.transitions.curtainY = function($cont, $slides, opts) { + opts.before.push(function(curr, next, opts) { + opts.cssBefore = { top: next.cycleH/2, height: 0, zIndex: 1, display: 'block' }; + opts.animIn = { top: 0, height: this.cycleH }; + opts.animOut = { top: curr.cycleH/2, height: 0 }; + $(curr).css('zIndex',2); + }); + opts.onAddSlide = function($s) { $s.hide(); }; + opts.cssAfter = { zIndex: 1, display: 'none' }; +}; + +// cover - curr slide covered by next slide +$.fn.cycle.transitions.cover = function($cont, $slides, opts) { + var d = opts.direction || 'left'; + var w = $cont.css('overflow','hidden').width(); + var h = $cont.height(); + opts.before.push(function(curr, next, opts) { + opts.cssBefore = opts.cssBefore || {}; + opts.cssBefore.zIndex = 2; + opts.cssBefore.display = 'block'; + + if (d == 'right') + opts.cssBefore.left = -w; + else if (d == 'up') + opts.cssBefore.top = h; + else if (d == 'down') + opts.cssBefore.top = -h; + else + opts.cssBefore.left = w; + $(curr).css('zIndex',1); + }); + if (!opts.animIn) opts.animIn = { left: 0, top: 0 }; + if (!opts.animOut) opts.animOut = { left: 0, top: 0 }; + opts.cssAfter = opts.cssAfter || {}; + opts.cssAfter.zIndex = 2; + opts.cssAfter.display = 'none'; +}; + +// uncover - curr slide moves off next slide +$.fn.cycle.transitions.uncover = function($cont, $slides, opts) { + var d = opts.direction || 'left'; + var w = $cont.css('overflow','hidden').width(); + var h = $cont.height(); + opts.before.push(function(curr, next, opts) { + opts.cssBefore.display = 'block'; + if (d == 'right') + opts.animOut.left = w; + else if (d == 'up') + opts.animOut.top = -h; + else if (d == 'down') + opts.animOut.top = h; + else + opts.animOut.left = -w; + $(curr).css('zIndex',2); + $(next).css('zIndex',1); + }); + opts.onAddSlide = function($s) { $s.hide(); }; + if (!opts.animIn) opts.animIn = { left: 0, top: 0 }; + opts.cssBefore = opts.cssBefore || {}; + opts.cssBefore.top = 0; + opts.cssBefore.left = 0; + + opts.cssAfter = opts.cssAfter || {}; + opts.cssAfter.zIndex = 1; + opts.cssAfter.display = 'none'; +}; + +// toss - move top slide and fade away +$.fn.cycle.transitions.toss = function($cont, $slides, opts) { + var w = $cont.css('overflow','visible').width(); + var h = $cont.height(); + opts.before.push(function(curr, next, opts) { + $(curr).css('zIndex',2); + opts.cssBefore.display = 'block'; + // provide default toss settings if animOut not provided + if (!opts.animOut.left && !opts.animOut.top) + opts.animOut = { left: w*2, top: -h/2, opacity: 0 }; + else + opts.animOut.opacity = 0; + }); + opts.onAddSlide = function($s) { $s.hide(); }; + opts.cssBefore = { left: 0, top: 0, zIndex: 1, opacity: 1 }; + opts.animIn = { left: 0 }; + opts.cssAfter = { zIndex: 2, display: 'none' }; +}; + +// wipe - clip animation +$.fn.cycle.transitions.wipe = function($cont, $slides, opts) { + var w = $cont.css('overflow','hidden').width(); + var h = $cont.height(); + opts.cssBefore = opts.cssBefore || {}; + var clip; + if (opts.clip) { + if (/l2r/.test(opts.clip)) + clip = 'rect(0px 0px '+h+'px 0px)'; + else if (/r2l/.test(opts.clip)) + clip = 'rect(0px '+w+'px '+h+'px '+w+'px)'; + else if (/t2b/.test(opts.clip)) + clip = 'rect(0px '+w+'px 0px 0px)'; + else if (/b2t/.test(opts.clip)) + clip = 'rect('+h+'px '+w+'px '+h+'px 0px)'; + else if (/zoom/.test(opts.clip)) { + var t = parseInt(h/2); + var l = parseInt(w/2); + clip = 'rect('+t+'px '+l+'px '+t+'px '+l+'px)'; + } + } + + opts.cssBefore.clip = opts.cssBefore.clip || clip || 'rect(0px 0px 0px 0px)'; + + var d = opts.cssBefore.clip.match(/(\d+)/g); + var t = parseInt(d[0]), r = parseInt(d[1]), b = parseInt(d[2]), l = parseInt(d[3]); + + opts.before.push(function(curr, next, opts) { + if (curr == next) return; + var $curr = $(curr).css('zIndex',2); + var $next = $(next).css({ + zIndex: 3, + display: 'block' + }); + + var step = 1, count = parseInt((opts.speedIn / 13)) - 1; + function f() { + var tt = t ? t - parseInt(step * (t/count)) : 0; + var ll = l ? l - parseInt(step * (l/count)) : 0; + var bb = b < h ? b + parseInt(step * ((h-b)/count || 1)) : h; + var rr = r < w ? r + parseInt(step * ((w-r)/count || 1)) : w; + $next.css({ clip: 'rect('+tt+'px '+rr+'px '+bb+'px '+ll+'px)' }); + (step++ <= count) ? setTimeout(f, 13) : $curr.css('display', 'none'); + } + f(); + }); + opts.cssAfter = { }; + opts.animIn = { left: 0 }; + opts.animOut = { left: 0 }; +}; + +})(jQuery); +/* + jQuery delayed observer - 0.8 + http://code.google.com/p/jquery-utils/ + + (c) Maxime Haineault + http://haineault.com + + MIT License (http://www.opensource.org/licenses/mit-license.php) + +*/ + +(function($){ + $.extend($.fn, { + delayedObserver: function(callback, delay, options){ + return this.each(function(){ + var el = $(this); + var op = options || {}; + el.data('oldval', el.val()) + .data('delay', delay || 0.5) + .data('condition', op.condition || function() { return ($(this).data('oldval') == $(this).val()); }) + .data('callback', callback) + [(op.event||'keyup')](function(){ + if (el.data('condition').apply(el)) { return; } + else { + if (el.data('timer')) { clearTimeout(el.data('timer')); } + el.data('timer', setTimeout(function(){ + el.data('callback').apply(el); + }, el.data('delay') * 1000)); + el.data('oldval', el.val()); + } + }); + }); + } + }); +})(jQuery); +/** + * Flash (http://jquery.lukelutman.com/plugins/flash) + * A jQuery plugin for embedding Flash movies. + * + * Version 1.0 + * November 9th, 2006 + * + * Copyright (c) 2006 Luke Lutman (http://www.lukelutman.com) + * Dual licensed under the MIT and GPL licenses. + * http://www.opensource.org/licenses/mit-license.php + * http://www.opensource.org/licenses/gpl-license.php + * + * Inspired by: + * SWFObject (http://blog.deconcept.com/swfobject/) + * UFO (http://www.bobbyvandersluis.com/ufo/) + * sIFR (http://www.mikeindustries.com/sifr/) + * + * IMPORTANT: + * The packed version of jQuery breaks ActiveX control + * activation in Internet Explorer. Use JSMin to minifiy + * jQuery (see: http://jquery.lukelutman.com/plugins/flash#activex). + * + **/ +;(function(){ + +var $$; + +/** + * + * @desc Replace matching elements with a flash movie. + * @author Luke Lutman + * @version 1.0.1 + * + * @name flash + * @param Hash htmlOptions Options for the embed/object tag. + * @param Hash pluginOptions Options for detecting/updating the Flash plugin (optional). + * @param Function replace Custom block called for each matched element if flash is installed (optional). + * @param Function update Custom block called for each matched if flash isn't installed (optional). + * @type jQuery + * + * @cat plugins/flash + * + * @example $('#hello').flash({ src: 'hello.swf' }); + * @desc Embed a Flash movie. + * + * @example $('#hello').flash({ src: 'hello.swf' }, { version: 8 }); + * @desc Embed a Flash 8 movie. + * + * @example $('#hello').flash({ src: 'hello.swf' }, { expressInstall: true }); + * @desc Embed a Flash movie using Express Install if flash isn't installed. + * + * @example $('#hello').flash({ src: 'hello.swf' }, { update: false }); + * @desc Embed a Flash movie, don't show an update message if Flash isn't installed. + * +**/ +$$ = jQuery.fn.flash = function(htmlOptions, pluginOptions, replace, update) { + + // Set the default block. + var block = replace || $$.replace; + + // Merge the default and passed plugin options. + pluginOptions = $$.copy($$.pluginOptions, pluginOptions); + + // Detect Flash. + if(!$$.hasFlash(pluginOptions.version)) { + // Use Express Install (if specified and Flash plugin 6,0,65 or higher is installed). + if(pluginOptions.expressInstall && $$.hasFlash(6,0,65)) { + // Add the necessary flashvars (merged later). + var expressInstallOptions = { + flashvars: { + MMredirectURL: location, + MMplayerType: 'PlugIn', + MMdoctitle: jQuery('title').text() + } + }; + // Ask the user to update (if specified). + } else if (pluginOptions.update) { + // Change the block to insert the update message instead of the flash movie. + block = update || $$.update; + // Fail + } else { + // The required version of flash isn't installed. + // Express Install is turned off, or flash 6,0,65 isn't installed. + // Update is turned off. + // Return without doing anything. + return this; + } + } + + // Merge the default, express install and passed html options. + htmlOptions = $$.copy($$.htmlOptions, expressInstallOptions, htmlOptions); + + // Invoke $block (with a copy of the merged html options) for each element. + return this.each(function(){ + block.call(this, $$.copy(htmlOptions)); + }); + +}; +/** + * + * @name flash.copy + * @desc Copy an arbitrary number of objects into a new object. + * @type Object + * + * @example $$.copy({ foo: 1 }, { bar: 2 }); + * @result { foo: 1, bar: 2 }; + * +**/ +$$.copy = function() { + var options = {}, flashvars = {}; + for(var i = 0; i < arguments.length; i++) { + var arg = arguments[i]; + if(arg == undefined) continue; + jQuery.extend(options, arg); + // don't clobber one flash vars object with another + // merge them instead + if(arg.flashvars == undefined) continue; + jQuery.extend(flashvars, arg.flashvars); + } + options.flashvars = flashvars; + return options; +}; +/* + * @name flash.hasFlash + * @desc Check if a specific version of the Flash plugin is installed + * @type Boolean + * +**/ +$$.hasFlash = function() { + // look for a flag in the query string to bypass flash detection + if(/hasFlash\=true/.test(location)) return true; + if(/hasFlash\=false/.test(location)) return false; + var pv = $$.hasFlash.playerVersion().match(/\d+/g); + var rv = String([arguments[0], arguments[1], arguments[2]]).match(/\d+/g) || String($$.pluginOptions.version).match(/\d+/g); + for(var i = 0; i < 3; i++) { + pv[i] = parseInt(pv[i] || 0); + rv[i] = parseInt(rv[i] || 0); + // player is less than required + if(pv[i] < rv[i]) return false; + // player is greater than required + if(pv[i] > rv[i]) return true; + } + // major version, minor version and revision match exactly + return true; +}; +/** + * + * @name flash.hasFlash.playerVersion + * @desc Get the version of the installed Flash plugin. + * @type String + * +**/ +$$.hasFlash.playerVersion = function() { + // ie + try { + try { + // avoid fp6 minor version lookup issues + // see: http://blog.deconcept.com/2006/01/11/getvariable-setvariable-crash-internet-explorer-flash-6/ + var axo = new ActiveXObject('ShockwaveFlash.ShockwaveFlash.6'); + try { axo.AllowScriptAccess = 'always'; } + catch(e) { return '6,0,0'; } + } catch(e) {} + return new ActiveXObject('ShockwaveFlash.ShockwaveFlash').GetVariable('$version').replace(/\D+/g, ',').match(/^,?(.+),?$/)[1]; + // other browsers + } catch(e) { + try { + if(navigator.mimeTypes["application/x-shockwave-flash"].enabledPlugin){ + return (navigator.plugins["Shockwave Flash 2.0"] || navigator.plugins["Shockwave Flash"]).description.replace(/\D+/g, ",").match(/^,?(.+),?$/)[1]; + } + } catch(e) {} + } + return '0,0,0'; +}; +/** + * + * @name flash.htmlOptions + * @desc The default set of options for the object or embed tag. + * +**/ +$$.htmlOptions = { + height: 240, + flashvars: {}, + pluginspage: 'http://www.adobe.com/go/getflashplayer', + src: '#', + type: 'application/x-shockwave-flash', + width: 320 +}; +/** + * + * @name flash.pluginOptions + * @desc The default set of options for checking/updating the flash Plugin. + * +**/ +$$.pluginOptions = { + expressInstall: false, + update: true, + version: '6.0.65' +}; +/** + * + * @name flash.replace + * @desc The default method for replacing an element with a Flash movie. + * +**/ +$$.replace = function(htmlOptions) { + this.innerHTML = '
'+this.innerHTML+'
'; + jQuery(this) + .addClass('flash-replaced') + .prepend($$.transform(htmlOptions)); +}; +/** + * + * @name flash.update + * @desc The default method for replacing an element with an update message. + * +**/ +$$.update = function(htmlOptions) { + var url = String(location).split('?'); + url.splice(1,0,'?hasFlash=true&'); + url = url.join(''); + var msg = '

This content requires the Flash Player. Download Flash Player. Already have Flash Player? Click here.

'; + this.innerHTML = ''+this.innerHTML+''; + jQuery(this) + .addClass('flash-update') + .prepend(msg); +}; +/** + * + * @desc Convert a hash of html options to a string of attributes, using Function.apply(). + * @example toAttributeString.apply(htmlOptions) + * @result foo="bar" foo="bar" + * +**/ +function toAttributeString() { + var s = ''; + for(var key in this) + if(typeof this[key] != 'function') + s += key+'="'+this[key]+'" '; + return s; +}; +/** + * + * @desc Convert a hash of flashvars to a url-encoded string, using Function.apply(). + * @example toFlashvarsString.apply(flashvarsObject) + * @result foo=bar&foo=bar + * +**/ +function toFlashvarsString() { + var s = ''; + for(var key in this) + if(typeof this[key] != 'function') + s += key+'='+encodeURIComponent(this[key])+'&'; + return s.replace(/&$/, ''); +}; +/** + * + * @name flash.transform + * @desc Transform a set of html options into an embed tag. + * @type String + * + * @example $$.transform(htmlOptions) + * @result + * + * Note: The embed tag is NOT standards-compliant, but it + * works in all current browsers. flash.transform can be + * overwritten with a custom function to generate more + * standards-compliant markup. + * +**/ +$$.transform = function(htmlOptions) { + htmlOptions.toString = toAttributeString; + if(htmlOptions.flashvars) htmlOptions.flashvars.toString = toFlashvarsString; + return ''; +}; + +/** + * + * Flash Player 9 Fix (http://blog.deconcept.com/2006/07/28/swfobject-143-released/) + * +**/ +if (window.attachEvent) { + window.attachEvent("onbeforeunload", function(){ + __flash_unloadHandler = function() {}; + __flash_savedUnloadHandler = function() {}; + }); +} + +})(); +(function($){ + $._i18n = { trans: {}, 'default': 'en', language: 'en' }; + $.i18n = function() { + var getTrans = function(ns, str) { + var trans = false; + // check if string exists in translation + if ($._i18n.trans[$._i18n.language] + && $._i18n.trans[$._i18n.language][ns] + && $._i18n.trans[$._i18n.language][ns][str]) { + trans = $._i18n.trans[$._i18n.language][ns][str]; + } + // or exists in default + else if ($._i18n.trans[$._i18n['default']] + && $._i18n.trans[$._i18n['default']][ns] + && $._i18n.trans[$._i18n['default']][ns][str]) { + trans = $._i18n.trans[$._i18n['default']][ns][str]; + } + // return trans or original string + return trans || str; + }; + // Set language (accepted formats: en or en-US) + if (arguments.length < 2) { + $._i18n.language = arguments[0]; + return $._i18n.language; + } + else { + // get translation + if (typeof(arguments[1]) == 'string') { + var trans = getTrans(arguments[0], arguments[1]); + // has variables for string formating + if (arguments[2] && typeof(arguments[2]) == 'object') { + return $.format(trans, arguments[2]); + } + else { + return trans; + } + } + // set translation + else { + var tmp = arguments[0].split('.'); + var lang = tmp[0]; + var ns = tmp[1] || 'jQuery'; + if (!$._i18n.trans[lang]) { + $._i18n.trans[lang] = {}; + $._i18n.trans[lang][ns] = arguments[1]; + } + else { + $.extend($._i18n.trans[lang][ns], arguments[1]); + } + } + } + }; +})(jQuery); +/* + * Copyright (c) 2007-2008 Josh Bush (digitalbush.com) + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * Version: 1.1.3 + * Release: 2008-04-16 + */ +(function($) { + + //Helper Function for Caret positioning + $.fn.caret=function(begin,end){ + if(this.length==0) return; + if (typeof begin == 'number') { + end = (typeof end == 'number')?end:begin; + return this.each(function(){ + if(this.setSelectionRange){ + this.focus(); + this.setSelectionRange(begin,end); + }else if (this.createTextRange){ + var range = this.createTextRange(); + range.collapse(true); + range.moveEnd('character', end); + range.moveStart('character', begin); + range.select(); + } + }); + } else { + if (this[0].setSelectionRange){ + begin = this[0].selectionStart; + end = this[0].selectionEnd; + }else if (document.selection && document.selection.createRange){ + var range = document.selection.createRange(); + begin = 0 - range.duplicate().moveStart('character', -100000); + end = begin + range.text.length; + } + return {begin:begin,end:end}; + } + }; + + //Predefined character definitions + var charMap={ + '9':"[0-9]", + 'a':"[A-Za-z]", + '*':"[A-Za-z0-9]" + }; + + //Helper method to inject character definitions + $.mask={ + addPlaceholder : function(c,r){ + charMap[c]=r; + } + }; + + $.fn.unmask=function(){ + return this.trigger("unmask"); + }; + + //Main Method + $.fn.mask = function(mask,settings) { + settings = $.extend({ + placeholder: "_", + completed: null + }, settings); + + //Build Regex for format validation + var re = new RegExp("^"+ + $.map( mask.split(""), function(c,i){ + return charMap[c]||((/[A-Za-z0-9]/.test(c)?"":"\\")+c); + }).join('')+ + "$"); + + return this.each(function(){ + var input=$(this); + var buffer=new Array(mask.length); + var locked=new Array(mask.length); + var valid=false; + var ignore=false; //Variable for ignoring control keys + var firstNonMaskPos=null; + + //Build buffer layout from mask & determine the first non masked character + $.each( mask.split(""), function(i,c){ + locked[i]=(charMap[c]==null); + buffer[i]=locked[i]?c:settings.placeholder; + if(!locked[i] && firstNonMaskPos==null) + firstNonMaskPos=i; + }); + + function focusEvent(){ + checkVal(); + writeBuffer(); + setTimeout(function(){ + $(input[0]).caret(valid?mask.length:firstNonMaskPos); + },0); + }; + + function keydownEvent(e){ + var pos=$(this).caret(); + var k = e.keyCode; + ignore=(k < 16 || (k > 16 && k < 32 ) || (k > 32 && k < 41)); + + //delete selection before proceeding + if((pos.begin-pos.end)!=0 && (!ignore || k==8 || k==46)){ + clearBuffer(pos.begin,pos.end); + } + //backspace and delete get special treatment + if(k==8){//backspace + while(pos.begin-->=0){ + if(!locked[pos.begin]){ + buffer[pos.begin]=settings.placeholder; + if($.browser.opera){ + //Opera won't let you cancel the backspace, so we'll let it backspace over a dummy character. + s=writeBuffer(); + input.val(s.substring(0,pos.begin)+" "+s.substring(pos.begin)); + $(this).caret(pos.begin+1); + }else{ + writeBuffer(); + $(this).caret(Math.max(firstNonMaskPos,pos.begin)); + } + return false; + } + } + }else if(k==46){//delete + clearBuffer(pos.begin,pos.begin+1); + writeBuffer(); + $(this).caret(Math.max(firstNonMaskPos,pos.begin)); + return false; + }else if (k==27){//escape + clearBuffer(0,mask.length); + writeBuffer(); + $(this).caret(firstNonMaskPos); + return false; + } + }; + + function keypressEvent(e){ + if(ignore){ + ignore=false; + //Fixes Mac FF bug on backspace + return (e.keyCode == 8)? false: null; + } + e=e||window.event; + var k=e.charCode||e.keyCode||e.which; + var pos=$(this).caret(); + + if(e.ctrlKey || e.altKey){//Ignore + return true; + }else if ((k>=41 && k<=122) ||k==32 || k>186){//typeable characters + var p=seekNext(pos.begin-1); + if(p + MIT-style license. +*/ + +(function($) { + + // Global variables, accessible to Slimbox only + var win = $(window), options, images, activeImage = -1, activeURL, prevImage, nextImage, compatibleOverlay, middle, centerWidth, centerHeight, ie6 = !window.XMLHttpRequest, + operaFix = window.opera && (document.compatMode == "CSS1Compat") && ($.browser.version >= 9.3), documentElement = document.documentElement, + + // Preload images + preload = {}, preloadPrev = new Image(), preloadNext = new Image(), + + // DOM elements + overlay, center, image, sizer, prevLink, nextLink, bottomContainer, bottom, caption, number; + + /* + Initialization + */ + + $(function() { + // Append the Slimbox HTML code at the bottom of the document + $("body").append( + $([ + overlay = $('
')[0], + center = $('
')[0], + bottomContainer = $('
')[0] + ]).css("display", "none") + ); + + image = $('
').appendTo(center).append( + sizer = $('
').append([ + prevLink = $('').click(previous)[0], + nextLink = $('').click(next)[0] + ])[0] + )[0]; + + bottom = $('
').appendTo(bottomContainer).append([ + $('').add(overlay).click(close)[0], + caption = $('
')[0], + number = $('
')[0], + $('
')[0] + ])[0]; + }); + + + /* + API + */ + + // Open Slimbox with the specified parameters + $.slimbox = function(_images, startImage, _options) { + options = $.extend({ + loop: false, // Allows to navigate between first and last images + overlayOpacity: 0.8, // 1 is opaque, 0 is completely transparent (change the color in the CSS file) + overlayFadeDuration: 400, // Duration of the overlay fade-in and fade-out animations (in milliseconds) + resizeDuration: 400, // Duration of each of the box resize animations (in milliseconds) + resizeEasing: "swing", // "swing" is jQuery's default easing + initialWidth: 250, // Initial width of the box (in pixels) + initialHeight: 250, // Initial height of the box (in pixels) + imageFadeDuration: 400, // Duration of the image fade-in animation (in milliseconds) + captionAnimationDuration: 400, // Duration of the caption animation (in milliseconds) + counterText: "Image {x} of {y}", // Translate or change as you wish, or set it to false to disable counter text for image groups + closeKeys: [27, 88, 67], // Array of keycodes to close Slimbox, default: Esc (27), 'x' (88), 'c' (67) + previousKeys: [37, 80], // Array of keycodes to navigate to the previous image, default: Left arrow (37), 'p' (80) + nextKeys: [39, 78] // Array of keycodes to navigate to the next image, default: Right arrow (39), 'n' (78) + }, _options); + + // The function is called for a single image, with URL and Title as first two arguments + if (typeof _images == "string") { + _images = [[_images, startImage]]; + startImage = 0; + } + + middle = win.scrollTop() + ((operaFix ? documentElement.clientHeight : win.height()) / 2); + centerWidth = options.initialWidth; + centerHeight = options.initialHeight; + $(center).css({top: Math.max(0, middle - (centerHeight / 2)), width: centerWidth, height: centerHeight, marginLeft: -centerWidth/2}).show(); + compatibleOverlay = ie6 || (overlay.currentStyle && (overlay.currentStyle.position != "fixed")); + if (compatibleOverlay) overlay.style.position = "absolute"; + $(overlay).css("opacity", options.overlayOpacity).fadeIn(options.overlayFadeDuration); + position(); + setup(1); + + images = _images; + options.loop = options.loop && (images.length > 1); + return changeImage(startImage); + }; + + /* + options: Optional options object, see jQuery.slimbox() + linkMapper: Optional function taking a link DOM element and an index as arguments and returning an array containing 2 elements: + the image URL and the image caption (may contain HTML) + linksFilter: Optional function taking a link DOM element and an index as arguments and returning true if the element is part of + the image collection that will be shown on click, false if not. "this" refers to the element that was clicked. + This function must always return true when the DOM element argument is "this". + */ + $.fn.slimbox = function(_options, linkMapper, linksFilter) { + linkMapper = linkMapper || function(el) { + return [el.href, el.title]; + }; + + linksFilter = linksFilter || function() { + return true; + }; + + var links = this; + + return links.unbind("click").click(function() { + // Build the list of images that will be displayed + var link = this, startIndex = 0, filteredLinks, i = 0, length; + filteredLinks = $.grep(links, function(el, i) { + return linksFilter.call(link, el, i); + }); + + // We cannot use jQuery.map() because it flattens the returned array + for (length = filteredLinks.length; i < length; ++i) { + if (filteredLinks[i] == link) startIndex = i; + filteredLinks[i] = linkMapper(filteredLinks[i], i); + } + + return $.slimbox(filteredLinks, startIndex, _options); + }); + }; + + + /* + Internal functions + */ + + function position() { + var l = win.scrollLeft(), w = operaFix ? documentElement.clientWidth : win.width(); + $([center, bottomContainer]).css("left", l + (w / 2)); + if (compatibleOverlay) $(overlay).css({left: l, top: win.scrollTop(), width: w, height: win.height()}); + } + + function setup(open) { + $("object").add(ie6 ? "select" : "embed").each(function(index, el) { + if (open) $.data(el, "slimbox", el.style.visibility); + el.style.visibility = open ? "hidden" : $.data(el, "slimbox"); + }); + var fn = open ? "bind" : "unbind"; + win[fn]("scroll resize", position); + $(document)[fn]("keydown", keyDown); + } + + function keyDown(event) { + var code = event.keyCode, fn = $.inArray; + // Prevent default keyboard action (like navigating inside the page) + return (fn(code, options.closeKeys) >= 0) ? close() + : (fn(code, options.nextKeys) >= 0) ? next() + : (fn(code, options.previousKeys) >= 0) ? previous() + : false; + } + + function previous() { + return changeImage(prevImage); + } + + function next() { + return changeImage(nextImage); + } + + function changeImage(imageIndex) { + if (imageIndex >= 0) { + activeImage = imageIndex; + activeURL = images[activeImage][0]; + prevImage = (activeImage || (options.loop ? images.length : 0)) - 1; + nextImage = ((activeImage + 1) % images.length) || (options.loop ? 0 : -1); + + stop(); + center.className = "lbLoading"; + + preload = new Image(); + preload.onload = animateBox; + preload.src = activeURL; + } + + return false; + } + + function animateBox() { + center.className = ""; + $(image).css({backgroundImage: "url(" + activeURL + ")", visibility: "hidden", display: ""}); + $(sizer).width(preload.width); + $([sizer, prevLink, nextLink]).height(preload.height); + + $(caption).html(images[activeImage][1] || ""); + $(number).html((((images.length > 1) && options.counterText) || "").replace(/{x}/, activeImage + 1).replace(/{y}/, images.length)); + + if (prevImage >= 0) preloadPrev.src = images[prevImage][0]; + if (nextImage >= 0) preloadNext.src = images[nextImage][0]; + + centerWidth = image.offsetWidth; + centerHeight = image.offsetHeight; + var top = Math.max(0, middle - (centerHeight / 2)); + if (center.offsetHeight != centerHeight) { + $(center).animate({height: centerHeight, top: top}, options.resizeDuration, options.resizeEasing); + } + if (center.offsetWidth != centerWidth) { + $(center).animate({width: centerWidth, marginLeft: -centerWidth/2}, options.resizeDuration, options.resizeEasing); + } + $(center).queue(function() { + $(bottomContainer).css({width: centerWidth, top: top + centerHeight, marginLeft: -centerWidth/2, visibility: "hidden", display: ""}); + $(image).css({display: "none", visibility: "", opacity: ""}).fadeIn(options.imageFadeDuration, animateCaption); + }); + } + + + function animateCaption() { + if (prevImage >= 0) $(prevLink).show(); + if (nextImage >= 0) $(nextLink).show(); + $(bottom).css("marginTop", -bottom.offsetHeight).animate({marginTop: 0}, options.captionAnimationDuration); + bottomContainer.style.visibility = ""; + } + + function stop() { + preload.onload = null; + preload.src = preloadPrev.src = preloadNext.src = activeURL; + $([center, image, bottom]).stop(true); + $([prevLink, nextLink, image, bottomContainer]).hide(); + } + + function close() { + if (activeImage >= 0) { + stop(); + activeImage = prevImage = nextImage = -1; + $(center).hide(); + $(overlay).stop().fadeOut(options.overlayFadeDuration, setup); + } + + return false; + } + +})(jQuery); +/* + * timeago: a jQuery plugin, version: 0.5.1 (08/20/2008) + * @requires jQuery v1.2 or later + * + * Timeago is a jQuery plugin that makes it easy to support automatically + * updating fuzzy timestamps (e.g. "4 minutes ago" or "about 1 day ago"). + * + * For usage and examples, visit: + * http://timeago.yarp.com/ + * + * Licensed under the MIT: + * http://www.opensource.org/licenses/mit-license.php + * + * Copyright (c) 2008, Ryan McGeary (ryanonjavascript -[at]- mcgeary [*dot*] org) + */ +(function($) { + $.timeago = function(timestamp) { + if (timestamp instanceof Date) return inWords(timestamp); + else if (typeof timestamp == "string") return inWords($.timeago.parse(timestamp)); + else return inWords($.timeago.parse($(timestamp).attr("title"))); + }; + var $t = $.timeago; + + $.extend($.timeago, { + settings: { + refreshMillis: 60000, + allowFuture: false, + strings: { + ago: "ago", + fromNow: "from now", + seconds: "less than a minute", + minute: "about a minute", + minutes: "%d minutes", + hour: "about an hour", + hours: "about %d hours", + day: "a day", + days: "%d days", + month: "about a month", + months: "%d months", + year: "about a year", + years: "%d years" + } + }, + inWords: function(distanceMillis) { + var $l = this.settings.strings; + var suffix = $l.ago; + if (this.settings.allowFuture) { + if (distanceMillis < 0) suffix = $l.fromNow; + distanceMillis = Math.abs(distanceMillis); + } + + var seconds = distanceMillis / 1000; + var minutes = seconds / 60; + var hours = minutes / 60; + var days = hours / 24; + var years = days / 365; + + var words = seconds < 45 && sprintf($l.seconds, Math.round(seconds)) || + seconds < 90 && $l.minute || + minutes < 45 && sprintf($l.minutes, Math.round(minutes)) || + minutes < 90 && $l.hour || + hours < 24 && sprintf($l.hours, Math.round(hours)) || + hours < 48 && $l.day || + days < 30 && sprintf($l.days, Math.floor(days)) || + days < 60 && $l.month || + days < 365 && sprintf($l.months, Math.floor(days / 30)) || + years < 2 && $l.year || + sprintf($l.years, Math.floor(years)); + + return words + " " + suffix; + }, + parse: function(iso8601) { + var s = $.trim(iso8601); + s = s.replace(/-/,"/").replace(/-/,"/"); + s = s.replace(/T/," ").replace(/Z/," UTC"); + s = s.replace(/([\+-]\d\d)\:?(\d\d)/," $1$2"); // -04:00 -> -0400 + return new Date(s); + } + }); + + $.fn.timeago = function() { + var self = this; + self.each(refresh); + + var $s = $t.settings; + if ($s.refreshMillis > 0) { + setInterval(function() { self.each(refresh); }, $s.refreshMillis); + } + return self; + }; + + function refresh() { + var date = $t.parse(this.title); + if (!isNaN(date)) { + $(this).text(inWords(date)); + } + return this; + } + + function inWords(date) { + return $t.inWords(distance(date)); + } + + function distance(date) { + return (new Date().getTime() - date.getTime()); + } + + // lame sprintf implementation + function sprintf(string, value) { + return string.replace(/%d/i, value); + } + + // fix for IE6 suckage + if ($.browser.msie && $.browser.version < 7.0) { + document.createElement('abbr'); + } +})(jQuery); + diff --git a/src/Orchard.Web/Modules/ArchiveLater/Scripts/ui.timepickr.js b/src/Orchard.Web/Modules/ArchiveLater/Scripts/ui.timepickr.js new file mode 100644 index 000000000..1c580790d --- /dev/null +++ b/src/Orchard.Web/Modules/ArchiveLater/Scripts/ui.timepickr.js @@ -0,0 +1,420 @@ +/* +jQuery ui.timepickr - @VERSION +http://code.google.com/p/jquery-utils/ + +(c) Maxime Haineault +http://haineault.com + +MIT License (http://www.opensource.org/licenses/mit-license.php + +Note: if you want the original experimental plugin checkout the rev 224 + +Dependencies +------------ +- jquery.utils.js +- jquery.strings.js +- jquery.ui.js + +*/ + +(function($) { + + $.tpl('timepickr.menu', '
'); //todo: (heskew) make the corner an option just like the items + $.tpl('timepickr.row', '
    '); + $.tpl('timepickr.button', '
  1. {label:s}
  2. '); + + $.widget('ui.timepickr', { + options: { + convention: 12, // 24, 12 + trigger: 'focus', + format12: '{h:02.d}:{m:02.d} {z}', + format24: '{h:02.d}:{m:02.d}', + hours: true, + prefix: ['AM', 'PM'], + suffix: ['AM', 'PM'], + prefixVal: false, + suffixVal: true, + rangeHour12: $.range(1, 13), + rangeHour24: [$.range(0, 12), $.range(12, 24)], + rangeMin: $.range(0, 60, 15), + rangeSec: $.range(0, 60, 15), + corners: 'all', + // plugins + core: true, + minutes: true, + seconds: false, + val: false, + updateLive: true, + resetOnBlur: true, + keyboardnav: true, + handle: false, + handleEvent: 'click' + }, + + plugins: {}, + + _create: function() { + this._dom = { + menu: $.tpl('timepickr.menu'), + row: $.tpl('timepickr.menu') + }; + this._trigger('start'); + this._trigger('initialized'); + }, + + _trigger: function(type, e, ui) { + var ui = ui || this; + $.ui.plugin.call(this, type, [e, ui]); + return $.Widget.prototype._trigger.call(this, type, e, ui); + }, + + _createButton: function(i, format, className) { + var o = format && $.format(format, i) || i; + var cn = className && 'ui-timepickr-button ' + className || 'ui-timepickr-button'; + return $.tpl('timepickr.button', { className: cn, label: o }).data('id', i) + .bind('mouseover', function() { + $(this).siblings().find('span') + .removeClass('ui-state-hover').end().end() + .find('span').addClass('ui-state-hover'); + }); + + }, + + _addRow: function(range, format, className, insertAfter) { + var ui = this; + var btn = false; + var row = $.tpl('timepickr.row').bind('mouseover', function() { + $(this).next().show(); + }); + $.each(range, function(idx, val) { + ui._createButton(val, format || false).appendTo(row); + }); + if (className) { + $(row).addClass(className); + } + if (this.options.corners) { + row.find('span').addClass('ui-corner-' + this.options.corners); + } + if (insertAfter) { + row.insertAfter(insertAfter); + } + else { + ui._dom.menu.append(row); + } + return row; + }, + + _setVal: function(val) { + val = val || this._getVal(); + this.element.data('timepickr.initialValue', val); + this.element.val(this._formatVal(val)); + if (this._dom.menu.is(':hidden')) { + this.element.trigger('change'); + } + }, + + _getVal: function() { + var ols = this._dom.menu.find('ol'); + function g(unit) { + var u = ols.filter('.' + unit).find('.ui-state-hover:first').text(); + return u || ols.filter('.' + unit + 'li:first span').text(); + } + return { + h: g('hours'), + m: g('minutes'), + s: g('seconds'), + a: g('prefix'), + z: g('suffix'), + f: this.options['format' + this.c], + c: this.c + }; + }, + + _formatVal: function(ival) { + var val = ival || this._getVal(); + + if (!val.h) return; + + val.c = this.options.convention; + val.f = val.c === 12 && this.options.format12 || this.options.format24; + return (new Time(val)).getTime(); + }, + + blur: function() { + return this.element.blur(); + }, + + focus: function() { + return this.element.focus(); + }, + show: function() { + this._trigger('show'); + var pos = this.element.position(); + var width = this.element.data('width'); + var elementWidth = this.element.outerWidth(); + var windowWidth = $(window).width() + $(window).scrollLeft(); + + if (width) { + this._dom.menu.css( + 'left', + pos.left + elementWidth < windowWidth + ? pos.left - width + elementWidth + : windowWidth - width + ); + } + + this._dom.menu.show(); //todo: (heskew) make show effect an option + }, + hide: function() { + this._trigger('hide'); + this._dom.menu.hide(); + } + + }); + + // These properties are shared accross every instances of timepickr + $.extend($.ui.timepickr, { + version: '@VERSION' + }); + + $.ui.plugin.add('timepickr', 'core', { + start: function(e, ui) { + var menu = ui._dom.menu; + var pos = ui.element.position(); + + //render off screen, to be repositioned by show() + menu.insertAfter(ui.element).css('left', '-9999em'); + + if (!$.boxModel) { // IE alignement fix + menu.css('margin-top', ui.element.height() + 8); + } + + ui.element + .bind(ui.options.trigger, function() { + ui._dom.menu.find('ol:first').show(); + ui.show(); + ui._trigger('focus'); + if (ui.options.trigger != 'focus') { + ui.element.focus(); + } + ui._trigger('focus'); + }) + .bind('blur', function() { + ui.hide(); + ui._trigger('blur'); + }); + + menu.find('li').bind('mouseover.timepickr', function() { + ui._trigger('refresh'); + }); + }, + initialized: function(e, ui) { + var menuItems = ui._dom.menu.find('ol'); + var pos = ui.element.position(); + + //load up + ui.show(); + menuItems.show(); + + //store width(s) + ui.element.data('width', ui._dom.menu.outerWidth()); + //fix the width + ui._dom.menu.width(ui._dom.menu.width()); + + //hide + menuItems.hide(); + ui.hide(); + }, + refresh: function(e, ui) { + // Realign each menu layers + ui._dom.menu.find('ol').each(function() { + var p = $(this).prev('ol'); + try { // .. to not fuckup IE + $(this).css('left', p.position().left + p.find('.ui-state-hover').position().left); + } catch (e) { }; + }); + } + }); + + $.ui.plugin.add('timepickr', 'hours', { + start: function(e, ui) { + if (ui.options.convention === 24) { + // prefix is required in 24h mode + ui._dom.prefix = ui._addRow(ui.options.prefix, false, 'prefix'); + + // split-range + if ($.isArray(ui.options.rangeHour24[0])) { + var range = []; + $.merge(range, ui.options.rangeHour24[0]); + $.merge(range, ui.options.rangeHour24[1]); + ui._dom.hours = ui._addRow(range, '{0:0.2d}', 'hours'); + ui._dom.hours.find('li').slice(ui.options.rangeHour24[0].length, -1).hide(); + var lis = ui._dom.hours.find('li'); + + var show = [ + function() { + lis.slice(ui.options.rangeHour24[0].length).hide().end() + .slice(0, ui.options.rangeHour24[0].length).show() + .filter(':visible:first').trigger('mouseover'); + + }, + function() { + lis.slice(0, ui.options.rangeHour24[0].length).hide().end() + .slice(ui.options.rangeHour24[0].length).show() + .filter(':visible:first').trigger('mouseover'); + } + ]; + + ui._dom.prefix.find('li').bind('mouseover.timepickr', function() { + var index = ui._dom.menu.find('.prefix li').index(this); + show[index].call(); + }); + } + else { + ui._dom.hours = ui._addRow(ui.options.rangeHour24, '{0:0.2d}', 'hours'); + ui._dom.hours.find('li').slice(12, -1).hide(); + } + } + else { + ui._dom.hours = ui._addRow(ui.options.rangeHour12, '{0:0.2d}', 'hours'); + // suffix is required in 12h mode + ui._dom.suffix = ui._addRow(ui.options.suffix, false, 'suffix'); + } + } + }); + + $.ui.plugin.add('timepickr', 'minutes', { + start: function(e, ui) { + var p = ui._dom.hours && ui._dom.hours || false; + ui._dom.minutes = ui._addRow(ui.options.rangeMin, '{0:0.2d}', 'minutes', p); + } + }); + + $.ui.plugin.add('timepickr', 'seconds', { + start: function(e, ui) { + var p = ui._dom.minutes && ui._dom.minutes || false; + ui._dom.seconds = ui._addRow(ui.options.rangeSec, '{0:0.2d}', 'seconds', p); + } + }); + + $.ui.plugin.add('timepickr', 'val', { + start: function(e, ui) { + ui._setVal(ui.options.val); + } + }); + + $.ui.plugin.add('timepickr', 'updateLive', { + refresh: function(e, ui) { + ui._setVal(); + } + }); + + $.ui.plugin.add('timepickr', 'resetOnBlur', { + start: function(e, ui) { + ui.element.data('timepickr.initialValue', ui._getVal()); + ui._dom.menu.find('li > span').bind('mousedown.timepickr', function() { + ui.element.data('timepickr.initialValue', ui._getVal()); + }); + }, + blur: function(e, ui) { + ui._setVal(ui.element.data('timepickr.initialValue')); + } + }); + + $.ui.plugin.add('timepickr', 'handle', { + start: function(e, ui) { + $(ui.options.handle).bind(ui.options.handleEvent + '.timepickr', function() { + ui.show(); + }); + } + }); + + $.ui.plugin.add('timepickr', 'keyboardnav', { + start: function(e, ui) { + ui.element + .bind('keydown', function(e) { + if ($.keyIs('enter', e)) { + ui._setVal(); + ui.blur(); + } + else if ($.keyIs('escape', e)) { + ui.blur(); + } + }); + } + }); + + var Time = function() { // arguments: h, m, s, c, z, f || time string + if (!(this instanceof arguments.callee)) { + throw Error("Constructor called as a function"); + } + // arguments as literal object + if (arguments.length == 1 && $.isObject(arguments[0])) { + this.h = arguments[0].h || 0; + this.m = arguments[0].m || 0; + this.s = arguments[0].s || 0; + this.c = arguments[0].c && ($.inArray(arguments[0].c, [12, 24]) >= 0) && arguments[0].c || 24; + this.f = arguments[0].f || ((this.c == 12) && '{h:02.d}:{m:02.d} {z:02.d}' || '{h:02.d}:{m:02.d}'); + this.z = arguments[0].z || 'am'; + } + // arguments as string + else if (arguments.length < 4 && $.isString(arguments[1])) { + this.c = arguments[2] && ($.inArray(arguments[0], [12, 24]) >= 0) && arguments[0] || 24; + this.f = arguments[3] || ((this.c == 12) && '{h:02.d}:{m:02.d} {z:02.d}' || '{h:02.d}:{m:02.d}'); + this.z = arguments[4] || 'am'; + + this.h = arguments[1] || 0; // parse + this.m = arguments[1] || 0; // parse + this.s = arguments[1] || 0; // parse + } + // no arguments (now) + else if (arguments.length === 0) { + // now + } + // standards arguments + else { + this.h = arguments[0] || 0; + this.m = arguments[1] || 0; + this.s = arguments[2] || 0; + this.c = arguments[3] && ($.inArray(arguments[3], [12, 24]) >= 0) && arguments[3] || 24; + this.f = this.f || ((this.c == 12) && '{h:02.d}:{m:02.d} {z:02.d}' || '{h:02.d}:{m:02.d}'); + this.z = 'am'; + } + return this; + }; + + Time.prototype.get = function(p, f, u) { return u && this.h || $.format(f, this.h); }; + Time.prototype.getHours = function(unformated) { return this.get('h', '{0:02.d}', unformated); }; + Time.prototype.getMinutes = function(unformated) { return this.get('m', '{0:02.d}', unformated); }; + Time.prototype.getSeconds = function(unformated) { return this.get('s', '{0:02.d}', unformated); }; + Time.prototype.setFormat = function(format) { return this.f = format; }; + Time.prototype.getObject = function() { return { h: this.h, m: this.m, s: this.s, c: this.c, f: this.f, z: this.z }; }; + Time.prototype.getTime = function() { return $.format(this.f, { h: this.h, m: this.m, z: this.z }); }; + Time.prototype.parse = function(str) { + // 12h formats + if (this.c === 12) { + // Supported formats: (can't find any *official* standards for 12h..) + // - [hh]:[mm]:[ss] [zz] | [hh]:[mm] [zz] | [hh] [zz] + // - [hh]:[mm]:[ss] [z.z.] | [hh]:[mm] [z.z.] | [hh] [z.z.] + this.tokens = str.split(/\s|:/); + this.h = this.tokens[0] || 0; + this.m = this.tokens[1] || 0; + this.s = this.tokens[2] || 0; + this.z = this.tokens[3] || ''; + return this.getObject(); + } + // 24h formats + else { + // Supported formats: + // - ISO 8601: [hh][mm][ss] | [hh][mm] | [hh] + // - ISO 8601 extended: [hh]:[mm]:[ss] | [hh]:[mm] | [hh] + this.tokens = /:/.test(str) && str.split(/:/) || str.match(/[0-9]{2}/g); + this.h = this.tokens[0] || 0; + this.m = this.tokens[1] || 0; + this.s = this.tokens[2] || 0; + this.z = this.tokens[3] || ''; + return this.getObject(); + } + }; + +})(jQuery); diff --git a/src/Orchard.Web/Modules/ArchiveLater/Services/ArchiveLaterService.cs b/src/Orchard.Web/Modules/ArchiveLater/Services/ArchiveLaterService.cs new file mode 100644 index 000000000..b2b393141 --- /dev/null +++ b/src/Orchard.Web/Modules/ArchiveLater/Services/ArchiveLaterService.cs @@ -0,0 +1,35 @@ +using System; +using System.Linq; +using ArchiveLater.Models; +using Orchard.ContentManagement; +using Orchard.Tasks.Scheduling; + +namespace ArchiveLater.Services { + public class ArchiveLaterService : IArchiveLaterService { + private const string UnpublishTaskType = "Unpublish"; + + private readonly IScheduledTaskManager _scheduledTaskManager; + + public ArchiveLaterService(IScheduledTaskManager scheduledTaskManager) { + _scheduledTaskManager = scheduledTaskManager; + } + + void IArchiveLaterService.ArchiveLater(ContentItem contentItem, DateTime scheduledArchiveUtc) { + RemoveArchiveLaterTasks(contentItem); + _scheduledTaskManager.CreateTask(UnpublishTaskType, scheduledArchiveUtc, contentItem); + } + + DateTime? IArchiveLaterService.GetScheduledArchiveUtc(ArchiveLaterPart archiveLaterPart) { + var task = _scheduledTaskManager + .GetTasks(archiveLaterPart.ContentItem) + .Where(t => t.TaskType == UnpublishTaskType) + .SingleOrDefault(); + + return (task == null ? null : task.ScheduledUtc); + } + + public void RemoveArchiveLaterTasks(ContentItem contentItem) { + _scheduledTaskManager.DeleteTasks(contentItem, t => t.TaskType == UnpublishTaskType); + } + } +} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/ArchiveLater/Services/IArchiveLaterService.cs b/src/Orchard.Web/Modules/ArchiveLater/Services/IArchiveLaterService.cs new file mode 100644 index 000000000..c7a1199ce --- /dev/null +++ b/src/Orchard.Web/Modules/ArchiveLater/Services/IArchiveLaterService.cs @@ -0,0 +1,12 @@ +using System; +using ArchiveLater.Models; +using Orchard; +using Orchard.ContentManagement; + +namespace ArchiveLater.Services { + public interface IArchiveLaterService : IDependency { + DateTime? GetScheduledArchiveUtc(ArchiveLaterPart archiveLaterPart); + void ArchiveLater(ContentItem contentItem, DateTime scheduledArchiveUtc); + void RemoveArchiveLaterTasks(ContentItem contentItem); + } +} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/ArchiveLater/Styles/datetime.css b/src/Orchard.Web/Modules/ArchiveLater/Styles/datetime.css new file mode 100644 index 000000000..f9557993c --- /dev/null +++ b/src/Orchard.Web/Modules/ArchiveLater/Styles/datetime.css @@ -0,0 +1,14 @@ +html.dyn label.forpicker { + display:none; +} +/* todo: (heskew) let themes take care of this */ +html.dyn input.hinted { + color:#ccc; + font-style:italic; +} +input#ArchiveLater_ScheduledArchiveDate { + width:50%; +} +input#ArchiveLater_ScheduledArchiveTime { + width:36%; +} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/ArchiveLater/Styles/images/ui-bg_flat_0_aaaaaa_40x100.png b/src/Orchard.Web/Modules/ArchiveLater/Styles/images/ui-bg_flat_0_aaaaaa_40x100.png new file mode 100644 index 000000000..5b5dab2ab Binary files /dev/null and b/src/Orchard.Web/Modules/ArchiveLater/Styles/images/ui-bg_flat_0_aaaaaa_40x100.png differ diff --git a/src/Orchard.Web/Modules/ArchiveLater/Styles/images/ui-bg_flat_75_ffffff_40x100.png b/src/Orchard.Web/Modules/ArchiveLater/Styles/images/ui-bg_flat_75_ffffff_40x100.png new file mode 100644 index 000000000..ac8b229af Binary files /dev/null and b/src/Orchard.Web/Modules/ArchiveLater/Styles/images/ui-bg_flat_75_ffffff_40x100.png differ diff --git a/src/Orchard.Web/Modules/ArchiveLater/Styles/images/ui-bg_glass_55_fbf9ee_1x400.png b/src/Orchard.Web/Modules/ArchiveLater/Styles/images/ui-bg_glass_55_fbf9ee_1x400.png new file mode 100644 index 000000000..b39a6fb27 Binary files /dev/null and b/src/Orchard.Web/Modules/ArchiveLater/Styles/images/ui-bg_glass_55_fbf9ee_1x400.png differ diff --git a/src/Orchard.Web/Modules/ArchiveLater/Styles/images/ui-bg_glass_65_ffffff_1x400.png b/src/Orchard.Web/Modules/ArchiveLater/Styles/images/ui-bg_glass_65_ffffff_1x400.png new file mode 100644 index 000000000..42ccba269 Binary files /dev/null and b/src/Orchard.Web/Modules/ArchiveLater/Styles/images/ui-bg_glass_65_ffffff_1x400.png differ diff --git a/src/Orchard.Web/Modules/ArchiveLater/Styles/images/ui-bg_glass_75_dadada_1x400.png b/src/Orchard.Web/Modules/ArchiveLater/Styles/images/ui-bg_glass_75_dadada_1x400.png new file mode 100644 index 000000000..5a46b47cb Binary files /dev/null and b/src/Orchard.Web/Modules/ArchiveLater/Styles/images/ui-bg_glass_75_dadada_1x400.png differ diff --git a/src/Orchard.Web/Modules/ArchiveLater/Styles/images/ui-bg_glass_75_e6e6e6_1x400.png b/src/Orchard.Web/Modules/ArchiveLater/Styles/images/ui-bg_glass_75_e6e6e6_1x400.png new file mode 100644 index 000000000..38df73a21 Binary files /dev/null and b/src/Orchard.Web/Modules/ArchiveLater/Styles/images/ui-bg_glass_75_e6e6e6_1x400.png differ diff --git a/src/Orchard.Web/Modules/ArchiveLater/Styles/images/ui-bg_glass_95_fef1ec_1x400.png b/src/Orchard.Web/Modules/ArchiveLater/Styles/images/ui-bg_glass_95_fef1ec_1x400.png new file mode 100644 index 000000000..4443fdc1a Binary files /dev/null and b/src/Orchard.Web/Modules/ArchiveLater/Styles/images/ui-bg_glass_95_fef1ec_1x400.png differ diff --git a/src/Orchard.Web/Modules/ArchiveLater/Styles/images/ui-bg_highlight-soft_75_cccccc_1x100.png b/src/Orchard.Web/Modules/ArchiveLater/Styles/images/ui-bg_highlight-soft_75_cccccc_1x100.png new file mode 100644 index 000000000..7c9fa6c6e Binary files /dev/null and b/src/Orchard.Web/Modules/ArchiveLater/Styles/images/ui-bg_highlight-soft_75_cccccc_1x100.png differ diff --git a/src/Orchard.Web/Modules/ArchiveLater/Styles/images/ui-icons_222222_256x240.png b/src/Orchard.Web/Modules/ArchiveLater/Styles/images/ui-icons_222222_256x240.png new file mode 100644 index 000000000..ee039dc09 Binary files /dev/null and b/src/Orchard.Web/Modules/ArchiveLater/Styles/images/ui-icons_222222_256x240.png differ diff --git a/src/Orchard.Web/Modules/ArchiveLater/Styles/images/ui-icons_2e83ff_256x240.png b/src/Orchard.Web/Modules/ArchiveLater/Styles/images/ui-icons_2e83ff_256x240.png new file mode 100644 index 000000000..45e8928e5 Binary files /dev/null and b/src/Orchard.Web/Modules/ArchiveLater/Styles/images/ui-icons_2e83ff_256x240.png differ diff --git a/src/Orchard.Web/Modules/ArchiveLater/Styles/images/ui-icons_454545_256x240.png b/src/Orchard.Web/Modules/ArchiveLater/Styles/images/ui-icons_454545_256x240.png new file mode 100644 index 000000000..fe1085b39 Binary files /dev/null and b/src/Orchard.Web/Modules/ArchiveLater/Styles/images/ui-icons_454545_256x240.png differ diff --git a/src/Orchard.Web/Modules/ArchiveLater/Styles/images/ui-icons_888888_256x240.png b/src/Orchard.Web/Modules/ArchiveLater/Styles/images/ui-icons_888888_256x240.png new file mode 100644 index 000000000..5ba708c39 Binary files /dev/null and b/src/Orchard.Web/Modules/ArchiveLater/Styles/images/ui-icons_888888_256x240.png differ diff --git a/src/Orchard.Web/Modules/ArchiveLater/Styles/images/ui-icons_cd0a0a_256x240.png b/src/Orchard.Web/Modules/ArchiveLater/Styles/images/ui-icons_cd0a0a_256x240.png new file mode 100644 index 000000000..7930a5580 Binary files /dev/null and b/src/Orchard.Web/Modules/ArchiveLater/Styles/images/ui-icons_cd0a0a_256x240.png differ diff --git a/src/Orchard.Web/Modules/ArchiveLater/Styles/jquery-ui-1.7.2.custom.css b/src/Orchard.Web/Modules/ArchiveLater/Styles/jquery-ui-1.7.2.custom.css new file mode 100644 index 000000000..444486b9b --- /dev/null +++ b/src/Orchard.Web/Modules/ArchiveLater/Styles/jquery-ui-1.7.2.custom.css @@ -0,0 +1,406 @@ +/* +* jQuery UI CSS Framework +* Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about) +* Dual licensed under the MIT (MIT-LICENSE.txt) and GPL (GPL-LICENSE.txt) licenses. +*/ + +/* Layout helpers +----------------------------------*/ +.ui-helper-hidden { display: none; } +.ui-helper-hidden-accessible { position: absolute; left: -99999999px; } +.ui-helper-reset { margin: 0; padding: 0; border: 0; outline: 0; line-height: 1.3; text-decoration: none; font-size: 100%; list-style: none; } +.ui-helper-clearfix:after { content: "."; display: block; height: 0; clear: both; visibility: hidden; } +.ui-helper-clearfix { display: inline-block; } +/* required comment for clearfix to work in Opera \*/ +* html .ui-helper-clearfix { height:1%; } +.ui-helper-clearfix { display:block; } +/* end clearfix */ +.ui-helper-zfix { width: 100%; height: 100%; top: 0; left: 0; position: absolute; opacity: 0; filter:Alpha(Opacity=0); } + + +/* Interaction Cues +----------------------------------*/ +.ui-state-disabled { cursor: default !important; } + + +/* Icons +----------------------------------*/ + +/* states and images */ +.ui-icon { display: block; text-indent: -99999px; overflow: hidden; background-repeat: no-repeat; } + + +/* Misc visuals +----------------------------------*/ + +/* Overlays */ +.ui-widget-overlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; } + + + +/* +* jQuery UI CSS Framework +* Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about) +* Dual licensed under the MIT (MIT-LICENSE.txt) and GPL (GPL-LICENSE.txt) licenses. +* To view and modify this theme, visit http://jqueryui.com/themeroller/?ffDefault=Verdana,Arial,sans-serif&fwDefault=normal&fsDefault=1.1em&cornerRadius=4px&bgColorHeader=cccccc&bgTextureHeader=03_highlight_soft.png&bgImgOpacityHeader=75&borderColorHeader=aaaaaa&fcHeader=222222&iconColorHeader=222222&bgColorContent=ffffff&bgTextureContent=01_flat.png&bgImgOpacityContent=75&borderColorContent=aaaaaa&fcContent=222222&iconColorContent=222222&bgColorDefault=e6e6e6&bgTextureDefault=02_glass.png&bgImgOpacityDefault=75&borderColorDefault=d3d3d3&fcDefault=555555&iconColorDefault=888888&bgColorHover=dadada&bgTextureHover=02_glass.png&bgImgOpacityHover=75&borderColorHover=999999&fcHover=212121&iconColorHover=454545&bgColorActive=ffffff&bgTextureActive=02_glass.png&bgImgOpacityActive=65&borderColorActive=aaaaaa&fcActive=212121&iconColorActive=454545&bgColorHighlight=fbf9ee&bgTextureHighlight=02_glass.png&bgImgOpacityHighlight=55&borderColorHighlight=fcefa1&fcHighlight=363636&iconColorHighlight=2e83ff&bgColorError=fef1ec&bgTextureError=02_glass.png&bgImgOpacityError=95&borderColorError=cd0a0a&fcError=cd0a0a&iconColorError=cd0a0a&bgColorOverlay=aaaaaa&bgTextureOverlay=01_flat.png&bgImgOpacityOverlay=0&opacityOverlay=30&bgColorShadow=aaaaaa&bgTextureShadow=01_flat.png&bgImgOpacityShadow=0&opacityShadow=30&thicknessShadow=8px&offsetTopShadow=-8px&offsetLeftShadow=-8px&cornerRadiusShadow=8px +*/ + + +/* Component containers +----------------------------------*/ +.ui-widget { font-family: Verdana,Arial,sans-serif; font-size: 1.1em; } +.ui-widget input, .ui-widget select, .ui-widget textarea, .ui-widget button { font-family: Verdana,Arial,sans-serif; font-size: 1em; } +.ui-widget-content { border: 1px solid #aaaaaa; background: #ffffff url(images/ui-bg_flat_75_ffffff_40x100.png) 50% 50% repeat-x; color: #222222; } +.ui-widget-content a { color: #222222; } +.ui-widget-header { border: 1px solid #aaaaaa; background: #cccccc url(images/ui-bg_highlight-soft_75_cccccc_1x100.png) 50% 50% repeat-x; color: #222222; font-weight: bold; } +.ui-widget-header a { color: #222222; } + +/* Interaction states +----------------------------------*/ +.ui-state-default, .ui-widget-content .ui-state-default { border: 1px solid #d3d3d3; background: #e6e6e6 url(images/ui-bg_glass_75_e6e6e6_1x400.png) 50% 50% repeat-x; font-weight: normal; color: #555555; outline: none; } +.ui-state-default a, .ui-state-default a:link, .ui-state-default a:visited { color: #555555; text-decoration: none; outline: none; } +.ui-state-hover, .ui-widget-content .ui-state-hover, .ui-state-focus, .ui-widget-content .ui-state-focus { border: 1px solid #999999; background: #dadada url(images/ui-bg_glass_75_dadada_1x400.png) 50% 50% repeat-x; font-weight: normal; color: #212121; outline: none; } +.ui-state-hover a, .ui-state-hover a:hover { color: #212121; text-decoration: none; outline: none; } +.ui-state-active, .ui-widget-content .ui-state-active { border: 1px solid #aaaaaa; background: #ffffff url(images/ui-bg_glass_65_ffffff_1x400.png) 50% 50% repeat-x; font-weight: normal; color: #212121; outline: none; } +.ui-state-active a, .ui-state-active a:link, .ui-state-active a:visited { color: #212121; outline: none; text-decoration: none; } + +/* Interaction Cues +----------------------------------*/ +.ui-state-highlight, .ui-widget-content .ui-state-highlight {border: 1px solid #fcefa1; background: #fbf9ee url(images/ui-bg_glass_55_fbf9ee_1x400.png) 50% 50% repeat-x; color: #363636; } +.ui-state-highlight a, .ui-widget-content .ui-state-highlight a { color: #363636; } +.ui-state-error, .ui-widget-content .ui-state-error {border: 1px solid #cd0a0a; background: #fef1ec url(images/ui-bg_glass_95_fef1ec_1x400.png) 50% 50% repeat-x; color: #cd0a0a; } +.ui-state-error a, .ui-widget-content .ui-state-error a { color: #cd0a0a; } +.ui-state-error-text, .ui-widget-content .ui-state-error-text { color: #cd0a0a; } +.ui-state-disabled, .ui-widget-content .ui-state-disabled { opacity: .35; filter:Alpha(Opacity=35); background-image: none; } +.ui-priority-primary, .ui-widget-content .ui-priority-primary { font-weight: bold; } +.ui-priority-secondary, .ui-widget-content .ui-priority-secondary { opacity: .7; filter:Alpha(Opacity=70); font-weight: normal; } + +/* Icons +----------------------------------*/ + +/* states and images */ +.ui-icon { width: 16px; height: 16px; background-image: url(images/ui-icons_222222_256x240.png); } +.ui-widget-content .ui-icon {background-image: url(images/ui-icons_222222_256x240.png); } +.ui-widget-header .ui-icon {background-image: url(images/ui-icons_222222_256x240.png); } +.ui-state-default .ui-icon { background-image: url(images/ui-icons_888888_256x240.png); } +.ui-state-hover .ui-icon, .ui-state-focus .ui-icon {background-image: url(images/ui-icons_454545_256x240.png); } +.ui-state-active .ui-icon {background-image: url(images/ui-icons_454545_256x240.png); } +.ui-state-highlight .ui-icon {background-image: url(images/ui-icons_2e83ff_256x240.png); } +.ui-state-error .ui-icon, .ui-state-error-text .ui-icon {background-image: url(images/ui-icons_cd0a0a_256x240.png); } + +/* positioning */ +.ui-icon-carat-1-n { background-position: 0 0; } +.ui-icon-carat-1-ne { background-position: -16px 0; } +.ui-icon-carat-1-e { background-position: -32px 0; } +.ui-icon-carat-1-se { background-position: -48px 0; } +.ui-icon-carat-1-s { background-position: -64px 0; } +.ui-icon-carat-1-sw { background-position: -80px 0; } +.ui-icon-carat-1-w { background-position: -96px 0; } +.ui-icon-carat-1-nw { background-position: -112px 0; } +.ui-icon-carat-2-n-s { background-position: -128px 0; } +.ui-icon-carat-2-e-w { background-position: -144px 0; } +.ui-icon-triangle-1-n { background-position: 0 -16px; } +.ui-icon-triangle-1-ne { background-position: -16px -16px; } +.ui-icon-triangle-1-e { background-position: -32px -16px; } +.ui-icon-triangle-1-se { background-position: -48px -16px; } +.ui-icon-triangle-1-s { background-position: -64px -16px; } +.ui-icon-triangle-1-sw { background-position: -80px -16px; } +.ui-icon-triangle-1-w { background-position: -96px -16px; } +.ui-icon-triangle-1-nw { background-position: -112px -16px; } +.ui-icon-triangle-2-n-s { background-position: -128px -16px; } +.ui-icon-triangle-2-e-w { background-position: -144px -16px; } +.ui-icon-arrow-1-n { background-position: 0 -32px; } +.ui-icon-arrow-1-ne { background-position: -16px -32px; } +.ui-icon-arrow-1-e { background-position: -32px -32px; } +.ui-icon-arrow-1-se { background-position: -48px -32px; } +.ui-icon-arrow-1-s { background-position: -64px -32px; } +.ui-icon-arrow-1-sw { background-position: -80px -32px; } +.ui-icon-arrow-1-w { background-position: -96px -32px; } +.ui-icon-arrow-1-nw { background-position: -112px -32px; } +.ui-icon-arrow-2-n-s { background-position: -128px -32px; } +.ui-icon-arrow-2-ne-sw { background-position: -144px -32px; } +.ui-icon-arrow-2-e-w { background-position: -160px -32px; } +.ui-icon-arrow-2-se-nw { background-position: -176px -32px; } +.ui-icon-arrowstop-1-n { background-position: -192px -32px; } +.ui-icon-arrowstop-1-e { background-position: -208px -32px; } +.ui-icon-arrowstop-1-s { background-position: -224px -32px; } +.ui-icon-arrowstop-1-w { background-position: -240px -32px; } +.ui-icon-arrowthick-1-n { background-position: 0 -48px; } +.ui-icon-arrowthick-1-ne { background-position: -16px -48px; } +.ui-icon-arrowthick-1-e { background-position: -32px -48px; } +.ui-icon-arrowthick-1-se { background-position: -48px -48px; } +.ui-icon-arrowthick-1-s { background-position: -64px -48px; } +.ui-icon-arrowthick-1-sw { background-position: -80px -48px; } +.ui-icon-arrowthick-1-w { background-position: -96px -48px; } +.ui-icon-arrowthick-1-nw { background-position: -112px -48px; } +.ui-icon-arrowthick-2-n-s { background-position: -128px -48px; } +.ui-icon-arrowthick-2-ne-sw { background-position: -144px -48px; } +.ui-icon-arrowthick-2-e-w { background-position: -160px -48px; } +.ui-icon-arrowthick-2-se-nw { background-position: -176px -48px; } +.ui-icon-arrowthickstop-1-n { background-position: -192px -48px; } +.ui-icon-arrowthickstop-1-e { background-position: -208px -48px; } +.ui-icon-arrowthickstop-1-s { background-position: -224px -48px; } +.ui-icon-arrowthickstop-1-w { background-position: -240px -48px; } +.ui-icon-arrowreturnthick-1-w { background-position: 0 -64px; } +.ui-icon-arrowreturnthick-1-n { background-position: -16px -64px; } +.ui-icon-arrowreturnthick-1-e { background-position: -32px -64px; } +.ui-icon-arrowreturnthick-1-s { background-position: -48px -64px; } +.ui-icon-arrowreturn-1-w { background-position: -64px -64px; } +.ui-icon-arrowreturn-1-n { background-position: -80px -64px; } +.ui-icon-arrowreturn-1-e { background-position: -96px -64px; } +.ui-icon-arrowreturn-1-s { background-position: -112px -64px; } +.ui-icon-arrowrefresh-1-w { background-position: -128px -64px; } +.ui-icon-arrowrefresh-1-n { background-position: -144px -64px; } +.ui-icon-arrowrefresh-1-e { background-position: -160px -64px; } +.ui-icon-arrowrefresh-1-s { background-position: -176px -64px; } +.ui-icon-arrow-4 { background-position: 0 -80px; } +.ui-icon-arrow-4-diag { background-position: -16px -80px; } +.ui-icon-extlink { background-position: -32px -80px; } +.ui-icon-newwin { background-position: -48px -80px; } +.ui-icon-refresh { background-position: -64px -80px; } +.ui-icon-shuffle { background-position: -80px -80px; } +.ui-icon-transfer-e-w { background-position: -96px -80px; } +.ui-icon-transferthick-e-w { background-position: -112px -80px; } +.ui-icon-folder-collapsed { background-position: 0 -96px; } +.ui-icon-folder-open { background-position: -16px -96px; } +.ui-icon-document { background-position: -32px -96px; } +.ui-icon-document-b { background-position: -48px -96px; } +.ui-icon-note { background-position: -64px -96px; } +.ui-icon-mail-closed { background-position: -80px -96px; } +.ui-icon-mail-open { background-position: -96px -96px; } +.ui-icon-suitcase { background-position: -112px -96px; } +.ui-icon-comment { background-position: -128px -96px; } +.ui-icon-person { background-position: -144px -96px; } +.ui-icon-print { background-position: -160px -96px; } +.ui-icon-trash { background-position: -176px -96px; } +.ui-icon-locked { background-position: -192px -96px; } +.ui-icon-unlocked { background-position: -208px -96px; } +.ui-icon-bookmark { background-position: -224px -96px; } +.ui-icon-tag { background-position: -240px -96px; } +.ui-icon-home { background-position: 0 -112px; } +.ui-icon-flag { background-position: -16px -112px; } +.ui-icon-calendar { background-position: -32px -112px; } +.ui-icon-cart { background-position: -48px -112px; } +.ui-icon-pencil { background-position: -64px -112px; } +.ui-icon-clock { background-position: -80px -112px; } +.ui-icon-disk { background-position: -96px -112px; } +.ui-icon-calculator { background-position: -112px -112px; } +.ui-icon-zoomin { background-position: -128px -112px; } +.ui-icon-zoomout { background-position: -144px -112px; } +.ui-icon-search { background-position: -160px -112px; } +.ui-icon-wrench { background-position: -176px -112px; } +.ui-icon-gear { background-position: -192px -112px; } +.ui-icon-heart { background-position: -208px -112px; } +.ui-icon-star { background-position: -224px -112px; } +.ui-icon-link { background-position: -240px -112px; } +.ui-icon-cancel { background-position: 0 -128px; } +.ui-icon-plus { background-position: -16px -128px; } +.ui-icon-plusthick { background-position: -32px -128px; } +.ui-icon-minus { background-position: -48px -128px; } +.ui-icon-minusthick { background-position: -64px -128px; } +.ui-icon-close { background-position: -80px -128px; } +.ui-icon-closethick { background-position: -96px -128px; } +.ui-icon-key { background-position: -112px -128px; } +.ui-icon-lightbulb { background-position: -128px -128px; } +.ui-icon-scissors { background-position: -144px -128px; } +.ui-icon-clipboard { background-position: -160px -128px; } +.ui-icon-copy { background-position: -176px -128px; } +.ui-icon-contact { background-position: -192px -128px; } +.ui-icon-image { background-position: -208px -128px; } +.ui-icon-video { background-position: -224px -128px; } +.ui-icon-script { background-position: -240px -128px; } +.ui-icon-alert { background-position: 0 -144px; } +.ui-icon-info { background-position: -16px -144px; } +.ui-icon-notice { background-position: -32px -144px; } +.ui-icon-help { background-position: -48px -144px; } +.ui-icon-check { background-position: -64px -144px; } +.ui-icon-bullet { background-position: -80px -144px; } +.ui-icon-radio-off { background-position: -96px -144px; } +.ui-icon-radio-on { background-position: -112px -144px; } +.ui-icon-pin-w { background-position: -128px -144px; } +.ui-icon-pin-s { background-position: -144px -144px; } +.ui-icon-play { background-position: 0 -160px; } +.ui-icon-pause { background-position: -16px -160px; } +.ui-icon-seek-next { background-position: -32px -160px; } +.ui-icon-seek-prev { background-position: -48px -160px; } +.ui-icon-seek-end { background-position: -64px -160px; } +.ui-icon-seek-first { background-position: -80px -160px; } +.ui-icon-stop { background-position: -96px -160px; } +.ui-icon-eject { background-position: -112px -160px; } +.ui-icon-volume-off { background-position: -128px -160px; } +.ui-icon-volume-on { background-position: -144px -160px; } +.ui-icon-power { background-position: 0 -176px; } +.ui-icon-signal-diag { background-position: -16px -176px; } +.ui-icon-signal { background-position: -32px -176px; } +.ui-icon-battery-0 { background-position: -48px -176px; } +.ui-icon-battery-1 { background-position: -64px -176px; } +.ui-icon-battery-2 { background-position: -80px -176px; } +.ui-icon-battery-3 { background-position: -96px -176px; } +.ui-icon-circle-plus { background-position: 0 -192px; } +.ui-icon-circle-minus { background-position: -16px -192px; } +.ui-icon-circle-close { background-position: -32px -192px; } +.ui-icon-circle-triangle-e { background-position: -48px -192px; } +.ui-icon-circle-triangle-s { background-position: -64px -192px; } +.ui-icon-circle-triangle-w { background-position: -80px -192px; } +.ui-icon-circle-triangle-n { background-position: -96px -192px; } +.ui-icon-circle-arrow-e { background-position: -112px -192px; } +.ui-icon-circle-arrow-s { background-position: -128px -192px; } +.ui-icon-circle-arrow-w { background-position: -144px -192px; } +.ui-icon-circle-arrow-n { background-position: -160px -192px; } +.ui-icon-circle-zoomin { background-position: -176px -192px; } +.ui-icon-circle-zoomout { background-position: -192px -192px; } +.ui-icon-circle-check { background-position: -208px -192px; } +.ui-icon-circlesmall-plus { background-position: 0 -208px; } +.ui-icon-circlesmall-minus { background-position: -16px -208px; } +.ui-icon-circlesmall-close { background-position: -32px -208px; } +.ui-icon-squaresmall-plus { background-position: -48px -208px; } +.ui-icon-squaresmall-minus { background-position: -64px -208px; } +.ui-icon-squaresmall-close { background-position: -80px -208px; } +.ui-icon-grip-dotted-vertical { background-position: 0 -224px; } +.ui-icon-grip-dotted-horizontal { background-position: -16px -224px; } +.ui-icon-grip-solid-vertical { background-position: -32px -224px; } +.ui-icon-grip-solid-horizontal { background-position: -48px -224px; } +.ui-icon-gripsmall-diagonal-se { background-position: -64px -224px; } +.ui-icon-grip-diagonal-se { background-position: -80px -224px; } + + +/* Misc visuals +----------------------------------*/ + +/* Corner radius */ +.ui-corner-tl { -moz-border-radius-topleft: 4px; -webkit-border-top-left-radius: 4px; } +.ui-corner-tr { -moz-border-radius-topright: 4px; -webkit-border-top-right-radius: 4px; } +.ui-corner-bl { -moz-border-radius-bottomleft: 4px; -webkit-border-bottom-left-radius: 4px; } +.ui-corner-br { -moz-border-radius-bottomright: 4px; -webkit-border-bottom-right-radius: 4px; } +.ui-corner-top { -moz-border-radius-topleft: 4px; -webkit-border-top-left-radius: 4px; -moz-border-radius-topright: 4px; -webkit-border-top-right-radius: 4px; } +.ui-corner-bottom { -moz-border-radius-bottomleft: 4px; -webkit-border-bottom-left-radius: 4px; -moz-border-radius-bottomright: 4px; -webkit-border-bottom-right-radius: 4px; } +.ui-corner-right { -moz-border-radius-topright: 4px; -webkit-border-top-right-radius: 4px; -moz-border-radius-bottomright: 4px; -webkit-border-bottom-right-radius: 4px; } +.ui-corner-left { -moz-border-radius-topleft: 4px; -webkit-border-top-left-radius: 4px; -moz-border-radius-bottomleft: 4px; -webkit-border-bottom-left-radius: 4px; } +.ui-corner-all { -moz-border-radius: 4px; -webkit-border-radius: 4px; } + +/* Overlays */ +.ui-widget-overlay { background: #aaaaaa url(images/ui-bg_flat_0_aaaaaa_40x100.png) 50% 50% repeat-x; opacity: .30;filter:Alpha(Opacity=30); } +.ui-widget-shadow { margin: -8px 0 0 -8px; padding: 8px; background: #aaaaaa url(images/ui-bg_flat_0_aaaaaa_40x100.png) 50% 50% repeat-x; opacity: .30;filter:Alpha(Opacity=30); -moz-border-radius: 8px; -webkit-border-radius: 8px; }/* Accordion +----------------------------------*/ +.ui-accordion .ui-accordion-header { cursor: pointer; position: relative; margin-top: 1px; zoom: 1; } +.ui-accordion .ui-accordion-li-fix { display: inline; } +.ui-accordion .ui-accordion-header-active { border-bottom: 0 !important; } +.ui-accordion .ui-accordion-header a { display: block; font-size: 1em; padding: .5em .5em .5em 2.2em; } +.ui-accordion .ui-accordion-header .ui-icon { position: absolute; left: .5em; top: 50%; margin-top: -8px; } +.ui-accordion .ui-accordion-content { padding: 1em 2.2em; border-top: 0; margin-top: -2px; position: relative; top: 1px; margin-bottom: 2px; overflow: auto; display: none; } +.ui-accordion .ui-accordion-content-active { display: block; }/* Datepicker +----------------------------------*/ +.ui-datepicker { width: 17em; padding: .2em .2em 0; } +.ui-datepicker .ui-datepicker-header { position:relative; padding:.2em 0; } +.ui-datepicker .ui-datepicker-prev, .ui-datepicker .ui-datepicker-next { position:absolute; top: 2px; width: 1.8em; height: 1.8em; } +.ui-datepicker .ui-datepicker-prev-hover, .ui-datepicker .ui-datepicker-next-hover { top: 1px; } +.ui-datepicker .ui-datepicker-prev { left:2px; } +.ui-datepicker .ui-datepicker-next { right:2px; } +.ui-datepicker .ui-datepicker-prev-hover { left:1px; } +.ui-datepicker .ui-datepicker-next-hover { right:1px; } +.ui-datepicker .ui-datepicker-prev span, .ui-datepicker .ui-datepicker-next span { display: block; position: absolute; left: 50%; margin-left: -8px; top: 50%; margin-top: -8px; } +.ui-datepicker .ui-datepicker-title { margin: 0 2.3em; line-height: 1.8em; text-align: center; } +.ui-datepicker .ui-datepicker-title select { float:left; font-size:1em; margin:1px 0; } +.ui-datepicker select.ui-datepicker-month-year {width: 100%;} +.ui-datepicker select.ui-datepicker-month, +.ui-datepicker select.ui-datepicker-year { width: 49%;} +.ui-datepicker .ui-datepicker-title select.ui-datepicker-year { float: right; } +.ui-datepicker table {width: 100%; font-size: .9em; border-collapse: collapse; margin:0 0 .4em; } +.ui-datepicker th { padding: .7em .3em; text-align: center; font-weight: bold; border: 0; } +.ui-datepicker td { border: 0; padding: 1px; } +.ui-datepicker td span, .ui-datepicker td a { display: block; padding: .2em; text-align: right; text-decoration: none; } +.ui-datepicker .ui-datepicker-buttonpane { background-image: none; margin: .7em 0 0 0; padding:0 .2em; border-left: 0; border-right: 0; border-bottom: 0; } +.ui-datepicker .ui-datepicker-buttonpane button { float: right; margin: .5em .2em .4em; cursor: pointer; padding: .2em .6em .3em .6em; width:auto; overflow:visible; } +.ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current { float:left; } + +/* with multiple calendars */ +.ui-datepicker.ui-datepicker-multi { width:auto; } +.ui-datepicker-multi .ui-datepicker-group { float:left; } +.ui-datepicker-multi .ui-datepicker-group table { width:95%; margin:0 auto .4em; } +.ui-datepicker-multi-2 .ui-datepicker-group { width:50%; } +.ui-datepicker-multi-3 .ui-datepicker-group { width:33.3%; } +.ui-datepicker-multi-4 .ui-datepicker-group { width:25%; } +.ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header { border-left-width:0; } +.ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header { border-left-width:0; } +.ui-datepicker-multi .ui-datepicker-buttonpane { clear:left; } +.ui-datepicker-row-break { clear:both; width:100%; } + +/* RTL support */ +.ui-datepicker-rtl { direction: rtl; } +.ui-datepicker-rtl .ui-datepicker-prev { right: 2px; left: auto; } +.ui-datepicker-rtl .ui-datepicker-next { left: 2px; right: auto; } +.ui-datepicker-rtl .ui-datepicker-prev:hover { right: 1px; left: auto; } +.ui-datepicker-rtl .ui-datepicker-next:hover { left: 1px; right: auto; } +.ui-datepicker-rtl .ui-datepicker-buttonpane { clear:right; } +.ui-datepicker-rtl .ui-datepicker-buttonpane button { float: left; } +.ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current { float:right; } +.ui-datepicker-rtl .ui-datepicker-group { float:right; } +.ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header { border-right-width:0; border-left-width:1px; } +.ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header { border-right-width:0; border-left-width:1px; } + +/* IE6 IFRAME FIX (taken from datepicker 1.5.3 */ +.ui-datepicker-cover { + display: none; /*sorry for IE5*/ + display/**/: block; /*sorry for IE5*/ + position: absolute; /*must have*/ + z-index: -1; /*must have*/ + filter: mask(); /*must have*/ + top: -4px; /*must have*/ + left: -4px; /*must have*/ + width: 200px; /*must have*/ + height: 200px; /*must have*/ +}/* Dialog +----------------------------------*/ +.ui-dialog { position: relative; padding: .2em; width: 300px; } +.ui-dialog .ui-dialog-titlebar { padding: .5em .3em .3em 1em; position: relative; } +.ui-dialog .ui-dialog-title { float: left; margin: .1em 0 .2em; } +.ui-dialog .ui-dialog-titlebar-close { position: absolute; right: .3em; top: 50%; width: 19px; margin: -10px 0 0 0; padding: 1px; height: 18px; } +.ui-dialog .ui-dialog-titlebar-close span { display: block; margin: 1px; } +.ui-dialog .ui-dialog-titlebar-close:hover, .ui-dialog .ui-dialog-titlebar-close:focus { padding: 0; } +.ui-dialog .ui-dialog-content { border: 0; padding: .5em 1em; background: none; overflow: auto; zoom: 1; } +.ui-dialog .ui-dialog-buttonpane { text-align: left; border-width: 1px 0 0 0; background-image: none; margin: .5em 0 0 0; padding: .3em 1em .5em .4em; } +.ui-dialog .ui-dialog-buttonpane button { float: right; margin: .5em .4em .5em 0; cursor: pointer; padding: .2em .6em .3em .6em; line-height: 1.4em; width:auto; overflow:visible; } +.ui-dialog .ui-resizable-se { width: 14px; height: 14px; right: 3px; bottom: 3px; } +.ui-draggable .ui-dialog-titlebar { cursor: move; } +/* Progressbar +----------------------------------*/ +.ui-progressbar { height:2em; text-align: left; } +.ui-progressbar .ui-progressbar-value {margin: -1px; height:100%; }/* Resizable +----------------------------------*/ +.ui-resizable { position: relative;} +.ui-resizable-handle { position: absolute;font-size: 0.1px;z-index: 99999; display: block;} +.ui-resizable-disabled .ui-resizable-handle, .ui-resizable-autohide .ui-resizable-handle { display: none; } +.ui-resizable-n { cursor: n-resize; height: 7px; width: 100%; top: -5px; left: 0px; } +.ui-resizable-s { cursor: s-resize; height: 7px; width: 100%; bottom: -5px; left: 0px; } +.ui-resizable-e { cursor: e-resize; width: 7px; right: -5px; top: 0px; height: 100%; } +.ui-resizable-w { cursor: w-resize; width: 7px; left: -5px; top: 0px; height: 100%; } +.ui-resizable-se { cursor: se-resize; width: 12px; height: 12px; right: 1px; bottom: 1px; } +.ui-resizable-sw { cursor: sw-resize; width: 9px; height: 9px; left: -5px; bottom: -5px; } +.ui-resizable-nw { cursor: nw-resize; width: 9px; height: 9px; left: -5px; top: -5px; } +.ui-resizable-ne { cursor: ne-resize; width: 9px; height: 9px; right: -5px; top: -5px;}/* Slider +----------------------------------*/ +.ui-slider { position: relative; text-align: left; } +.ui-slider .ui-slider-handle { position: absolute; z-index: 2; width: 1.2em; height: 1.2em; cursor: default; } +.ui-slider .ui-slider-range { position: absolute; z-index: 1; font-size: .7em; display: block; border: 0; } + +.ui-slider-horizontal { height: .8em; } +.ui-slider-horizontal .ui-slider-handle { top: -.3em; margin-left: -.6em; } +.ui-slider-horizontal .ui-slider-range { top: 0; height: 100%; } +.ui-slider-horizontal .ui-slider-range-min { left: 0; } +.ui-slider-horizontal .ui-slider-range-max { right: 0; } + +.ui-slider-vertical { width: .8em; height: 100px; } +.ui-slider-vertical .ui-slider-handle { left: -.3em; margin-left: 0; margin-bottom: -.6em; } +.ui-slider-vertical .ui-slider-range { left: 0; width: 100%; } +.ui-slider-vertical .ui-slider-range-min { bottom: 0; } +.ui-slider-vertical .ui-slider-range-max { top: 0; }/* Tabs +----------------------------------*/ +.ui-tabs { padding: .2em; zoom: 1; } +.ui-tabs .ui-tabs-nav { list-style: none; position: relative; padding: .2em .2em 0; } +.ui-tabs .ui-tabs-nav li { position: relative; float: left; border-bottom-width: 0 !important; margin: 0 .2em -1px 0; padding: 0; } +.ui-tabs .ui-tabs-nav li a { float: left; text-decoration: none; padding: .5em 1em; } +.ui-tabs .ui-tabs-nav li.ui-tabs-selected { padding-bottom: 1px; border-bottom-width: 0; } +.ui-tabs .ui-tabs-nav li.ui-tabs-selected a, .ui-tabs .ui-tabs-nav li.ui-state-disabled a, .ui-tabs .ui-tabs-nav li.ui-state-processing a { cursor: text; } +.ui-tabs .ui-tabs-nav li a, .ui-tabs.ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-selected a { cursor: pointer; } /* first selector in group seems obsolete, but required to overcome bug in Opera applying cursor: text overall if defined elsewhere... */ +.ui-tabs .ui-tabs-panel { padding: 1em 1.4em; display: block; border-width: 0; background: none; } +.ui-tabs .ui-tabs-hide { display: none !important; } diff --git a/src/Orchard.Web/Modules/ArchiveLater/Styles/ui.datepicker.css b/src/Orchard.Web/Modules/ArchiveLater/Styles/ui.datepicker.css new file mode 100644 index 000000000..a1116e69c --- /dev/null +++ b/src/Orchard.Web/Modules/ArchiveLater/Styles/ui.datepicker.css @@ -0,0 +1,61 @@ +/* Datepicker +----------------------------------*/ +.ui-datepicker { width: 17em; padding: .2em .2em 0; } +.ui-datepicker .ui-datepicker-header { position:relative; padding:.2em 0; } +.ui-datepicker .ui-datepicker-prev, .ui-datepicker .ui-datepicker-next { position:absolute; top: 2px; width: 1.8em; height: 1.8em; } +.ui-datepicker .ui-datepicker-prev-hover, .ui-datepicker .ui-datepicker-next-hover { top: 1px; } +.ui-datepicker .ui-datepicker-prev { left:2px; } +.ui-datepicker .ui-datepicker-next { right:2px; } +.ui-datepicker .ui-datepicker-prev-hover { left:1px; } +.ui-datepicker .ui-datepicker-next-hover { right:1px; } +.ui-datepicker .ui-datepicker-prev span, .ui-datepicker .ui-datepicker-next span { display: block; position: absolute; left: 50%; margin-left: -8px; top: 50%; margin-top: -8px; } +.ui-datepicker .ui-datepicker-title { margin: 0 2.3em; line-height: 1.8em; text-align: center; } +.ui-datepicker .ui-datepicker-title select { font-size:1em; margin:1px 0; } +.ui-datepicker select.ui-datepicker-month-year {width: 100%;} +.ui-datepicker select.ui-datepicker-month, +.ui-datepicker select.ui-datepicker-year { width: 49%;} +.ui-datepicker table {width: 100%; font-size: .9em; border-collapse: collapse; margin:0 0 .4em; } +.ui-datepicker th { padding: .7em .3em; text-align: center; font-weight: bold; border: 0; } +.ui-datepicker td { border: 0; padding: 1px; } +.ui-datepicker td span, .ui-datepicker td a { display: block; padding: .2em; text-align: right; text-decoration: none; } +.ui-datepicker .ui-datepicker-buttonpane { background-image: none; margin: .7em 0 0 0; padding:0 .2em; border-left: 0; border-right: 0; border-bottom: 0; } +.ui-datepicker .ui-datepicker-buttonpane button { float: right; margin: .5em .2em .4em; cursor: pointer; padding: .2em .6em .3em .6em; width:auto; overflow:visible; } +.ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current { float:left; } + +/* with multiple calendars */ +.ui-datepicker.ui-datepicker-multi { width:auto; } +.ui-datepicker-multi .ui-datepicker-group { float:left; } +.ui-datepicker-multi .ui-datepicker-group table { width:95%; margin:0 auto .4em; } +.ui-datepicker-multi-2 .ui-datepicker-group { width:50%; } +.ui-datepicker-multi-3 .ui-datepicker-group { width:33.3%; } +.ui-datepicker-multi-4 .ui-datepicker-group { width:25%; } +.ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header { border-left-width:0; } +.ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header { border-left-width:0; } +.ui-datepicker-multi .ui-datepicker-buttonpane { clear:left; } +.ui-datepicker-row-break { clear:both; width:100%; } + +/* RTL support */ +.ui-datepicker-rtl { direction: rtl; } +.ui-datepicker-rtl .ui-datepicker-prev { right: 2px; left: auto; } +.ui-datepicker-rtl .ui-datepicker-next { left: 2px; right: auto; } +.ui-datepicker-rtl .ui-datepicker-prev:hover { right: 1px; left: auto; } +.ui-datepicker-rtl .ui-datepicker-next:hover { left: 1px; right: auto; } +.ui-datepicker-rtl .ui-datepicker-buttonpane { clear:right; } +.ui-datepicker-rtl .ui-datepicker-buttonpane button { float: left; } +.ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current { float:right; } +.ui-datepicker-rtl .ui-datepicker-group { float:right; } +.ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header { border-right-width:0; border-left-width:1px; } +.ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header { border-right-width:0; border-left-width:1px; } + +/* IE6 IFRAME FIX (taken from datepicker 1.5.3 */ +.ui-datepicker-cover { + display: none; /*sorry for IE5*/ + display/**/: block; /*sorry for IE5*/ + position: absolute; /*must have*/ + z-index: -1; /*must have*/ + filter: mask(); /*must have*/ + top: -4px; /*must have*/ + left: -4px; /*must have*/ + width: 200px; /*must have*/ + height: 200px; /*must have*/ +} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/ArchiveLater/Styles/ui.timepickr.css b/src/Orchard.Web/Modules/ArchiveLater/Styles/ui.timepickr.css new file mode 100644 index 000000000..dfc7edfb7 --- /dev/null +++ b/src/Orchard.Web/Modules/ArchiveLater/Styles/ui.timepickr.css @@ -0,0 +1,50 @@ +.ui-timepickr { + display:none; + position:absolute; + padding:2px 2px 2px 0; +} + +.ui-timepickr-row { + padding:0; + float:right; + clear:both; + overflow:hidden; + margin:2px 0; + display:none; + position:relative; +} + +.ui-timepickr-button { + float:left; + margin:0; + padding:0; + list-style:none; + list-style-type:none; +} + +.ui-timepickr-button span { + font-size:.7em; + padding:4px 6px 4px 6px; + margin-left:2px; + text-align:center; + cursor:pointer; + display:block; + text-align:center; + + + /* system theme (default) */ + border-width:1px; + border-style:solid; + /*border-color:ThreeDLightShadow ThreeDShadow ThreeDShadow ThreeDLightShadow; + color:ButtonText; + background:ButtonFace;*/ +} + +.ui-timepickr-button span.ui-state-hover { + /*color:HighlightText; + background:Highlight;*/ +} + +.ui-state-hover span { + /*background:#c30;*/ +} diff --git a/src/Orchard.Web/Modules/ArchiveLater/ViewModels/ArchiveLaterViewModel.cs b/src/Orchard.Web/Modules/ArchiveLater/ViewModels/ArchiveLaterViewModel.cs new file mode 100644 index 000000000..f08455e13 --- /dev/null +++ b/src/Orchard.Web/Modules/ArchiveLater/ViewModels/ArchiveLaterViewModel.cs @@ -0,0 +1,26 @@ +using System; +using ArchiveLater.Models; +using Orchard.ContentManagement; + +namespace ArchiveLater.ViewModels { + public class ArchiveLaterViewModel { + private readonly ArchiveLaterPart _archiveLaterPart; + + public ArchiveLaterViewModel(ArchiveLaterPart archiveLaterPart) { + _archiveLaterPart = archiveLaterPart; + } + + public bool ArchiveLater { get; set; } + public ContentItem ContentItem { get { return _archiveLaterPart.ContentItem; } } + + public bool IsPublished { + get { return ContentItem.VersionRecord != null && ContentItem.VersionRecord.Published; } + } + + public DateTime? ScheduledArchiveUtc { get; set; } + + public string ScheduledArchiveDate { get; set; } + + public string ScheduledArchiveTime { get; set; } + } +} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/ArchiveLater/ViewModels/ItemReferenceContentFieldDisplayModel.cs b/src/Orchard.Web/Modules/ArchiveLater/ViewModels/ItemReferenceContentFieldDisplayModel.cs new file mode 100644 index 000000000..5344396c8 --- /dev/null +++ b/src/Orchard.Web/Modules/ArchiveLater/ViewModels/ItemReferenceContentFieldDisplayModel.cs @@ -0,0 +1,12 @@ +using Orchard.ContentManagement; + +namespace Orchard.Core.Common.ViewModels { + public class ItemReferenceContentFieldDisplayViewModel { + private ContentItem _item; + + public ContentItem Item { + get { return _item; } + set { _item = value; } + } + } +} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/ArchiveLater/ViewModels/ItemReferenceContentFieldEditorViewModel.cs b/src/Orchard.Web/Modules/ArchiveLater/ViewModels/ItemReferenceContentFieldEditorViewModel.cs new file mode 100644 index 000000000..dd0249005 --- /dev/null +++ b/src/Orchard.Web/Modules/ArchiveLater/ViewModels/ItemReferenceContentFieldEditorViewModel.cs @@ -0,0 +1,12 @@ +using Orchard.ContentManagement; + +namespace Orchard.Core.Common.ViewModels { + public class ItemReferenceContentFieldEditorViewModel { + private ContentItem _item; + + public ContentItem Item { + get { return _item; } + set { _item = value; } + } + } +} diff --git a/src/Orchard.Web/Modules/ArchiveLater/Views/DisplayTemplates/Parts/ArchiveLater.Metadata.SummaryAdmin.ascx b/src/Orchard.Web/Modules/ArchiveLater/Views/DisplayTemplates/Parts/ArchiveLater.Metadata.SummaryAdmin.ascx new file mode 100644 index 000000000..03804e6cb --- /dev/null +++ b/src/Orchard.Web/Modules/ArchiveLater/Views/DisplayTemplates/Parts/ArchiveLater.Metadata.SummaryAdmin.ascx @@ -0,0 +1,11 @@ +<%@ Control Language="C#" Inherits="Orchard.Mvc.ViewUserControl" %> + <% + if ((Model.IsPublished && Model.ScheduledArchiveUtc.HasValue && Model.ScheduledArchiveUtc.Value > DateTime.UtcNow)) {%> +
      +
    • + " alt="<%:T("Scheduled") %>" title="<%:T("The page is scheduled for archiving") %>" /><%:T("Unpublish on") %> + <%:Html.DateTime(Model.ScheduledArchiveUtc.Value.ToLocalTime(), T("M/d/yyyy h:mm tt"))%> +  |  +
    • +
    <% + } %> diff --git a/src/Orchard.Web/Modules/ArchiveLater/Views/DisplayTemplates/Parts/ArchiveLater.Metadata.ascx b/src/Orchard.Web/Modules/ArchiveLater/Views/DisplayTemplates/Parts/ArchiveLater.Metadata.ascx new file mode 100644 index 000000000..7873c0024 --- /dev/null +++ b/src/Orchard.Web/Modules/ArchiveLater/Views/DisplayTemplates/Parts/ArchiveLater.Metadata.ascx @@ -0,0 +1 @@ +<%@ Control Language="C#" Inherits="Orchard.Mvc.ViewUserControl" %> \ No newline at end of file diff --git a/src/Orchard.Web/Modules/ArchiveLater/Views/EditorTemplates/Parts/ArchiveLater.ascx b/src/Orchard.Web/Modules/ArchiveLater/Views/EditorTemplates/Parts/ArchiveLater.ascx new file mode 100644 index 000000000..6e35b7e23 --- /dev/null +++ b/src/Orchard.Web/Modules/ArchiveLater/Views/EditorTemplates/Parts/ArchiveLater.ascx @@ -0,0 +1,39 @@ +<%@ Control Language="C#" Inherits="Orchard.Mvc.ViewUserControl" %> +<% Html.RegisterStyle("datetime.css"); %> +<% Html.RegisterStyle("jquery-ui-1.7.2.custom.css"); %> +<% Html.RegisterStyle("ui.datepicker.css"); %> +<% Html.RegisterStyle("ui.timepickr.css"); %> +<% Html.RegisterFootScript("jquery.ui.core.js"); %> +<% Html.RegisterFootScript("jquery.ui.widget.js"); %> +<% Html.RegisterFootScript("jquery.ui.datepicker.js"); %> +<% Html.RegisterFootScript("jquery.utils.js"); %> +<% Html.RegisterFootScript("ui.timepickr.js"); %> +
    + <%: T("Archive Settings")%> +
    + <%: Html.CheckBox("ArchiveLater", Model.ScheduledArchiveUtc.HasValue, new { id = ViewData.TemplateInfo.GetFullHtmlFieldId("Command_ArchiveLater") })%> + +
    +
    + + <%: Html.EditorFor(m => m.ScheduledArchiveDate)%> + + <%: Html.EditorFor(m => m.ScheduledArchiveTime)%> +
    +
    + \ No newline at end of file diff --git a/src/Orchard.Web/Modules/ArchiveLater/Views/Web.config b/src/Orchard.Web/Modules/ArchiveLater/Views/Web.config new file mode 100644 index 000000000..e065d8735 --- /dev/null +++ b/src/Orchard.Web/Modules/ArchiveLater/Views/Web.config @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Orchard.Web/Orchard.Web.csproj b/src/Orchard.Web/Orchard.Web.csproj index 7a6026c30..5101b69df 100644 --- a/src/Orchard.Web/Orchard.Web.csproj +++ b/src/Orchard.Web/Orchard.Web.csproj @@ -130,7 +130,9 @@ - + + Designer + diff --git a/src/Orchard.sln b/src/Orchard.sln index 49c3f5eec..386f96c76 100644 --- a/src/Orchard.sln +++ b/src/Orchard.sln @@ -75,6 +75,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Orchard.Packaging", "Orchar EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Orchard.Tests", "Tools\Orchard.Tests\Orchard.Tests.csproj", "{0DFA2E10-96C8-4E05-BC10-B710B97ECCDE}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Orchard.ArchiveLater", "Orchard.Web\Modules\ArchiveLater\Orchard.ArchiveLater.csproj", "{1C981BB3-26F7-494C-9005-CC27A5144233}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -213,6 +215,10 @@ Global {0DFA2E10-96C8-4E05-BC10-B710B97ECCDE}.Debug|Any CPU.Build.0 = Debug|Any CPU {0DFA2E10-96C8-4E05-BC10-B710B97ECCDE}.Release|Any CPU.ActiveCfg = Release|Any CPU {0DFA2E10-96C8-4E05-BC10-B710B97ECCDE}.Release|Any CPU.Build.0 = Release|Any CPU + {1C981BB3-26F7-494C-9005-CC27A5144233}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1C981BB3-26F7-494C-9005-CC27A5144233}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1C981BB3-26F7-494C-9005-CC27A5144233}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1C981BB3-26F7-494C-9005-CC27A5144233}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -236,6 +242,7 @@ Global {0E7646E8-FE8F-43C1-8799-D97860925EC4} = {E9C9F120-07BA-4DFB-B9C3-3AFB9D44C9D5} {D5D447D7-EF8E-43A6-B9A4-3B025DD9F45D} = {E9C9F120-07BA-4DFB-B9C3-3AFB9D44C9D5} {DFD137A2-DDB5-4D22-BE0D-FA9AD4C8B059} = {E9C9F120-07BA-4DFB-B9C3-3AFB9D44C9D5} + {1C981BB3-26F7-494C-9005-CC27A5144233} = {E9C9F120-07BA-4DFB-B9C3-3AFB9D44C9D5} {ABC826D4-2FA1-4F2F-87DE-E6095F653810} = {74E681ED-FECC-4034-B9BD-01B0BB1BDECA} {F112851D-B023-4746-B6B1-8D2E5AD8F7AA} = {74E681ED-FECC-4034-B9BD-01B0BB1BDECA} {6CB3EB30-F725-45C0-9742-42599BA8E8D2} = {74E681ED-FECC-4034-B9BD-01B0BB1BDECA} diff --git a/src/Orchard/Tasks/Scheduling/IScheduledTaskManager.cs b/src/Orchard/Tasks/Scheduling/IScheduledTaskManager.cs index 0fa2f2401..f0d0e253d 100644 --- a/src/Orchard/Tasks/Scheduling/IScheduledTaskManager.cs +++ b/src/Orchard/Tasks/Scheduling/IScheduledTaskManager.cs @@ -5,7 +5,10 @@ using Orchard.ContentManagement; namespace Orchard.Tasks.Scheduling { public interface IScheduledTaskManager : IDependency { void CreateTask(string taskType, DateTime scheduledUtc, ContentItem contentItem); + IEnumerable GetTasks(ContentItem contentItem); - void DeleteTasks(ContentItem contentItem, Func predicate); + IEnumerable GetTasks(string taskType, DateTime? scheduledBeforeUtc = null); + + void DeleteTasks(ContentItem contentItem, Func predicate = null); } } \ No newline at end of file